App::plx - Perl Layout Executor

      plx --help                             # This output

      plx --init <perl>                      # Initialize layout config
      plx --perl                             # Show layout perl binary
      plx --libs                             # Show layout $PERL5LIB entries
      plx --paths                            # Show layout additional $PATH entries
      plx --env                              # Show layout env var changes
      plx --cpanm -llocal --installdeps .    # Run cpanm from outside $PATH
      plx perl <args>                        # Run perl within layout
      plx -E '...'                           # (ditto)
      plx script-in-dev <args>               # Run dev/ script within layout
      plx script-in-bin <args>               # Run bin/ script within layout
      plx ./script <args>                    # Run script within layout
      plx script/in/cwd <args>               # (ditto)
      plx program <args>                     # Run program from layout $PATH

    While perl has many tools for configuring per-project development
    environments, using them can still be a little on the lumpy side. With
    Carton, you find yourself running one of

      perl -Ilocal/lib/perl -Ilib bin/myapp
      carton exec perl -Ilib bin/myapp

    With App::perlbrew,

      perlbrew switch perl-5.28.0@libname
      perl -Ilib bin/myapp

    With <>,

      plenv exec perl -Ilib bin/myapp

    and if you have more than one distinct layer of dependencies, while
    local::lib will happily handle that, integrating it with everything else
    becomes a pain in the buttocks.

    As a result of this, your not-so-humble author found himself regularly
    having a miniature perl executor script at the root of git clones that
    looked something like:

      eval $(perl -Mlocal::lib=--deactivate-all)
      export PERL5LIB=$PWD/local/lib/perl5
      ~/perl5/perlbrew/perls/perl-5.28.0/bin/$bin "$@"

    and then running:

      ./pl perl -Ilib bin/myapp

    However, much like back in 2007 frustration with explaining to other
    developers how to set up CPAN to install into "~/perl5" and how to set
    up one's environment variables to then find the modules so installed led
    to the exercise in rage driven development that first created
    local::lib, walking newbies through the creation and subsequent use of
    such a script was not the most enjoyable experience for anybody

    Thus, the creation of this module to reduce the setup process to:

      cpanm App::plx
      cd MyProject
      plx --init 5.28.0
      plx --cpanm -llocal --notest --installdeps .

    Follwed by being able to immediately (and even more concisely) run:

      plx myapp

    which will execute "perl -Ilib bin/myapp" with the correct "perl" and
    the relevant local::lib already in scope.

    If this seems of use to you, the "QUICKSTART" is next and the "ACTIONS"
    section of this document lists the full capabilities of plx. Onwards!

    Let's assume we're going to be working on Foo-Bar, so we start with:

      git clone
      cd Foo-Bar

    Assuming the perl we'd get from running just "perl" suffices, then we
    next run:

      plx --init

    If we want a different perl - say, we have a "perl5.30.1" in our path,
    or a "perl-5.30.1" built in perlbrew, we'd instead run:

      plx --init 5.30.1

    To quickly get our dependencies available, we then run:

      plx --cpanm -llocal --notest --installdeps .

    If the project is designed to use Carton and has a "cpanfile.snapshot",
    instead we would run:

      plx --cpanm -ldevel --notest Carton
      plx carton install

    If the goal is to test this against our current development version of
    another library, then we'd also want to run:

      plx --config libspec add 40otherlib.dir ../Other-Lib/lib

    If we want our ~/perl local::lib available within the plx environment,
    we can add that as the least significant libspec with:

      plx --config libspec add 00tilde.ll $HOME/perl5

    At which point, we're ready to go, and can run:

      plx myapp              # to run bin/myapp
      plx t/foo.t            # to run one test file
      plx prove              # to run all t/*.t test files
      plx -E 'say for @INC'  # to run a one liner within the layout

    To learn everything else plx is capable of, read on to the "ACTIONS"
    section coming next.

    Have fun!

    Under normal circumstances, one would run something like:

      cpanm App::plx

    However, if you want a self-contained plx script without having a cpan
    installer available, you can run:

      mkdir bin
      wget -O bin/plx

    to get the current latest packed version.

    The packed version bundles local::lib and File::Which, and also includes
    a modified "--cpanm" action that uses an inline "App::cpanminus".

    "plx" actions that execute external commands all clear any existing
    environment variables that start with "PERL" to keep an encapsulated
    setup for commands being run within the layouts - and also set
    "PERL5OPT" to exclude "site_perl" (but not "vendor_perl") to avoid
    locally installed modules causing unexpected effects.

    Having done so, "plx" then loads each env config entry and sets those
    variables - then prepends the "plx" specific entries to both "PATH" and
    "PERL5LIB". You can add env config entries with "--config":

      plx --config env add NAME VALUE

    The changes that will be made to your environment can be output by
    calling the "--env" command.

    Additionally, environment variable overrides may be provided to the
    "--cmd", "--exec" and "--perl" commands by providing them in
    "NAME=VALUE" format:

      # do not do this, it will be deleted
      PERL_RL=Perl5 plx <something>

      # do this instead, it will provide the environment variable to the command
      plx PERL_RL=Perl5 <something>

      plx --help                             # Print synopsis
      plx --version                          # Print plx version

      plx --init <perl>                      # Initialize layout config for .
      plx --bareinit <perl>                  # Initialize bare layout config for .
      plx --base                             # Show layout base dir 
      plx --base <base> <action> <args>      # Run action with specified base dir
      plx --perl                             # Show layout perl binary
      plx --libs                             # Show layout $PERL5LIB entries
      plx --paths                            # Show layout additional $PATH entries
      plx --env                              # Show layout env var changes
      plx --cpanm -llocal --installdeps .    # Run cpanm from outside $PATH

      plx --config perl                      # Show perl binary
      plx --config perl set /path/to/perl    # Select exact perl binary
      plx --config perl set perl-5.xx.y      # Select perl via $PATH or perlbrew

      plx --config libspec                   # Show lib specifications
      plx --config libspec add <name> <path> # Add lib specification
      plx --config libspec del <name> <path> # Delete lib specification
      plx --config env                       # Show additional env vars
      plx --config env add <name> <path>     # Add env var
      plx --config env del <name> <path>     # Delete env var

      plx --exec <cmd> <args>                # exec()s with env vars set
      plx --perl <args>                      # Run perl with args

      plx --cmd <cmd> <args>                 # DWIM command:
        cmd = perl           -> --perl <args>
        cmd = -<flag>        -> --perl -<flag> <args>
        cmd = some/file      -> --perl some/file <args>
        cmd = ./file         -> --perl ./file <args>
        cmd = name ->
          exists .plx/cmd/<name> -> --perl .plx/cmd/<name> <args>
          exists dev/<name>      -> --perl dev/<name> <args>
          exists bin/<name>      -> --perl bin/<name> <args>
          else                   -> --exec <name> <args>

      plx --which <cmd>                      # Expands --cmd <cmd> without running
      plx <something> <args>                 # Shorthand for plx --cmd
      plx --commands <filter>?               # List available commands
      plx --multi [ <cmd1> <args1> ] [ ... ] # Run multiple actions
      plx --showmulti [ ... ] [ ... ]        # Show multiple action running
      plx [ ... ] [ ... ]                    # Shorthand for plx --multi
      plx --userinit <perl>                  # Init ~/.plx with ~/perl5 ll
      plx --installself                      # Installs plx and cpanm into layout
      plx --installenv                       # Appends plx --env call to .bashrc
      plx --userstrap <perl>                 # userinit+installself+installenv

    Prints out the usage information (i.e. the "SYNOPSIS") for plx.

      plx --init                     # resolve 'perl' in $PATH
      plx --init perl                # (ditto)
      plx --init 5.28.0              # looks for perl5.28.0 in $PATH
                                     # or perl-5.28.0 in perlbrew
      plx --init /path/to/some/perl  # uses the absolute path directly

    Initializes the layout.

    If a perl name is passed, attempts to resolve it via $PATH and
    "perlbrew" and sets the result as the layout perl; if not looks for just

    Creates the following libspec config:

      25-local.ll  local
      50-devel.ll  devel
      75-lib.dir   lib

    Identical to "--init" but creates no default configs except for "perl".

      plx --base
      plx --base <base> <action> <args>

    Without arguments, shows the selected base dir - "plx" finds this by
    checking for a ".plx" directory in the current directory, and if not
    tries the parent directory, recursively. The search stops either when
    "plx" finds a ".git" directory, to avoid accidentally escaping a project
    repository, or at the last directory before the root - i.e. "plx" will
    test "/home" but not "/".

    With arguments, specifies a base dir to use, and then invokes the rest
    of the arguments with that base dir selected - so for example one can
    make a default configuration in $HOME available as "plh" by running:

      plx --init $HOME
      alias plh='plx --base $HOME'

    Prints the directories that will be added to "PERL5LIB", one per line.

    These will include the "lib/perl5" subdirectory for each "ll" entry in
    the libspecs, and the directory for each "dir" entry.

    Prints the directories that will be added to "PATH", one per line.

    These will include the containing directory of the environment's perl
    binary if not already in "PATH", followed by the "bin" directories of
    any "ll" entries in the libspecs.

    Prints the changes that will be made to your environment variables, in a
    syntax that is (hopefully) correct for your current shell.

      plx --cpanm -Llocal --installdeps .
      plx --cpanm -ldevel App::Ack

    Finds the "cpanm" binary in the "PATH" that "plx" was executed *from*,
    and executes it using the layout's perl binary and environment

    Requires the user to specify a local::lib to install into via "-l" or
    "-L" in order to avoid installing modules into unexpected places.

    Note that this action exists primarily for bootstrapping, and if you
    want to use a different installer such as App::cpm, you'd install it

      plx --cpanm -ldevel App::cpm

    and then subsequently run e.g.

      plx cpm install App::Ack

    to install modules.

      plx --exec <command> <args>

    Sets up the layout's environment variables and "exec"s the command.

      plx --perl
      plx --perl <options> <script> <args>

    Without arguments, sugar for "--config perl".

    Otherwise, sets up the layout's environment variables and "exec"s the
    layout's perl with the given options and arguments.

      plx --cmd <cmd> <args>
        cmd = perl           -> --perl <args>
        cmd = -<flag>        -> --perl -<flag> <args>
        cmd = some/file      -> --perl some/file <args>
        cmd = ./file         -> --perl ./file <args>
        cmd = name ->
          exists .plx/cmd/<name> -> --perl .plx/cmd/<name> <args>
          exists dev/<name>      -> --perl dev/<name> <args>
          exists bin/<name>      -> --perl bin/<name> <args>
          else                   -> --exec <name> <args>

    Note: Much like the "devel" local::lib is created to allow for the
    installation of out-of-band dependencies that aren't going to be needed
    in production, the "dev" directory is supported to allow for the easy
    addition of development time only sugar commands. Note that since "perl"
    will re-exec anything with a non-perl shebang, one can add wrappers here

      $ cat dev/prove
      exec prove -j8 "$@"

      plx --which <cmd>

    Outputs the expanded form of a "--cmd" invocation without running it.

      plx --config                     # Show current config
      plx --config <name>              # Show current <name> config
      plx --config <name> <operation>  # Invoke config operation

      plx --config perl
      plx --config perl set <spec>

    If the spec passed to "set" contains a "/" character, plx assumes that
    it's an absolute bath and records it as-is.

    If not, we go a-hunting.

    First, if the spec begins with a 5, we replace it with "perl5".

    Second, we search $PATH for a binary of that name, and record it if so.

    Third, if the (current) spec begins "perl5", we replace it with

    Fourth, we search $PATH for a "perlbrew" binary, and ask it if it has a
    perl named after the spec, and record that if so.

    Fifth, we shrug and hope the user can come up with an absolute path next

    Note: The original spec passed to "set" is recorded in ".plx/perl.spec",
    so if you intend to share the ".plx" directory across multiple machines
    via version control or otherwise, remove/exclude the ".plx/perl" file
    and plx will automatically attempt to re-locate the perl on first

      plx --config libspec
      plx --config libspec add <name> <spec>
      plx --config libspec del <name> <spec>

    A libspec config entry consists of a name and a spec, and the show
    output prints them space separated one per line, with enough spaces to
    make the specs align:

      25-local.ll  local
      50-devel.ll  devel
      75-lib.dir   lib

    The part of the name before the last "." is not semantically significant
    to plx, but is used for asciibetical sorting of the libspec entries to
    determine in which order to apply them.

    The part after must be either "ll" for a local::lib, or "dir" for a bare
    lib directory.

    When loaded, the spec is (if relative) resolved to an absolute path
    relative to the layout root, then all ".." entries and symlinks resolved
    to give a final path used to set up the layout environment.

      plx --config env
      plx --config env add <name> <value>
      plx --config env del <name> <value>

    Manages additional environment variables, which are set immediately
    before any environment changes required for the current "libspec" and
    "perl" settings are processed.

      plx --commands         # all commands
      plx --commands c       # all commands starting with c
      plx --commands /json/  # all commands matching /json/

    Lists available commands, name first, then full path.

    If a filter argument is given, treats it as a fixed prefix to filter the
    command list, unless the filter is "/re/" in which case the slashes are
    stripped and the filter is treated as a regexp.

      plx --multi [ --init ] [ --config perl set 5.28.0 ]

    Runs multiple plx commands from a single invocation delimited by "[ ...

      plx --showmulti [ --init ] [ --config perl set 5.28.0 ]

    Outputs approximate plx invocations that would be run by "--multi".

    Same as "--init" but assumes $HOME as base and sets up only a single
    libspec pointing at "$HOME/perl5".

    Installs App::plx and App::cpanminus into the highest-numbered
    local::lib within the layout.

    (bash only currently)

    Appends an eval line to set up the layout environment to the user's

    Convenience command for "--userinit" plus "--installself" plus

     mst - Matt S. Trout (cpan:MSTROUT) <>

    None yet - maybe this software is perfect! (ahahahahahahahahaha)

    Copyright (c) 2020 the App::plx "AUTHOR" and "CONTRIBUTORS" as listed

    This library is free software and may be distributed under the same
    terms as perl itself.