#!/usr/bin/perl

use 5.010001;
use strict;
use warnings;

our $VERSION = '0.05'; # VERSION

use App::riap;

my $shell = App::riap->new;

$shell->cmdloop;

1;
# ABSTRACT: Riap command-line client shell
# PODNAME: riap

__END__

=pod

=encoding UTF-8

=head1 NAME

riap - Riap command-line client shell

=head1 VERSION

version 0.05

=head1 SYNOPSIS

 % riap --help
 % riap [opts] <uri>

Invoking:

 # URI defaults to 'pl:/', which is the local Perl realm
 % riap

 # ditto, but specify initial "pwd"
 % riap /Calendar/Indonesia/Holiday
 % riap pl:/Calendar/Indonesia/Holiday

 # access remote API starting point
 % riap https://cpanlists.org/api/
 % riap http://gudangapi.com/ga/

An example session:

 riap> pwd
 /

 riap> cd /spanel/api

 riap> ls
 account/
 disk_usage/
 mysql/
 pgsql/
 plan/
 ...

 riap> cd account/shared/query

 riap> pwd
 /spanel/api/account/shared/query

 riap> ls -l
 create_account     function
 delete_accounts    function
 suspend_account    function
 unsuspend_account  function

 # execute a Riap function like it is an executable program
 riap> list_accounts --nodisabled --nomigrated
 andi
 budi
 charlie
 devi
 steven

 riap> ../modify/delete_account --help

 riap> exit

=head1 DESCRIPTION

A Riap client in the form of a simple interactive command-line shell (as opposed
to L<Perinci::Access> which is a Perl library, or L<peri-run> and L<peri-access>
which are non-interactive command-line interface). Provides a convenient way to
explore API services which use the L<Riap> protocol or explore Perl modules
which have L<Rinci> metadata.

Example API services that you can (or will be able to) test this with:

=over

=item * cpanlists.org at L<https://cpanlists.org/api/>

=item * gudangdata.org at L<https://gudangdata.org/gd/>

=item * gudangapi.com at L<https://gudangapi.com/ga/>

=item * Any server using the Spanel control panel software

The API daemon listens at the Unix socket at C</var/run/spanel/apid.sock> or at
TCP C<https://localhost:1010>.

=back

Example Perl libraries you can test this with (you need to install them first):
L<Text::sprintfn>, L<Git::Bunch>, L<Calendar::Indonesia::Holiday>,
L<Perinci::Examples>. Try to search for CPAN distributions which specify
L<Rinci> as their prerequisites.

Within the shell, you can browse packages and functions as if they were
directories and executable files (using commands like C<cd>, C<ls>, C<pwd>). You
can call functions like they were command-line programs, by passing command-line
parameters for function arguments.

See L</"COMMANDS"> for list of known commands.

=head1 OPTIONS

=over

=item * --help

Show short help message.

=item * --user=S

Supply HTTP authentication user. You can also set this via environment
L<PERINCI_HTTP_USER> (see L<Perinci::Access> for more details) or from inside
the shell via C<< set user <S> >>.

=item * --password=S

Supply HTTP authentication password. You can also set this via environment
L<PERINCI_HTTP_PASSWORD> (see L<Perinci::Access> for more details) or from
inside the shell via C<< set password <S> >>.

Using the command-line option is not recommended because of security issue
(command-line commands/arguments are usually visible to all users on the system
via commands like B<ps>).

=back

=head1 COMMANDS

=head2 help [command]

Display help message.

=head2 exit

=head2 pwd

Print the current directory (package). When you first enter the shell, current
directory is set to C</>.

=head2 cd [path]

Change directory (package). You can use relative notation (C<../foo>) like in a
Unix filesystem.

=head2 doc <path>

Perform C<meta> Riap request and format the result as text.

=head2 ls [options] [path ...]

List of content of directory (package) or other code entities by performing
C<list> Riap request. If C<path> is not specified, will list the current
directory (package).

Options:

=over

=item * --long (-l)

Add C<< detail => 1 >> to the Riap request, which will return more details.

=back

=head2 list

Alias for C<ls>.

=head2 info [path]

Perform C<info> Riap request on an entity at C<path>.

=head2 request [options] <action> <path> [extra]

Perform Riap request to a code entity at C<path>. Extra request keys can be
specified in C<extra>.

Examples:

 riap> request call /Package/Sub/somefunc '{"args":{"a":1, "b":2}}'
 riap> request list /Package/Sub/somefunc '{"detail":1}'

=head2 call [options] <path> [args]

