Exheredludis/paludis/elike_use_requirement.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

980 lines
42 KiB
C++

/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
* Copyright (c) 2008, 2009, 2010, 2011, 2012 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/elike_use_requirement.hh>
#include <paludis/util/options.hh>
#include <paludis/util/stringify.hh>
#include <paludis/util/join.hh>
#include <paludis/util/tokeniser.hh>
#include <paludis/util/log.hh>
#include <paludis/util/wrapped_forward_iterator.hh>
#include <paludis/util/tribool.hh>
#include <paludis/dep_spec.hh>
#include <paludis/name.hh>
#include <paludis/environment.hh>
#include <paludis/package_id.hh>
#include <paludis/metadata_key.hh>
#include <paludis/choice.hh>
#include <paludis/changed_choices.hh>
#include <paludis/additional_package_dep_spec_requirement.hh>
#include <vector>
#include <functional>
#include <algorithm>
using namespace paludis;
namespace
{
bool icky_use_query(
const ELikeUseRequirementOptions & options,
const ChoiceNameWithPrefix & f,
const std::shared_ptr<const PackageID> & id,
const ChangedChoices * const changed_choices,
Tribool default_value = Tribool(indeterminate))
{
if (! id->choices_key())
{
Log::get_instance()->message("elike_use_requirement.query", ll_warning, lc_context) <<
"ID '" << *id << "' has no choices, so couldn't get the state of flag '" << f << "'";
return false;
}
if (changed_choices)
{
auto c(changed_choices->overridden_value(f));
if (! c.is_indeterminate())
return c.is_true();
}
auto choices(id->choices_key()->parse_value());
auto v(choices->find_by_name_with_prefix(f));
if (v)
{
if (co_special == v->origin())
Log::get_instance()->message("elike_use_requirement.query", ll_warning, lc_context) <<
"ID '" << *id << "' flag '" << f << "' should not be used as a conditional";
return v->enabled();
}
if (default_value.is_indeterminate() && ! choices->has_matching_contains_every_value_prefix(f) && options[euro_missing_is_qa])
Log::get_instance()->message("elike_use_requirement.query", ll_qa, lc_context) <<
"ID '" << *id << "' has no flag named '" << f << "'";
return default_value.is_true();
}
class UseRequirement
{
private:
const std::string _flags;
const Tribool _default_value;
const bool _ignore_if_no_such_group;
protected:
const ELikeUseRequirementOptions _options;
public:
UseRequirement(const std::string & n,
const ELikeUseRequirementOptions & o, Tribool d, const bool g) :
_flags(n),
_default_value(d),
_ignore_if_no_such_group(g),
_options(o)
{
}
virtual ~UseRequirement() = default;
virtual bool one_requirement_met_base(
const Environment * const,
const ChoiceNameWithPrefix &,
const ChangedChoices * const,
const std::shared_ptr<const PackageID> &,
const std::shared_ptr<const PackageID> &,
const ChangedChoices * const) const PALUDIS_ATTRIBUTE((warn_unused_result)) = 0;
bool one_requirement_met(
const Environment * const env,
const ChoiceNameWithPrefix & c,
const ChangedChoices * const maybe_changes_to_owner,
const std::shared_ptr<const PackageID> & id,
const std::shared_ptr<const PackageID> & from_id,
const ChangedChoices * const maybe_changes_to_target) const PALUDIS_ATTRIBUTE((warn_unused_result))
{
if (_ignore_if_no_such_group)
{
std::string::size_type p(_flags.find(':'));
ChoicePrefixName prefix((std::string::npos == p) ? "" : _flags.substr(0, p));
if (! id->choices_key())
return true;
auto choices(id->choices_key()->parse_value());
Choices::ConstIterator k(choices->find(prefix));
if (choices->end() == k)
return true;
if ((*k)->begin() == (*k)->end())
return true;
}
return one_requirement_met_base(env, c, maybe_changes_to_owner, id, from_id, maybe_changes_to_target);
}
virtual const std::string as_human_string(
const std::shared_ptr<const PackageID> & from_id) const PALUDIS_ATTRIBUTE((warn_unused_result)) = 0;
const std::string flags() const PALUDIS_ATTRIBUTE((warn_unused_result))
{
return _flags;
}
const std::pair<bool, std::string> requirement_met(
const Environment * const env,
const ChangedChoices * const maybe_changes_to_owner,
const std::shared_ptr<const PackageID> & id,
const std::shared_ptr<const PackageID> & from_id,
const ChangedChoices * const maybe_changes_to_target) const
{
if (_flags.length() >= 2 && ":*" == _flags.substr(_flags.length() - 2))
{
if ((! _options[euro_allow_self_deps]) || (! from_id) || (! from_id->choices_key()))
throw ELikeUseRequirementError(_flags, "[prefix:*] not allowed here");
if (_options[euro_portage_syntax] && ! _options[euro_both_syntaxes])
{
if (_options[euro_strict_parsing])
throw ELikeUseRequirementError(_flags, "[prefix:*] not allowed here");
else
Log::get_instance()->message("elike_use_requirement.prefix_star_not_allowed", ll_warning, lc_context)
<< "[prefix:*] not safe for use here";
}
ChoicePrefixName prefix(_flags.substr(0, _flags.length() - 2));
auto choices(from_id->choices_key()->parse_value());
Choices::ConstIterator cc(choices->find(prefix));
if (cc == choices->end())
Log::get_instance()->message("elike_use_requirement.prefix_star_unmatching", ll_warning, lc_context) <<
"ID '" << *from_id << "' uses requirement '" << _flags << "' but has no choice prefix '" << prefix << "'";
else
{
std::pair<bool, std::string> result(true, "");
for (Choice::ConstIterator v((*cc)->begin()), v_end((*cc)->end()) ;
v != v_end ; ++v)
if (! one_requirement_met(env, (*v)->name_with_prefix(), maybe_changes_to_owner, id, from_id, maybe_changes_to_target))
{
if (! result.first)
result.second.append(", ");
result.second.append(stringify((*v)->name_with_prefix()));
result.first = false;
}
if (! result.first)
{
result.second = as_human_string(from_id) + " (unmet: " + result.second + ")";
return result;
}
}
}
else
if (! one_requirement_met(env, ChoiceNameWithPrefix(_flags), maybe_changes_to_owner, id, from_id, maybe_changes_to_target))
return std::make_pair(false, as_human_string(from_id));
return std::make_pair(true, as_human_string(from_id));
}
const Tribool default_value() const PALUDIS_ATTRIBUTE((warn_unused_result))
{
return _default_value;
}
const std::string default_value_human_string_fragment() const PALUDIS_ATTRIBUTE((warn_unused_result))
{
std::string result;
if (_default_value.is_true())
result = ", assuming enabled if missing";
else if (_default_value.is_false())
result = ", assuming disabled if missing";
if (_ignore_if_no_such_group)
result.append(", only if the target has any flags with this prefix");
return result;
}
Tribool accumulate_changes_to_make_met(
const Environment * const env,
const ChangedChoices * const maybe_changes_to_owner,
const std::shared_ptr<const PackageID> & id,
const std::shared_ptr<const PackageID> & from_id,
ChangedChoices & changed_choices) const
{
if (requirement_met(env, maybe_changes_to_owner, id, from_id, &changed_choices).first)
return indeterminate;
if (_flags.length() >= 2 && ":*" == _flags.substr(_flags.length() - 2))
{
if ((! _options[euro_allow_self_deps]) || (! from_id) || (! from_id->choices_key()))
throw ELikeUseRequirementError(_flags, "[prefix:*] not allowed here");
if (_options[euro_portage_syntax] && ! _options[euro_both_syntaxes])
{
if (_options[euro_strict_parsing])
throw ELikeUseRequirementError(_flags, "[prefix:*] not allowed here");
else
Log::get_instance()->message("elike_use_requirement.prefix_star_not_allowed", ll_warning, lc_context)
<< "[prefix:*] not safe for use here";
}
ChoicePrefixName prefix(_flags.substr(0, _flags.length() - 2));
auto choices(from_id->choices_key()->parse_value());
Choices::ConstIterator cc(choices->find(prefix));
if (cc == choices->end())
Log::get_instance()->message("elike_use_requirement.prefix_star_unmatching", ll_warning, lc_context) <<
"ID '" << *from_id << "' uses requirement '" << _flags << "' but has no choice prefix '" << prefix << "'";
else
{
for (Choice::ConstIterator v((*cc)->begin()), v_end((*cc)->end()) ;
v != v_end ; ++v)
if (! one_accumulate_changes_to_make_met(env, maybe_changes_to_owner, id, changed_choices, (*v)->name_with_prefix()))
return false;
}
}
else
if (! one_accumulate_changes_to_make_met(env, maybe_changes_to_owner, id, changed_choices, ChoiceNameWithPrefix(_flags)))
return false;
return true;
}
bool one_accumulate_changes_to_make_met(
const Environment * const,
const ChangedChoices * const,
const std::shared_ptr<const PackageID> & id,
ChangedChoices & changed_choices,
const ChoiceNameWithPrefix & flag) const
{
const std::shared_ptr<const ChoiceValue> v(id->choices_key()->parse_value()->find_by_name_with_prefix(flag));
if (! v)
{
/* warning messages get done elsewhere, no need here */
return false;
}
if (v->locked() || co_explicit != v->origin())
return false;
return changed_choices.add_override_if_possible(flag, ! v->enabled());;
}
};
class PALUDIS_VISIBLE EnabledUseRequirement :
public UseRequirement
{
public:
EnabledUseRequirement(const std::string & n,
const ELikeUseRequirementOptions & o,
Tribool d, const bool b) :
UseRequirement(n, o, d, b)
{
}
bool one_requirement_met_base(const Environment * const, const ChoiceNameWithPrefix & flag, const ChangedChoices * const,
const std::shared_ptr<const PackageID> & pkg, const std::shared_ptr<const PackageID> &, const ChangedChoices * const changed_choices) const override
{
return icky_use_query(_options, flag, pkg, changed_choices, default_value());
}
const std::string as_human_string(
const std::shared_ptr<const PackageID> &) const override
{
return "Flag '" + stringify(flags()) + "' enabled" + default_value_human_string_fragment();
}
};
class PALUDIS_VISIBLE DisabledUseRequirement :
public UseRequirement
{
public:
DisabledUseRequirement(const std::string & n,
const ELikeUseRequirementOptions & o,
Tribool d, const bool b) :
UseRequirement(n, o, d, b)
{
}
bool one_requirement_met_base(const Environment * const, const ChoiceNameWithPrefix & flag, const ChangedChoices * const,
const std::shared_ptr<const PackageID> & pkg, const std::shared_ptr<const PackageID> &, const ChangedChoices * const changed_choices) const override
{
return ! icky_use_query(_options, flag, pkg, changed_choices, default_value());
}
const std::string as_human_string(
const std::shared_ptr<const PackageID> &) const override
{
return "Flag '" + stringify(flags()) + "' disabled" + default_value_human_string_fragment();
}
};
class PALUDIS_VISIBLE EnabledOrDisabledUseRequirement :
public UseRequirement
{
public:
EnabledOrDisabledUseRequirement(const std::string & n,
const ELikeUseRequirementOptions & o,
Tribool d, const bool b) :
UseRequirement(n, o, d, b)
{
}
bool one_requirement_met_base(const Environment * const, const ChoiceNameWithPrefix & flag, const ChangedChoices * const,
const std::shared_ptr<const PackageID> & pkg, const std::shared_ptr<const PackageID> &, const ChangedChoices * const changed_choices) const override
{
return icky_use_query(_options, flag, pkg, changed_choices, default_value()) ||
! icky_use_query(_options, flag, pkg, changed_choices, default_value());
}
const std::string as_human_string(
const std::shared_ptr<const PackageID> &) const override
{
return "Flag '" + stringify(flags()) + "' either enabled or disabled" + default_value_human_string_fragment();
}
};
class PALUDIS_VISIBLE ConditionalUseRequirement :
public UseRequirement
{
public:
ConditionalUseRequirement(const std::string & n,
const ELikeUseRequirementOptions & o,
Tribool d, const bool b) :
UseRequirement(n, o, d, b)
{
}
};
class PALUDIS_VISIBLE IfMineThenUseRequirement :
public ConditionalUseRequirement
{
public:
IfMineThenUseRequirement(
const std::string & n,
const ELikeUseRequirementOptions & o,
Tribool d, const bool b) :
ConditionalUseRequirement(n, o, d, b)
{
}
bool one_requirement_met_base(const Environment * const, const ChoiceNameWithPrefix & flag,
const ChangedChoices * const maybe_changes_to_owner, const std::shared_ptr<const PackageID> & pkg,
const std::shared_ptr<const PackageID> & from_id, const ChangedChoices * const changed_choices) const override
{
return ! icky_use_query(_options, flag, from_id, maybe_changes_to_owner) ||
icky_use_query(_options, flag, pkg, changed_choices, default_value());
}
const std::string as_human_string(
const std::shared_ptr<const PackageID> & from_id) const override
{
return "Flag '" + stringify(flags()) + "' enabled if it is enabled for '"
+ stringify(*from_id) + "'" + default_value_human_string_fragment();
}
};
class PALUDIS_VISIBLE IfNotMineThenUseRequirement :
public ConditionalUseRequirement
{
public:
IfNotMineThenUseRequirement(const std::string & n,
const ELikeUseRequirementOptions & o,
Tribool d, const bool b) :
ConditionalUseRequirement(n, o, d, b)
{
}
bool one_requirement_met_base(const Environment * const, const ChoiceNameWithPrefix & flag,
const ChangedChoices * const maybe_changes_to_owner,
const std::shared_ptr<const PackageID> & pkg, const std::shared_ptr<const PackageID> & from_id,
const ChangedChoices * const changed_choices) const override
{
return icky_use_query(_options, flag, from_id, maybe_changes_to_owner) ||
icky_use_query(_options, flag, pkg, changed_choices, default_value());
}
const std::string as_human_string(
const std::shared_ptr<const PackageID> & from_id) const override
{
return "Flag '" + stringify(flags()) + "' enabled if it is disabled for '" +
stringify(*from_id) + "'" + default_value_human_string_fragment();
}
};
class PALUDIS_VISIBLE IfMineThenNotUseRequirement :
public ConditionalUseRequirement
{
public:
IfMineThenNotUseRequirement(const std::string & n,
const ELikeUseRequirementOptions & o,
Tribool d, const bool b) :
ConditionalUseRequirement(n, o, d, b)
{
}
bool one_requirement_met_base(const Environment * const, const ChoiceNameWithPrefix & flag,
const ChangedChoices * const maybe_changes_to_owner, const std::shared_ptr<const PackageID> & pkg,
const std::shared_ptr<const PackageID> & from_id, const ChangedChoices * const changed_choices) const override
{
return ! icky_use_query(_options, flag, from_id, maybe_changes_to_owner) ||
! icky_use_query(_options, flag, pkg, changed_choices, default_value());
}
const std::string as_human_string(
const std::shared_ptr<const PackageID> & from_id) const override
{
return "Flag '" + stringify(flags()) + "' disabled if it is enabled for '" +
stringify(*from_id) + "'" + default_value_human_string_fragment();
}
};
class PALUDIS_VISIBLE IfNotMineThenNotUseRequirement :
public ConditionalUseRequirement
{
public:
IfNotMineThenNotUseRequirement(const std::string & n,
const ELikeUseRequirementOptions & o,
Tribool d, const bool b) :
ConditionalUseRequirement(n, o, d, b)
{
}
bool one_requirement_met_base(const Environment * const, const ChoiceNameWithPrefix & flag,
const ChangedChoices * const maybe_changes_to_owner, const std::shared_ptr<const PackageID> & pkg,
const std::shared_ptr<const PackageID> & from_id, const ChangedChoices * const changed_choices) const override
{
return icky_use_query(_options, flag, from_id, maybe_changes_to_owner) ||
! icky_use_query(_options, flag, pkg, changed_choices, default_value());
}
const std::string as_human_string(
const std::shared_ptr<const PackageID> & from_id) const override
{
return "Flag '" + stringify(flags()) + "' disabled if it is disabled for '" +
stringify(*from_id) + "'" + default_value_human_string_fragment();
}
};
class PALUDIS_VISIBLE EqualUseRequirement :
public ConditionalUseRequirement
{
public:
EqualUseRequirement(const std::string & n,
const ELikeUseRequirementOptions & o,
Tribool d, const bool b) :
ConditionalUseRequirement(n, o, d, b)
{
}
bool one_requirement_met_base(const Environment * const, const ChoiceNameWithPrefix & flag,
const ChangedChoices * const maybe_changes_to_owner, const std::shared_ptr<const PackageID> & pkg,
const std::shared_ptr<const PackageID> & from_id, const ChangedChoices * const changed_choices) const override
{
return icky_use_query(_options, flag, pkg, changed_choices, default_value()) ==
icky_use_query(_options, flag, from_id, maybe_changes_to_owner);
}
const std::string as_human_string(
const std::shared_ptr<const PackageID> & from_id) const override
{
return "Flag '" + stringify(flags()) + "' enabled or disabled like it is for '"
+ stringify(*from_id) + "'" + default_value_human_string_fragment();
}
};
class PALUDIS_VISIBLE NotEqualUseRequirement :
public ConditionalUseRequirement
{
public:
NotEqualUseRequirement(const std::string & n,
const ELikeUseRequirementOptions & o,
Tribool d, const bool b) :
ConditionalUseRequirement(n, o, d, b)
{
}
bool one_requirement_met_base(const Environment * const, const ChoiceNameWithPrefix & flag,
const ChangedChoices * const maybe_changes_to_owner, const std::shared_ptr<const PackageID> & pkg,
const std::shared_ptr<const PackageID> & from_id, const ChangedChoices * const changed_choices) const override
{
return icky_use_query(_options, flag, pkg, changed_choices, default_value()) !=
icky_use_query(_options, flag, from_id, maybe_changes_to_owner);
}
const std::string as_human_string(
const std::shared_ptr<const PackageID> & from_id) const override
{
return "Flag '" + stringify(flags()) + "' enabled or disabled opposite to how it is for '"
+ stringify(*from_id) + "'" + default_value_human_string_fragment();
}
};
class UseRequirements :
public AdditionalPackageDepSpecRequirement
{
private:
typedef std::vector<std::shared_ptr<const UseRequirement> > Reqs;
std::string _raw;
Reqs _reqs;
public:
UseRequirements(const std::string & r) :
_raw(r)
{
}
const std::pair<bool, std::string> requirement_met(
const Environment * const env,
const ChangedChoices * const maybe_changes_to_owner,
const std::shared_ptr<const PackageID> & id,
const std::shared_ptr<const PackageID> & from_id,
const ChangedChoices * const maybe_changes_to_target) const override
{
using namespace std::placeholders;
std::pair<bool, std::string> result(true, "");
for (const auto & _req : _reqs)
{
std::pair<bool, std::string> r_result(_req->requirement_met(env, maybe_changes_to_owner, id, from_id, maybe_changes_to_target));
if (! r_result.first)
{
if (! result.first)
result.second.append("; ");
result.second.append(r_result.second);
result.first = false;
}
}
return result;
}
const std::string as_human_string(
const std::shared_ptr<const PackageID> & from_id) const override
{
return join(_reqs.begin(), _reqs.end(), "; ", std::bind(std::mem_fn(&UseRequirement::as_human_string),
std::placeholders::_1, from_id));
}
const std::string as_raw_string() const override
{
return _raw;
}
void add_requirement(const std::shared_ptr<const UseRequirement> & req)
{
_reqs.push_back(req);
}
Tribool accumulate_changes_to_make_met(
const Environment * const env,
const ChangedChoices * const maybe_changes_to_owner,
const std::shared_ptr<const PackageID> & id,
const std::shared_ptr<const PackageID> & from_id,
ChangedChoices & changed_choices) const override
{
Tribool result(indeterminate);
for (const auto & _req : _reqs)
{
auto b(_req->accumulate_changes_to_make_met(env, maybe_changes_to_owner, id, from_id, changed_choices));
if (b.is_false())
return false;
else if (b.is_true())
result = true;
}
return result;
}
};
template <typename T_>
std::shared_ptr<const UseRequirement>
make_requirement(const std::string & n, const ELikeUseRequirementOptions & o, Tribool d, const bool b)
{
return std::make_shared<T_>(n, o, d, b);
}
typedef std::shared_ptr<const UseRequirement> (* Factory)(
const std::string &, const ELikeUseRequirementOptions &, Tribool, bool);
void
parse_flag(
const std::shared_ptr<UseRequirements> & result,
const Factory & factory,
const std::string & c,
Tribool d,
const bool i,
const ELikeUseRequirementOptions & options,
const std::shared_ptr<Set<std::string> > & maybe_accumulate_mentioned)
{
result->add_requirement(factory(c, options, d, i));
if (maybe_accumulate_mentioned)
maybe_accumulate_mentioned->insert(c);
}
void
parse_one_use_requirement(
const std::shared_ptr<UseRequirements> & result,
const std::string & s, std::string & flag,
const ELikeUseRequirementOptions & options,
const std::shared_ptr<Set<std::string> > & maybe_accumulate_mentioned)
{
Factory factory;
if (flag.empty())
throw ELikeUseRequirementError(s, "Invalid [] contents");
if ('=' == flag.at(flag.length() - 1))
{
if ((! options[euro_allow_self_deps]))
throw ELikeUseRequirementError(s, "Cannot use [use=] here");
flag.erase(flag.length() - 1);
if (flag.empty())
throw ELikeUseRequirementError(s, "Invalid [] contents");
if ('!' == flag.at(flag.length() - 1))
{
if (options[euro_portage_syntax] && ! options[euro_both_syntaxes])
{
if (options[euro_strict_parsing])
throw ELikeUseRequirementError(s, "[use!=] not safe for use here");
else
Log::get_instance()->message("e.use_requirement.flag_not_equal_not_allowed", ll_warning, lc_context)
<< "[use!=] not safe for use here";
}
flag.erase(flag.length() - 1, 1);
if (flag.empty())
throw ELikeUseRequirementError(s, "Invalid [] contents");
factory = make_requirement<NotEqualUseRequirement>;
}
else if ('!' == flag.at(0))
{
if (! options[euro_portage_syntax] && ! options[euro_both_syntaxes])
{
if (options[euro_strict_parsing])
throw ELikeUseRequirementError(s, "[!use=] not safe for use here");
else
Log::get_instance()->message("e.use_requirement.not_flag_equal_not_allowed", ll_warning, lc_context)
<< "[!use=] not safe for use here";
}
flag.erase(0, 1);
if (flag.empty())
throw ELikeUseRequirementError(s, "Invalid [] contents");
factory = make_requirement<NotEqualUseRequirement>;
}
else
factory = make_requirement<EqualUseRequirement>;
}
else if ('?' == flag.at(flag.length() - 1))
{
if ((! options[euro_allow_self_deps]))
throw ELikeUseRequirementError(s, "Cannot use [use?] here");
flag.erase(flag.length() - 1);
if (flag.empty())
throw ELikeUseRequirementError(s, "Invalid [] contents");
if ('!' == flag.at(flag.length() - 1))
{
flag.erase(flag.length() - 1, 1);
if (flag.empty())
throw ELikeUseRequirementError(s, "Invalid [] contents");
if ('-' == flag.at(0))
{
if (options[euro_portage_syntax] && ! options[euro_both_syntaxes])
{
if (options[euro_strict_parsing])
throw ELikeUseRequirementError(s, "[-use!?] not safe for use here");
else
Log::get_instance()->message("e.use_requirement.minus_flag_not_question_not_allowed", ll_warning, lc_context)
<< "[-use!?] not safe for use here";
}
flag.erase(0, 1);
if (flag.empty())
throw ELikeUseRequirementError(s, "Invalid [] contents");
factory = make_requirement<IfNotMineThenNotUseRequirement>;
}
else
{
if (options[euro_portage_syntax] && ! options[euro_both_syntaxes])
{
if (options[euro_strict_parsing])
throw ELikeUseRequirementError(s, "[use!?] not safe for use here");
else
Log::get_instance()->message("e.use_requirement.flag_not_question_not_allowed", ll_warning, lc_context)
<< "[use!?] not safe for use here";
}
factory = make_requirement<IfNotMineThenUseRequirement>;
}
}
else if ('!' == flag.at(0))
{
if (! options[euro_portage_syntax] && ! options[euro_both_syntaxes])
{
if (options[euro_strict_parsing])
throw ELikeUseRequirementError(s, "[!use?] not safe for use here");
else
Log::get_instance()->message("e.use_requirement.not_flag_question_not_allowed", ll_warning, lc_context)
<< "[!use?] not safe for use here";
}
flag.erase(0, 1);
if (flag.empty())
throw ELikeUseRequirementError(s, "Invalid [] contents");
factory = make_requirement<IfNotMineThenNotUseRequirement>;
}
else
{
if ('-' == flag.at(0))
{
if (options[euro_portage_syntax] && ! options[euro_both_syntaxes])
{
if (options[euro_strict_parsing])
throw ELikeUseRequirementError(s, "[-use?] not safe for use here");
else
Log::get_instance()->message("e.use_requirement.minus_flag_question_not_allowed", ll_warning, lc_context)
<< "[-use?] not safe for use here";
}
flag.erase(0, 1);
if (flag.empty())
throw ELikeUseRequirementError(s, "Invalid [] contents");
factory = make_requirement<IfMineThenNotUseRequirement>;
}
else
factory = make_requirement<IfMineThenUseRequirement>;
}
}
else if ('-' == flag.at(0))
{
flag.erase(0, 1);
if (flag.empty())
throw ELikeUseRequirementError(s, "Invalid [] contents");
factory = make_requirement<DisabledUseRequirement>;
}
else if ('?' == flag.at(0))
{
if (options[euro_portage_syntax] && ! options[euro_both_syntaxes])
{
if (options[euro_strict_parsing])
throw ELikeUseRequirementError(s, "[?use] not safe for use here");
else
Log::get_instance()->message("e.use_requirement.question_flag_not_allowed", ll_warning, lc_context)
<< "[?use] not safe for use here";
}
flag.erase(0, 1);
if (flag.empty())
throw ELikeUseRequirementError(s, "Invalid [] contents");
factory = make_requirement<EnabledOrDisabledUseRequirement>;
}
else
factory = make_requirement<EnabledUseRequirement>;
if (')' == flag.at(flag.length() - 1))
{
if (flag.length() < 4 || flag.at(flag.length() - 3) != '(')
throw ELikeUseRequirementError(s, "Invalid [] contents");
if ('+' == flag.at(flag.length() - 2))
{
if (! options[euro_allow_default_values])
{
if (options[euro_strict_parsing])
throw ELikeUseRequirementError(s, "[use(+)] not safe for use here");
else
Log::get_instance()->message("e.use_requirement.flag_bracket_plus_not_allowed", ll_warning, lc_context)
<< "[use(+)] not safe for use here";
}
flag.erase(flag.length() - 3, 3);
parse_flag(result, factory, flag, Tribool(true), false, options, maybe_accumulate_mentioned);
}
else if ('-' == flag.at(flag.length() - 2))
{
if (! options[euro_allow_default_values])
{
if (options[euro_strict_parsing])
throw ELikeUseRequirementError(s, "[use(-)] not safe for use here");
else
Log::get_instance()->message("e.use_requirement.flag_bracket_minus_not_allowed", ll_warning, lc_context)
<< "[use(-)] not safe for use here";
}
flag.erase(flag.length() - 3, 3);
parse_flag(result, factory, flag, Tribool(false), false, options, maybe_accumulate_mentioned);
}
else if ('?' == flag.at(flag.length() - 2))
{
if (! options[euro_allow_default_question_values])
{
if (options[euro_strict_parsing])
throw ELikeUseRequirementError(s, "[use(?)] not safe for use here");
else
Log::get_instance()->message("e.use_requirement.flag_bracket_question_not_allowed", ll_warning, lc_context)
<< "[use(?)] not safe for use here";
}
flag.erase(flag.length() - 3, 3);
parse_flag(result, factory, flag, Tribool(false), true, options, maybe_accumulate_mentioned);
}
else
throw ELikeUseRequirementError(s, "Invalid [] contents");
}
else
parse_flag(result, factory, flag, Tribool(indeterminate), false, options, maybe_accumulate_mentioned);
}
}
ELikeUseRequirementError::ELikeUseRequirementError(const std::string & s, const std::string & m) noexcept :
Exception("Error parsing use requirement '" + s + "': " + m)
{
}
std::shared_ptr<const AdditionalPackageDepSpecRequirement>
paludis::parse_elike_use_requirement(const std::string & s,
const ELikeUseRequirementOptions & options,
const std::shared_ptr<Set<std::string> > & maybe_accumulate_mentioned)
{
Context context("When parsing use requirement '" + s + "':");
std::shared_ptr<UseRequirements> result(std::make_shared<UseRequirements>("[" + s + "]"));
std::string::size_type pos(0);
for (;;)
{
std::string::size_type comma(s.find(',', pos));
std::string flag(s.substr(pos, std::string::npos == comma ? comma : comma - pos));
parse_one_use_requirement(result, s, flag, options, maybe_accumulate_mentioned);
if (std::string::npos == comma)
break;
if (! options[euro_portage_syntax] && ! options[euro_both_syntaxes])
{
if (options[euro_strict_parsing])
throw ELikeUseRequirementError(s, "[use,use] not safe for use here");
else
Log::get_instance()->message("e.use_requirement.comma_separated_not_allowed", ll_warning, lc_context)
<< "[use,use] not safe for use here";
}
pos = comma + 1;
}
return result;
}
namespace
{
class ELikePresumedChoicesRequirement :
public AdditionalPackageDepSpecRequirement
{
private:
const std::shared_ptr<const Set<std::string> > _mentioned;
public:
ELikePresumedChoicesRequirement(
const std::shared_ptr<const Set<std::string> > m) :
_mentioned(m)
{
}
const std::pair<bool, std::string> requirement_met(
const Environment * const,
const ChangedChoices * const,
const std::shared_ptr<const PackageID> & id,
const std::shared_ptr<const PackageID> &,
const ChangedChoices * const) const override PALUDIS_ATTRIBUTE((warn_unused_result))
{
if (! id->choices_key())
return std::make_pair(true, "");
auto choices(id->choices_key()->parse_value());
std::string p;
int n(0);
for (auto c(choices->begin()), c_end(choices->end()) ; c != c_end ; ++c)
{
if (_mentioned->end() != _mentioned->find(stringify((*c)->prefix()) + ":*"))
continue;
for (auto v((*c)->begin()), v_end((*c)->end()) ; v != v_end ; ++v)
if ((*v)->presumed() && ! (*v)->enabled())
{
if (_mentioned->end() != _mentioned->find(stringify((*v)->name_with_prefix())))
continue;
++n;
if (! p.empty())
p.append("', '");
p.append(stringify((*v)->name_with_prefix()));
}
}
if (n > 1)
return std::make_pair(false, "Flags '" + p + "' enabled (presumed)");
else if (n == 1)
return std::make_pair(false, "Flag '" + p + "' enabled (presumed)");
else
return std::make_pair(true, as_human_string(id));
}
Tribool accumulate_changes_to_make_met(
const Environment * const env,
const ChangedChoices * const maybe_changes_to_owner,
const std::shared_ptr<const PackageID> & id,
const std::shared_ptr<const PackageID> & spec_id,
ChangedChoices &) const override PALUDIS_ATTRIBUTE((warn_unused_result))
{
if (requirement_met(env, maybe_changes_to_owner, id, spec_id, nullptr).first)
return indeterminate;
else
return false;
}
const std::string as_human_string(
const std::shared_ptr<const PackageID> &) const override PALUDIS_ATTRIBUTE((warn_unused_result))
{
return "Remaining presumed flags enabled";
}
const std::string as_raw_string() const override PALUDIS_ATTRIBUTE((warn_unused_result))
{
return "";
}
};
}
std::shared_ptr<const AdditionalPackageDepSpecRequirement>
paludis::make_elike_presumed_choices_requirement(
const std::shared_ptr<const Set<std::string> > mentioned)
{
return std::make_shared<ELikePresumedChoicesRequirement>(mentioned);
}