package genspio

  1. Overview
  2. Docs

Module Genspio.EDSLSource

The Embedded Domain Specific Lanaguage to create “shell-expressions.”

Sourcetype 'a t = 'a Language.t

The type of a Genspio expression.

Type to encode arbitrary byte-arrays in the EDSL as str t values, OCaml literal strings or the outputs (as in stdout) of processes are byte-arrays.

NUL-terminated “C-like” strings are encoded at a lower level than this EDSL (as c_string t values). C-strings cannot contain the '\x00' character. The command line arguments of commands as well as the contents of environment variables must be C-strings. Genspio treats them properly by failing when a wrong byte-array needs to be converted to a C-string.

Sourcetype byte_array = Language.byte_array
Sourcetype c_string = Language.c_string

Literals

Sourceval str : string -> str t

Create a byte_array literal.

Sourceval string : string -> str t

string is an alias for function:str.

Sourceval int : int -> int t
Sourceval bool : bool -> bool t

Comments

Sourceval comment : string -> 'a t -> 'a t

Add a “comment” string to an expression (will be displayed in error messages happening inside the expression).

Sourceval (%%%) : string -> 'a t -> 'a t

"Some comment" %%% expr is an alias for comment "Some comment" expr.

Basic system Commands

Sourceval call : str t list -> unit t

Call a command from its list of “arguments” (including the first argument being the actual command).

Sourceval exec : string list -> unit t

Like call but with string literals; i.e. exec ["a"; "b"] is actually call [string "a"; string "b"] which is the usual shell command "a b" (with proper escaping).

Sourceval getenv : str t -> str t

Get the value of an environment variable as a string; it returns the empty string when the variable is not defined. If the argument is not a valid variable name, behavior is undefined.

Sourceval setenv : var:str t -> str t -> unit t

Set the value of an environment variable as a string; it returns the empty string is the variable is not defined.

If the ~var argument is not a valid variable name or if the value does not fit in a shell variable (e.g. newlines), behavior is undefined.

Also, the total environment of a UNIX process counts towards the total size of the arguments passed on to a sub-process (see usually the result of "getconf ARG_MAX"). Genspio does not check for that limit which is not that high in some operating systems (e.g. about 200 KiB on the MacOSX Sierra that the Travis CI runs …). You might prefer putting or accumulating things in a tmp_file.

Boolean Expressions

Sourceval (&&&) : bool t -> bool t -> bool t
Sourceval (|||) : bool t -> bool t -> bool t
Sourceval not : bool t -> bool t
Sourceval returns : 'a t -> value:int -> bool t

Check the return value of a command/expression/script.

Sourceval succeeds : 'a t -> bool t

succeeds expr is equivalent to returns expr ~value:0.

Sourceval file_exists : str t -> bool t

Check whether a file exists, i.e. a shortcut for call [str "test"; str "-f"; path] |> succeeds.

Sourcemodule Bool : sig ... end

Conversions of the bool t type.

Integer Arithmetic

Sourcemodule Integer : sig ... end

Functions on int t values (arithmetic, comparisons, conversions, etc.).

EDSL Lists

Sourcemodule Elist : sig ... end

Functions on 'a list t values.

String Manipulation

Sourcemodule Str : sig ... end

Control Flow

Sourceval nop : unit t

The silent “no-operation.”

Sourceval if_then_else : bool t -> unit t -> unit t -> unit t
Sourceval if_then : bool t -> unit t -> unit t
Sourceval seq : unit t list -> unit t

Sequence a list of expressions into an expression.

Sourceval loop_while : bool t -> body:unit t -> unit t

Build a while loop.

Sourceval loop_seq_while : bool t -> unit t list -> unit t

loop_seq_while condition body is a shortcut for loop_while condition ~body:(seq body).

Sourceval if_seq : t:unit t list -> ?e:unit t list -> bool t -> unit t

if_seq c ~t ~e is an alternate API for if_then_else (when ?e is provided) or if_then (otherwise) that takes “then” and “else” bodies which are lists for the seq construct.

Switch Statements

Sourceval switch : [ `Case of bool t * unit t | `Default of unit t ] list -> unit t

Create a switch statement from a list of case and optionally a default (the function raises an exception if there are more than one default cases).

Sourceval case : bool t -> unit t list -> [> `Case of bool t * unit t ]

Create a normal case for a switch statement.

Sourceval default : unit t list -> [> `Default of unit t ]

Create the default case for a switch statement.

