(**************************************************************************************) (* Copyright (C) 2009 Pietro Abate *) (* Copyright (C) 2009 Mancoosi Project *) (* Copyright (C) 2014 Johannes Schauer *) (* *) (* 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. *) (**************************************************************************************) open! ExtLib open Dose_debian open Dose_common open Dose_algo open Dose_doseparse module Src = Sources module Deb = Packages module Options = struct open OptParse let description = "Report the broken packages in a debian source list. \ You must provide a (list of) Debian Packages file(s) and \ a Debian Sources file in this order" let options = OptParser.make ~description include StdOptions.MakeOptions(struct let options = options end) let dump = StdOpt.str_option () let maforeign = StdOpt.store_true () let includextra = StdOpt.store_true () let tupletable = StdOpt.str_option () let cputable = StdOpt.str_option () let dropalternatives = StdOpt.store_true () include StdOptions.DistcheckOptions ;; StdOptions.DistcheckOptions.add_options options ;; include StdOptions.InputOptions ;; let default = List.fold_left (fun acc e -> List.remove acc e ) StdOptions.InputOptions.default_options ["inputtype";"fg";"bg";"compare"] in StdOptions.InputOptions.add_options ~default options ; include StdOptions.OutputOptions ;; StdOptions.OutputOptions.add_options options ;; StdOptions.OutputOptions.add_option options ~long_name:"dump" ~help:"dump the cudf file" dump; include StdOptions.DistribOptions ;; StdOptions.DistribOptions.add_debian_options options ;; let group = StdOptions.DistribOptions.deb_group options in StdOptions.DistribOptions.add_option options ~group ~long_name:"deb-tupletable" ~help:"Path to an architecture tuple table like /usr/share/dpkg/tupletable" tupletable; StdOptions.DistribOptions.add_option options ~group ~long_name:"deb-cputable" ~help:"Path to a cpu table like /usr/share/dpkg/cputable" cputable; StdOptions.DistribOptions.add_option options ~group ~long_name:"deb-defaulted-m-a-foreign" ~help:"Convert Arch:all packages to Multi-Arch: foreign" maforeign; StdOptions.DistribOptions.add_option options ~group ~long_name:"deb-include-extra-source" ~help:"Include packages with Extra-Source-Only:yes (dropped by default)" includextra; StdOptions.DistribOptions.add_option options ~group ~long_name:"deb-emulate-sbuild" ~help:"replicate sbuild behaviour to only keep the first alternative of build dependencies" dropalternatives; end #define __label __FILE__ let label = __label ;; include Util.Logging(struct let label = label end) ;; let timer = Util.Timer.create "Solver" let progress = Util.Progress.create "Solver" let main () = let posargs = OptParse.OptParser.parse_argv Options.options in StdDebug.enable_debug (OptParse.Opt.get Options.verbose); StdDebug.enable_timers (OptParse.Opt.get Options.timers) ["Solver";"Load.DebianSource"]; StdDebug.enable_bars (OptParse.Opt.get Options.progress) ["Solver"]; Util.Debug.disable "Depsolver_int"; StdDebug.all_quiet (OptParse.Opt.get Options.quiet); if not(OptParse.Opt.is_set Options.deb_native_arch) then fatal "You must at least specify the native architecture"; let fmt = if OptParse.Opt.is_set Options.outfile then let oc = open_out (OptParse.Opt.get Options.outfile) in Format.formatter_of_out_channel oc else Format.std_formatter in (* we set the Debian.Debcudf options wrt the user provided options *) let options = Options.set_deb_options () in (* buildarch and native arch must be set to some architecture at this point *) let buildarch = Option.get options.Debcudf.native in (* hostarch can be None *) let hostarch = match options.Debcudf.host with None -> "" | Some s -> s in let noindep = options.Debcudf.drop_bd_indep in let dropalternatives = OptParse.Opt.get Options.dropalternatives in let profiles = options.Debcudf.profiles in let filter_external_sources par = if (OptParse.Opt.get Options.includextra) then true else try not(Dose_pef.Packages.parse_bool ("extra-source-only",(Dose_pef.Packages.assoc "extra-source-only" par))) with Not_found -> true in if (OptParse.Opt.is_set Options.tupletable) || OptParse.Opt.is_set Options.cputable then begin let ttfile = if OptParse.Opt.is_set Options.tupletable then Some (OptParse.Opt.get Options.tupletable) else None in let ctfile = if OptParse.Opt.is_set Options.cputable then Some (OptParse.Opt.get Options.cputable) else None in Architecture.read_tupletable ~ttfile ~ctfile () end; let pkglist, srclist = match posargs with |[] | [_] -> fatal "You must provide a list of Debian Packages files and \ a Debian Sources file" |l -> begin match List.rev l with |h::t -> let srclist = StdLoaders.deb_load_source ~dropalternatives ~profiles ~filter:filter_external_sources ~noindep buildarch hostarch h in let pkglist = Deb.input_raw t in (pkglist,srclist) |_ -> fatal "An impossible situation occurred ?!#" end in let tables = Debcudf.init_tables (srclist @ pkglist) in let global_constraints = Debcudf.get_essential ~options tables in let to_cudf (p,v) = (p,Debcudf.get_cudf_version tables (p,v)) in let from_cudf (p,v) = Debcudf.get_real_version tables (p,v) in let pp = CudfAdd.pp ?fields:None ?decode:None from_cudf in (* XXX here latest could be a bit faster if done at the same time of the cudf conversion *) let sl = let l = List.map (fun pkg -> Debcudf.tocudf ~options tables pkg) srclist in if OptParse.Opt.is_set Options.latest then CudfAdd.latest ~n:(OptParse.Opt.get Options.latest) l else l in let bl = List.fold_left (fun acc pkg -> let pkg = if OptParse.Opt.get Options.maforeign && pkg#architecture = "all" then pkg#set_multiarch `Foreign else pkg in (Debcudf.tocudf ~options tables pkg)::acc ) sl pkglist in let universe = ref (Cudf.load_universe bl) in let universe_size = Cudf.universe_size !universe in let failure = OptParse.Opt.get Options.failure in let success = OptParse.Opt.get Options.success in let explain = if success || failure then OptParse.Opt.get Options.explain else false in let minimal = OptParse.Opt.get Options.minimal in let summary = OptParse.Opt.get Options.summary in let checklist = if OptParse.Opt.is_set Options.checkonly then begin List.flatten ( List.map (fun ((n,a),c) -> let (name,filter) = Dose_pef.Pefcudf.pefvpkg to_cudf (("src:"^n,a),c) in Cudf.lookup_packages ~filter !universe name ) (OptParse.Opt.get Options.checkonly) ) end else sl in Diagnostic.pp_out_version fmt; if OptParse.Opt.is_set Options.deb_native_arch then Format.fprintf fmt "native-architecture: %s@." (OptParse.Opt.get Options.deb_native_arch); if OptParse.Opt.is_set Options.deb_foreign_archs then Format.fprintf fmt "foreign-architecture: %s@." (String.concat "," (OptParse.Opt.get Options.deb_foreign_archs)); if OptParse.Opt.is_set Options.deb_host_arch then Format.fprintf fmt "host-architecture: %s@." (OptParse.Opt.get Options.deb_host_arch); let results = Diagnostic.default_result universe_size in if failure || success then Format.fprintf fmt "@[report:@,"; let failures = ref [] in let callback = function | {Diagnostic.result = Diagnostic.Failure _ ; request = [r]} -> failures := r::!failures | {Diagnostic.result = Diagnostic.Success _ } as d -> Diagnostic.fprintf ~pp ~failure ~success ~explain ~minimal fmt d | _ -> failwith "impossible" in Util.Timer.start timer; let nbp = Depsolver.listcheck ~global_constraints ~callback ~explain !universe checklist in Util.Progress.set_total progress (List.length !failures); (* process the packages to check one by one because the changes to the * universe made for one package must not propagate to the others *) List.iter (fun pkg -> Util.Progress.progress progress; info "working on %s" (BootstrapCommon.string_of_package pkg); (* reset the universe to its original state before every run *) universe := Cudf.load_universe bl; let rec aux () = match Depsolver.listcheck ~global_constraints ~callback:(BootstrapCommon.more_problems_callback (Diagnostic.fprintf ~pp ~failure ~success ~explain ~minimal fmt) universe results summary) !universe [pkg] with | 0 -> () | _ -> aux () in aux (); ) (BootstrapCommon.debcudf_sort !failures); ignore(Util.Timer.stop timer ()); (* reset the universe to its original state after the last run *) universe := Cudf.load_universe bl; if failure || success then Format.fprintf fmt "@]@."; let nb = universe_size in let nf = List.length sl in Format.fprintf fmt "binary-packages: %d@." nb; Format.fprintf fmt "source-packages: %d@." (if nf = 0 then nb else nf); Format.fprintf fmt "broken-packages: %d@." nbp; if summary then Format.fprintf fmt "@[%a@]@." (Diagnostic.pp_summary ~pp ()) results; if OptParse.Opt.is_set Options.dump then begin let oc = open_out (OptParse.Opt.get Options.dump) in info "Dumping Cudf file"; Cudf_printer.pp_preamble oc Debcudf.preamble; Printf.fprintf oc "\n"; Cudf_printer.pp_universe oc !universe end; nbp ;; StdUtils.if_application ~alternatives:["botch-buildcheck-more-problems"] __label main ;;