123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246(**************************************************************************************)(* Copyright (C) 2009 Pietro Abate <pietro.abate@pps.jussieu.fr> *)(* Copyright (C) 2009 Mancoosi Project *)(* *)(* This library is free software: you can redistribute it and/or modify *)(* it under the terms of the GNU Lesser General Public License as *)(* published by the Free Software Foundation, either version 3 of the *)(* License, or (at your option) any later version. A special linking *)(* exception to the GNU Lesser General Public License applies to this *)(* library, see the COPYING file for more information. *)(**************************************************************************************)(** Apt command line parsing *)modulePcre=Re_pcreopenExtLibopenDose_commonincludeUtil.Logging(structletlabel="dose_deb.apt"end)letblank_regexp=Pcre.regexp"[ \t]+"(* parse the output of "dpkg -l" *)letparse_instch=leth=Hashtbl.create1000intrywhiletruedolets=input_linechinmatchPcre.split~rex:blank_regexpswith|status::name::version::_whenstatus="ii"->Hashtbl.addh(name,version)()|_->()done;hwithEnd_of_file->hletparse_inst_from_cmdcmd=letch=Unix.open_process_incmdinleth=parse_instchinlet_=close_inchinhletparse_inst_from_filefile=letch=open_infileinleth=parse_instchinlet_=close_inchinh(**********************************************************************)(* parse the a popcon file *)letparse_popcons=matchPcre.split~rex:blank_regexpswith|rank::name::inst::_->(int_of_stringrank,name,int_of_stringinst)|_->fatal"Parse error %s\n"s(*****************************************************)(*
1. apt-get install PACKAGE ...
2. apt-get install PACKAGE=VERSION ...
3. apt-get install PACKAGE/RELEASE ...
4. apt-get remove PACKAGE ...
5. apt-get upgrade ...
6. apt-get dist-upgrade ...
"-t RELEASE" option
*)typeapt_req=|InstallofDose_pef.Packages_types.vpkgreqlist|RemoveofDose_pef.Packages_types.vpkgreqlist|UpgradeofDose_pef.Packages_types.suiteoption|DistUpgradeofDose_pef.Packages_types.suiteoptionletparse_reqlabels=let_loc=Format822.dummy_locinDose_pef.Packages.lexbuf_wrapperDose_pef.Packages_parser.request_top(label,(_loc,s))letparse_pkg_reqsuites=let(r,((n,a),c),s)=parse_req"apt req suite"sinmatchsuitewith|None->(r,((n,a),c),s)|Somesuite->(r,((n,a),c),Somesuite)(** parse a string containing an apt-get command line
@return a data structure containing the request *)letparse_request_apts=ifnot(String.existss"apt-get")thenfatal"Not a valid apt-get command";lets=String.slice~first:(String.finds"apt-get")sinletsuite=refNonein(* XXX we parse a lot of options, but we do not handle them ... *)letoptions=[("-t",Arg.String(funl->suite:=Somel),"");("-s",Arg.Unit(fun_->()),"");("-y",Arg.Unit(fun_->()),"");("-v",Arg.Unit(fun_->()),"");("-f",Arg.Unit(fun_->()),"");("-o",Arg.String(fun_->()),"");("--solver",Arg.String(fun_->()),"");("--no-install-recommends",Arg.Unit(fun_->()),"");("--install-recommends",Arg.Unit(fun_->()),"");("--no-upgrade",Arg.Unit(fun_->()),"");("--no-remove",Arg.Unit(fun_->()),"")]inletreqlist=ref[]inletanons=reqlist:=s::!reqlistin(tryArg.parse_argv~current:(ref0)(Array.of_list(Pcre.split~rex:blank_regexps))optionsanon""withArg.Bads->fatal"%s"s);matchList.rev!reqlistwith|"install"::tl->Install(List.map(parse_pkg_req!suite)tl)|"remove"::tl->Remove(List.map(parse_req"apt req remove")tl)|["upgrade"]->Upgrade!suite|["dist-upgrade"]->DistUpgrade!suite|_->fatal"Bad apt request '%s'"sletparse_request_aptitudes=ifnot(String.existss"aptitude")thenfatal"Not a valid aptitude command";lets=String.slice~first:(String.finds"aptitude")sinletsuite=refNonein(* XXX we parse a lot of options, but we do not handle them ... *)letoptions=[("-t",Arg.String(funl->suite:=Somel),"");(* default suite *)("-s",Arg.Unit(fun_->()),"");("-y",Arg.Unit(fun_->()),"");("-v",Arg.Unit(fun_->()),"");("--full-resolver",Arg.Unit(fun_->()),"");("--safe-resolver",Arg.Unit(fun_->()),"");("-f",Arg.Unit(fun_->()),"");(* fix-broken *)("-r",Arg.Unit(fun_->()),"");(* with-reccomends *)("--with-recommends",Arg.Unit(fun_->()),"");("-R",Arg.Unit(fun_->()),"");(* without-reccomends *)("--without-recommends",Arg.Unit(fun_->()),"")]inletreqlist=ref[]inletanons=reqlist:=s::!reqlistin(tryArg.parse_argv~current:(ref0)(Array.of_list(Pcre.split~rex:blank_regexps))optionsanon""withArg.Bads->fatal"%s"s);matchList.rev!reqlistwith|"install"::tl->Install(List.map(parse_pkg_req!suite)tl)|"remove"::tl->Remove(List.map(parse_req"apt req remove")tl)|["upgrade"]|["safe-upgrade"]|["dist-upgrade"]->Upgrade!suite|["full-upgrade"]->DistUpgrade!suite|_->fatal"Bad aptitude request '%s'"s(*****************************************************)(** for details on the apt_preferences format :
man apt_preferences *)modulePref=structtypepin_t=|Releaseof(string*string)list|Originofstring|Versionofstringtypepackage_t=Packageofstring|Startypepin_priority_t=inttypeapt_preferences={package:package_t;pin:pin_t;pin_priority:pin_priority_t}endletcomma_regexp=Pcre.regexp"[ \t]*,[ \t]*"leteq_regexp=Pcre.regexp"[ \t]*=[ \t]*"letdi_regexp=Pcre.regexp"[0-9.]+"letal_regexp=Pcre.regexp"[a-zA-Z]+"letparse_pref_labelss=List.map(funs'->matchPcre.split~rex:eq_regexps'with|[v]whenPcre.pmatch~rex:di_regexpv->("v",v)|[v]whenPcre.pmatch~rex:al_regexpv->("a",v)|[l;v]->(l,v)|_->fatal"To many '=' in label %s"s)(Pcre.split~rex:comma_regexps)letgeneral_regexp=Pcre.regexp"^[ \t]*[*][ \t]*$"letparse_pref_package(_,(_,s))=ifPcre.pmatch~rex:general_regexpsthenPref.StarelsePref.Package(Dose_pef.Packages.parse_name("apt pref",(Format822.dummy_loc,s)))letpin_regexp=Pcre.regexp"^([A-Za-z]+)[ \t]+(.*)$"letparse_pin(_,(_,s))=tryletsubstrings=Pcre.exec~rex:pin_regexpsinmatchPcre.get_substringsubstrings1with|"release"->Pref.Release(parse_pref_labels(Pcre.get_substringsubstrings2))|"version"->Pref.Version(Pcre.get_substringsubstrings2)|"origin"->Pref.Origin(Pcre.get_substringsubstrings2)|s->fatal"Unknown pin type %s"swithNot_found->fatal"Unknown pin format %s"sletparse_preferences_stanzapar={Pref.package=Dose_pef.Packages.parse_s~required:trueparse_pref_package"Package"par;pin=Dose_pef.Packages.parse_s~required:trueparse_pin"Pin"par;pin_priority=Dose_pef.Packages.parse_s~required:trueDose_pef.Packages.parse_int"Pin-Priority"par}letrecpreferences_parserstanza_parseraccp=matchFormat822_parser.stanza_822Format822_lexer.token_822p.Format822.lexbufwith|None->acc|Somestanza->letst=stanza_parserstanzainpreferences_parserstanza_parser(st::acc)p(** parse the apt_preferences file *)letparse_preferences_inic=Format822.parse_from_ch(preferences_parserparse_preferences_stanza[])ic