123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347(**************************************************************************)(* *)(* Copyright 2014-2019 OCamlPro *)(* Copyright 2012 INRIA *)(* *)(* All rights reserved. This file is distributed under the terms of the *)(* GNU Lesser General Public License version 2.1, with the special *)(* exception on linking described in the file LICENSE. *)(* *)(**************************************************************************)openOpamTypesmoduletypeACTION=sigtypepackagemodulePkg:GenericPackagewithtypet=packageincludeOpamParallel.VERTEXwithtypet=packageactionvalto_string:[<t]->stringvalto_aligned_strings:?append:(package->string)->[<t]list->stringlistlistmoduleSet:OpamStd.SETwithtypeelt=packageactionmoduleMap:OpamStd.MAPwithtypekey=packageactionendletname_of_action=function|`Remove_->"remove"|`Install_->"install"|`Change(`Up,_,_)->"upgrade"|`Change(`Down,_,_)->"downgrade"|`Reinstall_->"recompile"|`Build_->"build"|`Fetch_->"fetch"letsymbol_of_action=letopenOpamConsoleinfunction|`Remove_->utf8_symbolSymbols.circled_division_slash~alternates:[Symbols.greek_small_letter_lambda]"X"|`Install_->utf8_symbolSymbols.asterisk_operator~alternates:[Symbols.six_pointed_black_star]"*"|`Change(`Up,_,_)->utf8_symbolSymbols.north_east_arrow~alternates:[Symbols.upwards_arrow]"U"|`Change(`Down,_,_)->utf8_symbolSymbols.south_east_arrow~alternates:[Symbols.downwards_arrow]"D"|`Reinstall_->utf8_symbolSymbols.clockwise_open_circle_arrow~alternates:[Symbols.up_down_arrow]"R"|`Build_->utf8_symbolSymbols.greek_small_letter_lambda~alternates:[Symbols.six_pointed_black_star]"B"|`Fetch_->utf8_symbolSymbols.downwards_black_arrow~alternates:[Symbols.downwards_double_arrow;Symbols.black_down_pointing_triangle]"F"letaction_strings?utf8a=ifutf8=None&&(OpamConsole.utf8())||utf8=Sometruethensymbol_of_actionaelsename_of_actionaletaction_colorc=OpamConsole.colorise(matchcwith|`Install_|`Change(`Up,_,_)->`green|`Remove_|`Change(`Down,_,_)->`red|`Reinstall_->`yellow|`Build_|`Fetch_->`cyan)moduleMakeAction(P:GenericPackage):ACTIONwithtypepackage=P.t=structmodulePkg=Ptypepackage=P.ttypet=packageactionletcomparet1t2=(* `Install > `Build > `Fetch > `Upgrade > `Reinstall > `Downgrade > `Remove *)matcht1,t2with|`Removep,`Removeq|`Installp,`Installq|`Reinstallp,`Reinstallq|`Buildp,`Buildq|`Fetchp,`Fetchq->P.comparepq|`Change(`Up,p0,p),`Change(`Up,q0,q)|`Change(`Down,p0,p),`Change(`Down,q0,q)->letc=P.comparepqinifc<>0thencelseP.comparep0q0|`Install_,_|_,`Remove_->1|_,`Install_|`Remove_,_->-1|`Build_,_|_,`Change(`Down,_,_)->1|_,`Build_|`Change(`Down,_,_),_->-1|`Fetch_,_|_,`Reinstall_->1|_,`Fetch_|`Reinstall_,_->-1lethasha=Hashtbl.hash(OpamTypesBase.map_actionP.hasha)letequalt1t2=comparet1t2=0letto_stringa=matchawith|`Removep|`Installp|`Reinstallp|`Buildp|`Fetchp->Printf.sprintf"%s %s"(action_stringsa)(P.to_stringp)|`Change(_,p0,p)->Printf.sprintf"%s.%s %s %s"(P.name_to_stringp0)(P.version_to_stringp0)(action_stringsa)(P.version_to_stringp)letto_aligned_strings?(append=(fun_->""))l=List.map(funa->leta=(a:>packageaction)in(ifOpamConsole.utf8()thenaction_colora(symbol_of_actiona)else"-")::name_of_actiona::OpamConsole.colorise`bold(P.name_to_string(OpamTypesBase.action_contentsa))::matchawith|`Removep|`Installp|`Reinstallp|`Buildp|`Fetchp->(P.version_to_stringp^appendp)::[]|`Change(_,p0,p)->Printf.sprintf"%s to %s"(P.version_to_stringp0^appendp0)(P.version_to_stringp^appendp)::[])lletto_json=function|`Removep->`O["remove",P.to_jsonp]|`Installp->`O["install",P.to_jsonp]|`Change(d,o,p)->letdir_to_json=function|`Up->`String"up"|`Down->`String"down"in`O["change",`A[dir_to_jsond;P.to_jsono;P.to_jsonp]]|`Reinstallp->`O["recompile",P.to_jsonp]|`Buildp->`O["build",P.to_jsonp]|`Fetchp->`O["fetch",P.to_jsonp]letof_json=letopenOpamStd.Option.Opinfunction|`O["remove",p]->P.of_jsonp>>=(funp->Some(`Removep))|`O["install",p]->P.of_jsonp>>=(funp->Some(`Installp))|`O["change",`A[dj;oj;pj]]->letjson_of_dir=function|`String"up"->Some`Up|`String"down"->Some`Down|_->Noneinjson_of_dirdj>>=fund->P.of_jsonoj>>=funo->P.of_jsonpj>>=funp->Some(`Change(d,o,p))|`O["recompile",p]->P.of_jsonp>>=(funp->Some(`Reinstallp))|`O["build",p]->P.of_jsonp>>=(funp->Some(`Buildp))|`O["fetch",p]->P.of_jsonp>>=(funp->Some(`Fetchp))|_->NonemoduleO=structtypet=packageactionletcompare=compareletto_string=to_stringletto_json=to_jsonletof_json=of_jsonendmoduleSet=OpamStd.Set.Make(O)moduleMap=OpamStd.Map.Make(O)endmoduletypeSIG=sigtypepackageincludeOpamParallel.GRAPHwithtypeV.t=packageOpamTypes.actionvalreduce:t->tvalexplicit:?noop_remove:(package->bool)->sources_needed:(package->bool)->t->tvalfold_descendants:(V.t->'a->'a)->'a->t->V.t->'aendmoduleMake(A:ACTION):SIGwithtypepackage=A.package=structtypepackage=A.packageincludeOpamParallel.MakeGraph(A)moduleMap=OpamStd.Map.Make(A.Pkg)moduleSet=OpamStd.Set.Make(A.Pkg)(* Turn concrete actions (only install, remove and build) to higher-level
actions (install, remove, up/downgrade, recompile). Builds are removed when
they directly precede an install, which should be the case when [explicit]
is used. *)letreduceg=letg=copyginletremovals=fold_vertex(funvacc->matchvwith|`Removep->OpamStd.String.Map.add(A.Pkg.name_to_stringp)pacc|_->acc)gOpamStd.String.Map.emptyiniter_vertex(function|`Buildpasbuild->(matchfold_succ(funv_->ifv=`InstallpthenSomevelseNone)gbuildNonewith|None->()|Someinst->iter_pred(funpred->add_edgegpredinst)gbuild;remove_vertexgbuild)|_->())g;letreduced=refMap.emptyinletg=map_vertex(function|`Installpasact->(tryletp0=OpamStd.String.Map.find(A.Pkg.name_to_stringp)removalsinletact=matchA.Pkg.comparep0pwith|0->`Reinstallp|c->`Change((ifc<0then`Upelse`Down),p0,p)inreduced:=Map.addp0act!reduced;actwithNot_found->act)|act->act)ginMap.iter(funpact->letrm_act=`Removepiniter_pred(funv->add_edgegvact)grm_act;remove_vertexgrm_act)!reduced;gletsame_namep1p2=A.Pkg.(name_to_stringp1=name_to_stringp2)letcompute_closed_predecessorsnoop_removeg=letclosed_g=copygintransitive_closureclosed_g;letclosed_packages=(* The set of package that do not have dependencies
(in the action graph). *)fold_vertex(funaacc->matchawith|`Buildp->letpred=(* We ignore predecessors that do not modify the prefix *)List.filter(function|`Removenv->not(noop_removenv)|_->true)(predclosed_ga)inifpred=[]thenSet.addpaccelseacc|_->acc)gSet.emptyinletdependent_base_packages=fold_vertex(funaacc->matchawith|`Installp|`Reinstallp|`Change(_,_,p)->letpreds=List.filter(function|`Buildqasb->Set.memqclosed_packages&¬(List.exists(function|`Remover->same_namepr|_->false)(predclosed_gb))|_->false)(predclosed_ga)inOpamStd.String.Map.add(A.Pkg.name_to_stringp)predsacc|_->acc)gOpamStd.String.Map.emptyinfunctionp->matchOpamStd.String.Map.find_opt(A.Pkg.name_to_stringp)dependent_base_packageswith|None->[]|Somepred->predletexplicit?(noop_remove=(fun_->false))~sources_neededg0=letg=copyg0in(* We insert a "build" action before any "install" action.
Except, between the removal and installation of the same package
(the removal might be postponed after a succesfull build. *)iter_vertex(funa->matchawith|`Installp|`Reinstallp|`Change(_,_,p)->letb=`Buildpiniter_pred(function|`Removep1whensame_namepp1->()|pred->remove_edgegpreda;add_edgegpredb)g0a;add_edgegba|`Remove_->()|`Build_|`Fetch_->assertfalse)g0;(* For delaying removal a little bit, for each action "remove A" we add
a constraint "build B -> remove A" for transitive predecessors
of "A" that do not have dependencies.
For adding a little bit more delay, we ignore dependencies that do not
modify the prefix (see [OpamAction.noop_remove]) *)letclosed_predecessors=compute_closed_predecessorsnoop_removeginiter_vertex(function|`Removepasa->List.iter(funb->add_edgegba)(closed_predecessorsp)|`Install_|`Reinstall_|`Change_|`Build_|`Fetch_->())g;(* Add a "fetch" action as a dependency for all "build" and "remove" actions
that require it (via [sources_needed]). *)letacc_add_action(acc:vertexlistMap.t)(p:A.package)(a:vertex):vertexlistMap.t=letacts=tryMap.findpaccwithNot_found->[]inMap.addp(a::acts)accinletm=fold_vertex(funaacc->matchawith|`Buildp|`Removep->ifsources_neededpthenacc_add_actionaccpaelseacc|`Install_|`Reinstall_|`Change_->acc|`Fetch_->assertfalse)gMap.emptyinMap.iter(funpacts->letf=`FetchpinList.iter(funa->add_edgegfa)acts)m;gletfold_descendantsfacctv=letrecauxseenfacctv=ifA.Set.memvseenthenseen,accelsefold_succ(funv(seen,acc)->auxseenfacctv)tv(A.Set.addvseen,fvacc)insnd(auxA.Set.emptyfacctv)end