NAME

wrapperl - wrapper for Perl customized invocation

Hurry Up!

# download in "visible" location
cd /usr/bin
# alias wget='curl -LO' # in case you need it
wget https://raw.githubusercontent.com/polettix/wrapperl/master/wrapperl
chmod +x wrapperl 

# set wrapperl.env for your project. Suppose you have a 'lib' directory
# with your stuff inside, and a 'local/lib/perl5' directory with the
# local installation of support modules, all inside /path/to/project
cd /path/to/project
cat > wrapperl.env <<END
PERL5LIB(qw< lib local/lib/perl5 >);
PERL('/path/to/selected/bin/perl');
END

# start using it, most straightforward way is from hash-bang
cat > program.pl <<END
#!/usr/bin/env wrapperl
print "using perl '$^X', \@INC contains:\n";
print "- '$_'\n" for @INC;
END
./program.pl
# ...

# you can access docs for locally installed modules
wrapperl -d Log::Log4perl::Tiny

TL;DR

… or an example is worth a whole manual sometimes.

First of all, download wrapperl from https://raw.githubusercontent.com/polettix/wrapperl/master/wrapperl and put somewhere in the environments where you need it. It is not necessary to put it in a directory in the PATH, although it is suggested in order to access all functionalities and it will also be assumed in the following of this example.

Let’s make a few assumptions:

In both environments, you create a wrapperl.env file inside the root directory of your project, which will hold configurations that are specific for the specific environment it is located into. In this example we will put it in the same directory as prg.

This is what you end up with in the development environment:

me@devhost /home/me/program$ ls -l
-rwxr-xr-x 1 me me 74 Apr 23 22:28 prg
-rwxr-xr-x 1 me me 90 Apr 22 12:35 wrapperl.env

me@devhost /home/me/program$ cat wrapperl.env
PERL5LIB(
   qw< lib local/lib/perl5 >, # located as siblings of wrapperl.env
   [ qw< /path/to/some/lib another/lib > ],    # non-siblings paths
);
PERL('/home/me/perl/bin/perl');

This is what you have in the production environment:

me@production /app/program$ ls -l
-rwxr-xr-x 1 me me 74 Apr 25 20:51 prg
-rwxr-xr-x 1 me me 66 Apr 25 20:51 wrapperl.env

me@production /app/program$ cat wrapperl.env
PERL5LIB(
   qw< lib local/lib/perl5 >, # located as siblings of wrapperl.env
   [ qw< /approved/lib > ],   # non-siblings paths
);
PERL('/approved/perl/bin/perl');

So yes, they two setups are mostly the same, except for the contents of the wrapperl.env files, each containing configurations that are environment-specific. You should be able to easily guess what the two functions PERL5LIB and PERL do.

Now, you just execute your program. In the development environment:

me@devhost /home/me/program$ ./prg
using perl '/home/me/perl/bin/perl', @INC contains:
- '/home/me/program/lib'
- '/home/me/program/local/lib/perl5/i686-linux'
- '/home/me/program/local/lib/perl5'
- '/path/to/some/lib/i686-linux'
- '/path/to/some/lib'
- '/home/me/program/another/lib/i686-linux'
- '/home/me/program/another/lib'
- '/home/me/perl/lib/site_perl/5.18.1/i686-linux'
- '/home/me/perl/lib/site_perl/5.18.1'
- '/home/me/perl/lib/5.18.1/i686-linux'
- '/home/me/perl/lib/5.18.1'
- '.'

In the production environment:

me@production /app/program$ ./prg
using perl '/approved/perl/bin/perl', @INC contains:
- '/app/program/lib'
- '/app/program/local/lib/perl5/i686-linux'
- '/app/program/local/lib/perl5'
- '/approved/lib/i686-linux'
- '/approved/lib'
- '/approved/perl/lib/site_perl/5.18.1/i686-linux'
- '/approved/perl/lib/site_perl/5.18.1'
- '/approved/perl/lib/5.18.1/i686-linux'
- '/approved/perl/lib/5.18.1'
- '.'