Redirections and File Descriptors

Sourcetype fd_redirection

Abstract type of file-descriptor redirections.

Sourceval to_fd : int t -> int t -> fd_redirection

Create a file-descriptor to file-descriptor redirection.

Sourceval to_file : int t -> str t -> fd_redirection

Create a file-descriptor to file redirection.

Sourceval with_redirections : unit t -> fd_redirection list -> unit t

Run a unit t expression after applying a list of file-descriptor redirections.

The redirections are applied in the list's order (which means they can be more easily followed in reverse order), see the “Arbitrary Redirections” example.

Invalid cases, like redirecting to a file-descriptor has not been opened, lead to undefined behavior; see issue #41. If the shell is POSIX, the whole expression with_redirections expr redirs exits and its return value is in [1, 125]; if the shell is "bash" or "zsh", the failing redirection is just ignored and expr is executed with the remaining redirections if any.

Sourceval write_output : ?stdout:str t -> ?stderr:str t -> ?return_value:str t -> unit t -> unit t

Redirect selected streams or the return value to files (stdout, stderr, return_value are paths).

Sourceval write_stdout : path:str t -> unit t -> unit t

write_stdout ~path expr is write_output expr ~stdout:path.

Sourceval pipe : unit t list -> unit t

Pipe commands together ("stdout" into "stdin" exactly like the " | " operator).

Sourceval (||>) : unit t -> unit t -> unit t

a ||> b is a shortcut for pipe [a; b].

Sourceval get_stdout : unit t -> str t

Get the contents of stdout into a byte array (in previous versions this function was called output_as_string).

Sourceval feed : string:str t -> unit t -> unit t

Feed some content (~string) into the "stdin" filedescriptor of a unit t expression.

Sourceval (>>) : str t -> unit t -> unit t

str >> cmd is feed ~string:str cmd.

Sourceval printf : str t -> str t list -> unit t

printf fmt l is call (string "printf" :: string "--" :: fmt :: l).

Sourceval eprintf : str t -> str t list -> unit t

Like printf but redirected to "stderr".

Sourceval with_stdout_to_stderr : unit t -> unit t

Run a command with stdout redirected to stderr

Escaping The Execution Flow

Sourceval fail : string -> unit t

Expression that aborts the whole script/command immediately, it will try to output its argument to stderr (but this may be silent depending on the redirections active at a given time).

Temporary Files

Sourcetype file = < get : str t ; set : str t -> unit t ; append : str t -> unit t ; delete : unit t ; path : str t >

Abstraction of a file, cf. tmp_file.

Sourceval tmp_file : ?tmp_dir:str t -> string -> file

Create a temporary file that may contain arbitrary strings (can be used as variable containing string t values).

tmp_file "foo" points to a path that is a function of the string "foo"; it does not try to make temporary-files unique, on the contrary: two calls to tmp_file "foo" ensure that it is the same file.

Command Line Parsing

Sourcemodule Command_line : sig ... end

Typed command-line parsing for your shell scripts, à la Printf.scanf.

Additional Higher-Level Utilities

Sourceval loop_until_true : ?attempts:int -> ?sleep:int -> ?on_failed_attempt:(int t -> unit t) -> bool t -> bool t

loop_until_true eval_condition tries to run eval_condition in a loop until it succeeds. It makes ~attempts attemps (default 20), and sleeps for sleep seconds (default 2) after each failed attempt. The argument ~on_failed_attempt can be used for instance to display something between each failed attempt and the call to sleep, the default is

fun nth -> printf (string "%d.") [Integer.to_string nth]

.

Sourceval silently : unit t -> unit t

silently expr is expr with stdout and stderr redirected to "/dev/null".

Sourceval succeeds_silently : unit t -> bool t

succeeds_silently u is silently u |> succeeds.

Sourceval seq_and : 'a t list -> bool t

seq_and [a; b; c] is like succeeds a &&& succeeds b &&& succeeds c.

Sourceval output_markdown_code : string -> unit t -> unit t

output_markdown_code "ocaml" (exec ["echo"; "let x = 42"]) runs its second argument within markdown-like code fences.

Sourceval cat_markdown : string -> str t -> unit t

cat_markdown tag path outputs the contents of the file at path (with "cat") within a markdown code bloc.

