12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046letis_dir_sep=ifSys.win32||Sys.cygwinthenfunc->c='/'||c='\\'||c=':'elsefunc->c='/'letexplode_path=letrecstartaccpathi=ifi<0thenaccelseifis_dir_sep(String.unsafe_getpathi)thenstartaccpath(i-1)elsecomponentaccpathi(i-1)andcomponentaccpathend_i=ifi<0thenString.takepath(end_+1)::accelseifis_dir_sep(String.unsafe_getpathi)thenstart(String.subpath~pos:(i+1)~len:(end_-i)::acc)path(i-1)elsecomponentaccpathend_(i-1)infunpath->ifpath=Filename.current_dir_namethen[path]elsematchstart[]path(String.lengthpath-1)with|"."::xs->xs|xs->xsmoduleExternal:sigtypetvalto_sexp:tSexp.Encoder.tvalto_dyn:t->Dyn.tvalcompare:t->t->Ordering.tvalcompare_val:t->t->Ordering.tvalto_string:t->stringvalof_string:string->tvalrelative:t->string->tvalmkdir_p:t->unitvalbasename:t->stringvalparent:t->tvalinitial_cwd:tvalcwd:unit->tvalextend_basename:t->suffix:string->tvalextension:t->stringvalis_suffix:t->suffix:string->boolvalsplit_extension:t->t*stringvalset_extension:t->ext:string->tvalas_local:t->stringend=structincludeInterned.No_interning(structletinitial_size=512letresize_policy=Interned.Greedyletorder=Interned.Naturalend)()letcompare_valxy=String.compare(to_stringx)(to_stringy)letas_stringx~f=to_stringx|>f|>makeletextend_basenamet~suffix=as_stringt~f:(funt->t^suffix)letis_suffixt~suffix=String.is_suffix(to_stringt)~suffixletof_stringt=ifFilename.is_relativetthenExn.code_error"Path.External.of_string: relative path given"["t",Sexp.Encoder.stringt];maketletto_sexpt=Sexp.Encoder.string(to_stringt)letto_dynt=Dyn.String(to_stringt)(*
let rec cd_dot_dot t =
match Unix.readlink t with
| exception _ -> Filename.dirname t
| t -> cd_dot_dot t
let relative initial_t path =
let rec loop t components =
match components with
| [] | ["." | ".."] ->
die "invalid filename concatenation: %s / %s" initial_t path
| [fn] -> Filename.concat t fn
| "." :: rest -> loop t rest
| ".." :: rest -> loop (cd_dot_dot t) rest
| comp :: rest -> loop (Filename.concat t comp) rest
in
loop initial_t (explode_path path)
*)letrelativexy=matchywith|"."->x|_->make(Filename.concat(to_stringx)y)letrecmkdir_pt=lett_s=to_stringtinletp_s=Filename.dirnamet_sinletp=makep_sinifp<>tthentryUnix.mkdirt_s0o777with|Unix.Unix_error(EEXIST,_,_)->()|Unix.Unix_error(ENOENT,_,_)->mkdir_pp;Unix.mkdirt_s0o777letbasenamet=Filename.basename(to_stringt)letparentt=as_string~f:Filename.dirnametletextensiont=Filename.extension(to_stringt)letsplit_extensiont=lets,ext=Filename.split_extension(to_stringt)in(makes,ext)letset_extensiont~ext=let(base,_)=split_extensiontin(to_stringbase)^ext|>makeletcwd()=make(Sys.getcwd())letinitial_cwd=cwd()letas_localt=lets=to_stringtin"."^sendmoduleLocal:sigtypetvalto_sexp:tSexp.Encoder.tvalto_dyn:t->Dyn.tvalroot:tvalis_root:t->boolvalcompare:t->t->Ordering.tvalcompare_val:t->t->Ordering.tvalequal:t->t->boolvalof_string:?error_loc:Loc0.t->string->tvalto_string:t->stringvalrelative:?error_loc:Loc0.t->t->string->tvalappend:t->t->tvalparent:t->tvalmkdir_p:t->unitvaldescendant:t->of_:t->toptionvalis_descendant:t->of_:t->boolvalreach:t->from:t->stringvalbasename:t->stringvalextend_basename:t->suffix:string->tvalextension:t->stringvalis_suffix:t->suffix:string->boolvalsplit_extension:t->t*stringvalpp:Format.formatter->t->unitvalset_extension:t->ext:string->tmoduleL:sigvalrelative:?error_loc:Loc0.t->t->stringlist->tendmoduleSet:Set.Swithtypeelt=tmodulePrefix:sigtypelocal=ttypetvalmake:local->tvaldrop:t->local->localoption(* for all local path p, drop (invalid p = None) *)valinvalid:tendwithtypelocal:=tend=struct(* either "." for root, either a '/' separated list of components
other that ".", ".." and not containing '/'. *)includeInterned.No_interning(structletinitial_size=512letresize_policy=Interned.Greedyletorder=Interned.Naturalend)()letppppfs=Format.pp_print_stringppf(to_strings)letcompare_valxy=String.compare(to_stringx)(to_stringy)letequalxy=matchcomparexywith|Eq->true|Gt|Lt->falseletroot=make"."letis_roott=t=rootletis_suffixt~suffix=String.is_suffix(to_stringt)~suffixletto_list=letreclooptaccij=ifi=0thenString.taketj::accelsematcht.[i-1]with|'/'->loopt(String.subt~pos:i~len:(j-i)::acc)(i-1)(i-1)|_->looptacc(i-1)jinfunt->ifis_roottthen[]elselett=to_stringtinletlen=String.lengthtinloopt[]lenlenletparentt=ifis_roottthenExn.code_error"Path.Local.parent called on the root"[]elselett=to_stringtinmatchString.rindex_fromt(String.lengtht-1)'/'with|exceptionNot_found->root|i->make(String.taketi)letbasenamet=ifis_roottthenExn.code_error"Path.Local.basename called on the root"[]elselett=to_stringtinletlen=String.lengthtinmatchString.rindex_fromt(len-1)'/'with|exceptionNot_found->t|i->String.subt~pos:(i+1)~len:(len-i-1)letto_sexpt=Sexp.Encoder.string(to_stringt)letto_dynt=Dyn.String(to_stringt)moduleL=structletrelative_resulttcomponents=letreclooptcomponents=matchcomponentswith|[]->Result.Okt|"."::rest->looptrest|".."::rest->ifis_roottthenResult.Error()elseloop(parentt)rest|fn::rest->ifis_roottthenloop(makefn)restelseloop(make(to_stringt^"/"^fn))restinlooptcomponentsletrelative?error_loctcomponents=matchrelative_resulttcomponentswith|Result.Okt->t|Error()->Exn.fatalf?loc:error_loc"path outside the workspace: %s from %s"(String.concat~sep:"/"components)(to_stringt)endletrelative?error_loctpath=ifnot(Filename.is_relativepath)then(Exn.code_error"Local.relative: received absolute path"["t",to_sexpt;"path",Sexp.Encoder.stringpath]);matchL.relative_resultt(explode_pathpath)with|Result.Okt->t|Error()->Exn.fatalf?loc:error_loc"path outside the workspace: %s from %s"path(to_stringt)letis_canonicalized=letrecbefore_slashsi=ifi<0thenfalseelsematchs.[i]with|'/'->false|'.'->before_dot_slashs(i-1)|_->in_components(i-1)andbefore_dot_slashsi=ifi<0thenfalseelsematchs.[i]with|'/'->false|'.'->before_dot_dot_slashs(i-1)|_->in_components(i-1)andbefore_dot_dot_slashsi=ifi<0thenfalseelsematchs.[i]with|'/'->false|_->in_components(i-1)andin_componentsi=ifi<0thentrueelsematchs.[i]with|'/'->before_slashs(i-1)|_->in_components(i-1)infuns->letlen=String.lengthsinlen=0||before_slashs(len-1)letof_string?error_locs=matchswith|""|"."->root|_whenis_canonicalizeds->makes|_->relativeroots?error_locletrecmkdir_pt=ifis_roottthen()elselett_s=to_stringtintryUnix.mkdirt_s0o777with|Unix.Unix_error(EEXIST,_,_)->()|Unix.Unix_error(ENOENT,_,_)ase->letparent=parenttinifis_rootparentthenraiseeelsebeginmkdir_pparent;Unix.mkdirt_s0o777endletappendab=matchis_roota,is_rootbwith|true,_->b|_,true->a|_,_->make((to_stringa)^"/"^(to_stringb))letdescendantt~of_=ifis_rootof_thenSometelseift=of_thenSomerootelselett=to_stringtinletof_=to_stringof_inletof_len=String.lengthof_inlett_len=String.lengthtinif(t_len>of_len&&t.[of_len]='/'&&String.is_prefixt~prefix:of_)thenSome(make(String.dropt(of_len+1)))elseNoneletis_descendantt~of_=is_rootof_||t=of_||(lett=to_stringtinletof_=to_stringof_inletof_len=String.lengthof_inlett_len=String.lengthtin(t_len>of_len&&t.[of_len]='/'&&String.is_prefixt~prefix:of_))letreacht~from=letreclooptfrom=matcht,fromwith|a::t,b::fromwhena=b->looptfrom|_->matchList.fold_leftfrom~init:t~f:(funacc_->".."::acc)with|[]->"."|l->(String.concatl~sep:"/")inloop(to_listt)(to_listfrom)letextend_basenamet~suffix=make(to_stringt^suffix)letextensiont=Filename.extension(to_stringt)letsplit_extensiont=lets,ext=Filename.split_extension(to_stringt)in(makes,ext)letset_extensiont~ext=let(base,_)=split_extensiontin(to_stringbase)^ext|>makemodulePrefix=structletmake_path=maketypet={len:int;path:string;path_slash:string}letmakep=ifis_rootpthenExn.code_error"Path.Local.Prefix.make"["path",to_sexpp];letp=to_stringpin{len=String.lengthp;path=p;path_slash=p^"/"}letdroptp=letp=to_stringpinletlen=String.lengthpiniflen=t.len&&p=t.paththenSomerootelseString.drop_prefixp~prefix:t.path_slash|>Option.map~f:make_pathletinvalid={len=-1;path="/";path_slash="/"}endendlet(abs_root,set_root)=letroot_dir=refNoneinletset_rootnew_root=match!root_dirwith|None->root_dir:=Somenew_root|Someroot_dir->Exn.code_error"set_root: cannot set root_dir more than once"["root_dir",External.to_sexproot_dir;"new_root_dir",External.to_sexpnew_root]inletabs_root=lazy(match!root_dirwith|None->Exn.code_error"root_dir: cannot use root dir before it's set"[]|Someroot_dir->root_dir)in(abs_root,set_root)moduleKind=structtypet=|ExternalofExternal.t|LocalofLocal.tletto_absolute_filenamet=matchtwith|Externals->External.to_strings|Locall->External.to_string(External.relative(Lazy.forceabs_root)(Local.to_stringl))letto_string=function|Localt->Local.to_stringt|Externalt->External.to_stringtletto_sexpt=Sexp.Encoder.string(to_stringt)letof_strings=ifFilename.is_relativesthenLocal(Local.of_strings)elseExternal(External.of_strings)let_=letroot=LocalLocal.rootinassert(of_string""=root);assert(of_string"."=root)let_relative?error_loctfn=matchtwith|Localt->Local(Local.relative?error_loctfn)|Externalt->External(External.relativetfn)letmkdir_p=function|Localt->Local.mkdir_pt|Externalt->External.mkdir_ptletappend_localxy=matchxwith|Localx->Local(Local.appendxy)|Externalx->External(External.relativex(Local.to_stringy))endlet(build_dir_kind,build_dir_prefix,set_build_dir)=letbuild_dir=refNoneinletbuild_dir_prefix=refNoneinletset_build_dir(new_build_dir:Kind.t)=match!build_dirwith|None->(matchnew_build_dirwith|External_->()|Localp->ifLocal.is_rootp||Local.parentp<>Local.rootthenExn.fatalf"@{<error>Error@}: Invalid build directory: %s\n\
The build directory must be an absolute path or \
a sub-directory of the root of the workspace."(Local.to_stringp|>String.maybe_quoted));build_dir:=Somenew_build_dir;build_dir_prefix:=Some(matchnew_build_dirwith|Localp->Local.Prefix.makep|External_->Local.Prefix.invalid)|Somebuild_dir->Exn.code_error"set_build_dir: cannot set build_dir more than once"["build_dir",Kind.to_sexpbuild_dir;"new_build_dir",Kind.to_sexpnew_build_dir]inletbuild_dir=lazy(match!build_dirwith|None->Exn.code_error"build_dir: cannot use build dir before it's set"[]|Somebuild_dir->build_dir)inletbuild_dir_prefix=lazy(match!build_dir_prefixwith|None->Exn.code_error"build_dir: cannot use build dir before it's set"[]|Someprefix->prefix)in(build_dir,build_dir_prefix,set_build_dir)moduleT:sigtypet=private|ExternalofExternal.t|In_source_treeofLocal.t|In_build_dirofLocal.tvalcompare:t->t->Ordering.tvalequal:t->t->boolvalhash:t->intvalin_build_dir:Local.t->tvalin_source_tree:Local.t->tvalexternal_:External.t->tend=structtypet=|ExternalofExternal.t|In_source_treeofLocal.t|In_build_dirofLocal.tletcomparexy=matchx,ywith|Externalx,Externaly->External.comparexy|External_,_->Lt|_,External_->Gt|In_source_treex,In_source_treey->Local.comparexy|In_source_tree_,_->Lt|_,In_source_tree_->Gt|In_build_dirx,In_build_diry->Local.comparexyletequal(x:t)(y:t)=x=ylethash=Hashtbl.hashletin_build_dirs=In_build_dirsletin_source_trees=In_source_treesletexternal_e=ExternaleendincludeTlethash(t:t)=Hashtbl.hashtletbuild_dir=in_build_dirLocal.rootletis_root=function|In_source_trees->Local.is_roots|In_build_dir_|External_->falsemoduleMap=Map.Make(T)letkind=function|In_build_dirp->Kind.append_local(Lazy.forcebuild_dir_kind)p|In_source_trees->Kind.Locals|Externals->Kind.Externalsletis_managed=function|In_build_dir_|In_source_tree_->true|External_->falseletto_stringt=matchtwith|In_source_treep->Local.to_stringp|Externalp->External.to_stringp|In_build_dirp->matchLazy.forcebuild_dir_kindwith|Localb->Local.to_string(Local.appendbp)|Externalb->ifLocal.is_rootpthenExternal.to_stringbelseFilename.concat(External.to_stringb)(Local.to_stringp)letto_string_maybe_quotedt=String.maybe_quoted(to_stringt)letroot=in_source_treeLocal.rootletmake_local_pathp=matchLocal.Prefix.drop(Lazy.forcebuild_dir_prefix)pwith|None->in_source_treep|Somep->in_build_dirpletof_local=make_local_pathletrelative?error_loctfn=matchfnwith|""|"."->t|_whennot(Filename.is_relativefn)->external_(External.of_stringfn)|_->matchtwith|In_source_treep->make_local_path(Local.relativepfn?error_loc)|In_build_dirp->in_build_dir(Local.relativepfn?error_loc)|Externals->external_(External.relativesfn)letof_string?error_locs=matchswith|""|"."->in_source_treeLocal.root|s->ifFilename.is_relativesthenmake_local_path(Local.of_strings?error_loc)elseexternal_(External.of_strings)letto_sexpt=letconstrfxy=Sexp.Encoder.(pairstringf)(x,y)inmatchtwith|In_build_dirs->constrLocal.to_sexp"In_build_dir"s|In_source_trees->constrLocal.to_sexp"In_source_tree"s|Externals->constrExternal.to_sexp"External"sletto_dynt=letopenDyninmatchtwith|In_build_dirs->Variant("In_build_dir",[Local.to_dyns])|In_source_trees->Variant("In_source_tree",[Local.to_dyns])|Externals->Variant("External",[External.to_dyns])letof_filename_relative_to_initial_cwdfn=external_(ifFilename.is_relativefnthenExternal.relativeExternal.initial_cwdfnelseExternal.of_stringfn)letto_absolute_filenamet=Kind.to_absolute_filename(kindt)letexternal_of_localx~root=External.to_string(External.relativeroot(Local.to_stringx))letexternal_of_in_source_treex=external_of_localx~root:(Lazy.forceabs_root)letreacht~from=matcht,fromwith|Externalt,_->External.to_stringt|In_source_treet,In_source_treefrom|In_build_dirt,In_build_dirfrom->Local.reacht~from|In_source_treet,In_build_dirfrom->beginmatchLazy.forcebuild_dir_kindwith|Localb->Local.reacht~from:(Local.appendbfrom)|External_->external_of_in_source_treetend|In_build_dirt,In_source_treefrom->beginmatchLazy.forcebuild_dir_kindwith|Localb->Local.reach(Local.appendbt)~from|Externalb->external_of_localt~root:bend|In_source_treet,External_->external_of_in_source_treet|In_build_dirt,External_->matchLazy.forcebuild_dir_kindwith|Localb->external_of_in_source_tree(Local.appendbt)|Externalb->external_of_localt~root:bletreach_for_running?(from=root)t=letfn=reacht~frominmatchFilename.analyze_program_namefnwith|In_path->"./"^fn|_->fnletdescendantt~of_=matcht,of_with|In_source_treet,In_source_treeof_|In_build_dirt,In_build_dirof_->Option.map~f:in_source_tree(Local.descendantt~of_)|_->Noneletis_descendantt~of_=matcht,of_with|In_source_treet,In_source_treeof_|In_build_dirt,In_build_dirof_->Local.is_descendantt~of_|_->falseletappend_localab=matchawith|In_source_treea->in_source_tree(Local.appendab)|In_build_dira->in_build_dir(Local.appendab)|Externala->external_(External.relativea(Local.to_stringb))letappendab=matchbwith|In_build_dir_|External_->Exn.code_error"Path.append called with directory that's \
not in the source tree"["a",to_sexpa;"b",to_sexpb]|In_source_treeb->append_localabletbasenamet=matchkindtwith|Localt->Local.basenamet|Externalt->External.basenametletparent=function|Externals->letparent=External.parentsinifparent=sthenNoneelseSome(external_parent)|In_source_treep|In_build_dirpwhenLocal.is_rootp->None|In_source_treel->Some(in_source_tree(Local.parentl))|In_build_dirl->Some(in_build_dir(Local.parentl))letparent_exnt=matchparenttwith|Somep->p|None->Exn.code_error"Path.parent:exn t is root"["t",to_sexpt]letis_strict_descendant_of_build_dir=function|In_build_dirp->not(Local.is_rootp)|In_source_tree_|External_->falseletis_in_build_dir=function|In_build_dir_->true|In_source_tree_|External_->falseletis_in_source_tree=function|In_source_tree_->true|In_build_dir_|External_->falseletis_alias_stamp_file=function|In_build_dirs->String.is_prefix(Local.to_strings)~prefix:".aliases/"|In_source_tree_|External_->falseletextract_build_context=function|In_source_tree_|External_->None|In_build_dirpwhenLocal.is_rootp->None|In_build_dirt->lett=Local.to_stringtinbeginmatchString.lsplit2t~on:'/'with|None->Some(t,in_source_treeLocal.root)|Some(before,after)->Some(before,after|>Local.of_string|>in_source_tree)endletextract_build_context_exnt=matchextract_build_contexttwith|Somet->t|None->Exn.code_error"Path.extract_build_context_exn"["t",to_sexpt]letextract_build_context_dir=function|In_source_tree_|External_->None|In_build_dirt->lett_str=Local.to_stringtinbeginmatchString.lsplit2t_str~on:'/'with|None->Some(in_build_dirt,in_source_treeLocal.root)|Some(before,after)->Some(in_build_dir(Local.of_stringbefore),after|>Local.of_string|>in_source_tree)endletextract_build_context_dir_exnt=matchextract_build_context_dirtwith|Somet->t|None->Exn.code_error"Path.extract_build_context_dir_exn"["t",to_sexpt]letdrop_build_contextt=Option.map(extract_build_contextt)~f:sndletdrop_build_context_exnt=matchextract_build_contexttwith|None->Exn.code_error"Path.drop_build_context_exn"["t",to_sexpt]|Some(_,t)->tletdrop_optional_build_contextt=matchextract_build_contexttwith|None->t|Some(_,t)->tletlocal_src=Local.of_string"src"letlocal_build=Local.of_string"build"letsandbox_managed_paths~sandbox_dirt=matchtwith|External_->t|In_source_treep->append_localsandbox_dir(Local.appendlocal_srcp)|In_build_dirp->append_localsandbox_dir(Local.appendlocal_buildp)letsplit_first_componentt=matchkindt,is_roottwith|Localt,false->lett=Local.to_stringtinbeginmatchString.lsplit2t~on:'/'with|None->Some(t,root)|Some(before,after)->Some(before,after|>Local.of_string|>in_source_tree)end|_,_->Noneletexplodet=matchkindtwith|LocalpwhenLocal.is_rootp->Some[]|Locals->Some(String.split(Local.to_strings)~on:'/')|External_->Noneletexplode_exnt=matchexplodetwith|Somes->s|None->Exn.code_error"Path.explode_exn"["path",to_sexpt]letexistst=trySys.file_exists(to_stringt)withSys_error_->falseletreaddir_unsortedt=Sys.readdir(to_stringt)|>Array.to_listletis_directoryt=trySys.is_directory(to_stringt)withSys_error_->falseletis_filet=not(is_directoryt)letrmdirt=Unix.rmdir(to_stringt)letwin32_unlinkfn=tryUnix.unlinkfnwithUnix.Unix_error(Unix.EACCES,_,_)ase->(* Try removing the read-only attribute *)tryUnix.chmodfn0o666;Unix.unlinkfnwith_->raiseeletunlink_operation=ifSys.win32thenwin32_unlinkelseUnix.unlinkletunlinkt=unlink_operation(to_stringt)letunlink_no_errt=tryunlinktwith_->()letbuild_dir_exists()=is_directorybuild_dirletensure_build_dir_exists()=matchkindbuild_dirwith|Localp->Local.mkdir_pp|Externalp->letp=External.to_stringpintryUnix.mkdirp0o777with|Unix.Unix_error(EEXIST,_,_)->()|Unix.Unix_error(ENOENT,_,_)->Exn.fatalf"Cannot create external build directory %s. \
Make sure that the parent dir %s exists."p(Filename.dirnamep)letextend_basenamet~suffix=matchtwith|In_source_treet->in_source_tree(Local.extend_basenamet~suffix)|In_build_dirt->in_build_dir(Local.extend_basenamet~suffix)|Externalt->external_(External.extend_basenamet~suffix)letinsert_after_build_dir_exn=leterrorab=Exn.code_error"Path.insert_after_build_dir_exn"["path",to_sexpa;"insert",Sexp.Encoder.stringb]infunab->matchawith|In_build_dira->in_build_dir(Local.append(Local.of_stringb)a)|In_source_tree_|External_->errorabletrm_rf=letrecloopdir=Array.iter(Sys.readdirdir)~f:(funfn->letfn=Filename.concatdirfninmatchUnix.lstatfnwith|{st_kind=S_DIR;_}->loopfn|_->unlink_operationfn);Unix.rmdirdirinfunt->ifnot(is_managedt)then(Exn.code_error"Path.rm_rf called on external dir"["t",to_sexpt]);letfn=to_stringtinmatchUnix.lstatfnwith|exceptionUnix.Unix_error(ENOENT,_,_)->()|_->loopfnletmkdir_p=function|Externals->External.mkdir_ps|In_source_trees->Local.mkdir_ps|In_build_dirk->Kind.mkdir_p(Kind.append_local(Lazy.forcebuild_dir_kind)k)letcomparexy=matchx,ywith|Externalx,Externaly->External.compare_valxy|External_,_->Lt|_,External_->Gt|In_source_treex,In_source_treey->Local.compare_valxy|In_source_tree_,_->Lt|_,In_source_tree_->Gt|In_build_dirx,In_build_diry->Local.compare_valxyletextensiont=matchtwith|Externalt->External.extensiont|In_build_dirt|In_source_treet->Local.extensiontletsplit_extensiont=matchtwith|Externalt->lett,ext=External.split_extensiontin(external_t,ext)|In_build_dirt->lett,ext=Local.split_extensiontin(in_build_dirt,ext)|In_source_treet->lett,ext=Local.split_extensiontin(in_source_treet,ext)letset_extensiont~ext=matchtwith|Externalt->external_(External.set_extensiont~ext)|In_build_dirt->in_build_dir(Local.set_extensiont~ext)|In_source_treet->in_source_tree(Local.set_extensiont~ext)letppppft=Format.pp_print_stringppf(to_string_maybe_quotedt)letpp_in_sourceppft=ppppf(drop_optional_build_contextt)letpp_debugppf=function|In_source_trees->Format.fprintfppf"(In_source_tree %S)"(Local.to_strings)|In_build_dirs->Format.fprintfppf"(In_build_dir %S)"(Local.to_strings)|Externals->Format.fprintfppf"(External %S)"(External.to_strings)moduleSet=structincludeSet.Make(T)letto_sexpt=Sexp.Encoder.(listto_sexp)(to_listt)letof_string_setss~f=String.Set.to_listss|>List.map~f|>of_listendletin_sources=in_source_tree(Local.of_strings)letis_suffixp~suffix=matchpwith|In_build_dirl|In_source_treel->Local.is_suffixl~suffix|Externalp->External.is_suffixp~suffixmoduleTable=Hashtbl.Make(T)moduleInternal=structletraw_kind=function|In_build_dirl->Kind.Locall|In_source_treel->Locall|Externall->ExternallendmoduleL=struct(* TODO more efficient implementation *)letrelativet=List.fold_left~init:t~f:relativeendletlocal_part=function|Externale->Local.of_string(External.as_locale)|In_source_treel->l|In_build_dirl->lletstatt=Unix.stat(to_stringt)