242 lines
8.4 KiB
C++
242 lines
8.4 KiB
C++
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
|
|
|
|
/*
|
|
* Copyright (c) 2010, 2011, 2013 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/get_initial_constraints_for_helper.hh>
|
|
#include <paludis/resolver/reason.hh>
|
|
#include <paludis/resolver/constraint.hh>
|
|
#include <paludis/resolver/resolvent.hh>
|
|
#include <paludis/resolver/resolution.hh>
|
|
#include <paludis/resolver/decision.hh>
|
|
#include <paludis/resolver/destination_utils.hh>
|
|
#include <paludis/resolver/match_qpns.hh>
|
|
#include <paludis/resolver/suggest_restart.hh>
|
|
#include <paludis/util/pimp-impl.hh>
|
|
#include <paludis/util/make_shared_copy.hh>
|
|
#include <paludis/util/make_named_values.hh>
|
|
#include <paludis/util/stringify.hh>
|
|
#include <paludis/util/hashes.hh>
|
|
#include <paludis/util/timestamp.hh>
|
|
#include <paludis/util/enum_iterator.hh>
|
|
#include <paludis/dep_spec.hh>
|
|
#include <paludis/package_id.hh>
|
|
#include <paludis/selection.hh>
|
|
#include <paludis/generator.hh>
|
|
#include <paludis/filtered_generator.hh>
|
|
#include <paludis/filter.hh>
|
|
#include <paludis/environment.hh>
|
|
#include <paludis/metadata_key.hh>
|
|
#include <paludis/version_spec.hh>
|
|
#include <paludis/partially_made_package_dep_spec.hh>
|
|
#include <list>
|
|
#include <unordered_map>
|
|
|
|
using namespace paludis;
|
|
using namespace paludis::resolver;
|
|
|
|
typedef std::unordered_map<Resolvent, std::shared_ptr<Constraints>, Hash<Resolvent> > InitialConstraints;
|
|
|
|
namespace paludis
|
|
{
|
|
template <>
|
|
struct Imp<GetInitialConstraintsForHelper>
|
|
{
|
|
const Environment * const env;
|
|
|
|
std::list<PackageDepSpec> without_specs;
|
|
int reinstall_scm_days;
|
|
|
|
InitialConstraints initial_constraints;
|
|
|
|
Imp(const Environment * const e) :
|
|
env(e),
|
|
reinstall_scm_days(-1)
|
|
{
|
|
}
|
|
};
|
|
}
|
|
|
|
GetInitialConstraintsForHelper::GetInitialConstraintsForHelper(const Environment * const e) :
|
|
_imp(e)
|
|
{
|
|
}
|
|
|
|
GetInitialConstraintsForHelper::~GetInitialConstraintsForHelper() = default;
|
|
|
|
void
|
|
GetInitialConstraintsForHelper::add_without_spec(const PackageDepSpec & spec)
|
|
{
|
|
_imp->without_specs.push_back(spec);
|
|
}
|
|
|
|
void
|
|
GetInitialConstraintsForHelper::add_preset_spec(const PackageDepSpec & spec, const std::shared_ptr<const PackageID> & from_id)
|
|
{
|
|
Context context("When adding preset for '" + stringify(spec) + "':");
|
|
|
|
auto reason(std::make_shared<PresetReason>("preset", nullptr));
|
|
|
|
auto ids((*_imp->env)[selection::BestVersionInEachSlot(generator::Matches(spec, from_id, { }))]);
|
|
for (auto i(ids->begin()), i_end(ids->end()) ;
|
|
i != i_end ; ++i)
|
|
for (EnumIterator<DestinationType> t, t_end(last_dt) ; t != t_end ; ++t)
|
|
{
|
|
Resolvent r(*i, *t);
|
|
|
|
const std::shared_ptr<Constraint> constraint(std::make_shared<Constraint>(make_named_values<Constraint>(
|
|
n::destination_type() = r.destination_type(),
|
|
n::force_unable() = false,
|
|
n::from_id() = from_id,
|
|
n::nothing_is_fine_too() = true,
|
|
n::reason() = reason,
|
|
n::spec() = spec,
|
|
n::untaken() = false,
|
|
n::use_existing() = ue_if_possible
|
|
)));
|
|
auto ic(_imp->initial_constraints.find(r));
|
|
if (ic == _imp->initial_constraints.end())
|
|
ic = _imp->initial_constraints.insert(std::make_pair(r, _make_initial_constraints_for(r))).first;
|
|
|
|
ic->second->add(constraint);
|
|
}
|
|
}
|
|
|
|
void
|
|
GetInitialConstraintsForHelper::add_suggested_restart(const SuggestRestart & e)
|
|
{
|
|
auto ic(_imp->initial_constraints.find(e.resolvent()));
|
|
if (ic == _imp->initial_constraints.end())
|
|
ic = _imp->initial_constraints.insert(std::make_pair(e.resolvent(), _make_initial_constraints_for(e.resolvent()))).first;
|
|
|
|
ic->second->add(e.suggested_preset());
|
|
}
|
|
|
|
void
|
|
GetInitialConstraintsForHelper::set_reinstall_scm_days(const int d)
|
|
{
|
|
_imp->reinstall_scm_days = d;
|
|
}
|
|
|
|
const std::shared_ptr<Constraints>
|
|
GetInitialConstraintsForHelper::operator() (const Resolvent & resolvent) const
|
|
{
|
|
auto i(_imp->initial_constraints.find(resolvent));
|
|
if (i == _imp->initial_constraints.end())
|
|
return _make_initial_constraints_for(resolvent);
|
|
return i->second;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
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;
|
|
[[gnu::fallthrough]];
|
|
case 5:
|
|
if (0 == pkg.compare(pkg.length() - 5, 5, "-live"))
|
|
return true;
|
|
[[gnu::fallthrough]];
|
|
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::shared_ptr<const PackageID> & id, const int n)
|
|
{
|
|
if (id->version().is_scm() || is_scm_name(id->name()))
|
|
{
|
|
static Timestamp current_time(Timestamp::now()); /* static to avoid weirdness */
|
|
time_t installed_time(current_time.seconds());
|
|
if (id->installed_time_key())
|
|
installed_time = id->installed_time_key()->parse_value().seconds();
|
|
|
|
return (current_time.seconds() - installed_time) > (24 * 60 * 60 * n);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool installed_is_scm_older_than(const Environment * const env,
|
|
const Resolvent & r, const int n)
|
|
{
|
|
Context context("When working out whether '" + stringify(r) + "' has installed SCM packages:");
|
|
|
|
const std::shared_ptr<const PackageIDSequence> ids =
|
|
(*env)[selection::AllVersionsUnsorted(destination_filtered_generator(env, r.destination_type(), generator::Package(r.package())) |
|
|
make_slot_filter(r))];
|
|
|
|
for (const auto & package : *ids)
|
|
if (is_scm_older_than(package, n))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool use_existing_from_withish(const Environment * const env,
|
|
const QualifiedPackageName & name,
|
|
const std::list<PackageDepSpec> & list)
|
|
{
|
|
for (const auto & l : list)
|
|
if (match_qpns(*env, l, name))
|
|
return true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const std::shared_ptr<Constraints>
|
|
GetInitialConstraintsForHelper::_make_initial_constraints_for(const Resolvent & resolvent) const
|
|
{
|
|
auto result(std::make_shared<Constraints>());
|
|
|
|
if ((-1 != _imp->reinstall_scm_days) &&
|
|
installed_is_scm_older_than(_imp->env, resolvent, _imp->reinstall_scm_days) &&
|
|
! use_existing_from_withish(_imp->env, resolvent.package(), _imp->without_specs))
|
|
{
|
|
result->add(std::make_shared<Constraint>(make_named_values<Constraint>(
|
|
n::destination_type() = resolvent.destination_type(),
|
|
n::force_unable() = false,
|
|
n::from_id() = nullptr,
|
|
n::nothing_is_fine_too() = true,
|
|
n::reason() = std::make_shared<PresetReason>("is scm", nullptr),
|
|
n::spec() = make_package_dep_spec({ }).package(resolvent.package()),
|
|
n::untaken() = false,
|
|
n::use_existing() = ue_only_if_transient
|
|
)));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
namespace paludis
|
|
{
|
|
template class Pimp<GetInitialConstraintsForHelper>;
|
|
}
|