aboutsummaryrefslogtreecommitdiff
path: root/0.8.0/src/adjutrix
diff options
context:
space:
mode:
Diffstat (limited to '0.8.0/src/adjutrix')
-rw-r--r--0.8.0/src/adjutrix/Makefile.am88
-rw-r--r--0.8.0/src/adjutrix/adjutrix.cc278
-rw-r--r--0.8.0/src/adjutrix/command_line.cc140
-rw-r--r--0.8.0/src/adjutrix/command_line.hh126
-rw-r--r--0.8.0/src/adjutrix/display_default_system_resolution.cc135
-rw-r--r--0.8.0/src/adjutrix/display_default_system_resolution.hh27
-rw-r--r--0.8.0/src/adjutrix/display_profiles_use.cc176
-rw-r--r--0.8.0/src/adjutrix/display_profiles_use.hh27
-rw-r--r--0.8.0/src/adjutrix/find_dropped_keywords.cc208
-rw-r--r--0.8.0/src/adjutrix/find_dropped_keywords.hh28
-rw-r--r--0.8.0/src/adjutrix/find_dropped_keywords.sr13
-rw-r--r--0.8.0/src/adjutrix/find_insecure_packages.cc162
-rw-r--r--0.8.0/src/adjutrix/find_insecure_packages.hh27
-rw-r--r--0.8.0/src/adjutrix/find_reverse_deps.cc291
-rw-r--r--0.8.0/src/adjutrix/find_reverse_deps.hh28
-rw-r--r--0.8.0/src/adjutrix/find_stable_candidates.cc210
-rw-r--r--0.8.0/src/adjutrix/find_stable_candidates.hh27
-rw-r--r--0.8.0/src/adjutrix/find_stable_candidates.sr12
-rwxr-xr-x0.8.0/src/adjutrix/find_stable_candidates_TEST18
-rwxr-xr-x0.8.0/src/adjutrix/find_stable_candidates_TEST_cleanup.sh11
-rwxr-xr-x0.8.0/src/adjutrix/find_stable_candidates_TEST_setup.sh71
-rwxr-xr-x0.8.0/src/adjutrix/help_TEST4
-rw-r--r--0.8.0/src/adjutrix/keywords_graph.cc195
-rw-r--r--0.8.0/src/adjutrix/keywords_graph.hh27
-rw-r--r--0.8.0/src/adjutrix/man_adjutrix.cc36
-rwxr-xr-x0.8.0/src/adjutrix/version_TEST3
26 files changed, 2368 insertions, 0 deletions
diff --git a/0.8.0/src/adjutrix/Makefile.am b/0.8.0/src/adjutrix/Makefile.am
new file mode 100644
index 0000000..11eac6e
--- /dev/null
+++ b/0.8.0/src/adjutrix/Makefile.am
@@ -0,0 +1,88 @@
+AM_CXXFLAGS = -I$(top_srcdir) -I$(top_srcdir)/src @PALUDIS_CXXFLAGS@
+DEFS= \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DDATADIR=\"$(datadir)\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DLIBDIR=\"$(libdir)\"
+
+SUBDIRS = .
+
+bin_PROGRAMS = adjutrix
+noinst_PROGRAMS = man-adjutrix
+
+man_MANS = adjutrix.1
+
+adjutrix.1 : man-adjutrix
+ ./man-adjutrix | tee $@ | sed -e 's/^/ /'
+
+man_adjutrix_SOURCES = \
+ man_adjutrix.cc \
+ command_line.hh \
+ command_line.cc
+
+man_adjutrix_LDADD = \
+ $(top_builddir)/paludis/args/libpaludisargs.la \
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ $(top_builddir)/src/libcolour.a \
+ $(DYNAMIC_LD_LIBS)
+
+adjutrix_SOURCES = \
+ command_line.hh command_line.cc \
+ find_stable_candidates.hh find_stable_candidates.cc \
+ find_dropped_keywords.hh find_dropped_keywords.cc \
+ find_insecure_packages.hh find_insecure_packages.cc \
+ find_reverse_deps.hh find_reverse_deps.cc \
+ keywords_graph.hh keywords_graph.cc \
+ display_profiles_use.hh display_profiles_use.cc \
+ display_default_system_resolution.hh display_default_system_resolution.cc \
+ adjutrix.cc
+
+adjutrix_LDADD = \
+ $(top_builddir)/paludis/repositories/portage/libpaludisportagerepository.la \
+ $(top_builddir)/paludis/tasks/libpaludistasks.a \
+ $(top_builddir)/paludis/libpaludis.la \
+ $(top_builddir)/paludis/args/libpaludisargs.la \
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ $(top_builddir)/paludis/environment/no_config/libpaludisnoconfigenvironment.la \
+ $(top_builddir)/src/libcolour.a \
+ $(DYNAMIC_LD_LIBS)
+
+TESTS_ENVIRONMENT = env \
+ TEST_SCRIPT_DIR="$(srcdir)/" \
+ PALUDIS_NO_GLOBAL_HOOKS="yes" \
+ PALUDIS_NO_XTERM_TITLES="yes" \
+ PALUDIS_EBUILD_DIR="`$(top_srcdir)/ebuild/utils/canonicalise $(top_srcdir)/ebuild/`" \
+ PALUDIS_EBUILD_DIR_FALLBACK="`$(top_srcdir)/ebuild/utils/canonicalise $(top_builddir)/ebuild/`" \
+ PALUDIS_REPOSITORY_SO_DIR="`$(top_srcdir)/ebuild/utils/canonicalise $(top_builddir)/paludis/repositories`" \
+ SYSCONFDIR="$(sysconfdir)" \
+ bash $(top_srcdir)/test/run_test.sh bash
+
+TESTS = version_TEST help_TEST find_stable_candidates_TEST
+
+EXTRA_DIST = \
+ $(man_MANS) \
+ $(TESTS) \
+ find_stable_candidates-sr.hh find_stable_candidates-sr.cc find_stable_candidates.sr \
+ find_dropped_keywords-sr.hh find_dropped_keywords-sr.cc find_dropped_keywords.sr \
+ find_stable_candidates_TEST_setup.sh find_stable_candidates_TEST_cleanup.sh
+
+CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda
+DISTCLEANFILES = $(man_MANS) find_stable_candidates-sr.hh find_stable_candidates-sr.cc
+MAINTAINERCLEANFILES = Makefile.in
+BUILT_SOURCES = \
+ find_stable_candidates-sr.hh find_stable_candidates-sr.cc \
+ find_dropped_keywords-sr.hh find_dropped_keywords-sr.cc
+
+find_stable_candidates-sr.hh : find_stable_candidates.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --header $(srcdir)/find_stable_candidates.sr > $@
+
+find_stable_candidates-sr.cc : find_stable_candidates.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/find_stable_candidates.sr > $@
+
+find_dropped_keywords-sr.hh : find_dropped_keywords.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --header $(srcdir)/find_dropped_keywords.sr > $@
+
+find_dropped_keywords-sr.cc : find_dropped_keywords.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/find_dropped_keywords.sr > $@
+
+
diff --git a/0.8.0/src/adjutrix/adjutrix.cc b/0.8.0/src/adjutrix/adjutrix.cc
new file mode 100644
index 0000000..8737fbd
--- /dev/null
+++ b/0.8.0/src/adjutrix/adjutrix.cc
@@ -0,0 +1,278 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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 "colour.hh"
+#include "command_line.hh"
+#include "find_stable_candidates.hh"
+#include "find_dropped_keywords.hh"
+#include "find_insecure_packages.hh"
+#include "find_reverse_deps.hh"
+#include "keywords_graph.hh"
+#include "display_profiles_use.hh"
+#include "display_default_system_resolution.hh"
+
+#include <paludis/about.hh>
+#include <paludis/util/join.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/environment/no_config/no_config_environment.hh>
+#include <iostream>
+
+using namespace paludis;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace
+{
+ FSEntry
+ get_location_and_add_filters()
+ {
+ Context context("When determining tree location:");
+
+ if (CommandLine::get_instance()->a_repository_directory.specified())
+ return FSEntry(CommandLine::get_instance()->a_repository_directory.argument());
+
+ if ((FSEntry::cwd() / "profiles").is_directory())
+ return FSEntry::cwd();
+ if ((FSEntry::cwd().dirname() / "profiles").is_directory())
+ {
+ CommandLine::get_instance()->a_category.add_argument(FSEntry::cwd().basename());
+ CommandLine::get_instance()->a_category.set_specified(true);
+ return FSEntry::cwd().dirname();
+ }
+ if ((FSEntry::cwd().dirname().dirname() / "profiles").is_directory())
+ {
+ CommandLine::get_instance()->a_package.add_argument(FSEntry::cwd().basename());
+ CommandLine::get_instance()->a_package.set_specified(true);
+ CommandLine::get_instance()->a_category.add_argument(FSEntry::cwd().dirname().basename());
+ CommandLine::get_instance()->a_category.set_specified(true);
+ return FSEntry::cwd().dirname().dirname();
+ }
+
+ throw ConfigurationError("Cannot find tree location (try specifying --repository-dir)");
+ }
+
+ void display_version()
+ {
+ cout << "adjutrix " << PALUDIS_VERSION_MAJOR << "."
+ << PALUDIS_VERSION_MINOR << "." << PALUDIS_VERSION_MICRO;
+ if (! std::string(PALUDIS_SUBVERSION_REVISION).empty())
+ cout << " svn " << PALUDIS_SUBVERSION_REVISION;
+ cout << endl << endl;
+ cout << "Built by " << PALUDIS_BUILD_USER << "@" << PALUDIS_BUILD_HOST
+ << " on " << PALUDIS_BUILD_DATE << endl;
+ cout << "CXX: " << PALUDIS_BUILD_CXX
+#if defined(__ICC)
+ << " " << __ICC
+#elif defined(__VERSION__)
+ << " " << __VERSION__
+#endif
+ << endl;
+ cout << "CXXFLAGS: " << PALUDIS_BUILD_CXXFLAGS << endl;
+ cout << "LDFLAGS: " << PALUDIS_BUILD_LDFLAGS << endl;
+ cout << "DATADIR: " << DATADIR << endl;
+ cout << "LIBDIR: " << LIBDIR << endl;
+ cout << "LIBEXECDIR: " << LIBEXECDIR << endl;
+ cout << "SYSCONFDIR: " << SYSCONFDIR << endl;
+ cout << "stdlib: "
+#if defined(__GLIBCXX__)
+# define XSTRINGIFY(x) #x
+# define STRINGIFY(x) XSTRINGIFY(x)
+ << "GNU libstdc++ " << STRINGIFY(__GLIBCXX__)
+#endif
+ << endl;
+ }
+
+ struct DoVersion
+ {
+ };
+}
+
+int
+main(int argc, char *argv[])
+{
+ Context context("In program " + join(argv, argv + argc, " ") + ":");
+
+ try
+ {
+ CommandLine::get_instance()->run(argc, argv);
+ set_use_colour(! CommandLine::get_instance()->a_no_color.specified());
+
+ if (CommandLine::get_instance()->a_help.specified())
+ throw DoHelp();
+
+ if (CommandLine::get_instance()->a_version.specified())
+ throw DoVersion();
+
+ if (! CommandLine::get_instance()->a_log_level.specified())
+ Log::get_instance()->set_log_level(ll_qa);
+ else if (CommandLine::get_instance()->a_log_level.argument() == "debug")
+ Log::get_instance()->set_log_level(ll_debug);
+ else if (CommandLine::get_instance()->a_log_level.argument() == "qa")
+ Log::get_instance()->set_log_level(ll_qa);
+ else if (CommandLine::get_instance()->a_log_level.argument() == "warning")
+ Log::get_instance()->set_log_level(ll_warning);
+ else if (CommandLine::get_instance()->a_log_level.argument() == "silent")
+ Log::get_instance()->set_log_level(ll_silent);
+ else
+ throw DoHelp("bad value for --log-level");
+
+ if (1 != (
+ CommandLine::get_instance()->a_find_stable_candidates.specified() +
+ CommandLine::get_instance()->a_find_dropped_keywords.specified() +
+ CommandLine::get_instance()->a_find_insecure_packages.specified() +
+ CommandLine::get_instance()->a_keywords_graph.specified() +
+ CommandLine::get_instance()->a_reverse_deps.specified() +
+ CommandLine::get_instance()->a_display_profiles_use.specified() +
+ CommandLine::get_instance()->a_display_default_system_resolution.specified()
+ ))
+ throw DoHelp("you should specify exactly one action");
+
+ NoConfigEnvironment env(NoConfigEnvironmentParams::create()
+ .repository_dir(get_location_and_add_filters())
+ .accept_unstable(CommandLine::get_instance()->a_unstable.specified()));
+
+ if (CommandLine::get_instance()->a_find_stable_candidates.specified())
+ {
+ if (1 != std::distance(CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters()))
+ throw DoHelp("find-stable-candidates action takes exactly one parameter (the target arch)");
+
+ do_find_stable_candidates(env);
+ return EXIT_SUCCESS;
+ }
+
+ if (CommandLine::get_instance()->a_find_dropped_keywords.specified())
+ {
+ if (1 != std::distance(CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters()))
+ throw DoHelp("find-dropped-keywords action takes exactly one parameter (the target arch)");
+
+ do_find_dropped_keywords(env);
+ return EXIT_SUCCESS;
+ }
+
+ if (CommandLine::get_instance()->a_find_insecure_packages.specified())
+ {
+ if (CommandLine::get_instance()->begin_parameters() !=
+ CommandLine::get_instance()->end_parameters())
+ throw DoHelp("find-dropped-keywords action takes no parameters");
+
+ do_find_insecure_packages(env);
+ return EXIT_SUCCESS;
+ }
+
+
+ if (CommandLine::get_instance()->a_keywords_graph.specified())
+ {
+ if (CommandLine::get_instance()->begin_parameters() !=
+ CommandLine::get_instance()->end_parameters())
+ throw DoHelp("keywords-graph action takes no parameters");
+
+ do_keywords_graph(env);
+ return EXIT_SUCCESS;
+ }
+
+ if (CommandLine::get_instance()->a_reverse_deps.specified())
+ {
+ if (1 != std::distance(CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters()))
+ throw DoHelp("reverse-deps action takes exactly one parameter (the target dep)");
+
+ return do_find_reverse_deps(env);
+ }
+
+ if (CommandLine::get_instance()->a_display_profiles_use.specified())
+ {
+ if (CommandLine::get_instance()->begin_parameters() !=
+ CommandLine::get_instance()->end_parameters())
+ throw DoHelp("display-profiles-use action takes no parameters");
+
+ do_display_profiles_use(env);
+ return EXIT_SUCCESS;
+ }
+
+ if (CommandLine::get_instance()->a_display_default_system_resolution.specified())
+ {
+ if (CommandLine::get_instance()->begin_parameters() !=
+ CommandLine::get_instance()->end_parameters())
+ throw DoHelp("display-default-system-resolution action takes no parameters");
+
+ return do_display_default_system_resolution(env);
+ }
+
+ throw InternalError(__PRETTY_FUNCTION__, "no action?");
+ }
+ catch (const DoVersion &)
+ {
+ display_version();
+ cout << endl;
+ cout << "Paludis comes with ABSOLUTELY NO WARRANTY. Paludis is free software, and you" << endl;
+ cout << "are welcome to redistribute it under the terms of the GNU General Public" << endl;
+ cout << "License, version 2." << endl;
+
+ return EXIT_SUCCESS;
+ }
+ catch (const paludis::args::ArgsError & e)
+ {
+ cerr << "Usage error: " << e.message() << endl;
+ cerr << "Try " << argv[0] << " --help" << endl;
+ return EXIT_FAILURE;
+ }
+ catch (const DoHelp & h)
+ {
+ if (h.message.empty())
+ {
+ cout << "Usage: " << argv[0] << " [options]" << endl;
+ cout << endl;
+ cout << *CommandLine::get_instance();
+ return EXIT_SUCCESS;
+ }
+ else
+ {
+ cerr << "Usage error: " << h.message << endl;
+ cerr << "Try " << argv[0] << " --help" << endl;
+ return EXIT_FAILURE;
+ }
+ }
+ catch (const Exception & e)
+ {
+ cout << endl;
+ cerr << "Unhandled exception:" << endl
+ << " * " << e.backtrace("\n * ")
+ << e.message() << " (" << e.what() << ")" << endl;
+ return EXIT_FAILURE;
+ }
+ catch (const std::exception & e)
+ {
+ cout << endl;
+ cerr << "Unhandled exception:" << endl
+ << " * " << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+ catch (...)
+ {
+ cout << endl;
+ cerr << "Unhandled exception:" << endl
+ << " * Unknown exception type. Ouch..." << endl;
+ return EXIT_FAILURE;
+ }
+}
+
diff --git a/0.8.0/src/adjutrix/command_line.cc b/0.8.0/src/adjutrix/command_line.cc
new file mode 100644
index 0000000..c0b5c91
--- /dev/null
+++ b/0.8.0/src/adjutrix/command_line.cc
@@ -0,0 +1,140 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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 "command_line.hh"
+
+CommandLine::CommandLine() :
+ ArgsHandler(),
+
+ tree_action_args(this, "Tree-Oriented Actions",
+ "Selects which basic tree-oriented action to perform. Exactly one action should "
+ "be specified."),
+
+ a_find_stable_candidates(&tree_action_args,
+ "find-stable-candidates", 's', "Search for stable package candidates"),
+ a_find_dropped_keywords(&tree_action_args,
+ "find-dropped-keywords", 'd', "Search for packages where keywords have been dropped"),
+ a_find_insecure_packages(&tree_action_args,
+ "find-insecure-packages", 'i', "Search for packages marked as insecure by a GLSA"),
+ a_keywords_graph(&tree_action_args,
+ "keyword-graph", 'k', "Display keywords graphically"),
+ a_reverse_deps(&tree_action_args,
+ "reverse-deps", 'r', "Find all package that depend on a given dep atom"),
+
+ profile_action_args(this, "Profile-Oriented Actions",
+ "Selects which basic profile-oriented action to perform. Exactly one action should "
+ "be specified."),
+
+ a_display_profiles_use(&profile_action_args,
+ "display-profiles-use", 'u', "Display USE information for all profiles"),
+ a_display_default_system_resolution(&profile_action_args,
+ "display-default-system-resolution", 'S', "Display package names and versions that are included in "
+ "the default resolution of the system set"),
+
+ general_action_args(this, "General Actions",
+ "Selects which basic general action to perform. Exactly one action should "
+ "be specified."),
+
+ a_version(&general_action_args,
+ "version", 'V', "Display program version"),
+ a_help(&general_action_args,
+ "help", 'h', "Display program help"),
+
+ general_args(this, "General options",
+ "Options which are relevant for most or all actions."),
+ a_log_level(&general_args, "log-level", '\0', "Specify the log level",
+ paludis::args::EnumArg::EnumArgOptions("debug", "Show debug output (noisy)")
+ ("qa", "Show QA messages and warnings only")
+ ("warning", "Show warnings only")
+ ("silent", "Suppress all log messages"),
+ "qa"),
+ a_no_colour(&general_args, "no-colour", '\0', "Do not use colour"),
+ a_no_color(&a_no_colour, "no-color"),
+
+ a_repository_directory(&general_args, "repository-dir", 'D',
+ "Where to find the repository (default: detected from ./ or ../ or ../..)"),
+
+ tree_args(this, "Tree action options",
+ "Options which are relevant for tree actions."),
+ a_category(&tree_args, "category", 'C',
+ "Matches with this category name only (may be specified multiple times)"),
+ a_package(&tree_args, "package", 'P',
+ "Matches with this package name only (may be specified multiple times)"),
+
+ profile_args(this, "Profile action options",
+ "Options which are relevant for profile actions."),
+ a_profile(&profile_args, "profile", 'p',
+ "Display results for this profile path, rather than all profiles (may be specified multiple times)"),
+ a_unstable(&profile_args, "unstable", 'U',
+ "Accept ~arch as well as arch")
+{
+ add_usage_line("--find-stable-candidates arch [ --repository-dir /path ] "
+ "[ --category app-misc --category sys-apps ... ] "
+ "[ --package foo --package fnord ... ] ");
+ add_usage_line("--find-dropped-keywords arch [ --repository-dir /path ] "
+ "[ --category app-misc --category sys-apps ... ] "
+ "[ --package foo --package fnord ... ] ");
+ add_usage_line("--find-insecure-packages [ --repository-dir /path ] "
+ "[ --category app-misc --category sys-apps ... ] "
+ "[ --package foo --package fnord ... ] ");
+ add_usage_line("--keywords-graph [ --repository-dir /path ] "
+ "[ --category app-misc --category sys-apps ... ] "
+ "[ --package foo --package fnord ... ]");
+ add_usage_line("--display-profiles-use [ --profile default-linux/x86/2006.0 "
+ "--profile default-linux/x86/2006.1 ... ] [ --repository-dir /path ]");
+
+ add_usage_line("--version");
+ add_usage_line("--help");
+
+ add_enviromnent_variable("PALUDIS_EBUILD_DIR", "Where to look for ebuild.bash and related "
+ "utilities.");
+ add_enviromnent_variable("PALUDIS_REPOSITORY_SO_DIR", "Where to look for repository .so "
+ "files.");
+}
+
+std::string
+CommandLine::app_name() const
+{
+ return "adjutrix";
+}
+
+std::string
+CommandLine::app_synopsis() const
+{
+ return "A tool for arch teams";
+}
+
+std::string
+CommandLine::app_description() const
+{
+ return
+ "adjutrix provides a number of utilities that may be useful for arch teams."
+ "\n\n"
+ "The --repository-dir switch can be used to tell adjutrix where to find "
+ "the repository. If this switch is not used, adjutrix will check the current "
+ "directory, the parent directory and the parent's parent directory for "
+ "something resembling a profile root. If run inside a package or category "
+ "directory, filtering in the style of --package and --category is carried "
+ "out automatically for the current package or category.";
+}
+
+CommandLine::~CommandLine()
+{
+}
+
diff --git a/0.8.0/src/adjutrix/command_line.hh b/0.8.0/src/adjutrix/command_line.hh
new file mode 100644
index 0000000..7414728
--- /dev/null
+++ b/0.8.0/src/adjutrix/command_line.hh
@@ -0,0 +1,126 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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_ARCHTOOL_COMMAND_LINE_HH
+#define PALUDIS_GUARD_SRC_ARCHTOOL_COMMAND_LINE_HH 1
+
+#include <paludis/args/args.hh>
+#include <paludis/util/instantiation_policy.hh>
+
+/** \file
+ * Declarations for the CommandLine class.
+ */
+
+/**
+ * Our command line.
+ */
+class CommandLine :
+ public paludis::args::ArgsHandler,
+ public paludis::InstantiationPolicy<CommandLine, paludis::instantiation_method::SingletonAsNeededTag>
+{
+ friend class paludis::InstantiationPolicy<CommandLine, paludis::instantiation_method::SingletonAsNeededTag>;
+
+ private:
+ /// Constructor.
+ CommandLine();
+
+ /// Destructor.
+ ~CommandLine();
+
+ public:
+ ///\name Program information
+ ///\{
+
+ virtual std::string app_name() const;
+ virtual std::string app_synopsis() const;
+ virtual std::string app_description() const;
+
+ ///\}
+
+ /// \name Action arguments
+ ///{
+
+ /// Action arguments.
+
+ paludis::args::ArgsGroup tree_action_args;
+ paludis::args::SwitchArg a_find_stable_candidates;
+ paludis::args::SwitchArg a_find_dropped_keywords;
+ paludis::args::SwitchArg a_find_insecure_packages;
+ paludis::args::SwitchArg a_keywords_graph;
+ paludis::args::SwitchArg a_reverse_deps;
+
+ paludis::args::ArgsGroup profile_action_args;
+ paludis::args::SwitchArg a_display_profiles_use;
+ paludis::args::SwitchArg a_display_default_system_resolution;
+
+ paludis::args::ArgsGroup general_action_args;
+ paludis::args::SwitchArg a_version;
+ paludis::args::SwitchArg a_help;
+
+ /// \name General arguments
+ ///{
+
+ /// General arguments.
+ paludis::args::ArgsGroup general_args;
+
+ paludis::args::EnumArg a_log_level;
+ paludis::args::SwitchArg a_no_colour;
+ paludis::args::AliasArg a_no_color;
+
+ paludis::args::StringArg a_repository_directory;
+
+ ///}
+
+
+ ///\name Tree arguments
+ ///\{
+
+ paludis::args::ArgsGroup tree_args;
+
+ paludis::args::StringSetArg a_category;
+ paludis::args::StringSetArg a_package;
+
+ ///\}
+
+ ///\name Profile arguments
+ ///\{
+
+ paludis::args::ArgsGroup profile_args;
+
+ paludis::args::StringSetArg a_profile;
+ paludis::args::SwitchArg a_unstable;
+
+ ///\}
+
+};
+
+/**
+ * Show the help message.
+ */
+struct DoHelp
+{
+ const std::string message;
+
+ DoHelp(const std::string & m = "") :
+ message(m)
+ {
+ }
+};
+
+#endif
diff --git a/0.8.0/src/adjutrix/display_default_system_resolution.cc b/0.8.0/src/adjutrix/display_default_system_resolution.cc
new file mode 100644
index 0000000..7ccbf45
--- /dev/null
+++ b/0.8.0/src/adjutrix/display_default_system_resolution.cc
@@ -0,0 +1,135 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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 "display_default_system_resolution.hh"
+#include "command_line.hh"
+#include "colour.hh"
+#include <paludis/config_file.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/is_file_with_extension.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/dep_list.hh>
+
+#include <iostream>
+#include <iomanip>
+#include <vector>
+#include <cstdlib>
+#include <set>
+#include <map>
+
+using namespace paludis;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+using namespace paludis;
+
+namespace
+{
+ int
+ display_default_system_resolution(const NoConfigEnvironment & env, const std::string & desc,
+ const FSEntry & profile)
+ {
+ int return_code(0);
+
+ Context context("When displaying system resolution for '" + stringify(desc) + "' at '"
+ + stringify(profile) + "':");
+
+ std::string display_profile(stringify(profile)), display_profile_chop(
+ stringify(env.main_repository_dir() / "profiles"));
+ if (0 == display_profile.compare(0, display_profile_chop.length(), display_profile_chop))
+ {
+ display_profile.erase(0, display_profile_chop.length());
+ if (0 == display_profile.compare(0, 1, "/"))
+ display_profile.erase(0, 1);
+ if (display_profile.empty())
+ display_profile = "/";
+ }
+
+ cout << std::left << std::setw(20) << (desc + ":") << display_profile << endl;
+
+ DepListOptions d_options;
+ d_options.circular = dl_circular_discard;
+ DepList d(&env, d_options);
+
+ try
+ {
+ d.add(env.package_set("system"));
+
+ for (DepList::Iterator e(d.begin()), e_end(d.end()) ; e != e_end ; ++e)
+ cout << " " << e->package << ":" << e->metadata->slot << endl;
+ }
+ catch (const NoSuchPackageError & e)
+ {
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ");
+ cerr << "No such package '" << e.name() << "'" << endl;
+
+ return_code |= 1;
+ }
+ catch (const DepListError & e)
+ {
+ cout << endl;
+ cerr << "Dependency error:" << endl;
+ cerr << " * " << e.backtrace("\n * ") << e.message() << " ("
+ << e.what() << ")" << endl;
+ cerr << endl;
+
+ return_code |= 1;
+ }
+
+ cout << endl;
+
+ return return_code;
+ }
+}
+
+int do_display_default_system_resolution(NoConfigEnvironment & env)
+{
+ int return_code(0);
+
+ Context context("When performing display-default-system-resolution action:");
+
+ if (CommandLine::get_instance()->a_profile.args_begin() ==
+ CommandLine::get_instance()->a_profile.args_end())
+ {
+ for (NoConfigEnvironment::ProfilesIterator p(env.begin_profiles()), p_end(env.end_profiles()) ;
+ p != p_end ; ++p)
+ {
+ env.set_profile(p->path);
+ return_code |= display_default_system_resolution(env, p->arch + "." + p->status, p->path);
+ }
+ }
+ else
+ {
+ for (args::StringSetArg::Iterator i(CommandLine::get_instance()->a_profile.args_begin()),
+ i_end(CommandLine::get_instance()->a_profile.args_end()) ; i != i_end ; ++i)
+ {
+ env.set_profile(env.main_repository_dir() / "profiles" / (*i));
+ return_code |= display_default_system_resolution(env, *i, env.main_repository_dir() / "profiles" / *i);
+ }
+ }
+
+ return return_code;
+}
+
+
diff --git a/0.8.0/src/adjutrix/display_default_system_resolution.hh b/0.8.0/src/adjutrix/display_default_system_resolution.hh
new file mode 100644
index 0000000..6d6c340
--- /dev/null
+++ b/0.8.0/src/adjutrix/display_default_system_resolution.hh
@@ -0,0 +1,27 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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_ADJUTRIX_DISPLAY_DEFAULT_SYSTEM_RESOLUTION_HH
+#define PALUDIS_GUARD_SRC_ADJUTRIX_DISPLAY_DEFAULT_SYSTEM_RESOLUTION_HH 1
+
+#include <paludis/environment/no_config/no_config_environment.hh>
+
+int do_display_default_system_resolution(paludis::NoConfigEnvironment & env);
+
+#endif
diff --git a/0.8.0/src/adjutrix/display_profiles_use.cc b/0.8.0/src/adjutrix/display_profiles_use.cc
new file mode 100644
index 0000000..cce7eac
--- /dev/null
+++ b/0.8.0/src/adjutrix/display_profiles_use.cc
@@ -0,0 +1,176 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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 "display_profiles_use.hh"
+#include "command_line.hh"
+#include "colour.hh"
+#include <paludis/config_file.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/is_file_with_extension.hh>
+#include <paludis/util/strip.hh>
+
+#include <iostream>
+#include <iomanip>
+#include <vector>
+#include <cstdlib>
+#include <set>
+#include <map>
+
+using namespace paludis;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+using namespace paludis;
+
+namespace
+{
+ std::string
+ upperify(const std::string & s)
+ {
+ std::string result;
+ std::transform(s.begin(), s.end(), std::back_inserter(result), &::toupper);
+ return result;
+ }
+
+ void
+ display_profiles_use(const NoConfigEnvironment & env, const std::string & desc,
+ const FSEntry & profile, const std::set<UseFlagName> & all_use,
+ const std::multimap<std::string, UseFlagName> & all_use_expand_flags)
+ {
+ Context context("When displaying profile use for '" + stringify(desc) + "' at '"
+ + stringify(profile) + "':");
+
+ std::string display_profile(stringify(profile)), display_profile_chop(
+ stringify(env.main_repository_dir() / "profiles"));
+ if (0 == display_profile.compare(0, display_profile_chop.length(), display_profile_chop))
+ {
+ display_profile.erase(0, display_profile_chop.length());
+ if (0 == display_profile.compare(0, 1, "/"))
+ display_profile.erase(0, 1);
+ if (display_profile.empty())
+ display_profile = "/";
+ }
+
+ cout << std::left << std::setw(20) << (desc + ":") << display_profile << endl;
+
+ cout << std::setw(20) << "USE:";
+
+ PackageDatabaseEntry e(QualifiedPackageName("dummy-category/dummy-package"), VersionSpec("0"),
+ env.package_database()->favourite_repository());
+ for (std::set<UseFlagName>::const_iterator u(all_use.begin()), u_end(all_use.end()) ;
+ u != u_end ; ++u)
+ if (env.query_use(*u, &e))
+ cout << *u << " ";
+
+ std::string current_prefix("not on a boat");
+ for (std::multimap<std::string, UseFlagName>::const_iterator u(all_use_expand_flags.begin()),
+ u_end(all_use_expand_flags.end()) ; u != u_end ; ++u)
+ {
+ if (u->first != current_prefix)
+ cout << endl << std::setw(20) << (upperify(stringify(u->first)) + ":");
+ current_prefix = u->first;
+
+ if (env.query_use(UseFlagName(current_prefix + "_" + stringify(u->second)), &e))
+ cout << u->second << " ";
+ }
+
+ cout << endl << endl;
+ }
+}
+
+void do_display_profiles_use(NoConfigEnvironment & env)
+{
+ Context context("When performing display-profiles-use action:");
+
+ std::set<UseFlagName> all_use_flags;
+ {
+ LineConfigFile use_desc(env.main_repository_dir() / "profiles"/ "use.desc");
+ for (LineConfigFile::Iterator line(use_desc.begin()), line_end(use_desc.end()) ;
+ line != line_end ; ++line)
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens));
+
+ if (tokens.size() < 2)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Skipping invalid line '"
+ + *line + "'");
+ continue;
+ }
+
+ all_use_flags.insert(UseFlagName(tokens.at(0)));
+ }
+ }
+
+ std::multimap<std::string, UseFlagName> all_use_expand_flags;
+ {
+ for (DirIterator d(env.main_repository_dir() / "profiles" / "desc"), d_end ;
+ d != d_end ; ++d)
+ {
+ if (! IsFileWithExtension(".desc")(*d))
+ continue;
+
+ std::string prefix(strip_trailing_string(d->basename(), ".desc"));
+
+ LineConfigFile use_desc(*d);
+ for (LineConfigFile::Iterator line(use_desc.begin()), line_end(use_desc.end()) ;
+ line != line_end ; ++line)
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens));
+
+ if (tokens.size() < 2)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Skipping invalid line '"
+ + *line + "'");
+ continue;
+ }
+
+ all_use_expand_flags.insert(std::make_pair(prefix, UseFlagName(tokens.at(0))));
+ }
+ }
+ }
+
+ if (CommandLine::get_instance()->a_profile.args_begin() ==
+ CommandLine::get_instance()->a_profile.args_end())
+ {
+ for (NoConfigEnvironment::ProfilesIterator p(env.begin_profiles()), p_end(env.end_profiles()) ;
+ p != p_end ; ++p)
+ {
+ env.set_profile(p);
+ display_profiles_use(env, p->arch + "." + p->status, p->path,
+ all_use_flags, all_use_expand_flags);
+ }
+ }
+ else
+ {
+ for (args::StringSetArg::Iterator i(CommandLine::get_instance()->a_profile.args_begin()),
+ i_end(CommandLine::get_instance()->a_profile.args_end()) ; i != i_end ; ++i)
+ {
+ env.set_profile(env.main_repository_dir() / "profiles" / (*i));
+ display_profiles_use(env, *i, env.main_repository_dir() /
+ "profiles" / *i, all_use_flags, all_use_expand_flags);
+ }
+ }
+}
+
+
diff --git a/0.8.0/src/adjutrix/display_profiles_use.hh b/0.8.0/src/adjutrix/display_profiles_use.hh
new file mode 100644
index 0000000..8a5b4e0
--- /dev/null
+++ b/0.8.0/src/adjutrix/display_profiles_use.hh
@@ -0,0 +1,27 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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_ADJUTRIX_DISPLAY_PROFILES_USE_HH
+#define PALUDIS_GUARD_SRC_ADJUTRIX_DISPLAY_PROFILES_USE_HH 1
+
+#include <paludis/environment/no_config/no_config_environment.hh>
+
+void do_display_profiles_use(paludis::NoConfigEnvironment & env);
+
+#endif
diff --git a/0.8.0/src/adjutrix/find_dropped_keywords.cc b/0.8.0/src/adjutrix/find_dropped_keywords.cc
new file mode 100644
index 0000000..e8e2643
--- /dev/null
+++ b/0.8.0/src/adjutrix/find_dropped_keywords.cc
@@ -0,0 +1,208 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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 "find_dropped_keywords.hh"
+#include "command_line.hh"
+
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/compare.hh>
+
+#include <set>
+#include <map>
+#include <iostream>
+#include <iomanip>
+#include <algorithm>
+
+using namespace paludis;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace
+{
+
+#include "find_dropped_keywords-sr.hh"
+#include "find_dropped_keywords-sr.cc"
+
+ static const int col_width_package = 30;
+ static const int col_width_best_keyworded = 20;
+ static const int col_width_best_anywhere = 20;
+
+ void
+ write_repository_header(const KeywordName & keyword, const RepositoryName & repo)
+ {
+ std::string s("Dropped keywords for '" + stringify(repo) + "' on '"
+ + stringify(keyword) + "'");
+ cout << std::string(s.length(), '=') << endl;
+ cout << s << endl;
+ cout << std::string(s.length(), '=') << endl;
+ cout << endl;
+
+ cout << std::left
+ << std::setw(col_width_package) << "category/package (:slot)"
+ << std::setw(col_width_best_keyworded) << "best keyworded"
+ << std::setw(col_width_best_anywhere) << "best anywhere"
+ << endl;
+
+ cout
+ << std::string(col_width_package - 1, '-') << " "
+ << std::string(col_width_best_keyworded - 1, '-') << " "
+ << std::string(col_width_best_anywhere - 1, '-') << " "
+ << endl;
+ }
+
+ struct IsStableOrUnstableKeyword
+ {
+ bool operator() (const KeywordName & k) const
+ {
+ return stringify(k).at(0) != '-';
+ }
+ };
+
+ void
+ write_package(const QualifiedPackageName & package, const SlotName & slot,
+ const VersionSpec & best_keyworded, const VersionSpec & best_anywhere)
+ {
+ static CategoryNamePart previous_category("not-on-a-boat");
+ if (package.category != previous_category)
+ {
+ cout << std::setw(col_width_package) << (stringify(package.category) + "/") << endl;
+ previous_category = package.category;
+ }
+
+ std::string p(stringify(package.package));
+ if (SlotName("0") != slot)
+ p += ":" + stringify(slot);
+ cout << " " << std::setw(col_width_package - 2) << p;
+
+ if (best_keyworded != VersionSpec("0"))
+ cout << std::setw(col_width_best_keyworded) << best_keyworded;
+ else
+ cout << std::setw(col_width_best_keyworded) << " ";
+ cout << std::setw(col_width_best_anywhere) << best_anywhere;
+ cout << endl;
+ }
+
+ void
+ check_one_package(const Environment &, const KeywordName & keyword,
+ const Repository & repo, const QualifiedPackageName & package)
+ {
+ /* determine whether we have any interesting versions, and pick out
+ * slots where we do. for slots, we map slot to a pair (best stable
+ * version for us, best stable version for anyone). */
+
+ bool is_interesting(false);
+ VersionSpec worst_keyworded("99999999");
+ typedef std::map<SlotName, VersionsEntry> VersionsInSlots;
+ VersionsInSlots versions_in_slots;
+
+ VersionSpecCollection::ConstPointer versions(repo.version_specs(package));
+ for (VersionSpecCollection::Iterator v(versions->begin()), v_end(versions->end()) ;
+ v != v_end ; ++v)
+ {
+ VersionMetadata::ConstPointer metadata(repo.version_metadata(package, *v));
+ if (! metadata->get_ebuild_interface())
+ continue;
+
+ std::set<KeywordName> keywords;
+ WhitespaceTokeniser::get_instance()->tokenise(metadata->get_ebuild_interface()->keywords,
+ create_inserter<KeywordName>(std::inserter(keywords, keywords.end())));
+
+ /* ensure that there's an entry for this SLOT */
+ versions_in_slots.insert(std::make_pair(metadata->slot, VersionsEntry(
+ VersionsEntry::create()
+ .best_keyworded(VersionSpec("0"))
+ .best_anywhere(VersionSpec("0")))));
+
+ if (keywords.end() != keywords.find(keyword) ||
+ keywords.end() != keywords.find(KeywordName("~" + stringify(keyword))))
+ {
+ is_interesting = true;
+ versions_in_slots.find(metadata->slot)->second.best_keyworded =
+ std::max(versions_in_slots.find(metadata->slot)->second.best_keyworded, *v);
+ worst_keyworded = std::min(worst_keyworded, *v);
+ }
+
+ if (keywords.end() != std::find_if(keywords.begin(), keywords.end(), IsStableOrUnstableKeyword()))
+ versions_in_slots.find(metadata->slot)->second.best_anywhere =
+ std::max(versions_in_slots.find(metadata->slot)->second.best_anywhere, *v);
+ }
+
+ if (! is_interesting)
+ return;
+
+ /* for each slot, if there's a higher version on another arch, flag it */
+ for (VersionsInSlots::const_iterator s(versions_in_slots.begin()),
+ s_end(versions_in_slots.end()) ; s != s_end ; ++s)
+ {
+ if (s->second.best_keyworded >= s->second.best_anywhere)
+ continue;
+
+ if (s->second.best_anywhere < worst_keyworded)
+ continue;
+
+ write_package(package, s->first, s->second.best_keyworded, s->second.best_anywhere);
+ }
+ }
+}
+
+void do_find_dropped_keywords(const Environment & env)
+{
+ Context context("When performing find-dropped-keywords action:");
+
+ KeywordName keyword(*CommandLine::get_instance()->begin_parameters());
+
+ for (IndirectIterator<PackageDatabase::RepositoryIterator, const Repository>
+ r(env.package_database()->begin_repositories()),
+ r_end(env.package_database()->end_repositories()) ; r != r_end ; ++r)
+ {
+ if (r->name() == RepositoryName("virtuals"))
+ continue;
+
+ write_repository_header(keyword, r->name());
+
+ CategoryNamePartCollection::ConstPointer cat_names(r->category_names());
+ for (CategoryNamePartCollection::Iterator c(cat_names->begin()), c_end(cat_names->end()) ;
+ c != c_end ; ++c)
+ {
+ if (CommandLine::get_instance()->a_category.specified())
+ if (CommandLine::get_instance()->a_category.args_end() == std::find(
+ CommandLine::get_instance()->a_category.args_begin(),
+ CommandLine::get_instance()->a_category.args_end(),
+ stringify(*c)))
+ continue;
+
+ QualifiedPackageNameCollection::ConstPointer pkg_names(r->package_names(*c));
+ for (QualifiedPackageNameCollection::Iterator p(pkg_names->begin()), p_end(pkg_names->end()) ;
+ p != p_end ; ++p)
+ {
+ if (CommandLine::get_instance()->a_package.specified())
+ if (CommandLine::get_instance()->a_package.args_end() == std::find(
+ CommandLine::get_instance()->a_package.args_begin(),
+ CommandLine::get_instance()->a_package.args_end(),
+ stringify(p->package)))
+ continue;
+
+ check_one_package(env, keyword, *r, *p);
+ }
+ }
+ }
+}
+
+
diff --git a/0.8.0/src/adjutrix/find_dropped_keywords.hh b/0.8.0/src/adjutrix/find_dropped_keywords.hh
new file mode 100644
index 0000000..e6bbe22
--- /dev/null
+++ b/0.8.0/src/adjutrix/find_dropped_keywords.hh
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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_ARCHTOOL_FIND_DROPPED_KEYWORDS_HH
+#define PALUDIS_GUARD_SRC_ARCHTOOL_FIND_DROPPED_KEYWORDS_HH 1
+
+#include <paludis/environment.hh>
+
+void do_find_dropped_keywords(const paludis::Environment & env);
+
+#endif
+
diff --git a/0.8.0/src/adjutrix/find_dropped_keywords.sr b/0.8.0/src/adjutrix/find_dropped_keywords.sr
new file mode 100644
index 0000000..b197b2a
--- /dev/null
+++ b/0.8.0/src/adjutrix/find_dropped_keywords.sr
@@ -0,0 +1,13 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+make_class_VersionsEntry()
+{
+ key best_keyworded VersionSpec
+ key best_anywhere VersionSpec
+
+ allow_named_args
+}
+
+
+
diff --git a/0.8.0/src/adjutrix/find_insecure_packages.cc b/0.8.0/src/adjutrix/find_insecure_packages.cc
new file mode 100644
index 0000000..1409c69
--- /dev/null
+++ b/0.8.0/src/adjutrix/find_insecure_packages.cc
@@ -0,0 +1,162 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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 "find_insecure_packages.hh"
+#include "command_line.hh"
+
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/compare.hh>
+
+#include <set>
+#include <map>
+#include <iostream>
+#include <iomanip>
+#include <algorithm>
+
+using namespace paludis;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace
+{
+ const unsigned col_width_package = 30;
+ const unsigned col_width_id = 40;
+
+ void
+ write_repository_header(const RepositoryName & repo)
+ {
+ std::string s("Insecure packages from advisories in repository '" + stringify(repo) + "'");
+ cout << std::string(s.length(), '=') << endl;
+ cout << s << endl;
+ cout << std::string(s.length(), '=') << endl;
+ cout << endl;
+
+ cout << std::left
+ << std::setw(col_width_package) << "package"
+ << std::setw(col_width_id) << "GLSA IDs"
+ << endl;
+
+ cout
+ << std::string(col_width_package - 1, '-') << " "
+ << std::string(col_width_id - 1, '-') << " "
+ << endl;
+ }
+
+ class ListInsecureVisitor :
+ public DepAtomVisitorTypes::ConstVisitor
+ {
+ private:
+ const Environment & _env;
+ std::multimap<PackageDatabaseEntry, std::string> _found;
+
+ public:
+ ListInsecureVisitor(const Environment & e) :
+ _env(e)
+ {
+ }
+
+ void visit(const AllDepAtom * const a)
+ {
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+
+ void visit(const AnyDepAtom * const a)
+ {
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+
+ void visit(const UseDepAtom * const a)
+ {
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+
+ void visit(const PackageDepAtom * const a)
+ {
+ PackageDatabaseEntryCollection::ConstPointer insecure(
+ _env.package_database()->query(*a, is_either));
+ for (PackageDatabaseEntryCollection::Iterator i(insecure->begin()),
+ i_end(insecure->end()) ; i != i_end ; ++i)
+ if (a->tag())
+ _found.insert(std::make_pair(*i, a->tag()->short_text()));
+ else
+ throw InternalError(PALUDIS_HERE, "didn't get a tag");
+ }
+
+ void visit(const PlainTextDepAtom * const)
+ {
+ }
+
+ void visit(const BlockDepAtom * const)
+ {
+ }
+
+ friend std::ostream & operator<< (std::ostream &, const ListInsecureVisitor &);
+ };
+
+ std::ostream & operator<< (std::ostream & s, const ListInsecureVisitor & v)
+ {
+ QualifiedPackageName old_name("dormouse/teapot");
+ for (std::multimap<PackageDatabaseEntry, std::string>::const_iterator
+ f(v._found.begin()), f_end(v._found.end()) ; f != f_end ; ++f)
+ {
+ if (f->first.name != old_name)
+ s << std::setw(col_width_package) << (stringify(f->first.name) + " ") << endl;
+ old_name = f->first.name;
+ s << std::setw(col_width_package) << (" " + stringify(f->first.version) + " ")
+ << f->second;
+ while (next(f) != f_end)
+ {
+ if (next(f)->first != f->first)
+ break;
+ cout << " " << f->second;
+ ++f;
+ }
+ cout << endl;
+ }
+
+ return s;
+ }
+}
+
+void do_find_insecure_packages(const Environment & env)
+{
+ Context context("When performing find-insecure-packages action:");
+
+ for (IndirectIterator<PackageDatabase::RepositoryIterator, const Repository>
+ r(env.package_database()->begin_repositories()),
+ r_end(env.package_database()->end_repositories()) ; r != r_end ; ++r)
+ {
+ if (r->name() == RepositoryName("virtuals"))
+ continue;
+
+ if (! r->sets_interface)
+ continue;
+
+ write_repository_header(r->name());
+
+ DepAtom::ConstPointer all_insecure(r->sets_interface->package_set("insecurity"));
+ if (! all_insecure)
+ continue;
+ ListInsecureVisitor v(env);
+ all_insecure->accept(&v);
+ cout << v << endl;
+ }
+}
+
diff --git a/0.8.0/src/adjutrix/find_insecure_packages.hh b/0.8.0/src/adjutrix/find_insecure_packages.hh
new file mode 100644
index 0000000..a8c1cc0
--- /dev/null
+++ b/0.8.0/src/adjutrix/find_insecure_packages.hh
@@ -0,0 +1,27 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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_ADJUTRIX_FIND_INSECURE_PACKAGES_HH
+#define PALUDIS_GUARD_SRC_ADJUTRIX_FIND_INSECURE_PACKAGES_HH 1
+
+#include <paludis/environment.hh>
+
+void do_find_insecure_packages(const paludis::Environment & env);
+
+#endif
diff --git a/0.8.0/src/adjutrix/find_reverse_deps.cc b/0.8.0/src/adjutrix/find_reverse_deps.cc
new file mode 100644
index 0000000..e61a096
--- /dev/null
+++ b/0.8.0/src/adjutrix/find_reverse_deps.cc
@@ -0,0 +1,291 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Danny van Dyk <kugelfang@gentoo.org>
+ *
+ * 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 "find_reverse_deps.hh"
+#include "command_line.hh"
+#include "colour.hh"
+
+#include <paludis/util/compare.hh>
+#include <paludis/util/collection_concrete.hh>
+#include <paludis/util/save.hh>
+
+#include <set>
+#include <map>
+#include <iostream>
+#include <iomanip>
+#include <algorithm>
+
+using namespace paludis;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace
+{
+ class ReverseDepChecker :
+ public DepAtomVisitorTypes::ConstVisitor
+ {
+ private:
+ PackageDatabase::ConstPointer _db;
+ PackageDatabaseEntryCollection::ConstPointer _entries;
+ std::string _depname;
+ std::string _p;
+
+ bool _in_any;
+ bool _in_use;
+ std::string _flags;
+
+ bool _found_matches;
+
+ public:
+ ReverseDepChecker(PackageDatabase::ConstPointer db, PackageDatabaseEntryCollection::ConstPointer entries,
+ const std::string & p) :
+ _db(db),
+ _entries(entries),
+ _depname(""),
+ _p(p),
+ _in_any(false),
+ _in_use(false),
+ _found_matches(false)
+ {
+ }
+
+ void check(DepAtom::ConstPointer atom, const std::string & depname)
+ {
+ _depname = depname;
+ atom->accept(this);
+ }
+
+ bool found_matches()
+ {
+ return _found_matches;
+ }
+
+ void visit(const AllDepAtom * const);
+
+ void visit(const AnyDepAtom * const);
+
+ void visit(const UseDepAtom * const);
+
+ void visit(const PackageDepAtom * const);
+
+ void visit(const PlainTextDepAtom * const);
+
+ void visit(const BlockDepAtom * const);
+ };
+
+ void
+ ReverseDepChecker::visit(const AllDepAtom * const a)
+ {
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+
+ void
+ ReverseDepChecker::visit(const AnyDepAtom * const a)
+ {
+ Save<bool> in_any_save(&_in_any, true);
+
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+
+ void
+ ReverseDepChecker::visit(const UseDepAtom * const a)
+ {
+ Save<bool> in_use_save(&_in_use, true);
+ Save<std::string> flag_save(&_flags);
+
+ if (! _flags.empty())
+ _flags += " ";
+ _flags += (a->inverse() ? "!" : "") + stringify(a->flag());
+
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+
+ void
+ ReverseDepChecker::visit(const PackageDepAtom * const a)
+ {
+ PackageDatabaseEntryCollection::ConstPointer dep_entries(
+ _db->query(*a, is_uninstalled_only));
+ PackageDatabaseEntryCollection::Pointer matches(new PackageDatabaseEntryCollection::Concrete);
+
+ bool header_written = false;
+
+ for (PackageDatabaseEntryCollection::Iterator e(dep_entries->begin()), e_end(dep_entries->end()) ;
+ e != e_end ; ++e)
+ {
+ if (_entries->find(*e) != _entries->end())
+ {
+ _found_matches |= true;
+
+ if (! header_written)
+ {
+ std::cout << " " << _p << " " + _depname + " on one of:" << std::endl;
+ header_written = true;
+ }
+ std::cout << " " << stringify(*e);
+
+ if (_in_use || _in_any)
+ {
+ std::cout << " (";
+
+ if (_in_any)
+ std::cout << "any-of";
+
+ if (_in_use && _in_any)
+ std::cout << ", ";
+
+ if (_in_use)
+ std::cout << "condition USE='" << _flags << "'";
+
+ std::cout << ")";
+ }
+ std::cout << std::endl;
+ }
+ }
+ }
+
+ void
+ ReverseDepChecker::visit(const PlainTextDepAtom * const)
+ {
+ }
+
+ void
+ ReverseDepChecker::visit(const BlockDepAtom * const)
+ {
+ }
+
+ void write_repository_header(std::string atom, const std::string &)
+ {
+ cout << "Reverse dependencies for '" << atom << "':" << std::endl;
+ }
+
+ int check_one_package(const Environment & env, const Repository & r,
+ const PackageDatabaseEntryCollection & entries, const QualifiedPackageName & p)
+ {
+ Context context("When checking package '" + stringify(p) + "':");
+
+ PackageDatabaseEntryCollection::Pointer p_entries(env.package_database()->query(
+ PackageDepAtom::Pointer(new PackageDepAtom(stringify(p))), is_uninstalled_only));
+
+ bool found_matches(false);
+
+ for (PackageDatabaseEntryCollection::Iterator e(p_entries->begin()), e_end(p_entries->end()) ;
+ e != e_end ; ++e)
+ {
+ try
+ {
+ VersionMetadata::ConstPointer metadata(r.version_metadata(e->name, e->version));
+ ReverseDepChecker checker(env.package_database(), PackageDatabaseEntryCollection::ConstPointer(&entries),
+ stringify(p) + "-" + stringify(e->version));
+
+ checker.check(metadata->deps.parser(metadata->deps.build_depend_string), std::string("DEPEND"));
+ checker.check(metadata->deps.parser(metadata->deps.run_depend_string), std::string("RDEPEND"));
+ checker.check(metadata->deps.parser(metadata->deps.post_depend_string), std::string("PDEPEND"));
+
+ found_matches |= checker.found_matches();
+ }
+ catch (Exception & exception)
+ {
+ cerr << "Caught exception:" << endl;
+ cerr << " * " << exception.backtrace("\n * ") << endl;
+ cerr << " * " << exception.message() << " (" << exception.what() << ")" << endl;
+ return (found_matches ? 0 : 1) | 2;
+ }
+ }
+
+ return found_matches ? 0 : 1;
+ }
+}
+
+int do_find_reverse_deps(NoConfigEnvironment & env)
+{
+ Context context("When performing find-reverse-deps action:");
+
+ PackageDepAtom::Pointer atom(0);
+ try
+ {
+ if (std::string::npos == CommandLine::get_instance()->begin_parameters()->find('/'))
+ {
+ atom.assign(new PackageDepAtom(env.package_database()->fetch_unique_qualified_package_name(
+ PackageNamePart(*CommandLine::get_instance()->begin_parameters()))));
+ }
+ else
+ atom.assign(new PackageDepAtom(*CommandLine::get_instance()->begin_parameters()));
+ }
+ catch (const AmbiguousPackageNameError & e)
+ {
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ");
+ cerr << "Ambiguous package name '" << e.name() << "'. Did you mean:" << endl;
+ for (AmbiguousPackageNameError::OptionsIterator o(e.begin_options()),
+ o_end(e.end_options()) ; o != o_end ; ++o)
+ cerr << " * " << colour(cl_package_name, *o) << endl;
+ cerr << endl;
+ return 4;
+ }
+
+ PackageDatabaseEntryCollection::Pointer entries(env.package_database()->query(atom, is_either));
+ int ret(0);
+
+ if (entries->empty())
+ return 1;
+
+ for (IndirectIterator<PackageDatabase::RepositoryIterator, const Repository>
+ r(env.package_database()->begin_repositories()),
+ r_end(env.package_database()->end_repositories()) ; r != r_end ; ++r)
+ {
+ if (r->name() == RepositoryName("virtuals"))
+ continue;
+
+ write_repository_header(stringify(*atom), stringify(r->name()));
+
+ CategoryNamePartCollection::ConstPointer cat_names(r->category_names());
+ for (CategoryNamePartCollection::Iterator c(cat_names->begin()), c_end(cat_names->end()) ;
+ c != c_end ; ++c)
+ {
+ cerr << xterm_title("Checking " + stringify(*c) + " - adjutrix");
+
+ if (CommandLine::get_instance()->a_category.specified())
+ if (CommandLine::get_instance()->a_category.args_end() == std::find(
+ CommandLine::get_instance()->a_category.args_begin(),
+ CommandLine::get_instance()->a_category.args_end(),
+ stringify(*c)))
+ continue;
+
+ QualifiedPackageNameCollection::ConstPointer pkg_names(r->package_names(*c));
+ for (QualifiedPackageNameCollection::Iterator p(pkg_names->begin()), p_end(pkg_names->end()) ;
+ p != p_end ; ++p)
+ {
+ if (CommandLine::get_instance()->a_package.specified())
+ if (CommandLine::get_instance()->a_package.args_end() == std::find(
+ CommandLine::get_instance()->a_package.args_begin(),
+ CommandLine::get_instance()->a_package.args_end(),
+ stringify(p->package)))
+ continue;
+
+ ret |= check_one_package(env, *r, *entries, *p);
+ }
+ }
+ }
+
+ return ret;
+}
+
+
diff --git a/0.8.0/src/adjutrix/find_reverse_deps.hh b/0.8.0/src/adjutrix/find_reverse_deps.hh
new file mode 100644
index 0000000..048b1f5
--- /dev/null
+++ b/0.8.0/src/adjutrix/find_reverse_deps.hh
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Danny van Dyk <kugelfang@gentoo.org>
+ *
+ * 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_ARCHTOOL_FIND_REVERSE_DEPS_HH
+#define PALUDIS_GUARD_SRC_ARCHTOOL_FIND_REVERSE_DEPS_HH 1
+
+#include <paludis/environment/no_config/no_config_environment.hh>
+
+int do_find_reverse_deps(paludis::NoConfigEnvironment & env);
+
+#endif
+
diff --git a/0.8.0/src/adjutrix/find_stable_candidates.cc b/0.8.0/src/adjutrix/find_stable_candidates.cc
new file mode 100644
index 0000000..9d26c7d
--- /dev/null
+++ b/0.8.0/src/adjutrix/find_stable_candidates.cc
@@ -0,0 +1,210 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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 "find_stable_candidates.hh"
+#include "command_line.hh"
+
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/compare.hh>
+
+#include <set>
+#include <map>
+#include <iostream>
+#include <iomanip>
+#include <algorithm>
+
+using namespace paludis;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace
+{
+
+#include "find_stable_candidates-sr.hh"
+#include "find_stable_candidates-sr.cc"
+
+ static const int col_width_package = 30;
+ static const int col_width_our_version = 20;
+ static const int col_width_best_version = 20;
+
+ void
+ write_repository_header(const KeywordName & keyword, const RepositoryName & repo)
+ {
+ std::string s("Stable candidates for '" + stringify(repo) + "' on '"
+ + stringify(keyword) + "'");
+ cout << std::string(s.length(), '=') << endl;
+ cout << s << endl;
+ cout << std::string(s.length(), '=') << endl;
+ cout << endl;
+
+ cout << std::left
+ << std::setw(col_width_package) << "category/package (:slot)"
+ << std::setw(col_width_our_version) << "our version"
+ << std::setw(col_width_best_version) << "best version"
+ << endl;
+
+ cout
+ << std::string(col_width_package - 1, '-') << " "
+ << std::string(col_width_our_version - 1, '-') << " "
+ << std::string(col_width_best_version - 1, '-') << " "
+ << endl;
+ }
+
+ struct IsStableKeyword
+ {
+ bool operator() (const KeywordName & k) const
+ {
+ return std::string::npos == std::string("-~").find(k.data().at(0));
+ }
+ };
+
+ void
+ write_package(const QualifiedPackageName & package, const SlotName & slot,
+ const VersionSpec & our_version, const VersionSpec & best_version)
+ {
+ static CategoryNamePart previous_category("not-on-a-boat");
+ if (package.category != previous_category)
+ {
+ cout << std::setw(col_width_package) << (stringify(package.category) + "/") << endl;
+ previous_category = package.category;
+ }
+
+ std::string p(stringify(package.package));
+ if (SlotName("0") != slot)
+ p += ":" + stringify(slot);
+ cout << " " << std::setw(col_width_package - 2) << p;
+
+ if (our_version != VersionSpec("0"))
+ cout << std::setw(col_width_our_version) << our_version;
+ else
+ cout << std::setw(col_width_our_version) << " ";
+ cout << std::setw(col_width_best_version) << best_version;
+ cout << endl;
+ }
+
+ void
+ check_one_package(const Environment &, const KeywordName & keyword,
+ const Repository & repo, const QualifiedPackageName & package)
+ {
+ /* determine whether we have any interesting versions, and pick out
+ * slots where we do. for slots, we map slot to a pair (best stable
+ * version for us, best stable version for anyone). */
+
+ bool is_interesting(false);
+ typedef std::map<SlotName, SlotsEntry> SlotsToVersions;
+ SlotsToVersions slots_to_versions;
+
+ VersionSpecCollection::ConstPointer versions(repo.version_specs(package));
+ for (VersionSpecCollection::Iterator v(versions->begin()), v_end(versions->end()) ;
+ v != v_end ; ++v)
+ {
+ VersionMetadata::ConstPointer metadata(repo.version_metadata(package, *v));
+ if (! metadata->get_ebuild_interface())
+ continue;
+
+ std::set<KeywordName> keywords;
+ WhitespaceTokeniser::get_instance()->tokenise(metadata->get_ebuild_interface()->keywords,
+ create_inserter<KeywordName>(std::inserter(keywords, keywords.end())));
+
+ if (keywords.end() != keywords.find(keyword))
+ {
+ is_interesting = true;
+
+ /* replace the entry */
+ slots_to_versions.erase(metadata->slot);
+ slots_to_versions.insert(std::make_pair(metadata->slot,
+ SlotsEntry(SlotsEntry::create()
+ .our_version(*v)
+ .best_version(VersionSpec("0")))));
+ }
+
+ if (keywords.end() != std::find_if(keywords.begin(), keywords.end(), IsStableKeyword()))
+ {
+ /* ensure that an entry exists */
+ slots_to_versions.insert(std::make_pair(metadata->slot,
+ SlotsEntry(SlotsEntry::create()
+ .our_version(VersionSpec("0"))
+ .best_version(*v))));
+
+ /* update the entry to mark our current version as the best
+ * version */
+ if (slots_to_versions.find(metadata->slot)->second.best_version <= *v)
+ slots_to_versions.find(metadata->slot)->second.best_version = *v;
+ }
+ }
+
+ if (! is_interesting)
+ return;
+
+ /* for each slot, if there's a higher stable version on another arch, flag it */
+ for (SlotsToVersions::const_iterator s(slots_to_versions.begin()),
+ s_end(slots_to_versions.end()) ; s != s_end ; ++s)
+ {
+ if (s->second.our_version >= s->second.best_version)
+ continue;
+
+ write_package(package, s->first, s->second.our_version, s->second.best_version);
+ }
+ }
+}
+
+void do_find_stable_candidates(const Environment & env)
+{
+ Context context("When performing find-stable-candidates action:");
+
+ KeywordName keyword(*CommandLine::get_instance()->begin_parameters());
+
+ for (IndirectIterator<PackageDatabase::RepositoryIterator, const Repository>
+ r(env.package_database()->begin_repositories()),
+ r_end(env.package_database()->end_repositories()) ; r != r_end ; ++r)
+ {
+ if (r->name() == RepositoryName("virtuals"))
+ continue;
+
+ write_repository_header(keyword, r->name());
+
+ CategoryNamePartCollection::ConstPointer cat_names(r->category_names());
+ for (CategoryNamePartCollection::Iterator c(cat_names->begin()), c_end(cat_names->end()) ;
+ c != c_end ; ++c)
+ {
+ if (CommandLine::get_instance()->a_category.specified())
+ if (CommandLine::get_instance()->a_category.args_end() == std::find(
+ CommandLine::get_instance()->a_category.args_begin(),
+ CommandLine::get_instance()->a_category.args_end(),
+ stringify(*c)))
+ continue;
+
+ QualifiedPackageNameCollection::ConstPointer pkg_names(r->package_names(*c));
+ for (QualifiedPackageNameCollection::Iterator p(pkg_names->begin()), p_end(pkg_names->end()) ;
+ p != p_end ; ++p)
+ {
+ if (CommandLine::get_instance()->a_package.specified())
+ if (CommandLine::get_instance()->a_package.args_end() == std::find(
+ CommandLine::get_instance()->a_package.args_begin(),
+ CommandLine::get_instance()->a_package.args_end(),
+ stringify(p->package)))
+ continue;
+
+ check_one_package(env, keyword, *r, *p);
+ }
+ }
+ }
+}
+
diff --git a/0.8.0/src/adjutrix/find_stable_candidates.hh b/0.8.0/src/adjutrix/find_stable_candidates.hh
new file mode 100644
index 0000000..2860975
--- /dev/null
+++ b/0.8.0/src/adjutrix/find_stable_candidates.hh
@@ -0,0 +1,27 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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_ARCHTOOL_FIND_STABLE_CANDIDATES_HH
+#define PALUDIS_GUARD_SRC_ARCHTOOL_FIND_STABLE_CANDIDATES_HH 1
+
+#include <paludis/environment.hh>
+
+void do_find_stable_candidates(const paludis::Environment & env);
+
+#endif
diff --git a/0.8.0/src/adjutrix/find_stable_candidates.sr b/0.8.0/src/adjutrix/find_stable_candidates.sr
new file mode 100644
index 0000000..9172a89
--- /dev/null
+++ b/0.8.0/src/adjutrix/find_stable_candidates.sr
@@ -0,0 +1,12 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+make_class_SlotsEntry()
+{
+ key our_version VersionSpec
+ key best_version VersionSpec
+
+ allow_named_args
+}
+
+
diff --git a/0.8.0/src/adjutrix/find_stable_candidates_TEST b/0.8.0/src/adjutrix/find_stable_candidates_TEST
new file mode 100755
index 0000000..9ae9850
--- /dev/null
+++ b/0.8.0/src/adjutrix/find_stable_candidates_TEST
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+./adjutrix --find-stable-candidates -D find_stable_candidates_TEST_dir/ best | \
+ tee find_stable_candidates_TEST_dir/out1.txt
+
+if grep --silent '^ ' find_stable_candidates_TEST_dir/out1.txt ; then
+ echo "out1 failed" 1>&2
+ exit 127
+fi
+
+./adjutrix --find-stable-candidates -D find_stable_candidates_TEST_dir/ one | \
+ tee find_stable_candidates_TEST_dir/out2.txt
+
+if [[ $(grep --count '^ ' find_stable_candidates_TEST_dir/out2.txt ) != "1" ]] ; then
+ echo "out2 failed" 1>&2
+ exit 127
+fi
+
diff --git a/0.8.0/src/adjutrix/find_stable_candidates_TEST_cleanup.sh b/0.8.0/src/adjutrix/find_stable_candidates_TEST_cleanup.sh
new file mode 100755
index 0000000..1bdc7c1
--- /dev/null
+++ b/0.8.0/src/adjutrix/find_stable_candidates_TEST_cleanup.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d find_stable_candidates_TEST_dir ] ; then
+ rm -fr find_stable_candidates_TEST_dir
+else
+ true
+fi
+
+
+
diff --git a/0.8.0/src/adjutrix/find_stable_candidates_TEST_setup.sh b/0.8.0/src/adjutrix/find_stable_candidates_TEST_setup.sh
new file mode 100755
index 0000000..74a0a4a
--- /dev/null
+++ b/0.8.0/src/adjutrix/find_stable_candidates_TEST_setup.sh
@@ -0,0 +1,71 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir find_stable_candidates_TEST_dir || exit 1
+cd find_stable_candidates_TEST_dir || exit 1
+
+mkdir -p {eclass,distfiles,profiles/profile} || exit 1
+echo "test-repo-1" > profiles/repo_name || exit 1
+cat <<END > profiles/categories || exit 1
+cat-one
+cat-two
+cat-three
+END
+cat <<END > profiles/profile/make.defaults
+ARCH=test
+END
+
+mkdir cat-one
+mkdir cat-one/pkg-one
+cat <<"END" > cat-one/pkg-one/pkg-one-1.ebuild
+DESCRIPTION="one"
+SLOT="0"
+KEYWORDS="best one"
+END
+
+cat <<"END" > cat-one/pkg-one/pkg-one-2.ebuild
+DESCRIPTION="one"
+SLOT="0"
+KEYWORDS="best"
+END
+
+mkdir cat-one/pkg-two
+cat <<"END" > cat-one/pkg-two/pkg-two-1.ebuild
+DESCRIPTION="one"
+SLOT="0"
+KEYWORDS="foo"
+END
+
+cat <<"END" > cat-one/pkg-one/pkg-two-2.ebuild
+DESCRIPTION="one"
+SLOT="0"
+KEYWORDS="bar"
+END
+
+mkdir cat-one/pkg-three
+cat <<"END" > cat-one/pkg-two/pkg-three-1.ebuild
+DESCRIPTION="one"
+SLOT="0"
+KEYWORDS="best one"
+END
+
+cat <<"END" > cat-one/pkg-one/pkg-three-2.ebuild
+DESCRIPTION="one"
+SLOT="0"
+KEYWORDS="best one"
+END
+
+mkdir cat-one/pkg-four
+cat <<"END" > cat-one/pkg-two/pkg-four-1.ebuild
+DESCRIPTION="one"
+SLOT="0"
+KEYWORDS="best one"
+END
+
+cat <<"END" > cat-one/pkg-one/pkg-four-2.ebuild
+DESCRIPTION="one"
+SLOT="0"
+KEYWORDS="~best ~one"
+END
+
+
diff --git a/0.8.0/src/adjutrix/help_TEST b/0.8.0/src/adjutrix/help_TEST
new file mode 100755
index 0000000..7694394
--- /dev/null
+++ b/0.8.0/src/adjutrix/help_TEST
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+./adjutrix --help
+
diff --git a/0.8.0/src/adjutrix/keywords_graph.cc b/0.8.0/src/adjutrix/keywords_graph.cc
new file mode 100644
index 0000000..f4fef80
--- /dev/null
+++ b/0.8.0/src/adjutrix/keywords_graph.cc
@@ -0,0 +1,195 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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 "keywords_graph.hh"
+#include "command_line.hh"
+#include "colour.hh"
+
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/compare.hh>
+
+#include <set>
+#include <map>
+#include <iostream>
+#include <iomanip>
+#include <algorithm>
+
+using namespace paludis;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+using namespace paludis;
+
+namespace
+{
+ struct CompareByStringLength
+ {
+ template<typename T_>
+ bool
+ operator() (const T_ & l, const T_ & r) const
+ {
+ return stringify(l).length() < stringify(r).length();
+ }
+ };
+
+ void
+ write_keywords_graph(const Environment &, const Repository & repo,
+ const QualifiedPackageName & package)
+ {
+ Context context("When writing keyword graph for '" + stringify(package) + "' in '"
+ + stringify(repo.name()) + "':");
+
+ cout << "Keywords for " << package << ":" << endl;
+ cout << endl;
+
+ VersionSpecCollection::ConstPointer versions(repo.version_specs(package));
+ if (versions->empty())
+ return;
+
+ if (! repo.use_interface)
+ throw InternalError(PALUDIS_HERE, "Repository has no use_interface");
+
+ UseFlagNameCollection::ConstPointer arch_flags(repo.use_interface->arch_flags());
+ if (arch_flags->empty())
+ return;
+
+ std::set<SlotName> slots;
+ for (VersionSpecCollection::Iterator v(versions->begin()), v_end(versions->end()) ;
+ v != v_end ; ++v)
+ slots.insert(repo.version_metadata(package, *v)->slot);
+
+ unsigned version_specs_columns_width(stringify(*std::max_element(versions->begin(),
+ versions->end(), CompareByStringLength())).length() + 1);
+
+ unsigned tallest_arch_name(std::max(stringify(*std::max_element(arch_flags->begin(),
+ arch_flags->end(), CompareByStringLength())).length(), static_cast<std::size_t>(4)));
+
+ unsigned longest_slot_name(stringify(*std::max_element(slots.begin(),
+ slots.end(), CompareByStringLength())).length());
+
+ for (unsigned h = 0 ; h < tallest_arch_name ; ++h)
+ {
+ cout << std::left << std::setw(version_specs_columns_width) << " " << "| ";
+ for (UseFlagNameCollection::Iterator a(arch_flags->begin()), a_end(arch_flags->end()) ;
+ a != a_end ; ++a)
+ {
+ if ((tallest_arch_name - h) > a->data().length())
+ cout << " ";
+ else
+ cout << a->data().at(a->data().length() - tallest_arch_name + h) << " ";
+ }
+ cout << "| ";
+ if ((tallest_arch_name - h) <= 4)
+ cout << std::string("slot").at(4 - tallest_arch_name + h);
+ cout << endl;
+ }
+
+ cout << std::string(version_specs_columns_width, '-') << "+"
+ << std::string(arch_flags->size() * 2 + 1, '-') << "+"
+ << std::string(longest_slot_name + 1, '-') << endl;
+
+ SlotName old_slot("first_slot");
+ for (VersionSpecCollection::Iterator v(versions->begin()), v_end(versions->end()) ;
+ v != v_end ; ++v)
+ {
+ VersionMetadata::ConstPointer metadata(repo.version_metadata(package, *v));
+ if (! metadata->get_ebuild_interface())
+ continue;
+
+ if (metadata->slot != old_slot)
+ if (old_slot != SlotName("first_slot"))
+ cout << std::string(version_specs_columns_width, '-') << "+"
+ << std::string(arch_flags->size() * 2 + 1, '-') << "+"
+ << std::string(longest_slot_name + 1, '-') << endl;
+
+ cout << std::left << std::setw(version_specs_columns_width) << *v << "| ";
+
+ std::set<KeywordName> keywords;
+ WhitespaceTokeniser::get_instance()->tokenise(metadata->get_ebuild_interface()->keywords,
+ create_inserter<KeywordName>(std::inserter(keywords, keywords.end())));
+
+ for (UseFlagNameCollection::Iterator a(arch_flags->begin()), a_end(arch_flags->end()) ;
+ a != a_end ; ++a)
+ {
+ if (keywords.end() != keywords.find(KeywordName(stringify(*a))))
+ cout << colour(cl_bold_green, "+ ");
+ else if (keywords.end() != keywords.find(KeywordName("~" + stringify(*a))))
+ cout << colour(cl_bold_yellow, "~ ");
+ else if (keywords.end() != keywords.find(KeywordName("-" + stringify(*a))))
+ cout << colour(cl_red, "- ");
+ else if (keywords.end() != keywords.find(KeywordName("-*")))
+ cout << colour(cl_red, "* ");
+ else
+ cout << " ";
+ }
+
+ cout << "| ";
+ if (metadata->slot != old_slot)
+ {
+ cout << metadata->slot;
+ old_slot = metadata->slot;
+ }
+
+ cout << endl;
+ }
+
+ cout << endl;
+ }
+}
+
+void do_keywords_graph(const Environment & env)
+{
+ Context context("When performing keywords-graph action:");
+
+ for (IndirectIterator<PackageDatabase::RepositoryIterator, const Repository>
+ r(env.package_database()->begin_repositories()),
+ r_end(env.package_database()->end_repositories()) ; r != r_end ; ++r)
+ {
+ if (r->name() == RepositoryName("virtuals"))
+ continue;
+
+ CategoryNamePartCollection::ConstPointer cat_names(r->category_names());
+ for (CategoryNamePartCollection::Iterator c(cat_names->begin()), c_end(cat_names->end()) ;
+ c != c_end ; ++c)
+ {
+ if (CommandLine::get_instance()->a_category.specified())
+ if (CommandLine::get_instance()->a_category.args_end() == std::find(
+ CommandLine::get_instance()->a_category.args_begin(),
+ CommandLine::get_instance()->a_category.args_end(),
+ stringify(*c)))
+ continue;
+
+ QualifiedPackageNameCollection::ConstPointer pkg_names(r->package_names(*c));
+ for (QualifiedPackageNameCollection::Iterator p(pkg_names->begin()), p_end(pkg_names->end()) ;
+ p != p_end ; ++p)
+ {
+ if (CommandLine::get_instance()->a_package.specified())
+ if (CommandLine::get_instance()->a_package.args_end() == std::find(
+ CommandLine::get_instance()->a_package.args_begin(),
+ CommandLine::get_instance()->a_package.args_end(),
+ stringify(p->package)))
+ continue;
+
+ write_keywords_graph(env, *r, *p);
+ }
+ }
+ }
+}
+
diff --git a/0.8.0/src/adjutrix/keywords_graph.hh b/0.8.0/src/adjutrix/keywords_graph.hh
new file mode 100644
index 0000000..7376143
--- /dev/null
+++ b/0.8.0/src/adjutrix/keywords_graph.hh
@@ -0,0 +1,27 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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_ARCHTOOL_KEYWORDS_GRAPH_HH
+#define PALUDIS_GUARD_SRC_ARCHTOOL_KEYWORDS_GRAPH_HH 1
+
+#include <paludis/environment.hh>
+
+void do_keywords_graph(const paludis::Environment & env);
+
+#endif
diff --git a/0.8.0/src/adjutrix/man_adjutrix.cc b/0.8.0/src/adjutrix/man_adjutrix.cc
new file mode 100644
index 0000000..d36aa1d
--- /dev/null
+++ b/0.8.0/src/adjutrix/man_adjutrix.cc
@@ -0,0 +1,36 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * 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 "command_line.hh"
+#include <paludis/args/man.hh>
+
+#include <iostream>
+#include <cstdlib>
+
+using std::cout;
+using std::endl;
+
+int
+main(int, char *[])
+{
+ paludis::args::generate_man(cout, CommandLine::get_instance());
+ return EXIT_SUCCESS;
+}
+
+
diff --git a/0.8.0/src/adjutrix/version_TEST b/0.8.0/src/adjutrix/version_TEST
new file mode 100755
index 0000000..7d5c45e
--- /dev/null
+++ b/0.8.0/src/adjutrix/version_TEST
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+./adjutrix --version