Single-file distro

No, not Par.

I have a simple script perlall which is deployed as App::perlall, which comes with Makefile.PL, tests and such, but really I only want to rsync this single script to all of my test machines.

I even wrote a initvm command to deploy it automatically to other machines.

Then I came up with this simple autoinstaller to add missing non-core libs.

BEGIN { # autoinstall the non-core modules
  my @m;
  for (qw(App::Rad IO::Tee IO::Scalar Devel::Platform::Info Devel::PatchPerl)) {
    push @m, $_ unless eval "require $_;" }
  if (@m) { # Checked the API back to 1.76_01 (v5.8.4)
    require CPAN; CPAN->import;
    warn "CPAN::Shell->install(qw(@m))\n"; CPAN::Shell->install(@m); }
  $_->import for @m;

I'm still working on it, but I have created so far with perlall about 50 perls on about 6 machines with lots of compilers and features and platforms, and I am constantly testing with these.

The App::Cmd magic is done with App::Rad. This does the command, option and parameter detection from @ARGV, reads a config file for defaults, and runs the command or does the simple error handling. Thanks to Naveed Massjouni who said on Google+: "If you like App::Cmd, also take a look at" In fact I hated App::Cmd and App::Rad is the best tool for such a single-file script.

I even had to extend the limited option handling, because I need global pre-cmd options and special cmd-specific options.

perlall -v build 5.14.2d-nt --link

build = cmd
-v = global pre-cmd option, --link = cmd-specific options.
5.14.2d-nt argument to build

Plain App::Rad only supported pre-cmd options, but changing the cmd and argument detector was trivial.

All normal functions are available as commands, all underscored functions are internal helpers. The usage error screen is created automatically from :Help(text) attributes.

Take care not use valid perl statements in that text, because Attribute::Handler is used which evals the text. So a usage text of

sub version :Help(print version) { $0." ".$VERSION}

will actually print the version at CHECK time. It does CHECK{eval "print version"}. The fix was

sub version :Help(Print version) { $0." ".$VERSION}

Attribute::Handler sucks big-time because it is insanely hard to detect attributes generally. Better do your attribute handling with manual FETCH_SCALAR_ATTRIBUTES methods.