···1717 (** A context that is not persisted, but is passed through each loop of the
1818 shell *)
19192020+ type error
2121+ (** Shell specific errors *)
2222+2323+ val pp_error : error Fmt.t
2424+2025 val init :
2126 _ Eio.Path.t ->
2227 Eio_unix.Process.mgr_ty Eio_unix.Process.mgr ->
···3338 Eio_unix.Process.mgr_ty Eio_unix.Process.mgr ->
3439 entry History.t * ctx ->
3540 action ->
3636- (entry History.t * ctx, Eio.Process.error) result
4141+ ( entry History.t * ctx,
4242+ [ `Process of Eio.Process.error | `Shell of error ] )
4343+ result
3744 (** [run history action] runs the action in [history]. Return a new [history]
3845 that can be persisted *)
3946
+6-2
src/lib/passthrough/shelter_passthrough.ml
···11open Eio
2233+type error = string
44+55+let pp_error = Fmt.string
66+37type config = unit
4859let config_term = Cmdliner.Term.const ()
···5660 S.set_exn ~info store (key ()) command;
5761 let _ : (unit, string) result = LNoise.history_add command in
5862 Ok (full_store, ()))
5959- else Error (Eio.Process.Child_error res)
6060- with Eio.Exn.Io (Eio.Process.E e, _) -> Error e
6363+ else Shelter.process_error (Eio.Process.Child_error res)
6464+ with Eio.Exn.Io (Eio.Process.E e, _) -> Shelter.process_error e
+16-7
src/lib/shelter.ml
···22module Engine = Engine
33module Script = Script
4455+let process_error e = Error (`Process e)
66+let shell_error e = Error (`Shell e)
77+58module Make (H : History.S) (Engine : Engine.S with type entry = H.t) = struct
66- module Store = Irmin_fs_unix.KV.Make (H)
99+ module Store = Irmin_git_unix.FS.KV (H)
710811 let run config ~stdout fs clock proc store =
912 let store = History.Store ((module Store), store) in
···1518 | Some input -> (
1619 let action = Engine.action_of_command input in
1720 match Engine.run config ~stdout fs clock proc (store, ctx) action with
1818- | Error (Eio.Process.Child_error exit_code) ->
2121+ | Error (`Process (Eio.Process.Child_error exit_code)) ->
1922 Fmt.epr "%a\n%!" Eio.Process.pp_status exit_code;
2023 loop store ctx exit_code
2121- | Error (Eio.Process.Executable_not_found m) ->
2222- Fmt.epr "cshell: excutable not found %s\n%!" m;
2424+ | Error (`Process (Eio.Process.Executable_not_found m)) ->
2525+ Fmt.epr "shelter: excutable not found %s\n%!" m;
2326 loop store ctx (`Exited 127)
2727+ | Error (`Shell e) ->
2828+ Fmt.epr "shelter: %a\n%!" Engine.pp_error e;
2929+ loop store ctx (`Exited 255)
2430 | Ok (store, ctx) -> loop store ctx (`Exited 0))
2531 in
2632 loop store initial_ctx (`Exited 0)
···4551 match
4652 Engine.run config ~stdout fs clock proc (store, ctx) action
4753 with
4848- | Error (Eio.Process.Child_error exit_code) ->
5454+ | Error (`Process (Eio.Process.Child_error exit_code)) ->
4955 Fmt.epr "%a\n%!" Eio.Process.pp_status exit_code;
5056 (store, ctx, exit_code)
5151- | Error (Eio.Process.Executable_not_found m) ->
5252- Fmt.epr "cshell: excutable not found %s\n%!" m;
5757+ | Error (`Process (Eio.Process.Executable_not_found m)) ->
5858+ Fmt.epr "shelter: excutable not found %s\n%!" m;
5359 (store, ctx, `Exited 127)
6060+ | Error (`Shell e) ->
6161+ Fmt.epr "shelter: %a\n%!" Engine.pp_error e;
6262+ (store, ctx, `Exited 255)
5463 | Ok (store, ctx) -> (store, ctx, `Exited 0)
5564 in
5665 let _store, _ctx, exit_code =
+106-38
src/lib/shelter/shelter_main.ml
···22module Store = Store
33module H = Shelter.History
4455+type error = string
66+77+let pp_error = Fmt.string
88+59module History = struct
610 type mode = Void.mode
711···221225 in
222226 { store; tool_dir = tools }
223227224224-(* Run a command *)
228228+(* Run a command:
229229+230230+ - TODO: pretty confusing that we `entry` to build from and also as the
231231+ thing we are building (e.g. the build field and the args field... *)
225232let exec (config : config) ~stdout fs proc
226233 ((H.Store ((module S), _) : entry H.t), (ctx : ctx)) (entry : entry) =
227234 let build, env, (uid, gid) =
···236243 { entry with pre = { entry.pre with build = Build build } }
237244 in
238245 (* Store things under History.pre, this makes it possible to rediscover
239239- the hash for something purely from the arguments needed to execute something
240240- rather than needing, for example, the time it took to execute! *)
241241- let new_cid = Store.cid (Repr.to_string History.pre_t hash_entry.pre) in
246246+ the hash for something purely from the arguments needed to execute something
247247+ rather than needing, for example, the time it took to execute!
248248+249249+ Also, combine it with previous build step. *)
250250+ let new_cid =
251251+ Store.cid (Cid.to_string build ^ Repr.to_string History.pre_t hash_entry.pre)
252252+ in
242253 let with_rootfs fn =
243254 if entry.pre.mode = R then (Store.Run.with_build ctx.store build fn, [])
244255 else Store.Run.with_clone ctx.store ~src:build new_cid fn
···255266 | `Build rootfs ->
256267 let spawn sw log =
257268 if config.no_runc then
269269+ (* Experiment Void Process *)
258270 let rootfs = Filename.concat rootfs "rootfs" in
259271 let void =
260272 Void.empty
···367379 post = { hash_entry.post with time };
368380 },
369381 rootfs )))
370370- else Error (Eio.Process.Child_error res)
382382+ else Shelter.process_error (Eio.Process.Child_error res)
383383+384384+let complete_exec ((H.Store ((module S), store) as s : entry H.t), ctx) clock fs
385385+ new_entry diff =
386386+ match new_entry with
387387+ | Error e -> Error e
388388+ | Ok (`Reset c) -> (
389389+ match
390390+ S.Hash.unsafe_of_raw_string c |> S.Commit.of_hash (S.repo store)
391391+ with
392392+ | None ->
393393+ Fmt.epr "Resetting to existing entry failed...\n%!";
394394+ Ok (s, ctx)
395395+ | Some c ->
396396+ S.Head.set store c;
397397+ Ok (s, ctx))
398398+ | Ok (`Entry (entry, path)) ->
399399+ (* Set diff *)
400400+ let entry = History.{ entry with post = { entry.post with diff } } in
401401+ (* Commit if RW *)
402402+ if entry.pre.mode = RW then (
403403+ commit
404404+ ~message:("exec " ^ String.concat " " entry.pre.args)
405405+ clock s entry;
406406+ (* Save the commit hash for easy restoring later *)
407407+ let hash = S.Head.get store |> S.Commit.hash |> S.Hash.to_raw_string in
408408+ Eio.Path.save ~create:(`If_missing 0o644)
409409+ Eio.Path.(fs / path / "hash")
410410+ hash);
411411+ Ok (s, ctx)
412412+413413+let replay config (H.Store ((module S), s) as store : entry H.t) ctx fs clock
414414+ proc stdout existing_branch =
415415+ let seshes = sessions store in
416416+ if not (List.exists (String.equal existing_branch) seshes) then (
417417+ Fmt.epr "%s does not exist!" existing_branch;
418418+ Ok (store, ctx))
419419+ else
420420+ let repo = S.repo s in
421421+ let onto = S.of_branch repo existing_branch in
422422+ match S.lcas ~n:1 s onto with
423423+ | Error lcas_error ->
424424+ Fmt.epr "Replay LCAS: %a" (Repr.pp S.lca_error_t) lcas_error;
425425+ Ok (store, ctx)
426426+ | Ok [ lcas ] -> (
427427+ let all_commits = history store in
428428+ let lcas_hash = S.Commit.hash lcas |> S.Hash.to_raw_string in
429429+ let rec collect = function
430430+ | [] -> []
431431+ | (x, _) :: _ when String.equal lcas_hash x -> []
432432+ | v :: vs -> v :: collect vs
433433+ in
434434+ let commits_to_apply = collect all_commits in
435435+ match commits_to_apply with
436436+ | [] -> Shelter.shell_error ""
437437+ | (h, first) :: rest ->
438438+ let _, last_other =
439439+ history (H.Store ((module S), onto)) |> List.hd
440440+ in
441441+ let new_first =
442442+ {
443443+ first with
444444+ pre = { first.pre with build = last_other.pre.build };
445445+ }
446446+ in
447447+ let commits_to_apply = (h, new_first) :: rest in
448448+ (* Now we reset our head to point to the other store's head
449449+ and replay our commits onto it *)
450450+ let other_head = S.Head.get onto in
451451+ S.Head.set s other_head;
452452+ let res =
453453+ List.fold_left
454454+ (fun last (_, (entry : entry)) ->
455455+ match last with
456456+ | Error _ as e -> e
457457+ | Ok (new_store, new_ctx) ->
458458+ let new_entry, diff =
459459+ exec config ~stdout fs proc (new_store, new_ctx) entry
460460+ in
461461+ complete_exec (new_store, new_ctx) clock fs new_entry diff)
462462+ (Ok (H.Store ((module S), s), ctx))
463463+ commits_to_apply
464464+ in
465465+ res)
466466+ | _ -> assert false (* Because n = 1 *)
371467372468let run (config : config) ~stdout fs clock proc
373469 (((H.Store ((module S), store) : entry H.t) as s), (ctx : ctx)) = function
···391487 Ok (s, ctx)
392488 | Ok store -> Ok (store, ctx)))
393489 | Unknown args ->
394394- Fmt.epr "%a: %s\n%!" (text `Red) "Unknown Shelter Action"
395395- (String.concat " " args);
396396- Ok (s, ctx)
490490+ Fmt.epr "%a" (text `Red) "Unknown Shelter Action\n";
491491+ Shelter.shell_error (String.concat " " args)
397492 | Info `Current ->
398493 let sessions = sessions s in
399494 let sesh = Option.value ~default:"main" (snd (which_branch s)) in
···430525 Ok (s, ctx)
431526 | Exec [] -> Ok (s, ctx)
432527 | Undo -> Ok (reset_hard s, ctx)
433433- | Replay _ -> Ok (s, ctx)
528528+ | Replay branch -> replay config s ctx fs clock proc stdout branch
434529 | Info `History ->
435530 display_history s;
436531 Ok (s, ctx)
···457552 let entry = { entry with pre = { entry.pre with args = command } } in
458553 try
459554 let new_entry, diff = exec config ~stdout fs proc (s, ctx) entry in
460460- match new_entry with
461461- | Error e -> Error e
462462- | Ok (`Reset c) -> (
463463- match
464464- S.Hash.unsafe_of_raw_string c |> S.Commit.of_hash (S.repo store)
465465- with
466466- | None ->
467467- Fmt.epr "Resetting to existing entry failed...\n%!";
468468- Ok (s, ctx)
469469- | Some c ->
470470- S.Head.set store c;
471471- Ok (s, ctx))
472472- | Ok (`Entry (entry, path)) ->
473473- (* Set diff *)
474474- let entry = { entry with post = { entry.post with diff } } in
475475- (* Commit if RW *)
476476- if entry.pre.mode = RW then (
477477- commit
478478- ~message:("exec " ^ String.concat " " command)
479479- clock s entry;
480480- (* Save the commit hash for easy restoring later *)
481481- let hash =
482482- S.Head.get store |> S.Commit.hash |> S.Hash.to_raw_string
483483- in
484484- Eio.Path.save ~create:(`If_missing 0o644)
485485- Eio.Path.(fs / path / "hash")
486486- hash);
487487- Ok (s, ctx)
488488- with Eio.Exn.Io (Eio.Process.E e, _) -> Error e)
555555+ complete_exec (s, ctx) clock fs new_entry diff
556556+ with Eio.Exn.Io (Eio.Process.E e, _) -> Shelter.process_error e)