hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 78f8abee333122e841d620b409358b3f36239f55
parent 7e657ecd8c171350c5b440c9cf8c9a56116328e3
Author: Drew DeVault <sir@cmpwn.com>
Date:   Mon, 22 Nov 2021 10:06:33 +0100

os::exec: add exec::pipe

This provides a more portable way to create pipes than using unix::pipe
directly.

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Mcmd/hare/release.ha | 9++++-----
Mos/exec/cmd.ha | 3+++
Mos/exec/exec+linux.ha | 28++++++++++++++++++++++++++--
3 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/cmd/hare/release.ha b/cmd/hare/release.ha @@ -9,7 +9,6 @@ use path; use strconv; use strings; use temp; -use unix; type increment = enum { MAJOR, @@ -283,14 +282,14 @@ fn signtag(name: str, tag: str, key: str) (void | release_error) = { const note = exec::cmd("git", "notes", "add", "-F", "-", tag)?; exec::setenv(&note, "GIT_NOTES_REF", "refs/notes/signatures/tar.gz"); - // Squelch "Signing data on standard input" + // Squelch "Signing data on standard input" message // TODO: It might be better to capture this and print it to stderr // ourselves if ssh-keygen exits nonzero, so that the error details are // available to the user for diagnosis. exec::addfile(&ssh, exec::nullfd, os::stderr); - const pipe1 = unix::pipe()?; - const pipe2 = unix::pipe()?; + const pipe1 = exec::pipe(); + const pipe2 = exec::pipe(); exec::addfile(&archive, pipe1.1, os::stdout_file); exec::addfile(&ssh, pipe1.0, os::stdin_file); exec::addfile(&ssh, pipe2.1, os::stdout_file); @@ -316,7 +315,7 @@ fn git_runcmd(args: str...) (void | release_error) = { }; fn git_readcmd(args: str...) (str | release_error) = { - const pipe = unix::pipe()?; + const pipe = exec::pipe(); defer io::close(pipe.0); const cmd = exec::cmd("git", args...)?; exec::addfile(&cmd, pipe.1, os::stdout_file); diff --git a/os/exec/cmd.ha b/os/exec/cmd.ha @@ -130,6 +130,9 @@ export fn setenv(cmd: *command, key: str, value: str) void = { // Pass [[os::exec::closefd]] in the 'to' argument to close a file descriptor // which was not opened with the CLOEXEC flag. Note that Hare opens all files // with CLOEXEC by default, so this is not usually necessary. +// +// To write to a process's stdin, capture its stdout, or pipe two programs +// together, see the [[pipe]] function. export fn addfile( cmd: *command, from: (io::file | nullfd | closefd), diff --git a/os/exec/exec+linux.ha b/os/exec/exec+linux.ha @@ -1,8 +1,9 @@ use errors; +use io; +use os; use rt; use strings; -use os; -use io; +use unix; export type platform_cmd = io::file; @@ -17,6 +18,29 @@ export fn fork() (int | void | error) = { }; }; +// Creates an anonymous pipe for use with [[addfile]]. Any data written to the +// second file may be read from the first file. The caller should close one or +// both of the file descriptors after they have transferred them to another +// process, and after they have finished using them themselves, if applicable. +// +// This function will abort the process if the system is unable to allocate the +// resources for a pipe. If you need to handle this error gracefully, you may +// call [[unix::pipe]] yourself, but this may reduce the portability of your +// software. +// +// To capture the standard output of a process: +// +// let pipe = exec::pipe(); +// exec::addfile(&cmd, pipe.1, os::stdout_file); +// exec::start(&cmd); +// io::close(pipe.1); +// +// let data = io::drain(pipe.0)!; +// io::close(pipe.0); +export fn pipe() (io::file, io::file) = { + return unix::pipe()!; +}; + fn open(path: str) (platform_cmd | error) = { match (rt::access(path, rt::X_OK)) { case err: rt::errno =>