1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255letis_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:sigincludePath_intf.Svalrelative:t->string->tvalmkdir_p:t->unitvalinitial_cwd:tvalcwd:unit->tvalas_local:t->stringend=structmoduleT=Interned.No_interning(structletinitial_size=512letresize_policy=Interned.Greedyletorder=Interned.Naturalend)()moduleTable=Hashtbl.Make(T)typet=T.tletto_string=T.to_stringletmake=T.makeletequal=T.equallethash=T.hashletpp=T.ppletcompare=T.compareletas_stringx~f=to_stringx|>f|>makeletextend_basenamet~suffix=as_stringt~f:(funt->t^suffix)letof_stringt=ifFilename.is_relativetthenCode_error.raise"Path.External.of_string: relative path given"["t",Stringt];maketletparse_string_exn~loct=ifFilename.is_relativetthenUser_error.raise~loc[Pp.textf"path %s is not absolute"t];maketletto_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)letroot=of_string"/"letis_root=equalrootletparentt=ifis_roottthenNoneelseSome(as_stringt~f:Filename.dirname)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|>makeletcwd()=make(Sys.getcwd())letinitial_cwd=cwd()letas_localt=lets=to_stringtin"."^sinclude(Comparator.Operators(structtypenonrect=tletcompare=compareend):Comparator.OPSwithtypet:=t)letto_string_maybe_quotedt=String.maybe_quoted(to_stringt)letparent_exnt=matchparenttwith|None->Code_error.raise"Path.External.parent_exn called on a root path"[]|Somep->pletis_descendantb~of_:a=ifis_rootathentrueelseString.is_prefix~prefix:(to_stringa^"/")(to_stringb)moduleSet=structincludeT.Setletof_listing~dir~filenames=of_list(List.mapfilenames~f:(funf->relativedirf))endmoduleMap=T.MapendmoduleUnspecified=Path_intf.UnspecifiedmoduleLocal_gen:sigincludePath_intf.Local_genmodulePrefix:sigtype'wlocal='wttype'wtvalmake:'wlocal->'wtvaldrop:'wt->'wlocal->'wlocaloption(* for all local path p, drop (invalid p = None) *)valinvalid:'wtendwithtype'wlocal:='wtend=struct(* either "." for root, or a '/' separated list of components
other that ".", ".." and not containing '/'. *)moduleT=Interned.No_interning(structletinitial_size=512letresize_policy=Interned.Greedyletorder=Interned.Naturalend)()moduleTable=Hashtbl.Make(T)type_t=T.tletto_string=T.to_stringletmake=T.makelethash=T.hashletcompare=T.compareletppppfs=Format.pp_print_stringppf(to_strings)letroot=make"."letis_roott=Ordering.is_eq(comparetroot)letto_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_roottthenNoneelselett=to_stringtinmatchString.rindex_fromt(String.lengtht-1)'/'with|None->Someroot|Somei->Some(make(String.taketi))letbasenamet=ifis_roottthenCode_error.raise"Path.Local.basename called on the root"[]elselett=to_stringtinletlen=String.lengthtinmatchString.rindex_fromt(len-1)'/'with|None->t|Somei->String.subt~pos:(i+1)~len:(len-i-1)letto_dynt=Dyn.String(to_stringt)moduleL=structletrelative_resulttcomponents=letreclooptcomponents=matchcomponentswith|[]->Result.Okt|"."::rest->looptrest|".."::rest->ifis_roottthenResult.Error()elsebeginmatchparenttwith|None->Error()|Someparent->loopparentrestend|fn::rest->ifis_roottthenloop(makefn)restelseloop(make(to_stringt^"/"^fn))restinlooptcomponentsletrelative?error_loctcomponents=matchrelative_resulttcomponentswith|Result.Okt->t|Error()->User_error.raise?loc:error_loc[Pp.textf"path outside the workspace: %s from %s"(String.concat~sep:"/"components)(to_stringt)]endletrelative?error_loctpath=ifnot(Filename.is_relativepath)then(Code_error.raise"Local.relative: received absolute path"["t",to_dynt;"path",Stringpath]);matchL.relative_resultt(explode_pathpath)with|Result.Okt->t|Error()->User_error.raise?loc:error_loc[Pp.textf"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)letparse_string_exn~locs=matchswith|""|"."->root|_whenis_canonicalizeds->makes|_->relativeroots~error_loc:locletof_strings=parse_string_exn~loc:Loc0.nonesletappendab=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=maketype_t={len:int;path:string;path_slash:string}letmakep=ifis_rootpthenCode_error.raise"Path.Local.Prefix.make"["path",to_dynp];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="/"}endletsplit_first_componentt=ifis_roottthenNoneelselett=(to_stringt)inbeginmatchString.lsplit2t~on:'/'with|None->Some(t,root)|Some(before,after)->Some(before,after|>of_string)endletexplodep=ifis_rootpthen[]elseString.split(to_stringp)~on:'/'letto_string_maybe_quotedt=String.maybe_quoted(to_stringt)letparent_exnt=matchparenttwith|None->Code_error.raise"Path.Local.parent:exn t is root"["t",to_dynt]|Someparent->parentmoduleFix_root(Root:sigtypewend)=structtype_w=Root.wmoduleSet=structincludeT.Setletof_listing~dir~filenames=of_list(List.mapfilenames~f:(funf->relativedirf))endmoduleMap=T.MapmoduleTable=TableendendmoduleLocal:sigtypew=Unspecified.wtypet=wLocal_gen.tincludePath_intf.Swithtypet:=tvalroot:tvalis_root:t->boolvalrelative:?error_loc:Loc0.t->t->string->tvalappend:t->t->tvaldescendant:t->of_:t->toptionvalis_descendant:t->of_:t->boolvalreach:t->from:t->stringmoduleL:sigvalrelative:?error_loc:Loc0.t->t->stringlist->tendvalsplit_first_component:t->(string*t)optionvalexplode:t->stringlistvalof_local:t->tmodulePrefix:sigtypelocal=ttypetvalmake:local->tvaldrop:t->local->localoption(* for all local path p, drop (invalid p = None) *)valinvalid:tendwithtypelocal:=tend=structtypew=Unspecified.winclude(Local_gen:moduletypeofLocal_genwithtype'at:='aLocal_gen.twithmodulePrefix:=Local_gen.Prefix)typenonrect=wLocal_gen.tmodulePrefix=structopenLocal_geninclude(Prefix:moduletypeofPrefixwithtype'at:='aPrefix.t)typet=wPrefix.tendinclude(Comparator.Operators(structtypenonrect=tletcompare=Local_gen.compareend):Comparator.OPSwithtypet:=t)letof_localt=tincludeFix_root(structtypenonrecw=wend)endmoduleRelative_to_source_root:sigvalmkdir_p:Local.t->unitend=structopenLocalletrecmkdir_pt=ifis_roottthen()elselett_s=to_stringtintryUnix.mkdirt_s0o777with|Unix.Unix_error(EEXIST,_,_)->()|Unix.Unix_error(ENOENT,_,_)ase->letparent=parent_exntinifis_rootparentthenraiseeelsebeginmkdir_pparent;Unix.mkdirt_s0o777endendmoduleSource0=Locallet(abs_root,set_root)=letroot_dir=refNoneinletset_rootnew_root=match!root_dirwith|None->root_dir:=Somenew_root|Someroot_dir->Code_error.raise"set_root: cannot set root_dir more than once"["root_dir",External.to_dynroot_dir;"new_root_dir",External.to_dynnew_root]inletabs_root=lazy(match!root_dirwith|None->Code_error.raise"root_dir: cannot use root dir before it's set"[]|Someroot_dir->root_dir)in(abs_root,set_root)moduleKind=structtypet=|ExternalofExternal.t|In_source_dirofLocal.tletto_absolute_filenamet=matchtwith|Externals->External.to_strings|In_source_dirl->External.to_string(External.relative(Lazy.forceabs_root)(Local.to_stringl))letto_string=function|In_source_dirt->Local.to_stringt|Externalt->External.to_stringtletto_dynt=Dyn.String(to_stringt)letof_strings=ifFilename.is_relativesthenIn_source_dir(Local.of_strings)elseExternal(External.of_strings)letmkdir_p=function|In_source_dirt->Relative_to_source_root.mkdir_pt|Externalt->External.mkdir_ptletappend_localxy=matchxwith|In_source_dirx->In_source_dir(Local.appendxy)|Externalx->External(External.relativex(Local.to_stringy))endmoduleBuild=structincludeLocalletappend_source=appendletappend_local=appendletlocalt=tletextract_build_contextt=lett=Local.to_stringtinbeginmatchString.lsplit2t~on:'/'with|None->Some(t,Source0.root)|Some(before,after)->Some(before,after|>Source0.of_string)endletextract_first_component=extract_build_contextletextract_build_context_dirt=lett_str=Local.to_stringtinbeginmatchString.lsplit2t_str~on:'/'with|None->Some(t,Source0.root)|Some(before,after)->Some(Local.of_stringbefore,after|>Source0.of_string)endletextract_build_context_dir_exnt=matchextract_build_context_dirtwith|Somet->t|None->Code_error.raise"Path.Build.extract_build_context_dir_exn"["t",to_dynt]letextract_build_context_exnt=matchextract_build_contexttwith|Somet->t|None->Code_error.raise"Path.Build.extract_build_context_exn"["t",to_dynt]letdrop_build_contextt=Option.map(extract_build_contextt)~f:sndletdrop_build_context_exnt=matchdrop_build_contexttwith|Somed->d|None->Code_error.raise"Path.Build.drop_build_context_exn"["t",to_dynt](* CR-someday rgrinberg:
I think we should just move this function to the alias module. *)letis_alias_stamp_files=String.is_prefix(Local.to_strings)~prefix:".aliases/"let(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_->()|In_source_dirp->ifLocal.is_rootp||Local.parent_exnp<>Local.rootthenUser_error.raise[Pp.textf"Invalid build directory: %s"(Local.to_stringp|>String.maybe_quoted);Pp.text"The build directory must be an absolute path \
or a sub-directory of the root of the \
workspace."]);build_dir:=Somenew_build_dir;build_dir_prefix:=Some(matchnew_build_dirwith|In_source_dirp->Local.Prefix.makep|External_->Local.Prefix.invalid)|Somebuild_dir->Code_error.raise"set_build_dir: cannot set build_dir more than once"["build_dir",Kind.to_dynbuild_dir;"new_build_dir",Kind.to_dynnew_build_dir]inletbuild_dir=lazy(match!build_dirwith|None->Code_error.raise"build_dir: cannot use build dir before it's set"[]|Somebuild_dir->build_dir)inletbuild_dir_prefix=lazy(match!build_dir_prefixwith|None->Code_error.raise"build_dir: cannot use build dir before it's set"[]|Someprefix->prefix)in(build_dir,build_dir_prefix,set_build_dir)letto_stringp=matchLazy.forcebuild_dir_kindwith|In_source_dirb->Local.to_string(Local.appendbp)|Externalb->ifLocal.is_rootpthenExternal.to_stringbelseFilename.concat(External.to_stringb)(Local.to_stringp)moduleKind=KindendmoduleT:sigtypet=private|ExternalofExternal.t|In_source_treeofLocal.t|In_build_dirofLocal.tvalto_dyn:t->Dyn.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=Externaleletto_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])endincludeTlethash(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.build_dir_kind)p|In_source_trees->Kind.In_source_dirs|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->Build.to_stringpletto_string_maybe_quotedt=String.maybe_quoted(to_stringt)letroot=in_source_treeLocal.rootletmake_local_pathp=matchLocal.Prefix.drop(Lazy.forceBuild.build_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)letparse_string_exn~locs=matchswith|""|"."->in_source_treeLocal.root|s->ifFilename.is_relativesthenmake_local_path(Local.parse_string_exn~locs)elseexternal_(External.parse_string_exn~locs)letof_strings=parse_string_exn~loc:Loc0.nonesletto_dyn=letopenDyn.Encoderinfunction|In_build_dirs->constr"In_build_dir"[Local.to_dyns]|In_source_trees->constr"In_source_tree"[Local.to_dyns]|Externals->constr"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.build_dir_kindwith|In_source_dirb->Local.reacht~from:(Local.appendbfrom)|External_->external_of_in_source_treetend|In_build_dirt,In_source_treefrom->beginmatchLazy.forceBuild.build_dir_kindwith|In_source_dirb->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.build_dir_kindwith|In_source_dirb->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))letappend_local=append_localletappend_source=append_localletappendab=matchbwith|In_build_dir_|External_->Code_error.raise"Path.append called with directory that's \
not in the source tree"["a",to_dyna;"b",to_dynb]|In_source_treeb->append_localabletbasenamet=matchkindtwith|In_source_dirt->Local.basenamet|Externalt->External.basenametletparent=function|Externals->Option.map(External.parents)~f:external_|In_source_treel->Local.parentl|>Option.map~f:in_source_tree|In_build_dirl->Local.parentl|>Option.map~f:in_build_dirletparent_exnt=matchparenttwith|Somep->p|None->Code_error.raise"Path.parent:exn t is root"["t",to_dynt]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_->falseletas_in_source_tree=function|In_source_trees->Somes|In_build_dir_|External_->Noneletas_in_build_dir=function|In_build_dirb->Someb|In_source_tree_|External_->Noneletas_in_build_dir_exnt=matchtwith|External_|In_source_tree_->Code_error.raise"[as_in_build_dir_exn] called on something not in build dir"["t",to_dynt]|In_build_dirp->pletextract_build_context=function|In_source_tree_|External_->None|In_build_dirpwhenLocal.is_rootp->None|In_build_dirt->Build.extract_build_contexttletextract_build_dir_first_component=extract_build_contextletextract_build_context_exnt=matchextract_build_contexttwith|Somet->t|None->Code_error.raise"Path.extract_build_context_exn"["t",to_dynt]letextract_build_context_dir=function|In_source_tree_|External_->None|In_build_dirt->Option.map(Build.extract_build_context_dirt)~f:(fun(base,rest)->in_build_dirbase,rest)letextract_build_context_dir_exnt=matchextract_build_context_dirtwith|Somet->t|None->Code_error.raise"Path.extract_build_context_dir_exn"["t",to_dynt]letdrop_build_contextt=Option.map(extract_build_contextt)~f:sndletdrop_build_context_exnt=matchextract_build_contexttwith|None->Code_error.raise"Path.drop_build_context_exn"["t",to_dynt]|Some(_,t)->tletdrop_optional_build_contextt=matchextract_build_contexttwith|None->t|Some(_,t)->in_source_treetletdrop_optional_build_context_src_exnt=matchtwith|External_->Code_error.raise"drop_optional_build_context_src_exn called on an external path"[]|In_build_dir_->(matchextract_build_contexttwith|Some(_,s)->s|None->Code_error.raise"drop_optional_build_context_src_exn called on a build directory itself"[])|In_source_treep->pletsplit_first_componentt=matchkindt,is_roottwith|In_source_dirt,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|In_source_dirpwhenLocal.is_rootp->Some[]|In_source_dirs->Some(String.split(Local.to_strings)~on:'/')|External_->Noneletexplode_exnt=matchexplodetwith|Somes->s|None->Code_error.raise"Path.explode_exn"["path",to_dynt]letexistst=trySys.file_exists(to_stringt)withSys_error_->falseletreaddir_unsorted=letrecloopdhacc=matchUnix.readdirdhwith|"."|".."->loopdhacc|s->loopdh(s::acc)|exceptionEnd_of_file->accinfunt->tryletdh=Unix.opendir(to_stringt)inExn.protect~f:(fun()->matchloopdh[]with|exception(Unix.Unix_error(e,_,_))->Errore|s->Result.Oks)~finally:(fun()->Unix.closedirdh)withUnix.Unix_error(e,_,_)->Erroreletis_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|In_source_dirp->Relative_to_source_root.mkdir_pp|Externalp->letp=External.to_stringpintryUnix.mkdirp0o777with|Unix.Unix_error(EEXIST,_,_)->()|Unix.Unix_error(ENOENT,_,_)->User_error.raise[Pp.textf"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=Code_error.raise"Path.insert_after_build_dir_exn"["path",to_dyna;"insert",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(Code_error.raise"Path.rm_rf called on external dir"["t",to_dynt]);letfn=to_stringtinmatchUnix.lstatfnwith|exceptionUnix.Unix_error(ENOENT,_,_)->()|_->loopfnletmkdir_p=function|Externals->External.mkdir_ps|In_source_trees->Relative_to_source_root.mkdir_ps|In_build_dirk->Kind.mkdir_p(Kind.append_local(Lazy.forceBuild.build_dir_kind)k)letcomparexy=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.comparexyletextensiont=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_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)moduleO=Comparable.Make(T)moduleSet=structincludeO.Setletof_listing~dir~filenames=of_list(List.mapfilenames~f:(funf->relativedirf))endletin_sources=in_source_tree(Local.of_strings)letsources=in_source_treesletbuilds=in_build_dirsmoduleTable=Hashtbl.Make(T)moduleL=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)include(Comparator.Operators(T):Comparator.OPSwithtypet:=t)letpath_of_local=of_localmoduleSource=structincludeSource0letis_in_build_dirs=is_in_build_dir(path_of_locals)letto_localt=tendletset_of_source_pathsset=Source.Set.to_listset|>List.map~f:source|>Set.of_listletset_of_build_paths_list=List.fold_left~init:Set.empty~f:(funacce->Set.addacc(builde))