Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file sync.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295(*
* Copyright (c) 2013-2017 Thomas Gazagnaire <thomas@gazagnaire.org>
* and Romain Calascibetta <romain.calascibetta@gmail.com>
*
* 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.
*)let(<.>)fgx=f(gx)letsrc=Logs.Src.create"git.sync"moduleLog=(valLogs.src_logsrc:Logs.LOG)moduletypeS=sigtypehashtypestoretypeerror=private[>Mimic.error|`Exnofexn]valpp_error:errorFmt.tvalfetch:?push_stdout:(string->unit)->?push_stderr:(string->unit)->ctx:Mimic.ctx->Smart_git.Endpoint.t->store->?version:[>`V1]->?capabilities:Smart.Capability.tlist->?deepen:[`Depthofint|`Timestampofint64]->[`All|`Someof(Reference.t*Reference.t)list|`None]->((hash*(Reference.t*hash)list)option,error)resultLwt.tvalpush:ctx:Mimic.ctx->Smart_git.Endpoint.t->store->?version:[>`V1]->?capabilities:Smart.Capability.tlist->[`CreateofReference.t|`DeleteofReference.t|`UpdateofReference.t*Reference.t]list->(unit,error)resultLwt.tendmoduleMake(Digestif:Digestif.S)(Pack:Smart_git.APPENDwithtype+'afiber='aLwt.t)(Index:Smart_git.APPENDwithtype+'afiber='aLwt.t)(Store:Minimal.Swithtypehash=Digestif.t)(HTTP:Smart_git.HTTP)=structtypehash=Digestif.ttypestore=Store.ttypeerror=[`Exnofexn|`StoreofStore.error|Mimic.error]letpp_errorppf=function|#Mimic.erroraserr->Mimic.pp_errorppferr|`Exnexn->Fmt.pfppf"Exception: %s"(Printexc.to_stringexn)|`Storeerr->Fmt.pfppf"Store error: %a"Store.pp_errorerr|`Invalid_flow->Fmt.pfppf"Invalid flow"moduleHash=Hash.Make(Digestif)moduleScheduler=Hkt.Make_sched(Lwt)moduleMinistore=Hkt.Make_store(structtype('k,'v)t=Store.t*('k,'v)Hashtbl.t(* constraint 'k = Digestif.t *)end)openLwt.Infixletget_commit_for_negotiation(t,hashtbl)hash=Log.debug(funm->m"Load commit %a."Hash.pphash);matchHashtbl.findhashtblhashwith|v->Lwt.return_somev|exceptionNot_found->((* XXX(dinosaure): given hash can not exist into [t],
* in this call we try to see if remote hashes are available
* locally. *)Store.readthash>>=function|Ok(Value.Commitcommit)->let{User.date=ts,_;_}=Store.Value.Commit.committercommitinletv=hash,ref0,tsinHashtbl.addhashtblhashv;Lwt.return_somev|Ok_|Error_->Lwt.return_none)letparents_of_committhash=Log.debug(funm->m"Get parents of %a."Hash.pphash);Store.read_exnthash>>=function|Value.Commitcommit->(Store.is_shallowedthash>>=function|false->Lwt.return(Store.Value.Commit.parentscommit)|true->Lwt.return[])|_->Lwt.return[]letparents((t,_hashtbl)asstore)hash=parents_of_committhash>>=funparents->letfoldacchash=get_commit_for_negotiationstorehash>>=function|Somev->Lwt.return(v::acc)|None->Lwt.returnaccinLwt_list.fold_left_sfold[]parentsletderef(t,_)refname=Log.debug(funm->m"Dereference %a."Reference.pprefname);Store.Ref.resolvetrefname>>=function|Okhash->Lwt.return_somehash|Error_->Lwt.return_noneletlocals(t,_)=Log.debug(funm->m"Load locals references.");Store.Ref.listt>>=Lwt_list.map_p(Lwt.return<.>fst)letshallowed(t,_)=Log.debug(funm->m"Shallowed commits of the store.");Store.shallowedtletshallow(t,_)hash=Log.debug(funm->m"Shallow %a."Hash.pphash);Store.shallowthashletunshallow(t,_)hash=Log.debug(funm->m"Unshallow %a."Hash.pphash);Store.unshallowthashletaccess=Sigs.{get=(funuidt->Scheduler.inj(get_commit_for_negotiation(Ministore.prjt)uid));parents=(funuidt->Scheduler.inj(parents(Ministore.prjt)uid));deref=(funtrefname->Scheduler.inj(deref(Ministore.prjt)refname));locals=(funt->Scheduler.inj(locals(Ministore.prjt)));shallowed=(funt->Scheduler.inj(shallowed(Ministore.prjt)));shallow=(funtuid->Scheduler.inj(shallow(Ministore.prjt)uid));unshallow=(funtuid->Scheduler.inj(unshallow(Ministore.prjt)uid));}letlightly_loadthash=Store.read_exnthash>>=funv->letkind=matchvwith|Value.Commit_->`A|Value.Tree_->`B|Value.Blob_->`C|Value.Tag_->`Dinletlength=Int64.to_int(Store.Value.lengthv)inLwt.return(kind,length)letheavily_loadthash=Store.read_inflatedthash>>=function|Some(kind,{Cstruct.buffer;off;len})->letkind=matchkindwith|`Commit->`A|`Tree->`B|`Blob->`C|`Tag->`Dinletraw=Bigstringaf.subbuffer~off~leninLwt.return(Carton.Dec.v~kindraw)|None->Lwt.failNot_foundincludeSmart_git.Make(Scheduler)(Pack)(Index)(HTTP)(Hash)(Reference)let(>>?)xf=x>>=functionOkx->fx|Errorerr->Lwt.return_errorerrletfetch?(push_stdout=ignore)?(push_stderr=ignore)~ctxendpointt?version?capabilities?deepenwant~src~dst~idx~create_idx_stream~create_pack_streamt_pckt_idx=letwant,src_dst_mapping=matchwantwith|(`All|`None)asx->x,funsrc->[src]|`Somesrc_dst_refs->letsrc_refs=List.mapfstsrc_dst_refsinletsrc_dst_map=List.fold_left(funsrc_dst_map(src_ref,dst_ref)->tryletdst_refs=Reference.Map.findsrc_refsrc_dst_mapinifList.exists(Reference.equaldst_ref)dst_refsthensrc_dst_mapelseReference.Map.addsrc_ref(dst_ref::dst_refs)src_dst_mapwithNot_found->Reference.Map.addsrc_ref[dst_ref]src_dst_map)Reference.Map.emptysrc_dst_refsinletsrc_dst_mappingsrc_ref=Reference.Map.find_optsrc_refsrc_dst_map|>Option.value~default:[src_ref]in`Somesrc_refs,src_dst_mappinginletministore=Ministore.inj(t,Hashtbl.create0x100)infetch~push_stdout~push_stderr~ctx(access,lightly_loadt,heavily_loadt)ministoreendpoint?version?capabilities?deepenwantt_pckt_idx~src~dst~idx>>?function|`Empty->Lwt.return_okNone|`Pack(uid,refs)->Store.batch_writetuid~pck:(create_pack_stream())~idx:(create_idx_stream())>|=Rresult.R.reword_error(funerr->`Storeerr)>>?fun()->letupdate(src_ref,hash)=letwrite_dst_refdst_ref=Store.Ref.writetdst_ref(Reference.Uidhash)>>=function|Okv->Lwt.returnv|Errorerr->Log.warn(funm->m"Impossible to update %a to %a: %a."Reference.ppsrc_refStore.Hash.pphashStore.pp_errorerr);Lwt.return_unitinletdst_refs=src_dst_mappingsrc_refinLwt_list.iter_pwrite_dst_refdst_refsinLwt_list.iter_pupdaterefs>>=fun()->Lwt.return_ok(Some(uid,refs))letget_object_for_packerthash=Store.readthash>>=function|Ok(Value.Blob_)->Lwt.return_some(Pck.make~kind:Pck.blobPck.Leafhash)|Ok(Value.Treetree)->lethashes=Tree.hashestreeinLwt.return_some(Pck.make~kind:Pck.treehasheshash)|Ok(Value.Commitcommit)->(Store.is_shallowedthash>|=function|true->[]|false->Store.Value.Commit.parentscommit)>>=funpreds->letroot=Store.Value.Commit.treecommitinlet{User.date=ts,_;_}=Store.Value.Commit.committercommitinLwt.return_some(Pck.make~kind:Pck.commit{Pck.root;Pck.preds}~tshash)|Ok(Value.Tagtag)->letpred=Store.Value.Tag.objtaginLwt.return_some(Pck.make~kind:Pck.tagpredhash)|Error_->Lwt.return_noneletget_object_for_packer(t,hashtbl)hash=matchHashtbl.findhashtblhashwith|v->Lwt.return_somev|exceptionNot_found->(get_object_for_packerthash>>=function|Someoasv->Hashtbl.replacehashtblhasho;Lwt.returnv|None->Lwt.return_none)letaccess=Sigs.{get=(funuidt->Scheduler.inj(get_object_for_packer(Ministore.prjt)uid));parents=(fun__->assertfalse);deref=(funtrefname->Scheduler.inj(deref(Ministore.prjt)refname));locals=(fun_->assertfalse);shallowed=(fun_->assertfalse);shallow=(fun_->assertfalse);unshallow=(fun_->assertfalse);}letpush~ctxendpointt?version?capabilitiescmds=letministore=Ministore.inj(t,Hashtbl.create0x100)inpush~ctx(access,lightly_loadt,heavily_loadt)ministoreendpoint?version?capabilitiescmdsend