1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465[@@@ocaml.warning"-3"]typet={repo:string;(* Remote repository from which to pull. *)gref:string;(* Ref to pull, e.g. "master" or "pull/12/head". *)hash:string;(* Hash that [gref] is expected to have. *)}[@@derivingyojson][@@@ocaml.warning"+3"]letensure_no_spacesx=ifString.containsx' 'thenFmt.failwith"Spaces are not allowed here (in %S)"xletv~repo~gref~hash=ensure_no_spacesrepo;ensure_no_spacesgref;ensure_no_spaceshash;{repo;gref;hash}letppf{repo;gref;hash}=Fmt.pff"%s#%s (%s)"repogrefhashletis_localt=ifAstring.String.is_prefix~affix:"file:"t.repothentrueelsematchString.index_optt.repo':',String.index_optt.repo'/'with|Somei,Somej->i<j(* http://... is remote; /http:foo is local *)|None,_->true(* All remote URLs have colons *)|Some_,None->false(* foo:bar is remote *)letequal=(=)letcompare=compareletdigest{repo;gref;hash}=Fmt.str"%s %s %s"repogrefhashletrepot=t.repoletgreft=t.greflethasht=t.hash(* git-clone doesn't like the "refs/heads" prefix. *)letstrip_headsgref=letprefix="refs/heads/"inletopenAstringinifString.is_prefix~affix:prefixgrefthenString.with_index_range~first:(String.lengthprefix)grefelsegrefletpp_user_clonefid=letshort_hash=Astring.String.with_range~len:8id.hashinifAstring.String.(is_prefix~affix:"refs/pull/"id.gref||is_prefix~affix:"refs/merge-requests/"id.gref)then((* GitHub and GitLab don't recognise pull requests in clones, but they do in fetches. *)Fmt.pff"git clone --recursive %S && cd %S && git fetch origin %S && git reset --hard %s"id.repo(Filename.basenameid.repo|>Filename.remove_extension)(strip_headsid.gref)short_hash)else(Fmt.pff"git clone --recursive %S -b %S && cd %S && git reset --hard %s"id.repo(strip_headsid.gref)(Filename.basenameid.repo|>Filename.remove_extension)short_hash)