aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2008-11-03 19:58:55 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2008-11-03 19:58:55 +0000
commiteada9d181d571c9a06156dae1b37fe6899b1ed8b (patch)
tree50e297872ec14a60e3533b237cbfc1be201794b5
parentcb9b7c77715d51adb3e78253337ea9a5b23cdc80 (diff)
downloadpaludis-eada9d181d571c9a06156dae1b37fe6899b1ed8b.tar.gz
paludis-eada9d181d571c9a06156dae1b37fe6899b1ed8b.tar.xz
MYOPTIONS number-selected requirements
-rw-r--r--paludis/repositories/e/Makefile.am2
-rw-r--r--paludis/repositories/e/e_key.cc3
-rw-r--r--paludis/repositories/e/eapi.cc4
-rw-r--r--paludis/repositories/e/eapi.hh8
-rw-r--r--paludis/repositories/e/eapis/exheres-0.conf4
-rw-r--r--paludis/repositories/e/myoption.cc35
-rw-r--r--paludis/repositories/e/myoption.hh35
-rw-r--r--paludis/repositories/e/myoptions_requirements_verifier.cc133
8 files changed, 204 insertions, 20 deletions
diff --git a/paludis/repositories/e/Makefile.am b/paludis/repositories/e/Makefile.am
index 872a023..aafb05c 100644
--- a/paludis/repositories/e/Makefile.am
+++ b/paludis/repositories/e/Makefile.am
@@ -82,6 +82,7 @@ paludis_repositories_e_include_HEADERS = \
layout.hh \
manifest2_entry-sr.hh \
manifest2_reader.hh \
+ myoption.hh \
myoptions_requirements_verifier.hh \
pipe_command_handler.hh \
source_uri_finder.hh \
@@ -135,6 +136,7 @@ libpaludiserepository_@PALUDIS_PC_SLOT@_la_SOURCES = \
glsa.cc \
layout.cc \
manifest2_reader.cc \
+ myoption.cc \
myoptions_requirements_verifier.cc \
pipe_command_handler.cc \
registration.cc \
diff --git a/paludis/repositories/e/e_key.cc b/paludis/repositories/e/e_key.cc
index 5bc46a0..c048399 100644
--- a/paludis/repositories/e/e_key.cc
+++ b/paludis/repositories/e/e_key.cc
@@ -25,6 +25,7 @@
#include <paludis/repositories/e/vdb_contents_tokeniser.hh>
#include <paludis/repositories/e/e_repository_profile.hh>
#include <paludis/repositories/e/e_repository.hh>
+#include <paludis/repositories/e/myoption.hh>
#include <paludis/util/pretty_print.hh>
#include <paludis/util/private_implementation_pattern-impl.hh>
@@ -953,7 +954,7 @@ namespace
if (p == prefixes.end())
p = prefixes.insert(std::make_pair(*current_prefix_stack.begin(), Values())).first;
- UnprefixedChoiceName n('-' == s.text().at(0) ? s.text().substr(1) : s.text());
+ UnprefixedChoiceName n(parse_myoption(s.text()).first);
Values::iterator v(p->second.find(n));
if (v == p->second.end())
v = p->second.insert(std::make_pair(n, Annotations())).first;
diff --git a/paludis/repositories/e/eapi.cc b/paludis/repositories/e/eapi.cc
index b68fa5e..d23b560 100644
--- a/paludis/repositories/e/eapi.cc
+++ b/paludis/repositories/e/eapi.cc
@@ -214,6 +214,10 @@ namespace
{
return make_shared_ptr(new EAPIAnnotations(make_named_values<EAPIAnnotations>(
value_for<n::myoptions_description>(k.get("annotations_myoptions_description")),
+ value_for<n::myoptions_number_selected>(k.get("annotations_myoptions_number_selected")),
+ value_for<n::myoptions_number_selected_at_least_one>(k.get("annotations_myoptions_number_selected_at_least_one")),
+ value_for<n::myoptions_number_selected_at_most_one>(k.get("annotations_myoptions_number_selected_at_most_one")),
+ value_for<n::myoptions_number_selected_exactly_one>(k.get("annotations_myoptions_number_selected_exactly_one")),
value_for<n::myoptions_requires>(k.get("annotations_myoptions_requires"))
)));
}
diff --git a/paludis/repositories/e/eapi.hh b/paludis/repositories/e/eapi.hh
index 7b6fa24..a20d60d 100644
--- a/paludis/repositories/e/eapi.hh
+++ b/paludis/repositories/e/eapi.hh
@@ -112,6 +112,10 @@ namespace paludis
struct minimum_flat_list_size;
struct myoptions;
struct myoptions_description;
+ struct myoptions_number_selected;
+ struct myoptions_number_selected_at_least_one;
+ struct myoptions_number_selected_at_most_one;
+ struct myoptions_number_selected_exactly_one;
struct myoptions_requires;
struct must_not_change_variables;
struct name;
@@ -376,6 +380,10 @@ namespace paludis
struct EAPIAnnotations
{
NamedValue<n::myoptions_description, std::string> myoptions_description;
+ NamedValue<n::myoptions_number_selected, std::string> myoptions_number_selected;
+ NamedValue<n::myoptions_number_selected_at_least_one, std::string> myoptions_number_selected_at_least_one;
+ NamedValue<n::myoptions_number_selected_at_most_one, std::string> myoptions_number_selected_at_most_one;
+ NamedValue<n::myoptions_number_selected_exactly_one, std::string> myoptions_number_selected_exactly_one;
NamedValue<n::myoptions_requires, std::string> myoptions_requires;
};
}
diff --git a/paludis/repositories/e/eapis/exheres-0.conf b/paludis/repositories/e/eapis/exheres-0.conf
index e869cf3..c4e3c37 100644
--- a/paludis/repositories/e/eapis/exheres-0.conf
+++ b/paludis/repositories/e/eapis/exheres-0.conf
@@ -289,4 +289,8 @@ failure_is_fatal = true
annotations_myoptions_description = description
annotations_myoptions_requires = requires
+annotations_myoptions_number_selected = number-selected
+annotations_myoptions_number_selected_at_least_one = at-least-one
+annotations_myoptions_number_selected_at_most_one = at-most-one
+annotations_myoptions_number_selected_exactly_one = exactly-one
diff --git a/paludis/repositories/e/myoption.cc b/paludis/repositories/e/myoption.cc
new file mode 100644
index 0000000..4044cad
--- /dev/null
+++ b/paludis/repositories/e/myoption.cc
@@ -0,0 +1,35 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2008 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/repositories/e/myoption.hh>
+#include <paludis/util/validated.hh>
+#include <paludis/choice.hh>
+
+using namespace paludis;
+using namespace paludis::erepository;
+
+std::pair<UnprefixedChoiceName, bool>
+paludis::erepository::parse_myoption(const std::string & s)
+{
+ if ((! s.empty()) && '-' == s.at(0))
+ return std::make_pair(UnprefixedChoiceName(s.substr(1)), false);
+ else
+ return std::make_pair(UnprefixedChoiceName(s), true);
+}
+
diff --git a/paludis/repositories/e/myoption.hh b/paludis/repositories/e/myoption.hh
new file mode 100644
index 0000000..ea0e1e4
--- /dev/null
+++ b/paludis/repositories/e/myoption.hh
@@ -0,0 +1,35 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2008 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_REPOSITORIES_E_MYOPTION_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_E_MYOPTION_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <paludis/choice-fwd.hh>
+#include <utility>
+
+namespace paludis
+{
+ namespace erepository
+ {
+ std::pair<UnprefixedChoiceName, bool> parse_myoption(const std::string &) PALUDIS_VISIBLE PALUDIS_ATTRIBUTE((warn_unused_result));
+ }
+}
+
+#endif
diff --git a/paludis/repositories/e/myoptions_requirements_verifier.cc b/paludis/repositories/e/myoptions_requirements_verifier.cc
index 0b56013..d2bbe03 100644
--- a/paludis/repositories/e/myoptions_requirements_verifier.cc
+++ b/paludis/repositories/e/myoptions_requirements_verifier.cc
@@ -20,6 +20,7 @@
#include <paludis/repositories/e/myoptions_requirements_verifier.hh>
#include <paludis/repositories/e/e_repository_id.hh>
#include <paludis/repositories/e/eapi.hh>
+#include <paludis/repositories/e/myoption.hh>
#include <paludis/util/private_implementation_pattern-impl.hh>
#include <paludis/util/visitor-impl.hh>
#include <paludis/util/stringify.hh>
@@ -27,6 +28,7 @@
#include <paludis/util/tokeniser.hh>
#include <paludis/util/log.hh>
#include <paludis/util/set.hh>
+#include <paludis/util/make_shared_ptr.hh>
#include <paludis/choice.hh>
#include <paludis/metadata_key.hh>
#include <algorithm>
@@ -47,6 +49,7 @@ namespace paludis
std::tr1::shared_ptr<Sequence<std::string> > unmet_requirements;
std::list<ChoicePrefixName> current_prefix_stack;
std::list<ChildrenList> current_children_stack;
+ std::list<int> number_enabled_stack;
Implementation(const std::tr1::shared_ptr<const ERepositoryID> & i) :
id(i),
@@ -54,6 +57,7 @@ namespace paludis
{
current_prefix_stack.push_front(ChoicePrefixName(""));
current_children_stack.push_front(ChildrenList());
+ number_enabled_stack.push_front(0);
}
};
}
@@ -79,35 +83,47 @@ MyOptionsRequirementsVerifier::visit_leaf(const PlainTextLabelDepSpec & s)
*_imp->current_prefix_stack.begin() = ChoicePrefixName(s.label());
}
+namespace
+{
+ const std::tr1::shared_ptr<const ChoiceValue> find_choice_value(
+ const std::tr1::shared_ptr<const ERepositoryID> & id,
+ const ChoicePrefixName & prefix,
+ const ChoiceNameWithPrefix & name_with_prefix)
+ {
+ if (id->choices_key())
+ for (Choices::ConstIterator k(id->choices_key()->value()->begin()),
+ k_end(id->choices_key()->value()->end()) ;
+ k != k_end ; ++k)
+ {
+ if ((*k)->prefix() != prefix)
+ continue;
+
+ for (Choice::ConstIterator i((*k)->begin()), i_end((*k)->end()) ;
+ i != i_end ; ++i)
+ if ((*i)->name_with_prefix() == name_with_prefix)
+ return *i;
+ }
+
+ return make_null_shared_ptr();
+ }
+}
+
void
MyOptionsRequirementsVerifier::verify_one(const ChoicePrefixName & spec_prefix,
const std::string & spec_text, const std::tr1::shared_ptr<const MetadataSectionKey> & annotations_key)
{
- bool active_flag_state(spec_text.at(0) != '-');
+ std::pair<UnprefixedChoiceName, bool> active_myoption(parse_myoption(spec_text));
ChoiceNameWithPrefix active_flag((
! stringify(spec_prefix).empty() ? stringify(spec_prefix) +
stringify(_imp->id->eapi()->supported()->choices_options()->use_expand_separator()) : "") +
- stringify(spec_text.substr(active_flag_state ? 0 : 1)));
+ stringify(active_myoption.first));
{
- std::tr1::shared_ptr<const ChoiceValue> choice_value;
- if (_imp->id->choices_key())
- for (Choices::ConstIterator k(_imp->id->choices_key()->value()->begin()),
- k_end(_imp->id->choices_key()->value()->end()) ;
- k != k_end && ! choice_value ; ++k)
- {
- if ((*k)->prefix() != spec_prefix)
- continue;
-
- for (Choice::ConstIterator i((*k)->begin()), i_end((*k)->end()) ;
- i != i_end && ! choice_value ; ++i)
- if ((*i)->name_with_prefix() == active_flag)
- choice_value = *i;
- }
+ std::tr1::shared_ptr<const ChoiceValue> choice_value(find_choice_value(_imp->id, spec_prefix, active_flag));
if (choice_value)
{
- if (choice_value->enabled() != active_flag_state)
+ if (choice_value->enabled() != active_myoption.second)
return;
}
else
@@ -134,6 +150,9 @@ MyOptionsRequirementsVerifier::verify_one(const ChoicePrefixName & spec_prefix,
if (a_key == _imp->id->eapi()->supported()->annotations()->myoptions_description())
{
}
+ else if (a_key == _imp->id->eapi()->supported()->annotations()->myoptions_number_selected())
+ {
+ }
else if (a_key == _imp->id->eapi()->supported()->annotations()->myoptions_requires())
{
std::list<std::string> tokens;
@@ -180,7 +199,7 @@ MyOptionsRequirementsVerifier::verify_one(const ChoicePrefixName & spec_prefix,
{
if (choice_value->enabled() != req_state)
{
- _imp->unmet_requirements->push_back(stringify(active_flag_state ? "Enabling" : "Disabling") +
+ _imp->unmet_requirements->push_back(stringify(active_myoption.second ? "Enabling" : "Disabling") +
" option '" + stringify(active_flag) + "' requires option '" +
stringify(choice_value->name_with_prefix()) + "' to be " +
(req_state ? "enabled" : "disabled"));
@@ -191,7 +210,7 @@ MyOptionsRequirementsVerifier::verify_one(const ChoicePrefixName & spec_prefix,
/* ick */
ChoiceNameWithPrefix qualified_flag_name((stringify(prefix).empty() ? "" : stringify(prefix) +
stringify(_imp->id->eapi()->supported()->choices_options()->use_expand_separator())) + stringify(suffix));
- _imp->unmet_requirements->push_back(stringify(active_flag_state ? "Enabling" : "Disabling") +
+ _imp->unmet_requirements->push_back(stringify(active_myoption.second ? "Enabling" : "Disabling") +
" option '" + stringify(active_flag) + "' requires option '" + stringify(qualified_flag_name) + "' to be " +
(req_state ? "enabled" : "disabled") + ", but no such option exists");
}
@@ -212,6 +231,22 @@ MyOptionsRequirementsVerifier::visit_leaf(const PlainTextDepSpec & s)
l != l_end ; ++l)
l->push_back(std::make_pair(*_imp->current_prefix_stack.begin(), s.text()));
+ {
+ Context local_context("When finding associated choice:");
+
+ std::pair<UnprefixedChoiceName, bool> active_myoption(parse_myoption(s.text()));
+ ChoiceNameWithPrefix active_flag((
+ ! stringify(*_imp->current_prefix_stack.begin()).empty() ? stringify(*_imp->current_prefix_stack.begin()) +
+ stringify(_imp->id->eapi()->supported()->choices_options()->use_expand_separator()) : "") +
+ stringify(active_myoption.first));
+ std::tr1::shared_ptr<const ChoiceValue> choice_value(find_choice_value(_imp->id, *_imp->current_prefix_stack.begin(), active_flag));
+
+ if (choice_value && choice_value->enabled() == active_myoption.second)
+ for (std::list<int>::iterator l(_imp->number_enabled_stack.begin()), l_end(_imp->number_enabled_stack.end()) ;
+ l != l_end ; ++l)
+ ++*l;
+ }
+
if ((! s.annotations_key()) || (s.annotations_key()->begin_metadata() == s.annotations_key()->end_metadata()))
return;
@@ -227,7 +262,11 @@ MyOptionsRequirementsVerifier::visit_sequence(const ConditionalDepSpec & spec,
{
_imp->current_prefix_stack.push_front(*_imp->current_prefix_stack.begin());
_imp->current_children_stack.push_front(ChildrenList());
+ _imp->number_enabled_stack.push_front(0);
+
std::for_each(cur, end, accept_visitor(*this));
+
+ _imp->number_enabled_stack.pop_front();
_imp->current_children_stack.pop_front();
_imp->current_prefix_stack.pop_front();
}
@@ -240,6 +279,8 @@ MyOptionsRequirementsVerifier::visit_sequence(const AllDepSpec & s,
{
_imp->current_prefix_stack.push_front(*_imp->current_prefix_stack.begin());
_imp->current_children_stack.push_front(ChildrenList());
+ _imp->number_enabled_stack.push_front(0);
+
std::for_each(cur, end, accept_visitor(*this));
if (s.annotations_key() && (s.annotations_key()->begin_metadata() != s.annotations_key()->end_metadata()))
{
@@ -247,7 +288,61 @@ MyOptionsRequirementsVerifier::visit_sequence(const AllDepSpec & s,
i_end(_imp->current_children_stack.begin()->end()) ;
i != i_end ; ++i)
verify_one(i->first, i->second, s.annotations_key());
+
+ for (MetadataSectionKey::MetadataConstIterator m(s.annotations_key()->begin_metadata()), m_end(s.annotations_key()->end_metadata()) ;
+ m != m_end ; ++m)
+ {
+ const MetadataValueKey<std::string> * mm(visitor_cast<const MetadataValueKey<std::string> >(**m));
+ if (! mm)
+ {
+ Log::get_instance()->message("e_key.myoptions.strange_annotation", ll_warning, lc_context)
+ << "Don't know how to handle annotation '" << (*m)->raw_name() << "'";
+ continue;
+ }
+
+ std::string a_key(mm->raw_name()), a_value(mm->value());
+
+ if (a_key == _imp->id->eapi()->supported()->annotations()->myoptions_number_selected())
+ {
+ std::string children_s;
+ for (ChildrenList::const_iterator i(_imp->current_children_stack.begin()->begin()),
+ i_end(_imp->current_children_stack.begin()->end()) ;
+ i != i_end ; ++i)
+ {
+ if (! children_s.empty())
+ children_s.append(", ");
+
+ if (! stringify(i->first).empty())
+ {
+ children_s.append(stringify(i->first));
+ children_s.append(stringify(_imp->id->eapi()->supported()->choices_options()->use_expand_separator()));
+ }
+ children_s.append(stringify(i->second));
+ }
+
+ children_s = "( " + children_s + " )";
+
+ if (a_value == _imp->id->eapi()->supported()->annotations()->myoptions_number_selected_at_least_one())
+ {
+ if (*_imp->number_enabled_stack.begin() < 1)
+ _imp->unmet_requirements->push_back("At least one of options " + children_s + " must be met");
+ }
+ else if (a_value == _imp->id->eapi()->supported()->annotations()->myoptions_number_selected_at_most_one())
+ {
+ if (*_imp->number_enabled_stack.begin() > 1)
+ _imp->unmet_requirements->push_back("At most one of options " + children_s + " must be met");
+ }
+ else if (a_value == _imp->id->eapi()->supported()->annotations()->myoptions_number_selected_exactly_one())
+ {
+ if (*_imp->number_enabled_stack.begin() != 1)
+ _imp->unmet_requirements->push_back("Exactly one of options " + children_s + " must be met");
+ }
+ else
+ _imp->unmet_requirements->push_back("Don't know what '" + stringify(a_value) + "' means");
+ }
+ }
}
+ _imp->number_enabled_stack.pop_front();
_imp->current_children_stack.pop_front();
_imp->current_prefix_stack.pop_front();
}