feather
feather copied to clipboard
Commands become a DAG: split and join
Right now, our commands construct a linear chain of pipes. It would be nice if we could do arbitrary DAGs, something along the lines of:
val split : cmd -> cmd * cmd
(** [split] a command into two identical commands that have the same output *)
val as_fifo : cmd -> string
(** take a command and turn it into a named pipe. Similar to <( ... ) in bash. *)
This could be used like so:
let log1, log2 = process "tail" [ "-f" ; "log" ] |> split in
process "cat" [as_fifo (log1 |. shuf); as_fifo (log2 |. sort)] |> run
The named pipes would have to be cleaned up when the Feather.run exits and Stdlib.at_exit
.
I looked into this a bit and the most annoying part is that neither Base
nor Stdlib
implement a way to get the name of a tempfile without actually creating the tempfile. (We want to mkfifo ourselves.) So we'll have to implement our own random tempfile function.
Nice idea !
The situation is like this in Base
and Stdlib
because apparently the implementation tests if a file already exists with a given name by directly creating it.
It shouldn't be too hard to tweak the original implementation (below) to do what we want.
let temp_file_name temp_dir prefix suffix =
let rnd = (Random.State.bits (Lazy.force prng)) land 0xFFFFFF in
concat temp_dir (Printf.sprintf "%s%06x%s" prefix rnd suffix)
let current_temp_dir_name = ref temp_dir_name
let set_temp_dir_name s = current_temp_dir_name := s
let get_temp_dir_name () = !current_temp_dir_name
let temp_file ?(temp_dir = !current_temp_dir_name) prefix suffix =
let rec try_name counter =
let name = temp_file_name temp_dir prefix suffix in
try
close_desc(open_desc name [Open_wronly; Open_creat; Open_excl] 0o600);
name
with Sys_error _ as e ->
if counter >= 1000 then raise e else try_name (counter + 1)
in try_name 0
(also apparently the bos
library contains what we want but that would be another dependency)
Good point — I'd be happy with just having our own utility function for that.