this repo has no description

some morbig

Changed files
+125 -11
src
+4
.gitignore
···
_build
+
*.sh
+
*.sjson
+
*.json
+
*.shl
+4
README.md
···
```
$ sudo zpool destroy shelter && sudo zpool create shelter /var/shelter.img && sudo rm -rf ~/.cache/shelter
```
+
+
## Shl files
+
+
You can run both the main shelter program and the passthrough mode via a series of actions in a `.shl` file.
+27 -8
src/bin/main.ml
···
end
module Pass = Shelter.Make (History) (Shelter_passthrough)
-
module Shelter = Shelter.Make (Shelter_main.History) (Shelter_main)
+
module Main = Shelter.Make (Shelter_main.History) (Shelter_main)
let home = Unix.getenv "HOME"
···
(* Command Line *)
open Cmdliner
+
+
let cmd_file =
+
let doc = "Path to a file containing a series of commands." in
+
Arg.(
+
value
+
& opt (some file) None
+
& info [ "f"; "file" ] ~docv:"COMMAND_FILE" ~doc)
let main =
-
let run config =
+
let run config cmd_file =
Eio_posix.run @@ fun env ->
+
let cmd_file = Option.map (Eio.Path.( / ) env#fs) cmd_file in
let dir = state_dir env#fs "shelter" in
-
Shelter.main config env#fs env#clock env#process_mgr dir
+
Main.main config env#fs env#clock env#process_mgr dir cmd_file
in
-
let t = Term.(const run $ Shelter_main.config_term) in
+
let t = Term.(const run $ Shelter_main.config_term $ cmd_file) in
let man =
[
`P
···
(Cmd.v info t, t, info)
let passthrough =
-
let run config =
+
let run config cmd_file =
Eio_posix.run @@ fun env ->
+
let cmd_file = Option.map (Eio.Path.( / ) env#fs) cmd_file in
let dir = state_dir env#fs "passthrough" in
-
Pass.main config env#fs env#clock env#process_mgr dir
+
Pass.main config env#fs env#clock env#process_mgr dir cmd_file
in
-
let t = Term.(const run $ Shelter_passthrough.config_term) in
+
let t = Term.(const run $ Shelter_passthrough.config_term $ cmd_file) in
let info = Cmd.info "passthrough" in
Cmd.v info t
+
let extract_commands =
+
let run cmd_file =
+
Eio_posix.run @@ fun env ->
+
let cmd_file = Eio.Path.( / ) env#fs (Option.get cmd_file) in
+
Shelter.Script.to_commands cmd_file |> List.iter (Fmt.pr "%s\n")
+
in
+
let t = Term.(const run $ cmd_file) in
+
let info = Cmd.info "extract" in
+
Cmd.v info t
+
let cmds =
let cmd, term, info = main in
-
let cmds = [ cmd; passthrough ] in
+
let cmds = [ cmd; passthrough; extract_commands ] in
Cmd.group ~default:term info cmds
let () =
+1 -1
src/lib/dune
···
(library
(name shelter)
(public_name shelter)
-
(libraries cmdliner irmin-fs.unix eio.unix eio linenoise void repr))
+
(libraries cmdliner irmin-fs.unix eio.unix eio linenoise void repr morbig))
+57
src/lib/script.ml
···
+
module Cst = Morbig.CST
+
+
let redirect_to_string = function
+
| Cst.IoRedirect_IoFile { value = io_file; _ } -> (
+
match io_file with
+
| Cst.IoFile_Great_FileName
+
{ value = Cst.Filename_Word { value = Cst.Word (w, _); _ }; _ } ->
+
Fmt.str "> %s" w
+
| Cst.IoFile_DGreat_FileName
+
{ value = Cst.Filename_Word { value = Cst.Word (w, _); _ }; _ } ->
+
Fmt.str ">> %s" w
+
| _ -> failwith "Redirect Unsupported")
+
| _ -> failwith "IO Redirect Unsupported"
+
+
let cmd_suffix_to_list s =
+
let rec loop = function
+
| Cst.CmdSuffix_Word { value = Cst.Word (s, _); _ } -> [ s ]
+
| Cst.CmdSuffix_CmdSuffix_Word (suff, { value = Cst.Word (s, _); _ }) ->
+
s :: loop suff.value
+
| Cst.CmdSuffix_CmdSuffix_IoRedirect (suff, { value = redirect; _ }) ->
+
let sf = loop suff.value in
+
redirect_to_string redirect :: sf
+
| _ -> failwith "Unsupported!"
+
in
+
loop s |> List.rev |> String.concat " "
+
+
let of_cmd (c : Cst.command) =
+
match c with
+
| Cst.Command_SimpleCommand simple -> (
+
match simple.value with
+
| Cst.SimpleCommand_CmdName
+
{ value = Cst.CmdName_Word { value = Cst.Word (w, _); _ }; _ } ->
+
w
+
| Cst.SimpleCommand_CmdName_CmdSuffix
+
( { value = Cst.CmdName_Word { value = Cst.Word (w, _); _ }; _ },
+
{ value = suff; _ } ) ->
+
let s = cmd_suffix_to_list suff in
+
w ^ " " ^ s
+
| _ -> failwith "Unsupported")
+
| _ -> failwith "Unsupported"
+
+
let cmds_to_strings =
+
let v =
+
object
+
inherit [_] Morbig.CSTVisitors.reduce
+
method zero = []
+
method plus = List.append
+
method! visit_command acc c = of_cmd c :: acc
+
end
+
in
+
v#visit_program []
+
+
let to_commands file =
+
let contents = Eio.Path.load file in
+
let name = Eio.Path.native_exn file |> Filename.basename in
+
let ast = Morbig.parse_string name contents in
+
cmds_to_strings ast
+32 -2
src/lib/shelter.ml
···
module History = History
module Engine = Engine
+
module Script = Script
module Make (H : History.S) (Engine : Engine.S with type entry = H.t) = struct
module Store = Irmin_fs_unix.KV.Make (H)
···
in
loop store initial_ctx (`Exited 0)
-
let main config fs clock proc directory =
+
let command_file_to_actions cf =
+
Eio.Path.load cf |> String.split_on_char '\n'
+
|> List.map Engine.action_of_command
+
+
let main config fs clock proc directory command_file =
Irmin_fs.run directory @@ fun () ->
let conf = Irmin_fs.config (Eio.Path.native_exn directory) in
let repo = Store.Repo.v conf in
let store = Store.main repo in
-
run config fs clock proc store
+
match command_file with
+
| Some file -> (
+
let actions = command_file_to_actions file in
+
let store = History.Store ((module Store), store) in
+
let initial_ctx = Engine.init fs proc store in
+
let folder (store, ctx, exit_code) action =
+
if exit_code <> `Exited 0 then (store, ctx, exit_code)
+
else
+
match Engine.run config fs clock proc (store, ctx) action with
+
| Error (Eio.Process.Child_error exit_code) ->
+
Fmt.epr "%a\n%!" Eio.Process.pp_status exit_code;
+
(store, ctx, exit_code)
+
| Error (Eio.Process.Executable_not_found m) ->
+
Fmt.epr "cshell: excutable not found %s\n%!" m;
+
(store, ctx, `Exited 127)
+
| Ok (store, ctx) -> (store, ctx, `Exited 0)
+
in
+
let _store, _ctx, exit_code =
+
List.fold_left folder (store, initial_ctx, `Exited 0) actions
+
in
+
match exit_code with
+
| `Exited 0 -> ()
+
| `Exited n | `Signaled n ->
+
Fmt.epr "%a\n%!" Eio.Process.pp_status exit_code;
+
exit n)
+
| None -> run config fs clock proc store
end