NAME
   App::plx - Perl Layout Executor

SYNOPSIS
     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 --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

WHY PLX
   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 <https://github.com/tokuhirom/plenv>,

     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:

     #!/bin/sh
     eval $(perl -Mlocal::lib=--deactivate-all)
     export PERL5LIB=$PWD/local/lib/perl5
     bin=$1
     shift
     ~/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
   involved.

   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!

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

     git clone [email protected]:arthur-nonymous/Foo-Bar.git
     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!

BOOTSTRAP
   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 https://raw.githubusercontent.com/shadowcat-mst/plx/master/bin/plx-packed -O bin/plx

   to get the current latest packed version.

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

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

     plx --init <perl>                      # Initialize 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 --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

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

 --init
     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
   "perl".

   Creates the following libspec config:

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

 --base
     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'

 --libs
   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.

 --paths
   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.

 --cpanm
     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
   variables.

   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
   with:

     plx --cpanm -ldevel App::cpm

   and then subsequently run e.g.

     plx cpm install App::Ack

   to install modules.

 --exec
     plx --exec <command> <args>

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

 --perl
     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.

 --cmd
     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
   ala:

     $ cat dev/prove
     #!/bin/sh
     exec prove -j8 "$@"

 --which
     plx --which <cmd>

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

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

  perl
     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
   "perl-5".

   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
   time.

   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
   invocation.

  libspec
     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.

  env
     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.

 --commands
     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.

AUTHOR
    mst - Matt S. Trout (cpan:MSTROUT) <[email protected]>

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

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

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