package App::GenPericmdScript;

our $DATE = '2015-07-02'; # DATE
our $VERSION = '0.09'; # VERSION

use 5.010001;
use strict;
use warnings;
use Log::Any '$log';

use Data::Dump qw(dump);
use File::Which;
use String::Indent qw(indent);

use Exporter qw(import);
our @EXPORT_OK = qw(gen_perinci_cmdline_script);

our %SPEC;

sub _pa {
    state $pa = do {
        require Perinci::Access;
        my $pa = Perinci::Access->new;
        $pa;
    };
    $pa;
}

sub _riap_request {
    my ($action, $url, $extras, $main_args) = @_;

    local $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0
        unless $main_args->{ssl_verify_hostname};

    _pa()->request($action => $url, %{$extras // {}});
}

$SPEC{gen_perinci_cmdline_script} = {
    v => 1.1,
    summary => 'Generate Perinci::CmdLine CLI script',
    args => {

        output_file => {
            summary => 'Path to output file',
            schema => ['str*'],
            default => '-',
            cmdline_aliases => { o=>{} },
            tags => ['category:output'],
            'x.schema.entity' => 'filename',
        },
        overwrite => {
            schema => [bool => default => 0],
            summary => 'Whether to overwrite output if previously exists',
            tags => ['category:output'],
        },

        url => {
            summary => 'URL to function (or package, if you have subcommands)',
            schema => 'str*',
            'x.schema.entity' => 'riap_url',
            req => 1,
            pos => 0,
        },
        subcommand => {
            summary => 'Subcommand name followed by colon and function URL',
            description => <<'_',

Optionally, it can be additionally followed by a summary, so:

    NAME:URL[:SUMMARY]

Example (on CLI):

    --subcommand "delete:/My/App/delete_item:Delete an item"

_
            schema => ['array*', of=>'str*'],
            cmdline_aliases => { s=>{} },
        },
        subcommands_from_package_functions => {
            summary => "Form subcommands from functions under package's URL",
            schema => ['bool', is=>1],
            description => <<'_',

This is an alternative to the `subcommand` option. Instead of specifying each
subcommand's name and URL, you can also specify that subcommand names are from
functions under the package URL in `url`. So for example if `url` is `/My/App/`,
hen all functions under `/My/App` are listed first. If the functions are:

    foo
    bar
    baz_qux

then the subcommands become:

    foo => /My/App/foo
    bar => /My/App/bar
    "baz-qux" => /My/App/baz_qux

_
        },
        include_package_functions_match => {
            schema => 're*',
            summary => 'Only include package functions matching this pattern',
            links => [
                'subcommands_from_package_functions',
                'exclude_package_functions_match',
            ],
        },
        exclude_package_functions_match => {
            schema => 're*',
            summary => 'Exclude package functions matching this pattern',
            links => [
                'subcommands_from_package_functions',
                'include_package_functions_match',
            ],
        },
        cmdline => {
            summary => 'Specify module to use',
            schema  => 'str',
            default => 'Perinci::CmdLine::Any',
            'x.schema.entity' => 'modulename',
        },
        prefer_lite => {
            summary => 'Prefer Perinci::CmdLine::Lite backend',
            'summary.alt.bool.not' => 'Prefer Perinci::CmdLine::Classic backend',
            schema  => 'bool',
            default => 1,
        },
        log => {
            summary => 'Will be passed to Perinci::CmdLine constructor',
            schema  => 'bool',
        },
        extra_urls_for_version => {
            summary => 'Will be passed to Perinci::CmdLine constructor',
            schema => ['array*', of=>'str*'],
        },
        default_log_level => {
            schema  => ['str', in=>[qw/trace debug info warn error fatal none/]],
        },
        ssl_verify_hostname => {
            summary => q[If set to 0, will add: $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;' to code],
            schema  => 'bool',
            default => 1,
        },
        snippet_before_instantiate_cmdline => {
            schema => 'str',
        },
        config_filename => {
            summary => 'Will be passed to Perinci::CmdLine constructor',
            schema => 'str',
        },
        load_module => {
            summary => 'Load extra modules',
            schema => ['array', of=>'str*'],
            'x.schema.element_entity' => 'modulename',
        },
        interpreter_path => {
            summary => 'What to put on shebang line',
            schema => 'str',
        },
        script_name => {
            schema => 'str',
        },
        script_version => {
            summary => 'Use this for version number instead',
            schema => 'str',
        },

    },
};
use experimental 'smartmatch'; no warnings 'void'; require List::Util; $SPEC{gen_perinci_cmdline_script} = {args=>{cmdline=>{default=>"Perinci::CmdLine::Any", schema=>["str", {}, {}], summary=>"Specify module to use", "x.schema.entity"=>"modulename"}, config_filename=>{schema=>["str", {}, {}], summary=>"Will be passed to Perinci::CmdLine constructor"}, default_log_level=>{schema=>["str", {in=>["trace", "debug", "info", "warn", "error", "fatal", "none"]}, {}]}, exclude_package_functions_match=>{links=>["subcommands_from_package_functions", "include_package_functions_match"], schema=>["re", {req=>1}, {}], summary=>"Exclude package functions matching this pattern"}, extra_urls_for_version=>{schema=>["array", {of=>"str*", req=>1}, {}], summary=>"Will be passed to Perinci::CmdLine constructor"}, include_package_functions_match=>{links=>["subcommands_from_package_functions", "exclude_package_functions_match"], schema=>["re", {req=>1}, {}], summary=>"Only include package functions matching this pattern"}, interpreter_path=>{schema=>["str", {}, {}], summary=>"What to put on shebang line"}, load_module=>{schema=>["array", {of=>"str*"}, {}], summary=>"Load extra modules", "x.schema.element_entity"=>"modulename"}, log=>{schema=>["bool", {}, {}], summary=>"Will be passed to Perinci::CmdLine constructor"}, output_file=>{cmdline_aliases=>{o=>{}}, default=>"-", schema=>["str", {req=>1}, {}], summary=>"Path to output file", tags=>["category:output"], "x.schema.entity"=>"filename"}, overwrite=>{schema=>["bool", {default=>0}, {}], summary=>"Whether to overwrite output if previously exists", tags=>["category:output"]}, prefer_lite=>{default=>1, schema=>["bool", {}, {}], summary=>"Prefer Perinci::CmdLine::Lite backend", "summary.alt.bool.not"=>"Prefer Perinci::CmdLine::Classic backend"}, script_name=>{schema=>["str", {}, {}]}, script_version=>{schema=>["str", {}, {}], summary=>"Use this for version number instead"}, snippet_before_instantiate_cmdline=>{schema=>["str", {}, {}]}, ssl_verify_hostname=>{default=>1, schema=>["bool", {}, {}], summary=>"If set to 0, will add: \$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;' to code"}, subcommand=>{cmdline_aliases=>{s=>{}}, description=>"\nOptionally, it can be additionally followed by a summary, so:\n\n    NAME:URL[:SUMMARY]\n\nExample (on CLI):\n\n    --subcommand \"delete:/My/App/delete_item:Delete an item\"\n\n", schema=>["array", {of=>"str*", req=>1}, {}], summary=>"Subcommand name followed by colon and function URL"}, subcommands_from_package_functions=>{description=>"\nThis is an alternative to the `subcommand` option. Instead of specifying each\nsubcommand's name and URL, you can also specify that subcommand names are from\nfunctions under the package URL in `url`. So for example if `url` is `/My/App/`,\nhen all functions under `/My/App` are listed first. If the functions are:\n\n    foo\n    bar\n    baz_qux\n\nthen the subcommands become:\n\n    foo => /My/App/foo\n    bar => /My/App/bar\n    \"baz-qux\" => /My/App/baz_qux\n\n", schema=>["bool", {is=>1}, {}], summary=>"Form subcommands from functions under package's URL"}, url=>{pos=>0, req=>1, schema=>["str", {req=>1}, {}], summary=>"URL to function (or package, if you have subcommands)", "x.schema.entity"=>"riap_url"}}, args_as=>"hash", summary=>"Generate Perinci::CmdLine CLI script", v=>1.1, "x.perinci.sub.wrapper.logs"=>[{normalize_schema=>1, validate_args=>1, validate_result=>1}]}; sub gen_perinci_cmdline_script { ## this line is put by Dist::Zilla::Plugin::Rinci::Wrap
    my %args = @_; my $_sahv_dpath = []; my $_w_res = undef; for (sort keys %args) { if (!/\A(-?)\w+(\.\w+)*\z/o) { return [400, "Invalid argument name (please use letters/numbers/underscores only)'$_'"]; } if (!($1 || $_ ~~ ['cmdline','config_filename','default_log_level','exclude_package_functions_match','extra_urls_for_version','include_package_functions_match','interpreter_path','load_module','log','output_file','overwrite','prefer_lite','script_name','script_version','snippet_before_instantiate_cmdline','ssl_verify_hostname','subcommand','subcommands_from_package_functions','url'])) { return [400, "Unknown argument '$_'"]; } } if (exists($args{'cmdline'})) { my $err_cmdline; (!defined($args{'cmdline'}) ? 1 :  ((!ref($args{'cmdline'})) ? 1 : (($err_cmdline //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0))); if ($err_cmdline) { return [400, "Argument 'cmdline' fails validation: $err_cmdline"]; } } else { $args{'cmdline'} //= 'Perinci::CmdLine::Any'; }  if (exists($args{'config_filename'})) { my $err_config_filename; (!defined($args{'config_filename'}) ? 1 :  ((!ref($args{'config_filename'})) ? 1 : (($err_config_filename //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0))); if ($err_config_filename) { return [400, "Argument 'config_filename' fails validation: $err_config_filename"]; } }  if (exists($args{'default_log_level'})) { my $err_default_log_level; (!defined($args{'default_log_level'}) ? 1 :  ((!ref($args{'default_log_level'})) ? 1 : (($err_default_log_level //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0)) && (($args{'default_log_level'} ~~ ["trace","debug","info","warn","error","fatal","none"]) ? 1 : (($err_default_log_level //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Must be one of [\"trace\",\"debug\",\"info\",\"warn\",\"error\",\"fatal\",\"none\"]"),0))); if ($err_default_log_level) { return [400, "Argument 'default_log_level' fails validation: $err_default_log_level"]; } }  if (exists($args{'exclude_package_functions_match'})) { my $err_exclude_package_functions_match; ((defined($args{'exclude_package_functions_match'})) ? 1 : (($err_exclude_package_functions_match //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Required but not specified"),0)) && ((ref($args{'exclude_package_functions_match'}) eq 'Regexp' || !ref($args{'exclude_package_functions_match'}) && eval { my $tmp = $args{'exclude_package_functions_match'}; qr/$tmp/; 1 }) ? 1 : (($err_exclude_package_functions_match //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type regex pattern"),0)); if ($err_exclude_package_functions_match) { return [400, "Argument 'exclude_package_functions_match' fails validation: $err_exclude_package_functions_match"]; } }  if (exists($args{'extra_urls_for_version'})) { my $err_extra_urls_for_version; ((defined($args{'extra_urls_for_version'})) ? 1 : (($err_extra_urls_for_version //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Required but not specified"),0)) && ((ref($args{'extra_urls_for_version'}) eq 'ARRAY') ? 1 : (($err_extra_urls_for_version //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type array"),0)) && ([push(@{$_sahv_dpath}, undef), ~~((!defined(List::Util::first(sub {!( ($_sahv_dpath->[-1] = $_), ((defined($args{'extra_urls_for_version'}->[$_])) ? 1 : (($err_extra_urls_for_version //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Required but not specified"),0)) && ((!ref($args{'extra_urls_for_version'}->[$_])) ? 1 : (($err_extra_urls_for_version //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0)) )}, 0..@{$args{'extra_urls_for_version'}}-1))) ? 1 : (($err_extra_urls_for_version //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0)), pop(@{$_sahv_dpath})]->[1]); if ($err_extra_urls_for_version) { return [400, "Argument 'extra_urls_for_version' fails validation: $err_extra_urls_for_version"]; } }  if (exists($args{'include_package_functions_match'})) { my $err_include_package_functions_match; ((defined($args{'include_package_functions_match'})) ? 1 : (($err_include_package_functions_match //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Required but not specified"),0)) && ((ref($args{'include_package_functions_match'}) eq 'Regexp' || !ref($args{'include_package_functions_match'}) && eval { my $tmp = $args{'include_package_functions_match'}; qr/$tmp/; 1 }) ? 1 : (($err_include_package_functions_match //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type regex pattern"),0)); if ($err_include_package_functions_match) { return [400, "Argument 'include_package_functions_match' fails validation: $err_include_package_functions_match"]; } }  if (exists($args{'interpreter_path'})) { my $err_interpreter_path; (!defined($args{'interpreter_path'}) ? 1 :  ((!ref($args{'interpreter_path'})) ? 1 : (($err_interpreter_path //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0))); if ($err_interpreter_path) { return [400, "Argument 'interpreter_path' fails validation: $err_interpreter_path"]; } }  if (exists($args{'load_module'})) { my $err_load_module; (!defined($args{'load_module'}) ? 1 :  ((ref($args{'load_module'}) eq 'ARRAY') ? 1 : (($err_load_module //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type array"),0)) && ([push(@{$_sahv_dpath}, undef), ~~((!defined(List::Util::first(sub {!( ($_sahv_dpath->[-1] = $_), ((defined($args{'load_module'}->[$_])) ? 1 : (($err_load_module //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Required but not specified"),0)) && ((!ref($args{'load_module'}->[$_])) ? 1 : (($err_load_module //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0)) )}, 0..@{$args{'load_module'}}-1))) ? 1 : (($err_load_module //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0)), pop(@{$_sahv_dpath})]->[1])); if ($err_load_module) { return [400, "Argument 'load_module' fails validation: $err_load_module"]; } }  if (exists($args{'log'})) { my $err_log; (!defined($args{'log'}) ? 1 :  ((!ref($args{'log'})) ? 1 : (($err_log //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type boolean value"),0))); if ($err_log) { return [400, "Argument 'log' fails validation: $err_log"]; } }  if (exists($args{'output_file'})) { my $err_output_file; ((defined($args{'output_file'})) ? 1 : (($err_output_file //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Required but not specified"),0)) && ((!ref($args{'output_file'})) ? 1 : (($err_output_file //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0)); if ($err_output_file) { return [400, "Argument 'output_file' fails validation: $err_output_file"]; } } else { $args{'output_file'} //= '-'; }  if (exists($args{'overwrite'})) { my $err_overwrite; (($args{'overwrite'} //= 0), 1) && (!defined($args{'overwrite'}) ? 1 :  ((!ref($args{'overwrite'})) ? 1 : (($err_overwrite //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type boolean value"),0))); if ($err_overwrite) { return [400, "Argument 'overwrite' fails validation: $err_overwrite"]; } } else { $args{'overwrite'} //= 0; }  if (exists($args{'prefer_lite'})) { my $err_prefer_lite; (!defined($args{'prefer_lite'}) ? 1 :  ((!ref($args{'prefer_lite'})) ? 1 : (($err_prefer_lite //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type boolean value"),0))); if ($err_prefer_lite) { return [400, "Argument 'prefer_lite' fails validation: $err_prefer_lite"]; } } else { $args{'prefer_lite'} //= 1; }  if (exists($args{'script_name'})) { my $err_script_name; (!defined($args{'script_name'}) ? 1 :  ((!ref($args{'script_name'})) ? 1 : (($err_script_name //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0))); if ($err_script_name) { return [400, "Argument 'script_name' fails validation: $err_script_name"]; } }  if (exists($args{'script_version'})) { my $err_script_version; (!defined($args{'script_version'}) ? 1 :  ((!ref($args{'script_version'})) ? 1 : (($err_script_version //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0))); if ($err_script_version) { return [400, "Argument 'script_version' fails validation: $err_script_version"]; } }  if (exists($args{'snippet_before_instantiate_cmdline'})) { my $err_snippet_before_instantiate_cmdline; (!defined($args{'snippet_before_instantiate_cmdline'}) ? 1 :  ((!ref($args{'snippet_before_instantiate_cmdline'})) ? 1 : (($err_snippet_before_instantiate_cmdline //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0))); if ($err_snippet_before_instantiate_cmdline) { return [400, "Argument 'snippet_before_instantiate_cmdline' fails validation: $err_snippet_before_instantiate_cmdline"]; } }  if (exists($args{'ssl_verify_hostname'})) { my $err_ssl_verify_hostname; (!defined($args{'ssl_verify_hostname'}) ? 1 :  ((!ref($args{'ssl_verify_hostname'})) ? 1 : (($err_ssl_verify_hostname //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type boolean value"),0))); if ($err_ssl_verify_hostname) { return [400, "Argument 'ssl_verify_hostname' fails validation: $err_ssl_verify_hostname"]; } } else { $args{'ssl_verify_hostname'} //= 1; }  if (exists($args{'subcommand'})) { my $err_subcommand; ((defined($args{'subcommand'})) ? 1 : (($err_subcommand //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Required but not specified"),0)) && ((ref($args{'subcommand'}) eq 'ARRAY') ? 1 : (($err_subcommand //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type array"),0)) && ([push(@{$_sahv_dpath}, undef), ~~((!defined(List::Util::first(sub {!( ($_sahv_dpath->[-1] = $_), ((defined($args{'subcommand'}->[$_])) ? 1 : (($err_subcommand //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Required but not specified"),0)) && ((!ref($args{'subcommand'}->[$_])) ? 1 : (($err_subcommand //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0)) )}, 0..@{$args{'subcommand'}}-1))) ? 1 : (($err_subcommand //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0)), pop(@{$_sahv_dpath})]->[1]); if ($err_subcommand) { return [400, "Argument 'subcommand' fails validation: $err_subcommand"]; } }  if (exists($args{'subcommands_from_package_functions'})) { my $err_subcommands_from_package_functions; (!defined($args{'subcommands_from_package_functions'}) ? 1 :  ((!ref($args{'subcommands_from_package_functions'})) ? 1 : (($err_subcommands_from_package_functions //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type boolean value"),0)) && (($args{'subcommands_from_package_functions'} ? 1:0) == (1 ? 1:0) ? 1 : (($err_subcommands_from_package_functions //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Must have the value 1"),0))); if ($err_subcommands_from_package_functions) { return [400, "Argument 'subcommands_from_package_functions' fails validation: $err_subcommands_from_package_functions"]; } }  if (exists($args{'url'})) { my $err_url; ((defined($args{'url'})) ? 1 : (($err_url //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Required but not specified"),0)) && ((!ref($args{'url'})) ? 1 : (($err_url //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Not of type text"),0)); if ($err_url) { return [400, "Argument 'url' fails validation: $err_url"]; } }  if (!exists($args{'url'})) { return [400, "Missing required argument: url"]; }    $_w_res = do { ## this line is put by Dist::Zilla::Plugin::Rinci::Wrap

    local $Data::Dump::INDENT = "    ";

    my $output_file = $args{output_file};

    my $script_name = $args{script_name};
    unless ($script_name) {
        if ($output_file eq '-') {
            $script_name = 'script';
        } else {
            $script_name = $output_file;
            $script_name =~ s!.+[\\/]!!;
        }
    }

    my $cmdline_mod = "Perinci::CmdLine::Any";
    my $cmdline_mod_ver = 0;
    if ($args{cmdline}) {
        my $val = $args{cmdline};
        if ($val eq 'any') {
            $cmdline_mod = "Perinci::CmdLine::Any";
        } elsif ($val eq 'classic') {
            $cmdline_mod = "Perinci::CmdLine::Classic";
        } elsif ($val eq 'lite') {
            $cmdline_mod = "Perinci::CmdLine::Lite";
        } elsif ($val eq 'inline') {
            $cmdline_mod = "Perinci::CmdLine::Inline";
        } else {
            $cmdline_mod = $val;
        }
    }

    my $subcommands;
    if ($args{subcommand} && @{ $args{subcommand} }) {
        $subcommands = {};
        for (@{ $args{subcommand} }) {
            my ($sc_name, $sc_url, $sc_summary) = split /:/, $_, 3;
            $subcommands->{$sc_name} = {
                url => $sc_url,
                summary => $sc_summary,
            };
        }
    } elsif ($args{subcommands_from_package_functions}) {
        my $res = _riap_request(child_metas => $args{url} => {detail=>1}, \%args);
        return [500, "Can't child_metas $args{url}: $res->[0] - $res->[1]"]
            unless $res->[0] == 200;
        $subcommands = {};
        for my $uri (keys %{ $res->[2] }) {
            next unless $uri =~ /\A\w+\z/; # functions only
            my $meta = $res->[2]{$uri};
            if ($args{include_package_functions_match}) {
                next unless $uri =~ /$args{include_package_functions_match}/;
            }
            if ($args{exclude_package_functions_match}) {
                next if $uri =~ /$args{exclude_package_functions_match}/;
            }
            (my $sc_name = $uri) =~ s/_/-/g;
            $subcommands->{$sc_name} = {
                url     => "$args{url}$uri",
                summary => $meta->{summary},
            };
        }
    }


    # generate code
    my $code;
    if ($cmdline_mod eq 'Perinci::CmdLine::Inline') {
        require Perinci::CmdLine::Inline;
        $cmdline_mod_ver = $Perinci::CmdLine::Inline::VERSION;
        my $res = Perinci::CmdLine::Inline::gen_inline_pericmd_script(
            url => $args{url},
            program_name => $args{script_name},
            program_version => $args{script_version},
            subcommands => $subcommands,
            log => $args{log},
            (extra_urls_for_version => $args{extra_urls_for_version}) x !!$args{extra_urls_for_version},
            include => $args{load_module},
            (code_before_parse_cmdline_options => $args{snippet_before_instantiate_cmdline}) x !!$args{snippet_before_instantiate_cmdline},
            # config_filename => $args{config_filename},
            shebang => $args{interpreter_path},
        );
        return $res if $res->[0] != 200;
        $code = $res->[2];
    } else {
        # request metadata to get summary (etc)
        my $res = _riap_request(meta => $args{url} => {}, \%args);
        return [500, "Can't meta $args{url}: $res->[0] - $res->[1]"]
            unless $res->[0] == 200;
        my $meta = $res->[2];

        $code = join(
            "",
            "#!", ($args{interpreter_path} // $^X), "\n",
            "\n",
            "# Note: This script is a CLI interface",
            ($meta->{args} ? " to Riap function $args{url}" : ""), # a quick hack to guess meta is func metadata (XXX should've done an info Riap request)
            "\n",
            "# and generated automatically using ", __PACKAGE__,
            " version ", ($App::GenPericmdScript::VERSION // '?'), "\n",
            "\n",
            "# DATE\n",
            "# DIST\n",
            "# VERSION\n",
            "\n",
            "use 5.010001;\n",
            "use strict;\n",
            "use warnings;\n",
            "\n",

            ($args{load_module} && @{$args{load_module}} ?
                 join("", map {"use $_;\n"} @{$args{load_module}})."\n" : ""),

            ($args{default_log_level} ?
                 "BEGIN { no warnings; \$main::Log_Level = '$args{default_log_level}'; }\n\n" : ""),

            "use $cmdline_mod",
            ($cmdline_mod eq 'Perinci::CmdLine::Any' &&
                 defined($args{prefer_lite}) && !$args{prefer_lite} ? " -prefer_lite=>0" : ""),
            ";\n\n",

            ($args{ssl_verify_hostname} ? "" : '$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;' . "\n\n"),

            ($args{snippet_before_instantiate_cmdline} ? "# snippet_before_instantiate_cmdline\n" . $args{snippet_before_instantiate_cmdline} . "\n\n" : ""),

            "$cmdline_mod->new(\n",
            "    url => ", dump($args{url}), ",\n",
            (defined($subcommands) ? "    subcommands => " . indent("    ", dump($subcommands), {first_line_indent=>""}) . ",\n" : ""),
            (defined($args{log}) ? "    log => " . dump($args{log}) . ",\n" : ""),
            (defined($args{extra_urls_for_version}) ? "    extra_urls_for_version => " . dump($args{extra_urls_for_version}) . ",\n" : ""),
            (defined($args{config_filename}) ? "    config_filename => " . dump($args{config_filename}) . ",\n" : ""),
            ")->run;\n",
            "\n",
        );

        # abstract line
        $code .= "# ABSTRACT: " . ($meta->{summary} // $script_name) . "\n";

        # podname
        $code .= "# PODNAME: $script_name\n";
    } # END generate code

    if ($output_file ne '-') {
        $log->trace("Outputing result to %s ...", $output_file);
        if ((-f $output_file) && !$args{overwrite}) {
            return [409, "Output file '$output_file' already exists (please use --overwrite if you want to override)"];
        }
        open my($fh), ">", $output_file
            or return [500, "Can't open '$output_file' for writing: $!"];

        print $fh $code;
        close $fh
            or return [500, "Can't write '$output_file': $!"];

        chmod 0755, $output_file or do {
            $log->warn("Can't 'chmod 0755, $output_file': $!");
        };

        my $output_name = $output_file;
        $output_name =~ s!.+[\\/]!!;

        if (which("shcompgen") && which($output_name)) {
            $log->trace("We have shcompgen in PATH and output ".
                            "$output_name is also in PATH, running shcompgen ...");
            system "shcompgen", "generate", $output_name;
        }

        $code = "";
    }

    [200, "OK", $code, {
        'func.cmdline_module' => $cmdline_mod,
        'func.cmdline_module_version' => $cmdline_mod_ver,
        'func.script_name' => 0,
    }];
};      unless (ref($_w_res) eq "ARRAY" && $_w_res->[0]) { return [500, 'BUG: Sub App::GenPericmdScript::gen_perinci_cmdline_script does not produce envelope']; } return $_w_res; } ## this line is put by Dist::Zilla::Plugin::Rinci::Wrap

1;
# ABSTRACT: Generate Perinci::CmdLine CLI script

__END__

=pod

=encoding UTF-8

=head1 NAME

App::GenPericmdScript - Generate Perinci::CmdLine CLI script

=head1 VERSION

This document describes version 0.09 of App::GenPericmdScript (from Perl distribution App-GenPericmdScript), released on 2015-07-02.

=head1 FUNCTIONS


=head2 gen_perinci_cmdline_script(%args) -> [status, msg, result, meta]

Generate Perinci::CmdLine CLI script.

Arguments ('*' denotes required arguments):

=over 4

=item * B<cmdline> => I<str> (default: "Perinci::CmdLine::Any")

Specify module to use.

=item * B<config_filename> => I<str>

Will be passed to Perinci::CmdLine constructor.

=item * B<default_log_level> => I<str>

=item * B<exclude_package_functions_match> => I<re>

Exclude package functions matching this pattern.

=item * B<extra_urls_for_version> => I<array[str]>

Will be passed to Perinci::CmdLine constructor.

=item * B<include_package_functions_match> => I<re>

Only include package functions matching this pattern.

=item * B<interpreter_path> => I<str>

What to put on shebang line.

=item * B<load_module> => I<array[str]>

Load extra modules.

=item * B<log> => I<bool>

Will be passed to Perinci::CmdLine constructor.

=item * B<output_file> => I<str> (default: "-")

Path to output file.

=item * B<overwrite> => I<bool> (default: 0)

Whether to overwrite output if previously exists.

=item * B<prefer_lite> => I<bool> (default: 1)

Prefer Perinci::CmdLine::Lite backend.

=item * B<script_name> => I<str>

=item * B<script_version> => I<str>

Use this for version number instead.

=item * B<snippet_before_instantiate_cmdline> => I<str>

=item * B<ssl_verify_hostname> => I<bool> (default: 1)

If set to 0, will add: $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;' to code.

=item * B<subcommand> => I<array[str]>

Subcommand name followed by colon and function URL.

Optionally, it can be additionally followed by a summary, so:

 NAME:URL[:SUMMARY]

Example (on CLI):

 --subcommand "delete:/My/App/delete_item:Delete an item"

=item * B<subcommands_from_package_functions> => I<bool>

Form subcommands from functions under package's URL.

This is an alternative to the C<subcommand> option. Instead of specifying each
subcommand's name and URL, you can also specify that subcommand names are from
functions under the package URL in C<url>. So for example if C<url> is C</My/App/>,
hen all functions under C</My/App> are listed first. If the functions are:

 foo
 bar
 baz_qux

then the subcommands become:

 foo => /My/App/foo
 bar => /My/App/bar
 "baz-qux" => /My/App/baz_qux

=item * B<url>* => I<str>

URL to function (or package, if you have subcommands).

=back

Returns an enveloped result (an array).

First element (status) is an integer containing HTTP status code
(200 means OK, 4xx caller error, 5xx function error). Second element
(msg) is a string containing error message, or 'OK' if status is
200. Third element (result) is optional, the actual result. Fourth
element (meta) is called result metadata and is optional, a hash
that contains extra information.

Return value:  (any)

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/App-GenPericmdScript>.

=head1 SOURCE

Source repository is at L<https://github.com/perlancar/perl-App-GenPericmdScript>.

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=App-GenPericmdScript>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 AUTHOR

perlancar <perlancar@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2015 by perlancar@cpan.org.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
