Exheredludis/paludis/resolver/sanitised_dependencies.cc
Saleem Abdulrasool 64ba7d5be8 modernize: use default method synthesis
Convert a number of destructors to default synthesized functions.  Try to
inline a few instances into the header.  It should be possible to inline all of
them, however, gcc seems to emit a number of warnings.  Furthermore, some of the
destructors are pure-virtualed, but provide an implementation.  Placing the
definition into the header causes ODR violations.
2016-08-06 11:58:04 -07:00

580 lines
23 KiB
C++

/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
* Copyright (c) 2009, 2010, 2011 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/resolution.hh>
#include <paludis/resolver/decider.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/util/indirect_iterator-impl.hh>
#include <paludis/util/wrapped_output_iterator-impl.hh>
#include <paludis/util/sequence-impl.hh>
#include <paludis/util/log.hh>
#include <paludis/util/map.hh>
#include <paludis/spec_tree.hh>
#include <paludis/slot_requirement.hh>
#include <paludis/metadata_key.hh>
#include <paludis/package_id.hh>
#include <paludis/elike_package_dep_spec.hh>
#include <paludis/serialise-impl.hh>
#include <paludis/environment.hh>
#include <paludis/repository.hh>
#include <algorithm>
#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 MakeAnyOfStringVisitor
{
const Environment * const env;
const std::shared_ptr<const PackageID> our_id;
std::string result;
const std::shared_ptr<const ChangedChoices> changed_choices;
void visit(const DependencySpecTree::NodeType<NamedSetDepSpec>::Type & s)
{
result.append(" " + stringify(*s.spec()));
}
void visit(const DependencySpecTree::NodeType<DependenciesLabelsDepSpec>::Type & s)
{
result.append(" " + stringify(*s.spec()));
}
void visit(const DependencySpecTree::NodeType<PackageDepSpec>::Type & s)
{
result.append(" " + stringify(*s.spec()));
}
void visit(const DependencySpecTree::NodeType<BlockDepSpec>::Type & s)
{
result.append(" " + stringify(*s.spec()));
}
void visit(const DependencySpecTree::NodeType<ConditionalDepSpec>::Type & node)
{
if (changed_choices ? node.spec()->condition_would_be_met_when(env, our_id, *changed_choices) : node.spec()->condition_met(env, our_id))
{
MakeAnyOfStringVisitor v{env, our_id, "", changed_choices};
std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(v));
result.append(" " + stringify(*node.spec()) + " (" + v.result + " )");
}
}
void visit(const DependencySpecTree::NodeType<AnyDepSpec>::Type & node)
{
MakeAnyOfStringVisitor v{env, our_id, "", changed_choices};
std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(v));
result.append(" || (" + v.result + " )");
}
void visit(const DependencySpecTree::NodeType<AllDepSpec>::Type & node)
{
MakeAnyOfStringVisitor v{env, our_id, "", changed_choices};
std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(v));
result.append(" (" + v.result + " )");
}
};
struct AnyDepSpecChildHandler
{
const Environment * const env;
const Decider & decider;
const std::shared_ptr<const Resolution> our_resolution;
const std::shared_ptr<const PackageID> our_id;
const std::shared_ptr<const ChangedChoices> changed_choices;
const std::function<std::shared_ptr<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 Environment * const e,
const Decider & r, const std::shared_ptr<const Resolution> & q,
const std::shared_ptr<const PackageID> & o,
const std::shared_ptr<const ChangedChoices> & c,
const std::function<std::shared_ptr<SanitisedDependency> (const PackageOrBlockDepSpec &)> & f) :
env(e),
decider(r),
our_resolution(q),
our_id(o),
changed_choices(c),
parent_make_sanitised(f),
super_complicated(false),
nested(false),
active_sublist(nullptr),
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.blocking().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 (changed_choices ? node.spec()->condition_would_be_met_when(env, our_id, *changed_choices) : node.spec()->condition_met(env, our_id))
{
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, nullptr);
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, nullptr);
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(env, decider, our_resolution, our_id, changed_choices, 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::bind(&list_push_back<SanitisedDependency>, &l, std::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, nullptr);
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<DependenciesLabelsDepSpec>::Type &)
{
super_complicated = true;
}
void commit(
const std::function<std::shared_ptr<SanitisedDependency> (const PackageOrBlockDepSpec &)> & maybe_make_sanitised,
const std::function<void (const SanitisedDependency &)> & apply)
{
if (! seen_any)
{
}
else if (super_complicated)
throw InternalError(PALUDIS_HERE, "Nested || ( ) dependencies too complicated to handle");
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());
std::pair<AnyChildScore, OperatorScore> best_score(acs_worse_than_worst, os_worse_than_worst);
for (std::list<std::list<PackageOrBlockDepSpec> >::const_iterator g(child_groups.begin()),
g_end(child_groups.end()) ;
g != g_end ; ++g)
{
/* best possible, to get ( ) right */
std::pair<AnyChildScore, OperatorScore> worst_score(acs_better_than_best, os_better_than_best);
/* score of a group is the score of the worst child. */
for (const auto & h : *g)
{
auto s(maybe_make_sanitised(PackageOrBlockDepSpec(h)));
if (s)
{
auto score(decider.find_any_score(our_resolution, our_id, *s));
Log::get_instance()->message("resolver.sanitised_dependencies.any_score", ll_debug, lc_context)
<< "Scored " << h << " as " << score.first << " " << score.second;
if (score < worst_score)
worst_score = score;
}
}
if (worst_score > best_score)
{
best_score = worst_score;
g_best = g;
}
}
if (g_best != child_groups.end())
{
/* might be nothing to do, if no labels are enabled */
for (const auto & h : *g_best)
{
auto s(maybe_make_sanitised(h));
if (s)
apply(*s);
}
}
}
}
};
struct Finder
{
const Environment * const env;
const Decider & decider;
const std::shared_ptr<const Resolution> our_resolution;
const std::shared_ptr<const PackageID> & our_id;
const std::shared_ptr<const ChangedChoices> & changed_choices;
SanitisedDependencies & sanitised_dependencies;
const std::string raw_name;
const std::string human_name;
std::string original_specs_as_string;
std::list<std::shared_ptr<const DependenciesLabelSequence> > labels_stack;
std::list<ConditionalDepSpec> conditions_stack;
Finder(
const Environment * const e,
const Decider & r,
const std::shared_ptr<const Resolution> & q,
const std::shared_ptr<const PackageID> & f,
const std::shared_ptr<const ChangedChoices> & c,
SanitisedDependencies & s,
const std::shared_ptr<const DependenciesLabelSequence> & l,
const std::string & rn,
const std::string & hn,
const std::string & a) :
env(e),
decider(r),
our_resolution(q),
our_id(f),
changed_choices(c),
sanitised_dependencies(s),
raw_name(rn),
human_name(hn),
original_specs_as_string(a)
{
labels_stack.push_front(l);
}
void add(const SanitisedDependency & dep)
{
sanitised_dependencies.add(dep);
}
std::shared_ptr<SanitisedDependency> maybe_make_sanitised(const PackageOrBlockDepSpec & spec)
{
std::stringstream adl, acs;
auto classifier_builder(std::make_shared<LabelsClassifierBuilder>(env, our_id));
for (DependenciesLabelSequence::ConstIterator i((*labels_stack.begin())->begin()),
i_end((*labels_stack.begin())->end()) ;
i != i_end ; ++i)
{
adl << (adl.str().empty() ? "" : ", ") << stringify(**i);
(*i)->accept(*classifier_builder);
}
auto classifier(classifier_builder->create());
if (classifier->any_enabled)
{
for (auto & c : conditions_stack)
acs << (acs.str().empty() ? "" : ", ") << stringify(c);
return make_shared_copy(make_named_values<SanitisedDependency>(
n::active_conditions_as_string() = acs.str(),
n::active_dependency_labels() = *labels_stack.begin(),
n::active_dependency_labels_as_string() = adl.str(),
n::active_dependency_labels_classifier() = classifier,
n::from_id() = our_id,
n::metadata_key_human_name() = human_name,
n::metadata_key_raw_name() = raw_name,
n::original_specs_as_string() = original_specs_as_string,
n::spec() = spec
));
}
else
return nullptr;
}
void visit(const DependencySpecTree::NodeType<PackageDepSpec>::Type & node)
{
auto s(maybe_make_sanitised(*node.spec()));
if (s)
add(*s);
}
void visit(const DependencySpecTree::NodeType<BlockDepSpec>::Type & node)
{
auto s(maybe_make_sanitised(*node.spec()));
if (s)
add(*s);
}
void visit(const DependencySpecTree::NodeType<ConditionalDepSpec>::Type & node)
{
if (changed_choices ? node.spec()->condition_would_be_met_when(env, our_id, *changed_choices) : node.spec()->condition_met(env, our_id))
{
conditions_stack.push_front(*node.spec());
labels_stack.push_front(*labels_stack.begin());
std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this));
labels_stack.pop_front();
conditions_stack.pop_front();
}
}
void visit(const DependencySpecTree::NodeType<AllDepSpec>::Type & node)
{
labels_stack.push_front(*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)
{
Save<std::string> save_original_specs_as_string(&original_specs_as_string);
{
MakeAnyOfStringVisitor v{env, our_id, "", changed_choices};
std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(v));
original_specs_as_string = "|| (" + v.result + " )";
}
AnyDepSpecChildHandler h(env, decider, our_resolution, our_id, changed_choices,
std::bind(&Finder::maybe_make_sanitised, this, std::placeholders::_1));
std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(h));
h.commit(
std::bind(&Finder::maybe_make_sanitised, this, std::placeholders::_1),
std::bind(&Finder::add, this, std::placeholders::_1)
);
}
void visit(const DependencySpecTree::NodeType<NamedSetDepSpec>::Type & node)
{
const std::shared_ptr<const SetSpecTree> set(env->set(node.spec()->name()));
if (set)
set->top()->accept(*this);
else
throw NoSuchSetError(stringify(node.spec()->name()));
}
void visit(const DependencySpecTree::NodeType<DependenciesLabelsDepSpec>::Type & node)
{
std::shared_ptr<DependenciesLabelSequence> labels(std::make_shared<DependenciesLabelSequence>());
std::copy(node.spec()->begin(), node.spec()->end(), labels->back_inserter());
*labels_stack.begin() = labels;
}
};
}
namespace paludis
{
template <>
struct Imp<SanitisedDependencies>
{
std::list<SanitisedDependency> sanitised_dependencies;
};
template <>
struct WrappedForwardIteratorTraits<SanitisedDependencies::ConstIteratorTag>
{
typedef std::list<SanitisedDependency>::const_iterator UnderlyingIterator;
};
}
SanitisedDependencies::SanitisedDependencies() :
_imp()
{
}
SanitisedDependencies::~SanitisedDependencies() = default;
void
SanitisedDependencies::_populate_one(
const Environment * const env,
const Decider & decider,
const std::shared_ptr<const Resolution> & resolution,
const std::shared_ptr<const PackageID> & id,
const std::shared_ptr<const ChangedChoices> & changed,
const std::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(env, decider, resolution, id, changed, *this, ((*id).*pmf)()->initial_labels(), ((*id).*pmf)()->raw_name(),
((*id).*pmf)()->human_name(), "");
((*id).*pmf)()->parse_value()->top()->accept(f);
}
void
SanitisedDependencies::populate(
const Environment * const env,
const Decider & decider,
const std::shared_ptr<const Resolution> & resolution,
const std::shared_ptr<const PackageID> & id,
const std::shared_ptr<const ChangedChoices> & changed)
{
Context context("When finding dependencies for '" + stringify(*id) + "':");
if (id->dependencies_key())
_populate_one(env, decider, resolution, id, changed, &PackageID::dependencies_key);
else
{
if (id->build_dependencies_key())
_populate_one(env, decider, resolution, id, changed, &PackageID::build_dependencies_key);
if (id->run_dependencies_key())
_populate_one(env, decider, resolution, id, changed, &PackageID::run_dependencies_key);
if (id->post_dependencies_key())
_populate_one(env, decider, resolution, id, changed, &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());
}
void
SanitisedDependency::serialise(Serialiser & s) const
{
s.object("SanitisedDependency")
.member(SerialiserFlags<>(), "active_conditions_as_string", active_conditions_as_string())
.member(SerialiserFlags<>(), "active_dependency_labels_as_string", active_dependency_labels_as_string())
.member(SerialiserFlags<serialise::might_be_null>(), "active_dependency_labels_classifier", active_dependency_labels_classifier())
.member(SerialiserFlags<serialise::might_be_null>(), "from_id", from_id())
.member(SerialiserFlags<>(), "metadata_key_human_name", metadata_key_human_name())
.member(SerialiserFlags<>(), "metadata_key_raw_name", metadata_key_raw_name())
.member(SerialiserFlags<>(), "original_specs_as_string", original_specs_as_string())
.member(SerialiserFlags<>(), "spec", spec())
;
}
SanitisedDependency
SanitisedDependency::deserialise(Deserialisation & d, const std::shared_ptr<const PackageID> & from_id)
{
Context context("When deserialising:");
Deserialisator v(d, "SanitisedDependency");
return make_named_values<SanitisedDependency>(
n::active_conditions_as_string() = v.member<std::string>("active_conditions_as_string"),
n::active_dependency_labels() = nullptr,
n::active_dependency_labels_as_string() = v.member<std::string>("active_dependency_labels_as_string"),
n::active_dependency_labels_classifier() = v.member<std::shared_ptr<const LabelsClassifier> >("active_dependency_labels_classifier"),
n::from_id() = v.member<std::shared_ptr<const PackageID> >("from_id"),
n::metadata_key_human_name() = v.member<std::string>("metadata_key_human_name"),
n::metadata_key_raw_name() = v.member<std::string>("metadata_key_raw_name"),
n::original_specs_as_string() = v.member<std::string>("original_specs_as_string"),
n::spec() = PackageOrBlockDepSpec::deserialise(*v.find_remove_member("spec"),
from_id)
);
}
namespace paludis
{
template class WrappedForwardIterator<SanitisedDependencies::ConstIteratorTag, const SanitisedDependency>;
}