Module EDSL (.ml)

module EDSL: sig .. end
The Embedded Domain Specific Lanaguage to create “shell-expressions.”

type 'a t = 'a Language.t 
The type of a Genspio expression.

Literals


val string : string -> string t
val int : int -> int t
val bool : bool -> bool t

Basic system Commands


val call : string t list -> unit t
Call a command from its list of “arguments” (including the first argument being the actual command).

Note that UNIX does not allow strings passed as arguments to executables to contain NUL-characters ('\x00'). The function Language.to_many_lines raises an exception if an argument is a literal and contains a NUL, but if the argument is the result of some other expression the behavior is for now undefined.

val exec : string list -> unit t
Like EDSL.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).
val getenv : string t -> string 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.
val setenv : var:string t -> string 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 (newlines, '\000'), behavior is undefined.


Boolean Expressions


val (&&&) : bool t -> bool t -> bool t
val (|||) : bool t -> bool t -> bool t
val not : bool t -> bool t
val (=$=) : string t -> string t -> bool t
val (<$>) : string t -> string t -> bool t
val returns : 'a t -> value:int -> bool t
Check the return value of a command/expression/script.
module Bool: sig .. end
val succeeds : 'a t -> bool t
succeeds expr is a equivalent to returns expr ~value:0.
val file_exists : string t -> bool t

Integer Arithmetic


module Integer: sig .. end

Lists


val list : 'a t list -> 'a list t
val list_append : 'a list t -> 'a list t -> 'a list t
val list_iter : 'a list t -> f:((unit -> 'a t) -> unit t) -> unit t
val list_to_string : 'a list t -> f:('a t -> string t) -> string t
val list_of_string : string t -> f:(string t -> 'a t) -> 'a list t

String Manipulation


val output_as_string : unit t -> string t
val feed : string:string t -> unit t -> unit t
Feed some content (~string) into the "stdin" filedescriptor of a unit t expression.
val (>>) : string t -> unit t -> unit t
str >> cmd is feed ~string:str cmd.
val string_concat : string t list -> string t
Concatenate an (OCaml) list of string t values.
val string_concat_list : string list t -> string t
Concatenate a Genspio list of strings string list t.

Control Flow


val nop : unit t
The silent “no-operation.”
val if_then_else : bool t -> unit t -> unit t -> unit t
val if_then : bool t -> unit t -> unit t
val seq : unit t list -> unit t
Sequence a list of expressions into an expression.
val loop_while : bool t -> body:unit t -> unit t
val if_seq : t:unit t list -> ?e:unit t list -> bool t -> unit t
if_seq c ~t ~e is an alternate API for EDSL.if_then_else (when ?e is provided) or EDSL.if_then (otherwise) that assumes “then” and “else” bodies to be lists for EDSL.seq construct.

Switch Statements


val switch : [ `Case of bool t * unit t | `Default of unit t ] list ->
unit t
Create a switch statement from a list of EDSL.case and optionally a EDSL.default (the function raises an exception if there are more than one default cases).
val case : bool t -> unit t list -> [> `Case of bool t * unit t ]
Create a normal case for a EDSL.switch statement.
val default : unit t list -> [> `Default of unit t ]
Create the default case for a EDSL.switch statement.

Redirections


type fd_redirection 
Abstract type of file-descriptor redirections.
val to_fd : int t -> int t -> fd_redirection
Create a file-descriptor to file-descriptor redirection.
val to_file : int t -> string t -> fd_redirection
Create a file-descriptor to file redirection.
val 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.

Cf. the example:

       with_redirections (exec ["printf""%s""hello"]) [
         to_file (int 3) (string "/path/to/one");
         to_file (int 3) (string "/path/to/two");
         to_fd (int 2) (int 3);
         to_fd (int 1) (int 2);
       ];
   

"printf '%s' 'hello'" will output to the file "/path/to/two", because redirections are set in that order:

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.
val write_output : ?stdout:string t ->
?stderr:string t ->
?return_value:string t -> unit t -> unit t
Redirect selected streams or the return value to files (stdout, stderr, return_value are paths).
val write_stdout : path:string t -> unit t -> unit t
write_stdout ~path expr is write_output expr ~stdout:path.
val pipe : unit t list -> unit t
Pipe commands together ("stdout" into "stdin" exactly like the " | " operator).
val (||>) : unit t -> unit t -> unit t
a ||> b is a shortcut for pipe [a; b].
val printf : string t -> string t list -> unit t
printf fmt l is call (string "printf" :: string "--" :: fmt :: l).
val eprintf : string t -> string t list -> unit t
Like EDSL.printf but redirected to "stderr".

Escaping The Execution Flow


val fail : unit t
Expression that aborts the whole script/command immediately.
val with_signal : ?signal_name:string ->
catch:unit t -> (unit t -> unit t) -> unit t
Use a UNIX signal (default "USR2") to create a “jump.”

with_signal ~catch (fun signal -> (* more_code *)) executes (* more_code *) but if it uses signal, the code behaves like a raised exception, and the catch argument is executed.

See the example:

        let tmp = tmp_file "appender" in
        seq [
          tmp#set (string "start");
          with_signal ~signal_name:"USR1" (fun signal ->
               seq [
                tmp#append (string "-signal");
                signal;
                tmp#append (string "-WRONG");
              ])
            ~catch:(seq [
                tmp#append (string "-caught")
              ]);
          call [string "printf"; string "tmp: %s\\n"; tmp#get];
          assert_or_fail "Timeline-of-tmp"
            (tmp#get =$= string "start-signal-caught");
        ]
    

Note that by default, the compiler functions use the signal "USR1" and having 2 calls to trap with the same signal in the same script does not play well, so use ~signal_name:"USR1" at your own risk.

Moreover, for now this feature makes use of "sh -c <>" sub-shells; it does not play well with arbitrary redirections.

val with_failwith : ((message:string Language.t -> return:int Language.t -> unit Language.t) ->
unit Language.t) ->
unit Language.t
with_failwith f uses ! and EDSL.with_signal to call f with a function that exits the flow of execution and displays ~message and returns ~return (a bit like Pervasives.failwith).

Temporary Files


type file = <
   append : string t -> unit t;
   delete : unit t;
   get : string t;
   path : string t;
   set : string t -> unit t;
>
Abstraction of a file, cf. EDSL.tmp_file.
val tmp_file : ?tmp_dir:string t -> string -> file
Create a temporary file that may contain arbitrary strings (can be used as variable containing string t values).

tmp_file (string "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 (string "foo") ensure that it is the same file.


Command Line Parsing


module Command_line: sig .. end
Typed command-line parsing for your shell scripts, à la Prtinf.scanf.

Very Unsafe Operations


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