civicrm / cv

CiviCRM CLI Utility
28 stars 30 forks source link

Allow arguments to be passed to the script command 'cv scr' #143

Closed aydun closed 1 year ago

aydun commented 1 year ago

If cv scr is called with arguments like this:

cv scr myscript.php arg1 arg2 ...

myscript.php will have $argv = ['arg1', 'arg2']

Quoted args are passed through correctly:

cv scr myscript.php one 'two and' three => $argv = ['one', 'two and', 'three']

Options starting with a hyphen can also be passed to the script if -- is used:

cv scr myscript.php -- -a b => $argv = ['-a', 'b']

The superglobal $GLOBAL['argv'] is also available with the full command line but $argv will usually be easier to work with.

artfulrobot commented 1 year ago

I've tested this - it works! I've often stumbled across this problem, it would be great to see this merged.

Many thanks @aydun and @kenahoo

(It's enabled me to make this https://lab.civicrm.org/extensions/taggedlog/-/blob/main/cli/grep.php)

aydun commented 1 year ago

(It's enabled me to make this https://lab.civicrm.org/extensions/taggedlog/-/blob/main/cli/grep.php)

Wow @artfulrobot - that's great to see the feature getting used so quickly.

artfulrobot commented 1 year ago

@aydun I've needed/wanted this so many times before that i finally came here to suggest it as an enhancement, and from there found the original suggestion and your pr. Gotta love sharing code :heart:

totten commented 1 year ago

Oh, yes, this is very nice @aydun. It even has a test! 😃

There was one small catch -- the synthetic $argv was missing the standard 0-th parameter. Compare:

$ php ~/src/cv/tests/Command/hello-args.php one two three
0: /Users/totten/src/cv/tests/Command/hello-args.php
1: one
2: two
3: three
$ cv scr ~/src/cv/tests/Command/hello-args.php one two three
0: one
1: two
2: three

I pushed up a revision to make it match. Unless there's an objection to the change, let's merge.

artfulrobot commented 1 year ago

@totten's change makes $argv and $argc behave in their documented ways, so that's good by me as it's less confusing (even if the first thing I'mma do whenever I use this is array_shift($argv)!).

Let's merge!

aydun commented 1 year ago

Thanks @totten. I realised that if the required script uses a variable called $output, it will overwrite the existing one resulting in errors. This last change prevents that.

totten commented 1 year ago

(even if the first thing I'mma do whenever I use this is array_shift($argv)!).

Some rituals must be preserved.

I realised that if the required script uses a variable called $output ...

Agree, this looks like better isolation now. 👍

artfulrobot commented 1 year ago

Thanks @aydun and @totten :-)

aydun commented 1 year ago

Thanks!

totten commented 1 year ago

(@artfulrobot) (even if the first thing I'mma do whenever I use this is array_shift($argv)!).

This is a bit of tangential rant, but it might be interesting... argv was one of my pet-peeves in scripting. Specifically, the need for impromptu parsing of argv. It doesn't really come up on tiny scripts (eg 20 SLOC; not enough options to worry about parsing them) or full programs (eg 5000+ SLOC; big enough to setup a standalone project and download nice CLI library). But for a certain size in the middle (50-500 SLOC), it's kind of annoying. I don't care to remember how many times I had to write an argv parse-loop for a script in this size-bracket.

Now-a-days, for scripts in that middle-space, I like to pull in "silly"/"clippy". If you understand the synopsis from a typical Unix manpage, then the notation may be familiar. Ex:

## Goal:
myscript [--foo] [-b|--bar=] files*
## Implementation:
$c['app']->main('[--foo] [-b|--bar=] files*', function($io, bool $foo, ?string $bar, array $files) {
  $io->writeln("The foo is " . 
    ($foo ? '<info>ON</info>' : '<error>OFF</error>'));
  $io->writeln("The value of bar is <info>$bar</info>");
  $io->writeln("The files are: " . json_encode($files));
});

In that example, the script accepts --foo, -b=123, -b 123, -b123, --bar 123, --bar=123, and then an open-ended array of filenames. It's definitely nicer thangetopt or an impromptu parse-loop.

Of course, I've only used it for plumbing that's outside of Civi's runtime... it could be that (in this context) the path-of-least-resistence is still writing an argv parser in-situ...

artfulrobot commented 1 year ago

@totten yes, it's frustrating. I like Python's argparse package (but not for php, obvs!)

for php I generally prefer getopt or simply manual because I like a script to be standalone. e.g. reading clippy:

To simplify the workflows for dependency management, the examples use pogo. pogo should be installed in the PATH. Alternatively, you can rework the examples - instead, create a new composer package for each script and run composer require : has needed.

Ugh, no thanks!