=begin pod :kind("Language") :subkind("Language") :category("tutorial")

=TITLE Inter-process communication

=SUBTITLE Programs running other programs and communicating with them

X<|IPC>
=head1 X<Running programs>

Many programs need to be able to run other programs, and we need to pass
information to them and receive their output and exit status. Running a program
in Raku is as easy as:

    run 'git', 'status';

This line runs the program named "git" and passes "git" and "status" to its
command-line. It will find the program using the C<< %*ENV<PATH> >> setting.

If you would like to run a program by sending a command-line to the shell,
there's a tool for that as well. All shell metacharacters are interpreted by
the shell, including pipes, redirects, environment variable substitutions and so
on.

    shell 'ls -lR | gzip -9 > ls-lR.gz';

Caution should be taken when using C<shell> with user input.

=head1 The C<Proc> object

Both C<run> and C<shell> return a L<Proc|/type/Proc> object, which can be used
to communicate with the process in more detail. Please note that unless you
close all output pipes, the program will usually not terminate.

    my $git = run 'git', 'log', '--oneline', :out;
    for $git.out.lines -> $line {
        my ($sha, $subject) = $line.split: ' ', 2;
        say "$subject [$sha]";
    }
    $git.out.close();

If the program fails (exits with a non-zero exit code), it will throw
an exception when the returned L<Proc|/type/Proc> object is sunk. You can save it into
a variable, even anonymous one, to prevent the sinking:

    $ = run '/bin/false'; # does not sink the Proc and so does not throw

You can tell the C<Proc> object to capture output as a filehandle by passing
the C<:out> and C<:err> flags. You may also pass input via the C<:in> flag.

    my $echo = run 'echo', 'Hello, world', :out;
    my $cat  = run 'cat', '-n', :in($echo.out), :out;
    say $cat.out.get;
    $cat.out.close();

You may also use C<Proc> to capture the PID, send signals to the application,
and check the exitcode.

    my $crontab = run 'crontab', '-l';
    if $crontab.exitcode == 0 {
        say 'crontab -l ran ok';
    }
    else {
        say 'something went wrong';
    }

=head1 The C<Proc::Async> object

When you need more control over the communication with and from another process,
you will want to make use of L<Proc::Async|/type/Proc::Async>. This class
provides support for asynchronous communication with a program, as well as the
ability to send signals to that program.

    =begin code
    # Get ready to run the program
    my $log = Proc::Async.new('tail', '-f',  '/var/log/system.log');
    $log.stdout.tap(-> $buf { print $buf });
    $log.stderr.tap(-> $buf { $*ERR.print($buf) });

    # Start the program
    my $done = $log.start;
    sleep 10;

    # Tell the program to stop
    $log.kill('QUIT');

    # Wait for the program to finish
    await $done;
    =end code

The small program above uses the "tail" program to print out the contents of the
log named C<system.log> for 10 seconds and then tells the program to stop with a
QUIT signal.

Whereas C<Proc> provides access to output using C<IO::Handle>s, C<Proc::Async>
provides access using asynchronous supplies (see L<Supply|/type/Supply>).

If you want to run a program and do some work while you wait for the original
program to finish, the C<start> routine returns a L<Promise|/type/Promise>,
which is kept when the program quits.

Use the C<write> method to pass data into the program.

=end pod

# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6