One last hint! If you cannot manage to install wrapperl somewhere in the PATH in all the environments, you can either do some shell wrapping (but this would somehow make wrapperl slightly overkill probably) or use an approach based on symbolic links. If this is the case:

With this setup, when you run the symbolic link, it will just run the associated .pl file with the settings in the wrapperl.env file.

That’s all folks!

SYNOPSYS

# Minimal setup: create a "wrapperl.env" file.
# It is a Perl program to set up the right environment.
# Two handy functions PERL5LIB() and PERL() are all you need usually
shell$ cat wrapperl.env
PERL5LIB(qw< lib llib > [qw< /path/to/lib /path/to/other/lib >]);
PERL('/path/to/bin/perl');

# You can have a different "wrapperl.env" on each directory.
# What is the one that we would see from here? "wrapperl" can
# tell you this with -e | --env
shell$ wrapperl -e
/path/to/wrapperl.env

# If you also provide a parameter to -e | --env, it will tell
# you which environment file will be seen by the provided
# parameter (that is of course expected to be a path)
shell$ wrapperl -e /path/to/a/wrapperl/symlink
/path/to/a/wrapper.env

# Time to make it work! Option -x | --exec means calling it
# as if it were the chosen perl with the configurations in
# "wrapperl.env"
shell$ wrapperl -x -le 'print $^X'
/path/to/bin/perl

# Option -s | --sibling allows to call programs that are
# usually shipped with perl, e.g. perlthanks, podchecker, etc.
shell$ wrapperl -s podchecker myprogram.pl

# Another useful option is -d | --doc to call perldoc quickly,
# so the following ones are equivalent but the latter is less typing
shell$ wrapperl -s perldoc Module::Name
shell$ wrapperl -d Module::Name

# If the first parameter is not supported by "wrapperl" directly,
# it will be considered a perl program to be executed along with
# its own parameters. This makes it handy to use wrapperl in
# hash-bang setups. The program's *realpath* is also used as the
# starting point for searching wrapperl.env, so that symbolic
# links to your program should work as expected
shell$ wrapperl myprogram.pl --foo bar

# You can symlink pointing to wrapperl and it will do some magic.
# Call the real program a name ending with ".pl" (e.g. "prg.pl")
# and symlink wrapperl with the same name withouth the extension
# (e.g. "prg"). This is what will happen:
shell$ ls -l
-rw-r--r-- 1 me me 74 Apr 23 22:20 wrapperl.env
lrwxrwxrwx 1 me me  8 Apr 23 22:51 prg -> /path/to/wrapperl
-rwxr-xr-x 1 me me 74 Apr 23 22:28 prg.pl

shell$ cat prg.pl
#!/usr/bin/env perl
print "using perl '$^X', \@INC contains:\n";
print "- '$_'\n" for @INC;

shell$ cat wrapperl.env
$ENV{PERL5LIB} = '/path/to/some/lib:/path/to/another/lib';
$PERL = '/path/to/bin/perl';

shell$ which perl
/usr/bin/perl

# If you call the program directly, wrapperl is not used of course
shell$ ./prg.pl
using perl '/usr/bin/perl', @INC contains:
- '/etc/perl'
- '/usr/local/lib/perl/5.14.2'
- '/usr/local/share/perl/5.14.2'
- '/usr/lib/perl5'
- '/usr/share/perl5'
- '/usr/lib/perl/5.14'
- '/usr/share/perl/5.14'
- '/usr/local/lib/site_perl'
- '.'

# On the other hand, if you call the "prg" symlink to wrapperl,
# the same program above will be called, but with the perl and
# options set in "wrapperl.env"
shell$ ./prg
using perl '/path/to/bin/perl', @INC contains:
- '/path/to/another/lib/i686-linux'
- '/path/to/another/lib'
- '/path/to/some/lib/i686-linux'
- '/path/to/some/lib'
- '/path/to/lib/site_perl/5.18.1/i686-linux'
- '/path/to/lib/site_perl/5.18.1'
- '/path/to/lib/5.18.1/i686-linux'
- '/path/to/lib/5.18.1'
- '.'

