Genspio: Generate Shell Phrases In OCaml
Genspio is a typed EDSL to generate shell scripts and commands from OCaml.
The idea is to build values of type
'a EDSL.t with the
combinators in the
Genspio.EDSL module, and compile them to POSIX
shell scripts (or one-liners) with functions from
See the file
which generates a useful list of usage examples, or the
section “Getting Started” below.
The tests run the output of the compiler against a few shells that it tries to
find on the host (e.g.
zsh … cf. the
example test results summary below).
If you have any questions, do not hesitate to submit an issue.
Genspio's documentation root is at https://smondet.gitlab.io/genspio-doc/.
You can install the library though
opam install genspio
Or get the development version with
opam pin add genspio https://github.com/hammerlab/genspio.git
You can also build locally:
ocaml please.mlt configure jbuilder build @install
Here is a quick example:
utop> open Genspio.EDSL;; utop> let c = let username_one_way : c_string t = (* We lift the string "USER" to EDSL-land and use function `getenv`: *) getenv (string "USER") in let username_the_other_way : c_string t = (* The usual pipe operator is `||>` *) (exec ["whoami"] ||> exec ["tr"; "-d"; "\\n"]) (* `get_stdout` takes `stdout` from a `unit t` as a `byte_array t` *) |> get_stdout (* `to_c_string` checks that a `byte_array t` can be casted to a `c_string` *) |> to_c_string in let my_printf : string -> c_string t list -> unit t = fun fmt args -> (* The function `call` is like `exec` but operates on `c_string t` values instead of just OCaml strings: *) call (string "printf" :: string fmt :: args) in (* The operator `=$=` is `string t` equality, it returns a `bool t` that we can use with `if_seq`: *) if_seq (username_one_way =$= username_the_other_way) ~t:[ my_printf "Username matches: `%s`\\n" [username_one_way]; ] ~e:[ my_printf "Usernames do not match: `%s` Vs `%s`\\n" [username_one_way; username_the_other_way]; ] ;; val c : unit t utop> Sys.command (Genspio.Compile.to_one_liner c);; Username matches: `smondet` - : int = 0
- There are many examples in
src/examples/small.mlwhich are used to generate the usage examples documentation webpage.
- The file
src/examples/downloader.mlcontains a (much) bigger example.
- The file
src/examples/vm_tester.mlis a “Makefile + scripts” generator to setup Qemu virtual machines, they can be for instance used to run the tests on more exotic platforms.
- The project
hammerlab/secotrecis a real-world, larger-scale use of Genspio (for now using version 0.0.0).
To run the tests you also need
make and there is an additional dependency on
uri library, see:
genspio_test=_build/default/src/test/main.exe jbuilder build $genspio_test $genspio_test --help
$genspio_test --important-shells bash,dash /tmp/gtests/ cd /tmp/gtests/ make run-all # Attempts to run all the tests on all the shells make check # Checks that all the tests for the important ones succeeded
You can generate a markdown report with
make report and check
You can check failures in the
<shell-test>/failures.md files, see for instance
ksh-StdML/failures.md for the failures of the “KSH with standard Genspio
compilation to multi-line scripts” (similarly there are
From here, one can explore:
It's Apache 2.0.