Sourceval check_sequence : ?verbosity:[ `Announce of string | `Output_all | `Silent ] -> ?on_failure: (step:(string * unit t) -> stdout:str t -> stderr:str t -> unit t) -> ?on_success: (step:(string * unit t) -> stdout:str t -> stderr:str t -> unit t) -> ?tmpdir:string -> (string * unit t) list -> unit t

Run a sequence of expressions until the first that fails:

  • ?verbosity configures the output behavior,

    • `Announce prompt uses prompt to output the name-tag of the command, the output of the command is redirected to temporary files (accessible through the ~on_success and ~on_failure functions). The default value is `Announce ">> ".
    • `Output_all lets all the output of the commands go through.
    • `Silent is like `Announce _ but without even the “prompt” command annoucement.
  • ?on_failure configures what to do when encountering the first failure, the default is to display on stdout the name-tag of the failing command and outputting the contents of its stdout and stderr log-files (if any) and then call exec ["false"].
  • ?on_success is a similar function as ?on_failure, called before starting the next command, the default is to do nothing.
  • ?tmpdir configures where to create the logging files.
Sourceval on_stdin_lines : (str t -> unit t) -> unit t

on_stdin_lines body builds a loop that iterates over the lines of the stdin file descriptor. The argument of `body` is the current line. Note that this is for text-like input, '\000' characters in the input lead to undefined behavior.

Sourceval strs : string list -> str t list

strs is simply just List.map ~f:str.

Sourceval command_available : str t -> bool t

Call "command -v" to know if an executable is in "$PATH" (note that "which" is not POSIX, we use "command -v ..." which is expected to return a failure if the command is not found).

Sourceval get_stdout_one_line : ?first_line:bool -> ?remove_spaces:bool -> unit t -> str t

Get the output of a command as a string without new lines, potentially cutting at the first line:

  get_stdout
    ( (if first_line then u ||> exec ["head"; "-n"; "1"] else u)
    ||> exec ["tr"; "-d"; (if remove_spaces then " \\n" else "\\n")] )
Sourceval verbose_call : ?prefix:string -> ?verbose:bool t -> str t list -> unit t

Like call but print on stderr the command being run.

Sourceval check_sequence_with_output : unit t list -> unit t

A shortcut for check_sequence with ~verbosity:`Output_all hence ignoring the “names” of the commands.

Sourceval is_regular_file : str t -> bool t

Call "test -f ...".

Sourceval is_directory : str t -> bool t

Call "test -d ...".

Sourceval is_executable : str t -> bool t

Call "test -x ...".

Sourceval is_readable : str t -> bool t

Call "test -r ...".

Sourceval mkdir_p : str t -> unit t

Call "mkdir -p ...".

Sourceval exit : int -> unit t

Call "exit ...", warning: depending on the compiler, the call maybe nested in various sub-shells, to really exit a script use fail.

Sourceval home_path : unit -> str t

The value of "$HOME".

Sourceval (^$^) : str t -> str t -> str t

Concatenate two EDSL strings.

Sourceval (///) : str t -> str t -> str t

a /// b is a ^$^ str "/" ^$^ b.

Sourceval say : string -> str t list -> unit t

say fmt l is a shortcut to call eprintf (str fmt) l.

Sourceval ensure : string -> condition:bool t -> how:(string * unit t) list -> unit t

Ensure a condition:

  • Test the condition.
  • If true do nothing, succeed
  • If false, run ~how with check_sequence.
  • Test the condition again, if true succeed, if false fail.

Failures happen thanks to the !fail call.

Sourceval greps_to : ?extended_re:bool -> str t -> unit t -> bool t

Test a string or regular expression again the output of an expression.

Sourceval pager : ?file_descriptor:str t -> ?disable:bool t -> ?default_command:unit t -> unit -> unit t

“Smart pager” command to pipe long outputs through, conditions are tested in this order:

  • If ~disable is provided it can be used to make the pager behave like "cat".
  • If the ~file_descriptor (default str "1") is not a terminal, the command will be "cat" too.
  • If the environment variable "PAGER" it will be used as a shell command ("sh -c ..").
  • The last resort default is ~default_command (which by default value is exec ["more"]).
Sourcemodule Script_with_describe (P : sig ... end) : sig ... end

Make scripts that provide a "--describe" option/command.

Sourcemodule Dispatcher_script : sig ... end

Create a script that mostly behaves like "git", it concatenates its name with its first argument to call "${0}-${1}".

Very Unsafe Operations

Sourcemodule Magic : sig ... end

The Magic module is like OCaml's Obj.magic function for the EDSL; it allows one to bypass typing.

OCaml

Innovation. Community. Security.