123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199(*
* Copyright (c) 2013-2020 Thomas Gazagnaire <thomas@gazagnaire.org>
* Copyright (c) 2013-2020 Anil Madhavapeddy <anil@recoil.org>
* Copyright (c) 2015-2020 Gabriel Radanne <drupyog@zoho.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.
*)openAction.SyntaxopenAstringtypepackage=Package.ttypeinfo=Info.ttype'avalue='aKey.valuetype'acode={pos:(string*int*int*int)option;code:string}letcode_opt?posfmt=Fmt.kstr(funcode->{pos;code})fmtletcode~posfmt=Fmt.kstr(funcode->{pos=Somepos;code})fmttype('a,'impl)t={id:'aTypeid.t;module_name:string;module_type:'aType.t;keys:Key.tlist;runtime_args:Runtime_arg.tlist;packages:packagelistvalue;install:info->Install.tvalue;connect:info->string->stringlist->'acode;dune:info->Dune.stanzalist;configure:info->unitAction.t;files:(info->Fpath.tlist)option;extra_deps:'impllist;}letpp:typeab.bFmt.t->(a,b)tFmt.t=funpp_implppft->letopenFmt.Dumpinletfields=[field"id"(funt->t.id)Typeid.pp;field"module_name"(funt->t.module_name)string;field"module_type"(funt->t.module_type)Type.pp;field"keys"(funt->t.keys)(listKey.pp);field"install"(fun_->"<dyn>")Fmt.string;field"packages"(fun_->"<dyn>")Fmt.string;field"extra_deps"(funt->t.extra_deps)(listpp_impl);]inrecordfieldsppftletequalxy=Typeid.equalx.idy.idletwitnessxy=Typeid.witnessx.idy.idlethashx=Typeid.idx.idletdefault_connect__l=code_opt"return (%s)"(String.concat~sep:", "l)letniet_=Action.ok()letnil_=[]letmergeemptyunionab=match(a,b)with|None,None->Key.pureempty|Somea,None->Key.purea|None,Someb->b|Somea,Someb->Key.(pureunion$purea$b)letmerge_packages=merge[]List.appendletmerge_install=mergeInstall.emptyInstall.unionletv?packages?packages_v?install?install_v?(keys=[])?(runtime_args=[])?(extra_deps=[])?(connect=default_connect)?(dune=nil)?(configure=niet)?filesmodule_namemodule_type=letid=Typeid.gen()inletpackages=merge_packagespackagespackages_vinletinstalli=letaux=functionNone->None|Somef->Some(fi)inmerge_install(auxinstall)(auxinstall_v)in{module_type;id;module_name;keys;runtime_args;connect;packages;install;dune;configure;files;extra_deps;}letidt=Typeid.idt.idletmodule_namet=t.module_nameletmodule_typet=t.module_typeletpackagest=t.packagesletinstallt=t.installletconnectt=t.connectletconfiguret=t.configureletfilesti=letgen=Action.generated_files(t.configurei)inmatcht.fileswith|None->gen|Somefiles->Fpath.Set.(uniongen(of_list(filesi)))letdunet=t.duneletkeyst=t.keysletruntime_argst=t.runtime_argsletextra_depst=t.extra_depsletstart?posimpl_nameargs=code_opt?pos"@[(%s.start@ %a@ : unit io)@]"impl_nameFmt.(list~sep:spstring)argsletuniqt=Fpath.Set.(elements(of_listt))letexec_hooki=functionNone->Action.ok()|Someh->hiletextend?packages?packages_v?dune?pre_configure?post_configure?filest=letfiles=match(files,t.files)with|None,None->None|Somef,None|None,Somef->Somef|Somex,Somey->Some(funi->uniq(xi@yi))inletpackages=Key.(pureList.append$merge_packagespackagespackages_v$t.packages)inletexecprefposti=let*()=exec_hookipreinlet*()=fiinexec_hookipostinletconfigure=execpre_configuret.configurepost_configureinletdune=Option.map(fundunei->t.dunei@dunei)dune|>Option.value~default:t.dunein{twithpackages;files;configure;dune}letnice_named=module_named|>String.cuts~sep:"."|>String.concat~sep:"_"|>String.Ascii.lowercase|>Misc.Name.ocamlifytype('a,'i)device=('a,'i)tmoduleGraph=structtypet=|D:{dev:('a,_)device;args:tlist;deps:tlist;id:int}->ttypedtree=tmoduleIdTbl=Hashtbl.Make(structtypet=dtreelethash(Dt)=t.idletequal(Dt1)(Dt2)=Int.equalt1.idt2.idend)(* We iter in *reversed* topological order. *)letfoldftz=lettbl=IdTbl.create50inletstate=refzinletrecauxv=ifIdTbl.memtblvthen()elselet(D{args;deps;_})=vinIdTbl.addtblv();List.iterauxdeps;List.iterauxargs;state:=fv!stateinauxt;!stateletimpl_name(D{dev;args=_;deps=_;id})=matchType.is_functor(module_typedev)with|false->module_namedev|true->letprefix=Astring.String.Ascii.capitalize(nice_namedev)inFmt.str"%s__%d"prefixidletvar_name(D{dev;args=_;deps=_;id})=letprefix=nice_namedevinFmt.str"%s__%i"prefixidend