123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330(*
* Copyright (c) 2013-2022 Thomas Gazagnaire <thomas@gazagnaire.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)open!ImportmoduletypeS_generic_key=sig(** {1 Commit values} *)typet[@@derivingirmin](** The type for commit values. *)typenode_key[@@derivingirmin](** Type for node keys. *)typecommit_key[@@derivingirmin](** Type for commit keys. *)moduleInfo:Info.S(** The type for commit info. *)valv:info:Info.t->node:node_key->parents:commit_keylist->t(** Create a commit. *)valnode:t->node_key(** The underlying node key. *)valparents:t->commit_keylist(** The commit parents. *)valinfo:t->Info.t(** The commit info. *)endmoduletypeS=sigtypehash[@@derivingirmin](** @inline *)includeS_generic_keywithtypenode_key=hashandtypecommit_key=hashendmoduletypePortable=sigincludeStypecommitvalof_commit:commit->tendopenstructmoduleS_is_a_generic_key(X:S):S_generic_key=XendmoduletypeMaker_generic_key=sigmoduleInfo:Info.SmoduleMake(H:Type.S)(N:Key.Swithtypehash=H.t)(C:Key.Swithtypehash=H.t):sigincludeS_generic_keywithtypenode_key=N.tandtypecommit_key=C.tandmoduleInfo=InfomodulePortable:Portablewithtypecommit:=tandtypehash:=H.tandmoduleInfo=InfoendmoduleMake_v2(H:Type.S)(N:Key.Swithtypehash=H.t)(C:Key.Swithtypehash=H.t):sigincludeS_generic_keywithtypenode_key=N.tandtypecommit_key=C.tandmoduleInfo=InfomodulePortable:Portablewithtypecommit:=tandtypehash:=H.tandmoduleInfo=InfoendendmoduletypeMaker=sigmoduleInfo:Info.SmoduleMake(H:Type.S):Swithtypehash=H.tandmoduleInfo=InfoendmoduletypeStore=sig(** {1 Commit Store} *)includeIndexable.SmoduleInfo:Info.S(** Commit info. *)(** [Val] provides functions for commit values. *)moduleVal:S_generic_keywithtypet=valueandtypecommit_key=keyandmoduleInfo:=InfomoduleHash:Hash.Typedwithtypet=hashandtypevalue=valuemoduleNode:Node.Storewithtypekey=Val.node_key(** [Node] is the underlying node store. *)valmerge:[>read_write]t->info:Info.f->keyoptionMerge.t(** [merge] is the 3-way merge function for commit keys. *)endmoduletypeHistory=sig(** {1 Commit History} *)type'at(** The type for store handles. *)typenode_key[@@derivingirmin](** The type for node keys. *)typecommit_key[@@derivingirmin](** The type for commit keys. *)typev[@@derivingirmin](** The type for commit objects. *)typeinfo[@@derivingirmin](** The type for commit info. *)valv:[>write]t->node:node_key->parents:commit_keylist->info:info->(commit_key*v)Lwt.t(** Create a new commit. *)valparents:[>read]t->commit_key->commit_keylistLwt.t(** Get the commit parents.
Commits form a append-only, fully functional, partial-order
data-structure: every commit carries the list of its immediate
predecessors. *)valmerge:[>read_write]t->info:(unit->info)->commit_keyMerge.t(** [merge t] is the 3-way merge function for commit. *)vallcas:[>read]t->?max_depth:int->?n:int->commit_key->commit_key->(commit_keylist,[`Max_depth_reached|`Too_many_lcas])resultLwt.t(** Find the lowest common ancestors
{{:http://en.wikipedia.org/wiki/Lowest_common_ancestor} lca} between two
commits. *)vallca:[>read_write]t->info:(unit->info)->?max_depth:int->?n:int->commit_keylist->(commit_keyoption,Merge.conflict)resultLwt.t(** Compute the lowest common ancestors ancestor of a list of commits by
recursively calling {!lcas} and merging the results.
If one of the merges results in a conflict, or if a call to {!lcas}
returns either [Error `Max_depth_reached] or [Error `Too_many_lcas] then
the function returns the same error. *)valthree_way_merge:[>read_write]t->info:(unit->info)->?max_depth:int->?n:int->commit_key->commit_key->(commit_key,Merge.conflict)resultLwt.t(** Compute the {!lcas} of the two commit and 3-way merge the result. *)valclosure:[>read]t->min:commit_keylist->max:commit_keylist->commit_keylistLwt.t(** Same as {{!Node.Graph.closure} Node.Graph.closure} but for the history
graph. *)valiter:[>read]t->min:commit_keylist->max:commit_keylist->?commit:(commit_key->unitLwt.t)->?edge:(commit_key->commit_key->unitLwt.t)->?skip:(commit_key->boolLwt.t)->?rev:bool->unit->unitLwt.t(** Same as {{!Node.Graph.iter} Node.Graph.iter} but for traversing the
history graph. *)endmoduletypeSigs=sigmoduletypeS=SmoduletypeMaker=Maker(** [Maker] provides a simple implementation of commit values, parameterized
by commit info. *)moduleMaker(I:Info.S):MakerwithmoduleInfo=I(** [Generic_key] generalises the concept of "commit" to one that supports
object keys that are not strictly equal to hashes. *)moduleGeneric_key:sigmoduletypeS=S_generic_keymoduletypeMaker=Maker_generic_keymoduleMaker(I:Info.S):MakerwithmoduleInfo=ImoduleStore(I:Info.S)(N:Node.Store)(S:Indexable.S)(H:Hash.Swithtypet=S.hash)(V:Swithtypenode_key=N.keyandtypecommit_key=S.keyandtypet=S.valueandmoduleInfo:=I):Storewithtype'at='aN.t*'aS.tandtypekey=S.keyandtypevalue=S.valueandmoduleInfo=Iandtypehash=S.hashandmoduleVal=VincludeMakerwithmoduleInfo=Info.Defaultend(** V1 serialisation. *)moduleV1:sigmoduleInfo:Info.Swithtypet=Info.Default.t(** Serialisation format for V1 info. *)moduleMake(Hash:Hash.S)(C:Generic_key.SwithmoduleInfo:=Info):sigincludeGeneric_key.SwithmoduleInfo=Infoandtypenode_key=C.node_keyandtypecommit_key=C.commit_keyvalimport:C.t->tvalexport:t->C.tendendmodulePortable:sig(** Portable form of a commit implementation that can be constructed from a
concrete representation and used in computing hashes. Conceptually, a
[Commit.Portable.t] is a [Commit.t] in which all internal keys have been
replaced with the hashes of the values they point to.
As with {!Node.Portable}, computations over portable values must commute
with those over [t]s. *)(** A node implementation with hashes for keys is trivially portable: *)moduleOf_commit(S:S):Portablewithtypecommit:=S.tandtypet=S.tandtypehash=S.hashandmoduleInfo=S.InfomoduletypeS=PortableendmoduletypeStore=Store(** [Store] specifies the signature for commit stores. *)(** [Store] creates a new commit store. *)moduleStore(I:Info.S)(N:Node.Store)(S:Content_addressable.Swithtypekey=N.key)(H:Hash.Swithtypet=S.key)(V:Swithtypehash=S.keyandtypet=S.valueandmoduleInfo:=I):Storewithtype'at='aN.t*'aS.tandtypekey=S.keyandtypehash=S.keyandtypevalue=S.valueandmoduleInfo=IandmoduleVal=VmoduletypeHistory=History(** [History] specifies the signature for commit history. The history is
represented as a partial-order of commits and basic functions to search
through that history are provided.
Every commit can point to an entry point in a node graph, where
user-defined contents are stored. *)(** Build a commit history. *)moduleHistory(C:Store):Historywithtype'at='aC.tandtypev=C.Val.tandtypenode_key=C.Node.keyandtypecommit_key=C.keyandtypeinfo=C.Info.tincludeMakerwithmoduleInfo=Info.Defaultend