aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2009-08-14 17:34:04 +0100
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2009-08-14 17:34:04 +0100
commita772947849ba0d72659cf81dbbb8fe4b1a21c2fb (patch)
tree89fafca881cb956e79b44d8ff6d63dd0443ba6a8
parentebf6b0f75873c80d7103e53b60c1cf8333462f07 (diff)
parent51760bee6b5d17bd212a5057cf9e0681c13c0a5d (diff)
downloadpaludis-a772947849ba0d72659cf81dbbb8fe4b1a21c2fb.tar.gz
paludis-a772947849ba0d72659cf81dbbb8fe4b1a21c2fb.tar.xz
Merge commit 'github-com/cave-resolve'
-rw-r--r--configure.ac15
-rw-r--r--paludis/Makefile.am.m42
-rw-r--r--paludis/args/args_option.cc7
-rw-r--r--paludis/repositories/virtuals/installed_virtuals_repository.cc29
-rw-r--r--paludis/repositories/virtuals/installed_virtuals_repository.hh18
-rw-r--r--paludis/resolver/Makefile.am70
-rw-r--r--paludis/resolver/arrow-fwd.hh40
-rw-r--r--paludis/resolver/arrow.cc39
-rw-r--r--paludis/resolver/arrow.hh45
-rw-r--r--paludis/resolver/constraint-fwd.hh39
-rw-r--r--paludis/resolver/constraint.cc122
-rw-r--r--paludis/resolver/constraint.hh80
-rw-r--r--paludis/resolver/decision-fwd.hh36
-rw-r--r--paludis/resolver/decision.cc52
-rw-r--r--paludis/resolver/decision.hh53
-rw-r--r--paludis/resolver/destinations-fwd.hh38
-rw-r--r--paludis/resolver/destinations.cc58
-rw-r--r--paludis/resolver/destinations.hh53
-rw-r--r--paludis/resolver/qpn_s-fwd.hh39
-rw-r--r--paludis/resolver/qpn_s.cc159
-rw-r--r--paludis/resolver/qpn_s.hh69
-rw-r--r--paludis/resolver/reason-fwd.hh40
-rw-r--r--paludis/resolver/reason.cc141
-rw-r--r--paludis/resolver/reason.hh103
-rw-r--r--paludis/resolver/resolution-fwd.hh36
-rw-r--r--paludis/resolver/resolution.cc47
-rw-r--r--paludis/resolver/resolution.hh58
-rw-r--r--paludis/resolver/resolver-fwd.hh31
-rw-r--r--paludis/resolver/resolver.cc1303
-rw-r--r--paludis/resolver/resolver.hh173
-rw-r--r--paludis/resolver/resolver_functions-fwd.hh31
-rw-r--r--paludis/resolver/resolver_functions.hh74
-rw-r--r--paludis/resolver/sanitised_dependencies-fwd.hh40
-rw-r--r--paludis/resolver/sanitised_dependencies.cc421
-rw-r--r--paludis/resolver/sanitised_dependencies.hh87
-rw-r--r--paludis/resolver/suggest_restart-fwd.hh31
-rw-r--r--paludis/resolver/suggest_restart.cc108
-rw-r--r--paludis/resolver/suggest_restart.hh62
-rw-r--r--paludis/resolver/use_installed-fwd.hh34
-rw-r--r--paludis/resolver/use_installed.cc29
-rw-r--r--paludis/resolver/use_installed.hh33
-rw-r--r--paludis/resolver/use_installed.se16
-rw-r--r--src/clients/cave/Makefile.am12
-rw-r--r--src/clients/cave/cmd_resolve.cc638
-rw-r--r--src/clients/cave/cmd_resolve.hh46
-rw-r--r--src/clients/cave/cmd_resolve_cmdline.cc250
-rw-r--r--src/clients/cave/cmd_resolve_cmdline.hh126
-rw-r--r--src/clients/cave/cmd_resolve_display_callback.cc142
-rw-r--r--src/clients/cave/cmd_resolve_display_callback.hh50
-rw-r--r--src/clients/cave/cmd_resolve_display_explanations.cc156
-rw-r--r--src/clients/cave/cmd_resolve_display_explanations.hh38
-rw-r--r--src/clients/cave/cmd_resolve_display_resolution.cc258
-rw-r--r--src/clients/cave/cmd_resolve_display_resolution.hh38
-rw-r--r--src/clients/cave/cmd_resolve_dump.cc59
-rw-r--r--src/clients/cave/cmd_resolve_dump.hh38
-rw-r--r--src/clients/cave/colour_formatter.cc47
-rw-r--r--src/clients/cave/colour_formatter.hh11
-rw-r--r--src/clients/cave/command_factory.cc4
-rw-r--r--src/clients/cave/formats.cc42
-rw-r--r--src/clients/cave/formats.hh8
60 files changed, 5912 insertions, 12 deletions
diff --git a/configure.ac b/configure.ac
index 74904c1..d91ac4a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -105,6 +105,7 @@ need_xml_check=
need_pcrecpp_check=
need_syck_check=
need_gem_check=
+need_resolver=
dnl {{{ we can use abi::__cxa_demangle
AC_MSG_CHECKING([for abi::__cxa_demangle])
@@ -1445,6 +1446,19 @@ AC_SUBST([BUILD_CLIENTS])
if echo $clients | tr ' ' '\n' | grep '^inquisitio$' >/dev/null ; then
need_pcrecpp_check=yes
fi
+
+if echo $clients | tr ' ' '\n' | grep '^cave$' >/dev/null ; then
+ need_resolver=yes
+fi
+dnl }}}
+
+dnl {{{ new resolver
+
+if test "x$need_resolver" = "xyes" ; then
+ AC_DEFINE([ENABLE_NEW_RESOLVER], [1], [Enable new resolver])
+fi
+AM_CONDITIONAL([ENABLE_NEW_RESOLVER], test "x$need_resolver" = "xyes")
+
dnl }}}
dnl {{{ libxml2 check
@@ -1622,6 +1636,7 @@ AC_OUTPUT(
paludis/repositories/unpackaged/Makefile
paludis/repositories/unwritten/Makefile
paludis/repositories/virtuals/Makefile
+ paludis/resolver/Makefile
paludis/selinux/Makefile
paludis/syncers/Makefile
paludis/util/Makefile
diff --git a/paludis/Makefile.am.m4 b/paludis/Makefile.am.m4
index 7419865..d59805a 100644
--- a/paludis/Makefile.am.m4
+++ b/paludis/Makefile.am.m4
@@ -83,7 +83,7 @@ EXTRA_DIST = about.hh.in Makefile.am.m4 paludis.hh.m4 files.m4 \
testscriptlist srlist srcleanlist selist secleanlist \
hooker.bash \
stripper_TEST_binary.cc
-SUBDIRS = distributions fetchers syncers util selinux . repositories environments args
+SUBDIRS = distributions fetchers syncers util selinux . repositories environments args resolver
BUILT_SOURCES = srcleanlist secleanlist
libpaludis_@PALUDIS_PC_SLOT@_la_SOURCES = filelist
diff --git a/paludis/args/args_option.cc b/paludis/args/args_option.cc
index 6df2dd2..b44786b 100644
--- a/paludis/args/args_option.cc
+++ b/paludis/args/args_option.cc
@@ -276,11 +276,12 @@ EnumArg::set_argument(const std::string & arg)
{
Context context("When handling argument '" + arg + "' for '--" + long_name() + "':");
- if (_imp->allowed_args.end() == std::find_if(_imp->allowed_args.begin(),
- _imp->allowed_args.end(), ArgIs(arg)))
+ /* if we're given the short arg, turn it magically into the long one */
+ AllowedArgConstIterator i(std::find_if(_imp->allowed_args.begin(), _imp->allowed_args.end(), ArgIs(arg)));
+ if (i == _imp->allowed_args.end())
throw (BadValue("--" + long_name(), arg));
- _argument = arg;
+ _argument = i->long_name();
}
void
diff --git a/paludis/repositories/virtuals/installed_virtuals_repository.cc b/paludis/repositories/virtuals/installed_virtuals_repository.cc
index bfd3ae8..60820bf 100644
--- a/paludis/repositories/virtuals/installed_virtuals_repository.cc
+++ b/paludis/repositories/virtuals/installed_virtuals_repository.cc
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2006, 2007, 2008 Ciaran McCreesh
+ * Copyright (c) 2006, 2007, 2008, 2009 Ciaran McCreesh
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
@@ -110,7 +110,7 @@ namespace
InstalledVirtualsRepository::InstalledVirtualsRepository(const Environment * const env,
const FSEntry & r) :
Repository(env, RepositoryName(make_name(r)), make_named_values<RepositoryCapabilities>(
- value_for<n::destination_interface>(static_cast<RepositoryDestinationInterface *>(0)),
+ value_for<n::destination_interface>(static_cast<RepositoryDestinationInterface *>(this)),
value_for<n::e_interface>(static_cast<RepositoryEInterface *>(0)),
value_for<n::environment_variable_interface>(static_cast<RepositoryEnvironmentVariableInterface *>(0)),
value_for<n::hook_interface>(this),
@@ -363,4 +363,29 @@ InstalledVirtualsRepository::repository_factory_dependencies(
return make_shared_ptr(new RepositoryNameSet);
}
+bool
+InstalledVirtualsRepository::is_suitable_destination_for(const PackageID & e) const
+{
+ std::string f(e.repository()->format_key() ? e.repository()->format_key()->value() : "");
+ return f == "virtuals";
+
+}
+
+bool
+InstalledVirtualsRepository::is_default_destination() const
+{
+ return false;
+}
+
+bool
+InstalledVirtualsRepository::want_pre_post_phases() const
+{
+ return false;
+}
+
+void
+InstalledVirtualsRepository::merge(const MergeParams &)
+{
+ throw InternalError(PALUDIS_HERE, "can't merge to installed virtuals");
+}
diff --git a/paludis/repositories/virtuals/installed_virtuals_repository.hh b/paludis/repositories/virtuals/installed_virtuals_repository.hh
index b9f7ef9..af9e9e0 100644
--- a/paludis/repositories/virtuals/installed_virtuals_repository.hh
+++ b/paludis/repositories/virtuals/installed_virtuals_repository.hh
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2006, 2007, 2008 Ciaran McCreesh
+ * Copyright (c) 2006, 2007, 2008, 2009 Ciaran McCreesh
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
@@ -35,6 +35,7 @@ namespace paludis
class PALUDIS_VISIBLE InstalledVirtualsRepository :
public Repository,
public RepositoryHookInterface,
+ public RepositoryDestinationInterface,
public std::tr1::enable_shared_from_this<InstalledVirtualsRepository>,
private PrivateImplementationPattern<InstalledVirtualsRepository>
{
@@ -111,6 +112,21 @@ namespace paludis
virtual const std::tr1::shared_ptr<const MetadataValueKey<std::string> > format_key() const;
virtual const std::tr1::shared_ptr<const MetadataValueKey<FSEntry> > location_key() const;
virtual const std::tr1::shared_ptr<const MetadataValueKey<FSEntry> > installed_root_key() const;
+
+ /* RepositoryDestinationInterface */
+
+ virtual bool is_suitable_destination_for(const PackageID &) const
+ PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ virtual bool is_default_destination() const
+ PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ virtual bool want_pre_post_phases() const
+ PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ virtual void merge(const MergeParams &) PALUDIS_ATTRIBUTE((noreturn));
+
+ ///\}
};
}
diff --git a/paludis/resolver/Makefile.am b/paludis/resolver/Makefile.am
new file mode 100644
index 0000000..33b18e7
--- /dev/null
+++ b/paludis/resolver/Makefile.am
@@ -0,0 +1,70 @@
+CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda *.loT *.epicfail
+MAINTAINERCLEANFILES = Makefile.in
+DISTCLEANFILES = \
+ use_installed-se.hh use_installed-se.cc
+AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@ @PALUDIS_CXXFLAGS_VISIBILITY@
+EXTRA_DIST = \
+ use_installed-se.hh use_installed-se.cc use_installed.se
+BUILT_SOURCES = \
+ use_installed-se.hh use_installed-se.cc
+
+TESTS =
+
+noinst_HEADERS = \
+ arrow.hh arrow-fwd.hh \
+ constraint.hh constraint-fwd.hh \
+ decision.hh decision-fwd.hh \
+ destinations.hh destinations-fwd.hh \
+ qpn_s.hh qpn_s-fwd.hh \
+ reason.hh reason-fwd.hh \
+ resolution.hh resolution-fwd.hh \
+ resolver.hh resolver-fwd.hh \
+ resolver_functions.hh resolver_functions-fwd.hh \
+ sanitised_dependencies.hh sanitised_dependencies-fwd.hh \
+ suggest_restart.hh suggest_restart-fwd.hh \
+ use_installed.hh use_installed-fwd.hh use_installed-se.hh
+
+libpaludisresolver_a_SOURCES = \
+ arrow.cc \
+ constraint.cc \
+ decision.cc \
+ destinations.cc \
+ qpn_s.cc \
+ reason.cc \
+ resolution.cc \
+ resolver.cc \
+ sanitised_dependencies.cc \
+ suggest_restart.cc \
+ use_installed.cc
+
+TESTS_ENVIRONMENT = env PALUDIS_OPTIONS="" \
+ TEST_SCRIPT_DIR="$(srcdir)/" \
+ PALUDIS_REPOSITORY_SO_DIR="$(top_builddir)/paludis/repositories" \
+ PALUDIS_DISTRIBUTION="gentoo" \
+ bash $(top_srcdir)/test/run_test.sh
+
+if ENABLE_NEW_RESOLVER
+noinst_LIBRARIES = libpaludisresolver.a
+endif
+
+check_PROGRAMS = $(TESTS)
+
+built-sources : $(BUILT_SOURCES)
+ for s in `echo $(SUBDIRS) | tr -d .` ; do $(MAKE) -C $$s built-sources || exit 1 ; done
+
+DISTCHECK_DEPS =
+
+distcheck-deps-local : $(DISTCHECK_DEPS)
+
+distcheck-deps : distcheck-deps-subdirs
+
+distcheck-deps-subdirs :
+ for s in $(SUBDIRS) . ; do if test x$$s = x. ; then $(MAKE) distcheck-deps-local || exit 1 ; \
+ else $(MAKE) -C $$s distcheck-deps || exit 1 ; fi ; done
+
+use_installed-se.hh : use_installed.se $(top_srcdir)/misc/make_se.bash
+ if ! $(top_srcdir)/misc/make_se.bash --header $(srcdir)/use_installed.se > $@ ; then rm -f $@ ; exit 1 ; fi
+
+use_installed-se.cc : use_installed.se $(top_srcdir)/misc/make_se.bash
+ if ! $(top_srcdir)/misc/make_se.bash --source $(srcdir)/use_installed.se > $@ ; then rm -f $@ ; exit 1 ; fi
+
diff --git a/paludis/resolver/arrow-fwd.hh b/paludis/resolver/arrow-fwd.hh
new file mode 100644
index 0000000..e36f55d
--- /dev/null
+++ b/paludis/resolver/arrow-fwd.hh
@@ -0,0 +1,40 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_ARROW_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_ARROW_FWD_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <paludis/util/sequence-fwd.hh>
+#include <tr1/memory>
+#include <iosfwd>
+
+namespace paludis
+{
+ namespace resolver
+ {
+ struct Arrow;
+
+ typedef Sequence<std::tr1::shared_ptr<Arrow> > ArrowSequence;
+
+ std::ostream & operator<< (std::ostream & s, const Arrow &) PALUDIS_VISIBLE;
+ }
+}
+
+#endif
diff --git a/paludis/resolver/arrow.cc b/paludis/resolver/arrow.cc
new file mode 100644
index 0000000..5b745cd
--- /dev/null
+++ b/paludis/resolver/arrow.cc
@@ -0,0 +1,39 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/resolver/arrow.hh>
+#include <paludis/util/sequence-impl.hh>
+#include <paludis/util/wrapped_forward_iterator-impl.hh>
+
+using namespace paludis;
+using namespace paludis::resolver;
+
+std::ostream &
+paludis::resolver::operator<< (std::ostream & s, const Arrow & a)
+{
+ s << "Arrow(-> " << a.to_qpn_s();
+ if (0 != a.ignorable_pass())
+ s << ", ignorable pass " << a.ignorable_pass();
+ s << ")";
+ return s;
+}
+
+template class Sequence<std::tr1::shared_ptr<Arrow> >;
+template class WrappedForwardIterator<ArrowSequence::ConstIteratorTag, const std::tr1::shared_ptr<Arrow> >;
+
diff --git a/paludis/resolver/arrow.hh b/paludis/resolver/arrow.hh
new file mode 100644
index 0000000..7798d03
--- /dev/null
+++ b/paludis/resolver/arrow.hh
@@ -0,0 +1,45 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_ARROW_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_ARROW_HH 1
+
+#include <paludis/resolver/arrow-fwd.hh>
+#include <paludis/resolver/qpn_s.hh>
+#include <paludis/util/named_value.hh>
+
+namespace paludis
+{
+ namespace n
+ {
+ struct ignorable_pass;
+ struct to_qpn_s;
+ }
+
+ namespace resolver
+ {
+ struct Arrow
+ {
+ NamedValue<n::ignorable_pass, int> ignorable_pass;
+ NamedValue<n::to_qpn_s, QPN_S> to_qpn_s;
+ };
+ }
+}
+
+#endif
diff --git a/paludis/resolver/constraint-fwd.hh b/paludis/resolver/constraint-fwd.hh
new file mode 100644
index 0000000..e9943e9
--- /dev/null
+++ b/paludis/resolver/constraint-fwd.hh
@@ -0,0 +1,39 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_CONSTRAINT_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_CONSTRAINT_FWD_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <paludis/util/sequence-fwd.hh>
+#include <tr1/memory>
+#include <iosfwd>
+
+namespace paludis
+{
+ namespace resolver
+ {
+ struct Constraint;
+ struct Constraints;
+
+ std::ostream & operator<< (std::ostream & s, const Constraint & c) PALUDIS_VISIBLE;
+ }
+}
+
+#endif
diff --git a/paludis/resolver/constraint.cc b/paludis/resolver/constraint.cc
new file mode 100644
index 0000000..cb7bd59
--- /dev/null
+++ b/paludis/resolver/constraint.cc
@@ -0,0 +1,122 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/resolver/constraint.hh>
+#include <paludis/resolver/reason.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <paludis/util/wrapped_forward_iterator-impl.hh>
+#include <sstream>
+#include <list>
+
+using namespace paludis;
+using namespace paludis::resolver;
+
+std::ostream &
+paludis::resolver::operator<< (std::ostream & s, const Constraint & c)
+{
+ std::stringstream ss;
+ ss << "Constraint(spec: " << c.spec();
+ if (c.nothing_is_fine_too())
+ ss << "; nothing is fine too";
+ ss
+ << "; use_installed: " << stringify(c.use_installed())
+ << "; reason: " << (c.reason() ? stringify(*c.reason()) : "none")
+ << ")";
+ s << ss.str();
+
+ return s;
+}
+
+namespace paludis
+{
+ template <>
+ struct Implementation<Constraints>
+ {
+ UseInstalled strictest_use_installed;
+ bool nothing_is_fine_too;
+ bool to_destination_slash;
+ std::list<std::tr1::shared_ptr<const Constraint> > constraints;
+
+ Implementation() :
+ strictest_use_installed(ui_if_possible),
+ nothing_is_fine_too(true),
+ to_destination_slash(false)
+ {
+ }
+ };
+}
+
+Constraints::Constraints() :
+ PrivateImplementationPattern<Constraints>(new Implementation<Constraints>)
+{
+}
+
+Constraints::~Constraints()
+{
+}
+
+Constraints::ConstIterator
+Constraints::begin() const
+{
+ return ConstIterator(_imp->constraints.begin());
+}
+
+Constraints::ConstIterator
+Constraints::end() const
+{
+ return ConstIterator(_imp->constraints.end());
+}
+
+void
+Constraints::add(const std::tr1::shared_ptr<const Constraint> & c)
+{
+ _imp->constraints.push_back(c);
+ _imp->strictest_use_installed = std::min(_imp->strictest_use_installed, c->use_installed());
+ _imp->nothing_is_fine_too = _imp->nothing_is_fine_too && c->nothing_is_fine_too();
+ _imp->to_destination_slash = _imp->to_destination_slash || c->to_destination_slash();
+}
+
+bool
+Constraints::empty() const
+{
+ return _imp->constraints.empty();
+}
+
+UseInstalled
+Constraints::strictest_use_installed() const
+{
+ return _imp->strictest_use_installed;
+}
+
+bool
+Constraints::nothing_is_fine_too() const
+{
+ return _imp->nothing_is_fine_too;
+}
+
+bool
+Constraints::to_destination_slash() const
+{
+ return _imp->to_destination_slash;
+}
+
+template class PrivateImplementationPattern<Constraints>;
+template class WrappedForwardIterator<Constraints::ConstIteratorTag, const std::tr1::shared_ptr<const Constraint> >;
+
diff --git a/paludis/resolver/constraint.hh b/paludis/resolver/constraint.hh
new file mode 100644
index 0000000..7b6fbdb
--- /dev/null
+++ b/paludis/resolver/constraint.hh
@@ -0,0 +1,80 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_CONSTRAINT_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_CONSTRAINT_HH 1
+
+#include <paludis/resolver/constraint-fwd.hh>
+#include <paludis/resolver/reason-fwd.hh>
+#include <paludis/resolver/use_installed-fwd.hh>
+#include <paludis/resolver/sanitised_dependencies.hh>
+#include <paludis/util/named_value.hh>
+#include <paludis/dep_spec.hh>
+#include <tr1/memory>
+
+namespace paludis
+{
+ namespace n
+ {
+ struct nothing_is_fine_too;
+ struct reason;
+ struct spec;
+ struct to_destination_slash;
+ struct use_installed;
+ }
+
+ namespace resolver
+ {
+ struct Constraint
+ {
+ NamedValue<n::nothing_is_fine_too, bool> nothing_is_fine_too;
+ NamedValue<n::reason, std::tr1::shared_ptr<const Reason> > reason;
+ NamedValue<n::spec, PackageOrBlockDepSpec> spec;
+ NamedValue<n::to_destination_slash, bool> to_destination_slash;
+ NamedValue<n::use_installed, UseInstalled> use_installed;
+ };
+
+ class PALUDIS_VISIBLE Constraints :
+ private PrivateImplementationPattern<Constraints>
+ {
+ public:
+ Constraints();
+ ~Constraints();
+
+ UseInstalled strictest_use_installed() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ bool nothing_is_fine_too() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ bool to_destination_slash() const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ void add(const std::tr1::shared_ptr<const Constraint> &);
+
+ struct ConstIteratorTag;
+ typedef WrappedForwardIterator<ConstIteratorTag, const std::tr1::shared_ptr<const Constraint> > ConstIterator;
+ ConstIterator begin() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ ConstIterator end() const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ bool empty() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ };
+ }
+
+#ifdef PALUDIS_HAVE_EXTERN_TEMPLATE
+ extern template class PrivateImplementationPattern<resolver::Constraints>;
+#endif
+}
+
+#endif
diff --git a/paludis/resolver/decision-fwd.hh b/paludis/resolver/decision-fwd.hh
new file mode 100644
index 0000000..a17c564
--- /dev/null
+++ b/paludis/resolver/decision-fwd.hh
@@ -0,0 +1,36 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_DECISION_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_DECISION_FWD_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <iosfwd>
+
+namespace paludis
+{
+ namespace resolver
+ {
+ struct Decision;
+
+ std::ostream & operator<< (std::ostream & s, const Decision & d) PALUDIS_VISIBLE;
+ }
+}
+
+#endif
diff --git a/paludis/resolver/decision.cc b/paludis/resolver/decision.cc
new file mode 100644
index 0000000..32ea044
--- /dev/null
+++ b/paludis/resolver/decision.cc
@@ -0,0 +1,52 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/resolver/decision.hh>
+#include <sstream>
+
+using namespace paludis;
+using namespace paludis::resolver;
+
+std::ostream &
+paludis::resolver::operator<< (std::ostream & s, const Decision & d)
+{
+ std::stringstream ss;
+
+ ss << "Decision(";
+
+ if (d.if_package_id())
+ ss << *d.if_package_id();
+ else
+ ss << "(nothing)";
+
+ if (d.is_installed())
+ ss << ", is installed";
+ if (d.is_nothing())
+ ss << ", is nothing";
+ if (d.is_same())
+ ss << ", is same";
+ if (d.is_same_version())
+ ss << ", is same version";
+
+ ss << ")";
+
+ s << ss.str();
+ return s;
+}
+
diff --git a/paludis/resolver/decision.hh b/paludis/resolver/decision.hh
new file mode 100644
index 0000000..e4995dc
--- /dev/null
+++ b/paludis/resolver/decision.hh
@@ -0,0 +1,53 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_DECISION_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_DECISION_HH 1
+
+#include <paludis/resolver/decision-fwd.hh>
+#include <paludis/util/named_value.hh>
+#include <paludis/package_id.hh>
+
+namespace paludis
+{
+ namespace n
+ {
+ struct if_package_id;
+ struct is_installed;
+ struct is_nothing;
+ struct is_same;
+ struct is_same_version;
+ struct is_transient;
+ }
+
+ namespace resolver
+ {
+ struct Decision
+ {
+ NamedValue<n::if_package_id, std::tr1::shared_ptr<const PackageID> > if_package_id;
+ NamedValue<n::is_installed, bool> is_installed;
+ NamedValue<n::is_nothing, bool> is_nothing;
+ NamedValue<n::is_same, bool> is_same;
+ NamedValue<n::is_same_version, bool> is_same_version;
+ NamedValue<n::is_transient, bool> is_transient;
+ };
+ }
+}
+
+#endif
diff --git a/paludis/resolver/destinations-fwd.hh b/paludis/resolver/destinations-fwd.hh
new file mode 100644
index 0000000..9424462
--- /dev/null
+++ b/paludis/resolver/destinations-fwd.hh
@@ -0,0 +1,38 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_DESTINATIONS_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_DESTINATIONS_FWD_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <iosfwd>
+
+namespace paludis
+{
+ namespace resolver
+ {
+ struct Destination;
+ struct Destinations;
+
+ std::ostream & operator<< (std::ostream &, const Destination &) PALUDIS_VISIBLE;
+ std::ostream & operator<< (std::ostream &, const Destinations &) PALUDIS_VISIBLE;
+ }
+}
+
+#endif
diff --git a/paludis/resolver/destinations.cc b/paludis/resolver/destinations.cc
new file mode 100644
index 0000000..694561c
--- /dev/null
+++ b/paludis/resolver/destinations.cc
@@ -0,0 +1,58 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/resolver/destinations.hh>
+#include <paludis/util/indirect_iterator-impl.hh>
+#include <paludis/util/sequence.hh>
+#include <paludis/util/wrapped_forward_iterator.hh>
+#include <paludis/util/join.hh>
+#include <paludis/package_id.hh>
+#include <ostream>
+#include <sstream>
+
+using namespace paludis;
+using namespace paludis::resolver;
+
+std::ostream &
+paludis::resolver::operator<< (std::ostream & s, const Destination & d)
+{
+ std::stringstream ss;
+ ss << "Destination(" << d.repository();
+ if (! d.replacing()->empty())
+ ss << " replacing " << join(indirect_iterator(d.replacing()->begin()),
+ indirect_iterator(d.replacing()->end()), ", ");
+ ss << ")";
+
+ s << ss.str();
+ return s;
+}
+
+std::ostream &
+paludis::resolver::operator<< (std::ostream & s, const Destinations & d)
+{
+ std::stringstream ss;
+ ss << "Destinations(";
+ if (d.slash())
+ ss << "slash: " << *d.slash();
+ ss << ")";
+
+ s << ss.str();
+ return s;
+}
+
diff --git a/paludis/resolver/destinations.hh b/paludis/resolver/destinations.hh
new file mode 100644
index 0000000..e3cb66d
--- /dev/null
+++ b/paludis/resolver/destinations.hh
@@ -0,0 +1,53 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_DESTINATIONS_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_DESTINATIONS_HH 1
+
+#include <paludis/resolver/destinations-fwd.hh>
+#include <paludis/util/named_value.hh>
+#include <paludis/name.hh>
+#include <paludis/package_id-fwd.hh>
+#include <tr1/memory>
+
+namespace paludis
+{
+ namespace n
+ {
+ struct replacing;
+ struct repository;
+ struct slash;
+ }
+
+ namespace resolver
+ {
+ struct Destination
+ {
+ NamedValue<n::replacing, std::tr1::shared_ptr<const PackageIDSequence> > replacing;
+ NamedValue<n::repository, RepositoryName> repository;
+ };
+
+ struct Destinations
+ {
+ NamedValue<n::slash, std::tr1::shared_ptr<Destination> > slash;
+ };
+ }
+}
+
+#endif
diff --git a/paludis/resolver/qpn_s-fwd.hh b/paludis/resolver/qpn_s-fwd.hh
new file mode 100644
index 0000000..f89f645
--- /dev/null
+++ b/paludis/resolver/qpn_s-fwd.hh
@@ -0,0 +1,39 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_QPN_S_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_QPN_S_FWD_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <paludis/util/sequence-fwd.hh>
+#include <iosfwd>
+
+namespace paludis
+{
+ namespace resolver
+ {
+ struct QPN_S;
+
+ std::ostream & operator<< (std::ostream & s, const QPN_S &) PALUDIS_VISIBLE;
+
+ typedef Sequence<QPN_S> QPN_S_Sequence;
+ }
+}
+
+#endif
diff --git a/paludis/resolver/qpn_s.cc b/paludis/resolver/qpn_s.cc
new file mode 100644
index 0000000..47746f3
--- /dev/null
+++ b/paludis/resolver/qpn_s.cc
@@ -0,0 +1,159 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/resolver/qpn_s.hh>
+#include <paludis/util/sequence-impl.hh>
+#include <paludis/util/wrapped_forward_iterator-impl.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <paludis/filter.hh>
+#include <paludis/dep_spec.hh>
+#include <paludis/package_id.hh>
+#include <paludis/metadata_key.hh>
+#include <sstream>
+
+using namespace paludis;
+using namespace paludis::resolver;
+
+namespace paludis
+{
+ template <>
+ struct Implementation<QPN_S>
+ {
+ QualifiedPackageName package;
+ std::tr1::shared_ptr<const SlotName> slot_name_or_null;
+
+ Implementation(const QualifiedPackageName & q, const std::tr1::shared_ptr<const SlotName> & s) :
+ package(q),
+ slot_name_or_null(s)
+ {
+ }
+ };
+}
+
+QPN_S::QPN_S(const QualifiedPackageName & q, const std::tr1::shared_ptr<const SlotName> & s) :
+ PrivateImplementationPattern<QPN_S>(new Implementation<QPN_S>(q, s))
+{
+}
+
+QPN_S::QPN_S(const PackageDepSpec & p, const std::tr1::shared_ptr<const SlotName> & s) :
+ PrivateImplementationPattern<QPN_S>(new Implementation<QPN_S>(*p.package_ptr(), s))
+{
+}
+
+QPN_S::QPN_S(const std::tr1::shared_ptr<const PackageID> & id) :
+ PrivateImplementationPattern<QPN_S>(new Implementation<QPN_S>(id->name(),
+ id->slot_key() ? make_shared_ptr(new SlotName(id->slot_key()->value())) : make_null_shared_ptr()))
+{
+}
+
+QPN_S::QPN_S(const QPN_S & other) :
+ PrivateImplementationPattern<QPN_S>(new Implementation<QPN_S>(other.package(), other.slot_name_or_null()))
+{
+}
+
+QPN_S::~QPN_S()
+{
+}
+
+const QualifiedPackageName
+QPN_S::package() const
+{
+ return _imp->package;
+}
+
+const std::tr1::shared_ptr<const SlotName>
+QPN_S::slot_name_or_null() const
+{
+ return _imp->slot_name_or_null;
+}
+
+bool
+QPN_S::operator< (const QPN_S & other) const
+{
+ if (package() < other.package())
+ return true;
+ if (package() > other.package())
+ return false;
+
+ /* no slot orders before any slot */
+ if (slot_name_or_null())
+ {
+ if (other.slot_name_or_null())
+ return *slot_name_or_null() < *other.slot_name_or_null();
+ else
+ return false;
+ }
+ else
+ {
+ if (other.slot_name_or_null())
+ return true;
+ else
+ return false;
+ }
+}
+
+bool
+QPN_S::operator== (const QPN_S & other) const
+{
+ if (! (package() == other.package()))
+ return false;
+
+ if (slot_name_or_null())
+ return other.slot_name_or_null() && *slot_name_or_null() == *other.slot_name_or_null();
+ else
+ return ! other.slot_name_or_null();
+}
+
+std::ostream &
+paludis::resolver::operator<< (std::ostream & s, const QPN_S & q)
+{
+ std::stringstream ss;
+ ss << q.package();
+ if (q.slot_name_or_null())
+ ss << ":" << *q.slot_name_or_null();
+ else
+ ss << ":(no slot)";
+
+ s << ss.str();
+ return s;
+}
+
+Filter
+QPN_S::make_slot_filter() const
+{
+ if (slot_name_or_null())
+ return filter::Slot(*slot_name_or_null());
+ else
+ return filter::NoSlot();
+}
+
+QPN_S &
+QPN_S::operator= (const QPN_S & other)
+{
+ if (this != &other)
+ {
+ _imp->package = other._imp->package;
+ _imp->slot_name_or_null = other._imp->slot_name_or_null;
+ }
+ return *this;
+}
+
+template class PrivateImplementationPattern<QPN_S>;
+template class WrappedForwardIterator<QPN_S_Sequence::ConstIteratorTag, const QPN_S>;
+
diff --git a/paludis/resolver/qpn_s.hh b/paludis/resolver/qpn_s.hh
new file mode 100644
index 0000000..2872bbe
--- /dev/null
+++ b/paludis/resolver/qpn_s.hh
@@ -0,0 +1,69 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_QPN_S_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_QPN_S_HH 1
+
+#include <paludis/resolver/qpn_s-fwd.hh>
+#include <paludis/util/named_value.hh>
+#include <paludis/util/attributes.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/name.hh>
+#include <paludis/filter-fwd.hh>
+#include <paludis/dep_spec-fwd.hh>
+#include <paludis/package_id-fwd.hh>
+#include <tr1/memory>
+
+namespace paludis
+{
+ namespace n
+ {
+ struct package;
+ struct slot_name_or_null;
+ }
+
+ namespace resolver
+ {
+ class PALUDIS_VISIBLE QPN_S :
+ private PrivateImplementationPattern<QPN_S>
+ {
+ public:
+ QPN_S(const QualifiedPackageName &, const std::tr1::shared_ptr<const SlotName> &);
+ QPN_S(const PackageDepSpec &, const std::tr1::shared_ptr<const SlotName> &);
+ explicit QPN_S(const std::tr1::shared_ptr<const PackageID> &);
+ QPN_S(const QPN_S &);
+ QPN_S & operator= (const QPN_S & other);
+ ~QPN_S();
+
+ const QualifiedPackageName package() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ const std::tr1::shared_ptr<const SlotName> slot_name_or_null() const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ Filter make_slot_filter() const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ bool operator< (const QPN_S & other) const PALUDIS_ATTRIBUTE((warn_unused_result));
+ bool operator== (const QPN_S & other) const PALUDIS_ATTRIBUTE((warn_unused_result));
+ };
+ }
+
+#ifdef PALUDIS_HAVE_EXTERN_TEMPLATE
+ extern template class PrivateImplementationPattern<resolver::QPN_S>;
+#endif
+}
+
+#endif
diff --git a/paludis/resolver/reason-fwd.hh b/paludis/resolver/reason-fwd.hh
new file mode 100644
index 0000000..245f2e3
--- /dev/null
+++ b/paludis/resolver/reason-fwd.hh
@@ -0,0 +1,40 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_REASON_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_REASON_FWD_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <iosfwd>
+
+namespace paludis
+{
+ namespace resolver
+ {
+ struct Reason;
+ struct DependencyReason;
+ struct TargetReason;
+ struct PresetReason;
+ struct SetReason;
+
+ std::ostream & operator<< (std::ostream & s, const Reason &) PALUDIS_VISIBLE;
+ }
+}
+
+#endif
diff --git a/paludis/resolver/reason.cc b/paludis/resolver/reason.cc
new file mode 100644
index 0000000..76b4e6b
--- /dev/null
+++ b/paludis/resolver/reason.cc
@@ -0,0 +1,141 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/resolver/reason.hh>
+#include <paludis/resolver/qpn_s.hh>
+#include <paludis/resolver/sanitised_dependencies.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+
+using namespace paludis;
+using namespace paludis::resolver;
+
+std::ostream &
+paludis::resolver::operator<< (std::ostream & s, const Reason & r)
+{
+ s << r.as_string();
+ return s;
+}
+
+Reason::~Reason()
+{
+}
+
+std::string
+TargetReason::as_string() const
+{
+ return "Target()";
+}
+
+namespace paludis
+{
+ template <>
+ struct Implementation<DependencyReason>
+ {
+ const std::tr1::shared_ptr<const PackageID> from_id;
+ const SanitisedDependency dep;
+
+ Implementation(const std::tr1::shared_ptr<const PackageID> & i, const SanitisedDependency & d) :
+ from_id(i),
+ dep(d)
+ {
+ }
+ };
+}
+
+DependencyReason::DependencyReason(const std::tr1::shared_ptr<const PackageID> & i,
+ const SanitisedDependency & d) :
+ PrivateImplementationPattern<DependencyReason>(new Implementation<DependencyReason>(i, d))
+{
+}
+
+DependencyReason::~DependencyReason()
+{
+}
+
+const std::tr1::shared_ptr<const PackageID>
+DependencyReason::from_id() const
+{
+ return _imp->from_id;
+}
+
+const SanitisedDependency &
+DependencyReason::sanitised_dependency() const
+{
+ return _imp->dep;
+}
+
+std::string
+DependencyReason::as_string() const
+{
+ return "Dependency(package: " + stringify(*_imp->from_id) + " dep: " + stringify(_imp->dep) + ")";
+}
+
+std::string
+PresetReason::as_string() const
+{
+ return "Preset()";
+}
+
+namespace paludis
+{
+ template <>
+ struct Implementation<SetReason>
+ {
+ const SetName set_name;
+ const std::tr1::shared_ptr<const Reason> reason_for_set;
+
+ Implementation(const SetName & s, const std::tr1::shared_ptr<const Reason> & r) :
+ set_name(s),
+ reason_for_set(r)
+ {
+ }
+ };
+}
+
+SetReason::SetReason(const SetName & s, const std::tr1::shared_ptr<const Reason> & r) :
+ PrivateImplementationPattern<SetReason>(new Implementation<SetReason>(s, r))
+{
+}
+
+SetReason::~SetReason()
+{
+}
+
+const SetName
+SetReason::set_name() const
+{
+ return _imp->set_name;
+}
+
+const std::tr1::shared_ptr<const Reason>
+SetReason::reason_for_set() const
+{
+ return _imp->reason_for_set;
+}
+
+std::string
+SetReason::as_string() const
+{
+ return "Set(set: " + stringify(_imp->set_name) + " because: " + stringify(*_imp->reason_for_set) + ")";
+}
+
+template class PrivateImplementationPattern<DependencyReason>;
+template class PrivateImplementationPattern<SetReason>;
+
diff --git a/paludis/resolver/reason.hh b/paludis/resolver/reason.hh
new file mode 100644
index 0000000..d6cb177
--- /dev/null
+++ b/paludis/resolver/reason.hh
@@ -0,0 +1,103 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_REASON_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_REASON_HH 1
+
+#include <paludis/resolver/reason-fwd.hh>
+#include <paludis/resolver/qpn_s-fwd.hh>
+#include <paludis/resolver/sanitised_dependencies-fwd.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/simple_visitor.hh>
+#include <paludis/util/type_list.hh>
+#include <paludis/name-fwd.hh>
+#include <paludis/package_id-fwd.hh>
+#include <tr1/memory>
+
+namespace paludis
+{
+ namespace resolver
+ {
+ class Reason :
+ public virtual DeclareAbstractAcceptMethods<Reason, MakeTypeList<
+ TargetReason, DependencyReason, PresetReason, SetReason>::Type>
+ {
+ public:
+ virtual ~Reason() = 0;
+ virtual std::string as_string() const = 0;
+ };
+
+ class TargetReason :
+ public Reason,
+ public ImplementAcceptMethods<Reason, TargetReason>
+ {
+ public:
+ virtual std::string as_string() const;
+ };
+
+ class DependencyReason :
+ private PrivateImplementationPattern<DependencyReason>,
+ public Reason,
+ public ImplementAcceptMethods<Reason, DependencyReason>
+ {
+ public:
+ DependencyReason(
+ const std::tr1::shared_ptr<const PackageID> & id,
+ const SanitisedDependency & s);
+
+ ~DependencyReason();
+
+ const std::tr1::shared_ptr<const PackageID> from_id() const;
+ const SanitisedDependency & sanitised_dependency() const;
+
+ virtual std::string as_string() const;
+ };
+
+ class PresetReason :
+ public Reason,
+ public ImplementAcceptMethods<Reason, PresetReason>
+ {
+ public:
+ virtual std::string as_string() const;
+ };
+
+ class SetReason :
+ public Reason,
+ private PrivateImplementationPattern<SetReason>,
+ public ImplementAcceptMethods<Reason, SetReason>
+ {
+ public:
+ SetReason(const SetName &, const std::tr1::shared_ptr<const Reason> &);
+ ~SetReason();
+
+ const SetName set_name() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ const std::tr1::shared_ptr<const Reason> reason_for_set() const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ virtual std::string as_string() const;
+ };
+ }
+
+#ifdef PALUDIS_HAVE_EXTERN_TEMPLATE
+ extern template class PrivateImplementationPattern<resolver::DependencyReason>;
+ extern template class PrivateImplementationPattern<resolver::SetReason>;
+#endif
+
+}
+
+#endif
diff --git a/paludis/resolver/resolution-fwd.hh b/paludis/resolver/resolution-fwd.hh
new file mode 100644
index 0000000..0345a2a
--- /dev/null
+++ b/paludis/resolver/resolution-fwd.hh
@@ -0,0 +1,36 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_RESOLUTION_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_RESOLUTION_FWD_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <iosfwd>
+
+namespace paludis
+{
+ namespace resolver
+ {
+ struct Resolution;
+
+ std::ostream & operator<< (std::ostream & s, const Resolution & r) PALUDIS_VISIBLE;
+ }
+}
+
+#endif
diff --git a/paludis/resolver/resolution.cc b/paludis/resolver/resolution.cc
new file mode 100644
index 0000000..ef389cd
--- /dev/null
+++ b/paludis/resolver/resolution.cc
@@ -0,0 +1,47 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/resolver/resolution.hh>
+#include <paludis/resolver/constraint.hh>
+#include <paludis/resolver/arrow.hh>
+#include <paludis/resolver/decision.hh>
+#include <paludis/util/sequence.hh>
+#include <paludis/util/join.hh>
+#include <paludis/util/wrapped_forward_iterator.hh>
+#include <paludis/util/indirect_iterator-impl.hh>
+#include <sstream>
+
+using namespace paludis;
+using namespace paludis::resolver;
+
+std::ostream &
+paludis::resolver::operator<< (std::ostream & s, const Resolution & r)
+{
+ std::stringstream ss;
+ ss << "Resolution("
+ << "constraints: " << join(indirect_iterator(r.constraints()->begin()), indirect_iterator(r.constraints()->end()), ", ")
+ << "; decision: " << (r.decision() ? stringify(*r.decision()) : "none")
+ << "; arrows: " << join(indirect_iterator(r.arrows()->begin()), indirect_iterator(r.arrows()->end()), ", ")
+ << "; already_ordered: " << stringify(r.already_ordered()) << ")"
+ << "; destinations: " << (r.destinations() ? stringify(*r.destinations()) : "unknown")
+ << ")";
+ s << ss.str();
+ return s;
+}
+
diff --git a/paludis/resolver/resolution.hh b/paludis/resolver/resolution.hh
new file mode 100644
index 0000000..b89304a
--- /dev/null
+++ b/paludis/resolver/resolution.hh
@@ -0,0 +1,58 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_RESOLUTION_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_RESOLUTION_HH 1
+
+#include <paludis/resolver/resolution-fwd.hh>
+#include <paludis/resolver/arrow-fwd.hh>
+#include <paludis/resolver/constraint-fwd.hh>
+#include <paludis/resolver/decision-fwd.hh>
+#include <paludis/resolver/destinations-fwd.hh>
+#include <paludis/resolver/sanitised_dependencies-fwd.hh>
+#include <paludis/util/named_value.hh>
+#include <tr1/memory>
+
+namespace paludis
+{
+ namespace n
+ {
+ struct already_ordered;
+ struct arrows;
+ struct constraints;
+ struct decision;
+ struct destinations;
+ struct sanitised_dependencies;
+ }
+
+ namespace resolver
+ {
+ struct Resolution
+ {
+ NamedValue<n::already_ordered, bool> already_ordered;
+ NamedValue<n::arrows, std::tr1::shared_ptr<ArrowSequence> > arrows;
+ NamedValue<n::constraints, std::tr1::shared_ptr<Constraints> > constraints;
+ NamedValue<n::decision, std::tr1::shared_ptr<Decision> > decision;
+ NamedValue<n::destinations, std::tr1::shared_ptr<Destinations> > destinations;
+ NamedValue<n::sanitised_dependencies, std::tr1::shared_ptr<SanitisedDependencies> > sanitised_dependencies;
+ };
+ }
+}
+
+#endif
diff --git a/paludis/resolver/resolver-fwd.hh b/paludis/resolver/resolver-fwd.hh
new file mode 100644
index 0000000..df41385
--- /dev/null
+++ b/paludis/resolver/resolver-fwd.hh
@@ -0,0 +1,31 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_RESOLVER_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_RESOLVER_FWD_HH 1
+
+namespace paludis
+{
+ namespace resolver
+ {
+ struct Resolver;
+ }
+}
+
+#endif
diff --git a/paludis/resolver/resolver.cc b/paludis/resolver/resolver.cc
new file mode 100644
index 0000000..e479a06
--- /dev/null
+++ b/paludis/resolver/resolver.cc
@@ -0,0 +1,1303 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/resolver/resolver.hh>
+#include <paludis/resolver/resolution.hh>
+#include <paludis/resolver/constraint.hh>
+#include <paludis/resolver/reason.hh>
+#include <paludis/resolver/qpn_s.hh>
+#include <paludis/resolver/sanitised_dependencies.hh>
+#include <paludis/resolver/arrow.hh>
+#include <paludis/resolver/decision.hh>
+#include <paludis/resolver/destinations.hh>
+#include <paludis/resolver/resolver_functions.hh>
+#include <paludis/resolver/suggest_restart.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/make_named_values.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/join.hh>
+#include <paludis/util/wrapped_forward_iterator-impl.hh>
+#include <paludis/util/simple_visitor_cast.hh>
+#include <paludis/environment.hh>
+#include <paludis/notifier_callback.hh>
+#include <paludis/dep_spec_flattener.hh>
+#include <paludis/spec_tree.hh>
+#include <paludis/slot_requirement.hh>
+#include <paludis/filter.hh>
+#include <paludis/filtered_generator.hh>
+#include <paludis/generator.hh>
+#include <paludis/selection.hh>
+#include <paludis/metadata_key.hh>
+#include <paludis/match_package.hh>
+#include <paludis/action.hh>
+#include <paludis/version_spec.hh>
+#include <paludis/version_requirements.hh>
+#include <paludis/package_database.hh>
+#include <paludis/repository.hh>
+#include <iostream>
+#include <iomanip>
+#include <list>
+#include <map>
+#include <set>
+
+using namespace paludis;
+using namespace paludis::resolver;
+
+typedef std::map<QPN_S, std::tr1::shared_ptr<Resolution> > ResolutionsByQPN_SMap;
+typedef std::list<std::tr1::shared_ptr<const Resolution> > OrderedResolutionsList;
+
+namespace paludis
+{
+ template <>
+ struct Implementation<Resolver>
+ {
+ const Environment * const env;
+ const ResolverFunctions fns;
+
+ ResolutionsByQPN_SMap resolutions_by_qpn_s;
+ OrderedResolutionsList ordered_resolutions;
+
+ Implementation(const Environment * const e, const ResolverFunctions & f) :
+ env(e),
+ fns(f)
+ {
+ }
+ };
+}
+
+Resolver::Resolver(const Environment * const e, const ResolverFunctions & f) :
+ PrivateImplementationPattern<Resolver>(new Implementation<Resolver>(e, f))
+{
+}
+
+Resolver::~Resolver()
+{
+}
+
+void
+Resolver::resolve()
+{
+ Context context("When finding an appropriate resolution:");
+
+ _resolve_dependencies();
+ _resolve_destinations();
+ _resolve_arrows();
+ _resolve_order();
+}
+
+void
+Resolver::_resolve_dependencies()
+{
+ Context context("When resolving dependencies recursively:");
+
+ bool done(false);
+ while (! done)
+ {
+ done = true;
+
+ for (ResolutionsByQPN_SMap::iterator i(_imp->resolutions_by_qpn_s.begin()), i_end(_imp->resolutions_by_qpn_s.end()) ;
+ i != i_end ; ++i)
+ {
+ if (i->second->decision())
+ continue;
+
+ _imp->env->trigger_notifier_callback(NotifierCallbackResolverStepEvent());
+
+ done = false;
+ _decide(i->first, i->second);
+
+ if (i->second->decision()->is_nothing())
+ continue;
+
+ _add_dependencies(i->first, i->second);
+ }
+ }
+}
+
+void
+Resolver::_resolve_destinations()
+{
+ Context context("When resolving destinations:");
+
+ for (ResolutionsByQPN_SMap::iterator i(_imp->resolutions_by_qpn_s.begin()), i_end(_imp->resolutions_by_qpn_s.end()) ;
+ i != i_end ; ++i)
+ {
+ if (i->second->destinations())
+ continue;
+
+ i->second->destinations() = _make_destinations_for(i->first, i->second);
+ }
+}
+
+const std::tr1::shared_ptr<Destinations>
+Resolver::_make_destinations_for(const QPN_S & qpn_s,
+ const std::tr1::shared_ptr<const Resolution> & resolution) const
+{
+ Context context("When finding destinations for '" + stringify(qpn_s) + "':");
+
+ if (resolution->decision()->is_installed() || resolution->decision()->is_nothing())
+ return make_shared_ptr(new Destinations(make_named_values<Destinations>(
+ value_for<n::slash>(make_null_shared_ptr())
+ )));
+
+ bool requires_slash(resolution->constraints()->to_destination_slash());
+
+ return make_shared_ptr(new Destinations(
+ make_named_values<Destinations>(
+ value_for<n::slash>(requires_slash ?
+ _make_slash_destination_for(qpn_s, resolution) :
+ make_null_shared_ptr())
+ )));
+}
+
+const std::tr1::shared_ptr<Destination>
+Resolver::_make_slash_destination_for(const QPN_S & qpn_s,
+ const std::tr1::shared_ptr<const Resolution> & resolution) const
+{
+ Context context("When finding / destination for '" + stringify(qpn_s) + "':");
+
+ if ((! resolution->decision()) || (! resolution->decision()->if_package_id()))
+ throw InternalError(PALUDIS_HERE, "not decided. shouldn't happen.");
+
+ std::tr1::shared_ptr<const Repository> repo;
+ for (PackageDatabase::RepositoryConstIterator r(_imp->env->package_database()->begin_repositories()),
+ r_end(_imp->env->package_database()->end_repositories()) ;
+ r != r_end ; ++r)
+ {
+ if ((*r)->destination_interface() && (*r)->destination_interface()->is_suitable_destination_for(
+ *resolution->decision()->if_package_id()))
+ {
+ if (repo)
+ throw InternalError(PALUDIS_HERE, "multiple valid destinations.");
+ else
+ repo = *r;
+ }
+ }
+
+ if (! repo)
+ throw InternalError(PALUDIS_HERE, "no valid destination for " + stringify(*resolution));
+
+ return make_shared_ptr(new Destination(make_named_values<Destination>(
+ value_for<n::replacing>(_find_replacing(resolution->decision()->if_package_id(), repo)),
+ value_for<n::repository>(repo->name())
+ )));
+}
+
+const std::tr1::shared_ptr<const PackageIDSequence>
+Resolver::_find_replacing(
+ const std::tr1::shared_ptr<const PackageID> & id,
+ const std::tr1::shared_ptr<const Repository> & repo) const
+{
+ Context context("When working out what is replaced by '" + stringify(*id) +
+ "' when it is installed to '" + stringify(repo->name()) + "':");
+
+ std::set<RepositoryName, RepositoryNameComparator> repos;
+
+ if (repo->installed_root_key())
+ {
+ for (PackageDatabase::RepositoryConstIterator r(_imp->env->package_database()->begin_repositories()),
+ r_end(_imp->env->package_database()->end_repositories()) ;
+ r != r_end ; ++r)
+ if ((*r)->installed_root_key() &&
+ (*r)->installed_root_key()->value() == repo->installed_root_key()->value())
+ repos.insert((*r)->name());
+ }
+ else
+ repos.insert(repo->name());
+
+ std::tr1::shared_ptr<PackageIDSequence> result(new PackageIDSequence);
+ for (std::set<RepositoryName, RepositoryNameComparator>::const_iterator r(repos.begin()),
+ r_end(repos.end()) ;
+ r != r_end ; ++r)
+ {
+ std::tr1::shared_ptr<const PackageIDSequence> ids((*_imp->env)[selection::AllVersionsUnsorted(
+ generator::Package(id->name()) & generator::InRepository(*r))]);
+ for (PackageIDSequence::ConstIterator i(ids->begin()), i_end(ids->end()) ;
+ i != i_end ; ++i)
+ {
+ if ((*i)->version() == id->version() || _same_slot(*i, id))
+ result->push_back(*i);
+ }
+ }
+
+ return result;
+}
+
+bool
+Resolver::_same_slot(const std::tr1::shared_ptr<const PackageID> & a,
+ const std::tr1::shared_ptr<const PackageID> & b) const
+{
+ if (a->slot_key())
+ return b->slot_key() && a->slot_key()->value() == b->slot_key()->value();
+ else
+ return ! b->slot_key();
+}
+
+void
+Resolver::add_target_with_reason(const PackageDepSpec & spec, const std::tr1::shared_ptr<const Reason> & reason)
+{
+ Context context("When adding target '" + stringify(spec) + "' with reason '" + stringify(*reason) + "':");
+ _imp->env->trigger_notifier_callback(NotifierCallbackResolverStepEvent());
+
+ const std::tr1::shared_ptr<const QPN_S_Sequence> qpn_s_s(_imp->fns.get_qpn_s_s_for_fn()(spec, reason));
+ if (qpn_s_s->empty())
+ throw InternalError(PALUDIS_HERE, "not implemented: no slot for " + stringify(spec));
+
+ for (QPN_S_Sequence::ConstIterator qpn_s(qpn_s_s->begin()), qpn_s_end(qpn_s_s->end()) ;
+ qpn_s != qpn_s_end ; ++qpn_s)
+ {
+ Context context_2("When adding constraints from target '" + stringify(spec) + "' to qpn:s '"
+ + stringify(*qpn_s) + "':");
+
+ const std::tr1::shared_ptr<Resolution> dep_resolution(_resolution_for_qpn_s(*qpn_s, true));
+ const std::tr1::shared_ptr<Constraint> constraint(_make_constraint_from_target(*qpn_s, spec, reason));
+
+ _apply_resolution_constraint(*qpn_s, dep_resolution, constraint);
+ }
+}
+
+void
+Resolver::add_target(const PackageDepSpec & spec)
+{
+ add_target_with_reason(spec, make_shared_ptr(new TargetReason));
+}
+
+void
+Resolver::add_target(const SetName & set_name)
+{
+ Context context("When adding set target '" + stringify(set_name) + "':");
+ _imp->env->trigger_notifier_callback(NotifierCallbackResolverStepEvent());
+
+ const std::tr1::shared_ptr<const SetSpecTree> set(_imp->env->set(set_name));
+ if (! set)
+ throw InternalError(PALUDIS_HERE, "todo");
+
+ DepSpecFlattener<SetSpecTree, PackageDepSpec> flattener(_imp->env);
+ set->root()->accept(flattener);
+
+ const std::tr1::shared_ptr<Reason> reason(new SetReason(set_name, make_shared_ptr(new TargetReason)));
+ for (DepSpecFlattener<SetSpecTree, PackageDepSpec>::ConstIterator s(flattener.begin()), s_end(flattener.end()) ;
+ s != s_end ; ++s)
+ add_target_with_reason(**s, reason);
+}
+
+QualifiedPackageName
+Resolver::_package_from_spec(const PackageDepSpec & spec) const
+{
+ if (! spec.package_ptr())
+ throw InternalError(PALUDIS_HERE, "not implemented");
+
+ return *spec.package_ptr();
+}
+
+const std::tr1::shared_ptr<Resolution>
+Resolver::_create_resolution_for_qpn_s(const QPN_S & qpn_s) const
+{
+ return make_shared_ptr(new Resolution(make_named_values<Resolution>(
+ value_for<n::already_ordered>(false),
+ value_for<n::arrows>(make_shared_ptr(new ArrowSequence)),
+ value_for<n::constraints>(_initial_constraints_for(qpn_s)),
+ value_for<n::decision>(make_null_shared_ptr()),
+ value_for<n::destinations>(make_null_shared_ptr()),
+ value_for<n::sanitised_dependencies>(make_null_shared_ptr())
+ )));
+}
+
+const std::tr1::shared_ptr<Resolution>
+Resolver::_resolution_for_qpn_s(const QPN_S & qpn_s, const bool create)
+{
+ ResolutionsByQPN_SMap::iterator i(_imp->resolutions_by_qpn_s.find(qpn_s));
+ if (_imp->resolutions_by_qpn_s.end() == i)
+ {
+ if (create)
+ i = _imp->resolutions_by_qpn_s.insert(std::make_pair(qpn_s, _create_resolution_for_qpn_s(qpn_s))).first;
+ else
+ throw InternalError(PALUDIS_HERE, "doesn't exist");
+ }
+
+ return i->second;
+}
+
+const std::tr1::shared_ptr<Resolution>
+Resolver::_resolution_for_qpn_s(const QPN_S & qpn_s) const
+{
+ ResolutionsByQPN_SMap::const_iterator i(_imp->resolutions_by_qpn_s.find(qpn_s));
+ if (_imp->resolutions_by_qpn_s.end() == i)
+ throw InternalError(PALUDIS_HERE, "doesn't exist");
+
+ return i->second;
+}
+
+const std::tr1::shared_ptr<Constraint>
+Resolver::_make_constraint_from_target(
+ const QPN_S & qpn_s,
+ const PackageDepSpec & spec,
+ const std::tr1::shared_ptr<const Reason> & reason) const
+{
+ return make_shared_ptr(new Constraint(make_named_values<Constraint>(
+ value_for<n::nothing_is_fine_too>(false),
+ value_for<n::reason>(reason),
+ value_for<n::spec>(spec),
+ value_for<n::to_destination_slash>(true),
+ value_for<n::use_installed>(_imp->fns.get_use_installed_fn()(qpn_s, spec, reason))
+ )));
+}
+
+const std::tr1::shared_ptr<Constraint>
+Resolver::_make_constraint_from_dependency(const QPN_S & qpn_s, const SanitisedDependency & dep,
+ const std::tr1::shared_ptr<const Reason> & reason) const
+{
+ if (dep.spec().if_package())
+ return make_shared_ptr(new Constraint(make_named_values<Constraint>(
+ value_for<n::nothing_is_fine_too>(false),
+ value_for<n::reason>(reason),
+ value_for<n::spec>(*dep.spec().if_package()),
+ value_for<n::to_destination_slash>(_dependency_to_destination_slash(qpn_s, dep)),
+ value_for<n::use_installed>(_imp->fns.get_use_installed_fn()(qpn_s, *dep.spec().if_package(), reason))
+ )));
+ else if (dep.spec().if_block())
+ {
+ /* nothing is fine too if there's nothing installed matching the block. */
+ const std::tr1::shared_ptr<const PackageIDSequence> ids((*_imp->env)[selection::SomeArbitraryVersion(
+ generator::Matches(*dep.spec().if_block()->blocked_spec(), MatchPackageOptions()) |
+ filter::SupportsAction<InstalledAction>())]);
+
+ return make_shared_ptr(new Constraint(make_named_values<Constraint>(
+ value_for<n::nothing_is_fine_too>(ids->empty()),
+ value_for<n::reason>(reason),
+ value_for<n::spec>(dep.spec()),
+ value_for<n::to_destination_slash>(true),
+ value_for<n::use_installed>(ui_if_possible)
+ )));
+ }
+ else
+ throw InternalError(PALUDIS_HERE, "huh?");
+}
+
+void
+Resolver::_apply_resolution_constraint(
+ const QPN_S & qpn_s,
+ const std::tr1::shared_ptr<Resolution> & resolution,
+ const std::tr1::shared_ptr<const Constraint> & constraint)
+{
+ if (resolution->decision())
+ _verify_new_constraint(qpn_s, resolution, constraint);
+
+ resolution->constraints()->add(constraint);
+}
+
+void
+Resolver::_verify_new_constraint(const QPN_S & qpn_s,
+ const std::tr1::shared_ptr<const Resolution> & resolution,
+ const std::tr1::shared_ptr<const Constraint> & constraint)
+{
+ bool ok;
+
+ if (resolution->decision()->if_package_id())
+ {
+ if (constraint->spec().if_package())
+ ok = match_package(*_imp->env, *constraint->spec().if_package(),
+ *resolution->decision()->if_package_id(), MatchPackageOptions());
+ else
+ ok = ! match_package(*_imp->env, *constraint->spec().if_block()->blocked_spec(),
+ *resolution->decision()->if_package_id(), MatchPackageOptions());
+ }
+ else
+ ok = constraint->nothing_is_fine_too();
+
+ if (ok && resolution->decision()->is_installed())
+ {
+ switch (constraint->use_installed())
+ {
+ case ui_if_possible:
+ break;
+
+ case ui_only_if_transient:
+ ok = resolution->decision()->is_transient();
+ break;
+
+ case ui_if_same:
+ ok = resolution->decision()->is_same();
+ break;
+
+ case ui_if_same_version:
+ ok = resolution->decision()->is_same_version();
+ break;
+
+ case ui_never:
+ case last_ui:
+ ok = false;
+ break;
+ }
+ }
+
+ if (! ok)
+ _made_wrong_decision(qpn_s, resolution, constraint);
+}
+
+void
+Resolver::_made_wrong_decision(const QPN_S & qpn_s,
+ const std::tr1::shared_ptr<const Resolution> & resolution,
+ const std::tr1::shared_ptr<const Constraint> & constraint)
+{
+ /* can we find a resolution that works for all our constraints? */
+ std::tr1::shared_ptr<Resolution> adapted_resolution(make_shared_ptr(new Resolution(*resolution)));
+ adapted_resolution->constraints()->add(constraint);
+
+ const std::tr1::shared_ptr<Decision> decision(_try_to_find_decision_for(qpn_s, adapted_resolution));
+ if (decision)
+ {
+ /* can we preload and restart? */
+ if (_initial_constraints_for(qpn_s)->empty())
+ {
+ /* we've not already locked this to something. yes! */
+ _suggest_restart_with(qpn_s, resolution, constraint, decision);
+ }
+ else
+ {
+ /* we can restart if we've selected the same or a newer version
+ * than before. but we don't support that yet. */
+ throw InternalError(PALUDIS_HERE, "should have selected " + stringify(*decision));
+ }
+ }
+ else
+ _unable_to_decide(qpn_s, adapted_resolution);
+}
+
+void
+Resolver::_suggest_restart_with(const QPN_S & qpn_s,
+ const std::tr1::shared_ptr<const Resolution> & resolution,
+ const std::tr1::shared_ptr<const Constraint> & constraint,
+ const std::tr1::shared_ptr<const Decision> & decision) const
+{
+ throw SuggestRestart(qpn_s, resolution->decision(), constraint, decision, _make_constraint_for_preloading(qpn_s, decision));
+}
+
+const std::tr1::shared_ptr<const Constraint>
+Resolver::_make_constraint_for_preloading(
+ const QPN_S & qpn_s,
+ const std::tr1::shared_ptr<const Decision> & d) const
+{
+ const std::tr1::shared_ptr<PresetReason> reason(new PresetReason);
+
+ if (! d->if_package_id())
+ throw InternalError(PALUDIS_HERE, "not decided. shouldn't happen.");
+
+ return make_shared_ptr(new Constraint(make_named_values<Constraint>(
+ value_for<n::nothing_is_fine_too>(false),
+ value_for<n::reason>(reason),
+ value_for<n::spec>(d->if_package_id()->uniquely_identifying_spec()),
+ value_for<n::to_destination_slash>(false),
+ value_for<n::use_installed>(_imp->fns.get_use_installed_fn()(
+ qpn_s, d->if_package_id()->uniquely_identifying_spec(), reason))
+ )));
+}
+
+void
+Resolver::_decide(const QPN_S & qpn_s, const std::tr1::shared_ptr<Resolution> & resolution)
+{
+ Context context("When deciding upon an origin ID to use for '" + stringify(qpn_s) + "' with '"
+ + stringify(*resolution) + "':");
+
+ std::tr1::shared_ptr<Decision> decision(_try_to_find_decision_for(qpn_s, resolution));
+ if (decision)
+ resolution->decision() = decision;
+ else
+ _unable_to_decide(qpn_s, resolution);
+}
+
+void
+Resolver::_add_dependencies(const QPN_S & our_qpn_s, const std::tr1::shared_ptr<Resolution> & our_resolution)
+{
+ Context context("When adding dependencies for '" + stringify(our_qpn_s) + "' with '"
+ + stringify(*our_resolution) + "':");
+
+ if (! our_resolution->decision()->if_package_id())
+ throw InternalError(PALUDIS_HERE, "not decided. shouldn't happen.");
+
+ const std::tr1::shared_ptr<SanitisedDependencies> deps(new SanitisedDependencies);
+ deps->populate(*this, our_resolution->decision()->if_package_id());
+ our_resolution->sanitised_dependencies() = deps;
+
+ for (SanitisedDependencies::ConstIterator s(deps->begin()), s_end(deps->end()) ;
+ s != s_end ; ++s)
+ {
+ Context context_2("When handling dependency '" + stringify(*s) + "':");
+
+ if (! _care_about_dependency_spec(our_qpn_s, our_resolution, *s))
+ continue;
+
+ const std::tr1::shared_ptr<DependencyReason> reason(new DependencyReason(
+ our_resolution->decision()->if_package_id(), *s));
+
+ std::tr1::shared_ptr<const QPN_S_Sequence> qpn_s_s;
+
+ if (s->spec().if_package())
+ qpn_s_s = _imp->fns.get_qpn_s_s_for_fn()(*s->spec().if_package(), reason);
+ else
+ qpn_s_s = _get_qpn_s_s_for_blocker(*s->spec().if_block());
+
+ if (qpn_s_s->empty() && s->spec().if_package())
+ {
+ if (our_resolution->decision()->is_installed())
+ Log::get_instance()->message("resolver.cannot_find_installed_dep", ll_warning, lc_context)
+ << "Installed package '" << *our_resolution->decision() << "' dependency '" << *s << " cannot be met";
+ else
+ throw InternalError(PALUDIS_HERE, "not implemented: no slot for " + stringify(s->spec()));
+ }
+
+ for (QPN_S_Sequence::ConstIterator qpn_s(qpn_s_s->begin()), qpn_s_end(qpn_s_s->end()) ;
+ qpn_s != qpn_s_end ; ++qpn_s)
+ {
+ const std::tr1::shared_ptr<Resolution> dep_resolution(_resolution_for_qpn_s(*qpn_s, true));
+ const std::tr1::shared_ptr<Constraint> constraint(_make_constraint_from_dependency(our_qpn_s, *s, reason));
+
+ _apply_resolution_constraint(*qpn_s, dep_resolution, constraint);
+ }
+ }
+}
+
+bool
+Resolver::_care_about_dependency_spec(const QPN_S & qpn_s,
+ const std::tr1::shared_ptr<const Resolution> & resolution, const SanitisedDependency & dep) const
+{
+ /* dirty dirty hack */
+ if (dep.spec().if_block())
+ if (dep.spec().if_block()->blocked_spec()->package_ptr()->category() == CategoryNamePart("virtual"))
+ {
+ Log::get_instance()->message("resolver.virtual_haxx", ll_warning, lc_context)
+ << "Ignoring " << dep << " from " << qpn_s << " for now";
+ return false;
+ }
+
+ return _imp->fns.care_about_dep_fn()(qpn_s, resolution, dep);
+}
+
+namespace
+{
+ struct GetDependencyReason
+ {
+ const DependencyReason * visit(const DependencyReason & r) const
+ {
+ return &r;
+ }
+
+ const DependencyReason * visit(const SetReason & r) const
+ {
+ return r.reason_for_set()->accept_returning<const DependencyReason *>(*this);
+ }
+
+ const DependencyReason * visit(const TargetReason &) const
+ {
+ return 0;
+ }
+
+ const DependencyReason * visit(const PresetReason &) const
+ {
+ return 0;
+ }
+ };
+
+ struct ArrowInfo
+ {
+ bool causes_pre_arrow;
+ bool ignorable;
+
+ ArrowInfo(const DependencyReason & reason) :
+ causes_pre_arrow(false),
+ ignorable(true)
+ {
+ const std::tr1::shared_ptr<const ActiveDependencyLabels> labels(
+ reason.sanitised_dependency().active_dependency_labels());
+
+ if (labels->type_labels()->empty())
+ throw InternalError(PALUDIS_HERE, "why did that happen?");
+
+ std::for_each(indirect_iterator(labels->type_labels()->begin()),
+ indirect_iterator(labels->type_labels()->end()), accept_visitor(*this));
+ }
+
+ void visit(const DependencyBuildLabel &)
+ {
+ causes_pre_arrow = true;
+ ignorable = false;
+ }
+
+ void visit(const DependencyRunLabel &)
+ {
+ causes_pre_arrow = true;
+ }
+
+ void visit(const DependencyPostLabel &)
+ {
+ }
+
+ void visit(const DependencyInstallLabel &)
+ {
+ causes_pre_arrow = true;
+ ignorable = false;
+ }
+
+ void visit(const DependencyCompileLabel &)
+ {
+ causes_pre_arrow = true;
+ ignorable = false;
+ }
+ };
+}
+
+void
+Resolver::_resolve_arrows()
+{
+ Context context("When creating arrows for order resolution:");
+
+ for (ResolutionsByQPN_SMap::iterator i(_imp->resolutions_by_qpn_s.begin()), i_end(_imp->resolutions_by_qpn_s.end()) ;
+ i != i_end ; ++i)
+ {
+ for (Constraints::ConstIterator c(i->second->constraints()->begin()),
+ c_end(i->second->constraints()->end()) ;
+ c != c_end ; ++c)
+ {
+ if ((*c)->spec().if_block())
+ {
+ /* todo: strong blocks do impose arrows */
+ continue;
+ }
+
+ GetDependencyReason gdr;
+ const DependencyReason * if_dependency_reason((*c)->reason()->accept_returning<const DependencyReason *>(gdr));
+ if (! if_dependency_reason)
+ continue;
+
+ const QPN_S from_qpns(if_dependency_reason->from_id());
+ const std::tr1::shared_ptr<Resolution> resolution(_resolution_for_qpn_s(from_qpns, false));
+
+ ArrowInfo a(*if_dependency_reason);
+ if (a.causes_pre_arrow)
+ {
+ int ignorable_pass(0);
+ if (_already_met(if_dependency_reason->sanitised_dependency()))
+ ignorable_pass = 1;
+ else if (a.ignorable)
+ ignorable_pass = 2;
+
+ resolution->arrows()->push_back(make_shared_ptr(new Arrow(make_named_values<Arrow>(
+ value_for<n::ignorable_pass>(ignorable_pass),
+ value_for<n::to_qpn_s>(i->first)
+ ))));
+ }
+ }
+ }
+}
+
+bool
+Resolver::_already_met(const SanitisedDependency & dep) const
+{
+ if (dep.spec().if_package())
+ {
+ std::tr1::shared_ptr<const PackageIDSequence> ids((*_imp->env)[selection::SomeArbitraryVersion(
+ generator::Matches(*dep.spec().if_package(), MatchPackageOptions()) |
+ filter::SupportsAction<InstalledAction>())]);
+ return ! ids->empty();
+ }
+ else if (dep.spec().if_block())
+ {
+ /* it's imposing an arrow, so it's a strong block */
+ return false;
+ }
+ else
+ throw InternalError(PALUDIS_HERE, "huh?");
+}
+
+void
+Resolver::_resolve_order()
+{
+ Context context("When finding an order for selected packages:");
+
+ bool done(false);
+
+ for (ResolutionsByQPN_SMap::iterator i(_imp->resolutions_by_qpn_s.begin()), i_end(_imp->resolutions_by_qpn_s.end()) ;
+ i != i_end ; ++i)
+ if (i->second->decision()->is_installed() || i->second->decision()->is_nothing())
+ i->second->already_ordered() = true;
+
+ while (! done)
+ {
+ bool any(false);
+ done = true;
+
+ int ignore_pass(0);
+ while (true)
+ {
+ for (ResolutionsByQPN_SMap::iterator i(_imp->resolutions_by_qpn_s.begin()), i_end(_imp->resolutions_by_qpn_s.end()) ;
+ i != i_end ; ++i)
+ {
+ if (i->second->already_ordered())
+ continue;
+
+ if (_can_order_now(i->first, i->second, ignore_pass))
+ {
+ if (0 != ignore_pass)
+ Log::get_instance()->message("resolver.cycle_breaking", ll_warning, lc_context)
+ << "Had to use cycle breaking with ignore pass " << ignore_pass
+ << " to order " << i->first << " because of cycle "
+ << _find_cycle(i->first, false);
+
+ _imp->env->trigger_notifier_callback(NotifierCallbackResolverStepEvent());
+ _do_order(i->first, i->second);
+ any = true;
+
+ if (0 != ignore_pass)
+ break;
+ }
+ else
+ done = false;
+ }
+
+ if ((! done) && (! any))
+ {
+ if (ignore_pass >= 2)
+ _unable_to_order_more();
+ else
+ ++ignore_pass;
+ }
+ else
+ break;
+ }
+ }
+}
+
+bool
+Resolver::_can_order_now(const QPN_S &, const std::tr1::shared_ptr<const Resolution> & resolution,
+ const int ignorable_pass) const
+{
+ for (ArrowSequence::ConstIterator a(resolution->arrows()->begin()), a_end(resolution->arrows()->end()) ;
+ a != a_end ; ++a)
+ {
+ if (0 != (*a)->ignorable_pass())
+ if ((*a)->ignorable_pass() <= ignorable_pass)
+ continue;
+
+ const std::tr1::shared_ptr<const Resolution> dep_resolution(_resolution_for_qpn_s((*a)->to_qpn_s()));
+ if (! dep_resolution->already_ordered())
+ return false;
+ }
+
+ return true;
+}
+
+void
+Resolver::_do_order(const QPN_S &, const std::tr1::shared_ptr<Resolution> & resolution)
+{
+ _imp->ordered_resolutions.push_back(resolution);
+ resolution->already_ordered() = true;
+}
+
+void
+Resolver::_unable_to_decide(
+ const QPN_S &,
+ const std::tr1::shared_ptr<const Resolution> &) const
+{
+ throw InternalError(PALUDIS_HERE, "not implemented");
+}
+
+void
+Resolver::_unable_to_order_more() const
+{
+ std::cout << "Unable to order any of the following:" << std::endl;
+
+ for (ResolutionsByQPN_SMap::const_iterator i(_imp->resolutions_by_qpn_s.begin()),
+ i_end(_imp->resolutions_by_qpn_s.end()) ;
+ i != i_end ; ++i)
+ {
+ if (i->second->already_ordered())
+ continue;
+
+ std::cout << " * " << *i->second->decision() << " because of cycle " << _find_cycle(i->first, true)
+ << std::endl;
+ }
+
+ throw InternalError(PALUDIS_HERE, "not implemented");
+}
+
+const std::tr1::shared_ptr<Constraints>
+Resolver::_initial_constraints_for(const QPN_S & qpn_s) const
+{
+ return _imp->fns.get_initial_constraints_for_fn()(qpn_s);
+}
+
+bool
+Resolver::_dependency_to_destination_slash(const QPN_S &, const SanitisedDependency &) const
+{
+ return true;
+}
+
+Resolver::ConstIterator
+Resolver::begin() const
+{
+ return ConstIterator(_imp->ordered_resolutions.begin());
+}
+
+Resolver::ConstIterator
+Resolver::end() const
+{
+ return ConstIterator(_imp->ordered_resolutions.end());
+}
+
+Resolver::ResolutionsByQPN_SConstIterator
+Resolver::begin_resolutions_by_qpn_s() const
+{
+ return ResolutionsByQPN_SConstIterator(_imp->resolutions_by_qpn_s.begin());
+}
+
+Resolver::ResolutionsByQPN_SConstIterator
+Resolver::end_resolutions_by_qpn_s() const
+{
+ return ResolutionsByQPN_SConstIterator(_imp->resolutions_by_qpn_s.end());
+}
+
+int
+Resolver::find_any_score(const QPN_S & our_qpn_s, const SanitisedDependency & dep) const
+{
+ Context context("When working out whether we'd like '" + stringify(dep) + "' because of '"
+ + stringify(our_qpn_s) + "':");
+
+ if (dep.spec().if_block())
+ throw InternalError(PALUDIS_HERE, "not yet");
+
+ const PackageDepSpec & spec(*dep.spec().if_package());
+
+ int operator_bias(0);
+ if (spec.version_requirements_ptr() && ! spec.version_requirements_ptr()->empty())
+ {
+ int score(-1);
+ for (VersionRequirements::ConstIterator v(spec.version_requirements_ptr()->begin()),
+ v_end(spec.version_requirements_ptr()->end()) ;
+ v != v_end ; ++v)
+ {
+ int local_score(0);
+
+ switch (v->version_operator().value())
+ {
+ case vo_greater:
+ case vo_greater_equal:
+ local_score = 9;
+ break;
+
+ case vo_equal:
+ case vo_tilde:
+ case vo_nice_equal_star:
+ case vo_stupid_equal_star:
+ case vo_tilde_greater:
+ local_score = 2;
+ break;
+
+ case vo_less_equal:
+ case vo_less:
+ local_score = 1;
+ break;
+
+ case last_vo:
+ local_score = 1;
+ break;
+ }
+
+ if (score == -1)
+ score = local_score;
+ else
+ switch (spec.version_requirements_mode())
+ {
+ case vr_and:
+ score = std::min(score, local_score);
+ break;
+
+ case vr_or:
+ score = std::max(score, local_score);
+ break;
+
+ case last_vr:
+ break;
+ }
+ }
+ operator_bias = score;
+ }
+ else
+ {
+ /* don't bias no operator over a >= operator, so || ( >=foo-2 bar )
+ * still likes foo. */
+ operator_bias = 9;
+ }
+
+ /* best: already installed */
+ {
+ const std::tr1::shared_ptr<const PackageIDSequence> installed_ids((*_imp->env)[selection::BestVersionOnly(
+ generator::Matches(spec, MatchPackageOptions() + mpo_ignore_additional_requirements) |
+ filter::SupportsAction<InstalledAction>())]);
+ if (! installed_ids->empty())
+ return 40 + operator_bias;
+ }
+
+ const std::tr1::shared_ptr<DependencyReason> reason(new DependencyReason(
+ _resolution_for_qpn_s(our_qpn_s)->decision()->if_package_id(), dep));
+ const std::tr1::shared_ptr<const QPN_S_Sequence> qpn_s_s(_imp->fns.get_qpn_s_s_for_fn()(spec, reason));
+
+ /* next: will already be installing */
+ {
+ for (QPN_S_Sequence::ConstIterator qpn_s(qpn_s_s->begin()), qpn_s_end(qpn_s_s->end()) ;
+ qpn_s != qpn_s_end ; ++qpn_s)
+ {
+ ResolutionsByQPN_SMap::const_iterator i(_imp->resolutions_by_qpn_s.find(*qpn_s));
+ if (i != _imp->resolutions_by_qpn_s.end())
+ return 30 + operator_bias;
+ }
+ }
+
+ /* next: could install */
+ {
+ for (QPN_S_Sequence::ConstIterator qpn_s(qpn_s_s->begin()), qpn_s_end(qpn_s_s->end()) ;
+ qpn_s != qpn_s_end ; ++qpn_s)
+ {
+ const std::tr1::shared_ptr<Resolution> resolution(_create_resolution_for_qpn_s(*qpn_s));
+ const std::tr1::shared_ptr<Constraint> constraint(_make_constraint_from_dependency(our_qpn_s, dep, reason));
+ resolution->constraints()->add(constraint);
+ const std::tr1::shared_ptr<Decision> decision(_try_to_find_decision_for(*qpn_s, resolution));
+ if (decision)
+ return 20 + operator_bias;
+ }
+ }
+
+ /* next: exists */
+ {
+ const std::tr1::shared_ptr<const PackageIDSequence> ids((*_imp->env)[selection::BestVersionOnly(
+ generator::Matches(spec, MatchPackageOptions() + mpo_ignore_additional_requirements)
+ )]);
+ if (! ids->empty())
+ return 10 + operator_bias;
+ }
+
+ /* yay, people are depping upon packages that don't exist again. I SMELL A LESSPIPE. */
+ return 0;
+}
+
+const std::string
+Resolver::_find_cycle(const QPN_S & start_qpn_s, const int ignorable_pass) const
+{
+ std::stringstream result;
+
+ std::set<QPN_S> seen;
+ QPN_S current(start_qpn_s);
+
+ bool first(true);
+ while (true)
+ {
+ if (! first)
+ result << " -> ";
+ first = false;
+
+ result << current;
+
+ if (! seen.insert(current).second)
+ break;
+
+ bool ok(false);
+ const std::tr1::shared_ptr<const Resolution> resolution(_resolution_for_qpn_s(current));
+ for (ArrowSequence::ConstIterator a(resolution->arrows()->begin()), a_end(resolution->arrows()->end()) ;
+ a != a_end ; ++a)
+ {
+ if (_can_order_now(current, resolution, ignorable_pass))
+ continue;
+
+ const std::tr1::shared_ptr<const Resolution> to_resolution(_resolution_for_qpn_s((*a)->to_qpn_s()));
+ if (to_resolution->already_ordered())
+ continue;
+
+ ok = true;
+ current = (*a)->to_qpn_s();
+ break;
+ }
+
+ if (! ok)
+ throw InternalError(PALUDIS_HERE, "why did that happen? start is " + stringify(start_qpn_s)
+ + ", current is " + stringify(current) + ", seen is { "
+ + join(seen.begin(), seen.end(), ", ") + " }, result is "
+ + result.str() + ", resolution->arrows is { "
+ + join(indirect_iterator(resolution->arrows()->begin()),
+ indirect_iterator(resolution->arrows()->end()), ", ") + "}"
+ );
+ }
+
+ return result.str();
+}
+
+namespace
+{
+ struct SlotNameFinder
+ {
+ std::tr1::shared_ptr<SlotName> visit(const SlotExactRequirement & s)
+ {
+ return make_shared_ptr(new SlotName(s.slot()));
+ }
+
+ std::tr1::shared_ptr<SlotName> visit(const SlotAnyUnlockedRequirement &)
+ {
+ return make_null_shared_ptr();
+ }
+
+ std::tr1::shared_ptr<SlotName> visit(const SlotAnyLockedRequirement &)
+ {
+ return make_null_shared_ptr();
+ }
+ };
+}
+
+const std::tr1::shared_ptr<const QPN_S_Sequence>
+Resolver::_get_qpn_s_s_for_blocker(const BlockDepSpec & spec) const
+{
+ Context context("When finding slots for '" + stringify(spec) + "':");
+
+ std::tr1::shared_ptr<SlotName> exact_slot;
+ if (spec.blocked_spec()->slot_requirement_ptr())
+ {
+ SlotNameFinder f;
+ exact_slot = spec.blocked_spec()->slot_requirement_ptr()->accept_returning<std::tr1::shared_ptr<SlotName> >(f);
+ }
+
+ std::tr1::shared_ptr<QPN_S_Sequence> result(new QPN_S_Sequence);
+ if (exact_slot)
+ result->push_back(QPN_S(*spec.blocked_spec(), exact_slot));
+ else
+ {
+ const std::tr1::shared_ptr<const PackageIDSequence> ids((*_imp->env)[selection::BestVersionInEachSlot(
+ generator::Package(*spec.blocked_spec()->package_ptr())
+ )]);
+ for (PackageIDSequence::ConstIterator i(ids->begin()), i_end(ids->end()) ;
+ i != i_end ; ++i)
+ result->push_back(QPN_S(*i));
+ }
+
+ return result;
+}
+
+const std::tr1::shared_ptr<Decision>
+Resolver::_try_to_find_decision_for(
+ const QPN_S & qpn_s,
+ const std::tr1::shared_ptr<const Resolution> & resolution) const
+{
+ const std::tr1::shared_ptr<const PackageID> installed_id(_find_installed_id_for(qpn_s, resolution));
+ const std::tr1::shared_ptr<const PackageID> installable_id(_find_installable_id_for(qpn_s, resolution));
+
+ if (resolution->constraints()->nothing_is_fine_too() && ! installed_id)
+ {
+ /* nothing installed, but nothing's ok */
+ return make_shared_ptr(new Decision(make_named_values<Decision>(
+ value_for<n::if_package_id>(make_null_shared_ptr()),
+ value_for<n::is_installed>(false),
+ value_for<n::is_nothing>(true),
+ value_for<n::is_same>(false),
+ value_for<n::is_same_version>(false),
+ value_for<n::is_transient>(false)
+ )));
+ }
+ else if (installable_id && ! installed_id)
+ {
+ /* there's nothing suitable installed. */
+ return make_shared_ptr(new Decision(make_named_values<Decision>(
+ value_for<n::if_package_id>(installable_id),
+ value_for<n::is_installed>(false),
+ value_for<n::is_nothing>(false),
+ value_for<n::is_same>(false),
+ value_for<n::is_same_version>(false),
+ value_for<n::is_transient>(false)
+ )));
+ }
+ else if (installed_id && ! installable_id)
+ {
+ /* there's nothing installable. this may or may not be ok. */
+ bool is_transient(installed_id->transient_key() && installed_id->transient_key()->value());
+
+ switch (resolution->constraints()->strictest_use_installed())
+ {
+ case ui_if_possible:
+ break;
+
+ case ui_only_if_transient:
+ case ui_if_same:
+ case ui_if_same_version:
+ if (! is_transient)
+ return make_null_shared_ptr();
+ break;
+
+ case ui_never:
+ return make_null_shared_ptr();
+
+ case last_ui:
+ break;
+ }
+
+ return make_shared_ptr(new Decision(make_named_values<Decision>(
+ value_for<n::if_package_id>(installed_id),
+ value_for<n::is_installed>(true),
+ value_for<n::is_nothing>(false),
+ value_for<n::is_same>(true),
+ value_for<n::is_same_version>(true),
+ value_for<n::is_transient>(is_transient)
+ )));
+ }
+ else if ((! installed_id) && (! installable_id))
+ {
+ return make_null_shared_ptr();
+ }
+ else if (installed_id && installable_id)
+ {
+ bool is_same, is_same_version;
+ is_same_version = (installed_id->version() == installable_id->version());
+ is_same = is_same_version; /* todo */
+
+ bool is_transient(installed_id->transient_key() && installed_id->transient_key()->value());
+
+ /* we've got installed and installable. do we have any reason not to pick the installed id? */
+ switch (resolution->constraints()->strictest_use_installed())
+ {
+ case ui_only_if_transient:
+ case ui_never:
+ return make_shared_ptr(new Decision(make_named_values<Decision>(
+ value_for<n::if_package_id>(installable_id),
+ value_for<n::is_installed>(false),
+ value_for<n::is_nothing>(false),
+ value_for<n::is_same>(is_same),
+ value_for<n::is_same_version>(is_same_version),
+ value_for<n::is_transient>(false)
+ )));
+
+ case ui_if_same:
+ if (is_same)
+ return make_shared_ptr(new Decision(make_named_values<Decision>(
+ value_for<n::if_package_id>(installed_id),
+ value_for<n::is_installed>(true),
+ value_for<n::is_nothing>(false),
+ value_for<n::is_same>(is_same),
+ value_for<n::is_same_version>(is_same_version),
+ value_for<n::is_transient>(false)
+ )));
+ else
+ return make_shared_ptr(new Decision(make_named_values<Decision>(
+ value_for<n::if_package_id>(installable_id),
+ value_for<n::is_installed>(false),
+ value_for<n::is_nothing>(false),
+ value_for<n::is_same>(is_same),
+ value_for<n::is_same_version>(is_same_version),
+ value_for<n::is_transient>(is_transient)
+ )));
+
+ case ui_if_same_version:
+ if (is_same_version)
+ return make_shared_ptr(new Decision(make_named_values<Decision>(
+ value_for<n::if_package_id>(installed_id),
+ value_for<n::is_installed>(true),
+ value_for<n::is_nothing>(false),
+ value_for<n::is_same>(is_same),
+ value_for<n::is_same_version>(is_same_version),
+ value_for<n::is_transient>(false)
+ )));
+ else
+ return make_shared_ptr(new Decision(make_named_values<Decision>(
+ value_for<n::if_package_id>(installable_id),
+ value_for<n::is_installed>(false),
+ value_for<n::is_nothing>(false),
+ value_for<n::is_same>(is_same),
+ value_for<n::is_same_version>(is_same_version),
+ value_for<n::is_transient>(is_transient)
+ )));
+
+ case ui_if_possible:
+ return make_shared_ptr(new Decision(make_named_values<Decision>(
+ value_for<n::if_package_id>(installed_id),
+ value_for<n::is_installed>(true),
+ value_for<n::is_nothing>(false),
+ value_for<n::is_same>(is_same),
+ value_for<n::is_same_version>(is_same_version),
+ value_for<n::is_transient>(false)
+ )));
+
+ case last_ui:
+ break;
+ }
+ }
+
+ throw InternalError(PALUDIS_HERE, "why did that happen?");
+}
+
+const std::tr1::shared_ptr<const PackageID>
+Resolver::_find_installed_id_for(const QPN_S & qpn_s, const std::tr1::shared_ptr<const Resolution> & resolution) const
+{
+ const std::tr1::shared_ptr<const PackageIDSequence> ids((*_imp->env)[selection::AllVersionsSorted(
+ generator::Package(qpn_s.package()) |
+ qpn_s.make_slot_filter() |
+ filter::SupportsAction<InstalledAction>()
+ )]);
+
+ return _find_id_for_from(qpn_s, resolution, ids);
+}
+
+const std::tr1::shared_ptr<const PackageID>
+Resolver::_find_installable_id_for(const QPN_S & qpn_s, const std::tr1::shared_ptr<const Resolution> & resolution) const
+{
+ const std::tr1::shared_ptr<const PackageIDSequence> ids((*_imp->env)[selection::AllVersionsSorted(
+ generator::Package(qpn_s.package()) |
+ qpn_s.make_slot_filter() |
+ filter::SupportsAction<InstallAction>() |
+ filter::NotMasked()
+ )]);
+
+ return _find_id_for_from(qpn_s, resolution, ids);
+}
+
+const std::tr1::shared_ptr<const PackageID>
+Resolver::_find_id_for_from(
+ const QPN_S &, const std::tr1::shared_ptr<const Resolution> & resolution,
+ const std::tr1::shared_ptr<const PackageIDSequence> & ids) const
+{
+ for (PackageIDSequence::ReverseConstIterator i(ids->rbegin()), i_end(ids->rend()) ;
+ i != i_end ; ++i)
+ {
+ bool ok(true);
+ for (Constraints::ConstIterator c(resolution->constraints()->begin()),
+ c_end(resolution->constraints()->end()) ;
+ c != c_end ; ++c)
+ {
+ if ((*c)->spec().if_package())
+ ok = ok && match_package(*_imp->env, *(*c)->spec().if_package(), **i, MatchPackageOptions());
+ else
+ ok = ok && ! match_package(*_imp->env, *(*c)->spec().if_block()->blocked_spec(), **i, MatchPackageOptions());
+
+ if (! ok)
+ break;
+ }
+
+ if (ok)
+ return *i;
+ }
+
+ return make_null_shared_ptr();
+}
+
+template class WrappedForwardIterator<Resolver::ConstIteratorTag, const std::tr1::shared_ptr<const Resolution> >;
+template class WrappedForwardIterator<Resolver::ResolutionsByQPN_SConstIteratorTag,
+ const std::pair<const QPN_S, std::tr1::shared_ptr<Resolution> > >;
+
diff --git a/paludis/resolver/resolver.hh b/paludis/resolver/resolver.hh
new file mode 100644
index 0000000..028b3e6
--- /dev/null
+++ b/paludis/resolver/resolver.hh
@@ -0,0 +1,173 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_RESOLVER_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_RESOLVER_HH 1
+
+#include <paludis/resolver/resolver-fwd.hh>
+#include <paludis/resolver/resolution-fwd.hh>
+#include <paludis/resolver/qpn_s-fwd.hh>
+#include <paludis/resolver/constraint-fwd.hh>
+#include <paludis/resolver/sanitised_dependencies-fwd.hh>
+#include <paludis/resolver/decision-fwd.hh>
+#include <paludis/resolver/reason-fwd.hh>
+#include <paludis/resolver/use_installed-fwd.hh>
+#include <paludis/resolver/destinations-fwd.hh>
+#include <paludis/resolver/resolver_functions-fwd.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/wrapped_forward_iterator-fwd.hh>
+#include <paludis/package_id-fwd.hh>
+#include <paludis/dep_spec-fwd.hh>
+#include <paludis/name.hh>
+#include <paludis/environment-fwd.hh>
+#include <paludis/repository-fwd.hh>
+#include <tr1/memory>
+
+namespace paludis
+{
+ namespace resolver
+ {
+ class PALUDIS_VISIBLE Resolver :
+ private PrivateImplementationPattern<Resolver>
+ {
+ private:
+ QualifiedPackageName _package_from_spec(const PackageDepSpec &) const;
+
+ const std::tr1::shared_ptr<Resolution> _create_resolution_for_qpn_s(const QPN_S &) const;
+ const std::tr1::shared_ptr<Resolution> _resolution_for_qpn_s(const QPN_S &, const bool create);
+ const std::tr1::shared_ptr<Resolution> _resolution_for_qpn_s(const QPN_S &) const;
+
+ const std::tr1::shared_ptr<const QPN_S_Sequence> _get_qpn_s_s_for_blocker(const BlockDepSpec &) const;
+
+ const std::tr1::shared_ptr<Constraint> _make_constraint_from_target(
+ const QPN_S &,
+ const PackageDepSpec &,
+ const std::tr1::shared_ptr<const Reason> &) const;
+
+ const std::tr1::shared_ptr<Constraint> _make_constraint_from_dependency(
+ const QPN_S &, const SanitisedDependency &,
+ const std::tr1::shared_ptr<const Reason> &) const;
+
+ void _apply_resolution_constraint(const QPN_S &,
+ const std::tr1::shared_ptr<Resolution> &,
+ const std::tr1::shared_ptr<const Constraint> &);
+
+ void _verify_new_constraint(const QPN_S &,
+ const std::tr1::shared_ptr<const Resolution> &,
+ const std::tr1::shared_ptr<const Constraint> &);
+
+ void _made_wrong_decision(const QPN_S & qpn_s,
+ const std::tr1::shared_ptr<const Resolution> & resolution,
+ const std::tr1::shared_ptr<const Constraint> & constraint) PALUDIS_ATTRIBUTE((noreturn));
+
+ void _suggest_restart_with(const QPN_S & qpn_s,
+ const std::tr1::shared_ptr<const Resolution> & resolution,
+ const std::tr1::shared_ptr<const Constraint> & constraint,
+ const std::tr1::shared_ptr<const Decision> & decision) const PALUDIS_ATTRIBUTE((noreturn));
+
+ const std::tr1::shared_ptr<const Constraint> _make_constraint_for_preloading(
+ const QPN_S & qpn_s,
+ const std::tr1::shared_ptr<const Decision> & d) const;
+
+ const std::tr1::shared_ptr<Destinations> _make_destinations_for(const QPN_S &,
+ const std::tr1::shared_ptr<const Resolution> &) const;
+
+ const std::tr1::shared_ptr<Destination> _make_slash_destination_for(const QPN_S &,
+ const std::tr1::shared_ptr<const Resolution> &) const;
+
+ const std::tr1::shared_ptr<const PackageIDSequence> _find_replacing(
+ const std::tr1::shared_ptr<const PackageID> &,
+ const std::tr1::shared_ptr<const Repository> &) const;
+
+ void _resolve_dependencies();
+ void _resolve_destinations();
+ void _resolve_arrows();
+ void _resolve_order();
+
+ void _decide(const QPN_S &, const std::tr1::shared_ptr<Resolution> & resolution);
+
+ const std::tr1::shared_ptr<Decision> _try_to_find_decision_for(
+ const QPN_S &, const std::tr1::shared_ptr<const Resolution> & resolution) const;
+
+ void _add_dependencies(const QPN_S & our_qpn_s, const std::tr1::shared_ptr<Resolution> & our_resolution);
+
+ bool _care_about_dependency_spec(const QPN_S &, const std::tr1::shared_ptr<const Resolution> &,
+ const SanitisedDependency &) const;
+
+ bool _causes_pre_arrow(const DependencyReason &) const;
+
+ bool _can_order_now(const QPN_S &, const std::tr1::shared_ptr<const Resolution> & resolution,
+ const int ignorable_pass) const;
+
+ void _do_order(const QPN_S &, const std::tr1::shared_ptr<Resolution> & resolution);
+
+ void _unable_to_decide(const QPN_S &,
+ const std::tr1::shared_ptr<const Resolution> &) const PALUDIS_ATTRIBUTE((noreturn));
+
+ void _unable_to_order_more() const PALUDIS_ATTRIBUTE((noreturn));
+
+ const std::tr1::shared_ptr<Constraints> _initial_constraints_for(const QPN_S &) const;
+
+ bool _dependency_to_destination_slash(
+ const QPN_S &, const SanitisedDependency &) const;
+
+ bool _same_slot(const std::tr1::shared_ptr<const PackageID> & a,
+ const std::tr1::shared_ptr<const PackageID> & b) const;
+
+ bool _already_met(const SanitisedDependency & dep) const;
+
+ const std::string _find_cycle(const QPN_S &, const int ignorable_pass) const;
+
+ const std::tr1::shared_ptr<const PackageID> _find_installed_id_for(const QPN_S &, const std::tr1::shared_ptr<const Resolution> &) const;
+ const std::tr1::shared_ptr<const PackageID> _find_installable_id_for(const QPN_S &, const std::tr1::shared_ptr<const Resolution> &) const;
+ const std::tr1::shared_ptr<const PackageID> _find_id_for_from(
+ const QPN_S &, const std::tr1::shared_ptr<const Resolution> &,
+ const std::tr1::shared_ptr<const PackageIDSequence> &) const;
+
+ public:
+ Resolver(
+ const Environment * const,
+ const ResolverFunctions &);
+ ~Resolver();
+
+ void add_target_with_reason(const PackageDepSpec &, const std::tr1::shared_ptr<const Reason> &);
+ void add_target(const PackageDepSpec &);
+ void add_target(const SetName &);
+
+ void resolve();
+
+ struct ConstIteratorTag;
+ typedef WrappedForwardIterator<ConstIteratorTag,
+ const std::tr1::shared_ptr<const Resolution> > ConstIterator;
+ ConstIterator begin() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ ConstIterator end() const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ struct ResolutionsByQPN_SConstIteratorTag;
+ typedef WrappedForwardIterator<ResolutionsByQPN_SConstIteratorTag,
+ const std::pair<const QPN_S, std::tr1::shared_ptr<Resolution> > > ResolutionsByQPN_SConstIterator;
+ ResolutionsByQPN_SConstIterator begin_resolutions_by_qpn_s() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ ResolutionsByQPN_SConstIterator end_resolutions_by_qpn_s() const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ int find_any_score(const QPN_S &, const SanitisedDependency &) const;
+
+ };
+ }
+}
+
+#endif
diff --git a/paludis/resolver/resolver_functions-fwd.hh b/paludis/resolver/resolver_functions-fwd.hh
new file mode 100644
index 0000000..a33bb62
--- /dev/null
+++ b/paludis/resolver/resolver_functions-fwd.hh
@@ -0,0 +1,31 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_RESOLVER_FUNCTIONS_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_RESOLVER_FUNCTIONS_FWD_HH 1
+
+namespace paludis
+{
+ namespace resolver
+ {
+ struct ResolverFunctions;
+ }
+}
+
+#endif
diff --git a/paludis/resolver/resolver_functions.hh b/paludis/resolver/resolver_functions.hh
new file mode 100644
index 0000000..177349f
--- /dev/null
+++ b/paludis/resolver/resolver_functions.hh
@@ -0,0 +1,74 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_RESOLVER_FUNCTIONS_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_RESOLVER_FUNCTIONS_HH 1
+
+#include <paludis/resolver/resolver_functions-fwd.hh>
+#include <paludis/resolver/use_installed-fwd.hh>
+#include <paludis/resolver/resolution-fwd.hh>
+#include <paludis/resolver/qpn_s-fwd.hh>
+#include <paludis/resolver/reason-fwd.hh>
+#include <paludis/util/named_value.hh>
+#include <tr1/functional>
+
+namespace paludis
+{
+ namespace n
+ {
+ struct care_about_dep_fn;
+ struct get_initial_constraints_for_fn;
+ struct get_qpn_s_s_for_fn;
+ struct get_use_installed_fn;
+ }
+
+ namespace resolver
+ {
+ typedef std::tr1::function<bool (
+ const QPN_S &,
+ const std::tr1::shared_ptr<const Resolution> &,
+ const SanitisedDependency &
+ )> CareAboutDepFunction;
+
+ typedef std::tr1::function<std::tr1::shared_ptr<Constraints> (
+ const QPN_S &
+ )> GetInitialConstraintsFunction;
+
+ typedef std::tr1::function<std::tr1::shared_ptr<QPN_S_Sequence> (
+ const PackageDepSpec &,
+ const std::tr1::shared_ptr<const Reason> &
+ )> GetQPNSSForFunction;
+
+ typedef std::tr1::function<UseInstalled (
+ const QPN_S &,
+ const PackageDepSpec &,
+ const std::tr1::shared_ptr<const Reason> &
+ )> GetUseInstalledFunction;
+
+ struct ResolverFunctions
+ {
+ NamedValue<n::care_about_dep_fn, CareAboutDepFunction> care_about_dep_fn;
+ NamedValue<n::get_initial_constraints_for_fn, GetInitialConstraintsFunction> get_initial_constraints_for_fn;
+ NamedValue<n::get_qpn_s_s_for_fn, GetQPNSSForFunction> get_qpn_s_s_for_fn;
+ NamedValue<n::get_use_installed_fn, GetUseInstalledFunction> get_use_installed_fn;
+ };
+ }
+}
+
+#endif
diff --git a/paludis/resolver/sanitised_dependencies-fwd.hh b/paludis/resolver/sanitised_dependencies-fwd.hh
new file mode 100644
index 0000000..9ef1bb5
--- /dev/null
+++ b/paludis/resolver/sanitised_dependencies-fwd.hh
@@ -0,0 +1,40 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_SANITISED_DEPENDENCIES_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_SANITISED_DEPENDENCIES_FWD_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <iosfwd>
+
+namespace paludis
+{
+ namespace resolver
+ {
+ struct SanitisedDependencies;
+ struct SanitisedDependency;
+
+ struct PackageOrBlockDepSpec;
+
+ std::ostream & operator<< (std::ostream & s, const SanitisedDependency & d) PALUDIS_VISIBLE;
+ std::ostream & operator<< (std::ostream & s, const PackageOrBlockDepSpec & d) PALUDIS_VISIBLE;
+ }
+}
+
+#endif
diff --git a/paludis/resolver/sanitised_dependencies.cc b/paludis/resolver/sanitised_dependencies.cc
new file mode 100644
index 0000000..0ccad88
--- /dev/null
+++ b/paludis/resolver/sanitised_dependencies.cc
@@ -0,0 +1,421 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/resolver/sanitised_dependencies.hh>
+#include <paludis/resolver/resolver.hh>
+#include <paludis/resolver/qpn_s.hh>
+#include <paludis/util/make_named_values.hh>
+#include <paludis/util/save.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/options.hh>
+#include <paludis/util/join.hh>
+#include <paludis/util/wrapped_forward_iterator-impl.hh>
+#include <paludis/spec_tree.hh>
+#include <paludis/slot_requirement.hh>
+#include <paludis/metadata_key.hh>
+#include <paludis/package_id.hh>
+#include <set>
+#include <list>
+
+using namespace paludis;
+using namespace paludis::resolver;
+
+namespace
+{
+ template <typename T_>
+ void list_push_back(std::list<T_> * const l, const T_ & t)
+ {
+ l->push_back(t);
+ }
+
+ struct AnyDepSpecChildHandler
+ {
+ const Resolver & resolver;
+ const QPN_S our_qpn_s;
+ const std::tr1::function<SanitisedDependency (const PackageOrBlockDepSpec &)> parent_make_sanitised;
+
+ bool super_complicated, nested;
+
+ std::list<std::list<PackageOrBlockDepSpec> > child_groups;
+ std::list<PackageOrBlockDepSpec> * active_sublist;
+
+ bool seen_any;
+
+ AnyDepSpecChildHandler(const Resolver & r, const QPN_S & q,
+ const std::tr1::function<SanitisedDependency (const PackageOrBlockDepSpec &)> & f) :
+ resolver(r),
+ our_qpn_s(q),
+ parent_make_sanitised(f),
+ super_complicated(false),
+ nested(false),
+ active_sublist(0),
+ seen_any(false)
+ {
+ }
+
+ void visit_package_or_block_spec(const PackageOrBlockDepSpec & spec)
+ {
+ seen_any = true;
+
+ if (active_sublist)
+ active_sublist->push_back(spec);
+ else
+ {
+ std::list<PackageOrBlockDepSpec> l;
+ l.push_back(spec);
+ child_groups.push_back(l);
+ }
+ }
+
+ void visit_package_spec(const PackageDepSpec & spec)
+ {
+ if (spec.package_ptr())
+ visit_package_or_block_spec(PackageOrBlockDepSpec(spec));
+ else
+ super_complicated = true;
+ }
+
+ void visit_block_spec(const BlockDepSpec & spec)
+ {
+ if (spec.blocked_spec()->package_ptr())
+ visit_package_or_block_spec(PackageOrBlockDepSpec(spec));
+ else
+ super_complicated = true;
+ }
+
+ void visit(const DependencySpecTree::NodeType<PackageDepSpec>::Type & node)
+ {
+ visit_package_spec(*node.spec());
+ }
+
+ void visit(const DependencySpecTree::NodeType<BlockDepSpec>::Type & node)
+ {
+ visit_block_spec(*node.spec());
+ }
+
+ void visit(const DependencySpecTree::NodeType<ConditionalDepSpec>::Type & node)
+ {
+ if (node.spec()->condition_met())
+ {
+ nested = true;
+
+ if (active_sublist)
+ std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this));
+ else
+ {
+ Save<std::list<PackageOrBlockDepSpec> *> save_active_sublist(&active_sublist, 0);
+ active_sublist = &*child_groups.insert(child_groups.end(), std::list<PackageOrBlockDepSpec>());
+ std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this));
+ }
+ }
+ }
+
+ void visit(const DependencySpecTree::NodeType<AllDepSpec>::Type & node)
+ {
+ nested = true;
+
+ if (active_sublist)
+ std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this));
+ else
+ {
+ Save<std::list<PackageOrBlockDepSpec> *> save_active_sublist(&active_sublist, 0);
+ active_sublist = &*child_groups.insert(child_groups.end(), std::list<PackageOrBlockDepSpec>());
+ std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this));
+ }
+ }
+
+ void visit(const DependencySpecTree::NodeType<AnyDepSpec>::Type & node)
+ {
+ AnyDepSpecChildHandler h(resolver, our_qpn_s, parent_make_sanitised);
+ std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(h));
+ std::list<SanitisedDependency> l;
+ h.commit(
+ parent_make_sanitised,
+ std::tr1::bind(&list_push_back<SanitisedDependency>, &l, std::tr1::placeholders::_1)
+ );
+
+ if (active_sublist)
+ {
+ for (std::list<SanitisedDependency>::const_iterator i(l.begin()), i_end(l.end()) ;
+ i != i_end ; ++i)
+ visit_package_or_block_spec(i->spec());
+ }
+ else
+ {
+ Save<std::list<PackageOrBlockDepSpec> *> save_active_sublist(&active_sublist, 0);
+ active_sublist = &*child_groups.insert(child_groups.end(), std::list<PackageOrBlockDepSpec>());
+ for (std::list<SanitisedDependency>::const_iterator i(l.begin()), i_end(l.end()) ;
+ i != i_end ; ++i)
+ visit_package_or_block_spec(i->spec());
+ }
+ }
+
+ void visit(const DependencySpecTree::NodeType<NamedSetDepSpec>::Type &)
+ {
+ super_complicated = true;
+ }
+
+ void visit(const DependencySpecTree::NodeType<DependencyLabelsDepSpec>::Type &)
+ {
+ super_complicated = true;
+ }
+
+ void commit(
+ const std::tr1::function<SanitisedDependency (const PackageOrBlockDepSpec &)> & make_sanitised,
+ const std::tr1::function<void (const SanitisedDependency &)> & apply)
+ {
+ if (! seen_any)
+ {
+ }
+ else if (super_complicated)
+ throw InternalError(PALUDIS_HERE, "can't");
+ else
+ {
+ /* we've got a choice of groups of packages. pick the best score, left to right. */
+ std::list<std::list<PackageOrBlockDepSpec> >::const_iterator g_best(child_groups.end());
+ int best_score(-1);
+
+ for (std::list<std::list<PackageOrBlockDepSpec> >::const_iterator g(child_groups.begin()),
+ g_end(child_groups.end()) ;
+ g != g_end ; ++g)
+ {
+ int worst_score(-1);
+
+ if (g->empty())
+ throw InternalError(PALUDIS_HERE, "why did that happen?");
+
+ /* score of a group is the score of the worst child. */
+ for (std::list<PackageOrBlockDepSpec>::const_iterator h(g->begin()), h_end(g->end()) ;
+ h != h_end ; ++h)
+ {
+ int score(resolver.find_any_score(our_qpn_s, make_sanitised(PackageOrBlockDepSpec(*h))));
+ if ((-1 == worst_score) || (score < worst_score))
+ worst_score = score;
+ }
+
+ if ((best_score == -1) || (worst_score > best_score))
+ {
+ best_score = worst_score;
+ g_best = g;
+ }
+ }
+
+ if (g_best == child_groups.end())
+ throw InternalError(PALUDIS_HERE, "why did that happen?");
+ for (std::list<PackageOrBlockDepSpec>::const_iterator h(g_best->begin()), h_end(g_best->end()) ;
+ h != h_end ; ++h)
+ apply(make_sanitised(*h));
+ }
+ }
+ };
+
+ struct Finder
+ {
+ const Resolver & resolver;
+ const QPN_S our_qpn_s;
+ SanitisedDependencies & sanitised_dependencies;
+ std::list<std::tr1::shared_ptr<ActiveDependencyLabels> > labels_stack;
+
+ Finder(
+ const Resolver & r,
+ const QPN_S & q,
+ SanitisedDependencies & s,
+ const std::tr1::shared_ptr<const DependencyLabelSequence> & l) :
+ resolver(r),
+ our_qpn_s(q),
+ sanitised_dependencies(s)
+ {
+ labels_stack.push_front(make_shared_ptr(new ActiveDependencyLabels(*l)));
+ }
+
+
+ void add(const SanitisedDependency & dep)
+ {
+ sanitised_dependencies.add(dep);
+ }
+
+ SanitisedDependency make_sanitised(const PackageOrBlockDepSpec & spec)
+ {
+ return make_named_values<SanitisedDependency>(
+ value_for<n::active_dependency_labels>(*labels_stack.begin()),
+ value_for<n::spec>(spec)
+ );
+ }
+
+ void visit(const DependencySpecTree::NodeType<PackageDepSpec>::Type & node)
+ {
+ add(make_sanitised(*node.spec()));
+ }
+
+ void visit(const DependencySpecTree::NodeType<BlockDepSpec>::Type & node)
+ {
+ add(make_sanitised(*node.spec()));
+ }
+
+ void visit(const DependencySpecTree::NodeType<ConditionalDepSpec>::Type & node)
+ {
+ if (node.spec()->condition_met())
+ {
+ labels_stack.push_front(make_shared_ptr(new ActiveDependencyLabels(**labels_stack.begin())));
+ std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this));
+ labels_stack.pop_front();
+ }
+ }
+
+ void visit(const DependencySpecTree::NodeType<AllDepSpec>::Type & node)
+ {
+ labels_stack.push_front(make_shared_ptr(new ActiveDependencyLabels(**labels_stack.begin())));
+ std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this));
+ labels_stack.pop_front();
+ }
+
+ void visit(const DependencySpecTree::NodeType<AnyDepSpec>::Type & node)
+ {
+ AnyDepSpecChildHandler h(resolver, our_qpn_s, std::tr1::bind(&Finder::make_sanitised, this, std::tr1::placeholders::_1));
+ std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(h));
+ h.commit(
+ std::tr1::bind(&Finder::make_sanitised, this, std::tr1::placeholders::_1),
+ std::tr1::bind(&Finder::add, this, std::tr1::placeholders::_1)
+ );
+ }
+
+ void visit(const DependencySpecTree::NodeType<NamedSetDepSpec>::Type &) PALUDIS_ATTRIBUTE((noreturn))
+ {
+ throw InternalError(PALUDIS_HERE, "not implemented");
+ }
+
+ void visit(const DependencySpecTree::NodeType<DependencyLabelsDepSpec>::Type & node)
+ {
+ labels_stack.begin()->reset(new ActiveDependencyLabels(**labels_stack.begin(), *node.spec()));
+ }
+ };
+}
+
+namespace paludis
+{
+ template <>
+ struct Implementation<SanitisedDependencies>
+ {
+ std::list<SanitisedDependency> sanitised_dependencies;
+ };
+}
+
+SanitisedDependencies::SanitisedDependencies() :
+ PrivateImplementationPattern<SanitisedDependencies>(new Implementation<SanitisedDependencies>)
+{
+}
+
+SanitisedDependencies::~SanitisedDependencies()
+{
+}
+
+void
+SanitisedDependencies::_populate_one(
+ const Resolver & resolver,
+ const std::tr1::shared_ptr<const PackageID> & id,
+ const std::tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> > (PackageID::* const pmf) () const
+ )
+{
+ Context context("When finding dependencies for '" + stringify(*id) + "' from key '" + ((*id).*pmf)()->raw_name() + "':");
+
+ Finder f(resolver, QPN_S(id), *this, ((*id).*pmf)()->initial_labels());
+ ((*id).*pmf)()->value()->root()->accept(f);
+}
+
+void
+SanitisedDependencies::populate(
+ const Resolver & resolver,
+ const std::tr1::shared_ptr<const PackageID> & id)
+{
+ Context context("When finding dependencies for '" + stringify(*id) + "':");
+
+ if (id->build_dependencies_key())
+ _populate_one(resolver, id, &PackageID::build_dependencies_key);
+ if (id->run_dependencies_key())
+ _populate_one(resolver, id, &PackageID::run_dependencies_key);
+ if (id->post_dependencies_key())
+ _populate_one(resolver, id, &PackageID::post_dependencies_key);
+}
+
+void
+SanitisedDependencies::add(const SanitisedDependency & dep)
+{
+ _imp->sanitised_dependencies.push_back(dep);
+}
+
+SanitisedDependencies::ConstIterator
+SanitisedDependencies::begin() const
+{
+ return ConstIterator(_imp->sanitised_dependencies.begin());
+}
+
+SanitisedDependencies::ConstIterator
+SanitisedDependencies::end() const
+{
+ return ConstIterator(_imp->sanitised_dependencies.end());
+}
+
+std::ostream &
+paludis::resolver::operator<< (std::ostream & s, const SanitisedDependency & d)
+{
+ std::stringstream ss;
+ ss << "Dep(" << d.spec();
+
+ if (! d.active_dependency_labels()->system_labels()->empty())
+ ss << " system { " << join(indirect_iterator(d.active_dependency_labels()->system_labels()->begin()),
+ indirect_iterator(d.active_dependency_labels()->system_labels()->end()), ", ") << " }";
+ if (! d.active_dependency_labels()->type_labels()->empty())
+ ss << " type { " << join(indirect_iterator(d.active_dependency_labels()->type_labels()->begin()),
+ indirect_iterator(d.active_dependency_labels()->type_labels()->end()), ", ") << " }";
+ if (! d.active_dependency_labels()->abi_labels()->empty())
+ ss << " abi { " << join(indirect_iterator(d.active_dependency_labels()->abi_labels()->begin()),
+ indirect_iterator(d.active_dependency_labels()->abi_labels()->end()), ", ") << " }";
+ if (! d.active_dependency_labels()->suggest_labels()->empty())
+ ss << " suggest { " << join(indirect_iterator(d.active_dependency_labels()->suggest_labels()->begin()),
+ indirect_iterator(d.active_dependency_labels()->suggest_labels()->end()), ", ") << " }";
+
+ ss << ")";
+
+ s << ss.str();
+ return s;
+}
+
+std::ostream &
+paludis::resolver::operator<< (std::ostream & s, const PackageOrBlockDepSpec & d)
+{
+ if (d.if_package())
+ return s << *d.if_package();
+ else
+ return s << *d.if_block();
+}
+
+PackageOrBlockDepSpec::PackageOrBlockDepSpec(const BlockDepSpec & s) :
+ if_block(value_for<n::if_block>(make_shared_ptr(new BlockDepSpec(s)))),
+ if_package(value_for<n::if_package>(make_null_shared_ptr()))
+{
+}
+
+PackageOrBlockDepSpec::PackageOrBlockDepSpec(const PackageDepSpec & s) :
+ if_block(value_for<n::if_block>(make_null_shared_ptr())),
+ if_package(value_for<n::if_package>(make_shared_ptr(new PackageDepSpec(s))))
+{
+}
+
+template class WrappedForwardIterator<SanitisedDependencies::ConstIteratorTag, const SanitisedDependency>;
+
diff --git a/paludis/resolver/sanitised_dependencies.hh b/paludis/resolver/sanitised_dependencies.hh
new file mode 100644
index 0000000..b2881cd
--- /dev/null
+++ b/paludis/resolver/sanitised_dependencies.hh
@@ -0,0 +1,87 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_SANITISED_DEPENDENCIES_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_SANITISED_DEPENDENCIES_HH 1
+
+#include <paludis/resolver/sanitised_dependencies-fwd.hh>
+#include <paludis/resolver/resolver-fwd.hh>
+#include <paludis/util/named_value.hh>
+#include <paludis/dep_label-fwd.hh>
+#include <paludis/dep_spec.hh>
+#include <paludis/spec_tree-fwd.hh>
+#include <paludis/metadata_key-fwd.hh>
+
+namespace paludis
+{
+ namespace n
+ {
+ struct active_dependency_labels;
+ struct if_package;
+ struct if_block;
+ struct spec;
+ }
+
+ namespace resolver
+ {
+ struct PackageOrBlockDepSpec
+ {
+ NamedValue<n::if_block, std::tr1::shared_ptr<BlockDepSpec> > if_block;
+ NamedValue<n::if_package, std::tr1::shared_ptr<PackageDepSpec> > if_package;
+
+ PackageOrBlockDepSpec(const BlockDepSpec &);
+ PackageOrBlockDepSpec(const PackageDepSpec &);
+ };
+
+ struct SanitisedDependency
+ {
+ NamedValue<n::active_dependency_labels, std::tr1::shared_ptr<const ActiveDependencyLabels> > active_dependency_labels;
+ NamedValue<n::spec, PackageOrBlockDepSpec> spec;
+ };
+
+ class SanitisedDependencies :
+ private PrivateImplementationPattern<SanitisedDependencies>
+ {
+ private:
+ void _populate_one(
+ const Resolver &,
+ const std::tr1::shared_ptr<const PackageID> &,
+ const std::tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> > (PackageID::* const) () const
+ );
+
+ public:
+ SanitisedDependencies();
+ ~SanitisedDependencies();
+
+ void populate(
+ const Resolver &,
+ const std::tr1::shared_ptr<const PackageID> &);
+
+ void add(const SanitisedDependency & d);
+
+ struct ConstIteratorTag;
+ typedef WrappedForwardIterator<ConstIteratorTag, const SanitisedDependency> ConstIterator;
+
+ ConstIterator begin() const;
+ ConstIterator end() const;
+ };
+ }
+}
+
+#endif
diff --git a/paludis/resolver/suggest_restart-fwd.hh b/paludis/resolver/suggest_restart-fwd.hh
new file mode 100644
index 0000000..d63f2b5
--- /dev/null
+++ b/paludis/resolver/suggest_restart-fwd.hh
@@ -0,0 +1,31 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_SUGGEST_RESTART_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_SUGGEST_RESTART_FWD_HH 1
+
+namespace paludis
+{
+ namespace resolver
+ {
+ struct SuggestRestart;
+ }
+}
+
+#endif
diff --git a/paludis/resolver/suggest_restart.cc b/paludis/resolver/suggest_restart.cc
new file mode 100644
index 0000000..b25437f
--- /dev/null
+++ b/paludis/resolver/suggest_restart.cc
@@ -0,0 +1,108 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/resolver/suggest_restart.hh>
+#include <paludis/resolver/qpn_s.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <paludis/util/stringify.hh>
+
+using namespace paludis;
+using namespace paludis::resolver;
+
+namespace paludis
+{
+ template <>
+ struct Implementation<SuggestRestart>
+ {
+ const QPN_S qpn_s;
+ const std::tr1::shared_ptr<const Decision> previous_decision;
+ const std::tr1::shared_ptr<const Constraint> problematic_constraint;
+ const std::tr1::shared_ptr<const Decision> new_decision;
+ const std::tr1::shared_ptr<const Constraint> suggested_preset;
+
+ Implementation(const QPN_S & q,
+ const std::tr1::shared_ptr<const Decision> & pd,
+ const std::tr1::shared_ptr<const Constraint> & pc,
+ const std::tr1::shared_ptr<const Decision> & nd,
+ const std::tr1::shared_ptr<const Constraint> & nc
+ ) :
+ qpn_s(q),
+ previous_decision(pd),
+ problematic_constraint(pc),
+ new_decision(nd),
+ suggested_preset(nc)
+ {
+ }
+ };
+}
+
+SuggestRestart::SuggestRestart(const QPN_S & q,
+ const std::tr1::shared_ptr<const Decision> & pd,
+ const std::tr1::shared_ptr<const Constraint> & pc,
+ const std::tr1::shared_ptr<const Decision> & nd,
+ const std::tr1::shared_ptr<const Constraint> & nc
+ ) throw () :
+ PrivateImplementationPattern<SuggestRestart>(new Implementation<SuggestRestart>(q, pd, pc, nd, nc)),
+ Exception("Suggesting restart with " + stringify(*nc) + " for " + stringify(q))
+{
+}
+
+SuggestRestart::SuggestRestart(const SuggestRestart & o) :
+ PrivateImplementationPattern<SuggestRestart>(new Implementation<SuggestRestart>(o.qpn_s(), o.previous_decision(), o.problematic_constraint(),
+ o.new_decision(), o.suggested_preset())),
+ Exception(o)
+{
+}
+
+SuggestRestart::~SuggestRestart() throw ()
+{
+}
+
+const QPN_S
+SuggestRestart::qpn_s() const
+{
+ return _imp->qpn_s;
+}
+
+const std::tr1::shared_ptr<const Decision>
+SuggestRestart::previous_decision() const
+{
+ return _imp->previous_decision;
+}
+
+const std::tr1::shared_ptr<const Constraint>
+SuggestRestart::problematic_constraint() const
+{
+ return _imp->problematic_constraint;
+}
+
+const std::tr1::shared_ptr<const Decision>
+SuggestRestart::new_decision() const
+{
+ return _imp->new_decision;
+}
+
+const std::tr1::shared_ptr<const Constraint>
+SuggestRestart::suggested_preset() const
+{
+ return _imp->suggested_preset;
+}
+
+template class PrivateImplementationPattern<SuggestRestart>;
+
diff --git a/paludis/resolver/suggest_restart.hh b/paludis/resolver/suggest_restart.hh
new file mode 100644
index 0000000..fe88781
--- /dev/null
+++ b/paludis/resolver/suggest_restart.hh
@@ -0,0 +1,62 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_SUGGEST_RESTART_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_SUGGEST_RESTART_HH 1
+
+#include <paludis/resolver/suggest_restart-fwd.hh>
+#include <paludis/resolver/qpn_s-fwd.hh>
+#include <paludis/resolver/constraint-fwd.hh>
+#include <paludis/resolver/decision-fwd.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/exception.hh>
+#include <paludis/util/attributes.hh>
+
+namespace paludis
+{
+ namespace resolver
+ {
+ class PALUDIS_VISIBLE SuggestRestart :
+ private PrivateImplementationPattern<SuggestRestart>,
+ public Exception
+ {
+ public:
+ SuggestRestart(
+ const QPN_S &,
+ const std::tr1::shared_ptr<const Decision> & previous_decision,
+ const std::tr1::shared_ptr<const Constraint> & problematic_constraint,
+ const std::tr1::shared_ptr<const Decision> & new_decision,
+ const std::tr1::shared_ptr<const Constraint> & suggested_preset) throw ();
+ SuggestRestart(const SuggestRestart &);
+ ~SuggestRestart() throw ();
+
+ const QPN_S qpn_s() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ const std::tr1::shared_ptr<const Decision> previous_decision() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ const std::tr1::shared_ptr<const Constraint> problematic_constraint() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ const std::tr1::shared_ptr<const Decision> new_decision() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ const std::tr1::shared_ptr<const Constraint> suggested_preset() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ };
+ }
+
+#ifdef PALUDIS_HAVE_EXTERN_TEMPLATE
+ extern template class PrivateImplementationPattern<resolver::SuggestRestart>;
+#endif
+}
+
+#endif
diff --git a/paludis/resolver/use_installed-fwd.hh b/paludis/resolver/use_installed-fwd.hh
new file mode 100644
index 0000000..358c4c1
--- /dev/null
+++ b/paludis/resolver/use_installed-fwd.hh
@@ -0,0 +1,34 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_USE_INSTALLED_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_USE_INSTALLED_FWD_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <iosfwd>
+
+namespace paludis
+{
+ namespace resolver
+ {
+#include <paludis/resolver/use_installed-se.hh>
+ }
+}
+
+#endif
diff --git a/paludis/resolver/use_installed.cc b/paludis/resolver/use_installed.cc
new file mode 100644
index 0000000..e611566
--- /dev/null
+++ b/paludis/resolver/use_installed.cc
@@ -0,0 +1,29 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/resolver/use_installed.hh>
+#include <paludis/util/exception.hh>
+#include <paludis/util/stringify.hh>
+#include <ostream>
+
+using namespace paludis;
+using namespace paludis::resolver;
+
+#include <paludis/resolver/use_installed-se.cc>
+
diff --git a/paludis/resolver/use_installed.hh b/paludis/resolver/use_installed.hh
new file mode 100644
index 0000000..c114c61
--- /dev/null
+++ b/paludis/resolver/use_installed.hh
@@ -0,0 +1,33 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_RESOLVER_USE_INSTALLED_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_USE_INSTALLED_HH 1
+
+#include <paludis/resolver/use_installed-fwd.hh>
+
+namespace paludis
+{
+ namespace resolver
+ {
+
+ }
+}
+
+#endif
diff --git a/paludis/resolver/use_installed.se b/paludis/resolver/use_installed.se
new file mode 100644
index 0000000..ec6e438
--- /dev/null
+++ b/paludis/resolver/use_installed.se
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# vim: set sw=4 sts=4 et ft=sh :
+
+make_enum_UseInstalled()
+{
+ prefix ui
+ namespace paludis::resolver
+
+ # must be kept in strictness order
+ key ui_never "Never"
+ key ui_only_if_transient "Only if it is transient"
+ key ui_if_same "If it is the same"
+ key ui_if_same_version "If it is the same version"
+ key ui_if_possible "If possible"
+}
+
diff --git a/src/clients/cave/Makefile.am b/src/clients/cave/Makefile.am
index 22035a2..d2634e8 100644
--- a/src/clients/cave/Makefile.am
+++ b/src/clients/cave/Makefile.am
@@ -30,6 +30,7 @@ command_MANS = \
cave-print-repository-formats.1 \
cave-print-sets.1 \
cave-print-sync-protocols.1 \
+ cave-resolve.1 \
cave-show.1 \
cave-sync.1
@@ -51,6 +52,7 @@ cave_LDADD = \
$(top_builddir)/paludis/libpaludis_@PALUDIS_PC_SLOT@.la \
$(top_builddir)/paludis/args/libpaludisargs_@PALUDIS_PC_SLOT@.la \
$(top_builddir)/paludis/util/libpaludisutil_@PALUDIS_PC_SLOT@.la \
+ $(top_builddir)/paludis/resolver/libpaludisresolver.a \
$(top_builddir)/src/output/liboutput.a \
$(DYNAMIC_LD_LIBS)
@@ -62,7 +64,8 @@ man_cave_LDADD = \
$(top_builddir)/paludis/args/libpaludisargs_@PALUDIS_PC_SLOT@.la \
$(top_builddir)/paludis/args/libpaludisman_@PALUDIS_PC_SLOT@.a \
$(top_builddir)/paludis/util/libpaludisutil_@PALUDIS_PC_SLOT@.la \
- $(top_builddir)/paludis/libpaludismanpagethings_@PALUDIS_PC_SLOT@.la
+ $(top_builddir)/paludis/libpaludismanpagethings_@PALUDIS_PC_SLOT@.la \
+ $(top_builddir)/paludis/resolver/libpaludisresolver.a
noinst_LIBRARIES = libcave.a
@@ -86,6 +89,12 @@ libcave_a_SOURCES = \
cmd_print_repository_formats.cc cmd_print_repository_formats.hh \
cmd_print_sets.cc cmd_print_sets.hh \
cmd_print_sync_protocols.cc cmd_print_sync_protocols.hh \
+ cmd_resolve.cc cmd_resolve.hh \
+ cmd_resolve_cmdline.cc cmd_resolve_cmdline.hh \
+ cmd_resolve_display_callback.cc cmd_resolve_display_callback.hh \
+ cmd_resolve_display_explanations.cc cmd_resolve_display_explanations.hh \
+ cmd_resolve_display_resolution.cc cmd_resolve_display_resolution.hh \
+ cmd_resolve_dump.cc cmd_resolve_dump.hh \
cmd_show.cc cmd_show.hh \
cmd_sync.cc cmd_sync.hh \
exceptions.cc exceptions.hh \
@@ -100,7 +109,6 @@ libcave_a_SOURCES = \
# cmd_contents.cc \
# cmd_executables.cc \
# cmd_info.cc \
-# cmd_install.cc \
# cmd_owner.cc \
# cmd_print_id_actions.cc \
# cmd_print_id_masks.cc \
diff --git a/src/clients/cave/cmd_resolve.cc b/src/clients/cave/cmd_resolve.cc
new file mode 100644
index 0000000..dce3f00
--- /dev/null
+++ b/src/clients/cave/cmd_resolve.cc
@@ -0,0 +1,638 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "cmd_resolve.hh"
+#include "cmd_resolve_cmdline.hh"
+#include "cmd_resolve_display_callback.hh"
+#include "cmd_resolve_display_explanations.hh"
+#include "cmd_resolve_display_resolution.hh"
+#include "cmd_resolve_dump.hh"
+#include "exceptions.hh"
+#include "command_command_line.hh"
+
+#include <paludis/util/make_shared_ptr.hh>
+#include <paludis/util/mutex.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/make_named_values.hh>
+#include <paludis/args/do_help.hh>
+#include <paludis/resolver/resolver.hh>
+#include <paludis/resolver/resolution.hh>
+#include <paludis/resolver/decision.hh>
+#include <paludis/resolver/resolver_functions.hh>
+#include <paludis/resolver/reason.hh>
+#include <paludis/resolver/suggest_restart.hh>
+#include <paludis/resolver/qpn_s.hh>
+#include <paludis/resolver/constraint.hh>
+#include <paludis/resolver/sanitised_dependencies.hh>
+#include <paludis/resolver/destinations.hh>
+#include <paludis/user_dep_spec.hh>
+#include <paludis/notifier_callback.hh>
+#include <paludis/generator.hh>
+#include <paludis/filter.hh>
+#include <paludis/selection.hh>
+#include <paludis/filtered_generator.hh>
+#include <paludis/version_spec.hh>
+#include <paludis/metadata_key.hh>
+#include <paludis/environment.hh>
+#include <paludis/match_package.hh>
+
+#include <algorithm>
+#include <iostream>
+#include <cstdlib>
+#include <map>
+
+using namespace paludis;
+using namespace paludis::resolver;
+using namespace cave;
+
+using std::cout;
+using std::endl;
+
+namespace
+{
+ void add_resolver_targets(
+ const std::tr1::shared_ptr<Environment> & env,
+ const std::tr1::shared_ptr<Resolver> & resolver,
+ const ResolveCommandLine & cmdline)
+ {
+ Context context("When adding targets from commandline:");
+
+ if (cmdline.begin_parameters() == cmdline.end_parameters())
+ throw args::DoHelp("Must specify at least one target");
+
+ bool seen_sets(false), seen_packages(false);
+ for (ResolveCommandLine::ParametersConstIterator p(cmdline.begin_parameters()), p_end(cmdline.end_parameters()) ;
+ p != p_end ; ++p)
+ {
+ try
+ {
+ resolver->add_target(parse_user_package_dep_spec(*p, env.get(),
+ UserPackageDepSpecOptions() + updso_throw_if_set));
+ if (seen_sets)
+ throw args::DoHelp("Cannot specify both set and package targets");
+ seen_packages = true;
+ }
+ catch (const GotASetNotAPackageDepSpec &)
+ {
+ if (seen_packages)
+ throw args::DoHelp("Cannot specify both set and package targets");
+ if (seen_sets)
+ throw args::DoHelp("Cannot specify multiple set targets");
+
+ resolver->add_target(SetName(*p));
+ seen_sets = true;
+ }
+ }
+ }
+
+ UseInstalled use_installed_from_cmdline(const args::EnumArg & a, const bool is_set)
+ {
+ if (a.argument() == "auto")
+ return is_set ? ui_if_same : ui_never;
+ else if (a.argument() == "never")
+ return ui_never;
+ else if (a.argument() == "if-transient")
+ return ui_only_if_transient;
+ else if (a.argument() == "if-same")
+ return ui_if_same;
+ else if (a.argument() == "if-same-version")
+ return ui_if_same_version;
+ else if (a.argument() == "if-possible")
+ return ui_if_possible;
+ else
+ throw args::DoHelp("Don't understand argument '" + a.argument() + "' to '--" + a.long_name() + "'");
+ }
+
+ struct UseInstalledVisitor
+ {
+ const ResolveCommandLine & cmdline;
+ const bool from_set;
+
+ UseInstalledVisitor(const ResolveCommandLine & c, const bool f) :
+ cmdline(c),
+ from_set(f)
+ {
+ }
+
+ UseInstalled visit(const DependencyReason &) const
+ {
+ return use_installed_from_cmdline(cmdline.a_keep, false);
+ }
+
+ UseInstalled visit(const TargetReason &) const
+ {
+ return use_installed_from_cmdline(cmdline.a_keep_targets, from_set);
+ }
+
+ UseInstalled visit(const PresetReason &) const
+ {
+ return ui_if_possible;
+ }
+
+ UseInstalled visit(const SetReason & r) const
+ {
+ UseInstalledVisitor v(cmdline, true);
+ return r.reason_for_set()->accept_returning<UseInstalled>(v);
+ }
+ };
+
+ UseInstalled use_installed_fn(const ResolveCommandLine & cmdline,
+ const QPN_S &,
+ const PackageDepSpec &,
+ const std::tr1::shared_ptr<const Reason> & reason)
+ {
+ UseInstalledVisitor v(cmdline, false);
+ return reason->accept_returning<UseInstalled>(v);
+ }
+
+ int reinstall_scm_days(const ResolveCommandLine & cmdline)
+ {
+ if (cmdline.a_reinstall_scm.argument() == "always")
+ return 0;
+ else if (cmdline.a_reinstall_scm.argument() == "daily")
+ return 1;
+ else if (cmdline.a_reinstall_scm.argument() == "weekly")
+ return 7;
+ else if (cmdline.a_reinstall_scm.argument() == "never")
+ return -1;
+ else
+ throw args::DoHelp("Don't understand argument '" + cmdline.a_reinstall_scm.argument() + "' to '--"
+ + cmdline.a_reinstall_scm.long_name() + "'");
+ }
+
+ bool is_scm_name(const QualifiedPackageName & n)
+ {
+ std::string pkg(stringify(n.package()));
+ switch (pkg.length())
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ return false;
+
+ default:
+ if (0 == pkg.compare(pkg.length() - 6, 6, "-darcs"))
+ return true;
+
+ case 5:
+ if (0 == pkg.compare(pkg.length() - 5, 5, "-live"))
+ return true;
+
+ case 4:
+ if (0 == pkg.compare(pkg.length() - 4, 4, "-cvs"))
+ return true;
+ if (0 == pkg.compare(pkg.length() - 4, 4, "-svn"))
+ return true;
+ return false;
+ }
+ }
+
+ bool is_scm_older_than(const std::tr1::shared_ptr<const PackageID> & id, const int n)
+ {
+ if (id->version().is_scm() || is_scm_name(id->name()))
+ {
+ static time_t current_time(time(0)); /* static to avoid weirdness */
+ time_t installed_time(current_time);
+ if (id->installed_time_key())
+ installed_time = id->installed_time_key()->value();
+
+ return (current_time - installed_time) > (24 * 60 * 60 * n);
+ }
+ else
+ return false;
+ }
+
+ bool installed_is_scm_older_than(const Environment * const env, const QPN_S & q, const int n)
+ {
+ Context context("When working out whether '" + stringify(q) + "' has installed SCM packages:");
+
+ const std::tr1::shared_ptr<const PackageIDSequence> ids((*env)[selection::AllVersionsUnsorted(
+ generator::Package(q.package()) |
+ q.make_slot_filter() |
+ filter::SupportsAction<InstalledAction>())]);
+
+ for (PackageIDSequence::ConstIterator i(ids->begin()), i_end(ids->end()) ;
+ i != i_end ; ++i)
+ {
+ if (is_scm_older_than(*i, n))
+ return true;
+ }
+
+ return false;
+ }
+
+ typedef std::map<QPN_S, std::tr1::shared_ptr<Constraints> > InitialConstraints;
+
+ const std::tr1::shared_ptr<Constraints> make_initial_constraints_for(
+ const Environment * const env,
+ const ResolveCommandLine & cmdline,
+ const QPN_S & qpn_s)
+ {
+ const std::tr1::shared_ptr<Constraints> result(new Constraints);
+
+ int n(reinstall_scm_days(cmdline));
+ if ((-1 != n) && installed_is_scm_older_than(env, qpn_s, n))
+ {
+ result->add(make_shared_ptr(new Constraint(make_named_values<Constraint>(
+ value_for<n::nothing_is_fine_too>(false),
+ value_for<n::reason>(make_shared_ptr(new PresetReason)),
+ value_for<n::spec>(make_package_dep_spec(PartiallyMadePackageDepSpecOptions()).package(qpn_s.package())),
+ value_for<n::to_destination_slash>(false),
+ value_for<n::use_installed>(ui_only_if_transient)
+ ))));
+ }
+
+ return result;
+ }
+
+ const std::tr1::shared_ptr<Constraints> initial_constraints_for_fn(
+ const Environment * const env,
+ const ResolveCommandLine & cmdline,
+ const InitialConstraints & initial_constraints,
+ const QPN_S & qpn_s)
+ {
+ InitialConstraints::const_iterator i(initial_constraints.find(qpn_s));
+ if (i == initial_constraints.end())
+ return make_initial_constraints_for(env, cmdline, qpn_s);
+ else
+ return i->second;
+ }
+
+ struct IsTargetVisitor
+ {
+ bool visit(const DependencyReason &) const
+ {
+ return false;
+ }
+
+ bool visit(const PresetReason &) const
+ {
+ return false;
+ }
+
+ bool visit(const TargetReason &) const
+ {
+ return true;
+ }
+
+ bool visit(const SetReason & r) const
+ {
+ return r.reason_for_set()->accept_returning<bool>(*this);
+ }
+ };
+
+ bool is_target(const std::tr1::shared_ptr<const Reason> & reason)
+ {
+ IsTargetVisitor v;
+ return reason->accept_returning<bool>(v);
+ }
+
+ struct SlotNameFinder
+ {
+ std::tr1::shared_ptr<SlotName> visit(const SlotExactRequirement & s)
+ {
+ return make_shared_ptr(new SlotName(s.slot()));
+ }
+
+ std::tr1::shared_ptr<SlotName> visit(const SlotAnyUnlockedRequirement &)
+ {
+ return make_null_shared_ptr();
+ }
+
+ std::tr1::shared_ptr<SlotName> visit(const SlotAnyLockedRequirement &)
+ {
+ return make_null_shared_ptr();
+ }
+ };
+
+ const std::tr1::shared_ptr<QPN_S_Sequence>
+ get_qpn_s_s_for_fn(const Environment * const env,
+ const ResolveCommandLine & cmdline,
+ const PackageDepSpec & spec,
+ const std::tr1::shared_ptr<const Reason> & reason)
+ {
+ std::tr1::shared_ptr<QPN_S_Sequence> result(new QPN_S_Sequence);
+
+ std::tr1::shared_ptr<SlotName> exact_slot;
+
+ if (spec.slot_requirement_ptr())
+ {
+ SlotNameFinder f;
+ exact_slot = spec.slot_requirement_ptr()->accept_returning<std::tr1::shared_ptr<SlotName> >(f);
+ }
+
+ if (exact_slot)
+ result->push_back(QPN_S(spec, exact_slot));
+ else
+ {
+ std::tr1::shared_ptr<QPN_S> best;
+ std::list<QPN_S> installed;
+
+ const std::tr1::shared_ptr<const PackageIDSequence> ids((*env)[selection::BestVersionOnly(
+ generator::Matches(spec, MatchPackageOptions() + mpo_ignore_additional_requirements) |
+ filter::SupportsAction<InstallAction>() |
+ filter::NotMasked())]);
+
+ if (! ids->empty())
+ best = make_shared_ptr(new QPN_S(*ids->begin()));
+
+ const std::tr1::shared_ptr<const PackageIDSequence> installed_ids((*env)[selection::BestVersionInEachSlot(
+ generator::Matches(spec, MatchPackageOptions() + mpo_ignore_additional_requirements) |
+ filter::SupportsAction<InstalledAction>())]);
+
+ for (PackageIDSequence::ConstIterator i(installed_ids->begin()), i_end(installed_ids->end()) ;
+ i != i_end ; ++i)
+ installed.push_back(QPN_S(*i));
+
+ const args::EnumArg & arg(is_target(reason) ? cmdline.a_target_slots : cmdline.a_slots);
+
+ if (! best)
+ std::copy(installed.begin(), installed.end(), result->back_inserter());
+ else if (arg.argument() == "best-or-installed")
+ {
+ if (installed.end() == std::find(installed.begin(), installed.end(), *best))
+ result->push_back(*best);
+ else
+ std::copy(installed.begin(), installed.end(), result->back_inserter());
+ }
+ else if (arg.argument() == "installed-or-best")
+ {
+ if (installed.empty())
+ result->push_back(*best);
+ else
+ std::copy(installed.begin(), installed.end(), result->back_inserter());
+ }
+ else if (arg.argument() == "all")
+ {
+ if (installed.end() == std::find(installed.begin(), installed.end(), *best))
+ result->push_back(*best);
+ std::copy(installed.begin(), installed.end(), result->back_inserter());
+ }
+ else if (arg.argument() == "best")
+ result->push_back(*best);
+ else
+ throw args::DoHelp("Don't understand argument '" + arg.argument() + "' to '--"
+ + arg.long_name() + "'");
+ }
+
+ return result;
+ }
+
+ struct IsSuggestionVisitor
+ {
+ bool is_suggestion;
+
+ IsSuggestionVisitor() :
+ is_suggestion(true)
+ {
+ }
+
+ void visit(const DependencyRequiredLabel &)
+ {
+ is_suggestion = false;
+ }
+
+ void visit(const DependencyRecommendedLabel &)
+ {
+ is_suggestion = false;
+ }
+
+ void visit(const DependencySuggestedLabel &)
+ {
+ }
+ };
+
+ struct IsTypeDepVisitor
+ {
+ bool is_build_dep;
+ bool is_compiled_against_dep;
+
+ IsTypeDepVisitor() :
+ is_build_dep(true),
+ is_compiled_against_dep(false)
+ {
+ }
+
+ void visit(const DependencyBuildLabel &)
+ {
+ }
+
+ void visit(const DependencyRunLabel &)
+ {
+ is_build_dep = false;
+ }
+
+ void visit(const DependencyPostLabel &)
+ {
+ is_build_dep = false;
+ }
+
+ void visit(const DependencyInstallLabel &)
+ {
+ }
+
+ void visit(const DependencyCompileLabel &)
+ {
+ is_compiled_against_dep = true;
+ }
+ };
+
+ bool is_suggestion(const SanitisedDependency & dep)
+ {
+ if (dep.active_dependency_labels()->suggest_labels()->empty())
+ return false;
+
+ IsSuggestionVisitor v;
+ std::for_each(indirect_iterator(dep.active_dependency_labels()->suggest_labels()->begin()),
+ indirect_iterator(dep.active_dependency_labels()->suggest_labels()->end()),
+ accept_visitor(v));
+ return v.is_suggestion;
+ }
+
+ bool is_just_build_dep(const SanitisedDependency & dep)
+ {
+ if (dep.active_dependency_labels()->type_labels()->empty())
+ throw InternalError(PALUDIS_HERE, "not implemented");
+
+ IsTypeDepVisitor v;
+ std::for_each(indirect_iterator(dep.active_dependency_labels()->type_labels()->begin()),
+ indirect_iterator(dep.active_dependency_labels()->type_labels()->end()),
+ accept_visitor(v));
+ return v.is_build_dep;
+ }
+
+ bool is_compiled_against_dep(const SanitisedDependency & dep)
+ {
+ if (dep.active_dependency_labels()->type_labels()->empty())
+ throw InternalError(PALUDIS_HERE, "not implemented");
+
+ IsTypeDepVisitor v;
+ std::for_each(indirect_iterator(dep.active_dependency_labels()->type_labels()->begin()),
+ indirect_iterator(dep.active_dependency_labels()->type_labels()->end()),
+ accept_visitor(v));
+ return v.is_compiled_against_dep;
+ }
+
+ bool care_about_dep_fn(const Environment * const, const ResolveCommandLine & cmdline,
+ const QPN_S &, const std::tr1::shared_ptr<const Resolution> & resolution,
+ const SanitisedDependency & dep)
+ {
+ if (is_suggestion(dep))
+ return false;
+
+ if (resolution->decision()->is_installed())
+ {
+ if (! cmdline.a_follow_installed_build_dependencies.specified())
+ if (is_just_build_dep(dep))
+ return false;
+ if (cmdline.a_ignore_installed_dependencies.specified())
+ if (! is_compiled_against_dep(dep))
+ return false;
+ }
+
+ return true;
+ }
+}
+
+
+bool
+ResolveCommand::important() const
+{
+ return true;
+}
+
+int
+ResolveCommand::run(
+ const std::tr1::shared_ptr<Environment> & env,
+ const std::tr1::shared_ptr<const Sequence<std::string > > & args
+ )
+{
+ ResolveCommandLine cmdline;
+ cmdline.run(args, "CAVE", "CAVE_RESOLVE_OPTIONS", "CAVE_RESOLVE_CMDLINE");
+
+ if (cmdline.a_help.specified())
+ {
+ cout << cmdline;
+ return EXIT_SUCCESS;
+ }
+
+ if (cmdline.a_lazy.specified() + cmdline.a_complete.specified() + cmdline.a_everything.specified() > 1)
+ throw args::DoHelp("At most one of '--" + cmdline.a_lazy.long_name() + "', '--" + cmdline.a_complete.long_name()
+ + "' or '--" + cmdline.a_everything.long_name() + "' may be specified");
+
+ if (cmdline.a_lazy.specified())
+ {
+ if (! cmdline.a_target_slots.specified())
+ cmdline.a_target_slots.set_argument("best");
+ if (! cmdline.a_slots.specified())
+ cmdline.a_slots.set_argument("best");
+ if (! cmdline.a_reinstall_scm.specified())
+ cmdline.a_reinstall_scm.set_argument("never");
+ if (! cmdline.a_ignore_installed_dependencies.specified())
+ cmdline.a_ignore_installed_dependencies.set_specified(true);
+ }
+
+ if (cmdline.a_complete.specified())
+ {
+ if (! cmdline.a_keep.specified())
+ cmdline.a_keep.set_argument("if-same");
+ if (! cmdline.a_target_slots.specified())
+ cmdline.a_target_slots.set_argument("all");
+ if (! cmdline.a_slots.specified())
+ cmdline.a_slots.set_argument("all");
+ if (! cmdline.a_follow_installed_build_dependencies.specified())
+ cmdline.a_follow_installed_build_dependencies.set_specified(true);
+ }
+
+ if (cmdline.a_everything.specified())
+ {
+ if (! cmdline.a_keep.specified())
+ cmdline.a_keep.set_argument("if-transient");
+ if (! cmdline.a_keep_targets.specified())
+ cmdline.a_keep_targets.set_argument("if-transient");
+ if (! cmdline.a_target_slots.specified())
+ cmdline.a_target_slots.set_argument("all");
+ if (! cmdline.a_slots.specified())
+ cmdline.a_slots.set_argument("all");
+ if (! cmdline.a_follow_installed_build_dependencies.specified())
+ cmdline.a_follow_installed_build_dependencies.set_specified(true);
+ }
+
+ int retcode(0);
+
+ InitialConstraints initial_constraints;
+
+ ResolverFunctions resolver_functions(make_named_values<ResolverFunctions>(
+ value_for<n::care_about_dep_fn>(std::tr1::bind(&care_about_dep_fn,
+ env.get(), std::tr1::cref(cmdline), std::tr1::placeholders::_1,
+ std::tr1::placeholders::_2, std::tr1::placeholders::_3)),
+ value_for<n::get_initial_constraints_for_fn>(std::tr1::bind(&initial_constraints_for_fn,
+ env.get(), std::tr1::cref(cmdline), std::tr1::cref(initial_constraints), std::tr1::placeholders::_1)),
+ value_for<n::get_qpn_s_s_for_fn>(std::tr1::bind(&get_qpn_s_s_for_fn,
+ env.get(), std::tr1::cref(cmdline), std::tr1::placeholders::_1, std::tr1::placeholders::_2)),
+ value_for<n::get_use_installed_fn>(std::tr1::bind(&use_installed_fn,
+ std::tr1::cref(cmdline), std::tr1::placeholders::_1, std::tr1::placeholders::_2, std::tr1::placeholders::_3))
+ ));
+ std::tr1::shared_ptr<Resolver> resolver(new Resolver(env.get(), resolver_functions));
+ try
+ {
+ while (true)
+ {
+ try
+ {
+ DisplayCallback display_callback;
+ ScopedNotifierCallback display_callback_holder(env.get(),
+ NotifierCallbackFunction(std::tr1::cref(display_callback)));
+ add_resolver_targets(env, resolver, cmdline);
+ resolver->resolve();
+ break;
+ }
+ catch (const SuggestRestart & e)
+ {
+ std::cout << "Restarting: for '" << e.qpn_s() << "' we had chosen '" << *e.previous_decision()
+ << "' but new constraint '" << *e.problematic_constraint() << "' means we now want '"
+ << *e.new_decision() << "' instead" << std::endl;
+ initial_constraints.insert(std::make_pair(e.qpn_s(), make_initial_constraints_for(
+ env.get(), cmdline, e.qpn_s()))).first->second->add(
+ e.suggested_preset());
+ resolver = make_shared_ptr(new Resolver(env.get(), resolver_functions));
+ }
+ }
+
+ display_resolution(env, resolver, cmdline);
+ display_explanations(env, resolver, cmdline);
+ }
+ catch (...)
+ {
+ dump_if_requested(env, resolver, cmdline);
+ throw;
+ }
+
+ dump_if_requested(env, resolver, cmdline);
+
+ return retcode;
+}
+
+std::tr1::shared_ptr<args::ArgsHandler>
+ResolveCommand::make_doc_cmdline()
+{
+ return make_shared_ptr(new ResolveCommandLine);
+}
+
diff --git a/src/clients/cave/cmd_resolve.hh b/src/clients/cave/cmd_resolve.hh
new file mode 100644
index 0000000..9d7edbf
--- /dev/null
+++ b/src/clients/cave/cmd_resolve.hh
@@ -0,0 +1,46 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESOLVE_HH
+#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESOLVE_HH 1
+
+#include "command.hh"
+
+namespace paludis
+{
+ namespace cave
+ {
+ class PALUDIS_VISIBLE ResolveCommand :
+ public Command
+ {
+ public:
+ bool important() const;
+
+ int run(
+ const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<const Sequence<std::string > > & args
+ );
+
+ std::tr1::shared_ptr<args::ArgsHandler> make_doc_cmdline();
+ };
+ }
+}
+
+
+#endif
diff --git a/src/clients/cave/cmd_resolve_cmdline.cc b/src/clients/cave/cmd_resolve_cmdline.cc
new file mode 100644
index 0000000..d30b792
--- /dev/null
+++ b/src/clients/cave/cmd_resolve_cmdline.cc
@@ -0,0 +1,250 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "cmd_resolve_cmdline.hh"
+
+using namespace paludis;
+using namespace cave;
+
+ResolveCommandLine::ResolveCommandLine() :
+// g_execution_options(this, "Execution Options", "Control execution."),
+// a_execute(&g_execution_options, "execute", 'x', "Execute the suggested actions", true),
+// a_preserve_world(&g_execution_options, "preserve-world", '1', "Do not modify the 'world' set", true),
+//
+ g_convenience_options(this, "Convenience Options", "Broad behaviour options."),
+ a_lazy(&g_convenience_options, "lazy", 'z', "Do as little work as possible.", true),
+ a_complete(&g_convenience_options, "complete", 'c', "Do all optional work.", true),
+ a_everything(&g_convenience_options, "everything", 'e', "Do all optional work, and also reinstall", true),
+
+// g_resolution_options(this, "Resolution Options", "Resolution options."),
+// a_permit_slot_uninstalls(&g_resolution_options, "permit-slot-uninstalls", '\0',
+// "Uninstall slots of packages if they are blocked by other slots of that package", true),
+// a_permit_uninstalls(&g_resolution_options, "permit-uninstalls", '\0',
+// "Uninstall packages that are blocked", true),
+// a_permit_downgrades(&g_resolution_options, "permit-downgrades", '\0', "Permit downgrades", true),
+// a_permit_unsafe_uninstalls(&g_resolution_options, "permit-unsafe-uninstalls", '\0',
+// "Permit uninstalls even if the uninstall isn't known to be safe", true),
+//
+// g_cleanup_options(this, "Cleanup Options", "Cleanup options."),
+// a_purge_unused_slots(&g_cleanup_options, "purge-unused-slots", '\0',
+// "Purge slots that are no longer used after an uninstall or clean", true),
+// a_purge_unused_packages(&g_cleanup_options, "purge-unused-packages", '\0',
+// "Purge packages that are no longer used after an uninstall or clean", true),
+//
+// g_failure_options(this, "Failure Options", "Failure handling options."),
+// a_continue_on_failure(&g_failure_options, "continue-on-failure", '\0',
+// "Whether to continue after an error occurs",
+// args::EnumArg::EnumArgOptions
+// ("if-fetching", "Only if we are just fetching packages")
+// ("never", "Never")
+// ("if-satisfied", "If remaining packages' dependencies are satisfied")
+// ("if-independent", "If remaining packages do not depend upon any failing package")
+// ("always", "Always (dangerous)"),
+// "if-fetching"),
+//
+// g_display_options(this, "Display Options", "Options relating to the resolution display."),
+// a_show_option_descriptions(&g_display_options, "show-option-descriptions", '\0',
+// "Whether to display descriptions for package options",
+// args::EnumArg::EnumArgOptions
+// ("none", "Don't show any descriptions")
+// ("new", "Show for any new options")
+// ("changed", "Show for new or changed options")
+// ("all", "Show all options"),
+// "changed"
+// ),
+// a_show_descriptions(&g_display_options, "show-descriptions", '\0',
+// "Whether to display package descriptions",
+// args::EnumArg::EnumArgOptions
+// ("none", "Don't show any descriptions")
+// ("new", "Show for new packages")
+// ("all", "Show for all packages"),
+// "new"
+// ),
+
+ g_explanations(this, "Explanations", "Options requesting the resolver explain a particular decision "
+ "that it made"),
+ a_explain(&g_explanations, "explain", '\0', "Explain why the resolver made a particular decision. The "
+ "argument is a package dependency specification, so --explain dev-libs/boost or --explain qt:3"
+ " or even --explain '*/*' (although --dump is a better way of getting highly noisy debug output)."),
+
+// g_phase_options(this, "Phase Options", "Options controlling which phases to execute. No sanity checking "
+// "is done, allowing you to shoot as many feet off as you desire. Phase names do not have the "
+// "src_, pkg_ or builtin_ prefix, so 'init', 'preinst', 'unpack', 'merge', 'strip' etc."),
+// a_skip_phase(&g_phase_options, "skip-phase", '\0', "Skip the named phases"),
+// a_abort_at_phase(&g_phase_options, "abort-at-phase", '\0', "Abort when a named phase is encounted"),
+// a_skip_until_phase(&g_phase_options, "skip-until-phase", '\0', "Skip every phase until a named phase is encounted"),
+// a_change_phases_for(&g_phase_options, "change-phases-for", '\0',
+// "Control to which package or packages these phase options apply",
+// args::EnumArg::EnumArgOptions
+// ("all", "All packages")
+// ("first", "Only the first package on the list")
+// ("last", "Only the last package on the list"),
+// "all"),
+//
+ g_keep_options(this, "Reinstall Options", "Control whether installed packages are kept."),
+ a_keep_targets(&g_keep_options, "keep-targets", 'K',
+ "Select whether to keep target packages",
+ args::EnumArg::EnumArgOptions
+ ("auto", 'a', "If the target is a set, if-same, otherwise never")
+ ("never", 'n', "Never")
+ ("if-transient", 't', "Only if the installed package is transient "
+ "(e.g. from 'importare')")
+ ("if-same", 's', "If it is the same as the proposed replacement")
+ ("if-same-version", 'v', "If it is the same version as the proposed replacement")
+ ("if-possible", 'p', "If possible"),
+
+ "auto"
+ ),
+ a_keep(&g_keep_options, "keep", 'k',
+ "Select whether to keep installed packages that are not targets",
+ args::EnumArg::EnumArgOptions
+ ("never", 'n', "Never")
+ ("if-transient", 't', "Only if the installed package is transient "
+ "(e.g. from 'importare') (default if --everything)")
+ ("if-same", 's', "If it is the same as the proposed replacement "
+ "(default if --complete)")
+ ("if-same-version", 'v', "If it is the same version as the proposed replacement")
+ ("if-possible", 'p', "If possible"),
+
+ "if-possible"
+ ),
+ a_reinstall_scm(&g_keep_options, "reinstall-scm", 'R',
+ "Select whether to reinstall SCM packages that would otherwise be kept",
+ args::EnumArg::EnumArgOptions
+ ("always", 'a', "Always")
+ ("daily", 'd', "If they were installed more than a day ago")
+ ("weekly", 'w', "If they were installed more than a week ago")
+ ("never", 'n', "Never (default if --lazy)"),
+ "weekly"
+ ),
+// a_reinstall_for_removals(&g_reinstall_options, "reinstall-for-removals", '\0',
+// "Select whether to rebuild packages if rebuilding would avoid an unsafe removal", true),
+//
+ g_slot_options(this, "Slot Options", "Control which slots are considered."),
+ a_target_slots(&g_slot_options, "target-slots", 'S',
+ "Which slots to consider for targets",
+ args::EnumArg::EnumArgOptions
+ ("best-or-installed", 'x', "Consider the best slot, if it is not installed, "
+ "or all installed slots otherwise")
+ ("installed-or-best", 'i', "Consider all installed slots, or the best "
+ "installable slot if nothing is installed")
+ ("all", 'a', "Consider all installed slots and the best installable slot"
+ " (default if --complete or --everything)")
+ ("best", 'b', "Consider the best installable slot only"
+ " (default if --lazy)"),
+ "best-or-installed"
+ ),
+ a_slots(&g_slot_options, "slots", 's',
+ "Which slots to consider for packages that are not targets",
+ args::EnumArg::EnumArgOptions
+ ("best-or-installed", 'x', "Consider the best slot, if it is not installed, "
+ "or all installed slots otherwise")
+ ("installed-or-best", 'i', "Consider all installed slots, or the best "
+ "installable slot if nothing is installed")
+ ("all", 'a', "Consider all installed slots and the best installable slot"
+ " (default if --complete or --everything)")
+ ("best", 'b', "Consider the best installable slot only"
+ " (default if --lazy)"),
+ "best-or-installed"
+ ),
+
+ g_dependency_options(this, "Dependency Options", "Control which dependencies are followed."),
+ a_follow_installed_build_dependencies(&g_dependency_options, "follow-installed-build-dependencies", 'D',
+ "Follow build dependencies for installed packages (default if --complete or --everything)", true),
+ a_ignore_installed_dependencies(&g_dependency_options, "ignore-installed-dependencies", 'd',
+ "Ignore dependencies (except compiled-against dependencies, which are already taken) "
+ "for installed packages. (default if --lazy)", true),
+//
+// g_suggestion_options(this, "Suggestion Options", "Control whether suggestions are taken. Suggestions that are "
+// "already installed are instead treated as hard dependencies."),
+// a_suggestions(&g_suggestion_options, "suggestions", '\0', "How to treat suggestions and recommendations",
+// args::EnumArg::EnumArgOptions
+// ("ignore", "Ignore suggestions")
+// ("display", "Display suggestions, but do not take them unless explicitly told to do so")
+// ("take", "Take all suggestions"),
+// "display"),
+// a_recommendations(&g_suggestion_options, "recommendations", '\0', "How to treat recommendations",
+// args::EnumArg::EnumArgOptions
+// ("ignore", "Ignore recommendations")
+// ("display", "Display recommendations, but do not take them unless explicitly told to do so")
+// ("take", "Take all recommendations"),
+// "take"),
+// a_take(&g_suggestion_options, "take", '\0', "Take any suggestion matching the supplied package specification"
+// " (e.g. --take 'app-vim/securemodelines' or --take 'app-vim/*')"),
+// a_take_from(&g_suggestion_options, "take-from", '\0', "Take all suggestions made by any package matching the "
+// "supplied package specification"),
+// a_discard(&g_suggestion_options, "discard", '\0', "Discard any suggestion matching the supplied package specification"),
+// a_discard_from(&g_suggestion_options, "discard-from", '\0', "Discard all suggestions made by any package matching the "
+// "supplied package specification"),
+//
+// g_package_options(this, "Package Selection Options", "Control which packages are selected."),
+// a_prefer(&g_package_options, "prefer", '\0', "If there is a choice, prefer the specified package names"),
+// a_avoid(&g_package_options, "avoid", '\0', "If there is a choice, avoid the specified package names"),
+//
+// g_ordering_options(this, "Package Ordering Options", "Control the order in which packages are installed"),
+// a_early(&g_ordering_options, "early", '\0', "Try to install the specified package name as early as possible"),
+// a_late(&g_ordering_options, "late", '\0', "Try to install the specified package name as late as possible"),
+//
+// g_preset_options(this, "Preset Options", "Preset various constraints."),
+// a_soft_preset(&g_preset_options, "soft-preset", '\0', "Preset a given constraint, but allow the resolver to "
+// "override it. For example, --soft-preset cat/pkg::installed will tell the resolver to use the installed "
+// "cat/pkg if possible."),
+// a_fixed_preset(&g_preset_options, "fixed-preset", '\0', "Preset a given constraint, and do not allow the resolver to "
+// "override it. For example, --fixed-preset cat/pkg::installed will force the resolver to use the installed "
+// "cat/pkg, generating an error if it cannot."),
+//
+// g_destination_options(this, "Destination Options", "Control to which destinations packages are installed. "
+// "If no options from this group are selected, install only to /. Otherwise, install to all of the "
+// "specified destinations, and install to / as necessary to satisfy build dependencies."),
+// a_fetch(&g_destination_options, "fetch", 'f', "Only fetch packages, do not install anything", true),
+// a_create_binaries(&g_destination_options, "create-binaries", '\0', "Create binary packages", true),
+// a_install_to_chroot(&g_destination_options, "install-to-chroot", '\0', "Install packages to the environment-configured chroot", true),
+// a_install_to_root(&g_destination_options, "install-to-root", '\0', "Install packages to /", true),
+
+ g_dump_options(this, "Dump Options", "Dump the resolver's state to stdout after completion, or when an "
+ "error occurs. For debugging purposes; produces rather a lot of noise."),
+ a_dump(&g_dump_options, "dump", '\0', "Dump debug output", true),
+ a_dump_dependencies(&g_dump_options, "dump-dependencies", '\0', "If dumping, also dump the "
+ "sanitised dependencies selected for every package" , true)
+{
+ add_usage_line("[ -x|--execute ] [ -z|--lazy or -c|--complete or -e|--everything ] spec ...");
+ add_usage_line("[ -x|--execute ] [ -z|--lazy or -c|--complete or -e|--everything ] set");
+}
+
+std::string
+ResolveCommandLine::app_name() const
+{
+ return "cave resolve";
+}
+
+std::string
+ResolveCommandLine::app_synopsis() const
+{
+ return "Display how to resolve one or more targets, and possibly then "
+ "perform that resolution.";
+}
+
+std::string
+ResolveCommandLine::app_description() const
+{
+ return "Displays how to resolve one or more targets. If instructed, then "
+ "executes the relevant install and uninstall actions to perform that "
+ "resolution.";
+}
+
diff --git a/src/clients/cave/cmd_resolve_cmdline.hh b/src/clients/cave/cmd_resolve_cmdline.hh
new file mode 100644
index 0000000..366982b
--- /dev/null
+++ b/src/clients/cave/cmd_resolve_cmdline.hh
@@ -0,0 +1,126 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESOLVE_CMDLINE_HH
+#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESOLVE_CMDLINE_HH 1
+
+#include "command_command_line.hh"
+
+namespace paludis
+{
+ namespace cave
+ {
+ struct ResolveCommandLine :
+ CaveCommandCommandLine
+ {
+ virtual std::string app_name() const;
+ virtual std::string app_synopsis() const;
+ virtual std::string app_description() const;
+
+ // args::ArgsGroup g_execution_options;
+ // args::SwitchArg a_execute;
+ // args::SwitchArg a_preserve_world;
+
+ args::ArgsGroup g_convenience_options;
+ args::SwitchArg a_lazy;
+ args::SwitchArg a_complete;
+ args::SwitchArg a_everything;
+
+ // args::ArgsGroup g_resolution_options;
+ // args::SwitchArg a_permit_slot_uninstalls;
+ // args::SwitchArg a_permit_uninstalls;
+ // args::SwitchArg a_permit_downgrades;
+ // args::SwitchArg a_permit_unsafe_uninstalls;
+
+ // args::ArgsGroup g_cleanup_options;
+ // args::SwitchArg a_purge_unused_slots;
+ // args::SwitchArg a_purge_unused_packages;
+
+ // args::ArgsGroup g_failure_options;
+ // args::EnumArg a_continue_on_failure;
+
+ // args::ArgsGroup g_display_options;
+ // args::EnumArg a_show_option_descriptions;
+ // args::EnumArg a_show_descriptions;
+
+ args::ArgsGroup g_explanations;
+ args::StringSetArg a_explain;
+
+ // args::ArgsGroup g_phase_options;
+ // args::StringSetArg a_skip_phase;
+ // args::StringSetArg a_abort_at_phase;
+ // args::StringSetArg a_skip_until_phase;
+ // args::EnumArg a_change_phases_for;
+
+ args::ArgsGroup g_keep_options;
+ args::EnumArg a_keep_targets;
+ args::EnumArg a_keep;
+ args::EnumArg a_reinstall_scm;
+ // args::SwitchArg a_reinstall_for_removals;
+
+ args::ArgsGroup g_slot_options;
+ args::EnumArg a_target_slots;
+ args::EnumArg a_slots;
+
+ args::ArgsGroup g_dependency_options;
+ args::SwitchArg a_follow_installed_build_dependencies;
+ args::SwitchArg a_ignore_installed_dependencies;
+
+ // args::ArgsGroup g_suggestion_options;
+ // args::EnumArg a_suggestions;
+ // args::EnumArg a_recommendations;
+ // args::StringSetArg a_take;
+ // args::StringSetArg a_take_from;
+ // args::StringSetArg a_discard;
+ // args::StringSetArg a_discard_from;
+
+ // args::ArgsGroup g_package_options;
+ // args::StringSetArg a_prefer;
+ // args::StringSetArg a_avoid;
+
+ // args::ArgsGroup g_ordering_options;
+ // args::StringSetArg a_early;
+ // args::StringSetArg a_late;
+
+ // args::ArgsGroup g_preset_options;
+ // args::StringSetArg a_soft_preset;
+ // args::StringSetArg a_fixed_preset;
+
+ // args::ArgsGroup g_destination_options;
+ // args::SwitchArg a_fetch;
+ // args::SwitchArg a_create_binaries;
+ // args::SwitchArg a_install_to_chroot;
+ // args::SwitchArg a_install_to_root;
+
+ // args::ArgsGroup g_interactivity_options;
+ // args::SwitchArg a_interactive;
+ // args::SwitchArg a_interactive_slots;
+ // args::SwitchArg a_interactive_decisions;
+ // args::SwitchArg a_interactive_ordering;
+
+ args::ArgsGroup g_dump_options;
+ args::SwitchArg a_dump;
+ args::SwitchArg a_dump_dependencies;
+
+ ResolveCommandLine();
+ };
+ }
+}
+
+#endif
diff --git a/src/clients/cave/cmd_resolve_display_callback.cc b/src/clients/cave/cmd_resolve_display_callback.cc
new file mode 100644
index 0000000..6f00051
--- /dev/null
+++ b/src/clients/cave/cmd_resolve_display_callback.cc
@@ -0,0 +1,142 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "cmd_resolve_display_callback.hh"
+#include <paludis/notifier_callback.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <iostream>
+#include <map>
+
+using namespace paludis;
+using namespace cave;
+
+namespace paludis
+{
+ template <>
+ struct Implementation<DisplayCallback>
+ {
+ mutable Mutex mutex;
+ mutable unsigned width;
+ mutable std::map<std::string, int> metadata, steps;
+
+ Implementation() :
+ width(0)
+ {
+ }
+ };
+}
+
+
+DisplayCallback::DisplayCallback() :
+ PrivateImplementationPattern<DisplayCallback>(new Implementation<DisplayCallback>)
+{
+ std::cout << "Resolving: " << std::flush;
+}
+
+DisplayCallback::~DisplayCallback()
+{
+ std::cout << std::endl << std::endl;
+}
+
+void
+DisplayCallback::operator() (const NotifierCallbackEvent & event) const
+{
+ event.accept(*this);
+}
+
+void
+DisplayCallback::visit(const NotifierCallbackGeneratingMetadataEvent & e) const
+{
+ Lock lock(_imp->mutex);
+ ++_imp->metadata.insert(std::make_pair(stringify(e.repository()), 0)).first->second;
+ update();
+}
+
+void
+DisplayCallback::visit(const NotifierCallbackResolverStepEvent &) const
+{
+ Lock lock(_imp->mutex);
+ ++_imp->steps.insert(std::make_pair("steps", 0)).first->second;
+ update();
+}
+
+void
+DisplayCallback::update() const
+{
+ std::string s;
+ if (! _imp->steps.empty())
+ {
+ for (std::map<std::string, int>::const_iterator i(_imp->steps.begin()), i_end(_imp->steps.end()) ;
+ i != i_end ; ++i)
+ {
+ if (! s.empty())
+ s.append(", ");
+
+ s.append(stringify(i->second) + " " + i->first);
+ }
+ }
+
+ if (! _imp->metadata.empty())
+ {
+ std::multimap<int, std::string> biggest;
+ for (std::map<std::string, int>::const_iterator i(_imp->metadata.begin()), i_end(_imp->metadata.end()) ;
+ i != i_end ; ++i)
+ biggest.insert(std::make_pair(i->second, i->first));
+
+ int t(0), n(0);
+ std::string ss;
+ for (std::multimap<int, std::string>::const_reverse_iterator i(biggest.rbegin()), i_end(biggest.rend()) ;
+ i != i_end ; ++i)
+ {
+ ++n;
+
+ if (n == 4)
+ {
+ ss.append(", ...");
+ break;
+ }
+
+ if (n < 4)
+ {
+ if (! ss.empty())
+ ss.append(", ");
+
+ ss.append(stringify(i->first) + " " + i->second);
+ }
+
+ t += i->first;
+ }
+
+ if (! s.empty())
+ s.append(", ");
+ s.append(stringify(t) + " metadata (" + ss + ")");
+ }
+
+ std::cout << std::string(_imp->width, '\010') << s;
+
+ if (_imp->width > s.length())
+ std::cout
+ << std::string(_imp->width - s.length(), ' ')
+ << std::string(_imp->width - s.length(), '\010');
+
+ _imp->width = s.length();
+ std::cout << std::flush;
+}
+
diff --git a/src/clients/cave/cmd_resolve_display_callback.hh b/src/clients/cave/cmd_resolve_display_callback.hh
new file mode 100644
index 0000000..bf5ab55
--- /dev/null
+++ b/src/clients/cave/cmd_resolve_display_callback.hh
@@ -0,0 +1,50 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESOLVE_DISPLAY_CALLBACK_HH
+#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESOLVE_DISPLAY_CALLBACK_HH 1
+
+#include <paludis/util/mutex.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/notifier_callback-fwd.hh>
+
+namespace paludis
+{
+ namespace cave
+ {
+ struct DisplayCallback :
+ private PrivateImplementationPattern<DisplayCallback>
+ {
+ private:
+ void update() const;
+
+ public:
+ DisplayCallback();
+ ~DisplayCallback();
+
+ void operator() (const NotifierCallbackEvent & event) const;
+
+ void visit(const NotifierCallbackGeneratingMetadataEvent &) const;
+
+ void visit(const NotifierCallbackResolverStepEvent &) const;
+ };
+ }
+}
+
+#endif
diff --git a/src/clients/cave/cmd_resolve_display_explanations.cc b/src/clients/cave/cmd_resolve_display_explanations.cc
new file mode 100644
index 0000000..0622d95
--- /dev/null
+++ b/src/clients/cave/cmd_resolve_display_explanations.cc
@@ -0,0 +1,156 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "cmd_resolve_display_explanations.hh"
+#include <paludis/dep_spec.hh>
+#include <paludis/user_dep_spec.hh>
+#include <paludis/match_package.hh>
+#include <paludis/resolver/resolver.hh>
+#include <paludis/resolver/qpn_s.hh>
+#include <paludis/resolver/resolution.hh>
+#include <paludis/resolver/decision.hh>
+#include <paludis/resolver/constraint.hh>
+#include <paludis/resolver/reason.hh>
+#include <paludis/resolver/destinations.hh>
+#include <paludis/args/do_help.hh>
+#include <iostream>
+
+using namespace paludis;
+using namespace cave;
+using namespace paludis::resolver;
+
+namespace
+{
+ struct ReasonDisplayer
+ {
+ void visit(const TargetReason &)
+ {
+ std::cout << "it is a target";
+ }
+
+ void visit(const DependencyReason & reason)
+ {
+ std::cout << "of dependency " << reason.sanitised_dependency() << " from " << *reason.from_id();
+ }
+
+ void visit(const PresetReason &)
+ {
+ std::cout << "of a preset";
+ }
+
+ void visit(const SetReason & reason)
+ {
+ std::cout << "of set " << reason.set_name() << ", which is because ";
+ reason.reason_for_set()->accept(*this);
+ }
+ };
+}
+
+void
+cave::display_explanations(
+ const std::tr1::shared_ptr<Environment> & env,
+ const std::tr1::shared_ptr<Resolver> & resolver,
+ const ResolveCommandLine & cmdline)
+{
+ Context context("When displaying explanations:");
+
+ if (cmdline.a_explain.begin_args() == cmdline.a_explain.end_args())
+ return;
+
+ std::cout << "Explaining requested decisions:" << std::endl << std::endl;
+
+ for (args::StringSetArg::ConstIterator i(cmdline.a_explain.begin_args()), i_end(cmdline.a_explain.end_args()) ;
+ i != i_end ; ++i)
+ {
+ bool any(false);
+ PackageDepSpec spec(parse_user_package_dep_spec(*i, env.get(), UserPackageDepSpecOptions() + updso_allow_wildcards));
+ for (Resolver::ResolutionsByQPN_SConstIterator r(resolver->begin_resolutions_by_qpn_s()),
+ r_end(resolver->end_resolutions_by_qpn_s()) ;
+ r != r_end ; ++r)
+ {
+ if (! r->second->decision()->if_package_id())
+ {
+ /* really we want this to work for simple cat/pkg and
+ * cat/pkg:slot specs anyway, even if we chose nothing */
+ continue;
+ }
+
+ if (! match_package(*env, spec, *r->second->decision()->if_package_id(), MatchPackageOptions()))
+ continue;
+
+ any = true;
+
+ std::cout << "For " << r->first << ":" << std::endl;
+ std::cout << " The following constraints were in action:" << std::endl;
+ for (Constraints::ConstIterator c(r->second->constraints()->begin()),
+ c_end(r->second->constraints()->end()) ;
+ c != c_end ; ++c)
+ {
+ std::cout << " * " << (*c)->spec();
+
+ switch ((*c)->use_installed())
+ {
+ case ui_if_same:
+ std::cout << ", use installed if same";
+ break;
+ case ui_never:
+ std::cout << ", never using installed";
+ break;
+ case ui_only_if_transient:
+ std::cout << ", using installed only if transient";
+ break;
+ case ui_if_same_version:
+ std::cout << ", use installed if same version";
+ break;
+ case ui_if_possible:
+ std::cout << ", use installed if possible";
+ break;
+
+ case last_ui:
+ break;
+ }
+
+ if ((*c)->to_destination_slash())
+ std::cout << ", installing to /";
+
+ std::cout << std::endl;
+ std::cout << " because ";
+ ReasonDisplayer v;
+ (*c)->reason()->accept(v);
+ std::cout << std::endl;
+ }
+ std::cout << " The decision made was:" << std::endl;
+ std::cout << " Use " << *r->second->decision()->if_package_id() << std::endl;
+ if (r->second->destinations()->slash())
+ {
+ std::cout << " Install to / using repository " << r->second->destinations()->slash()->repository() << std::endl;
+ if (! r->second->destinations()->slash()->replacing()->empty())
+ for (PackageIDSequence::ConstIterator x(r->second->destinations()->slash()->replacing()->begin()),
+ x_end(r->second->destinations()->slash()->replacing()->end()) ;
+ x != x_end ; ++x)
+ std::cout << " Replacing " << **x << std::endl;
+ }
+ std::cout << std::endl;
+ }
+
+ if (! any)
+ throw args::DoHelp("There is nothing matching '" + *i + "' in the resolution set.");
+ }
+}
+
diff --git a/src/clients/cave/cmd_resolve_display_explanations.hh b/src/clients/cave/cmd_resolve_display_explanations.hh
new file mode 100644
index 0000000..0166f74
--- /dev/null
+++ b/src/clients/cave/cmd_resolve_display_explanations.hh
@@ -0,0 +1,38 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESOLVE_DISPLAY_EXPLANATIONS_HH
+#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESOLVE_DISPLAY_EXPLANATIONS_HH 1
+
+#include <paludis/environment-fwd.hh>
+#include <paludis/resolver/resolver-fwd.hh>
+#include "cmd_resolve_cmdline.hh"
+
+namespace paludis
+{
+ namespace cave
+ {
+ void display_explanations(
+ const std::tr1::shared_ptr<Environment> & env,
+ const std::tr1::shared_ptr<resolver::Resolver> & resolver,
+ const ResolveCommandLine & cmdline);
+ }
+}
+
+#endif
diff --git a/src/clients/cave/cmd_resolve_display_resolution.cc b/src/clients/cave/cmd_resolve_display_resolution.cc
new file mode 100644
index 0000000..fee954b
--- /dev/null
+++ b/src/clients/cave/cmd_resolve_display_resolution.cc
@@ -0,0 +1,258 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "cmd_resolve_display_resolution.hh"
+#include "colour_formatter.hh"
+#include "formats.hh"
+#include <paludis/resolver/resolver.hh>
+#include <paludis/resolver/resolution.hh>
+#include <paludis/resolver/decision.hh>
+#include <paludis/resolver/destinations.hh>
+#include <paludis/resolver/constraint.hh>
+#include <paludis/resolver/reason.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/simple_visitor_cast.hh>
+#include <paludis/util/join.hh>
+#include <paludis/util/iterator_funcs.hh>
+#include <paludis/package_id.hh>
+#include <paludis/version_spec.hh>
+#include <paludis/metadata_key.hh>
+#include <paludis/choice.hh>
+#include <iostream>
+#include <set>
+
+using namespace paludis;
+using namespace cave;
+using namespace paludis::resolver;
+
+namespace
+{
+ struct ReasonNameGetter
+ {
+ std::string visit(const DependencyReason & r) const
+ {
+ return stringify(r.from_id()->name());
+ }
+
+ std::string visit(const TargetReason &) const
+ {
+ return "target";
+ }
+
+ std::string visit(const SetReason & r) const
+ {
+ return r.reason_for_set()->accept_returning<std::string>(*this) +
+ " (" + stringify(r.set_name()) + ")";
+ }
+
+ std::string visit(const PresetReason &) const
+ {
+ return "";
+ }
+ };
+}
+
+void
+paludis::cave::display_resolution(
+ const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<Resolver> & resolver,
+ const ResolveCommandLine &)
+{
+ Context context("When displaying chosen resolution:");
+
+ std::cout << "These are the actions I will take, in order:" << std::endl << std::endl;
+
+ for (Resolver::ConstIterator c(resolver->begin()), c_end(resolver->end()) ;
+ c != c_end ; ++c)
+ {
+ const std::tr1::shared_ptr<const PackageID> id((*c)->decision()->if_package_id());
+ if (! id)
+ throw InternalError(PALUDIS_HERE, "why did that happen?");
+
+ bool is_new(false), is_upgrade(false), is_downgrade(false), is_reinstall(false);
+ std::tr1::shared_ptr<const PackageID> old_id;
+
+ if ((*c)->destinations()->slash())
+ {
+ if ((*c)->destinations()->slash()->replacing()->empty())
+ is_new = true;
+ else
+ for (PackageIDSequence::ConstIterator x((*c)->destinations()->slash()->replacing()->begin()),
+ x_end((*c)->destinations()->slash()->replacing()->end()) ;
+ x != x_end ; ++x)
+ {
+ old_id = *x;
+ if ((*x)->version() == id->version())
+ is_reinstall = true;
+ else if ((*x)->version() < id->version())
+ is_upgrade = true;
+ else if ((*x)->version() > id->version())
+ is_downgrade = true;
+ }
+
+ /* pick the worst of what it is */
+ is_upgrade = is_upgrade && (! is_reinstall) && (! is_downgrade);
+ is_reinstall = is_reinstall && (! is_downgrade);
+ }
+
+ if (is_new)
+ std::cout << "[n] " << c::bold_blue() << id->canonical_form(idcf_no_version);
+ else if (is_upgrade)
+ std::cout << "[u] " << c::blue() << id->canonical_form(idcf_no_version);
+ else if (is_reinstall)
+ std::cout << "[r] " << c::yellow() << id->canonical_form(idcf_no_version);
+ else if (is_downgrade)
+ std::cout << "[d] " << c::bold_yellow() << id->canonical_form(idcf_no_version);
+ else
+ throw InternalError(PALUDIS_HERE, "why did that happen?");
+
+ std::cout << c::normal() << " " << id->canonical_form(idcf_version);
+
+ if ((*c)->destinations()->slash())
+ {
+ std::cout << " to ::" << (*c)->destinations()->slash()->repository();
+ if (! (*c)->destinations()->slash()->replacing()->empty())
+ {
+ std::cout << " replacing";
+ for (PackageIDSequence::ConstIterator x((*c)->destinations()->slash()->replacing()->begin()),
+ x_end((*c)->destinations()->slash()->replacing()->end()) ;
+ x != x_end ; ++x)
+ std::cout << " " << (*x)->canonical_form(idcf_version);
+ }
+ }
+
+ std::cout << std::endl;
+
+ if (id->choices_key())
+ {
+ ColourFormatter formatter(0);
+
+ std::tr1::shared_ptr<const Choices> old_choices;
+ if (old_id && old_id->choices_key())
+ old_choices = old_id->choices_key()->value();
+
+ bool non_blank_prefix(false);
+ std::string s;
+ for (Choices::ConstIterator k(id->choices_key()->value()->begin()),
+ k_end(id->choices_key()->value()->end()) ;
+ k != k_end ; ++k)
+ {
+ if ((*k)->hidden())
+ continue;
+
+ bool shown_prefix(false);
+ for (Choice::ConstIterator i((*k)->begin()), i_end((*k)->end()) ;
+ i != i_end ; ++i)
+ {
+ if (! (*i)->explicitly_listed())
+ continue;
+
+ if (! shown_prefix)
+ {
+ if (non_blank_prefix || ! (*k)->show_with_no_prefix())
+ {
+ shown_prefix = true;
+ if (! s.empty())
+ s.append(" ");
+ s.append((*k)->raw_name() + ":");
+ }
+ }
+
+ if (! s.empty())
+ s.append(" ");
+
+ std::string t;
+ if ((*i)->enabled())
+ {
+ if ((*i)->locked())
+ t = formatter.format(**i, format::Forced());
+ else
+ t = formatter.format(**i, format::Enabled());
+ }
+ else
+ {
+ if ((*i)->locked())
+ t = formatter.format(**i, format::Masked());
+ else
+ t = formatter.format(**i, format::Disabled());
+ }
+
+ bool changed(false), added(false);
+ if ((*k)->consider_added_or_changed())
+ {
+ if (old_choices)
+ {
+ std::tr1::shared_ptr<const ChoiceValue> old_choice(
+ old_choices->find_by_name_with_prefix((*i)->name_with_prefix()));
+ if (! old_choice)
+ added = true;
+ else if (old_choice->enabled() != (*i)->enabled())
+ changed = true;
+ }
+ else
+ added = true;
+ }
+
+ if (changed)
+ {
+ t = formatter.decorate(**i, t, format::Changed());
+ }
+ else if (added)
+ {
+ if (old_id)
+ t = formatter.decorate(**i, t, format::Added());
+ }
+
+ s.append(t);
+ }
+ }
+
+ if (s.empty())
+ break;
+
+ std::cout << " " << s << std::endl;
+ }
+
+ if (id->short_description_key())
+ std::cout << " \"" << id->short_description_key()->value() << "\"" << std::endl;
+
+ std::set<std::string> reason_names;
+ for (Constraints::ConstIterator r((*c)->constraints()->begin()),
+ r_end((*c)->constraints()->end()) ;
+ r != r_end ; ++r)
+ {
+ ReasonNameGetter g;
+ std::string s((*r)->reason()->accept_returning<std::string>(g));
+ if (! s.empty())
+ reason_names.insert(s);
+ }
+
+ if (! reason_names.empty())
+ {
+ if (reason_names.size() > 4)
+ std::cout << " Because of " << join(reason_names.begin(), next(reason_names.begin(), 3), ", ")
+ << ", " << (reason_names.size() - 3) << " more" << std::endl;
+ else
+ std::cout << " Because of " << join(reason_names.begin(), reason_names.end(), ", ") << std::endl;
+ }
+ }
+
+ std::cout << std::endl;
+}
+
diff --git a/src/clients/cave/cmd_resolve_display_resolution.hh b/src/clients/cave/cmd_resolve_display_resolution.hh
new file mode 100644
index 0000000..ded734e
--- /dev/null
+++ b/src/clients/cave/cmd_resolve_display_resolution.hh
@@ -0,0 +1,38 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESOLVE_DISPLAY_RESOLUTION_HH
+#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESOLVE_DISPLAY_RESOLUTION_HH 1
+
+#include <paludis/environment-fwd.hh>
+#include <paludis/resolver/resolver-fwd.hh>
+#include "cmd_resolve_cmdline.hh"
+
+namespace paludis
+{
+ namespace cave
+ {
+ void display_resolution(
+ const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<resolver::Resolver> & resolver,
+ const ResolveCommandLine &);
+ }
+}
+
+#endif
diff --git a/src/clients/cave/cmd_resolve_dump.cc b/src/clients/cave/cmd_resolve_dump.cc
new file mode 100644
index 0000000..86ff75e
--- /dev/null
+++ b/src/clients/cave/cmd_resolve_dump.cc
@@ -0,0 +1,59 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "cmd_resolve_dump.hh"
+#include <paludis/resolver/resolver.hh>
+#include <paludis/resolver/qpn_s.hh>
+#include <paludis/resolver/sanitised_dependencies.hh>
+#include <paludis/resolver/resolution.hh>
+#include <iostream>
+
+using namespace paludis;
+using namespace cave;
+using namespace paludis::resolver;
+
+void
+paludis::cave::dump_if_requested(
+ const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<Resolver> & resolver,
+ const ResolveCommandLine & cmdline)
+{
+ Context context("When dumping the resolver:");
+
+ if (! cmdline.a_dump.specified())
+ return;
+
+ std::cout << "Dumping resolutions by QPN:S:" << std::endl << std::endl;
+
+ for (Resolver::ResolutionsByQPN_SConstIterator c(resolver->begin_resolutions_by_qpn_s()),
+ c_end(resolver->end_resolutions_by_qpn_s()) ;
+ c != c_end ; ++c)
+ {
+ std::cout << c->first << std::endl;
+ std::cout << " = " << *c->second << std::endl;
+ if (cmdline.a_dump_dependencies.specified())
+ for (SanitisedDependencies::ConstIterator d(c->second->sanitised_dependencies()->begin()),
+ d_end(c->second->sanitised_dependencies()->end()) ;
+ d != d_end ; ++d)
+ std::cout << " -> " << *d << std::endl;
+ }
+
+ std::cout << std::endl;
+}
+
diff --git a/src/clients/cave/cmd_resolve_dump.hh b/src/clients/cave/cmd_resolve_dump.hh
new file mode 100644
index 0000000..8e7b8db
--- /dev/null
+++ b/src/clients/cave/cmd_resolve_dump.hh
@@ -0,0 +1,38 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2009 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESOLVE_DUMP_HH
+#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_CMD_RESOLVE_DUMP_HH 1
+
+#include <paludis/environment-fwd.hh>
+#include <paludis/resolver/resolver-fwd.hh>
+#include "cmd_resolve_cmdline.hh"
+
+namespace paludis
+{
+ namespace cave
+ {
+ void dump_if_requested(
+ const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<resolver::Resolver> & resolver,
+ const ResolveCommandLine & cmdline);
+ }
+}
+
+#endif
diff --git a/src/clients/cave/colour_formatter.cc b/src/clients/cave/colour_formatter.cc
index 7b987e4..1e02a62 100644
--- a/src/clients/cave/colour_formatter.cc
+++ b/src/clients/cave/colour_formatter.cc
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2008 Ciaran McCreesh
+ * Copyright (c) 2008, 2009 Ciaran McCreesh
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
@@ -22,6 +22,7 @@
#include "format_general.hh"
#include <paludis/util/stringify.hh>
#include <paludis/name.hh>
+#include <paludis/choice.hh>
using namespace paludis;
using namespace cave;
@@ -32,6 +33,50 @@ ColourFormatter::ColourFormatter(const int initial_indent) :
}
std::string
+ColourFormatter::format(const paludis::ChoiceValue & s, const paludis::format::Plain &) const
+{
+ return format_general_s(f::colour_formatter_choice_value_plain(), stringify(s.name_with_prefix()));
+}
+
+std::string
+ColourFormatter::format(const paludis::ChoiceValue & s, const paludis::format::Enabled &) const
+{
+ return format_general_kv(f::colour_formatter_choice_value_enabled(),
+ stringify(s.unprefixed_name()), s.parameter().empty() ? "" : "=" + s.parameter());
+}
+
+std::string
+ColourFormatter::format(const paludis::ChoiceValue & s, const paludis::format::Disabled &) const
+{
+ return format_general_s(f::colour_formatter_choice_value_disabled(), stringify(s.unprefixed_name()));
+}
+
+std::string
+ColourFormatter::format(const paludis::ChoiceValue & s, const paludis::format::Forced &) const
+{
+ return format_general_kv(f::colour_formatter_choice_value_forced(),
+ stringify(s.unprefixed_name()), s.parameter().empty() ? "" : "=" + s.parameter());
+}
+
+std::string
+ColourFormatter::format(const paludis::ChoiceValue & s, const paludis::format::Masked &) const
+{
+ return format_general_s(f::colour_formatter_choice_value_masked(), stringify(s.unprefixed_name()));
+}
+
+std::string
+ColourFormatter::decorate(const paludis::ChoiceValue &, const std::string & f, const paludis::format::Added &) const
+{
+ return f + "+";
+}
+
+std::string
+ColourFormatter::decorate(const paludis::ChoiceValue &, const std::string & f, const paludis::format::Changed &) const
+{
+ return f + "*";
+}
+
+std::string
ColourFormatter::format(const KeywordName & s, const format::Plain &) const
{
return format_general_s(f::colour_formatter_keyword_name_plain(), stringify(s));
diff --git a/src/clients/cave/colour_formatter.hh b/src/clients/cave/colour_formatter.hh
index e4d638e..6c8ff90 100644
--- a/src/clients/cave/colour_formatter.hh
+++ b/src/clients/cave/colour_formatter.hh
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2008 Ciaran McCreesh
+ * Copyright (c) 2008, 2009 Ciaran McCreesh
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
@@ -42,6 +42,7 @@ namespace paludis
public CanFormat<BlockDepSpec>,
public CanFormat<NamedSetDepSpec>,
public CanFormat<PlainTextLabelDepSpec>,
+ public CanFormat<ChoiceValue>,
public CanSpace
{
private:
@@ -50,6 +51,14 @@ namespace paludis
public:
ColourFormatter(const int initial_indent);
+ std::string format(const paludis::ChoiceValue &, const paludis::format::Plain &) const;
+ std::string format(const paludis::ChoiceValue &, const paludis::format::Enabled &) const;
+ std::string format(const paludis::ChoiceValue &, const paludis::format::Disabled &) const;
+ std::string format(const paludis::ChoiceValue &, const paludis::format::Forced &) const;
+ std::string format(const paludis::ChoiceValue &, const paludis::format::Masked &) const;
+ std::string decorate(const paludis::ChoiceValue &, const std::string &, const paludis::format::Added &) const;
+ std::string decorate(const paludis::ChoiceValue &, const std::string &, const paludis::format::Changed &) const;
+
std::string format(const KeywordName &, const format::Plain &) const;
std::string format(const KeywordName &, const format::Accepted &) const;
std::string format(const KeywordName &, const format::Unaccepted &) const;
diff --git a/src/clients/cave/command_factory.cc b/src/clients/cave/command_factory.cc
index 1f2d9e1..c07df95 100644
--- a/src/clients/cave/command_factory.cc
+++ b/src/clients/cave/command_factory.cc
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2008 Ciaran McCreesh
+ * Copyright (c) 2008, 2009 Ciaran McCreesh
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
@@ -40,6 +40,7 @@
#include "cmd_print_repository_formats.hh"
#include "cmd_print_sets.hh"
#include "cmd_print_sync_protocols.hh"
+#include "cmd_resolve.hh"
#include "cmd_show.hh"
#include "cmd_sync.hh"
@@ -83,6 +84,7 @@ CommandFactory::CommandFactory() :
_imp->handlers.insert(std::make_pair("print-repository-formats", make_command<PrintRepositoryFormatsCommand>));
_imp->handlers.insert(std::make_pair("print-sets", make_command<PrintSetsCommand>));
_imp->handlers.insert(std::make_pair("print-sync-protocols", make_command<PrintSyncProtocolsCommand>));
+ _imp->handlers.insert(std::make_pair("resolve", make_command<ResolveCommand>));
_imp->handlers.insert(std::make_pair("show", make_command<ShowCommand>));
_imp->handlers.insert(std::make_pair("sync", make_command<SyncCommand>));
}
diff --git a/src/clients/cave/formats.cc b/src/clients/cave/formats.cc
index 52ed6be..6dcdb5a 100644
--- a/src/clients/cave/formats.cc
+++ b/src/clients/cave/formats.cc
@@ -59,6 +59,18 @@ paludis::cave::c::bold_red()
}
const std::string
+paludis::cave::c::yellow()
+{
+ return "\033[0;33m";
+}
+
+const std::string
+paludis::cave::c::bold_yellow()
+{
+ return "\033[1;33m";
+}
+
+const std::string
paludis::cave::c::normal()
{
return "\033[0;0m";
@@ -263,6 +275,36 @@ paludis::cave::f::colour_formatter_license_dep_spec_unaccepted()
}
const std::string
+paludis::cave::f::colour_formatter_choice_value_plain()
+{
+ return "%s";
+}
+
+const std::string
+paludis::cave::f::colour_formatter_choice_value_enabled()
+{
+ return c::green() + "%k" + c::normal() + "%v";
+}
+
+const std::string
+paludis::cave::f::colour_formatter_choice_value_disabled()
+{
+ return c::red() + "-%s" + c::normal();
+}
+
+const std::string
+paludis::cave::f::colour_formatter_choice_value_forced()
+{
+ return c::green() + "(%k%v)" + c::normal();
+}
+
+const std::string
+paludis::cave::f::colour_formatter_choice_value_masked()
+{
+ return c::red() + "(-%s)" + c::normal();
+}
+
+const std::string
paludis::cave::f::colour_formatter_conditional_dep_spec_plain()
{
return "%s";
diff --git a/src/clients/cave/formats.hh b/src/clients/cave/formats.hh
index f3869f1..23d59ce 100644
--- a/src/clients/cave/formats.hh
+++ b/src/clients/cave/formats.hh
@@ -34,6 +34,8 @@ namespace paludis
const std::string green();
const std::string bold_red();
const std::string red();
+ const std::string bold_yellow();
+ const std::string yellow();
const std::string bold_normal();
const std::string normal();
@@ -83,6 +85,12 @@ namespace paludis
const std::string colour_formatter_keyword_name_accepted();
const std::string colour_formatter_keyword_name_unaccepted();
+ const std::string colour_formatter_choice_value_plain();
+ const std::string colour_formatter_choice_value_enabled();
+ const std::string colour_formatter_choice_value_disabled();
+ const std::string colour_formatter_choice_value_forced();
+ const std::string colour_formatter_choice_value_masked();
+
const std::string colour_formatter_string_plain();
const std::string colour_formatter_package_id_plain();