NAME
Venus::Run - Run Class
ABSTRACT
Run Class for Perl 5
SYNOPSIS
package main;
use Venus::Run;
my $run = Venus::Run->new;
# bless({...}, 'Venus::Run')
DESCRIPTION
This package provides a modular command execution framework for Perl projects. It loads a configuration with commands, aliases, scripts, variables, and paths, and resolves them into full shell commands. This allows you to define reusable CLI behaviors using declarative config without writing wrappers or shell scripts. It supports layered configuration, caching, variable expansion, and recursive resolution, with support for custom flow control, Perl module injection, and user prompts. It also resets the PATH and PERL5LIB variables where appropriate. See vns for an executable file which loads this package and provides the CLI. See "FEATURES" for usage and configuration information.
Environment variables:
VENUS_FILE- Explicitly set the config file for Venus::Run (and vns).VENUS_RUN_FILE- Alias forVENUS_FILE.VENUS_RUN_CONFIG- Alias forVENUS_FILE.VENUS_RUN_DEBUG- Enable debugging in Venus::Run (and vns).
ATTRIBUTES
This package has the following attributes:
cache
cache(hashref $data) (hashref)
The cache attribute is used to store resolved values and avoid redundant computation during command expansion.
Since 4.15
- cache example 1
-
package main; use Venus::Run; my $run = Venus::Run->new; my $cache = $run->cache; # {}
config
config(hashref $data) (hashref)
The config attribute is used to store the configuration used to resolve commands, variables, paths, and other runtime behavior.
Since 4.15
- config example 1
-
package main; use Venus::Run; my $run = Venus::Run->new; my $config = $run->config; # {...}
debug
debug(boolean $data) (boolean)
The debug attribute is used to determine whether to output additional content for the purpose of debugging command execution.
Since 4.15
- debug example 1
-
package main; use Venus::Run; my $run = Venus::Run->new; my $debug = $run->debug; # false
handler
handler(coderef $data) (coderef)
The handler attribute holds the callback (i.e. coderef) invoked for each step or command returned for a resolved command or expression.
Since 4.15
- handler example 1
-
package main; use Venus::Run; my $run = Venus::Run->new; my $handler = $run->handler; # sub {...}
INHERITS
This package inherits behaviors from:
INTEGRATES
This package integrates behaviors from:
METHODS
This package provides the following methods:
callback
callback(coderef $code, any @args) (any)
The callback method executes a against each fully-resolved command derived from the given arguments. This method prepares the runtime environment by expanding variables, updating paths, and loading libraries as defined in the config. It resolves the given arguments into executable commands and passes each one to the callback in sequence. The callback receives the resolved program name followed by its arguments. Environment variables are restored to their original state after execution. Returns the result of the last successful callback execution, or undef if none were executed.
Since 4.15
- callback example 1
-
package main; use Venus::Run; my $run = Venus::Run->new; my $callback = $run->callback; # undef
- callback example 2
-
package main; use Venus::Run; my $run = Venus::Run->new; my $data; $run->config({ exec => { info => 'perl -V', }, libs => [ '-Ilib', '-Ilocal/lib/perl5', ], perl => { perl => 'perl', }, }); my $callback = $run->callback(sub{join ' ', @_}, 'info'); # perl -Ilib -Ilocal/lib/perl5 -V
execute
execute(any @args) (any)
The execute method "resolves" the argument(s) provided and executes "callback" using the "handler" for each fully-resolved command encountered.
Since 4.15
- execute example 1
-
package main; use Venus::Run; my $run = Venus::Run->new; my $execute = $run->execute; # undef
- execute example 2
-
package main; use Venus::Run; my $run = Venus::Run->new; $run->handler(sub{join ' ', @_}); my $execute = $run->execute('perl'); # ['perl']
- execute example 3
-
package main; use Venus::Run; my $run = Venus::Run->new; $run->config({ exec => { info => 'perl -V', }, libs => [ '-Ilib', '-Ilocal/lib/perl5', ], perl => { perl => 'perl', }, }); $run->handler(sub{join ' ', @_}); my $execute = $run->execute('info'); # ['perl', "'-Ilib'", "'-Ilocal/lib/perl5'", "'-V'"]
new
new(any @args) (Venus::Run)
The new method constructs an instance of the package.
Since 4.15
- new example 2
-
package main; use Venus; use Venus::Run; my $run = Venus::Run->new(debug => true); # bless({...}, 'Venus::Run')
- new example 3
-
package main; use Venus; use Venus::Run; my $run = Venus::Run->new(debug => false, handler => sub {}); # bless({...}, 'Venus::Run')
resolve
resolve(hashref $config, any @data) (arrayref)
The resolve method expands a given item or command by recursively resolving aliases, variables, and configuration entries into a full command string or array. This method returns a list in list context.
Since 4.15
- resolve example 1
-
package main; use Venus::Run; my $run = Venus::Run->new; my $resolve = $run->resolve; # []
- resolve example 2
-
package main; use Venus::Run; my $run = Venus::Run->new; my $resolve = $run->resolve({}, 'perl'); # [['perl']]
- resolve example 3
-
package main; use Venus::Run; my $run = Venus::Run->new; my $config = {find => {perl => '/path/to/perl'}}; my $resolve = $run->resolve($config, 'perl -c'); # [['/path/to/perl', "'-c'"]]
- resolve example 4
-
package main; use Venus::Run; my $run = Venus::Run->new; my $config = { exec => { info => 'perl -V', }, libs => [ '-Ilib', '-Ilocal/lib/perl5', ], perl => { perl => 'perl', }, }; my $resolve = $run->resolve($config, 'info'); # [['perl', "'-Ilib'", "'-Ilocal/lib/perl5'", "'-V'"]]
- resolve example 5
-
package main; use Venus::Run; my $run = Venus::Run->new; my $config = { exec => { info => 'perl -V', }, libs => [ '-Ilib', '-Ilocal/lib/perl5', ], load => [ '-MVenus', ], perl => { perl => 'perl', }, }; my $resolve = $run->resolve($config, 'info'); # [['perl', "'-Ilib'", "'-Ilocal/lib/perl5'", "'-MVenus'", "'-V'"]]
- resolve example 6
-
package main; use Venus::Run; my $run = Venus::Run->new; my $config = { exec => { repl => '$REPL', }, libs => [ '-Ilib', '-Ilocal/lib/perl5', ], load => [ '-MVenus', ], perl => { perl => 'perl', }, vars => { REPL => 'perl -dE0', }, }; my $resolve = $run->resolve($config, 'repl'); # [['perl', "'-Ilib'", "'-Ilocal/lib/perl5'", "'-MVenus'", "'-dE0'"]]
- resolve example 7
-
package main; use Venus::Run; my $run = Venus::Run->new; my $config = { exec => { eval => 'shim -E', says => 'eval "map log(eval), @ARGV"', shim => '$PERL -MVenus=true,false,log', }, libs => [ '-Ilib', '-Ilocal/lib/perl5', ], perl => { perl => 'perl', }, vars => { PERL => 'perl', }, }; my $resolve = $run->resolve($config, 'says', 1); # [['perl', "'-Ilib'", "'-Ilocal/lib/perl5'", "'-MVenus=true,false,log'", "'-E'", "\"map log(eval), \@ARGV\"", "'1'"]]
- resolve example 8
-
package main; use Venus::Run; my $run = Venus::Run->new; my $config = { exec => { cpan => 'cpanm -llocal -qn', }, }; my $resolve = $run->resolve($config, 'cpan', 'Venus'); # [['cpanm', "'-llocal'", "'-qn'", "'Venus'"]]
- resolve example 9
-
package main; use Venus::Run; my $run = Venus::Run->new; my $config = { exec => { test => '$PROVE', }, libs => [ '-Ilib', '-Ilocal/lib/perl5', ], perl => { perl => 'perl', prove => 'prove', }, vars => { PROVE => 'prove -j8', }, }; my $resolve = $run->resolve($config, 'test', 't'); # [['prove', "'-Ilib'", "'-Ilocal/lib/perl5'", "'-j8'", "'t'"]]
- resolve example 10
-
package main; use Venus::Run; my $run = Venus::Run->new; my $config = {}; my $resolve = $run->resolve($config, 'echo 1 | less'); # [['echo', "'1'", '|', "'less'"]]
- resolve example 11
-
package main; use Venus::Run; my $run = Venus::Run->new; my $config = {}; my $resolve = $run->resolve($config, 'echo 1 && echo 2'); # [['echo', "'1'", '&&', 'echo', "'2'"]]
- resolve example 12
-
package main; use Venus::Run; my $run = Venus::Run->new; my $config = {}; my $resolve = $run->resolve($config, 'echo 1 || echo 2'); # [['echo', "'1'", '||', 'echo', "'2'"]]
- resolve example 13
-
package main; use Venus::Run; my $run = Venus::Run->from_file('t/conf/from.perl'); # in config # # --- # from: # - /path/to/parent # # ... # # exec: # mypan: cpan -M https://pkg.myapp.com # in config (/path/to/parent) # # --- # exec: # cpan: cpanm -llocal -qn # # ... my $config = $run->prepare_conf($run->config); my $resolve = $run->resolve($config, 'mypan'); # [['cpanm', "'-llocal'", "'-qn'", "'-M'", "'https://pkg.myapp.com'"]]
- resolve example 14
-
package main; use Venus::Run; my $run = Venus::Run->from_file('t/conf/func.perl'); # in config # # --- # with: # psql: /path/to/other # # ... # in config (/path/to/other) # # --- # exec: # backup: pg_backupcluster # restore: pg_restorecluster # # ... my $config = $run->prepare_conf($run->config); my $resolve = $run->resolve($config, 'psql', 'backup'); # [['pg_backupcluster']]
- resolve example 15
-
package main; use Venus::Run; my $run = Venus::Run->from_file('t/conf/psql.perl'); # in config # # --- # exec: # backup: pg_backupcluster # restore: pg_restorecluster # # ... my $config = $run->prepare_conf($run->config); my $resolve = $run->resolve($config, 'backup'); # [['pg_backupcluster']]
- resolve example 16
-
package main; use Venus::Run; my $run = Venus::Run->from_file('t/conf/flow.perl'); # in config # # --- # exec: # cpan: cpanm -llocal -qn # # ... # # flow: # setup-term: # - cpan Term::ReadKey # - cpan Term::ReadLine::Gnu # # ... my $config = $run->prepare_conf($run->config); my $resolve = $run->resolve($config, 'setup-term'); # [ # ['cpanm', "'-llocal'", "'-qn'", "'Term::ReadKey'"], # ['cpanm', "'-llocal'", "'-qn'", "'Term::ReadLine::Gnu'"], # ]
- resolve example 17
-
package main; use Venus::Run; my $run = Venus::Run->from_file('t/conf/asks.perl'); # in config # # --- # asks: # PASS: What's the password # # ... my $config = $run->prepare_vars($run->prepare_conf($run->config)); my $resolve = $run->resolve($config, 'echo', '$PASS'); # [['echo', "'secret'"]]
- resolve example 18
-
package main; use Venus::Run; my $run = Venus::Run->from_file('t/conf/with.perl'); # in config # # --- # with: # psql: /path/to/other # # ... # in config (/path/to/other) # # --- # exec: # backup: pg_backupcluster # restore: pg_restorecluster # # ... my $config = $run->prepare_conf($run->config); my $resolve = $run->resolve($config, 'psql', 'backup'); # [['pg_backupcluster']]
- resolve example 19
-
package main; use Venus::Run; my $run = Venus::Run->from_file('t/conf/when.perl'); # in config # # --- # exec: # name: echo $OSNAME # # ... # when: # is_lin: # data: # OSNAME: LINUX # is_win: # data: # OSNAME: WINDOWS # # ... # assume Linux OS my $config = $run->prepare_vars($run->prepare_conf($run->config)); my $resolve = $run->resolve($config, 'name'); # [['echo', "'LINUX'"]]
- resolve example 20
-
package main; use Venus::Run; my $run = Venus::Run->from_file('t/conf/when.perl'); # in config # # --- # exec: # name: echo $OSNAME # # ... # when: # is_lin: # data: # OSNAME: LINUX # is_win: # data: # OSNAME: WINDOWS # # ... # assume Windows OS my $config = $run->prepare_vars($run->prepare_conf($run->config)); my $resolve = $run->resolve($config, 'name'); # [['echo', "'WINDOWS'"]]
result
result(any @args) (any)
The result method is an alias for the "execute" method, which executes the the "handler" for each fully-resolved command based on the arguments provided.
Since 4.15
- result example 1
-
package main; use Venus::Run; my $run = Venus::Run->new; my $result = $run->result; # undef
- result example 2
-
package main; use Venus::Run; my $run = Venus::Run->new; $run->handler(sub{join ' ', @_}); my $result = $run->result('perl'); # ['perl']
- result example 3
-
package main; use Venus::Run; my $run = Venus::Run->new; $run->config({ exec => { info => 'perl -V', }, libs => [ '-Ilib', '-Ilocal/lib/perl5', ], perl => { perl => 'perl', }, }); $run->handler(sub{join ' ', @_}); my $result = $run->result('info'); # ['perl', "'-Ilib'", "'-Ilocal/lib/perl5'", "'-V'"]
FEATURES
This package provides the following features:
- config
-
config(hashref $data) (hashref)The CLI provided by this package operates on a configuration file, typically having a base name of
.vnswith a Perl, JSON, or YAML file extension. Here is an example of a configuration file using YAML with the filename.vns.yaml.--- exec: cpan: cpanm -llocal -qn okay: $PERL -c repl: $PERL -dE0 says: $PERL -E "map log(eval), @ARGV" test: $PROVE libs: - -Ilib - -Ilocal/lib/perl5 load: - -MVenus=true,false path: - ./bin - ./dev - -Ilocal/bin perl: perl: perl prove: prove vars: PERL: perl PROVE: proveSince
4.15example 1
package main; use Venus::Run; my $run = Venus::Run->new; my $config = $run->config; # {...}
- config: asks
-
--- asks: HOME: Enter your home dirThe configuration file's
askssection provides a list of key/value pairs where the key is the name of the environment variable and the value is used as the message used by the CLI to prompt for input if the environment variable is not defined.
- config: data
-
--- data: VENUS_DEBUG: trueThe configuration file's
datasection provides a non-dynamic list of key/value pairs that will be used as environment variables.
- config: exec
-
--- exec: okay: $PERL -cThe configuration file's
execsection provides the main dynamic tasks which can be recursively resolved and expanded.
- config: find
-
--- find: cpanm: /usr/local/bin/cpanmThe configuration file's
findsection provides aliases which can be recursively resolved and expanded for use in other tasks.
- config: flow
-
--- flow: deps: - cpan Term::ReadKey - cpan Term::ReadLine::GnuThe configuration file's
flowsection provides chainable tasks which are recursively resolved and expanded from other tasks.
- config: from
-
--- from: - /usr/share/vns/.vns.yamlThe configuration file's
fromsection provides paths to other configuration files which will be merged before execution allowing the inheritance of of configuration values.
- config: func
-
--- func: psql: ./psql-tools/.vns.ymlThe configuration file's
funcsection provides a list of static key/value pairs where the key is the "subcommand" passed to the runner as the first arugment, and the value is the configuration file where the subcommand task definitions are defined which the runner dispatches to. The differs from thewithsection commands in that the runner doesn't"chdir"|perlfunc/chdirinto the configuration root before executing commands. When executed, the following environment variables are set.Environment variables:
VENUS_RUN_FROM_ROOT- The$VENUS_FILEroot directory.VENUS_RUN_FROM_FILE- The$VENUS_FILEconfiguration file path.VENUS_RUN_FUNC_ROOT- The "func" configuration file root directory.VENUS_RUN_FUNC_FILE- The "func" configuration file path.
- config: libs
-
--- libs: - -Ilib - -Ilocal/lib/perl5The configuration file's
libssection provides a list of-I/path/to/lib"include" statements that will be automatically added to tasks expanded from theperlsection.
- config: load
-
--- load: - -MVenus=true,falseThe configuration file's
loadsection provides a list of-MPackage"import" statements that will be automatically added to tasks expanded from theperlsection.
- config: path
-
--- path: - ./bin - ./dev - -Ilocal/binThe configuration file's
pathsection provides a list of paths to be prepended to thePATHenvironment variable which allows programs to be found.
- config: perl
-
--- perl: perl: perlThe configuration file's
perlsection provides the dynamic perl tasks which can serve as tasks with default commands (with options) and which can be recursively resolved and expanded.
- config: task
-
--- task: setup: $PERL -MMyApp::Task::Setup -E0 --The configuration file's
tasksection provides the dynamic perl tasks which "load" Venus::Task derived packages, and which can be recursively resolved and expanded. These tasks will typically take the form ofperl -Ilib -MMyApp::Task -E0 --and will be automatically executed as a CLI.
- config: vars
-
--- vars: PERL: perlThe configuration file's
varssection provides a list of dynamic key/value pairs that can be recursively resolved and expanded and will be used as environment variables.
- config: when
-
--- when: is_lin: data: OSNAME: LINUX is_win: data: OSNAME: WINDOWSThe configuration file's
whensection provides a configuration tree to be merged with the existing configuration based on the name current operating system. Theis_$namekey should correspond to one of the types specified by "type" in Venus::Os.
- config: with
-
--- with: psql: ./psql-tools/.vns.ymlThe configuration file's
withsection provides a list of static key/value pairs where the key is the "subcommand" passed to the runner as the first arugment, and the value is the configuration file where the subcommand task definitions are defined which the runner dispatches to. The differs from thefuncsection commands in that the runner will"chdir"|perlfunc/chdirinto the configuration root before executing commands. When executed, the following environment variables are set.Environment variables:
VENUS_RUN_FROM_ROOT- The$VENUS_FILEroot directory.VENUS_RUN_FROM_FILE- The$VENUS_FILEconfiguration file path.VENUS_RUN_WITH_ROOT- The "with" configuration file root directory.VENUS_RUN_WITH_FILE- The "with" configuration file path.
- runner: vns
-
Here are example usages of the configuration file mentioned, executed by the vns CLI, which is an executable file which loads this package.
# Mint a new configuration file vns new pl # Mint a new JSON configuration file vns new json # Mint a new YAML configuration file vns new yaml # Install a distribution vns cpan $DIST # i.e. # cpanm --llocal -qn $DIST # Check that a package can be compiled vns okay $FILE # i.e. # perl -Ilib -Ilocal/lib/perl5 -c $FILE # Use the Perl debugger as a REPL vns repl # i.e. # perl -Ilib -Ilocal/lib/perl5 -dE0 # Evaluate arbitrary Perl expressions vns exec ... # i.e. # perl -Ilib -Ilocal/lib/perl5 -MVenus=log -E $@ # Test the Perl project in the CWD vns test t # i.e. # prove -Ilib -Ilocal/lib/perl5 t
AUTHORS
Awncorp, awncorp@cpan.org
LICENSE
Copyright (C) 2022, Awncorp, awncorp@cpan.org.
This program is free software, you can redistribute it and/or modify it under the terms of the Apache license version 2.0.