# There are two symlinks/names that trigger a special behaviour,
# namely "perl" and "perldoc" that do what you think
shell$ ls -l
lrwxrwxrwx 1 me me  8 Apr 23 21:51 perl -> /path/to/wrapperl
lrwxrwxrwx 1 me me  8 Apr 23 22:46 perldoc -> /path/to/wrapperl

# The following two are therefore equivalent (and no, the
# double "-x" is not an error, because the first is consumed by
# "wrapperl" and the second one is for the invoked perl)
shell$ ./perl -x /path/to/my/program.pl
shell$ wrapperl -x -x /path/to/my/program.pl

# These three are equivalent too
shell$ ./perldoc My::Module
shell$ wrapperl -d My::Module
shell$ wrapperl -s perldoc My::Module

# Last, if you manage to install wrapperl somewhere in the PATH
# you can spare the symbolic link and use the hash bang directly!
shell$ cat hashbanged-program
#!/usr/bin/env wrapperl
print "using perl $^X\n";
print "$_\n" for @INC;

shell$ ./hashbanged-program
using perl '/path/to/bin/perl', @INC contains:
- '/path/to/another/lib/i686-linux'
- '/path/to/another/lib'
- '/path/to/some/lib/i686-linux'
- '/path/to/some/lib'
- '/path/to/lib/site_perl/5.18.1/i686-linux'
- '/path/to/lib/site_perl/5.18.1'
- '/path/to/lib/5.18.1/i686-linux'
- '/path/to/lib/5.18.1'
- '.'

DESCRIPTION

This program lets you wrap a perl program with some local-specific configurations.

Why would you do this, e.g. as opposed to modifying the hash-bang line or setting PERL5LIB, or calling the perl executable directly? Well, lazyness of course, but also the fact that in different environments the same program might need different configurations, and changing those configurations possibly in many little Perl programs quickly becomes an error-prone hassle.

wrapperl provides you with a consistent, minimal and easy to setup way to concentrate local-specific configurations in the “The wrapperl.env File”, and be sure that you will call your Perl program(s) with the right setup every time.

wrapperl’s behaviour strongly depends on its name. That is, if you leave it as wrapperl it behaves in a specific way, while if you name it differently then it does something else.

You have several options to do call wrapperl with a different name:

The following sections start by describing the wrapperl.env file you should set up, then describe the behaviour in the different conditions; among them, most probably you will be interested into “Named Something Else”.

The wrapperl.env File

The wrapperl.env file is at the heart of the localization of your configurations.

Contents

The file is a standard Perl program. It will be called using whatever default perl is found, that is not what you are looking for most probably (otherwise you would probably not be using wrapperl at all). You can do whatever setting inside it, while most probably you will be interested in setting the environment variable PERL5LIB to point towards the library directories you want to include in @INC, and also set the right Perl executable to use.

You can affect how wrapperl works by calling the following functions from within a wrapperl.env file (you should normally only need the first two anyway):

Loading

The wrapperl.env file is loaded via a do, so you are warned about any possible security issue.

The invocation is supposed to return a true value (in Perl terms), otherwise the execution will be stopped.

Position

Depending on how wrapperl is called, the wrapperl.env file is searched in different locations.

One or more starting positions will be considered, and used to perform a search from that position upwards in the filesystem. For example, if the starting point is /path/to/some/internal/sub, then the following paths will be searched for wrapperl.env:

/path/to/some/internal/sub
/path/to/some/internal
/path/to/some
/path/to
/path
/

An exception is thrown if no wrapperl.env file is found during the search in all the starting points.

The standard resolution of the wrapperl.env file is performed starting from the current working directory, then from the user’s home directory as read from the HOME environment variable.

