Functorize git-kv with Pclock to save the right time when we commit

This commit is contained in:
Romain Calascibetta 2022-10-19 13:00:04 +02:00
parent 7323b8f065
commit 83be2b3f25
8 changed files with 303 additions and 241 deletions

11
.gitignore vendored Normal file
View file

@ -0,0 +1,11 @@
_build
setup.data
setup.log
doc/*.html
*.native
*.byte
*.so
*.tar.gz
_tests
*.merlin
*.install

17
.ocamlformat Normal file
View file

@ -0,0 +1,17 @@
version=0.23.0
profile=conventional
break-struct=natural
break-infix=fit-or-vertical
break-sequences=false
break-collection-expressions=wrap
break-separators=before
exp-grouping=preserve
parens-tuple=multi-line-only
space-around-lists=false
space-around-records=false
space-around-arrays=false
break-fun-decl=smart
cases-exp-indent=2
sequence-style=before
field-space=tight
break-before-in=auto

View file

@ -1,4 +1,4 @@
(executable (executable
(name mgit) (name mgit)
(public_name mgit) (public_name mgit)
(libraries logs.fmt fmt.tty git-unix git-kv)) (libraries mirage-clock-unix logs.fmt fmt.tty git-unix git-kv))

View file

@ -1,4 +1,5 @@
let () = Printexc.record_backtrace true let () = Printexc.record_backtrace true
module Store = Git_kv.Make (Pclock)
let reporter ppf = let reporter ppf =
let report src level ~over k msgf = let report src level ~over k msgf =
@ -25,17 +26,17 @@ open Rresult
open Lwt.Infix open Lwt.Infix
let get ~quiet store key = let get ~quiet store key =
Git_kv.get store key >>= function Store.get store key >>= function
| Ok contents when not quiet -> | Ok contents when not quiet ->
Fmt.pr "@[<hov>%a@]\n%!" (Hxd_string.pp Hxd.default) contents ; Fmt.pr "@[<hov>%a@]\n%!" (Hxd_string.pp Hxd.default) contents ;
Lwt.return (Ok 0) Lwt.return (Ok 0)
| Ok _ -> Lwt.return (Ok 0) | Ok _ -> Lwt.return (Ok 0)
| Error err -> | Error err ->
if not quiet then Fmt.epr "%a.\n%!" Git_kv.pp_error err ; if not quiet then Fmt.epr "%a.\n%!" Store.pp_error err ;
Lwt.return (Ok 1) Lwt.return (Ok 1)
let list ~quiet store key = let list ~quiet store key =
Git_kv.list store key >>= function Store.list store key >>= function
| Ok lst when not quiet -> | Ok lst when not quiet ->
List.iter (fun (name, k) -> match k with List.iter (fun (name, k) -> match k with
| `Dictionary -> Fmt.pr "d %s\n%!" name | `Dictionary -> Fmt.pr "d %s\n%!" name
@ -43,7 +44,7 @@ let list ~quiet store key =
Lwt.return (Ok 0) Lwt.return (Ok 0)
| Ok _ -> Lwt.return (Ok 0) | Ok _ -> Lwt.return (Ok 0)
| Error err -> | Error err ->
if not quiet then Fmt.epr "%a.\n%!" Git_kv.pp_error err ; if not quiet then Fmt.epr "%a.\n%!" Store.pp_error err ;
Lwt.return (Ok 1) Lwt.return (Ok 1)
let pull ~quiet store = let pull ~quiet store =

View file

@ -12,6 +12,8 @@ depends: [
"git" {>= "3.9.0"} "git" {>= "3.9.0"}
"mirage-kv" {>= "4.0.0"} "mirage-kv" {>= "4.0.0"}
"git-unix" "git-unix"
"mirage-clock-unix"
"mirage-clock"
"ptime" "ptime"
] ]

View file

@ -2,4 +2,4 @@
(name git_kv) (name git_kv)
(public_name git-kv) (public_name git-kv)
(flags (-w -32)) (flags (-w -32))
(libraries git ptime mirage-kv)) (libraries git ptime mirage-clock mirage-kv))

View file

@ -116,21 +116,6 @@ type change = [
| `Change of key | `Change of key
] ]
type error = Mirage_kv.error
type write_error = [ `Msg of string
| `Hash_not_found of Digestif.SHA1.t
| `Reference_not_found of Git.Reference.t
| Mirage_kv.write_error ]
let pp_error ppf = Mirage_kv.pp_error ppf
let pp_write_error ppf = function
| #Mirage_kv.write_error as err -> Mirage_kv.pp_write_error ppf err
| `Reference_not_found _ | `Msg _ as err -> Store.pp_error ppf err
| `Hash_not_found hash -> Store.pp_error ppf (`Not_found hash)
let disconnect _t = Lwt.return_unit
module SHA1 = struct module SHA1 = struct
include Digestif.SHA1 include Digestif.SHA1
@ -356,6 +341,24 @@ let of_octets ctx ~remote data =
(Printexc.raw_backtrace_to_string (Printexc.get_raw_backtrace ())) ; (Printexc.raw_backtrace_to_string (Printexc.get_raw_backtrace ())) ;
Lwt.return_error (`Msg "Invalid PACK file")) Lwt.return_error (`Msg "Invalid PACK file"))
module Make (Pclock : Mirage_clock.PCLOCK) = struct
type nonrec t = t
type key = Mirage_kv.Key.t
type error = Mirage_kv.error
type write_error = [ `Msg of string
| `Hash_not_found of Digestif.SHA1.t
| `Reference_not_found of Git.Reference.t
| Mirage_kv.write_error ]
let pp_error ppf = Mirage_kv.pp_error ppf
let disconnect _t = Lwt.return_unit
let pp_write_error ppf = function
| #Mirage_kv.write_error as err -> Mirage_kv.pp_write_error ppf err
| `Reference_not_found _ | `Msg _ as err -> Store.pp_error ppf err
| `Hash_not_found hash -> Store.pp_error ppf (`Not_found hash)
let exists t key = let exists t key =
let open Lwt.Infix in let open Lwt.Infix in
match t.head with match t.head with
@ -483,7 +486,7 @@ let rec unroll_tree t ?head (pred_name, pred_hash) rpath =
let set t key contents = let set t key contents =
let segs = Mirage_kv.Key.segments key in let segs = Mirage_kv.Key.segments key in
let now () = 0L (* TODO(dinosaure): functorize? *) in let now () = Int64.of_float (Ptime.to_float_s (Ptime.v (Pclock.now_d_ps ()))) in
match segs with match segs with
| [] -> assert false | [] -> assert false
| path -> | path ->
@ -525,7 +528,7 @@ let batch t ?retries:_ f = f t
let remove t key = let remove t key =
let segs = Mirage_kv.Key.segments key in let segs = Mirage_kv.Key.segments key in
let now () = 0L (* TODO(dinosaure): functorize? *) in let now () = Int64.of_float (Ptime.to_float_s (Ptime.v (Pclock.now_d_ps ()))) in
match List.rev segs, t.head with match List.rev segs, t.head with
| [], _ -> assert false | [], _ -> assert false
| _, None -> Lwt.return_ok () (* XXX(dinosaure): or [`Not_found]? *) | _, None -> Lwt.return_ok () (* XXX(dinosaure): or [`Not_found]? *)
@ -571,3 +574,4 @@ let rename t ~source ~dest =
get t source >>= fun contents -> get t source >>= fun contents ->
remove t source >>= fun () -> remove t source >>= fun () ->
set t dest contents set t dest contents
end

View file

@ -3,24 +3,51 @@
remote one: either this is the only writer (and thus only set/remove remote one: either this is the only writer (and thus only set/remove
operations need to be pushed, or the API client receives a callback that operations need to be pushed, or the API client receives a callback that
some update was done, and proceeds with a pull. *) some update was done, and proceeds with a pull. *)
type t
val connect : Mimic.ctx -> string -> t Lwt.t
(** [connect ctx remote] creates a new Git store which synchronizes
with [remote] {i via} protocols available into the given [ctx].
@raise [Invalid_argument _] if we can not initialize the store, or if
we can not fetch the given [remote]. *)
val to_octets : t -> string Lwt.t
(** [to_octets store] returns a serialized version of the given [store]. *)
val of_octets : Mimic.ctx -> remote:string -> string ->
(t, [> `Msg of string]) result Lwt.t
(** [of_octets ctx ~remote contents] tries to re-create a {!type:t} from its
serialized version [contents]. This function does not do I/O and the
returned {!type:t} can be out of sync with the given [remote]. We advise
to call {!val:pull} to be in-sync with [remote]. *)
type change = [ `Add of Mirage_kv.Key.t
| `Remove of Mirage_kv.Key.t
| `Change of Mirage_kv.Key.t ]
val pull : t -> (change list, [> `Msg of string ]) result Lwt.t
(** [pull store] tries to synchronize the remote Git repository with your local
[store] Git repository. It returns a list of changes between the old state
of your store and what you have remotely. *)
val push : t -> (unit, [> `Msg of string ]) result Lwt.t
(** [push store] tries to push any changes from your local Git repository
[store] to the remoe Git repository. The [push] function can fails for many
reasons. Currently, we don't handle merge politics and how we can resolve
conflicts between local and remote Git repositories. That mostly means that
if you are the only one who push to the Git repository (into a specific
branch), everything should be fine. But, if someone else push into the same
remote Git repository, your change can be discarded by the remote server
(due to conflicts). *)
module Make (Pclock : Mirage_clock.PCLOCK) : sig
include Mirage_kv.RW include Mirage_kv.RW
with type write_error = [ `Msg of string with type t = t
and type write_error = [ `Msg of string
| `Hash_not_found of Digestif.SHA1.t | `Hash_not_found of Digestif.SHA1.t
| `Reference_not_found of Git.Reference.t | `Reference_not_found of Git.Reference.t
| Mirage_kv.write_error ] | Mirage_kv.write_error ]
val connect : Mimic.ctx -> string -> t Lwt.t
val to_octets : t -> string Lwt.t
val of_octets : Mimic.ctx -> remote:string -> string ->
(t, [> `Msg of string]) result Lwt.t
type change = [ `Add of key
| `Remove of key
| `Change of key ]
val pull : t -> (change list, [> `Msg of string ]) result Lwt.t
val push : t -> (unit, [> `Msg of string ]) result Lwt.t
val size : t -> key -> (int, error) result Lwt.t val size : t -> key -> (int, error) result Lwt.t
end