aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2009-10-28 20:22:31 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2009-10-28 20:22:31 +0000
commit932596077ee44f41f3c095509b56c6ea9860d7dc (patch)
tree959278f2a3db8c3e58f19274efe8d4b760d1dda0
parentab78efe8b9fc9f7be998e9b7c0cc117d94808280 (diff)
downloadpaludis-932596077ee44f41f3c095509b56c6ea9860d7dc.tar.gz
paludis-932596077ee44f41f3c095509b56c6ea9860d7dc.tar.xz
Also rewrite targets.
-rw-r--r--paludis/resolver/Makefile.am2
-rw-r--r--paludis/resolver/resolver.cc126
-rw-r--r--paludis/resolver/resolver.hh7
-rw-r--r--paludis/resolver/resolver_TEST_virtuals.cc32
-rwxr-xr-xpaludis/resolver/resolver_TEST_virtuals_setup.sh9
-rw-r--r--paludis/resolver/sanitised_dependencies.cc12
-rw-r--r--paludis/resolver/spec_rewriter-fwd.hh32
-rw-r--r--paludis/resolver/spec_rewriter.cc181
-rw-r--r--paludis/resolver/spec_rewriter.hh71
9 files changed, 372 insertions, 100 deletions
diff --git a/paludis/resolver/Makefile.am b/paludis/resolver/Makefile.am
index 607cce7..6213ac5 100644
--- a/paludis/resolver/Makefile.am
+++ b/paludis/resolver/Makefile.am
@@ -25,6 +25,7 @@ noinst_HEADERS = \
resolver.hh resolver-fwd.hh \
resolver_functions.hh resolver_functions-fwd.hh \
sanitised_dependencies.hh sanitised_dependencies-fwd.hh \
+ spec_rewriter.hh spec_rewriter-fwd.hh \
suggest_restart.hh suggest_restart-fwd.hh \
unsuitable_candidates.hh unsuitable_candidates-fwd.hh \
use_existing.hh use_existing-fwd.hh use_existing-se.hh
@@ -41,6 +42,7 @@ libpaludisresolver_a_SOURCES = \
resolvent.cc \
resolver.cc \
sanitised_dependencies.cc \
+ spec_rewriter.cc \
suggest_restart.cc \
unsuitable_candidates.cc \
use_existing.cc
diff --git a/paludis/resolver/resolver.cc b/paludis/resolver/resolver.cc
index ad74f1e..7783a65 100644
--- a/paludis/resolver/resolver.cc
+++ b/paludis/resolver/resolver.cc
@@ -30,6 +30,7 @@
#include <paludis/resolver/resolutions.hh>
#include <paludis/resolver/destination.hh>
#include <paludis/resolver/unsuitable_candidates.hh>
+#include <paludis/resolver/spec_rewriter.hh>
#include <paludis/util/stringify.hh>
#include <paludis/util/make_named_values.hh>
#include <paludis/util/log.hh>
@@ -68,7 +69,6 @@ using namespace paludis;
using namespace paludis::resolver;
typedef std::map<Resolvent, std::tr1::shared_ptr<Resolution> > ResolutionsByResolventMap;
-typedef std::map<QualifiedPackageName, std::set<QualifiedPackageName> > Rewrites;
namespace paludis
{
@@ -77,19 +77,16 @@ namespace paludis
{
const Environment * const env;
const ResolverFunctions fns;
+ SpecRewriter rewriter;
ResolutionsByResolventMap resolutions_by_resolvent;
- mutable Mutex rewrites_mutex;
- mutable Rewrites rewrites;
- mutable bool has_rewrites;
-
std::tr1::shared_ptr<ResolutionLists> resolution_lists;
Implementation(const Environment * const e, const ResolverFunctions & f) :
env(e),
fns(f),
- has_rewrites(false),
+ rewriter(env),
resolution_lists(new ResolutionLists(make_named_values<ResolutionLists>(
value_for<n::all>(new Resolutions),
value_for<n::errors>(new Resolutions),
@@ -303,22 +300,35 @@ Resolver::add_target_with_reason(const PackageDepSpec & spec, const std::tr1::sh
_imp->env->trigger_notifier_callback(NotifierCallbackResolverStepEvent());
- std::tr1::shared_ptr<const Resolvents> resolvents(_get_resolvents_for(spec, reason));
- if (resolvents->empty())
- resolvents = _get_error_resolvents_for(spec, reason);
-
- for (Resolvents::ConstIterator r(resolvents->begin()), r_end(resolvents->end()) ;
- r != r_end ; ++r)
+ const std::tr1::shared_ptr<const RewrittenSpec> if_rewritten(rewrite_if_special(spec, make_null_shared_ptr()));
+ if (if_rewritten)
{
- Context context_2("When adding constraints from target '" + stringify(spec) + "' to resolvent '"
- + stringify(*r) + "':");
+ for (Sequence<PackageOrBlockDepSpec>::ConstIterator i(if_rewritten->specs()->begin()), i_end(if_rewritten->specs()->end()) ;
+ i != i_end ; ++i)
+ if (i->if_package())
+ add_target_with_reason(*i->if_package(), reason);
+ else
+ throw InternalError(PALUDIS_HERE, "resolver bug: rewritten " + stringify(spec) + " includes " + stringify(*i));
+ }
+ else
+ {
+ std::tr1::shared_ptr<const Resolvents> resolvents(_get_resolvents_for(spec, reason));
+ if (resolvents->empty())
+ resolvents = _get_error_resolvents_for(spec, reason);
- const std::tr1::shared_ptr<Resolution> dep_resolution(_resolution_for_resolvent(*r, true));
- const std::tr1::shared_ptr<ConstraintSequence> constraints(_make_constraints_from_target(*r, spec, reason));
+ for (Resolvents::ConstIterator r(resolvents->begin()), r_end(resolvents->end()) ;
+ r != r_end ; ++r)
+ {
+ Context context_2("When adding constraints from target '" + stringify(spec) + "' to resolvent '"
+ + stringify(*r) + "':");
- for (ConstraintSequence::ConstIterator c(constraints->begin()), c_end(constraints->end()) ;
- c != c_end ; ++c)
- _apply_resolution_constraint(*r, dep_resolution, *c);
+ const std::tr1::shared_ptr<Resolution> dep_resolution(_resolution_for_resolvent(*r, true));
+ const std::tr1::shared_ptr<ConstraintSequence> constraints(_make_constraints_from_target(*r, spec, reason));
+
+ for (ConstraintSequence::ConstIterator c(constraints->begin()), c_end(constraints->end()) ;
+ c != c_end ; ++c)
+ _apply_resolution_constraint(*r, dep_resolution, *c);
+ }
}
}
@@ -1737,58 +1747,6 @@ Resolver::resolution_lists() const
return _imp->resolution_lists;
}
-const std::tr1::shared_ptr<DependencySpecTree>
-Resolver::rewrite_if_special(const PackageOrBlockDepSpec & s, const Resolvent & our_resolvent) const
-{
- if (s.if_package() && s.if_package()->package_ptr())
- {
- if (s.if_package()->package_ptr()->category() != CategoryNamePart("virtual"))
- return make_null_shared_ptr();
- _need_rewrites();
-
- Rewrites::const_iterator r(_imp->rewrites.find(*s.if_package()->package_ptr()));
- if (r == _imp->rewrites.end())
- return make_null_shared_ptr();
-
- std::tr1::shared_ptr<DependencySpecTree> result(new DependencySpecTree(make_shared_ptr(new AllDepSpec)));
- std::tr1::shared_ptr<DependencySpecTree::NodeType<AnyDepSpec>::Type> any(result->root()->append(make_shared_ptr(new AnyDepSpec)));
- for (std::set<QualifiedPackageName>::const_iterator n(r->second.begin()), n_end(r->second.end()) ;
- n != n_end ; ++n)
- any->append(make_shared_ptr(new PackageDepSpec(PartiallyMadePackageDepSpec(*s.if_package()).package(*n))));
-
- return result;
- }
- else if (s.if_block() && s.if_block()->blocking().package_ptr())
- {
- if (s.if_block()->blocking().package_ptr()->category() != CategoryNamePart("virtual"))
- return make_null_shared_ptr();
- _need_rewrites();
-
- Rewrites::const_iterator r(_imp->rewrites.find(*s.if_block()->blocking().package_ptr()));
- if (r == _imp->rewrites.end())
- return make_null_shared_ptr();
-
- std::tr1::shared_ptr<DependencySpecTree> result(new DependencySpecTree(make_shared_ptr(new AllDepSpec)));
- for (std::set<QualifiedPackageName>::const_iterator n(r->second.begin()), n_end(r->second.end()) ;
- n != n_end ; ++n)
- {
- if (*n == our_resolvent.package())
- continue;
-
- PackageDepSpec spec(PartiallyMadePackageDepSpec(s.if_block()->blocking()).package(*n));
- std::string prefix(s.if_block()->blocking().text());
- std::string::size_type p(prefix.find_first_not_of('!'));
- if (std::string::npos != p)
- prefix.erase(p);
- result->root()->append(make_shared_ptr(new BlockDepSpec(prefix + stringify(spec), spec, s.if_block()->strong())));
- }
-
- return result;
- }
- else
- return make_null_shared_ptr();
-}
-
const std::tr1::shared_ptr<const Constraints>
Resolver::_get_unmatching_constraints(
const Resolvent & resolvent,
@@ -1813,28 +1771,12 @@ Resolver::_get_unmatching_constraints(
return result;
}
-void
-Resolver::_need_rewrites() const
+const std::tr1::shared_ptr<const RewrittenSpec>
+Resolver::rewrite_if_special(
+ const PackageOrBlockDepSpec & spec,
+ const std::tr1::shared_ptr<const Resolvent> & maybe_from) const
{
-#ifdef ENABLE_VIRTUALS_REPOSITORY
- Lock lock(_imp->rewrites_mutex);
- if (_imp->has_rewrites)
- return;
- _imp->has_rewrites = true;
-
- const std::tr1::shared_ptr<const PackageIDSequence> ids((*_imp->env)[selection::AllVersionsSorted(
- generator::InRepository(RepositoryName("virtuals")) +
- generator::InRepository(RepositoryName("installed-virtuals"))
- )]);
- for (PackageIDSequence::ConstIterator i(ids->begin()), i_end(ids->end()) ;
- i != i_end ; ++i)
- {
- if (! ((*i)->virtual_for_key()))
- throw InternalError(PALUDIS_HERE, "huh? " + stringify(**i) + " has no virtual_for_key");
- _imp->rewrites.insert(std::make_pair((*i)->name(), std::set<QualifiedPackageName>())).first->second.insert(
- (*i)->virtual_for_key()->value()->name());
- }
-#endif
+ return _imp->rewriter.rewrite_if_special(spec, maybe_from);
}
template class WrappedForwardIterator<Resolver::ResolutionsByResolventConstIteratorTag,
diff --git a/paludis/resolver/resolver.hh b/paludis/resolver/resolver.hh
index 54f71d5..861b54c 100644
--- a/paludis/resolver/resolver.hh
+++ b/paludis/resolver/resolver.hh
@@ -33,6 +33,7 @@
#include <paludis/resolver/destination_types-fwd.hh>
#include <paludis/resolver/destination-fwd.hh>
#include <paludis/resolver/unsuitable_candidates-fwd.hh>
+#include <paludis/resolver/spec_rewriter-fwd.hh>
#include <paludis/util/private_implementation_pattern.hh>
#include <paludis/util/wrapped_forward_iterator-fwd.hh>
#include <paludis/package_id-fwd.hh>
@@ -189,8 +190,6 @@ namespace paludis
const std::tr1::shared_ptr<const Resolution> &,
const std::tr1::shared_ptr<const PackageID> &) const;
- void _need_rewrites() const;
-
public:
Resolver(
const Environment * const,
@@ -216,8 +215,8 @@ namespace paludis
int find_any_score(const Resolvent &, const SanitisedDependency &) const;
- const std::tr1::shared_ptr<DependencySpecTree> rewrite_if_special(const PackageOrBlockDepSpec &,
- const Resolvent & from) const;
+ const std::tr1::shared_ptr<const RewrittenSpec> rewrite_if_special(const PackageOrBlockDepSpec &,
+ const std::tr1::shared_ptr<const Resolvent> & maybe_from) const;
};
}
}
diff --git a/paludis/resolver/resolver_TEST_virtuals.cc b/paludis/resolver/resolver_TEST_virtuals.cc
index 3bd4ae6..a50aa5e 100644
--- a/paludis/resolver/resolver_TEST_virtuals.cc
+++ b/paludis/resolver/resolver_TEST_virtuals.cc
@@ -97,5 +97,37 @@ namespace test_cases
}
}
} test_virtuals;
+
+ struct TestVirtualsTarget : ResolverVirtualsTestCase
+ {
+ TestVirtualsTarget() : ResolverVirtualsTestCase("virtuals target") { }
+
+ void run()
+ {
+ std::tr1::shared_ptr<const ResolutionLists> resolutions(get_resolutions("virtual/virtual-target"));
+
+ {
+ TestMessageSuffix s("errors");
+ check_resolution_list(resolutions->errors(), ResolutionListChecks()
+ .finished()
+ );
+ }
+
+ {
+ TestMessageSuffix s("ordered");
+ check_resolution_list(resolutions->ordered(), ResolutionListChecks()
+ .qpn(QualifiedPackageName("cat/real-target"))
+ .finished()
+ );
+ }
+
+ {
+ TestMessageSuffix s("untaken");
+ check_resolution_list(resolutions->untaken(), ResolutionListChecks()
+ .finished()
+ );
+ }
+ }
+ } test_virtuals_target;
}
diff --git a/paludis/resolver/resolver_TEST_virtuals_setup.sh b/paludis/resolver/resolver_TEST_virtuals_setup.sh
index c177de3..cffe73b 100755
--- a/paludis/resolver/resolver_TEST_virtuals_setup.sh
+++ b/paludis/resolver/resolver_TEST_virtuals_setup.sh
@@ -18,12 +18,21 @@ ARCH=test
END
cat <<'END' > profiles/profile/virtuals
virtual/foo cat/foo-a
+virtual/virtual-target cat/real-target
END
# common providers
echo 'cat' >> profiles/categories
+mkdir -p 'cat/real-target'
+cat <<END > cat/real-target/real-target-1.ebuild
+DESCRIPTION="dep"
+KEYWORDS="test"
+SLOT="0"
+PROVIDE="virtual/virtual-target"
+END
+
mkdir -p 'cat/foo-a'
cat <<END > cat/foo-a/foo-a-1.ebuild
DESCRIPTION="dep"
diff --git a/paludis/resolver/sanitised_dependencies.cc b/paludis/resolver/sanitised_dependencies.cc
index ef6d0c5..f648581 100644
--- a/paludis/resolver/sanitised_dependencies.cc
+++ b/paludis/resolver/sanitised_dependencies.cc
@@ -20,12 +20,14 @@
#include <paludis/resolver/sanitised_dependencies.hh>
#include <paludis/resolver/resolver.hh>
#include <paludis/resolver/resolvent.hh>
+#include <paludis/resolver/spec_rewriter.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/util/make_shared_copy.hh>
#include <paludis/spec_tree.hh>
#include <paludis/slot_requirement.hh>
#include <paludis/metadata_key.hh>
@@ -124,9 +126,10 @@ namespace
{
seen_any = true;
- std::tr1::shared_ptr<DependencySpecTree> if_rewritten(resolver.rewrite_if_special(spec, our_resolvent));
+ const std::tr1::shared_ptr<const RewrittenSpec> if_rewritten(resolver.rewrite_if_special(spec,
+ make_shared_copy(our_resolvent)));
if (if_rewritten)
- if_rewritten->root()->accept(*this);
+ if_rewritten->as_spec_tree()->root()->accept(*this);
else
{
if (active_sublist)
@@ -313,9 +316,10 @@ namespace
void add(const SanitisedDependency & dep)
{
- std::tr1::shared_ptr<DependencySpecTree> if_rewritten(resolver.rewrite_if_special(dep.spec(), our_resolvent));
+ const std::tr1::shared_ptr<const RewrittenSpec> if_rewritten(resolver.rewrite_if_special(dep.spec(),
+ make_shared_copy(our_resolvent)));
if (if_rewritten)
- if_rewritten->root()->accept(*this);
+ if_rewritten->as_spec_tree()->root()->accept(*this);
else
sanitised_dependencies.add(dep);
}
diff --git a/paludis/resolver/spec_rewriter-fwd.hh b/paludis/resolver/spec_rewriter-fwd.hh
new file mode 100644
index 0000000..87cb30c
--- /dev/null
+++ b/paludis/resolver/spec_rewriter-fwd.hh
@@ -0,0 +1,32 @@
+/* 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_SPEC_REWRITER_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_SPEC_REWRITER_FWD_HH 1
+
+namespace paludis
+{
+ namespace resolver
+ {
+ struct SpecRewriter;
+ struct RewrittenSpec;
+ }
+}
+
+#endif
diff --git a/paludis/resolver/spec_rewriter.cc b/paludis/resolver/spec_rewriter.cc
new file mode 100644
index 0000000..775c5c7
--- /dev/null
+++ b/paludis/resolver/spec_rewriter.cc
@@ -0,0 +1,181 @@
+/* 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/spec_rewriter.hh>
+#include <paludis/resolver/sanitised_dependencies.hh>
+#include <paludis/resolver/resolvent.hh>
+#include <paludis/util/type_list.hh>
+#include <paludis/util/make_shared_copy.hh>
+#include <paludis/util/make_named_values.hh>
+#include <paludis/util/mutex.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <paludis/spec_tree.hh>
+#include <paludis/dep_spec.hh>
+#include <paludis/environment.hh>
+#include <paludis/selection.hh>
+#include <paludis/generator.hh>
+#include <paludis/filtered_generator.hh>
+#include <paludis/filter.hh>
+#include <paludis/package_id.hh>
+#include <paludis/metadata_key.hh>
+#include <map>
+#include <set>
+
+#include "config.h"
+
+using namespace paludis;
+using namespace paludis::resolver;
+
+typedef std::map<QualifiedPackageName, std::set<QualifiedPackageName> > Rewrites;
+
+const std::tr1::shared_ptr<const DependencySpecTree>
+RewrittenSpec::as_spec_tree() const
+{
+ const std::tr1::shared_ptr<DependencySpecTree> result(new DependencySpecTree(make_shared_ptr(new AllDepSpec)));
+
+ for (Sequence<PackageOrBlockDepSpec>::ConstIterator i(specs()->begin()), i_end(specs()->end()) ;
+ i != i_end ; ++i)
+ if (i->if_package())
+ result->root()->append(i->if_package());
+ else
+ result->root()->append(i->if_block());
+
+ return result;
+}
+
+namespace paludis
+{
+ template <>
+ struct Implementation<SpecRewriter>
+ {
+ const Environment * const env;
+
+ mutable Mutex rewrites_mutex;
+ mutable Rewrites rewrites;
+ mutable bool has_rewrites;
+
+ Implementation(const Environment * const e) :
+ env(e),
+ has_rewrites(false)
+ {
+ }
+ };
+}
+
+SpecRewriter::SpecRewriter(const Environment * const e) :
+ PrivateImplementationPattern<SpecRewriter>(new Implementation<SpecRewriter>(e))
+{
+}
+
+#ifdef PALUDIS_HAVE_DEFAULT_DELETED
+
+SpecRewriter::~SpecRewriter() = default;
+
+#else
+
+SpecRewriter::~SpecRewriter()
+{
+}
+
+#endif
+
+const std::tr1::shared_ptr<const RewrittenSpec>
+SpecRewriter::rewrite_if_special(const PackageOrBlockDepSpec & s, const std::tr1::shared_ptr<const Resolvent> & maybe_our_resolvent) const
+{
+ if (s.if_package() && s.if_package()->package_ptr())
+ {
+ if (s.if_package()->package_ptr()->category() != CategoryNamePart("virtual"))
+ return make_null_shared_ptr();
+ _need_rewrites();
+
+ Rewrites::const_iterator r(_imp->rewrites.find(*s.if_package()->package_ptr()));
+ if (r == _imp->rewrites.end())
+ return make_null_shared_ptr();
+
+ const std::tr1::shared_ptr<RewrittenSpec> result(new RewrittenSpec(make_named_values<RewrittenSpec>(
+ value_for<n::specs>(make_shared_ptr(new Sequence<PackageOrBlockDepSpec>))
+ )));
+
+ for (std::set<QualifiedPackageName>::const_iterator n(r->second.begin()), n_end(r->second.end()) ;
+ n != n_end ; ++n)
+ result->specs()->push_back(PackageOrBlockDepSpec(PartiallyMadePackageDepSpec(*s.if_package()).package(*n)));
+
+ return result;
+ }
+ else if (s.if_block() && s.if_block()->blocking().package_ptr())
+ {
+ if (s.if_block()->blocking().package_ptr()->category() != CategoryNamePart("virtual"))
+ return make_null_shared_ptr();
+ _need_rewrites();
+
+ Rewrites::const_iterator r(_imp->rewrites.find(*s.if_block()->blocking().package_ptr()));
+ if (r == _imp->rewrites.end())
+ return make_null_shared_ptr();
+
+ const std::tr1::shared_ptr<RewrittenSpec> result(new RewrittenSpec(make_named_values<RewrittenSpec>(
+ value_for<n::specs>(make_shared_ptr(new Sequence<PackageOrBlockDepSpec>))
+ )));
+
+ for (std::set<QualifiedPackageName>::const_iterator n(r->second.begin()), n_end(r->second.end()) ;
+ n != n_end ; ++n)
+ {
+ if (maybe_our_resolvent && (*n == maybe_our_resolvent->package()))
+ continue;
+
+ PackageDepSpec spec(PartiallyMadePackageDepSpec(s.if_block()->blocking()).package(*n));
+ std::string prefix(s.if_block()->blocking().text());
+ std::string::size_type p(prefix.find_first_not_of('!'));
+ if (std::string::npos != p)
+ prefix.erase(p);
+ result->specs()->push_back(BlockDepSpec(prefix + stringify(spec), spec, s.if_block()->strong()));
+ }
+
+ return result;
+ }
+ else
+ return make_null_shared_ptr();
+}
+
+void
+SpecRewriter::_need_rewrites() const
+{
+#ifdef ENABLE_VIRTUALS_REPOSITORY
+ Lock lock(_imp->rewrites_mutex);
+ if (_imp->has_rewrites)
+ return;
+ _imp->has_rewrites = true;
+
+ const std::tr1::shared_ptr<const PackageIDSequence> ids((*_imp->env)[selection::AllVersionsSorted(
+ generator::InRepository(RepositoryName("virtuals")) +
+ generator::InRepository(RepositoryName("installed-virtuals"))
+ )]);
+ for (PackageIDSequence::ConstIterator i(ids->begin()), i_end(ids->end()) ;
+ i != i_end ; ++i)
+ {
+ if (! ((*i)->virtual_for_key()))
+ throw InternalError(PALUDIS_HERE, "huh? " + stringify(**i) + " has no virtual_for_key");
+ _imp->rewrites.insert(std::make_pair((*i)->name(), std::set<QualifiedPackageName>())).first->second.insert(
+ (*i)->virtual_for_key()->value()->name());
+ }
+#endif
+}
+
+template class PrivateImplementationPattern<resolver::SpecRewriter>;
+
diff --git a/paludis/resolver/spec_rewriter.hh b/paludis/resolver/spec_rewriter.hh
new file mode 100644
index 0000000..7f5fdab
--- /dev/null
+++ b/paludis/resolver/spec_rewriter.hh
@@ -0,0 +1,71 @@
+/* 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_SPEC_REWRITER_HH
+#define PALUDIS_GUARD_PALUDIS_RESOLVER_SPEC_REWRITER_HH 1
+
+#include <paludis/resolver/spec_rewriter-fwd.hh>
+#include <paludis/resolver/sanitised_dependencies-fwd.hh>
+#include <paludis/resolver/resolvent-fwd.hh>
+#include <paludis/util/attributes.hh>
+#include <paludis/util/named_value.hh>
+#include <paludis/util/sequence-fwd.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/dep_spec-fwd.hh>
+#include <paludis/environment-fwd.hh>
+#include <paludis/spec_tree-fwd.hh>
+
+namespace paludis
+{
+ namespace n
+ {
+ struct specs;
+ }
+
+ namespace resolver
+ {
+ struct RewrittenSpec
+ {
+ NamedValue<n::specs, std::tr1::shared_ptr<Sequence<PackageOrBlockDepSpec> > > specs;
+
+ const std::tr1::shared_ptr<const DependencySpecTree> as_spec_tree() const PALUDIS_ATTRIBUTE((warn_unused_result));
+ };
+
+ class PALUDIS_VISIBLE SpecRewriter :
+ private PrivateImplementationPattern<SpecRewriter>
+ {
+ private:
+ void _need_rewrites() const;
+
+ public:
+ SpecRewriter(const Environment * const);
+ ~SpecRewriter();
+
+ const std::tr1::shared_ptr<const RewrittenSpec> rewrite_if_special(const PackageOrBlockDepSpec &,
+ const std::tr1::shared_ptr<const Resolvent> & maybe_from) const PALUDIS_ATTRIBUTE((warn_unused_result));
+ };
+ }
+
+#ifdef PALUDIS_HAVE_EXTERN_TEMPLATE
+ extern template class PrivateImplementationPattern<resolver::SpecRewriter>;
+#endif
+
+}
+
+#endif