aboutsummaryrefslogtreecommitdiff
path: root/0.4.0/src
diff options
context:
space:
mode:
Diffstat (limited to '0.4.0/src')
-rw-r--r--0.4.0/src/Makefile.am47
-rw-r--r--0.4.0/src/applets.cc196
-rw-r--r--0.4.0/src/applets.hh51
-rw-r--r--0.4.0/src/colour.cc31
-rw-r--r--0.4.0/src/colour.hh93
-rw-r--r--0.4.0/src/command_line.cc102
-rw-r--r--0.4.0/src/command_line.hh252
-rw-r--r--0.4.0/src/contents.cc153
-rw-r--r--0.4.0/src/contents.hh30
-rwxr-xr-x0.4.0/src/exception_TEST6
-rwxr-xr-x0.4.0/src/help_TEST3
-rw-r--r--0.4.0/src/install.cc710
-rw-r--r--0.4.0/src/install.hh32
-rwxr-xr-x0.4.0/src/install_TEST5
-rwxr-xr-x0.4.0/src/install_TEST_cleanup.sh11
-rwxr-xr-x0.4.0/src/install_TEST_setup.sh121
-rw-r--r--0.4.0/src/licence.cc66
-rw-r--r--0.4.0/src/licence.hh67
-rw-r--r--0.4.0/src/list.cc324
-rw-r--r--0.4.0/src/list.hh39
-rwxr-xr-x0.4.0/src/list_dep_tag_categories_TEST3
-rwxr-xr-x0.4.0/src/list_repository_formats_TEST3
-rwxr-xr-x0.4.0/src/list_sync_formats_TEST3
-rw-r--r--0.4.0/src/news.cc51
-rw-r--r--0.4.0/src/news.hh34
-rw-r--r--0.4.0/src/owner.cc131
-rw-r--r--0.4.0/src/owner.hh30
-rw-r--r--0.4.0/src/paludis.cc435
-rw-r--r--0.4.0/src/qualudis/Makefile.am31
-rw-r--r--0.4.0/src/qualudis/qualudis.cc583
-rw-r--r--0.4.0/src/qualudis/qualudis_command_line.cc54
-rw-r--r--0.4.0/src/qualudis/qualudis_command_line.hh65
-rw-r--r--0.4.0/src/query.cc371
-rw-r--r--0.4.0/src/query.hh32
-rw-r--r--0.4.0/src/sync.cc123
-rw-r--r--0.4.0/src/sync.hh33
-rw-r--r--0.4.0/src/uninstall.cc155
-rw-r--r--0.4.0/src/uninstall.hh33
-rwxr-xr-x0.4.0/src/upgrade_TEST17
-rwxr-xr-x0.4.0/src/upgrade_TEST_cleanup.sh11
-rwxr-xr-x0.4.0/src/upgrade_TEST_setup.sh153
-rwxr-xr-x0.4.0/src/version_TEST3
42 files changed, 4693 insertions, 0 deletions
diff --git a/0.4.0/src/Makefile.am b/0.4.0/src/Makefile.am
new file mode 100644
index 000000000..2c9e466f8
--- /dev/null
+++ b/0.4.0/src/Makefile.am
@@ -0,0 +1,47 @@
+AM_CXXFLAGS = -I$(top_srcdir)
+DEFS= \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DLIBEXECDIR=\"$(libexecdir)\"
+SUBDIRS = . qualudis
+
+bin_PROGRAMS = paludis
+
+paludis_SOURCES = \
+ applets.hh applets.cc \
+ command_line.hh command_line.cc \
+ colour.hh colour.cc \
+ install.hh install.cc \
+ uninstall.hh uninstall.cc \
+ list.hh list.cc \
+ query.hh query.cc \
+ sync.hh sync.cc \
+ licence.hh licence.cc \
+ contents.hh contents.cc \
+ owner.hh owner.cc \
+ news.hh news.cc \
+ paludis.cc
+
+paludis_LDADD = \
+ $(top_builddir)/paludis/libpaludis.a \
+ $(top_builddir)/paludis/args/libpaludisargs.a \
+ $(top_builddir)/paludis/util/libpaludisutil.a
+
+TESTS_ENVIRONMENT = env \
+ TEST_SCRIPT_DIR="$(srcdir)/" \
+ PALUDIS_NO_GLOBAL_HOOKS="yes" \
+ PALUDIS_EBUILD_DIR="`$(top_srcdir)/ebuild/utils/canonicalise $(top_srcdir)/ebuild/`" \
+ PALUDIS_EBUILD_DIR_FALLBACK="`$(top_srcdir)/ebuild/utils/canonicalise $(top_builddir)/ebuild/`" \
+ SYSCONFDIR="$(sysconfdir)" \
+ bash $(top_srcdir)/test/run_test.sh bash
+
+TESTS = version_TEST help_TEST list_sync_formats_TEST \
+ list_repository_formats_TEST list_dep_tag_categories_TEST \
+ exception_TEST install_TEST upgrade_TEST
+
+EXTRA_DIST = $(TESTS) \
+ install_TEST_setup.sh install_TEST_cleanup.sh \
+ upgrade_TEST_setup.sh upgrade_TEST_cleanup.sh
+
+CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda
+MAINTAINERCLEANFILES = Makefile.in
+
diff --git a/0.4.0/src/applets.cc b/0.4.0/src/applets.cc
new file mode 100644
index 000000000..b9ddc0786
--- /dev/null
+++ b/0.4.0/src/applets.cc
@@ -0,0 +1,196 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "src/applets.hh"
+#include "src/colour.hh"
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <paludis/paludis.hh>
+#include <string>
+#include <set>
+
+/** \file
+ * Handle the --has-version, --best-version and various --list actions for the
+ * main paludis program.
+ */
+
+namespace p = paludis;
+
+int do_has_version()
+{
+ int return_code(0);
+
+ p::Context context("When performing has-version action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ std::string query(*CommandLine::get_instance()->begin_parameters());
+ p::PackageDepAtom::Pointer atom(new p::PackageDepAtom(query));
+ p::PackageDatabaseEntryCollection::ConstPointer entries(env->package_database()->query(
+ atom, p::is_installed_only));
+ if (entries->empty())
+ return_code = 1;
+
+ return return_code;
+}
+
+int do_best_version()
+{
+ int return_code(0);
+
+ p::Context context("When performing best-version action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ std::string query(*CommandLine::get_instance()->begin_parameters());
+ p::PackageDepAtom::Pointer atom(new p::PackageDepAtom(query));
+ p::PackageDatabaseEntryCollection::ConstPointer entries(env->package_database()->query(
+ atom, p::is_installed_only));
+ if (entries->empty())
+ return_code = 1;
+ else
+ {
+ // don't include repo, it breaks built_with_use and the like.
+ std::string entry(
+ stringify(entries->last()->get<p::pde_name>()) + "-" +
+ stringify(entries->last()->get<p::pde_version>()));
+ std::cout << entry << std::endl;
+ }
+
+ return return_code;
+}
+
+int do_environment_variable()
+{
+ int return_code(0);
+
+ p::Context context("When performing environment-variable action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ std::string atom_str(*CommandLine::get_instance()->begin_parameters());
+ std::string var_str(* p::next(CommandLine::get_instance()->begin_parameters()));
+ p::PackageDepAtom::Pointer atom(new p::PackageDepAtom(atom_str));
+
+ p::PackageDatabaseEntryCollection::ConstPointer entries(env->package_database()->query(
+ atom, p::is_installed_only));
+
+ if (entries->empty())
+ entries = env->package_database()->query(atom, p::is_uninstalled_only);
+
+ if (entries->empty())
+ throw p::NoSuchPackageError(atom_str);
+
+ p::Repository::ConstPointer repo(env->package_database()->fetch_repository(
+ entries->begin()->get<p::pde_repository>()));
+ p::Repository::EnvironmentVariableInterface * env_if(
+ repo->get_interface<p::repo_environment_variable>());
+
+ if (! env_if)
+ {
+ std::cerr << "Repository '" << repo->name() <<
+ "' cannot be queried for environment variables" << std::endl;
+ return_code |= 1;
+ }
+ else
+ std::cout << env_if->get_environment_variable(*entries->begin(), var_str) << std::endl;
+
+ return return_code;
+}
+
+int do_configuration_variable()
+{
+ int return_code(0);
+
+ p::Context context("When performing configuration-variable action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ std::string repo_str(*CommandLine::get_instance()->begin_parameters());
+ std::string var_str(* p::next(CommandLine::get_instance()->begin_parameters()));
+
+ p::RepositoryInfo::ConstPointer info(env->package_database()->fetch_repository(
+ p::RepositoryName(repo_str))->info(false));
+
+ return_code = 1;
+ for (p::RepositoryInfo::SectionIterator s(info->begin_sections()),
+ s_end(info->end_sections()) ; s != s_end ; ++s)
+ for (p::RepositoryInfoSection::KeyValueIterator k(s->begin_kvs()),
+ k_end(s->end_kvs()) ; k != k_end ; ++k)
+ if (var_str == k->first)
+ {
+ std::cout << k->second << std::endl;
+ return_code = 0;
+ break;
+ }
+
+ return return_code;
+}
+
+int do_list_repository_formats()
+{
+ int return_code(1);
+
+ std::set<std::string> keys;
+ p::RepositoryMaker::get_instance()->copy_keys(std::inserter(keys, keys.begin()));
+
+ if (! keys.empty())
+ {
+ return_code = 0;
+ for (std::set<std::string>::const_iterator k(keys.begin()), k_end(keys.end()) ;
+ k != k_end ; ++k)
+ std::cout << "* " << colour(cl_package_name, *k) << std::endl;
+ }
+
+ return return_code;
+}
+
+int do_list_sync_protocols()
+{
+ int return_code(1);
+
+ std::set<std::string> keys;
+ p::SyncerMaker::get_instance()->copy_keys(std::inserter(keys, keys.begin()));
+
+ if (! keys.empty())
+ {
+ return_code = 0;
+ for (std::set<std::string>::const_iterator k(keys.begin()), k_end(keys.end()) ;
+ k != k_end ; ++k)
+ std::cout << "* " << colour(cl_package_name, *k) << std::endl;
+ }
+
+ return return_code;
+}
+
+int do_list_dep_tag_categories()
+{
+ int return_code(1);
+
+ std::set<std::string> keys;
+ p::DepTagCategoryMaker::get_instance()->copy_keys(std::inserter(keys, keys.begin()));
+
+ if (! keys.empty())
+ {
+ return_code = 0;
+ for (std::set<std::string>::const_iterator k(keys.begin()), k_end(keys.end()) ;
+ k != k_end ; ++k)
+ std::cout << "* " << colour(cl_package_name, *k) << std::endl;
+ }
+
+ return return_code;
+}
+
diff --git a/0.4.0/src/applets.hh b/0.4.0/src/applets.hh
new file mode 100644
index 000000000..33602ce37
--- /dev/null
+++ b/0.4.0/src/applets.hh
@@ -0,0 +1,51 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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_APPLETS_HH
+#define PALUDIS_GUARD_SRC_APPLETS_HH 1
+
+#include "src/command_line.hh"
+
+/** \file
+ * Declaration for small do_* functions.
+ */
+
+/// Handle --has-version.
+int do_has_version();
+
+/// Handle --best-version.
+int do_best_version();
+
+/// Handle --environment-variable.
+int do_environment_variable();
+
+/// Handle --configuration-variable.
+int do_configuration_variable();
+
+/// Handle --list-repository-formats
+int do_list_repository_formats();
+
+/// Handle --list-sync-protocols
+int do_list_sync_protocols();
+
+/// Handle --list-dep-tag-categories
+int do_list_dep_tag_categories();
+
+#endif
+
diff --git a/0.4.0/src/colour.cc b/0.4.0/src/colour.cc
new file mode 100644
index 000000000..9e63e5883
--- /dev/null
+++ b/0.4.0/src/colour.cc
@@ -0,0 +1,31 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 <paludis/util/system.hh>
+#include <unistd.h>
+
+bool use_colour()
+{
+ static bool result(
+ (1 == isatty(1)) &&
+ (0 != paludis::getenv_with_default("TERM", "").compare(0, 4, "dumb")));
+
+ return result;
+}
diff --git a/0.4.0/src/colour.hh b/0.4.0/src/colour.hh
new file mode 100644
index 000000000..da835ab67
--- /dev/null
+++ b/0.4.0/src/colour.hh
@@ -0,0 +1,93 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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_COLOUR_HH
+#define PALUDIS_GUARD_SRC_COLOUR_HH 1
+
+#include "src/command_line.hh"
+#include <paludis/util/stringify.hh>
+#include <config.h>
+#include <string>
+
+enum Colour
+{
+ cl_none = 0,
+ cl_red = 31,
+ cl_green = 32,
+ cl_yellow = 33,
+ cl_blue = 34,
+ cl_pink = 35,
+
+ cl_bold_red = cl_red + 100,
+ cl_bold_green = cl_green + 100,
+ cl_bold_blue = cl_blue + 100,
+ cl_bold_pink = cl_pink + 100,
+
+#if PALUDIS_COLOUR_PINK==1
+ cl_package_name = cl_bold_pink,
+ cl_flag_on = cl_pink,
+ cl_flag_off = cl_red,
+ cl_slot = cl_blue,
+ cl_visible = cl_flag_on,
+ cl_masked = cl_flag_off,
+ cl_heading = cl_bold_pink,
+ cl_updatemode = cl_yellow,
+ cl_tag = cl_yellow,
+#else
+ cl_package_name = cl_bold_blue,
+ cl_flag_on = cl_green,
+ cl_flag_off = cl_red,
+ cl_slot = cl_blue,
+ cl_visible = cl_flag_on,
+ cl_masked = cl_flag_off,
+ cl_heading = cl_bold_green,
+ cl_updatemode = cl_yellow,
+ cl_tag = cl_yellow,
+#endif
+ cl_file = cl_none,
+ cl_dir = cl_blue,
+ cl_sym = cl_pink,
+ cl_misc = cl_red
+};
+
+bool use_colour() PALUDIS_ATTRIBUTE((pure));
+
+template <typename T_>
+std::string colour(Colour colour, const T_ & s)
+{
+ if (CommandLine::get_instance()->a_no_color.specified() || ! use_colour())
+ return paludis::stringify(s);
+ else if (cl_none != colour)
+ return "\033[" + paludis::stringify(static_cast<unsigned>(colour) / 100) + ";"
+ + paludis::stringify(static_cast<unsigned>(colour) % 100) + "m" + paludis::stringify(s)
+ + "\033[0;0m";
+ else
+ return paludis::stringify(s);
+}
+
+template <typename T_>
+std::string xterm_title(const T_ & s)
+{
+ if (CommandLine::get_instance()->a_no_color.specified() || ! use_colour())
+ return "";
+ else
+ return "\x1b]2;" + paludis::stringify(s) + "\x07";
+}
+
+#endif
diff --git a/0.4.0/src/command_line.cc b/0.4.0/src/command_line.cc
new file mode 100644
index 000000000..a8daaf743
--- /dev/null
+++ b/0.4.0/src/command_line.cc
@@ -0,0 +1,102 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "src/command_line.hh"
+
+CommandLine::CommandLine() :
+ ArgsHandler(),
+
+ action_args(this, "Actions (specify exactly one)"),
+ a_query(&action_args, "query", 'q', "Query for package information"),
+ a_install(&action_args, "install", 'i', "Install one or more packages"),
+ a_uninstall(&action_args, "uninstall", 'u', "Uninstall one or more packages"),
+ a_sync(&action_args, "sync", 's', "Sync repositories"),
+ a_contents(&action_args, "contents", 'k', "Display contents of a package"),
+ a_owner(&action_args, "owner", 'o', "Display the owner of a file"),
+ a_version(&action_args, "version", 'V', "Display program version"),
+ a_info(&action_args, "info", 'I', "Display program version and system information"),
+ a_help(&action_args, "help", 'h', "Display program help"),
+
+ action_args_internal(this, "More actions (mostly for internal / script use)"),
+ a_has_version(&action_args_internal, "has-version", '\0', "Check whether the specified atom is installed"),
+ a_best_version(&action_args_internal, "best-version", '\0', "Display the best version of the specified atom"),
+ a_environment_variable(&action_args_internal, "environment-variable", '\0', "Display the value of an environment "
+ "variable for a particular package"),
+ a_configuration_variable(&action_args_internal, "configuration-variable", '\0', "Display the value of a "
+ "configuration variable for a particular package"),
+ a_list_repositories(&action_args_internal, "list-repositories", '\0', "List available repositories"),
+ a_list_categories(&action_args_internal, "list-categories", '\0', "List available categories"),
+ a_list_packages(&action_args_internal, "list-packages", '\0', "List available packages"),
+ a_list_sync_protocols(&action_args_internal, "list-sync-protocols", '\0', "List available sync protocols"),
+ a_list_repository_formats(&action_args_internal, "list-repository-formats", '\0', "List available repository formats"),
+ a_list_dep_tag_categories(&action_args_internal, "list-dep-tag-categories", '\0', "List known dep tag categories"),
+ a_list_vulnerabilities(&action_args_internal, "list-vulnerabilities", '\0', "List known vulnerabilities"),
+ a_update_news(&action_args_internal, "update-news", '\0', "Regenerate news.unread files"),
+
+ general_args(this, "General options"),
+ 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", 'C', "Do not use colour"),
+ a_no_color(&a_no_colour, "no-color"),
+ a_config_suffix(&general_args, "config-suffix", 'c', "Config directory suffix"),
+
+ query_args(this, "Query options"),
+ a_show_slot(&query_args, "show-slot", 'S', "Show SLOTs"),
+ a_show_deps(&query_args, "show-deps", 'D', "Show dependencies"),
+ a_show_metadata(&query_args, "show-metadata", 'M', "Show raw metadata"),
+
+ install_args(this, "Install, Uninstall options"),
+ a_pretend(&install_args, "pretend", 'p', "Pretend only"),
+ a_preserve_world(&install_args, "preserve-world", '1', "Don't modify the world file"),
+ a_no_config_protection(&install_args, "no-config-protection", '\0', "Disable config file protection (dangerous)"),
+ a_fetch(&install_args, "fetch", 'f', "Only fetch sources; don't install anything"),
+
+ dl_args(this, "DepList behaviour (use with caution)"),
+ a_dl_rdepend_post(&dl_args, "dl-rdepend-post", '\0', "Treat RDEPEND like PDEPEND",
+ paludis::args::EnumArg::EnumArgOptions("always", "Always")
+ ("never", "Never")
+ ("as-needed", "To resolve circular dependencies"),
+ "as-needed"),
+ a_dl_drop_self_circular(&dl_args, "dl-drop-self-circular", '\0', "Drop self-circular dependencies"),
+ a_dl_drop_circular(&dl_args, "dl-drop-circular", '\0', "Drop circular dependencies"),
+ a_dl_drop_all(&dl_args, "dl-drop-all", '0', "Drop all dependencies"),
+ a_dl_ignore_installed(&dl_args, "dl-ignore-installed", 'e', "Ignore installed packages"),
+ a_dl_no_recursive_deps(&dl_args, "dl-no-recursive-deps", '\0', "Don't check runtime dependencies for installed packages"),
+ a_dl_max_stack_depth(&dl_args, "dl-max-stack-depth", '\0', "Maximum stack depth (default 100)"),
+ a_dl_no_unnecessary_upgrades(&dl_args, "dl-no-unnecessary-upgrades", 'U', "Don't upgrade installed packages except where necessary as a dependency of another package"),
+
+ list_args(this, "List options"),
+ a_repository(&list_args, "repository", '\0', "Matches with this repository name only"),
+ a_category(&list_args, "category", '\0', "Matches with this category name only"),
+ a_package(&list_args, "package", '\0', "Matches with this package name only"),
+
+ owner_args(this, "Owner options"),
+ a_full_match(&owner_args, "full-match", '\0', "Match whole filename")
+{
+ a_dl_max_stack_depth.set_argument(100);
+}
+
+CommandLine::~CommandLine()
+{
+}
+
diff --git a/0.4.0/src/command_line.hh b/0.4.0/src/command_line.hh
new file mode 100644
index 000000000..61f88e781
--- /dev/null
+++ b/0.4.0/src/command_line.hh
@@ -0,0 +1,252 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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_COMMAND_LINE_HH
+#define PALUDIS_GUARD_SRC_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 Action arguments
+ ///{
+
+ /// Action arguments.
+ paludis::args::ArgsGroup action_args;
+
+ /// --query
+ paludis::args::SwitchArg a_query;
+
+ /// --install
+ paludis::args::SwitchArg a_install;
+
+ /// --uninstall
+ paludis::args::SwitchArg a_uninstall;
+
+ /// --sync
+ paludis::args::SwitchArg a_sync;
+
+ /// --contents
+ paludis::args::SwitchArg a_contents;
+
+ /// --owner
+ paludis::args::SwitchArg a_owner;
+
+ /// --version
+ paludis::args::SwitchArg a_version;
+
+ /// --info
+ paludis::args::SwitchArg a_info;
+
+ /// --help
+ paludis::args::SwitchArg a_help;
+
+ /// Action arguments (internal).
+ paludis::args::ArgsGroup action_args_internal;
+
+ /// --has-version
+ paludis::args::SwitchArg a_has_version;
+
+ /// --best-version
+ paludis::args::SwitchArg a_best_version;
+
+ /// --environment-variable
+ paludis::args::SwitchArg a_environment_variable;
+
+ /// --configuration-variable
+ paludis::args::SwitchArg a_configuration_variable;
+
+ /// --list-repositories
+ paludis::args::SwitchArg a_list_repositories;
+
+ /// --list-categories
+ paludis::args::SwitchArg a_list_categories;
+
+ /// --list-packages
+ paludis::args::SwitchArg a_list_packages;
+
+ /// --list-sync-protocols
+ paludis::args::SwitchArg a_list_sync_protocols;
+
+ /// --list-repository-formats
+ paludis::args::SwitchArg a_list_repository_formats;
+
+ /// --list-dep-tag-categories
+ paludis::args::SwitchArg a_list_dep_tag_categories;
+
+ /// --list-vulnerabilities
+ paludis::args::SwitchArg a_list_vulnerabilities;
+
+ /// --update-news
+ paludis::args::SwitchArg a_update_news;
+
+ ///}
+
+ /// \name General arguments
+ ///{
+
+ /// General arguments.
+ paludis::args::ArgsGroup general_args;
+
+ /// --log-level
+ paludis::args::EnumArg a_log_level;
+
+ /// --no-colour
+ paludis::args::SwitchArg a_no_colour;
+
+ /// --no-color
+ paludis::args::AliasArg a_no_color;
+
+ /// --config-suffix
+ paludis::args::StringArg a_config_suffix;
+
+ ///}
+
+ /// \name Query arguments
+ ///{
+
+ /// Query arguments.
+ paludis::args::ArgsGroup query_args;
+
+ /// --show-slot
+ paludis::args::SwitchArg a_show_slot;
+
+ /// --show-deps
+ paludis::args::SwitchArg a_show_deps;
+
+ /// --show-metadata
+ paludis::args::SwitchArg a_show_metadata;
+
+ /// }
+
+ /// \name (Un)Install arguments
+ /// {
+
+ /// Install arguments.
+ paludis::args::ArgsGroup install_args;
+
+ /// --pretend
+ paludis::args::SwitchArg a_pretend;
+
+ /// --preserve-world
+ paludis::args::SwitchArg a_preserve_world;
+
+ /// --no-config-protection
+ paludis::args::SwitchArg a_no_config_protection;
+
+ /// --fetch
+ paludis::args::SwitchArg a_fetch;
+
+ /// }
+
+ /// \name DepList behaviour arguments
+ /// {
+
+ /// DepList behaviour arguments.
+ paludis::args::ArgsGroup dl_args;
+
+ /// --dl-rdepend-post
+ paludis::args::EnumArg a_dl_rdepend_post;
+
+ /// --dl-drop-self-circular
+ paludis::args::SwitchArg a_dl_drop_self_circular;
+
+ /// --dl-drop-circular
+ paludis::args::SwitchArg a_dl_drop_circular;
+
+ /// --dl-drop-all
+ paludis::args::SwitchArg a_dl_drop_all;
+
+ /// --dl-ignore-installed
+ paludis::args::SwitchArg a_dl_ignore_installed;
+
+ /// --dl-no-recursive-deps
+ paludis::args::SwitchArg a_dl_no_recursive_deps;
+
+ /// --dl-max-stack-depth
+ paludis::args::IntegerArg a_dl_max_stack_depth;
+
+ /// --dl-no-unnecessary-upgrades
+ paludis::args::SwitchArg a_dl_no_unnecessary_upgrades;
+
+ /// }
+
+ /// \name List arguments
+ /// {
+
+ /// List arguments.
+ paludis::args::ArgsGroup list_args;
+
+ /// --repository
+ paludis::args::StringSetArg a_repository;
+
+ /// --category
+ paludis::args::StringSetArg a_category;
+
+ /// --package
+ paludis::args::StringSetArg a_package;
+
+ /// }
+
+ /// \name Owner arguments
+ /// {
+
+ /// Owner arguments.
+ paludis::args::ArgsGroup owner_args;
+
+ /// --full-match
+ paludis::args::SwitchArg a_full_match;
+
+ /// }
+};
+
+/**
+ * Show the help message.
+ */
+struct DoHelp
+{
+ const std::string message;
+
+ DoHelp(const std::string & m = "") :
+ message(m)
+ {
+ }
+};
+
+#endif
diff --git a/0.4.0/src/contents.cc b/0.4.0/src/contents.cc
new file mode 100644
index 000000000..4138eced2
--- /dev/null
+++ b/0.4.0/src/contents.cc
@@ -0,0 +1,153 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "contents.hh"
+#include "colour.hh"
+#include <paludis/paludis.hh>
+#include <iostream>
+#include <algorithm>
+
+namespace p = paludis;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace
+{
+ struct ContentsDisplayer :
+ p::ContentsVisitorTypes::ConstVisitor
+ {
+ void visit(const p::ContentsFileEntry * const e)
+ {
+ cout << " " << colour(cl_file, e->name()) << endl;
+ }
+
+ void visit(const p::ContentsDirEntry * const e)
+ {
+ cout << " " << colour(cl_dir, e->name()) << endl;
+ }
+
+ void visit(const p::ContentsSymEntry * const e)
+ {
+ cout << " " << colour(cl_sym, e->name()) << " -> " << e->target() << endl;
+ }
+
+ void visit(const p::ContentsMiscEntry * const e)
+ {
+ cout << " " << colour(cl_misc, e->name()) << endl;
+ }
+ };
+}
+
+void
+do_one_contents_entry(
+ const p::Environment * const env,
+ const p::PackageDatabaseEntry & e)
+{
+ cout << "* " << colour(cl_package_name, e) << endl;
+
+ const p::Repository::InstalledInterface * const installed_interface(
+ env->package_database()->fetch_repository(e.get<p::pde_repository>())->
+ get_interface<p::repo_installed>());
+ if (installed_interface)
+ {
+ p::Contents::ConstPointer contents(installed_interface->contents(
+ e.get<p::pde_name>(), e.get<p::pde_version>()));
+ ContentsDisplayer d;
+ std::for_each(contents->begin(), contents->end(), accept_visitor(&d));
+ }
+ else
+ cout << " " << colour(cl_red, "(unknown)") << endl;
+
+ cout << endl;
+}
+
+void
+do_one_contents(
+ const p::Environment * const env,
+ const std::string & q)
+{
+ p::Context local_context("When handling query '" + q + "':");
+
+ /* we might have a dep atom, but we might just have a simple package name
+ * without a category. either should work. */
+ p::PackageDepAtom::Pointer atom(std::string::npos == q.find('/') ?
+ new p::PackageDepAtom(env->package_database()->fetch_unique_qualified_package_name(
+ p::PackageNamePart(q))) :
+ new p::PackageDepAtom(q));
+
+ p::PackageDatabaseEntryCollection::ConstPointer
+ entries(env->package_database()->query(atom, p::is_installed_only));
+
+ if (entries->empty())
+ throw p::NoSuchPackageError(q);
+
+ for (p::PackageDatabaseEntryCollection::Iterator i(entries->begin()),
+ i_end(entries->end()) ; i != i_end ; ++i)
+ do_one_contents_entry(env, *i);
+}
+
+int
+do_contents()
+{
+ int return_code(0);
+
+ p::Context context("When performing contents action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ CommandLine::ParametersIterator q(CommandLine::get_instance()->begin_parameters()),
+ q_end(CommandLine::get_instance()->end_parameters());
+ for ( ; q != q_end ; ++q)
+ {
+ try
+ {
+ do_one_contents(env, *q);
+ }
+ catch (const p::AmbiguousPackageNameError & e)
+ {
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ");
+ cerr << "Ambiguous package name '" << e.name() << "'. Did you mean:" << endl;
+ for (p::AmbiguousPackageNameError::OptionsIterator o(e.begin_options()),
+ o_end(e.end_options()) ; o != o_end ; ++o)
+ cerr << " * " << colour(cl_package_name, *o) << endl;
+ cerr << endl;
+ }
+ catch (const p::NameError & e)
+ {
+ return_code |= 1;
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ") << e.message() << endl;
+ cerr << endl;
+ }
+ catch (const p::PackageDatabaseLookupError & e)
+ {
+ return_code |= 1;
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ") << e.message() << endl;
+ cerr << endl;
+ }
+ }
+
+ return return_code;
+}
+
diff --git a/0.4.0/src/contents.hh b/0.4.0/src/contents.hh
new file mode 100644
index 000000000..4cf3b6175
--- /dev/null
+++ b/0.4.0/src/contents.hh
@@ -0,0 +1,30 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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_CONTENTS_HH
+#define PALUDIS_GUARD_SRC_CONTENTS_HH 1
+
+/** \file
+ * Declaration for the do_contents function.
+ */
+
+/// Handle --contents.
+int do_contents();
+
+#endif
diff --git a/0.4.0/src/exception_TEST b/0.4.0/src/exception_TEST
new file mode 100755
index 000000000..a3daaaf26
--- /dev/null
+++ b/0.4.0/src/exception_TEST
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+PALUDIS_HOME=./ \
+ ./paludis --config-suffix paludis-build-test -pi asdf 2>&1 \
+ | grep 'Default configuration error' >/dev/null
+
diff --git a/0.4.0/src/help_TEST b/0.4.0/src/help_TEST
new file mode 100755
index 000000000..3a0f5fbb5
--- /dev/null
+++ b/0.4.0/src/help_TEST
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+PALUDIS_SKIP_CONFIG=yes ./paludis --help
diff --git a/0.4.0/src/install.cc b/0.4.0/src/install.cc
new file mode 100644
index 000000000..08eb6c444
--- /dev/null
+++ b/0.4.0/src/install.cc
@@ -0,0 +1,710 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "src/colour.hh"
+#include "src/install.hh"
+#include "src/licence.hh"
+#include <iostream>
+#include <paludis/paludis.hh>
+#include <paludis/util/iterator.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/log.hh>
+
+/** \file
+ * Handle the --install action for the main paludis program.
+ */
+
+namespace p = paludis;
+
+using std::cerr;
+using std::cout;
+using std::endl;
+
+namespace
+{
+ struct TagDisplayer :
+ p::DepTagVisitorTypes::ConstVisitor
+ {
+ void visit(const p::GLSADepTag * const tag)
+ {
+ cout << "* " << colour(cl_yellow, tag->short_text()) << ": "
+ << tag->glsa_title() << endl;
+ }
+
+ void visit(const p::GeneralSetDepTag * const tag)
+ {
+ cout << "* " << colour(cl_yellow, tag->short_text());
+ if (tag->short_text() == "world")
+ cout << ": " << "Packages that have been explicitly installed";
+ else if (tag->short_text() == "everything")
+ cout << ": " << "All installed packages";
+ else if (tag->short_text() == "system")
+ cout << ": " << "Packages that are part of the base system";
+ cout << endl;
+ }
+ };
+
+ void
+ world_add_callback(const p::PackageDepAtom * const p)
+ {
+ cout << "* adding " << *p << endl;
+ }
+
+ void
+ world_skip_callback(const p::PackageDepAtom * const p, const std::string & why)
+ {
+ cout << "* skipping " << *p << " (" << why << ")" << endl;
+ }
+}
+
+int
+do_install()
+{
+ int return_code(0);
+
+ p::Context context("When performing install action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ cout << colour(cl_heading, "These packages will be installed:") << endl << endl;
+
+ p::CompositeDepAtom::Pointer targets(new p::AllDepAtom);
+
+ p::DepList dep_list(env);
+
+ dep_list.set_drop_self_circular(CommandLine::get_instance()->a_dl_drop_self_circular.specified());
+ dep_list.set_drop_circular(CommandLine::get_instance()->a_dl_drop_circular.specified());
+ dep_list.set_drop_all(CommandLine::get_instance()->a_dl_drop_all.specified());
+ dep_list.set_ignore_installed(CommandLine::get_instance()->a_dl_ignore_installed.specified());
+ dep_list.set_recursive_deps(! CommandLine::get_instance()->a_dl_no_recursive_deps.specified());
+ dep_list.set_max_stack_depth(CommandLine::get_instance()->a_dl_max_stack_depth.argument());
+ dep_list.set_no_unnecessary_upgrades(CommandLine::get_instance()->a_dl_no_unnecessary_upgrades.specified());
+
+ if (CommandLine::get_instance()->a_dl_rdepend_post.argument() == "always")
+ dep_list.set_rdepend_post(p::dlro_always);
+ else if (CommandLine::get_instance()->a_dl_rdepend_post.argument() == "never")
+ dep_list.set_rdepend_post(p::dlro_never);
+ else
+ dep_list.set_rdepend_post(p::dlro_as_needed);
+
+ p::InstallOptions opts(false, false);
+ if (CommandLine::get_instance()->a_no_config_protection.specified())
+ opts.set<p::io_noconfigprotect>(true);
+ if (CommandLine::get_instance()->a_fetch.specified())
+ opts.set<p::io_fetchonly>(true);
+
+ bool had_set_targets(false), had_pkg_targets(false);
+ try
+ {
+ CommandLine::ParametersIterator q(CommandLine::get_instance()->begin_parameters()),
+ q_end(CommandLine::get_instance()->end_parameters());
+
+ for ( ; q != q_end ; ++q)
+ {
+ p::DepAtom::Pointer s(0);
+ if (s = ((env->package_set(*q))))
+ {
+ if (had_set_targets)
+ throw DoHelp("You should not specify more than one set target.");
+
+ had_set_targets = true;
+ targets->add_child(s);
+ }
+ else
+ {
+ had_pkg_targets = true;
+
+ /* we might have a dep atom, but we might just have a simple package name
+ * without a category. either should work. also allow full atoms, to make
+ * it easy to test things like '|| ( foo/bar foo/baz )'. */
+ if (std::string::npos != q->find('/'))
+ targets->add_child(p::PortageDepParser::parse(*q));
+ else
+ targets->add_child(p::DepAtom::Pointer(new p::PackageDepAtom(
+ env->package_database()->fetch_unique_qualified_package_name(
+ p::PackageNamePart(*q)))));
+ }
+ }
+
+ if (had_set_targets && had_pkg_targets)
+ throw DoHelp("You should not specify set and package targets at the same time.");
+
+ if (had_set_targets)
+ dep_list.set_reinstall(false);
+ }
+ catch (const p::AmbiguousPackageNameError & e)
+ {
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ");
+ cerr << "Ambiguous package name '" << e.name() << "'. Did you mean:" << endl;
+ for (p::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 1;
+ }
+
+ try
+ {
+ dep_list.add(targets);
+
+ int current_count(0), max_count(0), new_count(0), upgrade_count(0),
+ downgrade_count(0), new_slot_count(0), rebuild_count(0);
+
+ if (CommandLine::get_instance()->a_pretend.specified())
+ env->perform_hook(p::Hook("install_pretend_pre")("TARGETS", p::join(
+ CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters(), " ")));
+
+ std::set<p::DepTag::ConstPointer, p::DepTag::Comparator> all_tags;
+
+ for (p::DepList::Iterator dep(dep_list.begin()), dep_end(dep_list.end()) ;
+ dep != dep_end ; ++dep)
+ {
+ p::Context loop_context("When displaying DepList entry '" + stringify(*dep) + "':");
+
+ /* display name */
+ cout << "* " << colour(cl_package_name, dep->get<p::dle_name>());
+
+ /* display version, unless it's 0 and our category is "virtual" */
+ if ((p::VersionSpec("0") != dep->get<p::dle_version>()) ||
+ p::CategoryNamePart("virtual") != dep->get<p::dle_name>().get<p::qpn_category>())
+ cout << "-" << dep->get<p::dle_version>();
+
+ /* display repository, unless it's our main repository */
+ if (env->package_database()->favourite_repository() != dep->get<p::dle_repository>())
+ cout << "::" << dep->get<p::dle_repository>();
+
+ /* display slot name, unless it's 0 */
+ if (p::SlotName("0") != dep->get<p::dle_metadata>()->get<p::vm_slot>())
+ cout << colour(cl_slot, " {:" + p::stringify(
+ dep->get<p::dle_metadata>()->get<p::vm_slot>()) + "}");
+
+ /* indicate [U], [S] or [N]. display existing version, if we're
+ * already installed */
+ p::PackageDatabaseEntryCollection::Pointer existing(env->package_database()->
+ query(p::PackageDepAtom::Pointer(new p::PackageDepAtom(p::stringify(
+ dep->get<p::dle_name>()))), p::is_installed_only));
+
+ if (existing->empty())
+ {
+ cout << colour(cl_updatemode, " [N]");
+ ++new_count;
+ ++max_count;
+ }
+ else
+ {
+ existing = env->package_database()->query(p::PackageDepAtom::Pointer(
+ new p::PackageDepAtom(p::stringify(dep->get<p::dle_name>()) + ":" +
+ stringify(dep->get<p::dle_metadata>()->get<p::vm_slot>()))),
+ p::is_installed_only);
+ if (existing->empty())
+ {
+ cout << colour(cl_updatemode, " [S]");
+ ++new_slot_count;
+ ++max_count;
+ }
+ else if (existing->last()->get<p::pde_version>() < dep->get<p::dle_version>())
+ {
+ cout << colour(cl_updatemode, " [U " + p::stringify(
+ existing->last()->get<p::pde_version>()) + "]");
+ ++upgrade_count;
+ ++max_count;
+ }
+ else if (existing->last()->get<p::pde_version>() > dep->get<p::dle_version>())
+ {
+ cout << colour(cl_updatemode, " [D " + p::stringify(
+ existing->last()->get<p::pde_version>()) + "]");
+ ++downgrade_count;
+ ++max_count;
+ }
+ else
+ {
+ cout << colour(cl_updatemode, " [R]");
+ ++rebuild_count;
+ ++max_count;
+ }
+ }
+
+ /* fetch db entry */
+ p::PackageDatabaseEntry p(p::PackageDatabaseEntry(dep->get<p::dle_name>(),
+ dep->get<p::dle_version>(), dep->get<p::dle_repository>()));
+
+ /* display USE flags */
+ if (dep->get<p::dle_metadata>()->get_ebuild_interface())
+ {
+ const p::Repository::UseInterface * const use_interface(
+ env->package_database()->fetch_repository(dep->get<p::dle_repository>())->
+ get_interface<p::repo_use>());
+ std::set<p::UseFlagName> iuse;
+ p::WhitespaceTokeniser::get_instance()->tokenise(
+ dep->get<p::dle_metadata>()->get_ebuild_interface()->get<p::evm_iuse>(),
+ p::create_inserter<p::UseFlagName>(std::inserter(iuse, iuse.end())));
+
+
+ /* display normal use flags first */
+ for (std::set<p::UseFlagName>::const_iterator i(iuse.begin()), i_end(iuse.end()) ;
+ i != i_end ; ++i)
+ {
+ if (use_interface->is_expand_flag(*i))
+ continue;
+
+ if (env->query_use(*i, &p))
+ {
+ if (use_interface && use_interface->query_use_force(*i, &p))
+ cout << " " << colour(cl_flag_on, "(" + p::stringify(*i) + ")");
+ else
+ cout << " " << colour(cl_flag_on, *i);
+ }
+ else
+ {
+ if (use_interface && use_interface->query_use_mask(*i, &p))
+ cout << " " << colour(cl_flag_off, "(-" + p::stringify(*i) + ")");
+ else
+ cout << " " << colour(cl_flag_off, "-" + p::stringify(*i));
+ }
+ }
+
+ /* now display expand flags */
+ p::UseFlagName old_expand_name("OFTEN_NOT_BEEN_ON_BOATS");
+ for (std::set<p::UseFlagName>::const_iterator i(iuse.begin()), i_end(iuse.end()) ;
+ i != i_end ; ++i)
+ {
+ if ((! use_interface->is_expand_flag(*i)) ||
+ (use_interface->is_expand_hidden_flag(*i)))
+ continue;
+
+ p::UseFlagName expand_name(use_interface->expand_flag_name(*i)),
+ expand_value(use_interface->expand_flag_value(*i));
+
+ if (expand_name != old_expand_name)
+ {
+ cout << " " << expand_name << ":";
+ old_expand_name = expand_name;
+ }
+
+ if (env->query_use(*i, &p))
+ {
+ if (use_interface && use_interface->query_use_force(*i, &p))
+ cout << " " << colour(cl_flag_on, "(" + p::stringify(expand_value) + ")");
+ else
+ cout << " " << colour(cl_flag_on, expand_value);
+ }
+ else
+ {
+ if (use_interface && use_interface->query_use_mask(*i, &p))
+ cout << " " << colour(cl_flag_off, "(-" + p::stringify(expand_value) + ")");
+ else
+ cout << " " << colour(cl_flag_off, "-" + p::stringify(expand_value));
+ }
+ }
+ }
+
+ /* display tag, add tag to our post display list */
+ if (! dep->get<p::dle_tag>().empty())
+ {
+ std::string tag_titles;
+ for (std::set<p::DepTag::ConstPointer, p::DepTag::Comparator>::const_iterator
+ tag(dep->get<p::dle_tag>().begin()),
+ tag_end(dep->get<p::dle_tag>().end()) ;
+ tag != tag_end ; ++tag)
+ {
+ all_tags.insert(*tag);
+ tag_titles.append((*tag)->short_text());
+ tag_titles.append(",");
+ }
+ tag_titles.erase(tag_titles.length() - 1);
+ cout << " " << colour(cl_tag, "<" + tag_titles + ">");
+ }
+
+ cout << endl;
+ }
+
+ if (max_count != new_count + upgrade_count + downgrade_count + new_slot_count +
+ rebuild_count)
+ p::Log::get_instance()->message(p::ll_warning, p::lc_no_context,
+ "Max count doesn't add up. This is a bug!");
+
+ cout << endl << "Total: " << max_count << (max_count == 1 ? " package" : " packages");
+ if (max_count)
+ {
+ bool need_comma(false);
+ cout << " (";
+ if (new_count)
+ {
+ cout << new_count << " new";
+ need_comma = true;
+ }
+ if (upgrade_count)
+ {
+ if (need_comma)
+ cout << ", ";
+ cout << upgrade_count << (upgrade_count == 1 ? " upgrade" : " upgrades");
+ need_comma = true;
+ }
+ if (downgrade_count)
+ {
+ if (need_comma)
+ cout << ", ";
+ cout << downgrade_count << (downgrade_count == 1 ? " downgrade" : " downgrades");
+ need_comma = true;
+ }
+ if (new_slot_count)
+ {
+ if (need_comma)
+ cout << ", ";
+ cout << new_slot_count << (new_slot_count == 1 ? " in new slot" : " in new slots");
+ need_comma = true;
+ }
+ if (rebuild_count)
+ {
+ if (need_comma)
+ cout << ", ";
+ cout << rebuild_count << (rebuild_count == 1 ? " rebuild" : " rebuilds");
+ need_comma = true;
+ }
+ cout << ")";
+ }
+ cout << endl << endl;
+
+ if (CommandLine::get_instance()->a_pretend.specified() && ! all_tags.empty())
+ {
+ TagDisplayer tag_displayer;
+
+ std::set<std::string> tag_categories;
+ std::transform(
+ p::indirect_iterator<const p::DepTag>(all_tags.begin()),
+ p::indirect_iterator<const p::DepTag>(all_tags.end()),
+ std::inserter(tag_categories, tag_categories.begin()),
+ std::mem_fun_ref(&p::DepTag::category));
+
+ for (std::set<std::string>::iterator cat(tag_categories.begin()),
+ cat_end(tag_categories.end()) ; cat != cat_end ; ++cat)
+ {
+ p::DepTagCategory::ConstPointer c(p::DepTagCategoryMaker::get_instance()->
+ find_maker(*cat)());
+
+ if (! c->title().empty())
+ cout << colour(cl_heading, c->title()) << ":" << endl << endl;
+ if (! c->pre_text().empty())
+ cout << c->pre_text() << endl << endl;
+
+ for (std::set<p::DepTag::ConstPointer, p::DepTag::Comparator>::const_iterator
+ t(all_tags.begin()), t_end(all_tags.end()) ;
+ t != t_end ; ++t)
+ {
+ if ((*t)->category() != *cat)
+ continue;
+ (*t)->accept(&tag_displayer);
+ }
+ cout << endl;
+
+ if (! c->post_text().empty())
+ cout << c->post_text() << endl << endl;
+ }
+ }
+
+ if (CommandLine::get_instance()->a_pretend.specified())
+ {
+ env->perform_hook(p::Hook("install_pretend_post")("TARGETS", p::join(
+ CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters(), " ")));
+ return return_code;
+ }
+
+ if (opts.get<p::io_fetchonly>())
+ env->perform_hook(p::Hook("fetch_all_pre")("TARGETS", p::join(
+ CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters(), " ")));
+ else
+ env->perform_hook(p::Hook("install_all_pre")("TARGETS", p::join(
+ CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters(), " ")));
+
+ for (p::DepList::Iterator dep(dep_list.begin()), dep_end(dep_list.end()) ;
+ dep != dep_end ; ++dep)
+ {
+ std::string cpvr = p::stringify(dep->get<p::dle_name>()) + "-" +
+ p::stringify(dep->get<p::dle_version>()) + "::" +
+ p::stringify(dep->get<p::dle_repository>());
+
+ if (opts.get<p::io_fetchonly>())
+ {
+ cout << endl << colour(cl_heading, "Fetching " + cpvr) << endl << endl;
+
+ // TODO: some way to reset this properly would be nice.
+ cerr << xterm_title("(" + p::stringify(++current_count) + " of " +
+ p::stringify(max_count) + ") Fetching " + cpvr);
+
+ }
+ else
+ {
+ cout << endl << colour(cl_heading,
+ "Installing " + cpvr) << endl << endl;
+
+ // TODO: some way to reset this properly would be nice.
+ cerr << xterm_title("(" + p::stringify(++current_count) + " of " +
+ p::stringify(max_count) + ") Installing " + cpvr);
+ }
+
+ if (opts.get<p::io_fetchonly>())
+ env->perform_hook(p::Hook("fetch_pre")("TARGET", cpvr));
+ else
+ env->perform_hook(p::Hook("install_pre")("TARGET", cpvr));
+
+ const p::Repository::InstallableInterface * const installable_interface(
+ env->package_database()->fetch_repository(dep->get<p::dle_repository>())->
+ get_interface<p::repo_installable>());
+ if (! installable_interface)
+ throw p::InternalError(PALUDIS_HERE, "Trying to install from a non-installable repository");
+ installable_interface->install(dep->get<p::dle_name>(), dep->get<p::dle_version>(), opts);
+
+ if (opts.get<p::io_fetchonly>())
+ env->perform_hook(p::Hook("fetch_post")("TARGET", cpvr));
+ else
+ env->perform_hook(p::Hook("install_post")("TARGET", cpvr));
+
+ if (! opts.get<p::io_fetchonly>())
+ {
+ // figure out if we need to unmerge anything
+ cout << endl << colour(cl_heading,
+ "Cleaning stale versions after installing " + cpvr) << endl << endl;
+
+ // manually invalidate any installed repos, they're probably
+ // wrong now
+ for (p::PackageDatabase::RepositoryIterator r(env->package_database()->begin_repositories()),
+ r_end(env->package_database()->end_repositories()) ; r != r_end ; ++r)
+ if ((*r)->get_interface<p::repo_installed>())
+ (*r)->invalidate();
+
+ // look for packages with the same name in the same slot
+ p::PackageDatabaseEntryCollection::Pointer collision_list(env->package_database()->query(
+ p::PackageDepAtom::Pointer(new p::PackageDepAtom(
+ p::stringify(dep->get<p::dle_name>()) + ":" +
+ p::stringify(dep->get<p::dle_metadata>()->get<p::vm_slot>()))),
+ p::is_installed_only));
+
+ // don't clean the thing we just installed
+ p::PackageDatabaseEntryCollection clean_list;
+ for (p::PackageDatabaseEntryCollection::Iterator c(collision_list->begin()),
+ c_end(collision_list->end()) ; c != c_end ; ++c)
+ if (dep->get<p::dle_version>() != c->get<p::pde_version>())
+ clean_list.insert(*c);
+
+ if (clean_list.empty())
+ {
+ cout << "* No cleaning required" << endl;
+ }
+ else
+ {
+ for (p::PackageDatabaseEntryCollection::Iterator c(clean_list.begin()),
+ c_end(clean_list.end()) ; c != c_end ; ++c)
+ cout << "* " << colour(cl_package_name, *c) << endl;
+ cout << endl;
+
+ p::PackageDatabaseEntryCollection::Iterator c(clean_list.begin()),
+ c_end(clean_list.end());
+ env->perform_hook(p::Hook("uninstall_all_pre")("TARGETS", p::join(c, c_end, " ")));
+ for ( ; c != c_end ; ++c)
+ {
+ cout << endl << colour(cl_heading, "Cleaning " + p::stringify(*c)) << endl << endl;
+
+ // TODO: some way to reset this properly would be nice.
+ cerr << xterm_title("(" + p::stringify(current_count) + " of " +
+ p::stringify(max_count) + ") Cleaning " + cpvr + ": " + stringify(*c));
+
+ env->perform_hook(p::Hook("uninstall_pre")("TARGET", stringify(*c)));
+
+ const p::Repository::UninstallableInterface * const uninstall_interface(
+ env->package_database()->fetch_repository(c->get<p::pde_repository>())->
+ get_interface<p::repo_uninstallable>());
+ if (! uninstall_interface)
+ throw p::InternalError(PALUDIS_HERE, "Trying to uninstall from a non-uninstallable repo");
+ uninstall_interface->uninstall(c->get<p::pde_name>(), c->get<p::pde_version>(), opts);
+ env->perform_hook(p::Hook("uninstall_post")("TARGET", stringify(*c)));
+ }
+ env->perform_hook(p::Hook("uninstall_all_pre")("TARGETS", p::join(c, c_end, " ")));
+ }
+ }
+ }
+
+ if ((! had_set_targets) &&
+ (! CommandLine::get_instance()->a_pretend.specified()) &&
+ (! opts.get<p::io_fetchonly>()))
+ {
+ cout << endl << colour(cl_heading, "Updating world file") << endl << endl;
+ if (! CommandLine::get_instance()->a_preserve_world.specified())
+ env->add_appropriate_to_world(targets, &world_add_callback,
+ &world_skip_callback);
+ else
+ cout << "* --preserve-world was specified, skipping world adds" << endl;
+ }
+
+
+ if (opts.get<p::io_fetchonly>())
+ env->perform_hook(p::Hook("fetch_all_post")("TARGETS", p::join(
+ CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters(), " ")));
+ else
+ env->perform_hook(p::Hook("install_all_post")("TARGETS", p::join(
+ CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters(), " ")));
+
+ cout << endl;
+ }
+ catch (const p::PackageInstallActionError & e)
+ {
+ cout << endl;
+ cerr << "Install error:" << endl;
+ cerr << " * " << e.backtrace("\n * ");
+ cerr << e.message() << endl;
+
+ return_code |= 1;
+ }
+ catch (const p::NoSuchPackageError & e)
+ {
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ");
+ cerr << "No such package '" << e.name() << "'" << endl;
+ return 1;
+ }
+ catch (const p::AllMaskedError & e)
+ {
+ try
+ {
+ p::PackageDatabaseEntryCollection::ConstPointer p(env->package_database()->query(
+ p::PackageDepAtom::ConstPointer(new p::PackageDepAtom(e.query())),
+ p::is_uninstalled_only));
+ if (p->empty())
+ {
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ");
+ cerr << "All versions of '" << e.query() << "' are masked" << endl;
+ }
+ else
+ {
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ");
+ cerr << "All versions of '" << e.query() << "' are masked. Candidates are:" << endl;
+ for (p::PackageDatabaseEntryCollection::Iterator pp(p->begin()), pp_end(p->end()) ;
+ pp != pp_end ; ++pp)
+ {
+ cerr << " * " << colour(cl_package_name, *pp) << ": Masked by ";
+
+ bool need_comma(false);
+ p::MaskReasons m(env->mask_reasons(*pp));
+ for (unsigned mm = 0 ; mm < m.size() ; ++mm)
+ if (m[mm])
+ {
+ if (need_comma)
+ cerr << ", ";
+ cerr << p::MaskReason(mm);
+
+ if (p::mr_eapi == mm)
+ {
+ std::string eapi_str(env->package_database()->fetch_repository(
+ pp->get<p::pde_repository>())->version_metadata(
+ pp->get<p::pde_name>(), pp->get<p::pde_version>())->get<p::vm_eapi>());
+
+ cerr << " ( " << colour(cl_red, eapi_str) << " )";
+ }
+ else if (p::mr_license == mm)
+ {
+ cerr << " ";
+
+ LicenceDisplayer ld(cerr, env, &*pp);
+ env->package_database()->fetch_repository(
+ pp->get<p::pde_repository>())->version_metadata(
+ pp->get<p::pde_name>(), pp->get<p::pde_version>())->license()->
+ accept(&ld);
+ }
+ else if (p::mr_keyword == mm)
+ {
+ p::VersionMetadata::ConstPointer m(env->package_database()->fetch_repository(
+ pp->get<p::pde_repository>())->version_metadata(
+ pp->get<p::pde_name>(), pp->get<p::pde_version>()));
+ if (m->get_ebuild_interface())
+ {
+ std::set<p::KeywordName> keywords;
+ p::WhitespaceTokeniser::get_instance()->tokenise(
+ m->get_ebuild_interface()->get<p::evm_keywords>(),
+ p::create_inserter<p::KeywordName>(
+ std::inserter(keywords, keywords.end())));
+
+ cerr << " ( " << colour(cl_red, p::join(keywords.begin(),
+ keywords.end(), " ")) << " )";
+ }
+ }
+
+ need_comma = true;
+ }
+ cerr << endl;
+ }
+ }
+ }
+ catch (...)
+ {
+ throw e;
+ }
+
+ return 1;
+ }
+ catch (const p::UseRequirementsNotMetError & e)
+ {
+ cout << endl;
+ cerr << "DepList USE requirements not met error:" << endl;
+ cerr << " * " << e.backtrace("\n * ") << e.message() << endl;
+ cerr << endl;
+ cerr << "This error usually indicates that one of the packages you are trying to" << endl;
+ cerr << "install requires that another package be built with particular USE flags" << endl;
+ cerr << "enabled or disabled. You may be able to work around this restriction by" << endl;
+ cerr << "adjusting your use.conf." << endl;
+ cerr << endl;
+
+ return_code |= 1;
+ }
+ catch (const p::DepListStackTooDeepError & e)
+ {
+ cout << endl;
+ cerr << "DepList stack too deep error:" << endl;
+ cerr << " * " << e.backtrace("\n * ") << e.message() << endl;
+ cerr << endl;
+ cerr << "Try '--dl-max-stack-depth " << std::max(
+ CommandLine::get_instance()->a_dl_max_stack_depth.argument() * 2, 100)
+ << "'." << endl << endl;
+
+ return_code |= 1;
+ }
+ catch (const p::DepListError & e)
+ {
+ cout << endl;
+ cerr << "Dependency error:" << endl;
+ cerr << " * " << e.backtrace("\n * ") << e.message() << " ("
+ << e.what() << ")" << endl;
+ cerr << endl;
+
+ return_code |= 1;
+ }
+
+ return return_code;
+}
+
diff --git a/0.4.0/src/install.hh b/0.4.0/src/install.hh
new file mode 100644
index 000000000..ba3623dfa
--- /dev/null
+++ b/0.4.0/src/install.hh
@@ -0,0 +1,32 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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_DEPGRAPH_HH
+#define PALUDIS_GUARD_SRC_DEPGRAPH_HH 1
+
+#include "src/command_line.hh"
+
+/** \file
+ * Declaration for the do_install function.
+ */
+
+/// Handle --install.
+int do_install();
+
+#endif
diff --git a/0.4.0/src/install_TEST b/0.4.0/src/install_TEST
new file mode 100755
index 000000000..eab20a9d0
--- /dev/null
+++ b/0.4.0/src/install_TEST
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+PALUDIS_HOME=./install_TEST_dir/config/ ./paludis --config-suffix install-test --install target || exit 1
+./install_TEST_dir/root/usr/bin/testbin | grep success >/dev/null
+
diff --git a/0.4.0/src/install_TEST_cleanup.sh b/0.4.0/src/install_TEST_cleanup.sh
new file mode 100755
index 000000000..92bb92a5a
--- /dev/null
+++ b/0.4.0/src/install_TEST_cleanup.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d install_TEST_dir ] ; then
+ rm -fr install_TEST_dir
+else
+ true
+fi
+
+
+
diff --git a/0.4.0/src/install_TEST_setup.sh b/0.4.0/src/install_TEST_setup.sh
new file mode 100755
index 000000000..b511e8ea9
--- /dev/null
+++ b/0.4.0/src/install_TEST_setup.sh
@@ -0,0 +1,121 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir install_TEST_dir || exit 1
+cd install_TEST_dir || exit 1
+
+mkdir -p config/.paludis-install-test
+cat <<END > config/.paludis-install-test/specpath
+root = `pwd`/root
+config-suffix =
+END
+
+mkdir -p root/${SYSCONFDIR}/paludis/repositories
+cat <<END > root/${SYSCONFDIR}/paludis/use.conf
+* foo
+END
+
+cat <<END > root/${SYSCONFDIR}/paludis/licenses.conf
+* *
+END
+
+cat <<END > root/${SYSCONFDIR}/paludis/keywords.conf
+* test
+END
+
+cat <<END > root/${SYSCONFDIR}/paludis/bashrc
+export CHOST="my-chost"
+export USER_BASHRC_WAS_USED=yes
+END
+
+cat <<END > root/${SYSCONFDIR}/paludis/repositories/repo1.conf
+location = `pwd`/repo1
+cache = /var/empty
+format = portage
+profiles = \${location}/profiles/testprofile \${location}/profiles/anothertestprofile
+buildroot = `pwd`/build
+END
+
+mkdir -p root/tmp
+touch root/${SYSCONFDIR}/ld.so.conf
+
+mkdir -p repo1/{eclass,distfiles,profiles/{testprofile,anothertestprofile},test-category/target/files} || exit 1
+
+mkdir -p src/target-2
+cat <<"END" > src/target-2/testbin
+#!/bin/bash
+echo "Test was a success"
+END
+chmod +x src/target-2/testbin
+cd src
+tar zcf target-2.tar.gz target-2/
+mv target-2.tar.gz ../repo1/distfiles/
+cd ..
+rm -fr src
+
+cd repo1 || exit 1
+echo "test-repo-1" > profiles/repo_name || exit 1
+cat <<END > profiles/categories || exit 1
+test-category
+END
+cat <<END > profiles/testprofile/make.defaults
+ARCH=test
+USERLAND=test
+KERNEL=test
+TESTPROFILE_WAS_SOURCED=yes
+PROFILE_ORDERING=1
+END
+cat <<END > profiles/anothertestprofile/make.defaults
+ARCH=test
+USERLAND=test
+KERNEL=test
+ANOTHERTESTPROFILE_WAS_SOURCED=yes
+PROFILE_ORDERING=2
+END
+
+cat <<"END" > eclass/foo.eclass
+inherit_was_ok() {
+ true
+}
+END
+
+cat <<"END" > test-category/target/target-2.ebuild || exit 1
+inherit foo
+
+DESCRIPTION="Test target"
+HOMEPAGE="http://paludis.berlios.de/"
+SRC_URI="http://invalid.domain/${P}.tar.gz oink? ( http://example.com/foo.tar.gz )"
+SLOT="0"
+IUSE="oink"
+LICENSE="GPL-2"
+KEYWORDS="test"
+
+pkg_setup() {
+ [[ -z "${USER_BASHRC_WAS_USED}" ]] && die "bad env"
+ [[ -z "${TESTPROFILE_WAS_SOURCED}" ]] && die "testprofile not sourced"
+ [[ -z "${ANOTHERTESTPROFILE_WAS_SOURCED}" ]] && die "anothertestprofile not sourced"
+ [[ ${PROFILE_ORDERING:-0} != 2 ]] && die "bad profile source ordering"
+}
+
+src_unpack() {
+ hasq "${P}.tar.gz" ${A} || die
+ hasq "${P}.tar.gz" ${AA} || die
+ hasq "foo.tar.gz" ${A} && die
+ hasq "foo.tar.gz" ${AA} || die
+ unpack ${A}
+}
+
+src_compile() {
+ inherit_was_ok || die "inherit didn't work"
+}
+
+src_test() {
+ ./testbin | grep success || die "failure"
+}
+
+src_install() {
+ dobin testbin
+}
+END
+cd ..
+
diff --git a/0.4.0/src/licence.cc b/0.4.0/src/licence.cc
new file mode 100644
index 000000000..bb1ebfd2c
--- /dev/null
+++ b/0.4.0/src/licence.cc
@@ -0,0 +1,66 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "licence.hh"
+#include "colour.hh"
+#include <ostream>
+
+void
+LicenceDisplayer::visit(const paludis::AllDepAtom * atom)
+{
+ stream << "( ";
+ std::for_each(atom->begin(), atom->end(), paludis::accept_visitor(this));
+ stream << ") ";
+}
+
+void
+LicenceDisplayer::visit(const paludis::AnyDepAtom * atom)
+{
+ stream << "|| ( ";
+ std::for_each(atom->begin(), atom->end(), paludis::accept_visitor(this));
+ stream << ") ";
+}
+
+void
+LicenceDisplayer::visit(const paludis::UseDepAtom * atom)
+{
+ stream << atom->flag() << "? ( ";
+ std::for_each(atom->begin(), atom->end(), paludis::accept_visitor(this));
+ stream << ") ";
+}
+
+void
+LicenceDisplayer::visit(const paludis::PlainTextDepAtom * atom)
+{
+ if (env->accept_license(atom->text(), db_entry))
+ stream << colour(cl_green, atom->text());
+ else
+ stream << colour(cl_red, "(" + atom->text() + ")!");
+ stream << " ";
+}
+
+LicenceDisplayer::LicenceDisplayer(
+ std::ostream & s,
+ const paludis::Environment * const e,
+ const paludis::PackageDatabaseEntry * const d) :
+ stream(s),
+ env(e),
+ db_entry(d)
+{
+}
diff --git a/0.4.0/src/licence.hh b/0.4.0/src/licence.hh
new file mode 100644
index 000000000..df3cae7fa
--- /dev/null
+++ b/0.4.0/src/licence.hh
@@ -0,0 +1,67 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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_LICENCE_HH
+#define PALUDIS_GUARD_SRC_LICENCE_HH 1
+
+#include <paludis/paludis.hh>
+#include <iosfwd>
+
+/**
+ * Display licences.
+ */
+struct LicenceDisplayer :
+ paludis::DepAtomVisitorTypes::ConstVisitor
+{
+ /// Our stream.
+ std::ostream & stream;
+
+ /// Our environment.
+ const paludis::Environment * const env;
+
+ /// Our db entry.
+ const paludis::PackageDatabaseEntry * const db_entry;
+
+ /// Constructor.
+ LicenceDisplayer(
+ std::ostream & stream,
+ const paludis::Environment * const e,
+ const paludis::PackageDatabaseEntry * const d);
+
+ ///\name Visit methods
+ ///{
+ void visit(const paludis::AllDepAtom * atom);
+
+ void visit(const paludis::AnyDepAtom * atom);
+
+ void visit(const paludis::UseDepAtom * atom);
+
+ void visit(const paludis::PlainTextDepAtom * atom);
+
+ void visit(const paludis::PackageDepAtom *)
+ {
+ }
+
+ void visit(const paludis::BlockDepAtom *)
+ {
+ }
+ ///}
+};
+
+#endif
diff --git a/0.4.0/src/list.cc b/0.4.0/src/list.cc
new file mode 100644
index 000000000..40c1efaf4
--- /dev/null
+++ b/0.4.0/src/list.cc
@@ -0,0 +1,324 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "list.hh"
+#include <iomanip>
+#include <iostream>
+#include <list>
+#include <map>
+#include <paludis/paludis.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/visitor.hh>
+
+namespace p = paludis;
+
+int
+do_list_repositories()
+{
+ int ret_code(1);
+
+ p::Context context("When performing list-repositories action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ for (p::IndirectIterator<p::PackageDatabase::RepositoryIterator, const p::Repository>
+ r(env->package_database()->begin_repositories()), r_end(env->package_database()->end_repositories()) ;
+ r != r_end ; ++r)
+ {
+ if (CommandLine::get_instance()->a_repository.specified())
+ if (CommandLine::get_instance()->a_repository.args_end() == std::find(
+ CommandLine::get_instance()->a_repository.args_begin(),
+ CommandLine::get_instance()->a_repository.args_end(),
+ stringify(r->name())))
+ continue;
+
+ ret_code = 0;
+
+ std::cout << "* " << colour(cl_package_name, r->name()) << std::endl;
+
+ p::RepositoryInfo::ConstPointer ii(r->info(false));
+ for (p::RepositoryInfo::SectionIterator i(ii->begin_sections()),
+ i_end(ii->end_sections()) ; i != i_end ; ++i)
+ {
+ std::cout << " " << colour(cl_heading, i->heading() + ":") << std::endl;
+ for (p::RepositoryInfoSection::KeyValueIterator k(i->begin_kvs()),
+ k_end(i->end_kvs()) ; k != k_end ; ++k)
+ std::cout << " " << std::setw(22) << std::left << (p::stringify(k->first) + ":")
+ << std::setw(0) << " " << k->second << std::endl;
+ std::cout << std::endl;
+ }
+ }
+
+ return ret_code;
+}
+
+int
+do_list_categories()
+{
+ int ret_code(1);
+
+ p::Context context("When performing list-categories action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ std::map<p::CategoryNamePart, std::list<p::RepositoryName> > cats;
+
+ for (p::IndirectIterator<p::PackageDatabase::RepositoryIterator, const p::Repository>
+ r(env->package_database()->begin_repositories()), r_end(env->package_database()->end_repositories()) ;
+ r != r_end ; ++r)
+ {
+ if (CommandLine::get_instance()->a_repository.specified())
+ if (CommandLine::get_instance()->a_repository.args_end() == std::find(
+ CommandLine::get_instance()->a_repository.args_begin(),
+ CommandLine::get_instance()->a_repository.args_end(),
+ stringify(r->name())))
+ continue;
+
+ p::CategoryNamePartCollection::ConstPointer cat_names(r->category_names());
+ for (p::CategoryNamePartCollection::Iterator c(cat_names->begin()), c_end(cat_names->end()) ;
+ c != c_end ; ++c)
+ cats[*c].push_back(r->name());
+ }
+
+ for (std::map<p::CategoryNamePart, std::list<p::RepositoryName > >::const_iterator
+ c(cats.begin()), c_end(cats.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->first)))
+ continue;
+
+ ret_code = 0;
+
+ std::cout << "* " << colour(cl_package_name, c->first) << std::endl;
+ std::cout << " " << std::setw(22) << std::left << "found in:" <<
+ std::setw(0) << " " << p::join(c->second.begin(), c->second.end(), ", ") << std::endl;
+ std::cout << std::endl;
+ }
+
+ return ret_code;
+}
+
+int
+do_list_packages()
+{
+ int ret_code(1);
+
+ p::Context context("When performing list-packages action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ std::map<p::QualifiedPackageName, std::list<p::RepositoryName> > pkgs;
+
+ for (p::IndirectIterator<p::PackageDatabase::RepositoryIterator, const p::Repository>
+ r(env->package_database()->begin_repositories()), r_end(env->package_database()->end_repositories()) ;
+ r != r_end ; ++r)
+ {
+ if (CommandLine::get_instance()->a_repository.specified())
+ if (CommandLine::get_instance()->a_repository.args_end() == std::find(
+ CommandLine::get_instance()->a_repository.args_begin(),
+ CommandLine::get_instance()->a_repository.args_end(),
+ stringify(r->name())))
+ continue;
+
+ p::CategoryNamePartCollection::ConstPointer cat_names(r->category_names());
+ for (p::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;
+
+ p::QualifiedPackageNameCollection::ConstPointer pkg_names(r->package_names(*c));
+ for (p::QualifiedPackageNameCollection::Iterator p(pkg_names->begin()), p_end(pkg_names->end()) ;
+ p != p_end ; ++p)
+ pkgs[*p].push_back(r->name());
+ }
+ }
+
+ for (std::map<p::QualifiedPackageName, std::list<p::RepositoryName > >::const_iterator
+ p(pkgs.begin()), p_end(pkgs.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->first.get<p::qpn_package>())))
+ continue;
+
+ ret_code = 0;
+
+ std::cout << "* " << colour(cl_package_name, p->first) << std::endl;
+ std::cout << " " << std::setw(22) << std::left << "found in:" <<
+ std::setw(0) << " " << p::join(p->second.begin(), p->second.end(), ", ") << std::endl;
+ std::cout << std::endl;
+ }
+
+ return ret_code;
+}
+
+namespace
+{
+ /**
+ * Print dependency atoms as returned by do_package_set("security").
+ *
+ * \ingroup grpvulnerabilitiesprinter
+ */
+ class VulnerabilitiesPrinter :
+ public p::DepAtomVisitorTypes::ConstVisitor
+ {
+ private:
+ unsigned _size;
+
+ public:
+ /**
+ * Constructor.
+ */
+ VulnerabilitiesPrinter() :
+ _size(0)
+ {
+ }
+
+ /// \name Visit functions
+ ///{
+ void visit(const p::AllDepAtom * const);
+
+ void visit(const p::AnyDepAtom * const);
+
+ void visit(const p::UseDepAtom * const);
+
+ void visit(const p::PackageDepAtom * const);
+
+ void visit(const p::PlainTextDepAtom * const);
+
+ void visit(const p::BlockDepAtom * const);
+ ///}
+
+ /**
+ * Return number of visited atoms.
+ */
+ unsigned size() const
+ {
+ return _size;
+ }
+ };
+
+ void
+ VulnerabilitiesPrinter::visit(const p::AllDepAtom * const a)
+ {
+ std::for_each(a->begin(), a->end(), p::accept_visitor(this));
+ }
+
+ void
+ VulnerabilitiesPrinter::visit(const p::AnyDepAtom * const a)
+ {
+ std::for_each(a->begin(), a->end(), p::accept_visitor(this));
+ }
+
+ void
+ VulnerabilitiesPrinter::visit(const p::UseDepAtom * const a)
+ {
+ p::Log::get_instance()->message(p::ll_warning, p::lc_no_context,
+ "UseDepAtom encounter in do_package_set(\"security\").");
+ std::for_each(a->begin(), a->end(), p::accept_visitor(this));
+ }
+
+ void
+ VulnerabilitiesPrinter::visit(const p::PackageDepAtom * const a)
+ {
+ p::QualifiedPackageName q(a->package());
+
+ std::string c(p::stringify(q.get<p::qpn_category>()));
+ 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(),
+ c))
+ return;
+
+ std::string p(p::stringify(q.get<p::qpn_package>()));
+ 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(),
+ p))
+ return;
+
+ std::cout << "* " << colour(cl_package_name, p::stringify(q));
+ if (0 != a->tag())
+ std::cout << "-" << p::stringify(*a->version_spec_ptr());
+ if (0 != a->tag())
+ std::cout << " " << colour(cl_tag, "<" + a->tag()->short_text() + ">");
+ std::cout << std::endl;
+ ++_size;
+ }
+
+ void
+ VulnerabilitiesPrinter::visit(const p::PlainTextDepAtom * const)
+ {
+ }
+
+ void
+ VulnerabilitiesPrinter::visit(const p::BlockDepAtom * const)
+ {
+ }
+}
+
+int
+do_list_vulnerabilities()
+{
+ int ret_code = 0;
+
+ p::Context context("When performing list-vulnerabilities action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+ p::PackageSetOptions opts(true);
+
+ p::CompositeDepAtom::Pointer vulnerabilities(new p::AllDepAtom);
+
+ for (p::IndirectIterator<p::PackageDatabase::RepositoryIterator, const p::Repository>
+ r(env->package_database()->begin_repositories()), r_end(env->package_database()->end_repositories()) ;
+ r != r_end ; ++r)
+ {
+ if (CommandLine::get_instance()->a_repository.specified())
+ if (CommandLine::get_instance()->a_repository.args_end() == std::find(
+ CommandLine::get_instance()->a_repository.args_begin(),
+ CommandLine::get_instance()->a_repository.args_end(),
+ stringify(r->name())))
+ continue;
+
+ if (! r->get_interface<p::repo_sets>())
+ continue;
+
+ p::DepAtom::Pointer dep = r->get_interface<p::repo_sets>()->package_set("security", opts);
+ if (0 != dep)
+ vulnerabilities->add_child(dep);
+ }
+
+ VulnerabilitiesPrinter vp;
+ std::for_each(vulnerabilities->begin(), vulnerabilities->end(), p::accept_visitor(&vp));
+
+ if (vp.size() == 0)
+ ret_code = 1;
+
+ return ret_code;
+}
+
diff --git a/0.4.0/src/list.hh b/0.4.0/src/list.hh
new file mode 100644
index 000000000..5cae90f3e
--- /dev/null
+++ b/0.4.0/src/list.hh
@@ -0,0 +1,39 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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_LIST_REPOSITORIES_HH
+#define PALUDIS_GUARD_SRC_LIST_REPOSITORIES_HH 1
+
+/** \file
+ * Declaration for the do_list_repositories and do_list_categories functions.
+ */
+
+/// Handle --list-repositories.
+int do_list_repositories();
+
+/// Handle --list-categories.
+int do_list_categories();
+
+/// Handle --list-packages.
+int do_list_packages();
+
+/// Handle --list-vulnerabilities.
+int do_list_vulnerabilities();
+
+#endif
diff --git a/0.4.0/src/list_dep_tag_categories_TEST b/0.4.0/src/list_dep_tag_categories_TEST
new file mode 100755
index 000000000..40fa15c1a
--- /dev/null
+++ b/0.4.0/src/list_dep_tag_categories_TEST
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+PALUDIS_SKIP_CONFIG=yes ./paludis --list-dep-tag-categories
diff --git a/0.4.0/src/list_repository_formats_TEST b/0.4.0/src/list_repository_formats_TEST
new file mode 100755
index 000000000..487513c46
--- /dev/null
+++ b/0.4.0/src/list_repository_formats_TEST
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+PALUDIS_SKIP_CONFIG=yes ./paludis --list-repository-formats
diff --git a/0.4.0/src/list_sync_formats_TEST b/0.4.0/src/list_sync_formats_TEST
new file mode 100755
index 000000000..f638b2263
--- /dev/null
+++ b/0.4.0/src/list_sync_formats_TEST
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+PALUDIS_SKIP_CONFIG=yes ./paludis --list-sync-protocols
diff --git a/0.4.0/src/news.cc b/0.4.0/src/news.cc
new file mode 100644
index 000000000..68ce07088
--- /dev/null
+++ b/0.4.0/src/news.cc
@@ -0,0 +1,51 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "src/colour.hh"
+#include "src/news.hh"
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <paludis/paludis.hh>
+#include <string>
+
+/** \file
+ * Handle the --update-news action for the main paludis program.
+ */
+
+namespace p = paludis;
+
+int
+do_update_news()
+{
+ int return_code(0);
+
+ p::Context context("When performing update-news action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ for (p::PackageDatabase::RepositoryIterator r(env->package_database()->begin_repositories()),
+ r_end(env->package_database()->end_repositories()) ; r != r_end ; ++r)
+ if ((*r)->get_interface<p::repo_news>())
+ (*r)->get_interface<p::repo_news>()->update_news();
+
+ return return_code;
+}
+
+
+
diff --git a/0.4.0/src/news.hh b/0.4.0/src/news.hh
new file mode 100644
index 000000000..8d8b54bea
--- /dev/null
+++ b/0.4.0/src/news.hh
@@ -0,0 +1,34 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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_NEWS_HH
+#define PALUDIS_GUARD_SRC_NEWS_HH 1
+
+#include "src/command_line.hh"
+
+/** \file
+ * Declaration for the do_update_news function.
+ */
+
+/// Handle --update-news.
+int do_update_news();
+
+#endif
+
+
diff --git a/0.4.0/src/owner.cc b/0.4.0/src/owner.cc
new file mode 100644
index 000000000..b83393bfd
--- /dev/null
+++ b/0.4.0/src/owner.cc
@@ -0,0 +1,131 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "owner.hh"
+#include "colour.hh"
+#include <paludis/paludis.hh>
+#include <iostream>
+
+namespace p = paludis;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace
+{
+ struct ContentsFinder :
+ p::ContentsVisitorTypes::ConstVisitor
+ {
+ bool found;
+ const std::string query;
+ const bool full;
+
+ ContentsFinder(const std::string & q, bool f) :
+ found(false),
+ query(q),
+ full(f)
+ {
+ }
+
+ void handle(const std::string & e)
+ {
+ if (full)
+ found |= (e == query);
+ else
+ found |= (std::string::npos != e.find(query));
+ }
+
+ void visit(const p::ContentsFileEntry * const e)
+ {
+ handle(e->name());
+ }
+
+ void visit(const p::ContentsDirEntry * const e)
+ {
+ handle(e->name());
+ }
+
+ void visit(const p::ContentsSymEntry * const e)
+ {
+ handle(e->name());
+ }
+
+ void visit(const p::ContentsMiscEntry * const e)
+ {
+ handle(e->name());
+ }
+ };
+}
+
+void
+do_one_owner(
+ const p::Environment * const env,
+ const std::string & query)
+{
+ cout << "* " << colour(cl_package_name, query) << endl;
+
+ for (p::PackageDatabase::RepositoryIterator r(env->package_database()->begin_repositories()),
+ r_end(env->package_database()->end_repositories()) ; r != r_end ; ++r)
+ {
+ if (! (*r)->get_interface<p::repo_installed>())
+ continue;
+
+ p::CategoryNamePartCollection::ConstPointer cats((*r)->category_names());
+ for (p::CategoryNamePartCollection::Iterator c(cats->begin()),
+ c_end(cats->end()) ; c != c_end ; ++c)
+ {
+ p::QualifiedPackageNameCollection::ConstPointer pkgs((*r)->package_names(*c));
+ for (p::QualifiedPackageNameCollection::Iterator p(pkgs->begin()),
+ p_end(pkgs->end()) ; p != p_end ; ++p)
+ {
+ p::VersionSpecCollection::ConstPointer vers((*r)->version_specs(*p));
+ for (p::VersionSpecCollection::Iterator v(vers->begin()),
+ v_end(vers->end()) ; v != v_end ; ++v)
+ {
+ p::PackageDatabaseEntry e(*p, *v, (*r)->name());
+ p::Contents::ConstPointer contents((*r)->get_interface<p::repo_installed>()->
+ contents(*p, *v));
+ ContentsFinder d(query, CommandLine::get_instance()->a_full_match.specified());
+ std::for_each(contents->begin(), contents->end(), accept_visitor(&d));
+ if (d.found)
+ cout << " " << e << endl;
+ }
+ }
+ }
+ }
+
+ cout << endl;
+}
+
+
+int
+do_owner()
+{
+ int return_code(0);
+ p::Context context("When performing owner action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ CommandLine::ParametersIterator q(CommandLine::get_instance()->begin_parameters()),
+ q_end(CommandLine::get_instance()->end_parameters());
+ for ( ; q != q_end ; ++q)
+ do_one_owner(env, *q);
+
+ return return_code;
+}
+
diff --git a/0.4.0/src/owner.hh b/0.4.0/src/owner.hh
new file mode 100644
index 000000000..672b652a2
--- /dev/null
+++ b/0.4.0/src/owner.hh
@@ -0,0 +1,30 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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_OWNER_HH
+#define PALUDIS_GUARD_SRC_OWNER_HH 1
+
+/** \file
+ * Declaration for the do_owner function.
+ */
+
+/// Handle --owner.
+int do_owner();
+
+#endif
diff --git a/0.4.0/src/paludis.cc b/0.4.0/src/paludis.cc
new file mode 100644
index 000000000..0bdc82383
--- /dev/null
+++ b/0.4.0/src/paludis.cc
@@ -0,0 +1,435 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "src/applets.hh"
+#include "src/colour.hh"
+#include "src/command_line.hh"
+#include "src/contents.hh"
+#include "src/install.hh"
+#include "src/list.hh"
+#include "src/news.hh"
+#include "src/owner.hh"
+#include "src/query.hh"
+#include "src/sync.hh"
+#include "src/uninstall.hh"
+#include "config.h"
+
+#include <paludis/paludis.hh>
+#include <paludis/util/util.hh>
+
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <cstdlib>
+
+/** \file
+ * Main paludis program.
+ */
+
+namespace p = paludis;
+
+using std::cout;
+using std::cerr;
+using std::endl;
+
+#ifndef DOXYGEN
+struct DoVersion
+{
+};
+#endif
+
+namespace
+{
+ void display_version()
+ {
+ cout << PALUDIS_PACKAGE << " " << 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 << "SYSCONFDIR: " << SYSCONFDIR << endl;
+ cout << "LIBEXECDIR: " << LIBEXECDIR << endl;
+ cout << "stdlib: "
+#if defined(__GLIBCXX__)
+# define XSTRINGIFY(x) #x
+# define STRINGIFY(x) XSTRINGIFY(x)
+ << "GNU libstdc++ " << STRINGIFY(__GLIBCXX__)
+#endif
+ << endl;
+
+ cout << "libebt: " << LIBEBT_VERSION_MAJOR << "." << LIBEBT_VERSION_MINOR
+ << "." << LIBEBT_VERSION_MICRO << endl;
+#if HAVE_SANDBOX
+ cout << "sandbox: enabled" << endl;
+#else
+ cout << "sandbox: disabled" << endl;
+#endif
+ }
+
+ void display_info()
+ {
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ for (p::IndirectIterator<p::PackageDatabase::RepositoryIterator, const p::Repository>
+ r(env->package_database()->begin_repositories()), r_end(env->package_database()->end_repositories()) ;
+ r != r_end ; ++r)
+ {
+ cout << "Repository " << colour(cl_package_name, r->name()) << ":" << endl;
+
+ p::RepositoryInfo::ConstPointer ii(r->info(true));
+ for (p::RepositoryInfo::SectionIterator i(ii->begin_sections()),
+ i_end(ii->end_sections()) ; i != i_end ; ++i)
+ {
+ cout << " " << colour(cl_heading, i->heading() + ":") << endl;
+ for (p::RepositoryInfoSection::KeyValueIterator k(i->begin_kvs()),
+ k_end(i->end_kvs()) ; k != k_end ; ++k)
+ cout << " " << std::setw(22) << std::left << (p::stringify(k->first) + ":")
+ << std::setw(0) << " " << k->second << endl;
+ cout << endl;
+ }
+ }
+
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ p::Context context("In main program:");
+
+ try
+ {
+ context.change_context("When parsing command line arguments:");
+
+ CommandLine::get_instance()->run(argc, argv);
+
+ 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())
+ p::Log::get_instance()->set_log_level(p::ll_qa);
+ else if (CommandLine::get_instance()->a_log_level.argument() == "debug")
+ p::Log::get_instance()->set_log_level(p::ll_debug);
+ else if (CommandLine::get_instance()->a_log_level.argument() == "qa")
+ p::Log::get_instance()->set_log_level(p::ll_qa);
+ else if (CommandLine::get_instance()->a_log_level.argument() == "warning")
+ p::Log::get_instance()->set_log_level(p::ll_warning);
+ else if (CommandLine::get_instance()->a_log_level.argument() == "silent")
+ p::Log::get_instance()->set_log_level(p::ll_silent);
+ else
+ throw DoHelp("bad value for --log-level");
+
+ p::Log::get_instance()->set_program_name(argv[0]);
+
+ if (1 != (CommandLine::get_instance()->a_query.specified() +
+ CommandLine::get_instance()->a_version.specified() +
+ CommandLine::get_instance()->a_install.specified() +
+ CommandLine::get_instance()->a_uninstall.specified() +
+ CommandLine::get_instance()->a_sync.specified() +
+ CommandLine::get_instance()->a_list_repositories.specified() +
+ CommandLine::get_instance()->a_list_categories.specified() +
+ CommandLine::get_instance()->a_list_packages.specified() +
+ CommandLine::get_instance()->a_list_sync_protocols.specified() +
+ CommandLine::get_instance()->a_list_repository_formats.specified() +
+ CommandLine::get_instance()->a_list_dep_tag_categories.specified() +
+ CommandLine::get_instance()->a_list_vulnerabilities.specified() +
+ CommandLine::get_instance()->a_contents.specified() +
+ CommandLine::get_instance()->a_owner.specified() +
+ CommandLine::get_instance()->a_has_version.specified() +
+ CommandLine::get_instance()->a_update_news.specified() +
+ CommandLine::get_instance()->a_environment_variable.specified() +
+ CommandLine::get_instance()->a_configuration_variable.specified() +
+ CommandLine::get_instance()->a_info.specified() +
+ CommandLine::get_instance()->a_best_version.specified()))
+ {
+ if ((1 == std::distance(CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters())) &&
+ ("moo" == *CommandLine::get_instance()->begin_parameters()))
+ {
+ cout << endl;
+ cout << " ______________________________" << endl;
+ cout << "( Ugh. Another Portage user... )" << endl;
+ cout << " ------------------------------ " << endl;
+ cout << " o" << endl;
+ cout << " o" << endl;
+ cout << " ^__^ /" << endl;
+ cout << " (" << colour(cl_bold_pink, "oo") << ")\\_______/ _________" << endl;
+ cout << " (__)\\ )=( ____|_ \\_____" << endl;
+ cout << " ||----w | \\ \\ \\_____ |" << endl;
+ cout << " || || || ||" << endl;
+ cout << endl;
+ return EXIT_SUCCESS;
+ }
+ else
+ throw DoHelp("you should specify exactly one action");
+ }
+
+ /* these actions don't need DefaultConfig */
+
+ if (CommandLine::get_instance()->a_list_sync_protocols.specified())
+ {
+ if (! CommandLine::get_instance()->empty())
+ throw DoHelp("list-sync-protocols action takes no parameters");
+
+ return do_list_sync_protocols();
+ }
+
+ if (CommandLine::get_instance()->a_list_repository_formats.specified())
+ {
+ if (! CommandLine::get_instance()->empty())
+ throw DoHelp("list-repository-formats action takes no parameters");
+
+ return do_list_repository_formats();
+ }
+
+ if (CommandLine::get_instance()->a_list_dep_tag_categories.specified())
+ {
+ if (! CommandLine::get_instance()->empty())
+ throw DoHelp("list-dep-tag-categories action takes no parameters");
+
+ return do_list_dep_tag_categories();
+ }
+
+ if (CommandLine::get_instance()->a_list_vulnerabilities.specified())
+ {
+ if (! CommandLine::get_instance()->empty())
+ throw DoHelp("list-vulnerabilities action takes no paramters");
+
+ return do_list_vulnerabilities();
+ }
+
+ /* these actions do need DefaultConfig */
+
+ try
+ {
+ std::string paludis_command(argv[0]);
+ if (CommandLine::get_instance()->a_config_suffix.specified())
+ {
+ p::DefaultConfig::set_config_suffix(CommandLine::get_instance()->a_config_suffix.argument());
+ paludis_command.append(" --config-suffix " +
+ CommandLine::get_instance()->a_config_suffix.argument());
+ }
+ paludis_command.append(" --log-level " + CommandLine::get_instance()->a_log_level.argument());
+ p::DefaultConfig::get_instance()->set_paludis_command(paludis_command);
+ }
+ catch (const p::DefaultConfigError & e)
+ {
+ if (CommandLine::get_instance()->a_info.specified())
+ {
+ display_version();
+ cout << endl;
+ cout << "Cannot complete --info output due to configuration exception" << endl;
+ }
+ throw;
+ }
+
+ if (CommandLine::get_instance()->a_info.specified())
+ {
+ display_version();
+ cout << endl;
+ display_info();
+ cout << endl;
+ return EXIT_SUCCESS;
+ }
+
+ if (CommandLine::get_instance()->a_query.specified())
+ {
+ if (CommandLine::get_instance()->empty())
+ throw DoHelp("query action requires at least one parameter");
+
+ return do_query();
+ }
+
+ if (CommandLine::get_instance()->a_install.specified())
+ {
+ if (CommandLine::get_instance()->empty())
+ throw DoHelp("install action requires at least one parameter");
+
+ return do_install();
+ }
+
+ if (CommandLine::get_instance()->a_uninstall.specified())
+ {
+ if (CommandLine::get_instance()->empty())
+ throw DoHelp("uninstall action requires at least one parameter");
+
+ return do_uninstall();
+ }
+
+ if (CommandLine::get_instance()->a_sync.specified())
+ {
+ return do_sync();
+ }
+
+ if (CommandLine::get_instance()->a_list_repositories.specified())
+ {
+ if (! CommandLine::get_instance()->empty())
+ throw DoHelp("list-repositories action takes no parameters");
+
+ return do_list_repositories();
+ }
+
+ if (CommandLine::get_instance()->a_list_categories.specified())
+ {
+ if (! CommandLine::get_instance()->empty())
+ throw DoHelp("list-categories action takes no parameters");
+
+ return do_list_categories();
+ }
+
+ if (CommandLine::get_instance()->a_list_packages.specified())
+ {
+ if (! CommandLine::get_instance()->empty())
+ throw DoHelp("list-packages action takes no parameters");
+
+ return do_list_packages();
+ }
+
+ if (CommandLine::get_instance()->a_contents.specified())
+ {
+ if (CommandLine::get_instance()->empty())
+ throw DoHelp("contents action requires at least one parameter");
+
+ return do_contents();
+ }
+
+ if (CommandLine::get_instance()->a_owner.specified())
+ {
+ if (CommandLine::get_instance()->empty())
+ throw DoHelp("owner action requires at least one parameter");
+
+ return do_owner();
+ }
+
+ if (CommandLine::get_instance()->a_has_version.specified())
+ {
+ if (1 != std::distance(CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters()))
+ throw DoHelp("has-version action takes exactly one parameter");
+
+ return do_has_version();
+ }
+
+ if (CommandLine::get_instance()->a_best_version.specified())
+ {
+ if (1 != std::distance(CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters()))
+ throw DoHelp("best-version action takes exactly one parameter");
+
+ return do_best_version();
+ }
+
+ if (CommandLine::get_instance()->a_environment_variable.specified())
+ {
+ if (2 != std::distance(CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters()))
+ throw DoHelp("environment-variable action takes exactly two parameters (depatom var)");
+
+ return do_environment_variable();
+ }
+
+ if (CommandLine::get_instance()->a_configuration_variable.specified())
+ {
+ if (2 != std::distance(CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters()))
+ throw DoHelp("configuration-variable action takes exactly two parameters (depatom var)");
+
+ return do_configuration_variable();
+ }
+
+ if (CommandLine::get_instance()->a_update_news.specified())
+ {
+ if (! CommandLine::get_instance()->empty())
+ throw DoHelp("update-news action takes no parameters");
+
+ return do_update_news();
+ }
+
+ throw p::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 p::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.4.0/src/qualudis/Makefile.am b/0.4.0/src/qualudis/Makefile.am
new file mode 100644
index 000000000..1fd9695e4
--- /dev/null
+++ b/0.4.0/src/qualudis/Makefile.am
@@ -0,0 +1,31 @@
+CLEANFILES = *~ version_TEST gmon.out *.gcov *.gcno *.gcda
+MAINTAINERCLEANFILES = Makefile.in
+AM_CXXFLAGS = -I$(top_srcdir)
+DEFS= \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DBIGTEMPDIR=\"/var/tmp\"
+SUBDIRS = .
+
+if ENABLE_QA
+
+bin_PROGRAMS = qualudis
+
+qualudis_SOURCES = \
+ qualudis_command_line.hh qualudis_command_line.cc \
+ qualudis.cc
+
+qualudis_LDADD = \
+ $(top_builddir)/paludis/args/libpaludisargs.a \
+ $(top_builddir)/paludis/qa/libpaludisqa.a \
+ $(top_builddir)/paludis/libpaludis.a \
+ $(top_builddir)/paludis/util/libpaludisutil.a
+
+TESTS_ENVIRONMENT = env TEST_SCRIPT_DIR="$(srcdir)/" bash $(top_srcdir)/test/run_test.sh bash
+TESTS = version_TEST
+
+version_TEST :
+ echo -e "#!/bin/sh\n./qualudis --version" > $@
+
+endif
+
diff --git a/0.4.0/src/qualudis/qualudis.cc b/0.4.0/src/qualudis/qualudis.cc
new file mode 100644
index 000000000..8a5073b47
--- /dev/null
+++ b/0.4.0/src/qualudis/qualudis.cc
@@ -0,0 +1,583 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 <paludis/args/args.hh>
+#include <paludis/paludis.hh>
+#include <paludis/qa/qa.hh>
+#include <paludis/util/util.hh>
+
+#include <cstdlib>
+#include <iostream>
+#include <algorithm>
+
+#include "qualudis_command_line.hh"
+#include "config.h"
+
+using namespace paludis;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace
+{
+ struct DoHelp
+ {
+ const std::string message;
+
+ DoHelp(const std::string & m = "") :
+ message(m)
+ {
+ }
+ };
+
+ struct DoVersion
+ {
+ };
+
+ void
+ display_header(const qa::CheckResult & r)
+ {
+ cout << r.item() << ": " << r.rule() << ":" << endl;
+ }
+
+ void
+ display_header_once(bool * const once, const qa::CheckResult & r)
+ {
+ if (! *once)
+ {
+ display_header(r);
+ *once = true;
+ }
+ }
+
+ void
+ display_no_errors(const qa::CheckResult & r)
+ {
+ if (QualudisCommandLine::get_instance()->a_verbose.specified())
+ display_header(r);
+ }
+
+ void
+ display_errors(const qa::CheckResult & r)
+ {
+ bool done_out(false);
+
+ for (qa::CheckResult::Iterator i(r.begin()), i_end(r.end()) ; i != i_end ; ++i)
+ {
+ if (i->get<qa::mk_level>() < QualudisCommandLine::get_instance()->message_level)
+ continue;
+
+ bool show(true);
+ do
+ {
+ switch (i->get<qa::mk_level>())
+ {
+ case qa::qal_info:
+ display_header_once(&done_out, r);
+ cout << " info: ";
+ continue;
+
+ case qa::qal_skip:
+ if (QualudisCommandLine::get_instance()->a_verbose.specified())
+ {
+ display_header_once(&done_out, r);
+ cout << " skip: ";
+ }
+ else
+ show = false;
+ continue;
+
+ case qa::qal_minor:
+ display_header_once(&done_out, r);
+ cout << " minor: ";
+ continue;
+
+ case qa::qal_major:
+ display_header_once(&done_out, r);
+ cout << " major: ";
+ continue;
+
+ case qa::qal_fatal:
+ display_header_once(&done_out, r);
+ cout << " fatal: ";
+ continue;
+
+ case qa::qal_maybe:
+ display_header_once(&done_out, r);
+ cout << " maybe: ";
+ continue;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Bad mk_level");
+ }
+ while (false);
+
+ if (show)
+ cout << i->get<qa::mk_msg>() << endl;
+ }
+ }
+
+ template <typename VC_>
+ struct IsImportant :
+ std::binary_function<bool, std::string, std::string>
+ {
+ bool operator() (const std::string & k1, const std::string & k2) const
+ {
+ return (*VC_::get_instance()->find_maker(k1))()->is_important() >
+ (*VC_::get_instance()->find_maker(k2))()->is_important();
+ }
+ };
+
+ template <typename VC_, typename P_>
+ void do_check_kind(bool & ok, bool & fatal, const P_ & value)
+ {
+ std::list<std::string> checks;
+ VC_::get_instance()->copy_keys(std::back_inserter(checks));
+ checks.sort();
+ checks.sort(IsImportant<VC_>());
+
+ for (std::list<std::string>::const_iterator i(checks.begin()),
+ i_end(checks.end()) ; i != i_end ; ++i)
+ {
+ try
+ {
+ Context context("When performing check '" + stringify(*i) + "':");
+
+ qa::CheckResult r((*VC_::get_instance()->find_maker(*i)())(value));
+
+ if (r.empty())
+ {
+ display_no_errors(r);
+ continue;
+ }
+
+ display_errors(r);
+
+ do
+ {
+ switch (r.most_severe_level())
+ {
+ case qa::qal_info:
+ case qa::qal_skip:
+ case qa::qal_maybe:
+ continue;
+
+ case qa::qal_minor:
+ case qa::qal_major:
+ ok = false;
+ continue;
+
+ case qa::qal_fatal:
+ ok = false;
+ fatal = true;
+ return;
+ }
+ throw InternalError(PALUDIS_HERE, "Bad most_severe_level");
+ } while (0);
+ }
+ catch (const InternalError &)
+ {
+ throw;
+ }
+ catch (const Exception & e)
+ {
+ std::cout << "Eek! Caught Exception '" << e.message() << "' (" << e.what()
+ << ") when doing check '" << *i << "'" << endl;
+ ok = false;
+ }
+ catch (const std::exception & e)
+ {
+ std::cout << "Eek! Caught std::exception '" << e.what()
+ << "' when doing check '" << *i << "'" << endl;
+ ok = false;
+ }
+ }
+ }
+
+ bool
+ do_check_package_dir(const FSEntry & dir, const Environment & env)
+ {
+ Context context("When checking package '" + stringify(dir) + "':");
+
+ bool ok(true), fatal(false);
+
+ cout << "QA checks for package directory " << dir << ":" << endl;
+
+ if (! fatal)
+ do_check_kind<qa::PackageDirCheckMaker>(ok, fatal, dir);
+
+ if (! fatal)
+ {
+ std::list<FSEntry> files((DirIterator(dir)), DirIterator());
+ for (std::list<FSEntry>::iterator f(files.begin()) ; f != files.end() ; ++f)
+ {
+ if (f->basename() == "CVS" || '.' == f->basename().at(0))
+ continue;
+ if (fatal)
+ break;
+
+ do_check_kind<qa::FileCheckMaker>(ok, fatal, *f);
+ }
+ }
+
+ if (! fatal)
+ {
+ std::list<FSEntry> files((DirIterator(dir)), DirIterator());
+ for (std::list<FSEntry>::iterator f(files.begin()) ; f != files.end() ; ++f)
+ {
+ if (! IsFileWithExtension(".ebuild")(*f))
+ continue;
+
+ qa::EbuildCheckData d(
+ QualifiedPackageName(CategoryNamePart(stringify(dir.dirname().basename())),
+ PackageNamePart(stringify(dir.basename()))),
+ VersionSpec(strip_leading_string(strip_trailing_string(f->basename(), ".ebuild"),
+ stringify(dir.basename()) + "-")),
+ &env);
+ do_check_kind<qa::EbuildCheckMaker>(ok, fatal, d);
+
+ if (fatal)
+ break;
+ }
+ }
+
+ cout << endl;
+
+ return ok;
+ }
+
+ bool
+ do_check_category_dir(const FSEntry & dir, const Environment & env)
+ {
+ Context context("When checking category '" + stringify(dir) + "':");
+
+ cout << "QA checks for category directory " << dir << ":" << endl;
+ cout << endl;
+
+ bool ok(true);
+
+ for (DirIterator d(dir) ; d != DirIterator() ; ++d)
+ {
+ if ("CVS" == d->basename())
+ continue;
+ else if ('.' == d->basename().at(0))
+ continue;
+ else if (d->is_directory())
+ ok &= do_check_package_dir(*d, env);
+ else if ("metadata.xml" == d->basename())
+ {
+ bool fatal(false);
+
+ cout << "QA checks for category file " << *d << ":" << endl;
+
+ do_check_kind<qa::FileCheckMaker>(ok, fatal, *d);
+
+ cout << endl;
+
+ if (fatal)
+ break;
+ }
+ }
+
+ return ok;
+ }
+
+ bool
+ do_check_eclass_dir(const FSEntry & dir, const Environment &)
+ {
+ Context context("When checking eclass directory '" + stringify(dir) + "':");
+
+ cout << "QA checks for eclass directory " << dir << ":" << endl;
+ cout << endl;
+
+ bool ok(true);
+
+ for (DirIterator d(dir) ; d != DirIterator() ; ++d)
+ {
+ if ("CVS" == d->basename())
+ continue;
+ else if ('.' == d->basename().at(0))
+ continue;
+ else if (IsFileWithExtension(".eclass")(d->basename()))
+ {
+ bool fatal(false);
+
+ cout << "QA checks for eclass file " << *d << ":" << endl;
+
+ do_check_kind<qa::FileCheckMaker>(ok, fatal, *d);
+
+ cout << endl;
+
+ if (fatal)
+ break;
+ }
+ }
+
+ return ok;
+ }
+
+ bool
+ do_check_top_level(const FSEntry & dir)
+ {
+ Context context("When checking top level '" + stringify(dir) + "':");
+
+ cout << "QA checks for top level directory " << dir << ":" << endl << endl;
+
+ qa::QAEnvironment env(dir);
+ bool ok(true);
+
+ for (DirIterator d(dir) ; d != DirIterator() ; ++d)
+ {
+ if (d->basename() == "CVS" || '.' == d->basename().at(0))
+ continue;
+ if (! d->is_directory())
+ continue;
+ if (d->basename() == "eclass")
+ ok &= do_check_eclass_dir(*d, env);
+ else if (env.package_database()->fetch_repository(
+ env.package_database()->favourite_repository())->
+ has_category_named(CategoryNamePart(d->basename())))
+ ok &= do_check_category_dir(*d, env);
+ }
+
+ return ok;
+ }
+
+
+ bool
+ do_check(const FSEntry & dir)
+ {
+ Context context("When checking directory '" + stringify(dir) + "':");
+
+ if (dir.basename() == "eclass" && dir.is_directory())
+ {
+ qa::QAEnvironment env(dir.dirname());
+ return do_check_eclass_dir(dir, env);
+ }
+
+ else if (std::count_if(DirIterator(dir), DirIterator(), IsFileWithExtension(
+ dir.basename() + "-", ".ebuild")))
+ {
+ qa::QAEnvironment env(dir.dirname().dirname());
+ return do_check_package_dir(dir, env);
+ }
+
+ else if ((dir / "profiles").is_directory())
+ return do_check_top_level(dir);
+
+ else if ((dir.dirname() / "profiles").is_directory())
+ {
+ qa::QAEnvironment env(dir.dirname());
+ return do_check_category_dir(dir, env);
+ }
+
+ else
+ throw DoHelp("qualudis should be run inside a repository");
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ Context context("In main program:");
+
+ try
+ {
+ QualudisCommandLine::get_instance()->run(argc, argv);
+
+ if (QualudisCommandLine::get_instance()->a_help.specified())
+ throw DoHelp();
+
+ if (! QualudisCommandLine::get_instance()->a_log_level.specified())
+ Log::get_instance()->set_log_level(ll_qa);
+ else if (QualudisCommandLine::get_instance()->a_log_level.argument() == "debug")
+ Log::get_instance()->set_log_level(ll_debug);
+ else if (QualudisCommandLine::get_instance()->a_log_level.argument() == "qa")
+ Log::get_instance()->set_log_level(ll_qa);
+ else if (QualudisCommandLine::get_instance()->a_log_level.argument() == "warning")
+ Log::get_instance()->set_log_level(ll_warning);
+ else if (QualudisCommandLine::get_instance()->a_log_level.argument() == "silent")
+ Log::get_instance()->set_log_level(ll_silent);
+ else
+ throw DoHelp("bad value for --log-level");
+
+ if (! QualudisCommandLine::get_instance()->a_message_level.specified())
+ QualudisCommandLine::get_instance()->message_level = qa::qal_info;
+ else if (QualudisCommandLine::get_instance()->a_message_level.argument() == "info")
+ QualudisCommandLine::get_instance()->message_level = qa::qal_info;
+ else if (QualudisCommandLine::get_instance()->a_message_level.argument() == "minor")
+ QualudisCommandLine::get_instance()->message_level = qa::qal_minor;
+ else if (QualudisCommandLine::get_instance()->a_message_level.argument() == "major")
+ QualudisCommandLine::get_instance()->message_level = qa::qal_major;
+ else if (QualudisCommandLine::get_instance()->a_message_level.argument() == "fatal")
+ QualudisCommandLine::get_instance()->message_level = qa::qal_fatal;
+ else
+ throw DoHelp("bad value for --message-level");
+
+ if (QualudisCommandLine::get_instance()->a_version.specified())
+ throw DoVersion();
+
+ if (QualudisCommandLine::get_instance()->a_check.specified())
+ {
+ if (! QualudisCommandLine::get_instance()->empty())
+ throw DoHelp("check action takes no parameters");
+
+ return do_check(FSEntry::cwd()) ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+
+ if (QualudisCommandLine::get_instance()->a_describe.specified())
+ {
+ if (! QualudisCommandLine::get_instance()->empty())
+ throw DoHelp("describe action takes no parameters");
+
+ cout << "Package directory checks:" << endl;
+ std::list<std::string> package_dir_checks;
+ qa::PackageDirCheckMaker::get_instance()->copy_keys(std::back_inserter(package_dir_checks));
+ for (std::list<std::string>::const_iterator i(package_dir_checks.begin()),
+ i_end(package_dir_checks.end()) ; i != i_end ; ++i)
+ cout << " " << *i << ":" << endl << " " <<
+ (*qa::PackageDirCheckMaker::get_instance()->find_maker(*i))()->describe() << endl;
+ cout << endl;
+
+ cout << "File checks:" << endl;
+ std::list<std::string> file_checks;
+ qa::FileCheckMaker::get_instance()->copy_keys(std::back_inserter(file_checks));
+ for (std::list<std::string>::const_iterator i(file_checks.begin()),
+ i_end(file_checks.end()) ; i != i_end ; ++i)
+ cout << " " << *i << ":" << endl << " " <<
+ (*qa::FileCheckMaker::get_instance()->find_maker(*i))()->describe() << endl;
+ cout << endl;
+
+ cout << "Ebuild checks:" << endl;
+ std::list<std::string> ebuild_checks;
+ qa::EbuildCheckMaker::get_instance()->copy_keys(std::back_inserter(ebuild_checks));
+ for (std::list<std::string>::const_iterator i(ebuild_checks.begin()),
+ i_end(ebuild_checks.end()) ; i != i_end ; ++i)
+ cout << " " << *i << ":" << endl << " " <<
+ (*qa::EbuildCheckMaker::get_instance()->find_maker(*i))()->describe() << endl;
+ cout << endl;
+
+ return EXIT_SUCCESS;
+ }
+
+ if (! QualudisCommandLine::get_instance()->empty())
+ {
+ QualudisCommandLine *c1 = QualudisCommandLine::get_instance();
+ QualudisCommandLine::ParametersIterator argit = c1->begin_parameters(), arge = c1->end_parameters();
+ for ( ; argit != arge; ++argit )
+ {
+ std::string arg = *argit;
+ try
+ {
+ do_check(FSEntry::cwd() / arg);
+ }
+ catch(const DirOpenError & e)
+ {
+ cout << e.message() << endl;
+ }
+ }
+ return EXIT_SUCCESS;
+ }
+
+ throw InternalError(__PRETTY_FUNCTION__, "no action?");
+ }
+ catch (const DoVersion &)
+ {
+ cout << "qualudis, part of " << PALUDIS_PACKAGE << " " << 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 << "SYSCONFDIR: " << SYSCONFDIR << endl;
+ cout << "LIBEXECDIR: " << LIBEXECDIR << endl;
+ cout << "BIGTEMPDIR: " << BIGTEMPDIR << endl;
+ cout << "stdlib: "
+#if defined(__GLIBCXX__)
+# define XSTRINGIFY(x) #x
+# define STRINGIFY(x) XSTRINGIFY(x)
+ << "GNU libstdc++ " << STRINGIFY(__GLIBCXX__)
+#endif
+ << endl;
+
+ cout << "libebt: " << LIBEBT_VERSION_MAJOR << "." << LIBEBT_VERSION_MINOR
+ << "." << LIBEBT_VERSION_MICRO << endl;
+ 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 << " or: " << argv[0] << " [package/category ..]" << endl;
+ cout << endl;
+ cout << *QualudisCommandLine::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.4.0/src/qualudis/qualudis_command_line.cc b/0.4.0/src/qualudis/qualudis_command_line.cc
new file mode 100644
index 000000000..ed279da0e
--- /dev/null
+++ b/0.4.0/src/qualudis/qualudis_command_line.cc
@@ -0,0 +1,54 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "qualudis_command_line.hh"
+
+QualudisCommandLine::QualudisCommandLine() :
+ ArgsHandler(),
+
+ action_args(this, "Actions (specify exactly one)"),
+ a_check(&action_args, "check", 'c', "Check the current directory"),
+ a_describe(&action_args, "describe", 'd', "Describe checks"),
+ a_version(&action_args, "version", 'V', "Display program version"),
+ a_help(&action_args, "help", 'h', "Display program help"),
+
+ check_options(this, "Options for --check"),
+ a_verbose(&check_options, "verbose", 'v', "Be verbose"),
+ a_log_level(&check_options, "log-level", 'L', "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"),
+ "warning"),
+
+ a_message_level(&check_options, "message-level", 'M', "Specify the message level",
+ paludis::args::EnumArg::EnumArgOptions("info", "Show info and upwards")
+ ("minor", "Show minor and upwards")
+ ("major", "Show major and upwards")
+ ("fatal", "Show only fatals"),
+ "warning"),
+
+ message_level(paludis::qa::qal_info)
+{
+}
+
+QualudisCommandLine::~QualudisCommandLine()
+{
+}
+
diff --git a/0.4.0/src/qualudis/qualudis_command_line.hh b/0.4.0/src/qualudis/qualudis_command_line.hh
new file mode 100644
index 000000000..386349913
--- /dev/null
+++ b/0.4.0/src/qualudis/qualudis_command_line.hh
@@ -0,0 +1,65 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#ifndef PALUDIS_GUARD_SRC_QUALUDIS_QUALUDIS_COMMAND_LINE_HH
+#define PALUDIS_GUARD_SRC_QUALUDIS_QUALUDIS_COMMAND_LINE_HH 1
+
+#include <paludis/args/args.hh>
+#include <paludis/qa/qa.hh>
+#include <paludis/util/instantiation_policy.hh>
+
+class QualudisCommandLine :
+ public paludis::args::ArgsHandler,
+ public paludis::InstantiationPolicy<QualudisCommandLine, paludis::instantiation_method::SingletonAsNeededTag>
+{
+ friend class paludis::InstantiationPolicy<QualudisCommandLine, paludis::instantiation_method::SingletonAsNeededTag>;
+
+ private:
+ /// Constructor.
+ QualudisCommandLine();
+
+ /// Destructor.
+ ~QualudisCommandLine();
+
+ public:
+ /// \name Action arguments
+ ///{
+
+ /// Action arguments.
+ paludis::args::ArgsGroup action_args;
+
+ /// --check
+ paludis::args::SwitchArg a_check;
+
+ /// --describe
+ paludis::args::SwitchArg a_describe;
+
+ /// --version
+ paludis::args::SwitchArg a_version;
+
+ /// --help
+ paludis::args::SwitchArg a_help;
+
+ ///}
+
+ /// \name Check options
+ ///{
+
+ /// Check options.
+ paludis::args::ArgsGroup check_options;
+
+ /// --verbose
+ paludis::args::SwitchArg a_verbose;
+
+ /// --log-level
+ paludis::args::EnumArg a_log_level;
+
+ /// --message-level
+ paludis::args::EnumArg a_message_level;
+
+ paludis::qa::QALevel message_level;
+
+ ///}
+};
+
+
+#endif
diff --git a/0.4.0/src/query.cc b/0.4.0/src/query.cc
new file mode 100644
index 000000000..2123d8b70
--- /dev/null
+++ b/0.4.0/src/query.cc
@@ -0,0 +1,371 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "src/colour.hh"
+#include "src/query.hh"
+#include "src/licence.hh"
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <paludis/paludis.hh>
+#include <string>
+
+/** \file
+ * Handle the --query action for the main paludis program.
+ */
+
+namespace p = paludis;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace
+{
+ struct CannotQueryPackageSet
+ {
+ const std::string query;
+
+ CannotQueryPackageSet(const std::string & q) :
+ query(q)
+ {
+ }
+ };
+}
+
+void do_one_query(
+ const p::Environment * const env,
+ const std::string & q,
+ p::MaskReasons & mask_reasons_to_explain)
+{
+ p::Context local_context("When handling query '" + q + "':");
+
+ /* we might have a dep atom, but we might just have a simple package name
+ * without a category. either should work. */
+ p::PackageDepAtom::Pointer atom(0);
+ if (std::string::npos == q.find('/'))
+ {
+ if (0 != env->package_set(q))
+ throw CannotQueryPackageSet(q);
+ else
+ atom.assign(new p::PackageDepAtom(env->package_database()->fetch_unique_qualified_package_name(
+ p::PackageNamePart(q))));
+ }
+ else
+ atom.assign(new p::PackageDepAtom(q));
+
+ p::PackageDatabaseEntryCollection::ConstPointer
+ entries(env->package_database()->query(atom, p::is_either)),
+ preferred_entries(env->package_database()->query(atom, p::is_installed_only));
+ if (entries->empty())
+ throw p::NoSuchPackageError(q);
+ if (preferred_entries->empty())
+ preferred_entries = entries;
+
+ const p::PackageDatabaseEntry display_entry(*preferred_entries->last());
+
+ /* match! display it. */
+ cout << "* " << colour(cl_package_name, entries->begin()->get<p::pde_name>());
+ if (atom->version_spec_ptr())
+ cout << " (" << atom->version_operator() << *atom->version_spec_ptr() << ")";
+ if (atom->slot_ptr())
+ cout << " (:" << *atom->slot_ptr() << ")";
+ if (atom->repository_ptr())
+ cout << " (::" << *atom->repository_ptr() << ")";
+ cout << endl;
+
+ /* find all repository names. */
+ p::RepositoryNameCollection repo_names;
+ p::PackageDatabaseEntryCollection::Iterator e(entries->begin()), e_end(entries->end());
+ for ( ; e != e_end ; ++e)
+ repo_names.append(e->get<p::pde_repository>());
+
+ /* display versions, by repository. */
+ p::RepositoryNameCollection::Iterator r(repo_names.begin()), r_end(repo_names.end());
+ for ( ; r != r_end ; ++r)
+ {
+ cout << " " << std::setw(22) << std::left <<
+ (p::stringify(*r) + ":") << std::setw(0) << " ";
+
+ std::string old_slot;
+ for (e = entries->begin() ; e != e_end ; ++e)
+ if (e->get<p::pde_repository>() == *r)
+ {
+ p::VersionMetadata::ConstPointer metadata(env->package_database()->fetch_repository(
+ e->get<p::pde_repository>())->version_metadata(e->get<p::pde_name>(),
+ e->get<p::pde_version>()));
+ if (CommandLine::get_instance()->a_show_slot.specified())
+ {
+ /* show the slot, if we're about to move onto a new slot */
+ std::string slot_name(stringify(metadata->get<p::vm_slot>()));
+ if (old_slot.empty())
+ old_slot = slot_name;
+ else if (old_slot != slot_name)
+ cout << colour(cl_slot, "{:" + old_slot + "} ");
+ old_slot = slot_name;
+ }
+
+ const p::MaskReasons masks(env->mask_reasons(*e));
+
+ if (masks.none())
+ cout << colour(cl_visible, e->get<p::pde_version>());
+ else
+ {
+ std::string reasons;
+ for (p::MaskReason m(p::MaskReason(0)) ; m < p::last_mr ;
+ m = p::MaskReason(static_cast<int>(m) + 1))
+ {
+ if (! masks.test(m))
+ continue;
+
+ switch (m)
+ {
+ case p::mr_keyword:
+ reasons.append("K");
+ break;
+ case p::mr_user_mask:
+ reasons.append("U");
+ break;
+ case p::mr_profile_mask:
+ reasons.append("P");
+ break;
+ case p::mr_repository_mask:
+ reasons.append("R");
+ break;
+ case p::mr_eapi:
+ reasons.append("E");
+ break;
+ case p::mr_license:
+ reasons.append("L");
+ break;
+ case p::last_mr:
+ break;
+ }
+ }
+ mask_reasons_to_explain |= masks;
+ cout << colour(cl_masked, "(" + stringify(e->get<p::pde_version>()) + ")" + reasons);
+ }
+
+ if (*e == display_entry)
+ cout << "*";
+ cout << " ";
+ }
+
+ /* still need to show the slot for the last item */
+ if (CommandLine::get_instance()->a_show_slot.specified())
+ cout << colour(cl_slot, "{:" + old_slot + "} ");
+
+ cout << endl;
+ }
+
+ /* display metadata */
+ p::VersionMetadata::ConstPointer metadata(env->package_database()->fetch_repository(
+ display_entry.get<p::pde_repository>())->version_metadata(
+ display_entry.get<p::pde_name>(), display_entry.get<p::pde_version>()));
+
+ if (CommandLine::get_instance()->a_show_metadata.specified())
+ {
+ cout << " " << std::setw(22) << std::left << "DESCRIPTION:" << std::setw(0) <<
+ " " << metadata->get<p::vm_description>() << endl;
+ cout << " " << std::setw(22) << std::left << "HOMEPAGE:" << std::setw(0) <<
+ " " << metadata->get<p::vm_homepage>() << endl;
+ cout << " " << std::setw(22) << std::left << "LICENSE:" << std::setw(0) <<
+ " " << metadata->get<p::vm_license>() << endl;
+
+ cout << " " << std::setw(22) << std::left << "DEPEND:" << std::setw(0) <<
+ " " << metadata->get<p::vm_deps>().get<p::vmd_build_depend_string>() << endl;
+ cout << " " << std::setw(22) << std::left << "RDEPEND:" << std::setw(0) <<
+ " " << metadata->get<p::vm_deps>().get<p::vmd_run_depend_string>() << endl;
+ cout << " " << std::setw(22) << std::left << "PDEPEND:" << std::setw(0) <<
+ " " << metadata->get<p::vm_deps>().get<p::vmd_post_depend_string>() << endl;
+
+ if (metadata->get_ebuild_interface())
+ {
+ cout << " " << std::setw(22) << std::left << "IUSE:" << std::setw(0) <<
+ " " << metadata->get_ebuild_interface()->get<p::evm_iuse>() << endl;
+ cout << " " << std::setw(22) << std::left << "KEYWORDS:" << std::setw(0) <<
+ " " << metadata->get_ebuild_interface()->get<p::evm_keywords>() << endl;
+ cout << " " << std::setw(22) << std::left << "PROVIDE:" << std::setw(0) <<
+ " " << metadata->get_ebuild_interface()->get<p::evm_provide>() << endl;
+ cout << " " << std::setw(22) << std::left << "RESTRICT:" << std::setw(0) <<
+ " " << metadata->get_ebuild_interface()->get<p::evm_restrict>() << endl;
+ cout << " " << std::setw(22) << std::left << "SRC_URI:" << std::setw(0) <<
+ " " << metadata->get_ebuild_interface()->get<p::evm_src_uri>() << endl;
+ cout << " " << std::setw(22) << std::left << "VIRTUAL:" << std::setw(0) <<
+ " " << metadata->get_ebuild_interface()->get<p::evm_virtual>() << endl;
+ }
+ }
+ else
+ {
+ if (! metadata->get<p::vm_homepage>().empty())
+ cout << " " << std::setw(22) << std::left << "Homepage:" << std::setw(0) <<
+ " " << metadata->get<p::vm_homepage>() << endl;
+
+ if (! metadata->get<p::vm_description>().empty())
+ cout << " " << std::setw(22) << std::left << "Description:" << std::setw(0) <<
+ " " << metadata->get<p::vm_description>() << endl;
+
+ if (! metadata->get<p::vm_license>().empty())
+ {
+ cout << " " << std::setw(22) << std::left << "License:" << std::setw(0) << " ";
+ LicenceDisplayer d(cout, env, &display_entry);
+ metadata->license()->accept(&d);
+ cout << endl;
+ }
+
+ if (CommandLine::get_instance()->a_show_deps.specified())
+ {
+ if (! metadata->get<p::vm_deps>().get<p::vmd_build_depend_string>().empty())
+ {
+ p::DepAtomPrettyPrinter p_depend(12);
+ metadata->get<p::vm_deps>().build_depend()->accept(&p_depend);
+ cout << " " << std::setw(22) << std::left << "Build dependencies:" << std::setw(0)
+ << endl << p_depend;
+ }
+
+ if (! metadata->get<p::vm_deps>().get<p::vmd_run_depend_string>().empty())
+ {
+ p::DepAtomPrettyPrinter p_depend(12);
+ metadata->get<p::vm_deps>().run_depend()->accept(&p_depend);
+ cout << " " << std::setw(22) << std::left << "Runtime dependencies:" << std::setw(0)
+ << endl << p_depend;
+ }
+
+ if (! metadata->get<p::vm_deps>().get<p::vmd_post_depend_string>().empty())
+ {
+ p::DepAtomPrettyPrinter p_depend(12);
+ metadata->get<p::vm_deps>().post_depend()->accept(&p_depend);
+ cout << " " << std::setw(22) << std::left << "Post dependencies:" << std::setw(0)
+ << endl << p_depend;
+ }
+ }
+
+ if (metadata->get_ebuild_interface() && ! metadata->get_ebuild_interface()->
+ get<p::evm_virtual>().empty())
+ cout << " " << std::setw(22) << std::left << "Virtual for:" << std::setw(0) <<
+ " " << metadata->get_ebuild_interface()->get<p::evm_virtual>() << endl;
+
+ if (metadata->get_ebuild_interface() && ! metadata->get_ebuild_interface()->
+ get<p::evm_provide>().empty())
+ cout << " " << std::setw(22) << std::left << "Provides:" << std::setw(0) <<
+ " " << metadata->get_ebuild_interface()->get<p::evm_provide>() << endl;
+ }
+
+
+ /* blank line */
+ cout << endl;
+}
+
+int do_query()
+{
+ int return_code(0);
+
+ p::Context context("When performing query action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ p::MaskReasons mask_reasons_to_explain;
+
+ CommandLine::ParametersIterator q(CommandLine::get_instance()->begin_parameters()),
+ q_end(CommandLine::get_instance()->end_parameters());
+ for ( ; q != q_end ; ++q)
+ {
+ try
+ {
+ do_one_query(env, *q, mask_reasons_to_explain);
+ }
+ catch (const p::AmbiguousPackageNameError & e)
+ {
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ");
+ cerr << "Ambiguous package name '" << e.name() << "'. Did you mean:" << endl;
+ for (p::AmbiguousPackageNameError::OptionsIterator o(e.begin_options()),
+ o_end(e.end_options()) ; o != o_end ; ++o)
+ cerr << " * " << colour(cl_package_name, *o) << endl;
+ cerr << endl;
+ }
+ catch (const CannotQueryPackageSet & e)
+ {
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * Target '" << e.query << "' is a set, not a package." << endl;
+ cerr << endl;
+ }
+ catch (const p::NameError & e)
+ {
+ return_code |= 1;
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ") << e.message() << endl;
+ cerr << endl;
+ }
+ catch (const p::PackageDatabaseLookupError & e)
+ {
+ return_code |= 1;
+ cout << endl;
+ cerr << "Query error:" << endl;
+ cerr << " * " << e.backtrace("\n * ") << e.message() << endl;
+ cerr << endl;
+ }
+ }
+
+ if (mask_reasons_to_explain.any())
+ {
+ cout << colour(cl_heading, "Key to mask reasons:") << endl << endl;
+
+ /* use for/case to get compiler warnings when new mr_ are added */
+ for (p::MaskReason m(p::MaskReason(0)) ; m < p::last_mr ;
+ m = p::MaskReason(static_cast<int>(m) + 1))
+ {
+ if (! mask_reasons_to_explain.test(m))
+ continue;
+
+ switch (m)
+ {
+ case p::mr_keyword:
+ cout << "* " << colour(cl_yellow, "K") << ": keyword";
+ break;
+ case p::mr_user_mask:
+ cout << "* " << colour(cl_yellow, "U") << ": user mask";
+ break;
+ case p::mr_profile_mask:
+ cout << "* " << colour(cl_yellow, "P") << ": profile mask";
+ break;
+ case p::mr_repository_mask:
+ cout << "* " << colour(cl_yellow, "R") << ": repository mask";
+ break;
+ case p::mr_eapi:
+ cout << "* " << colour(cl_yellow, "E") << ": EAPI";
+ break;
+ case p::mr_license:
+ cout << "* " << colour(cl_yellow, "L") << ": licence";
+ break;
+
+ case p::last_mr:
+ break;
+ }
+
+ cout << endl;
+ }
+
+ cout << endl;
+ }
+
+ return return_code;
+}
+
diff --git a/0.4.0/src/query.hh b/0.4.0/src/query.hh
new file mode 100644
index 000000000..ce26c2785
--- /dev/null
+++ b/0.4.0/src/query.hh
@@ -0,0 +1,32 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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_QUERY_HH
+#define PALUDIS_GUARD_SRC_QUERY_HH 1
+
+#include "src/command_line.hh"
+
+/** \file
+ * Declaration for the do_query function.
+ */
+
+/// Handle --query.
+int do_query();
+
+#endif
diff --git a/0.4.0/src/sync.cc b/0.4.0/src/sync.cc
new file mode 100644
index 000000000..2645d8850
--- /dev/null
+++ b/0.4.0/src/sync.cc
@@ -0,0 +1,123 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "src/colour.hh"
+#include "src/sync.hh"
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <paludis/paludis.hh>
+#include <string>
+
+/** \file
+ * Handle the --sync action for the main paludis program.
+ */
+
+namespace p = paludis;
+using std::cerr;
+
+namespace
+{
+ int do_one_sync(p::Repository::ConstPointer r)
+ {
+ int return_code(0);
+
+ std::cout << colour(cl_heading, "Sync " + p::stringify(r->name())) << std::endl;
+ try
+ {
+ cerr << xterm_title("Syncing " + p::stringify(r->name()));
+ if (r->get_interface<p::repo_syncable>() && r->get_interface<p::repo_syncable>()->sync())
+ std::cout << "Sync " << r->name() << " completed" << std::endl;
+ else
+ std::cout << "Sync " << r->name() << " skipped" << std::endl;
+ }
+ catch (const p::SyncFailedError & e)
+ {
+ return_code |= 1;
+ std::cout << std::endl;
+ std::cerr << "Sync error:" << std::endl;
+ std::cerr << " * " << e.backtrace("\n * ") << e.message() << std::endl;
+ std::cerr << std::endl;
+ std::cout << "Sync " << r->name() << " failed" << std::endl;
+ }
+
+ return return_code;
+ }
+}
+
+int do_sync()
+{
+ int return_code(0);
+
+ p::Context context("When performing sync action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ if (CommandLine::get_instance()->empty())
+ {
+ std::string targets;
+ for (p::PackageDatabase::RepositoryIterator r(env->package_database()->begin_repositories()),
+ r_end(env->package_database()->end_repositories()) ; r != r_end ; ++r)
+ targets.append(stringify((*r)->name()) + " ");
+
+ env->perform_hook(p::Hook("sync_all_pre")("TARGETS", targets));
+ for (p::PackageDatabase::RepositoryIterator r(env->package_database()->begin_repositories()),
+ r_end(env->package_database()->end_repositories()) ; r != r_end ; ++r)
+ {
+ env->perform_hook(p::Hook("sync_pre")("TARGET", stringify((*r)->name())));
+ return_code |= do_one_sync(*r);
+ env->perform_hook(p::Hook("sync_post")("TARGET", stringify((*r)->name())));
+ }
+ env->perform_hook(p::Hook("sync_all_post")("TARGETS", targets));
+ }
+ else
+ {
+ std::set<p::RepositoryName> repo_names;
+ std::copy(CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters(),
+ p::create_inserter<p::RepositoryName>(std::inserter(
+ repo_names, repo_names.begin())));
+
+ env->perform_hook(p::Hook("sync_all_pre")("TARGETS", p::join(
+ CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters(), " ")));
+ for (std::set<p::RepositoryName>::iterator r(repo_names.begin()), r_end(repo_names.end()) ;
+ r != r_end ; ++r)
+ {
+ try
+ {
+ env->perform_hook(p::Hook("sync_pre")("TARGET", stringify(*r)));
+ return_code |= do_one_sync(env->package_database()->fetch_repository(*r));
+ env->perform_hook(p::Hook("sync_post")("TARGET", stringify(*r)));
+ }
+ catch (const p::NoSuchRepositoryError & e)
+ {
+ return_code |= 1;
+ std::cerr << "No such repository '" << *r << "'" << std::endl;
+ std::cout << "Sync " << *r << " failed" << std::endl;
+ }
+ }
+ env->perform_hook(p::Hook("sync_all_post")("TARGETS", p::join(
+ CommandLine::get_instance()->begin_parameters(),
+ CommandLine::get_instance()->end_parameters(), " ")));
+ }
+
+ return return_code;
+}
+
+
diff --git a/0.4.0/src/sync.hh b/0.4.0/src/sync.hh
new file mode 100644
index 000000000..d4f565f87
--- /dev/null
+++ b/0.4.0/src/sync.hh
@@ -0,0 +1,33 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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_SYNC_HH
+#define PALUDIS_GUARD_SRC_SYNC_HH 1
+
+#include "src/command_line.hh"
+
+/** \file
+ * Declaration for the do_sync function.
+ */
+
+/// Handle --sync.
+int do_sync();
+
+#endif
+
diff --git a/0.4.0/src/uninstall.cc b/0.4.0/src/uninstall.cc
new file mode 100644
index 000000000..2acec9b3a
--- /dev/null
+++ b/0.4.0/src/uninstall.cc
@@ -0,0 +1,155 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "src/colour.hh"
+#include "src/uninstall.hh"
+#include <iostream>
+#include <paludis/paludis.hh>
+
+/** \file
+ * Handle the --uninstall action for the main paludis program.
+ */
+
+namespace p = paludis;
+
+using std::cerr;
+using std::cout;
+using std::endl;
+
+namespace
+{
+ void world_remove_callback(const p::PackageDepAtom * const p)
+ {
+ cout << "* removing " << *p << endl;
+ }
+}
+
+int
+do_uninstall()
+{
+ int return_code(0);
+
+ p::Context context("When performing uninstall action from command line:");
+ p::Environment * const env(p::DefaultEnvironment::get_instance());
+
+ cout << colour(cl_heading, "These packages will be uninstalled:") << endl << endl;
+
+ std::list<p::PackageDepAtom::Pointer> targets;
+
+ CommandLine::ParametersIterator q(CommandLine::get_instance()->begin_parameters()),
+ q_end(CommandLine::get_instance()->end_parameters());
+
+ for ( ; q != q_end ; ++q)
+ {
+ /* we might have a dep atom, but we might just have a simple package name
+ * without a category. either should work. */
+ if (std::string::npos != q->find('/'))
+ targets.push_back(p::PackageDepAtom::Pointer(new p::PackageDepAtom(*q)));
+ else
+ targets.push_back(p::PackageDepAtom::Pointer(new p::PackageDepAtom(
+ env->package_database()->fetch_unique_qualified_package_name(
+ p::PackageNamePart(*q)))));
+ }
+
+ bool ok(true);
+ p::PackageDatabaseEntryCollection::Pointer unmerge(new p::PackageDatabaseEntryCollection);
+ for (std::list<p::PackageDepAtom::Pointer>::iterator t(targets.begin()), t_end(targets.end()) ;
+ t != t_end ; ++t)
+ {
+ p::PackageDatabaseEntryCollection::ConstPointer r(
+ env->package_database()->query(*t, p::is_installed_only));
+ if (r->empty())
+ {
+ cout << "* No match for " << colour(cl_red, **t) << endl;
+ ok = false;
+ }
+ else if (r->size() > 1)
+ {
+ cout << "* Multiple matches for " << colour(cl_red, **t) << ":" << endl;
+ for (p::PackageDatabaseEntryCollection::Iterator p(r->begin()),
+ p_end(r->end()) ; p != p_end ; ++p)
+ cout << " * " << *p << endl;
+ ok = false;
+ }
+ else
+ {
+ cout << "* " << colour(cl_package_name, *r->begin()) << endl;
+ unmerge->insert(*r->begin());
+ }
+ }
+
+ int current_count = 0, max_count = std::distance(unmerge->begin(), unmerge->end());
+
+ cout << endl << "Total: " << max_count <<
+ (max_count == 1 ? " package" : " packages") << endl << endl;
+
+ if (! ok)
+ return 1 | return_code;
+
+ if (CommandLine::get_instance()->a_pretend.specified())
+ return return_code;
+
+ cout << endl << colour(cl_heading, "Updating world file") << endl << endl;
+ if (! CommandLine::get_instance()->a_preserve_world.specified())
+ {
+ p::AllDepAtom::Pointer all(new p::AllDepAtom);
+ for (std::list<p::PackageDepAtom::Pointer>::const_iterator t(targets.begin()),
+ t_end(targets.end()) ; t != t_end ; ++t)
+ all->add_child(*t);
+
+ env->remove_appropriate_from_world(all, &world_remove_callback);
+ }
+ else
+ cout << "* --preserve-world was specified, skipping world removes" << endl;
+
+ p::InstallOptions opts(false, false);
+ if (CommandLine::get_instance()->a_no_config_protection.specified())
+ opts.set<p::io_noconfigprotect>(true);
+
+ env->perform_hook(p::Hook("uninstall_all_pre")("TARGETS", join(unmerge->begin(), unmerge->end(), " ")));
+ for (p::PackageDatabaseEntryCollection::Iterator pkg(unmerge->begin()), pkg_end(unmerge->end()) ;
+ pkg != pkg_end ; ++pkg)
+ {
+ std::string cpvr = p::stringify(pkg->get<p::pde_name>()) + "-" +
+ p::stringify(pkg->get<p::pde_version>()) + "::" +
+ p::stringify(pkg->get<p::pde_repository>());
+
+ cout << endl << colour(cl_heading,
+ "Uninstalling " + cpvr) << endl << endl;
+
+ // TODO: some way to reset this properly would be nice.
+ cerr << xterm_title("(" + p::stringify(++current_count) + " of " +
+ p::stringify(max_count) + ") Uninstalling " + cpvr);
+
+ env->perform_hook(p::Hook("uninstall_pre")("TARGET", cpvr));
+ const p::Repository::UninstallableInterface * const uninstall_interface(
+ env->package_database()->fetch_repository(pkg->get<p::pde_repository>())->
+ get_interface<p::repo_uninstallable>());
+ if (! uninstall_interface)
+ throw p::InternalError(PALUDIS_HERE, "Trying to uninstall from a non-uninstallable repo");
+ uninstall_interface->uninstall(pkg->get<p::pde_name>(), pkg->get<p::pde_version>(), opts);
+ env->perform_hook(p::Hook("uninstall_post")("TARGET", cpvr));
+ }
+ env->perform_hook(p::Hook("uninstall_all_post")("TARGETS", join(unmerge->begin(), unmerge->end(), " ")));
+
+ cout << endl;
+
+ return return_code;
+}
+
diff --git a/0.4.0/src/uninstall.hh b/0.4.0/src/uninstall.hh
new file mode 100644
index 000000000..06485d6b2
--- /dev/null
+++ b/0.4.0/src/uninstall.hh
@@ -0,0 +1,33 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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_UNINSTALL_HH
+#define PALUDIS_GUARD_SRC_UNINSTALL_HH 1
+
+#include "src/command_line.hh"
+
+/** \file
+ * Declaration for the do_uninstall function.
+ */
+
+/// Handle --uninstall.
+int do_uninstall();
+
+#endif
+
diff --git a/0.4.0/src/upgrade_TEST b/0.4.0/src/upgrade_TEST
new file mode 100755
index 000000000..48b315fe3
--- /dev/null
+++ b/0.4.0/src/upgrade_TEST
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+PALUDIS_HOME=./upgrade_TEST_dir/config/ \
+ ./paludis --config-suffix upgrade-test --install =test-category/target-1 || exit 1
+
+./upgrade_TEST_dir/root/usr/bin/testbin | grep testbin-1 >/dev/null || exit 1
+./upgrade_TEST_dir/root/usr/bin/testbin1 | grep testbin1 >/dev/null || exit 1
+./upgrade_TEST_dir/root/usr/bin/testbin2 && exit 1
+
+
+PALUDIS_HOME=./upgrade_TEST_dir/config/ \
+ ./paludis --config-suffix upgrade-test --install target || exit 1
+
+./upgrade_TEST_dir/root/usr/bin/testbin | grep testbin-2 >/dev/null || exit 1
+./upgrade_TEST_dir/root/usr/bin/testbin1 && exit 1
+./upgrade_TEST_dir/root/usr/bin/testbin2 | grep testbin2 >/dev/null || exit 1
+
diff --git a/0.4.0/src/upgrade_TEST_cleanup.sh b/0.4.0/src/upgrade_TEST_cleanup.sh
new file mode 100755
index 000000000..bc42e7885
--- /dev/null
+++ b/0.4.0/src/upgrade_TEST_cleanup.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d upgrade_TEST_dir ] ; then
+ rm -fr upgrade_TEST_dir
+else
+ true
+fi
+
+
+
diff --git a/0.4.0/src/upgrade_TEST_setup.sh b/0.4.0/src/upgrade_TEST_setup.sh
new file mode 100755
index 000000000..eb69c9535
--- /dev/null
+++ b/0.4.0/src/upgrade_TEST_setup.sh
@@ -0,0 +1,153 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir upgrade_TEST_dir || exit 1
+cd upgrade_TEST_dir || exit 1
+
+mkdir -p config/.paludis-upgrade-test
+cat <<END > config/.paludis-upgrade-test/specpath
+root = `pwd`/root
+config-suffix =
+END
+
+mkdir -p root/${SYSCONFDIR}/paludis/repositories
+cat <<END > root/${SYSCONFDIR}/paludis/use.conf
+* foo
+END
+
+cat <<END > root/${SYSCONFDIR}/paludis/licenses.conf
+* *
+END
+
+cat <<END > root/${SYSCONFDIR}/paludis/keywords.conf
+* test
+END
+
+cat <<END > root/${SYSCONFDIR}/paludis/bashrc
+export CHOST="my-chost"
+export USER_BASHRC_WAS_USED=yes
+END
+
+cat <<END > root/${SYSCONFDIR}/paludis/repositories/repo1.conf
+location = `pwd`/repo1
+cache = /var/empty
+format = portage
+profile = \${location}/profiles/testprofile
+buildroot = `pwd`/build
+END
+
+cat <<END > root/${SYSCONFDIR}/paludis/repositories/installed.conf
+location = \${ROOT}/var/db/pkg
+format = vdb
+buildroot = `pwd`/build
+END
+
+mkdir -p root/tmp
+touch root/${SYSCONFDIR}/ld.so.conf
+mkdir -p root/var/db/pkg
+
+mkdir -p repo1/{eclass,distfiles,profiles/testprofile,test-category/target/files} || exit 1
+
+mkdir -p src/target-1
+cat <<"END" > src/target-1/testbin
+#!/bin/bash
+echo "This is testbin-1"
+END
+chmod +x src/target-1/testbin
+cat <<"END" > src/target-1/testbin1
+#!/bin/bash
+echo "This is testbin1"
+END
+chmod +x src/target-1/testbin1
+cd src
+tar zcf target-1.tar.gz target-1/
+mv target-1.tar.gz ../repo1/distfiles/
+cd ..
+rm -fr src
+
+mkdir -p src/target-2
+cat <<"END" > src/target-2/testbin
+#!/bin/bash
+echo "This is testbin-2"
+END
+chmod +x src/target-2/testbin
+cat <<"END" > src/target-2/testbin2
+#!/bin/bash
+echo "This is testbin2"
+END
+chmod +x src/target-2/testbin2
+cd src
+tar zcf target-2.tar.gz target-2/
+mv target-2.tar.gz ../repo1/distfiles/
+cd ..
+rm -fr src
+
+cd repo1 || exit 1
+echo "test-repo-1" > profiles/repo_name || exit 1
+cat <<END > profiles/categories || exit 1
+test-category
+END
+cat <<END > profiles/testprofile/make.defaults
+ARCH=test
+USERLAND=test
+KERNEL=test
+END
+
+cat <<"END" > eclass/myeclass.eclass || exit 1
+the_eclass_works()
+{
+ true
+}
+END
+
+cat <<"END" > test-category/target/target-1.ebuild || exit 1
+inherit myeclass
+
+DESCRIPTION="Test target"
+HOMEPAGE="http://paludis.berlios.de/"
+SRC_URI="http://invalid.domain/${P}.tar.gz"
+SLOT="0"
+IUSE=""
+LICENSE="GPL-2"
+KEYWORDS="test"
+
+pkg_setup() {
+ export VAR1=yes
+ VAR2=yes
+ local VAR3=yes
+}
+
+src_install() {
+ [[ "${VAR1}" == yes ]] || die
+ [[ "${VAR2}" == yes ]] || die
+ [[ "${VAR3}" == yes ]] && die
+
+ dobin testbin
+ dobin testbin${PV}
+}
+
+pkg_prerm() {
+ [[ "${VAR1}" == yes ]] || die
+ [[ "${VAR2}" == yes ]] || die
+ [[ "${VAR3}" == yes ]] && die
+
+ the_eclass_works || die
+}
+END
+
+cat <<"END" > test-category/target/target-2.ebuild || exit 1
+DESCRIPTION="Test target"
+HOMEPAGE="http://paludis.berlios.de/"
+SRC_URI="http://invalid.domain/${P}.tar.gz"
+SLOT="0"
+IUSE=""
+LICENSE="GPL-2"
+KEYWORDS="test"
+
+src_install() {
+ dobin testbin
+ dobin testbin${PV}
+}
+END
+cd ..
+
diff --git a/0.4.0/src/version_TEST b/0.4.0/src/version_TEST
new file mode 100755
index 000000000..02513f03a
--- /dev/null
+++ b/0.4.0/src/version_TEST
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+PALUDIS_SKIP_CONFIG=yes ./paludis --version