In some cases, the starting position will be some other specific location. For example, when wrapperl is “Named Something Else”, the only starting location will be the path to the link to wrapperl, (i.e. what is used to initialize $ME).

Direct Invocation

Direct invocation of wrapperl (i.e. without changing the name when calling it) is subject to the processing of some options (see “OPTIONS”).

Unless otherwise noted, the resolution of the wrapperl.env file is the standard one as described in section “Position”.

If none of the options in “OPTIONS” is recognized, the selected perl via PERL() is invoked with whatever argument list is provided. This is equivalent to using the -x|--exec option, except that the first option is not stripped away in this case and also that the first item in the command line list is assumed to be the path to a program and its path will be used as the starting position for wrapperl.env location resolution.

Option -d|--doc helps you call perldoc, or whatever is set in $PERLDOC. This will be useful in order to use the perldoc that is shipped with the selected $PERL, and more importantly with the same options (e.g. PERL5LIB) set in wrapperl.env, so that you will be able to find whatever module is installed in your personalized paths.

Option -e|--env helps you find out what will be the wrapperl.env used, so that you can double check that it is the one you are expecting and its contents. If you also pass a path in the command line, it will be used as the starting point for searching wrapperl.env, otherwise the standard resolution process is used.

Option -s|--sibling allows you to call one of the Perl programs that are present in the same directory as $PERL, much in the same way as described for perldoc above. For example, if you want to check the POD documentation in YourModule.pm using the podchecker that is shipped with the perl you indicated in wrapperl.env:

shell$ wrapperl -s podchecker

Last, option -x|--exec allows you to call $PERL with the options set in wrapperl.env (where the resolution process starts from the current directory or from the HOME directory).

Named perl

This name makes wrapperl transform into a call to what set as PERL(), including any command line option provided.

The resolution of the wrapperl.env file is performed according to the standard resolution process explained in section “Position”, starting from the location of the symbolic link.

Named

This name calls the perldoc set via PERLDOC() and located in the same directory as what set via PERL(), including any command line option provided. The behaviour is the same as calling wrapperl with option -d|--doc, with the exception of the resolution process.

The resolution of the wrapperl.env file is performed according to the standard resolution process explained in section “Position”, starting from the location of the symbolic link.

Named Something Else

If your system(s) have /usr/bin/env and you can put wrapperl somewhere in the PATH, just set the hash-bang to:

#!/usr/bin/env wrapperl

and you’re done. If not, read on.

Assuming that you have set up your wrapperl.env file (see “The wrapperl.env File”), you are only two steps away from using wrapperl to automate calling your program with the right setup:

This is really it! Now, every time you need to run your program… don’t do it, execute the wrapperl copy instead! That is, in the example you would call prg, and it would in turn call your prg.pl but after reading all the configurations in wrapperl.env.

See “TL;DR” for a complete and commented example.

OPTIONS

When invoked with name wrapperl, this program supports the following options. Note that you can provide one of them as the first option, and anyone not appearing here will actually be used for invoking the perl indicated in the wrapperl.env file.

In all the options below, unless otherwise noted, the standard resolution process for searching wrapperl.env is used (see “Position”).

DIAGNOSTICS

CONFIGURATION AND ENVIRONMENT

wrapperl does not have a configuration per-se, but is of course relying on the presence of a wrapperl.env file for proper functioning - see “DESCRIPTION”.

DEPENDENCIES

wrapperl relies on modules that are part of any standard Perl distribution as of release 5.6.0.

BUGS AND LIMITATIONS

Please report bugs and hopefully solutions through the GitHub repository at https://github.com/polettix/wrapperl.

AUTHOR

Flavio Poletti polettix@cpan.org

LICENSE AND COPYRIGHT

Copyright (c) 2015, Flavio Poletti polettix@cpan.org.

This module is free software. You can redistribute it and/or modify it under the terms of the Artistic License 2.0. Please read the full license in the LICENSE file inside the distribution, as you can find at https://github.com/polettix/wrapperl.

This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.