aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2008-11-03 17:55:46 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2008-11-03 17:55:46 +0000
commit6e7666ca2ae92ae7648e93e9986eadccafe70495 (patch)
tree6c11e267ff3abd5a08db039d26b4c2131a67acde
parentc0b811f3266617e9baca5ef33b570a57220c74af (diff)
downloadpaludis-6e7666ca2ae92ae7648e93e9986eadccafe70495.tar.gz
paludis-6e7666ca2ae92ae7648e93e9986eadccafe70495.tar.xz
Start MYOPTIONS requirements work
-rw-r--r--paludis/choice.cc27
-rw-r--r--paludis/repositories/e/Makefile.am2
-rw-r--r--paludis/repositories/e/e_installed_repository_id.cc2
-rw-r--r--paludis/repositories/e/e_key.cc22
-rw-r--r--paludis/repositories/e/eapi.cc8
-rw-r--r--paludis/repositories/e/eapi.hh6
-rw-r--r--paludis/repositories/e/eapis/exheres-0.conf6
-rw-r--r--paludis/repositories/e/ebuild.cc52
-rw-r--r--paludis/repositories/e/ebuild.hh45
-rwxr-xr-xpaludis/repositories/e/ebuild/ebuild.bash11
-rw-r--r--paludis/repositories/e/ebuild/exheres-0/Makefile.am1
-rw-r--r--paludis/repositories/e/ebuild/exheres-0/pkg_bad_options.bash45
-rw-r--r--paludis/repositories/e/ebuild_entries.cc67
-rw-r--r--paludis/repositories/e/ebuild_id.cc2
-rw-r--r--paludis/repositories/e/myoptions_requirements_verifier.cc231
-rw-r--r--paludis/repositories/e/myoptions_requirements_verifier.hh67
16 files changed, 566 insertions, 28 deletions
diff --git a/paludis/choice.cc b/paludis/choice.cc
index c7a1a69..60a32e3 100644
--- a/paludis/choice.cc
+++ b/paludis/choice.cc
@@ -47,6 +47,15 @@ ChoicePrefixNameValidator::validate(const std::string & s)
break;
};
+ switch (s.at(0))
+ {
+ case ':':
+ case '_':
+ case '-':
+ throw ChoicePrefixNameError(s);
+ break;
+ };
+
if (s[0] >= 'A' && s[0] <= 'Z')
throw ChoicePrefixNameError(s);
@@ -74,6 +83,15 @@ ChoiceNameWithPrefixValidator::validate(const std::string & s)
break;
};
+ switch (s.at(0))
+ {
+ case ':':
+ case '_':
+ case '-':
+ throw ChoiceNameWithPrefixError(s);
+ break;
+ };
+
if (std::string::npos != s.find(" \t\r\n"))
throw ChoiceNameWithPrefixError(s);
}
@@ -97,6 +115,15 @@ UnprefixedChoiceNameValidator::validate(const std::string & s)
break;
};
+ switch (s.at(0))
+ {
+ case ':':
+ case '_':
+ case '-':
+ throw ChoiceNameWithPrefixError(s);
+ break;
+ };
+
if (std::string::npos != s.find(" \t\r\n"))
throw ChoiceNameWithPrefixError(s);
}
diff --git a/paludis/repositories/e/Makefile.am b/paludis/repositories/e/Makefile.am
index 08d30b6..872a023 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 \
+ myoptions_requirements_verifier.hh \
pipe_command_handler.hh \
source_uri_finder.hh \
traditional_layout.hh \
@@ -134,6 +135,7 @@ libpaludiserepository_@PALUDIS_PC_SLOT@_la_SOURCES = \
glsa.cc \
layout.cc \
manifest2_reader.cc \
+ myoptions_requirements_verifier.cc \
pipe_command_handler.cc \
registration.cc \
source_uri_finder.cc \
diff --git a/paludis/repositories/e/e_installed_repository_id.cc b/paludis/repositories/e/e_installed_repository_id.cc
index 9eeb980..4100d9d 100644
--- a/paludis/repositories/e/e_installed_repository_id.cc
+++ b/paludis/repositories/e/e_installed_repository_id.cc
@@ -950,7 +950,7 @@ EInstalledRepositoryID::make_choice_value(const std::tr1::shared_ptr<const Choic
name_with_prefix = stringify(v);
else
{
- char use_expand_separator(eapi()->supported()->ebuild_options()->use_expand_separator());
+ char use_expand_separator(eapi()->supported()->choices_options()->use_expand_separator());
if (! use_expand_separator)
throw InternalError(PALUDIS_HERE, "No use_expand_separator defined");
name_with_prefix = stringify(c->prefix()) + std::string(1, use_expand_separator) + stringify(v);
diff --git a/paludis/repositories/e/e_key.cc b/paludis/repositories/e/e_key.cc
index cbcc9fd..5bc46a0 100644
--- a/paludis/repositories/e/e_key.cc
+++ b/paludis/repositories/e/e_key.cc
@@ -944,13 +944,16 @@ namespace
void visit_leaf(const PlainTextDepSpec & s)
{
+ if (s.text().empty())
+ return;
+
Context context("When handling item '" + stringify(s) + "':");
Prefixes::iterator p(prefixes.find(*current_prefix_stack.begin()));
if (p == prefixes.end())
p = prefixes.insert(std::make_pair(*current_prefix_stack.begin(), Values())).first;
- UnprefixedChoiceName n(s.text());
+ UnprefixedChoiceName n('-' == s.text().at(0) ? s.text().substr(1) : s.text());
Values::iterator v(p->second.find(n));
if (v == p->second.end())
v = p->second.insert(std::make_pair(n, Annotations())).first;
@@ -970,12 +973,7 @@ namespace
}
Annotations::iterator a(v->second.find(mm->raw_name()));
- if ((a != v->second.end()) && a->second != mm->value())
- Log::get_instance()->message("e_key.myoptions.duplicate", ll_qa, lc_context)
- << "Annotation '" << mm->raw_name() << "' set to both '" << a->second << "' and '"
- << mm->value() << "'";
- else
- v->second.insert(make_pair(mm->raw_name(), mm->value()));
+ v->second.insert(make_pair(mm->raw_name(), mm->value()));
}
}
}
@@ -989,8 +987,9 @@ namespace
PlainTextSpecTree::ConstSequenceIterator cur,
PlainTextSpecTree::ConstSequenceIterator end)
{
- if (cur != end)
- throw InternalError(PALUDIS_HERE, "Don't know how to handle conditionals here yet");
+ current_prefix_stack.push_front(*current_prefix_stack.begin());
+ std::for_each(cur, end, accept_visitor(*this));
+ current_prefix_stack.pop_front();
}
void visit_sequence(const AllDepSpec &,
@@ -1016,9 +1015,6 @@ namespace
{
if (a->first == id->eapi()->supported()->annotations()->myoptions_description())
description = a->second;
- else
- Log::get_instance()->message("e_key.myoptions.unknown", ll_qa, lc_context)
- << "Unknown annotation '" << a->first << "' = '" << a->second << "'";
}
return id->make_choice_value(choice, v->first, s, b, description, false);
}
@@ -1111,7 +1107,7 @@ EChoicesKey::value() const
Context local_context("When using raw_iuse_key and raw_use_key to populate choices:");
std::map<ChoiceNameWithPrefix, Tribool> i_values;
- std::string delim(1, _imp->id->eapi()->supported()->ebuild_options()->use_expand_separator());
+ std::string delim(1, _imp->id->eapi()->supported()->choices_options()->use_expand_separator());
if (_imp->id->raw_iuse_key())
{
diff --git a/paludis/repositories/e/eapi.cc b/paludis/repositories/e/eapi.cc
index d79b93d..b68fa5e 100644
--- a/paludis/repositories/e/eapi.cc
+++ b/paludis/repositories/e/eapi.cc
@@ -168,7 +168,6 @@ namespace
value_for<n::source_merged_variables>(check_get(k, "source_merged_variables")),
value_for<n::support_eclasses>(destringify_key<bool>(k, "support_eclasses")),
value_for<n::support_exlibs>(destringify_key<bool>(k, "support_exlibs")),
- value_for<n::use_expand_separator>(destringify_key<char>(k, "use_expand_separator")),
value_for<n::utility_path_suffixes>(check_get(k, "utility_path_suffixes")),
value_for<n::vdb_from_env_unless_empty_variables>(check_get(k, "vdb_from_env_unless_empty_variables")),
value_for<n::vdb_from_env_variables>(check_get(k, "vdb_from_env_variables")),
@@ -179,6 +178,7 @@ namespace
std::tr1::shared_ptr<const EAPIEbuildPhases> make_ebuild_phases(const KeyValueConfigFile & k)
{
return make_shared_ptr(new EAPIEbuildPhases(make_named_values<EAPIEbuildPhases>(
+ value_for<n::ebuild_bad_options>(check_get(k, "ebuild_bad_options")),
value_for<n::ebuild_config>(check_get(k, "ebuild_config")),
value_for<n::ebuild_info>(check_get(k, "ebuild_info")),
value_for<n::ebuild_install>(check_get(k, "ebuild_install")),
@@ -213,7 +213,8 @@ namespace
std::tr1::shared_ptr<const EAPIAnnotations> make_annotations(const KeyValueConfigFile & k)
{
return make_shared_ptr(new EAPIAnnotations(make_named_values<EAPIAnnotations>(
- value_for<n::myoptions_description>(k.get("annotations_myoptions_description"))
+ value_for<n::myoptions_description>(k.get("annotations_myoptions_description")),
+ value_for<n::myoptions_requires>(k.get("annotations_myoptions_requires"))
)));
}
@@ -222,7 +223,8 @@ namespace
return make_shared_ptr(new EAPIChoicesOptions(make_named_values<EAPIChoicesOptions>(
value_for<n::fancy_test_flag>(check_get(k, "fancy_test_flag")),
value_for<n::has_optional_tests>(destringify_key<bool>(k, "has_optional_tests")),
- value_for<n::has_recommended_tests>(destringify_key<bool>(k, "has_recommended_tests"))
+ value_for<n::has_recommended_tests>(destringify_key<bool>(k, "has_recommended_tests")),
+ value_for<n::use_expand_separator>(destringify_key<char>(k, "use_expand_separator"))
)));
}
diff --git a/paludis/repositories/e/eapi.hh b/paludis/repositories/e/eapi.hh
index ebd575f..7b6fa24 100644
--- a/paludis/repositories/e/eapi.hh
+++ b/paludis/repositories/e/eapi.hh
@@ -57,6 +57,7 @@ namespace paludis
struct doman_lang_filenames;
struct dosym_mkdir;
struct eapi;
+ struct ebuild_bad_options;
struct ebuild_config;
struct ebuild_environment_variables;
struct ebuild_functions;
@@ -111,6 +112,7 @@ namespace paludis
struct minimum_flat_list_size;
struct myoptions;
struct myoptions_description;
+ struct myoptions_requires;
struct must_not_change_variables;
struct name;
struct no_slot_or_repo;
@@ -247,6 +249,7 @@ namespace paludis
NamedValue<n::fancy_test_flag, std::string> fancy_test_flag;
NamedValue<n::has_optional_tests, bool> has_optional_tests;
NamedValue<n::has_recommended_tests, bool> has_recommended_tests;
+ NamedValue<n::use_expand_separator, char> use_expand_separator;
};
struct EAPIEbuildEnvironmentVariables
@@ -335,7 +338,6 @@ namespace paludis
NamedValue<n::source_merged_variables, std::string> source_merged_variables;
NamedValue<n::support_eclasses, bool> support_eclasses;
NamedValue<n::support_exlibs, bool> support_exlibs;
- NamedValue<n::use_expand_separator, char> use_expand_separator;
NamedValue<n::utility_path_suffixes, std::string> utility_path_suffixes;
NamedValue<n::vdb_from_env_unless_empty_variables, std::string> vdb_from_env_unless_empty_variables;
NamedValue<n::vdb_from_env_variables, std::string> vdb_from_env_variables;
@@ -344,6 +346,7 @@ namespace paludis
struct EAPIEbuildPhases
{
+ NamedValue<n::ebuild_bad_options, std::string> ebuild_bad_options;
NamedValue<n::ebuild_config, std::string> ebuild_config;
NamedValue<n::ebuild_info, std::string> ebuild_info;
NamedValue<n::ebuild_install, std::string> ebuild_install;
@@ -373,6 +376,7 @@ namespace paludis
struct EAPIAnnotations
{
NamedValue<n::myoptions_description, std::string> myoptions_description;
+ NamedValue<n::myoptions_requires, std::string> myoptions_requires;
};
}
#endif
diff --git a/paludis/repositories/e/eapis/exheres-0.conf b/paludis/repositories/e/eapis/exheres-0.conf
index 05fb3b6..e869cf3 100644
--- a/paludis/repositories/e/eapis/exheres-0.conf
+++ b/paludis/repositories/e/eapis/exheres-0.conf
@@ -100,7 +100,7 @@ ebuild_functions = \
builtin_killoldmisc builtin_saveenv builtin_tidyup builtin_tidyuprm \
builtin_tidyupmisc builtin_variable \
pkg_config pkg_info pkg_nofetch pkg_postinst pkg_postrm \
- pkg_preinst pkg_prerm pkg_pretend pkg_setup \
+ pkg_preinst pkg_prerm pkg_pretend pkg_setup pkg_bad_options \
src_compile src_configure src_install src_prepare src_test src_unpack
ebuild_install = \
@@ -126,6 +126,9 @@ ebuild_uninstall = \
ebuild_pretend = \
sandbox userpriv : pretend
+ebuild_bad_options = \
+ sandbox userpriv : bad_options
+
ebuild_info = \
: killoldmisc ; \
sandbox userpriv : initmisc infovars info ; \
@@ -285,4 +288,5 @@ dosym_mkdir = false
failure_is_fatal = true
annotations_myoptions_description = description
+annotations_myoptions_requires = requires
diff --git a/paludis/repositories/e/ebuild.cc b/paludis/repositories/e/ebuild.cc
index c1f155e..9be3a47 100644
--- a/paludis/repositories/e/ebuild.cc
+++ b/paludis/repositories/e/ebuild.cc
@@ -1053,3 +1053,55 @@ WriteBinaryEbuildCommand::operator() ()
throw InstallActionError("Write binary command failed");
}
+std::string
+EbuildBadOptionsCommand::commands() const
+{
+ return params.commands();
+}
+
+bool
+EbuildBadOptionsCommand::failure()
+{
+ return false;
+}
+
+Command
+EbuildBadOptionsCommand::extend_command(const Command & cmd)
+{
+ Command result(Command(cmd)
+ .with_setenv("ROOT", bad_options_params.root())
+ .with_setenv("PALUDIS_PROFILE_DIR", stringify(*bad_options_params.profiles()->begin()))
+ .with_setenv("PALUDIS_PROFILE_DIRS", join(bad_options_params.profiles()->begin(),
+ bad_options_params.profiles()->end(), " "))
+ .with_setenv("EX_UNMET_REQUIREMENTS", join(bad_options_params.unmet_requirements()->begin(),
+ bad_options_params.unmet_requirements()->end(), "\n"))
+ );
+
+ if (! params.package_id()->eapi()->supported()->ebuild_environment_variables()->env_use().empty())
+ result.with_setenv(params.package_id()->eapi()->supported()->ebuild_environment_variables()->env_use(),
+ bad_options_params.use());
+ if (! params.package_id()->eapi()->supported()->ebuild_environment_variables()->env_use_expand().empty())
+ result.with_setenv(params.package_id()->eapi()->supported()->ebuild_environment_variables()->env_use_expand(),
+ bad_options_params.use_expand());
+ if (! params.package_id()->eapi()->supported()->ebuild_environment_variables()->env_use_expand_hidden().empty())
+ result.with_setenv(params.package_id()->eapi()->supported()->ebuild_environment_variables()->env_use_expand_hidden(),
+ bad_options_params.use_expand_hidden());
+
+ for (Map<std::string, std::string>::ConstIterator
+ i(bad_options_params.expand_vars()->begin()),
+ j(bad_options_params.expand_vars()->end()) ; i != j ; ++i)
+ result.with_setenv(i->first, i->second);
+
+ result.with_uid_gid(params.environment()->reduced_uid(), params.environment()->reduced_gid());
+
+ return result;
+}
+
+EbuildBadOptionsCommand::EbuildBadOptionsCommand(const EbuildCommandParams & p,
+ const EbuildBadOptionsCommandParams & f) :
+ EbuildCommand(p),
+ bad_options_params(f)
+{
+}
+
+
diff --git a/paludis/repositories/e/ebuild.hh b/paludis/repositories/e/ebuild.hh
index ec0543d..d580646 100644
--- a/paludis/repositories/e/ebuild.hh
+++ b/paludis/repositories/e/ebuild.hh
@@ -74,6 +74,7 @@ namespace paludis
struct sandbox;
struct slot;
struct unmerge_only;
+ struct unmet_requirements;
struct use;
struct use_ebuild_file;
struct use_expand;
@@ -170,6 +171,24 @@ namespace paludis
};
/**
+ * Parameters for an EbuildBadOptionsCommand.
+ *
+ * \see EbuildBadOptionsCommand
+ * \ingroup grpebuildinterface
+ * \nosubgrouping
+ */
+ struct EbuildBadOptionsCommandParams
+ {
+ NamedValue<n::expand_vars, std::tr1::shared_ptr<const Map<std::string, std::string> > > expand_vars;
+ NamedValue<n::profiles, std::tr1::shared_ptr<const FSEntrySequence> > profiles;
+ NamedValue<n::root, std::string> root;
+ NamedValue<n::unmet_requirements, std::tr1::shared_ptr<const Sequence<std::string> > > unmet_requirements;
+ NamedValue<n::use, std::string> use;
+ NamedValue<n::use_expand, std::string> use_expand;
+ NamedValue<n::use_expand_hidden, std::string> use_expand_hidden;
+ };
+
+ /**
* Parameters for an EbuildUninstallCommand.
*
* \see EbuildUninstallCommand
@@ -511,6 +530,32 @@ namespace paludis
};
/**
+ * An EbuildBadOptionsCommand is used to handle unmet MYOPTIONS requirements for
+ * a package in ERepository.
+ *
+ * \ingroup grpebuildinterface
+ */
+ class EbuildBadOptionsCommand :
+ public EbuildCommand
+ {
+ protected:
+ /// Parameters for config.
+ const EbuildBadOptionsCommandParams bad_options_params;
+
+ virtual std::string commands() const;
+
+ virtual bool failure();
+
+ virtual Command extend_command(const Command &);
+
+ public:
+ /**
+ * Constructor.
+ */
+ EbuildBadOptionsCommand(const EbuildCommandParams &, const EbuildBadOptionsCommandParams &);
+ };
+
+ /**
* An EbuildInfoCommand is used to obtain information from a package.
*
* \ingroup grpebuildinterface
diff --git a/paludis/repositories/e/ebuild/ebuild.bash b/paludis/repositories/e/ebuild/ebuild.bash
index 1a1d6a6..c714584 100755
--- a/paludis/repositories/e/ebuild/ebuild.bash
+++ b/paludis/repositories/e/ebuild/ebuild.bash
@@ -146,7 +146,7 @@ done
builtin_killoldmisc builtin_saveenv builtin_tidyup builtin_tidyuprm
builtin_tidyupmisc builtin_variable
pkg_config pkg_info pkg_nofetch pkg_postinst pkg_postrm
- pkg_preinst pkg_prerm pkg_pretend pkg_setup
+ pkg_preinst pkg_prerm pkg_pretend pkg_setup pkg_bad_options
src_compile src_configure src_install src_prepare src_test src_unpack"
check_paludis_pipe_command()
@@ -443,7 +443,8 @@ ebuild_main()
if [[ ${#@} -ge 2 ]] ; then
ebuild_section "Running ebuild phases $@ as $(id -un ):$(id -gn )..."
- elif [[ ${1} != variable ]] && [[ ${1} != metadata ]] && [[ ${1} != pretend ]] ; then
+ elif [[ ${1} != variable ]] && [[ ${1} != metadata ]] && \
+ [[ ${1} != pretend ]] && [[ ${1} != bad_options ]] ; then
ebuild_section "Running ebuild phase $@ as $(id -un ):$(id -gn )..."
fi
@@ -451,7 +452,8 @@ ebuild_main()
ebuild_load_module $(paludis_phase_to_function_name "${action}")
done
- if [[ $1 == metadata ]] || [[ $1 == variable ]] || [[ $1 == pretend ]] ; then
+ if [[ $1 == metadata ]] || [[ $1 == variable ]] || [[ $1 == pretend ]] || \
+ [[ $1 == bad_options ]] ; then
export EBUILD_PHASE="${1}"
perform_hook ebuild_${action}_pre
if [[ $1 != variable ]] || [[ -n "${EBUILD}" ]] ; then
@@ -484,7 +486,8 @@ ebuild_main()
if [[ ${#@} -ge 2 ]] ; then
ebuild_section "Completed ebuild phases $@"
- elif [[ ${1} != variable ]] && [[ ${1} != metadata ]] && [[ ${1} != pretend ]] ; then
+ elif [[ ${1} != variable ]] && [[ ${1} != metadata ]] && \
+ [[ ${1} != pretend ]] && [[ ${1} != bad_options ]] ; then
ebuild_section "Completed ebuild phase $@"
fi
}
diff --git a/paludis/repositories/e/ebuild/exheres-0/Makefile.am b/paludis/repositories/e/ebuild/exheres-0/Makefile.am
index c97b58a..841960e 100644
--- a/paludis/repositories/e/ebuild/exheres-0/Makefile.am
+++ b/paludis/repositories/e/ebuild/exheres-0/Makefile.am
@@ -25,6 +25,7 @@ libexecprogexheres_SCRIPTS = \
exlib_functions.bash \
list_functions.bash \
output_functions.bash \
+ pkg_bad_options.bash \
pkg_config.bash \
pkg_info.bash \
pkg_nofetch.bash \
diff --git a/paludis/repositories/e/ebuild/exheres-0/pkg_bad_options.bash b/paludis/repositories/e/ebuild/exheres-0/pkg_bad_options.bash
new file mode 100644
index 0000000..328b838
--- /dev/null
+++ b/paludis/repositories/e/ebuild/exheres-0/pkg_bad_options.bash
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2007, 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
+
+default_pkg_bad_options()
+{
+ eerror "The following option requirements are unmet for ${CATEGORY}/${PNVR}:"
+ local f
+ echo "${EX_UNMET_REQUIREMENTS}" | while IFS=$'\n' read f ; do
+ eerror " ${f}"
+ done
+}
+
+pkg_bad_options()
+{
+ default "$@"
+}
+
+exheres_internal_bad_options()
+{
+ if hasq "bad_options" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping pkg_bad_options (SKIP_FUNCTIONS)"
+ else
+ echo
+ pkg_bad_options
+ echo
+ fi
+
+ true
+}
+
diff --git a/paludis/repositories/e/ebuild_entries.cc b/paludis/repositories/e/ebuild_entries.cc
index 424beef..8f34146 100644
--- a/paludis/repositories/e/ebuild_entries.cc
+++ b/paludis/repositories/e/ebuild_entries.cc
@@ -30,6 +30,7 @@
#include <paludis/repositories/e/check_fetched_files_visitor.hh>
#include <paludis/repositories/e/aa_visitor.hh>
#include <paludis/repositories/e/e_stripper.hh>
+#include <paludis/repositories/e/myoptions_requirements_verifier.hh>
#include <paludis/action.hh>
#include <paludis/dep_spec_flattener.hh>
@@ -937,9 +938,13 @@ EbuildEntries::pretend(const std::tr1::shared_ptr<const ERepositoryID> & id,
Context context("When running pretend for '" + stringify(*id) + "':");
if (! id->eapi()->supported())
- return true;
- if (id->eapi()->supported()->ebuild_phases()->ebuild_pretend().empty())
- return true;
+ return false;
+
+ bool result(true);
+
+ if (! id->raw_myoptions_key())
+ if (id->eapi()->supported()->ebuild_phases()->ebuild_pretend().empty())
+ return result;
bool userpriv_restrict;
{
@@ -962,6 +967,60 @@ EbuildEntries::pretend(const std::tr1::shared_ptr<const ERepositoryID> & id,
std::tr1::shared_ptr<const FSEntrySequence> exlibsdirs(_imp->e_repository->layout()->exlibsdirs(id->name()));
+ if (id->raw_myoptions_key())
+ {
+ MyOptionsRequirementsVerifier verifier(id);
+ id->raw_myoptions_key()->value()->accept(verifier);
+
+ if (verifier.unmet_requirements() && ! verifier.unmet_requirements()->empty())
+ {
+ EAPIPhases phases(id->eapi()->supported()->ebuild_phases()->ebuild_bad_options());
+ if (phases.begin_phases() == phases.end_phases())
+ throw InternalError(PALUDIS_HERE, "using myoptions but no ebuild_bad_options phase");
+
+ for (EAPIPhases::ConstIterator phase(phases.begin_phases()), phase_end(phases.end_phases()) ;
+ phase != phase_end ; ++phase)
+ {
+ EbuildCommandParams command_params(make_named_values<EbuildCommandParams>(
+ value_for<n::builddir>(_imp->params.builddir),
+ value_for<n::commands>(join(phase->begin_commands(), phase->end_commands(), " ")),
+ value_for<n::distdir>(_imp->params.distdir),
+ value_for<n::ebuild_dir>(_imp->e_repository->layout()->package_directory(id->name())),
+ value_for<n::ebuild_file>(id->fs_location_key()->value()),
+ value_for<n::eclassdirs>(_imp->params.eclassdirs),
+ value_for<n::environment>(_imp->params.environment),
+ value_for<n::exlibsdirs>(exlibsdirs),
+ value_for<n::files_dir>(_imp->e_repository->layout()->package_directory(id->name()) / "files"),
+ value_for<n::package_id>(id),
+ value_for<n::portdir>(
+ (_imp->params.master_repositories && ! _imp->params.master_repositories->empty()) ?
+ (*_imp->params.master_repositories->begin())->params().location : _imp->params.location),
+ value_for<n::sandbox>(phase->option("sandbox")),
+ value_for<n::userpriv>(phase->option("userpriv") && userpriv_ok)
+ ));
+
+ EbuildBadOptionsCommand bad_options_cmd(command_params,
+ make_named_values<EbuildBadOptionsCommandParams>(
+ value_for<n::expand_vars>(expand_vars),
+ value_for<n::profiles>(_imp->params.profiles),
+ value_for<n::root>(stringify(_imp->params.environment->root())),
+ value_for<n::unmet_requirements>(verifier.unmet_requirements()),
+ value_for<n::use>(use),
+ value_for<n::use_expand>(join(p->use_expand()->begin(), p->use_expand()->end(), " ")),
+ value_for<n::use_expand_hidden>(join(p->use_expand_hidden()->begin(), p->use_expand_hidden()->end(), " "))
+ ));
+
+ if (! bad_options_cmd())
+ throw ActionError("Bad options phase died");
+ }
+
+ result = false;
+ }
+ }
+
+ if (id->eapi()->supported()->ebuild_phases()->ebuild_pretend().empty())
+ return result;
+
EAPIPhases phases(id->eapi()->supported()->ebuild_phases()->ebuild_pretend());
for (EAPIPhases::ConstIterator phase(phases.begin_phases()), phase_end(phases.end_phases()) ;
phase != phase_end ; ++phase)
@@ -998,7 +1057,7 @@ EbuildEntries::pretend(const std::tr1::shared_ptr<const ERepositoryID> & id,
return false;
}
- return true;
+ return result;
}
std::string
diff --git a/paludis/repositories/e/ebuild_id.cc b/paludis/repositories/e/ebuild_id.cc
index 5f05f9e..44db25e 100644
--- a/paludis/repositories/e/ebuild_id.cc
+++ b/paludis/repositories/e/ebuild_id.cc
@@ -1110,7 +1110,7 @@ EbuildID::make_choice_value(
name_with_prefix_s = stringify(value_name);
else
{
- char use_expand_separator(eapi()->supported()->ebuild_options()->use_expand_separator());
+ char use_expand_separator(eapi()->supported()->choices_options()->use_expand_separator());
if (! use_expand_separator)
throw InternalError(PALUDIS_HERE, "No use_expand_separator defined");
name_with_prefix_s = stringify(choice->prefix()) + std::string(1, use_expand_separator) + stringify(value_name);
diff --git a/paludis/repositories/e/myoptions_requirements_verifier.cc b/paludis/repositories/e/myoptions_requirements_verifier.cc
new file mode 100644
index 0000000..b090be6
--- /dev/null
+++ b/paludis/repositories/e/myoptions_requirements_verifier.cc
@@ -0,0 +1,231 @@
+/* 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/myoptions_requirements_verifier.hh>
+#include <paludis/repositories/e/e_repository_id.hh>
+#include <paludis/repositories/e/eapi.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <paludis/util/visitor-impl.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/visitor_cast.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/set.hh>
+#include <paludis/choice.hh>
+#include <paludis/metadata_key.hh>
+#include <algorithm>
+#include <list>
+
+using namespace paludis;
+using namespace paludis::erepository;
+
+namespace paludis
+{
+ template <>
+ struct Implementation<MyOptionsRequirementsVerifier>
+ {
+ const std::tr1::shared_ptr<const ERepositoryID> id;
+
+ std::tr1::shared_ptr<Sequence<std::string> > unmet_requirements;
+ std::list<ChoicePrefixName> current_prefix_stack;
+
+ Implementation(const std::tr1::shared_ptr<const ERepositoryID> & i) :
+ id(i),
+ unmet_requirements(new Sequence<std::string>)
+ {
+ current_prefix_stack.push_front(ChoicePrefixName(""));
+ }
+ };
+}
+
+MyOptionsRequirementsVerifier::MyOptionsRequirementsVerifier(const std::tr1::shared_ptr<const ERepositoryID> & id) :
+ PrivateImplementationPattern<MyOptionsRequirementsVerifier>(new Implementation<MyOptionsRequirementsVerifier>(id))
+{
+}
+
+MyOptionsRequirementsVerifier::~MyOptionsRequirementsVerifier()
+{
+}
+
+const std::tr1::shared_ptr<const Sequence<std::string> >
+MyOptionsRequirementsVerifier::unmet_requirements() const
+{
+ return _imp->unmet_requirements;
+}
+
+void
+MyOptionsRequirementsVerifier::visit_leaf(const PlainTextLabelDepSpec & s)
+{
+ *_imp->current_prefix_stack.begin() = ChoicePrefixName(s.label());
+}
+
+void
+MyOptionsRequirementsVerifier::visit_leaf(const PlainTextDepSpec & s)
+{
+ Context context("When verifying requirements for item '" + stringify(s) + "':");
+
+ if (! s.annotations_key())
+ return;
+
+ bool active_flag_state(s.text().at(0) != '-');
+ 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(s.text().substr(active_flag_state ? 0 : 1)));
+
+ {
+ 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() != *_imp->current_prefix_stack.begin())
+ 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;
+ }
+
+ if (choice_value)
+ {
+ if (choice_value->enabled() != active_flag_state)
+ return;
+ }
+ else
+ {
+ /* weird ick */
+ _imp->unmet_requirements->push_back("Can't work out the state of option '" + stringify(active_flag) + "'");
+ return;
+ }
+ }
+
+ 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_description())
+ {
+ }
+ else if (a_key == _imp->id->eapi()->supported()->annotations()->myoptions_requires())
+ {
+ std::list<std::string> tokens;
+ tokenise_whitespace(a_value, std::back_inserter(tokens));
+ ChoicePrefixName prefix("");
+ for (std::list<std::string>::const_iterator t(tokens.begin()), t_end(tokens.end()) ;
+ t != t_end ; ++t)
+ {
+ if (t->empty())
+ continue;
+
+ if (':' == t->at(t->length() - 1))
+ {
+ prefix = ChoicePrefixName(t->substr(0, t->length() - 1));
+ continue;
+ }
+
+ bool req_state(true);
+ std::string req_flag_s(*t);
+ if ('-' == req_flag_s.at(0))
+ {
+ req_state = false;
+ req_flag_s.erase(0, 1);
+ }
+
+ UnprefixedChoiceName suffix(req_flag_s);
+
+ 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() != prefix)
+ continue;
+
+ for (Choice::ConstIterator i((*k)->begin()), i_end((*k)->end()) ;
+ i != i_end && ! choice_value ; ++i)
+ if ((*i)->unprefixed_name() == suffix)
+ choice_value = *i;
+ }
+
+ if (choice_value)
+ {
+ if (choice_value->enabled() != req_state)
+ {
+ _imp->unmet_requirements->push_back(stringify(active_flag_state ? "Enabling" : "Disabling") +
+ " option '" + stringify(active_flag) + "' requires option '" +
+ stringify(choice_value->name_with_prefix()) + "' to be " +
+ (req_state ? "enabled" : "disabled"));
+ }
+ }
+ else
+ {
+ /* 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") +
+ " option '" + stringify(active_flag) + "' requires option '" + stringify(qualified_flag_name) + "' to be " +
+ (req_state ? "enabled" : "disabled") + ", but no such option exists");
+ }
+ }
+ }
+ else
+ Log::get_instance()->message("e.myoptions_requirements_verifier.unknown_annotation", ll_warning, lc_context)
+ << "Unknown annotation '" << a_key << "' = '" << a_value << "' on option '" << s << "'";
+ }
+}
+
+void
+MyOptionsRequirementsVerifier::visit_sequence(const ConditionalDepSpec & spec,
+ PlainTextSpecTree::ConstSequenceIterator cur,
+ PlainTextSpecTree::ConstSequenceIterator end)
+{
+ if (spec.condition_met())
+ {
+ _imp->current_prefix_stack.push_front(*_imp->current_prefix_stack.begin());
+ std::for_each(cur, end, accept_visitor(*this));
+ _imp->current_prefix_stack.pop_front();
+ }
+}
+
+void
+MyOptionsRequirementsVerifier::visit_sequence(const AllDepSpec &,
+ PlainTextSpecTree::ConstSequenceIterator cur,
+ PlainTextSpecTree::ConstSequenceIterator end)
+{
+ _imp->current_prefix_stack.push_front(*_imp->current_prefix_stack.begin());
+ std::for_each(cur, end, accept_visitor(*this));
+ _imp->current_prefix_stack.pop_front();
+}
+
+template class PrivateImplementationPattern<MyOptionsRequirementsVerifier>;
+
diff --git a/paludis/repositories/e/myoptions_requirements_verifier.hh b/paludis/repositories/e/myoptions_requirements_verifier.hh
new file mode 100644
index 0000000..20e26d2
--- /dev/null
+++ b/paludis/repositories/e/myoptions_requirements_verifier.hh
@@ -0,0 +1,67 @@
+/* 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_MYOPTIONS_REQUIREMENTS_VERIFIER_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_E_MYOPTIONS_REQUIREMENTS_VERIFIER_HH 1
+
+#include <paludis/repositories/e/e_repository_id.hh>
+#include <paludis/util/visitor.hh>
+#include <paludis/util/sequence.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/attributes.hh>
+#include <paludis/dep_spec.hh>
+#include <paludis/dep_tree.hh>
+#include <tr1/memory>
+
+namespace paludis
+{
+ namespace erepository
+ {
+ class PALUDIS_VISIBLE MyOptionsRequirementsVerifier :
+ private PrivateImplementationPattern<MyOptionsRequirementsVerifier>,
+ public ConstVisitor<PlainTextSpecTree>
+ {
+ public:
+ MyOptionsRequirementsVerifier(const std::tr1::shared_ptr<const ERepositoryID> &);
+ ~MyOptionsRequirementsVerifier();
+
+ const std::tr1::shared_ptr<const Sequence<std::string> > unmet_requirements() const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ void visit_leaf(const PlainTextLabelDepSpec &);
+
+ void visit_leaf(const PlainTextDepSpec &);
+
+ void visit_sequence(const ConditionalDepSpec &,
+ PlainTextSpecTree::ConstSequenceIterator,
+ PlainTextSpecTree::ConstSequenceIterator
+ );
+
+ void visit_sequence(const AllDepSpec &,
+ PlainTextSpecTree::ConstSequenceIterator,
+ PlainTextSpecTree::ConstSequenceIterator
+ );
+ };
+ }
+
+#ifdef PALUDIS_HAVE_EXTERN_TEMPLATE
+ extern template class PrivateImplementationPattern<erepository::MyOptionsRequirementsVerifier>;
+#endif
+}
+
+#endif