Perform C<call> Riap request. Note that C<call> command is actually optional:
the shell performs call requests by default on paths.

Examples:

 riap> call /Package/Sub/somefunc '{"foo":1, "bar":2}'

which is equivalent to:

 riap> /Package/Sub/somefunc --foo 1 --bar 2

=head2 set <name> <value>

If invoked without any argument, will list all known settings. If C<name> is
specified but C<value> is not, will show value for that particular setting. If
C<name> and C<value> is both specified, will set a setting's value.

=head1 SETTINGS

Settings are configuration and regulate how the shell behaves.

=head2 user => str

For HTTP authentication.

=head2 password => str

For HTTP authentication.

=head2 output_format => str (default: C<text>)

Set output format for command results. The same formatting is used by
L<Perinci::CmdLine>. See that module or L<Perinci::Result::Format> for more
details.

=head2 debug_show_request => bool (default: 0)

Whether to show raw Riap requests being sent to the server.

Note: since B<riap> uses L<Perinci::Access>, you can also achieve the same thing
via:

 % TRACE=1 LOG_RIAP_REQUEST=1 perl -MLog::Any::App /path/to/riap ...

=head2 debug_show_request_for_completion => bool (default: 0)

Even though C<debug_show_request> setting is turned on, to see Riap requests
sent when doing Tab completion, you need to turn on this setting. This setting
is separated because showing logs during Tab completion is rather interfering,
visually.

=head2 debug_show_response => bool (default: 0)

Whether to show raw Riap responses returned by the server.

Note: since B<riap> uses L<Perinci::Access>, you can also achieve the same thing
via:

 % TRACE=1 LOG_RIAP_RESPONSE=1 perl -MLog::Any::App /path/to/riap ...

=head2 debug_show_response_for_completion => bool (default: 0)

Even though C<debug_show_response> setting is turned on, to see Riap responses
returned by server when doing Tab completion, you need to turn on this setting.
This setting is separated because showing logs during Tab completion is rather
interfering, visually.

=head1 FAQ

=head2 The prompt looks rather garbled (e.g. extra " m >" character)!

It looks to be an issue with L<Term::ReadLine::Perl>. Try installing
L<Term::ReadLine::Gnu> instead.

=head2 How do I redirect output to files?

B<riap> is meant to be a simple shell, not a full-blown Unix shell. Besides, a
syntax like this:

 riap> call /Package/Sub/somefunc > /path/to/file

will be confusing since paths map to code entity URIs in B<riap>, not filesystem
paths.

But something like a setting might be implemented if this is a popular feature
request.

=head2 What about variables, aliases, looping, or $other_Unix_shell_feature?

Again, B<riap> is meant to be a simple shell, not a full-blown Unix shell. To do
those things, you are better off using L<peri-run> or L<peri-access> and
incorporate them in a Unix shell script. For example you can write these two
short scripts:

 # list-accounts
 #!/bin/sh
 peri-access call https://yourservice.com/api/Account/list

 # delete-account (input sanitizing is left as exercise for the readers)
 #!/bin/sh
 peri-access call "https://yourservice.com/api/Account/delete?account=$1"

and then write:

 # delete all accounts
 for a in `list-accounts`; do
     delete-account "$a"
 done

=head1 ENVIRONMENT

=head2 PERINCI_HTTP_USER => str

If set, can be used to set C<user> setting (but priority lower than command-line
option C<--user>).

=head2 PERINCI_HTTP_PASSWORD => str

If set, can be used to set C<password> setting (but priority lower than
command-line option C<--password>). This is usually more secure to use than
command-line option, because command-line option is usually visible from all
users on the system via commands like C<ps>.

=head2 RIAP_HISTFILE => str (default: C<~/.riap_history>)

Specify location of command history file. Like in shells, can be set to empty
string to disable history loading/saving.

=head2 RIAPRC => str (default: C<~/.riaprc>)

Specify location of settings file.

=head1 FILES

=head2 C<~/.riap_history>

Command history file.

=head2 C<~/.riaprc>

Settings file. Each line is either a blank line, a comment (C<# ...>), or C<<
<name>=<value-in-json> >>. An invalid line (e.g. unknown settings, invalid JSON
syntax) will cause shell to abort when loading.

=head1 TODO

=over

=item * Configurable prompt

=item * RIAP_HISTSIZE

And also probably RIAP_HISTFILESIZE, RIAP_HISTIGNORE, RIAP_HISTTIMEFORMAT.

=item * Something like PATH? [#E]

=back

=head1 AUTHOR

Steven Haryanto <stevenharyanto@gmail.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by Steven Haryanto.

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
