Doit - an experimental scripting framework
==========================================

Doit is a framework for writing imperative scripts which feel in the
execution like declarative ones.

The commands implemented in this framework follow these priciples:

* A failing command throws an exception and thus stops the script
 (unless caught). This is like a Perl script using "use autodie", but
 in Doit it is implemented consistently for all framework commands.
 "use autodie" knows only about Perl builtins, not about module
 functions

* Before executing a command a check is done whether the command has
 to run at all. This makes it possible to write "converging" scripts:
 a first run would do the changes, subsequent runs would not do at
 all.

* Command execution is logged --- so one actually see what changes are
 done to a system. A command which doesn't have to run won't output
 anything. So "convergent" scripts are typically silent after the
 first run.

There's a dry-run mode built-in, which would just show what commands
would run, similar like make's -n switch or puppet's --noop --test
options.

Status
------

This module is experimental, but already used in productive scripts.
Backward-incompatible changes to the module are possible, but will be
kept to a low number.

Examples
--------

Here's an example using a command from the git component. It just
either clones the given git repository to the given directory, or does
a fetch if the repository is already cloned:

   use Doit;
   my $doit = Doit->init;
   $doit->add_component("git");
   $doit->git_repo_update(
       repository => "git://github.com/eserte/Doit",
       directory  => "$ENV{HOME}/src/Doit",
   );

An excerpt from a real-world system setup script (for setup of
FreeBSD and Linux based smokers for CPAN Testers):

   use Doit;
   my $doit = Doit->init;
   $d->add_component('user');

   my $root = $doit->do_sudo; # for running commands/scripts as root
   $root->write_binary('/etc/sudoers.d/20_cpansand', <<'EOF'); # for auto-installing system depencies with CPAN::Plugin::Sysdeps
   cpansand ALL=(ALL) NOPASSWD: /usr/bin/apt-get install *
   cpansand ALL=(ALL) NOPASSWD: /usr/bin/apt-get -y install *
   EOF
   $root->chmod(0440, '/etc/sudoers.d/20_cpansand');
   chomp(my $zsh = `which zsh`);
   $root->user_account(
       username => 'cpansand',
       uid      => 1234,
       shell    => $zsh,
       ssh_keys => ['ssh-rsa ... '],
   );

   my $cpansand = $d->do_sudo(sudo_opts => [qw(-u cpansand)]); # for running commands as cpansand user
   $cpansand->make_path("/home/cpansand/.cpan/build");
   $cpansand->mkdir("/home/cpansand/.cpanreporter");
   $cpansand->write_binary("/home/cpansand/.cpanreporter/config.ini", <<'EOF');
   edit_report=default:no
   [email protected]
   send_report=default:yes fail:ask/yes
   transport = Metabase uri http://metabase.cpantesters.org/beta/ id_file /home/cpansand/.cpanreporter/somebody_metabase_id.json
   EOF
   ...

Installation
------------

The distribution is installed like a normal CPAN distribution. You
don't have to download it but use CPAN.pm or cpanm:

   cpan Doit

or

   cpanm Doit

An extracted tarball or git clone may be installed like this:

   perl Build.PL
   ./Build
   ./Build test
   ./Build install

(on Windows use just "Build" instead of "./Build")

The Build script itself is a Doit script and not implementing all
features of a Module::Build-based script, but it provides some
interesting actions like

   test_installed
   test_in_docker
   debian_package
   debian_package_with_docker

You don't have to install the distribution at all --- just leave the
extracted or cloned directory where it is and specify in your script

   use lib "/path/to/Doit/lib";
   use Doit;

Or if the extracted is relative to a script, say, in an "inc"
subdirectory:

   use FindBin;
   use lib "$FindBin::RealBin/inc/Doit/lib";
   use Doit;