diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | doc/clients/Makefile.am | 1 | ||||
-rw-r--r-- | src/clients/cave/Makefile.am | 9 | ||||
-rw-r--r-- | src/clients/cave/cmd_fix_linkage.cc | 3 | ||||
-rw-r--r-- | src/clients/cave/cmd_graph_jobs.cc | 258 | ||||
-rw-r--r-- | src/clients/cave/cmd_graph_jobs.hh | 52 | ||||
-rw-r--r-- | src/clients/cave/cmd_import.cc | 3 | ||||
-rw-r--r-- | src/clients/cave/cmd_purge.cc | 4 | ||||
-rw-r--r-- | src/clients/cave/cmd_resolve.cc | 4 | ||||
-rw-r--r-- | src/clients/cave/cmd_resolve_cmdline.cc | 27 | ||||
-rw-r--r-- | src/clients/cave/cmd_resolve_cmdline.hh | 16 | ||||
-rw-r--r-- | src/clients/cave/cmd_uninstall.cc | 4 | ||||
-rw-r--r-- | src/clients/cave/command_factory.cc | 2 | ||||
-rw-r--r-- | src/clients/cave/resolve_common.cc | 82 | ||||
-rw-r--r-- | src/clients/cave/resolve_common.hh | 1 |
15 files changed, 461 insertions, 6 deletions
diff --git a/.gitignore b/.gitignore index d09dba3c6..813dc9d76 100644 --- a/.gitignore +++ b/.gitignore @@ -90,6 +90,7 @@ paludis-*.*.*.tar.bz2 /doc/clients/cave-find-candidates.html /doc/clients/cave-fix-cache.html /doc/clients/cave-fix-linkage.html +/doc/clients/cave-graph-jobs.html /doc/clients/cave-help.html /doc/clients/cave-import.html /doc/clients/cave-info.html diff --git a/doc/clients/Makefile.am b/doc/clients/Makefile.am index 05eac7c20..4b1d7ee55 100644 --- a/doc/clients/Makefile.am +++ b/doc/clients/Makefile.am @@ -35,6 +35,7 @@ CAVE_COMMANDS_HTML = \ cave-find-candidates.html \ cave-fix-cache.html \ cave-fix-linkage.html \ + cave-graph-jobs.html \ cave-help.html \ cave-import.html \ cave-info.html \ diff --git a/src/clients/cave/Makefile.am b/src/clients/cave/Makefile.am index 49518b231..5ab056601 100644 --- a/src/clients/cave/Makefile.am +++ b/src/clients/cave/Makefile.am @@ -17,7 +17,10 @@ bin_PROGRAMS = cave noinst_PROGRAMS = man-cave -# Also update doc/clients/Makefile.am when adding here: +# When adding commands, you need to add to both command_MANS and +# libcave_a_SOURCES. You should also update command_factory.cc, +# doc/clients/Makefile.am and .gitignore. + command_MANS = \ cave-config.1 \ cave-contents.1 \ @@ -28,6 +31,7 @@ command_MANS = \ cave-find-candidates.1 \ cave-fix-cache.1 \ cave-fix-linkage.1 \ + cave-graph-jobs.1 \ cave-help.1 \ cave-import.1 \ cave-info.1 \ @@ -104,7 +108,7 @@ man_cave_LDADD = \ noinst_LIBRARIES = libcave.a -# Also update command_MANS above when adding new commands here: +# See note above for adding commands libcave_a_SOURCES = \ colour_formatter.cc colour_formatter.hh colour_formatter-fmt.hh \ command.cc command.hh \ @@ -120,6 +124,7 @@ libcave_a_SOURCES = \ cmd_find_candidates.cc cmd_find_candidates.hh \ cmd_fix_cache.cc cmd_fix_cache.hh cmd_fix_cache-fmt.hh \ cmd_fix_linkage.cc cmd_fix_linkage.hh \ + cmd_graph_jobs.cc cmd_graph_jobs.hh \ cmd_help.cc cmd_help.hh \ cmd_import.cc cmd_import.hh \ cmd_info.cc cmd_info.hh cmd_info-fmt.hh \ diff --git a/src/clients/cave/cmd_fix_linkage.cc b/src/clients/cave/cmd_fix_linkage.cc index 936928d62..01e8a110b 100644 --- a/src/clients/cave/cmd_fix_linkage.cc +++ b/src/clients/cave/cmd_fix_linkage.cc @@ -108,12 +108,14 @@ namespace ResolveCommandLineResolutionOptions resolution_options; ResolveCommandLineExecutionOptions execution_options; ResolveCommandLineDisplayOptions display_options; + ResolveCommandLineGraphJobsOptions graph_jobs_options; ResolveCommandLineProgramOptions program_options; OptionsForResolve() : resolution_options(this), execution_options(this), display_options(this), + graph_jobs_options(this), program_options(this) { } @@ -247,6 +249,7 @@ FixLinkageCommand::run( return resolve_common(env, resolve_cmdline.resolution_options, resolve_cmdline.execution_options, resolve_cmdline.display_options, + resolve_cmdline.graph_jobs_options, resolve_cmdline.program_options, make_null_shared_ptr(), targets, make_null_shared_ptr(), false); } diff --git a/src/clients/cave/cmd_graph_jobs.cc b/src/clients/cave/cmd_graph_jobs.cc new file mode 100644 index 000000000..ea0e43dd8 --- /dev/null +++ b/src/clients/cave/cmd_graph_jobs.cc @@ -0,0 +1,258 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2009, 2010 Ciaran McCreesh + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "cmd_graph_jobs.hh" +#include "cmd_resolve_cmdline.hh" +#include "exceptions.hh" +#include "command_command_line.hh" +#include <paludis/args/do_help.hh> +#include <paludis/util/safe_ifstream.hh> +#include <paludis/util/make_named_values.hh> +#include <paludis/util/make_shared_copy.hh> +#include <paludis/util/system.hh> +#include <paludis/util/destringify.hh> +#include <paludis/util/safe_ofstream.hh> +#include <paludis/util/fs_path.hh> +#include <paludis/util/join.hh> +#include <paludis/util/process.hh> +#include <paludis/resolver/job_list.hh> +#include <paludis/resolver/job_lists.hh> +#include <paludis/resolver/job.hh> +#include <paludis/resolver/job_requirements.hh> +#include <paludis/serialise-impl.hh> +#include <paludis/dep_spec.hh> +#include <paludis/name.hh> + +#include <iostream> +#include <cstdlib> + +using namespace paludis; +using namespace cave; +using namespace paludis::resolver; + +using std::cout; +using std::endl; + +namespace +{ + struct GraphJobsCommandLine : + CaveCommandCommandLine + { + ResolveCommandLineGraphJobsOptions graph_jobs_options; + ResolveCommandLineImportOptions import_options; + ResolveCommandLineProgramOptions program_options; + + GraphJobsCommandLine() : + graph_jobs_options(this), + import_options(this), + program_options(this) + { + add_environment_variable("PALUDIS_SERIALISED_RESOLUTION_FD", + "The file descriptor on which the serialised resolution can be found."); + } + + virtual std::string app_name() const + { + return "cave graph-jobs"; + } + + virtual std::string app_synopsis() const + { + return "Creates a Graphviz graph for jobs in a resolution created using 'cave resolve'."; + } + + virtual std::string app_description() const + { + return "Creates a Graphviz graph for jobs in a resolution created using 'cave resolve'. Mostly for " + "internal use; most users will not use this command directly."; + } + }; + + std::string short_spec(const PackageDepSpec & p, bool full) + { + if (full || ! p.package_ptr()) + return stringify(p); + else + { + std::string result(stringify(p.package_ptr()->package())); + if (p.slot_requirement_ptr()) + result = result + stringify(*p.slot_requirement_ptr()); + if (p.in_repository_ptr()) + result = result + "::" + stringify(*p.in_repository_ptr()); + return result; + } + } + + struct ShowOneJobAttrs + { + std::ostream & output_stream; + bool full; + + void visit(const FetchJob & job) const + { + output_stream << "label=\"fetch " << short_spec(job.origin_id_spec(), full) << "\", "; + output_stream << "shape=ellipse, "; + output_stream << "fillcolor=cadetblue, "; + output_stream << "style=filled"; + } + + void visit(const InstallJob & job) const + { + output_stream << "label=\"" << short_spec(job.origin_id_spec(), full) << " -> " << job.destination_repository_name() << "\""; + output_stream << "shape=box, "; + output_stream << "fillcolor=royalblue, "; + output_stream << "style=filled"; + } + + void visit(const UninstallJob & job) const + { + output_stream << "label=\"uninstall " << join(job.ids_to_remove_specs()->begin(), job.ids_to_remove_specs()->end(), ", ", + std::bind(&short_spec, std::placeholders::_1, full)) << "\""; + output_stream << "shape=hexagon, "; + output_stream << "fillcolor=slateblue, "; + output_stream << "style=filled"; + } + }; + + void graph_jobs( + const std::shared_ptr<Environment> &, + const GraphJobsCommandLine & cmdline, + const std::shared_ptr<const JobList<ExecuteJob> > & execute_job_list, + std::ostream & output_stream) + { + output_stream << "digraph Jobs {" << endl; + output_stream << " graph [ splines=true ]" << endl; + output_stream << " node [ fontsize=8, fontname=sans, height=0, width=0 ]" << endl; + + for (auto j(execute_job_list->begin()), j_end(execute_job_list->end()) ; + j != j_end ; ++j) + { + output_stream << " job" << execute_job_list->number(j) << " [ "; + (*j)->accept(ShowOneJobAttrs{output_stream, cmdline.graph_jobs_options.a_graph_jobs_full_names.specified()}); + output_stream << " ]" << endl; + + for (auto r((*j)->requirements()->begin()), r_end((*j)->requirements()->end()) ; + r != r_end ; ++r) + { + if (! cmdline.graph_jobs_options.a_graph_jobs_all_arrows.specified()) + if (! (r->required_if() - jri_require_for_independent).any()) + continue; + + output_stream << " job" << execute_job_list->number(j) << " -> job" << r->job_number() << " [ "; + if (r->required_if()[jri_fetching]) + output_stream << " color=cadetblue"; + else if (r->required_if()[jri_require_always]) + output_stream << " color=crimson"; + else if (r->required_if()[jri_require_for_satisfied]) + output_stream << " color=indianred"; + else if (r->required_if()[jri_require_for_independent]) + output_stream << " color=lightpink"; + + output_stream << " ]" << endl; + } + + output_stream << endl; + } + + output_stream << "}" << endl; + } + + int create_graph( + const std::shared_ptr<Environment> &, + const GraphJobsCommandLine & cmdline, + const FSPath & src, + const FSPath & dst) + { + Process process(ProcessCommand({ cmdline.program_options.a_graph_jobs_program.argument(), + "-T", cmdline.graph_jobs_options.a_graph_jobs_format.argument(), + stringify(src), "-o", stringify(dst) + })); + + return process.run().wait(); + } +} + +bool +GraphJobsCommand::important() const +{ + return false; +} + +int +GraphJobsCommand::run( + const std::shared_ptr<Environment> & env, + const std::shared_ptr<const Sequence<std::string > > & args, + const std::shared_ptr<const Resolved> & maybe_resolved + ) +{ + GraphJobsCommandLine cmdline; + cmdline.run(args, "CAVE", "CAVE_GRAPH_JOBS_OPTIONS", "CAVE_GRAPH_JOBS_CMDLINE"); + + if (cmdline.a_help.specified()) + { + cout << cmdline; + return EXIT_SUCCESS; + } + + cmdline.import_options.apply(env); + + std::shared_ptr<const Resolved> resolved(maybe_resolved); + if (! resolved) + { + if (getenv_with_default("PALUDIS_SERIALISED_RESOLUTION_FD", "").empty()) + throw args::DoHelp("PALUDIS_SERIALISED_RESOLUTION_FD must be provided"); + + int fd(destringify<int>(getenv_with_default("PALUDIS_SERIALISED_RESOLUTION_FD", ""))); + SafeIFStream deser_stream(fd); + Deserialiser deserialiser(env.get(), deser_stream); + Deserialisation deserialisation("Resolved", deserialiser); + resolved = make_shared_copy(Resolved::deserialise(deserialisation)); + close(fd); + } + + std::shared_ptr<SafeOFStream> stream_if_file; + if (! cmdline.graph_jobs_options.a_graph_jobs_basename.argument().empty()) + stream_if_file = std::make_shared<SafeOFStream>(FSPath(cmdline.graph_jobs_options.a_graph_jobs_basename.argument() + ".graphviz")); + + int retcode(0); + + graph_jobs(env, cmdline, resolved->job_lists()->execute_job_list(), stream_if_file ? *stream_if_file : cout); + + if (stream_if_file && ! cmdline.graph_jobs_options.a_graph_jobs_format.argument().empty()) + retcode = create_graph(env, cmdline, + FSPath(cmdline.graph_jobs_options.a_graph_jobs_basename.argument() + ".graphviz"), + FSPath(cmdline.graph_jobs_options.a_graph_jobs_basename.argument() + "." + cmdline.graph_jobs_options.a_graph_jobs_format.argument())); + + return retcode; +} + +int +GraphJobsCommand::run( + const std::shared_ptr<Environment> & env, + const std::shared_ptr<const Sequence<std::string > > & args) +{ + return run(env, args, make_null_shared_ptr()); +} + +std::shared_ptr<args::ArgsHandler> +GraphJobsCommand::make_doc_cmdline() +{ + return std::make_shared<GraphJobsCommandLine>(); +} + diff --git a/src/clients/cave/cmd_graph_jobs.hh b/src/clients/cave/cmd_graph_jobs.hh new file mode 100644 index 000000000..c1772d556 --- /dev/null +++ b/src/clients/cave/cmd_graph_jobs.hh @@ -0,0 +1,52 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2009, 2010 Ciaran McCreesh + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_GRAPH_JOBS_HH +#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_GRAPH_JOBS_HH 1 + +#include "command.hh" +#include <paludis/resolver/resolved-fwd.hh> + +namespace paludis +{ + namespace cave + { + class PALUDIS_VISIBLE GraphJobsCommand : + public Command + { + public: + bool important() const; + + int run( + const std::shared_ptr<Environment> &, + const std::shared_ptr<const Sequence<std::string > > & args + ); + + int run( + const std::shared_ptr<Environment> &, + const std::shared_ptr<const Sequence<std::string > > & args, + const std::shared_ptr<const resolver::Resolved> & maybe_resolved + ); + + std::shared_ptr<args::ArgsHandler> make_doc_cmdline(); + }; + } +} + +#endif diff --git a/src/clients/cave/cmd_import.cc b/src/clients/cave/cmd_import.cc index a027b35c7..889c89b86 100644 --- a/src/clients/cave/cmd_import.cc +++ b/src/clients/cave/cmd_import.cc @@ -144,12 +144,14 @@ namespace ResolveCommandLineResolutionOptions resolution_options; ResolveCommandLineExecutionOptions execution_options; ResolveCommandLineDisplayOptions display_options; + ResolveCommandLineGraphJobsOptions graph_jobs_options; ResolveCommandLineProgramOptions program_options; OptionsForResolve() : resolution_options(this), execution_options(this), display_options(this), + graph_jobs_options(this), program_options(this) { } @@ -311,6 +313,7 @@ ImportCommand::run( resolve_cmdline.resolution_options, resolve_cmdline.execution_options, resolve_cmdline.display_options, + resolve_cmdline.graph_jobs_options, resolve_cmdline.program_options, keys, targets, world_specs, false); } diff --git a/src/clients/cave/cmd_purge.cc b/src/clients/cave/cmd_purge.cc index 7382a4ec3..704601502 100644 --- a/src/clients/cave/cmd_purge.cc +++ b/src/clients/cave/cmd_purge.cc @@ -51,12 +51,14 @@ namespace std::shared_ptr<ResolveCommandLineResolutionOptions> resolution_options; std::shared_ptr<ResolveCommandLineExecutionOptions> execution_options; std::shared_ptr<ResolveCommandLineDisplayOptions> display_options; + std::shared_ptr<ResolveCommandLineGraphJobsOptions> graph_jobs_options; std::shared_ptr<ResolveCommandLineProgramOptions> program_options; PurgeCommandLine(const bool for_docs) : resolution_options(for_docs ? make_null_shared_ptr() : std::make_shared<ResolveCommandLineResolutionOptions>(this)), execution_options(for_docs ? make_null_shared_ptr() : std::make_shared<ResolveCommandLineExecutionOptions>(this)), display_options(for_docs ? make_null_shared_ptr() : std::make_shared<ResolveCommandLineDisplayOptions>(this)), + graph_jobs_options(for_docs ? make_null_shared_ptr() : std::make_shared<ResolveCommandLineGraphJobsOptions>(this)), program_options(for_docs ? make_null_shared_ptr() : std::make_shared<ResolveCommandLineProgramOptions>(this)) { add_usage_line("[ -x|--execute ]"); @@ -112,7 +114,7 @@ PurgeCommand::run( cmdline.resolution_options->a_purge.add_argument("*/*"); return resolve_common(env, *cmdline.resolution_options, *cmdline.execution_options, *cmdline.display_options, - *cmdline.program_options, make_null_shared_ptr(), make_null_shared_ptr(), make_null_shared_ptr(), true); + *cmdline.graph_jobs_options, *cmdline.program_options, make_null_shared_ptr(), make_null_shared_ptr(), make_null_shared_ptr(), true); } std::shared_ptr<args::ArgsHandler> diff --git a/src/clients/cave/cmd_resolve.cc b/src/clients/cave/cmd_resolve.cc index b3dab40cf..7d01f1d46 100644 --- a/src/clients/cave/cmd_resolve.cc +++ b/src/clients/cave/cmd_resolve.cc @@ -39,12 +39,14 @@ namespace ResolveCommandLineResolutionOptions resolution_options; ResolveCommandLineExecutionOptions execution_options; ResolveCommandLineDisplayOptions display_options; + ResolveCommandLineGraphJobsOptions graph_jobs_options; ResolveCommandLineProgramOptions program_options; ResolveCommandLine() : resolution_options(this), execution_options(this), display_options(this), + graph_jobs_options(this), program_options(this) { add_usage_line("[ -x|--execute ] [ -z|--lazy or -c|--complete or -e|--everything ] spec ..."); @@ -102,7 +104,7 @@ ResolveCommand::run( targets->push_back(std::make_pair(*p, "")); return resolve_common(env, cmdline.resolution_options, cmdline.execution_options, cmdline.display_options, - cmdline.program_options, make_null_shared_ptr(), targets, make_null_shared_ptr(), false); + cmdline.graph_jobs_options, cmdline.program_options, make_null_shared_ptr(), targets, make_null_shared_ptr(), false); } std::shared_ptr<args::ArgsHandler> diff --git a/src/clients/cave/cmd_resolve_cmdline.cc b/src/clients/cave/cmd_resolve_cmdline.cc index c58f31835..a0abbc364 100644 --- a/src/clients/cave/cmd_resolve_cmdline.cc +++ b/src/clients/cave/cmd_resolve_cmdline.cc @@ -304,6 +304,26 @@ ResolveCommandLineDisplayOptions::ResolveCommandLineDisplayOptions(args::ArgsHan { } +ResolveCommandLineGraphJobsOptions::ResolveCommandLineGraphJobsOptions(args::ArgsHandler * const h) : + ArgsSection(h, "Graph Jobs Options"), + g_graph_jobs_options(this, "Graph Jobs Options", "Options relating to creating graphs for jobs. If " + "--graph-jobs-basename is specified, a Graphviz graph will be created for the jobs in the resolution."), + a_graph_jobs_basename(&g_graph_jobs_options, "graph-jobs-basename", '\0', "Specify the basename (filename without " + "extension) to be used when creating job graphs. If unspecified, no jobs graph will be created."), + a_graph_jobs_format(&g_graph_jobs_options, "graph-jobs-format", '\0', "Specifies the desired output format for " + "the Graphviz graph. The argument must be a valid value for the '-T' option for Graphviz. Also determines " + "the file extension of the generated graph. If unspecified, only a raw graph file will be created, and it " + "will not be processed using Graphviz."), + + g_graph_jobs_format_options(this, "Graph Jobs Format Options", "Options relating to the format of created graphs."), + a_graph_jobs_all_arrows(&g_graph_jobs_format_options, "graph-jobs-all-arrows", '\0', "Show all arrows. By default " + "dependencies required only for if-independent are not shown, since for non-trivial resolutions " + "Graphviz will otherwise require obscene amounts of memory.", true), + a_graph_jobs_full_names(&g_graph_jobs_format_options, "graph-jobs-full-names", '\0', "Show full names for graph " + "jobs.", true) +{ +} + ResolveCommandLineExecutionOptions::ResolveCommandLineExecutionOptions(args::ArgsHandler * const h) : ArgsSection(h, "Execution Options"), @@ -356,13 +376,18 @@ ResolveCommandLineProgramOptions::ResolveCommandLineProgramOptions(args::ArgsHan "instead of spawning a new process."), a_display_resolution_program(&g_program_options, "display-resolution-program", '\0', "The program used to display " "the resolution. Defaults to '$CAVE display-resolution'."), + a_graph_jobs_program(&g_program_options, "graph-jobs-resolution-program", '\0', "The program used to graph " + "jobs. Defaults to '$CAVE graph-jobs'."), a_execute_resolution_program(&g_program_options, "execute-resolution-program", '\0', "The program used to execute " "the resolution. Defaults to '$CAVE execute-resolution'."), a_perform_program(&g_program_options, "perform-program", '\0', "The program used to perform " "actions. Defaults to '$CAVE perform'."), a_update_world_program(&g_program_options, "update-world-program", '\0', "The program used to perform " - "world updates. Defaults to '$CAVE update-world'.") + "world updates. Defaults to '$CAVE update-world'."), + a_graph_program(&g_program_options, "graph-program", '\0', "The program used to create Graphviz graphs. " + "Defaults to 'dot'.") { + a_graph_jobs_program.set_argument("dot"); } ResolveCommandLineImportOptions::ResolveCommandLineImportOptions(args::ArgsHandler * const h) : diff --git a/src/clients/cave/cmd_resolve_cmdline.hh b/src/clients/cave/cmd_resolve_cmdline.hh index bda9eab1c..01a22e048 100644 --- a/src/clients/cave/cmd_resolve_cmdline.hh +++ b/src/clients/cave/cmd_resolve_cmdline.hh @@ -150,6 +150,20 @@ namespace paludis args::StringSetArg a_explain; }; + struct ResolveCommandLineGraphJobsOptions : + args::ArgsSection + { + ResolveCommandLineGraphJobsOptions(args::ArgsHandler * const); + + args::ArgsGroup g_graph_jobs_options; + args::StringArg a_graph_jobs_basename; + args::StringArg a_graph_jobs_format; + + args::ArgsGroup g_graph_jobs_format_options; + args::SwitchArg a_graph_jobs_all_arrows; + args::SwitchArg a_graph_jobs_full_names; + }; + struct ResolveCommandLineProgramOptions : args::ArgsSection { @@ -157,9 +171,11 @@ namespace paludis args::ArgsGroup g_program_options; args::StringArg a_display_resolution_program; + args::StringArg a_graph_jobs_program; args::StringArg a_execute_resolution_program; args::StringArg a_perform_program; args::StringArg a_update_world_program; + args::StringArg a_graph_program; }; struct ResolveCommandLineImportOptions : diff --git a/src/clients/cave/cmd_uninstall.cc b/src/clients/cave/cmd_uninstall.cc index 17626a270..4510de0c9 100644 --- a/src/clients/cave/cmd_uninstall.cc +++ b/src/clients/cave/cmd_uninstall.cc @@ -57,6 +57,7 @@ namespace std::shared_ptr<ResolveCommandLineResolutionOptions> resolution_options; std::shared_ptr<ResolveCommandLineExecutionOptions> execution_options; std::shared_ptr<ResolveCommandLineDisplayOptions> display_options; + std::shared_ptr<ResolveCommandLineGraphJobsOptions> graph_jobs_options; std::shared_ptr<ResolveCommandLineProgramOptions> program_options; UninstallCommandLine(const bool for_docs) : @@ -66,6 +67,7 @@ namespace resolution_options(for_docs ? make_null_shared_ptr() : std::make_shared<ResolveCommandLineResolutionOptions>(this)), execution_options(for_docs ? make_null_shared_ptr() : std::make_shared<ResolveCommandLineExecutionOptions>(this)), display_options(for_docs ? make_null_shared_ptr() : std::make_shared<ResolveCommandLineDisplayOptions>(this)), + graph_jobs_options(for_docs ? make_null_shared_ptr() : std::make_shared<ResolveCommandLineGraphJobsOptions>(this)), program_options(for_docs ? make_null_shared_ptr() : std::make_shared<ResolveCommandLineProgramOptions>(this)) { add_usage_line("[ -x|--execute ] [ --uninstalls-may-break */* ] [ --remove-if-dependent */* ] spec ..."); @@ -187,7 +189,7 @@ UninstallCommand::run( } return resolve_common(env, *cmdline.resolution_options, *cmdline.execution_options, *cmdline.display_options, - *cmdline.program_options, make_null_shared_ptr(), targets, targets_cleaned_up, false); + *cmdline.graph_jobs_options, *cmdline.program_options, make_null_shared_ptr(), targets, targets_cleaned_up, false); } std::shared_ptr<args::ArgsHandler> diff --git a/src/clients/cave/command_factory.cc b/src/clients/cave/command_factory.cc index f7c18c18b..2df39687b 100644 --- a/src/clients/cave/command_factory.cc +++ b/src/clients/cave/command_factory.cc @@ -44,6 +44,7 @@ #include "cmd_find_candidates.hh" #include "cmd_fix_cache.hh" #include "cmd_fix_linkage.hh" +#include "cmd_graph_jobs.hh" #include "cmd_help.hh" #include "cmd_import.hh" #include "cmd_info.hh" @@ -152,6 +153,7 @@ CommandFactory::CommandFactory() : _imp->handlers.insert(std::make_pair("find-candidates", std::bind(&make_command<FindCandidatesCommand>))); _imp->handlers.insert(std::make_pair("fix-cache", std::bind(&make_command<FixCacheCommand>))); _imp->handlers.insert(std::make_pair("fix-linkage", std::bind(&make_command<FixLinkageCommand>))); + _imp->handlers.insert(std::make_pair("graph-jobs", std::bind(&make_command<GraphJobsCommand>))); _imp->handlers.insert(std::make_pair("help", std::bind(&make_command<HelpCommand>))); _imp->handlers.insert(std::make_pair("import", std::bind(&make_command<ImportCommand>))); _imp->handlers.insert(std::make_pair("info", std::bind(&make_command<InfoCommand>))); diff --git a/src/clients/cave/resolve_common.cc b/src/clients/cave/resolve_common.cc index 3c7b02cdd..341f64f1a 100644 --- a/src/clients/cave/resolve_common.cc +++ b/src/clients/cave/resolve_common.cc @@ -22,6 +22,7 @@ #include "cmd_resolve_dump.hh" #include "cmd_display_resolution.hh" #include "cmd_execute_resolution.hh" +#include "cmd_graph_jobs.hh" #include "exceptions.hh" #include "command_command_line.hh" @@ -255,6 +256,82 @@ namespace return DisplayResolutionCommand().run(env, args, resolved); } + int graph_jobs( + const std::shared_ptr<Environment> & env, + const std::shared_ptr<const Resolved> & resolved, + const ResolveCommandLineResolutionOptions &, + const ResolveCommandLineGraphJobsOptions & graph_jobs_options, + const ResolveCommandLineProgramOptions & program_options, + const std::shared_ptr<const Map<std::string, std::string> > & keys_if_import, + const std::shared_ptr<const Sequence<std::pair<std::string, std::string> > > & targets) + { + Context context("When graphing jobs:"); + + if (! graph_jobs_options.a_graph_jobs_basename.specified()) + return 0; + + StringListStream ser_stream; + Thread ser_thread(std::bind(&serialise_resolved, + std::ref(ser_stream), + std::cref(*resolved))); + + std::shared_ptr<Sequence<std::string> > args(std::make_shared<Sequence<std::string>>()); + + for (args::ArgsSection::GroupsConstIterator g(graph_jobs_options.begin()), g_end(graph_jobs_options.end()) ; + g != g_end ; ++g) + { + for (args::ArgsGroup::ConstIterator o(g->begin()), o_end(g->end()) ; + o != o_end ; ++o) + if ((*o)->specified()) + { + const std::shared_ptr<const Sequence<std::string> > f((*o)->forwardable_args()); + std::copy(f->begin(), f->end(), args->back_inserter()); + } + } + + for (args::ArgsSection::GroupsConstIterator g(program_options.begin()), g_end(program_options.end()) ; + g != g_end ; ++g) + { + for (args::ArgsGroup::ConstIterator o(g->begin()), o_end(g->end()) ; + o != o_end ; ++o) + if ((*o)->specified()) + { + const std::shared_ptr<const Sequence<std::string> > f((*o)->forwardable_args()); + std::copy(f->begin(), f->end(), args->back_inserter()); + } + } + + for (Sequence<std::pair<std::string, std::string> >::ConstIterator p(targets->begin()), p_end(targets->end()) ; + p != p_end ; ++p) + args->push_back(p->first); + + if (program_options.a_graph_jobs_program.specified()) + { + std::string command(program_options.a_graph_jobs_program.argument()); + + if (keys_if_import) + for (Map<std::string, std::string>::ConstIterator k(keys_if_import->begin()), + k_end(keys_if_import->end()) ; + k != k_end ; ++k) + { + args->push_back("--unpackaged-repository-params"); + args->push_back(k->first + "=" + k->second); + } + + for (Sequence<std::string>::ConstIterator a(args->begin()), a_end(args->end()) ; + a != a_end ; ++a) + command = command + " " + args::escape(*a); + + Process process((ProcessCommand(command))); + process + .send_input_to_fd(ser_stream, -1, "PALUDIS_SERIALISED_RESOLUTION_FD"); + + return process.run().wait(); + } + else + return GraphJobsCommand().run(env, args, resolved); + } + void serialise_job_lists(StringListStream & ser_stream, const JobLists & job_lists) { Serialiser ser(ser_stream); @@ -569,6 +646,7 @@ paludis::cave::resolve_common( const ResolveCommandLineResolutionOptions & resolution_options, const ResolveCommandLineExecutionOptions & execution_options, const ResolveCommandLineDisplayOptions & display_options, + const ResolveCommandLineGraphJobsOptions & graph_jobs_options, const ResolveCommandLineProgramOptions & program_options, const std::shared_ptr<const Map<std::string, std::string> > & keys_if_import, const std::shared_ptr<const Sequence<std::pair<std::string, std::string> > > & targets_if_not_purge, @@ -891,6 +969,10 @@ paludis::cave::resolve_common( display_options, program_options, keys_if_import, purge ? std::make_shared<const Sequence<std::pair<std::string, std::string> > >() : targets_if_not_purge); + retcode |= graph_jobs(env, resolver->resolved(), resolution_options, + graph_jobs_options, program_options, keys_if_import, + purge ? std::make_shared<const Sequence<std::pair<std::string, std::string> > >() : targets_if_not_purge); + if (! resolver->resolved()->taken_unable_to_make_decisions()->empty()) retcode |= 1; diff --git a/src/clients/cave/resolve_common.hh b/src/clients/cave/resolve_common.hh index 242b1ae3d..1a7aa8f13 100644 --- a/src/clients/cave/resolve_common.hh +++ b/src/clients/cave/resolve_common.hh @@ -35,6 +35,7 @@ namespace paludis const ResolveCommandLineResolutionOptions & resolution_options, const ResolveCommandLineExecutionOptions & execution_options, const ResolveCommandLineDisplayOptions & display_options, + const ResolveCommandLineGraphJobsOptions & graph_jobs_options, const ResolveCommandLineProgramOptions & program_options, const std::shared_ptr<const Map<std::string, std::string> > & keys_if_import, const std::shared_ptr<const Sequence<std::pair<std::string, std::string> > > & targets_if_not_purge, |