#!/usr/bin/perl
use
5.010;
our
$VERSION
=
'0.53'
;
my
%opts
= (
library
=> [],
subcommands
=> [],
);
Getopt::Long::Configure(
'pass_through'
,
'no_permute'
);
GetOptions(
'library|I=s'
=>
$opts
{library},
'help|h|?'
=> \
$opts
{help},
'subcommand|s=s'
=>
$opts
{subcommands},
);
my
$me
= $0;
$me
=~ s!.+/!!;
my
$oscs
=
$opts
{subcommands};
if
(
$opts
{help} || !
@ARGV
&& !
@$oscs
) {
print
<<USAGE;
$me - Run commands (from any Riap function) on the command-line
Usage:
$me --help
$me [common options] <command def> [subcommand] [action]
*Common options* include: '--library' ('-I') to add directory to Perl search dir
(a la Perl's '-I'), can be specified multiple times.
*Command def* is either a single command definition or multiple subcommands
definition. To define a single command, you can specify a Riap function URL
(e.g. '/Foo/Bar/func'). For multiple subcommands, you can specify a Riap package
URL (e.g. '/Foo/Bar/') or a Perl module name (e.g. 'Foo::Bar'), in which case
all functions in the module/package will be listed and added as subcommands.
Alternatively, you can specify each subcommand separately using '--subcommand'
('-s'). For example, the command below specifies two subcommands called 'func1'
and 'altname':
$me -s /Foo/Bar/func1 -s "/Foo/Bar/func2 altname"
*Subcommand* picks a subcommand name, required only when you specify multiple
subcommands. And not required for actions like '--list' and '--version'.
*action* is either '--help' to get help message on the command or subcommand,
'--list' to list subcommands, '--version' to get version, or zero or more
command (function) arguments.
Examples:
List all subcommands (functions) in a module:
$me Foo::Bar -l
Show usage for a subcommand (function):
$me Foo::Bar func1 --help
$me /Foo/Bar/func1 -h
Execute a command and display the result as YAML:
Execute a subcommand:
$me -s "/Foo/Bar/func1 sc1" -s "/Foo/Baz/func1 sc2" sc2 --arg 12
Notes:
* This is just a simple generic front-end for 'Perinci::CmdLine'. For more
options/customizations, use or subclass the module directly.
TODO:
* HTTP authentication parameters
USAGE
exit
0;
}
for
my
$dir
(@{
$opts
{library} }) {
require
lib; lib->
import
(
$dir
) }
my
$cmd
= Perinci::CmdLine->new;
if
(
@ARGV
&& !
@$oscs
) {
my
$url
=
shift
@ARGV
;
my
$type
;
if
(
$url
=~ /\A\w+::(?:\w+)*\z/) {
$url
=~ s!::!/!;
$url
=
"/$url/"
;
$type
=
'package'
;
}
else
{
my
$res
=
$cmd
->_pa->request(
info
=>
$url
);
die
"Can't 'info' $url: $res->[0] - $res->[1]\n"
unless
$res
->[0] == 200;
$type
=
$res
->[2]{type} //
''
;
die
"Please specify URL to a function or package, not '$type': $url\n"
unless
$type
eq
'function'
||
$type
eq
'package'
;
}
$cmd
->url(
$url
);
$cmd
->program_name(
"$me $url"
)
unless
defined
(
$ENV
{PERINCI_CMDLINE_PROGRAM_NAME});
if
(
$type
eq
'package'
) {
my
$res
=
$cmd
->_pa->request(
list
=>
$url
, {
detail
=>1});
die
"Can't 'list' $url: $res->[0] - $res->[1]\n"
unless
$res
->[0] == 200;
my
$scs
= {};
for
my
$e
(@{
$res
->[2]}) {
next
unless
$e
->{type} eq
'function'
;
my
$sub
=
$e
->{uri};
$sub
=~ s!.+/!!;
$scs
->{
$sub
} = {
url
=>
$e
->{uri},
summary
=>
$e
->{summary},
};
}
$cmd
->subcommands(
$scs
);
}
}
elsif
(
@$oscs
) {
my
$scs
= {};
for
my
$item
(
@$oscs
) {
my
(
$url
,
$name
);
if
(
$item
=~ /\s/) {
(
$url
,
$name
) =
split
/\s+/,
$item
, 2;
}
else
{
$url
=
$item
;
my
$i
= 1;
my
$leaf
=
$url
;
$leaf
=~ s!.+/(.+)!$1!;
$leaf
||=
"func"
;
while
(1) {
$name
=
$leaf
. (
$i
> 1 ?
$i
:
""
);
last
unless
$scs
->{
$name
};
$i
++;
}
}
$scs
->{
$name
} = {
url
=>
$url
};
}
$cmd
->subcommands(
$scs
);
}
else
{
die
"BUG: This shouldn't be reached"
;
}
$cmd
->run;