hammerlab/genspio

Name: genspio

Owner: Hammer Lab

Description: Generate Shell Phrases In OCaml

Created: 2016-09-09 18:55:45.0

Updated: 2017-11-20 23:44:13.0

Pushed: 2017-12-14 19:29:48.0

Homepage: https://smondet.gitlab.io/genspio-doc/

Size: 326

Language: OCaml

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

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 Genspio.Compile.

Genspio is still in alpha status. For now the EDSL is based on a big GADT and compiles to POSIX one-liners or multi-line scripts.

The tests run the output of the compiler against a few shells that it tries to find on the host (e.g. dash, bash, busybox, mksh, zsh ? cf. the example test results summary below).

If you have any questions, do not hesitate to submit an issue.

Build

You can install the library though opam:

opam install genspio

Or get the development version with opam pin:

opam pin add genspio https://github.com/hammerlab/genspio.git

You can also build locally:

You need OCaml ? 4.03.0 together with nonstd, sosa, and jbuilder:

jbuilder build @install
Getting Started

Here is a quick example:

> open Genspio.EDSL;;

> 
c =
t username_one_way : c_string t =
(* We lift the string "USER" to EDSL-land and use function `getenv`: *)
getenv (string "USER") in
t 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 

t 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`: *)
_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];
 ]

c : unit t

> Sys.command (Genspio.Compile.to_one_liner c);;
name matches: `smondet`
int = 0

More examples:

Testing

To run the tests you also need make and there is an additional dependency on the uri library, see:

genspio_test=_build/default/src/test/main.exe
jbuilder build $genspio_test
$genspio_test --help

Try this:

$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:

Some failures are expected with not-really-POSIX or buggy shells like KSH93, or on some corner cases cf. #35.

You can check failures in the <shell-test>/failures.md files, see for instance ksh/failures.md:

(similarly there are <shell-test>/successes.md files).

Additional Documentation

From here, one can explore:

License

It's Apache 2.0.


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.