diff options
author | 2010-12-05 16:14:14 +0000 | |
---|---|---|
committer | 2010-12-05 21:19:06 +0000 | |
commit | 74d54724984bc1b3fa49414995151edfe031e368 (patch) | |
tree | 1c72f0f666f9dfe358ff794533ebee152c16dd57 | |
parent | d97eebaccb30a9669471516db9e7243420cbae47 (diff) | |
download | paludis-74d54724984bc1b3fa49414995151edfe031e368.tar.gz paludis-74d54724984bc1b3fa49414995151edfe031e368.tar.xz |
Split things up
20 files changed, 1788 insertions, 1148 deletions
diff --git a/paludis/repositories/e/Makefile.am b/paludis/repositories/e/Makefile.am index b71a2aa4f..52fe10f56 100644 --- a/paludis/repositories/e/Makefile.am +++ b/paludis/repositories/e/Makefile.am @@ -20,14 +20,21 @@ lib_LTLIBRARIES = libpaludiserepositoryxmlthings_@PALUDIS_PC_SLOT@.la endif noinst_HEADERS = \ + a_finder.hh \ aa_visitor.hh \ can_skip_phase.hh \ check_fetched_files_visitor.hh \ + check_userpriv.hh \ dep_parser.hh \ dep_parser-se.hh \ dep_parser-fwd.hh \ dep_spec_pretty_printer.hh \ dependencies_rewriter.hh \ + do_fetch_action.hh \ + do_info_action.hh \ + do_install_action.hh \ + do_pretend_action.hh \ + do_pretend_fetch_action.hh \ e_choice_value.hh \ e_installed_repository.hh \ e_installed_repository_id.hh \ @@ -63,6 +70,7 @@ noinst_HEADERS = \ fix_locked_dependencies.hh \ glsa.hh \ layout.hh \ + make_use.hh \ manifest2_reader.hh \ memoised_hashes.hh \ metadata_xml.hh \ @@ -84,12 +92,19 @@ noinst_HEADERS = \ vdb_unmerger.hh libpaludiserepository_la_SOURCES = \ + a_finder.cc \ aa_visitor.cc \ can_skip_phase.cc \ check_fetched_files_visitor.cc \ + check_userpriv.cc \ dep_parser.cc \ dep_spec_pretty_printer.cc \ dependencies_rewriter.cc \ + do_fetch_action.cc \ + do_info_action.cc \ + do_install_action.cc \ + do_pretend_action.cc \ + do_pretend_fetch_action.cc \ e_choice_value.cc \ e_installed_repository.cc \ e_installed_repository_id.cc \ @@ -122,6 +137,7 @@ libpaludiserepository_la_SOURCES = \ fix_locked_dependencies.cc \ glsa.cc \ layout.cc \ + make_use.cc \ manifest2_reader.cc \ memoised_hashes.cc \ metadata_xml.cc \ diff --git a/paludis/repositories/e/a_finder.cc b/paludis/repositories/e/a_finder.cc new file mode 100644 index 000000000..956d3e164 --- /dev/null +++ b/paludis/repositories/e/a_finder.cc @@ -0,0 +1,77 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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/a_finder.hh> +#include <paludis/util/indirect_iterator-impl.hh> +#include <paludis/util/accept_visitor.hh> +#include <algorithm> + +using namespace paludis; +using namespace paludis::erepository; + +AFinder::AFinder(const Environment * const e, const std::shared_ptr<const PackageID> & i) : + env(e), + id(i) +{ + _labels.push_back(0); +} + +void +AFinder::visit(const FetchableURISpecTree::NodeType<FetchableURIDepSpec>::Type & node) +{ + _specs.push_back(std::make_pair(node.spec().get(), *_labels.begin())); +} + +void +AFinder::visit(const FetchableURISpecTree::NodeType<URILabelsDepSpec>::Type & node) +{ + *_labels.begin() = node.spec().get(); +} + +void +AFinder::visit(const FetchableURISpecTree::NodeType<AllDepSpec>::Type & node) +{ + _labels.push_front(*_labels.begin()); + std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this)); + _labels.pop_front(); +} + +void +AFinder::visit(const FetchableURISpecTree::NodeType<ConditionalDepSpec>::Type & node) +{ + if (node.spec()->condition_met()) + { + _labels.push_front(*_labels.begin()); + std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this)); + _labels.pop_front(); + } +} + +AFinder::ConstIterator +AFinder::begin() +{ + return _specs.begin(); +} + +AFinder::ConstIterator +AFinder::end() const +{ + return _specs.end(); +} + diff --git a/paludis/repositories/e/a_finder.hh b/paludis/repositories/e/a_finder.hh new file mode 100644 index 000000000..f057a200a --- /dev/null +++ b/paludis/repositories/e/a_finder.hh @@ -0,0 +1,65 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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_A_FINDER_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_E_A_FINDER_HH 1 + +#include <paludis/dep_label.hh> +#include <paludis/environment.hh> +#include <paludis/package_id.hh> +#include <paludis/dep_spec.hh> +#include <paludis/spec_tree.hh> +#include <memory> +#include <list> + +namespace paludis +{ + namespace erepository + { + class AFinder + { + private: + std::list<std::pair<const FetchableURIDepSpec *, const URILabelsDepSpec *> > _specs; + std::list<const URILabelsDepSpec *> _labels; + + const Environment * const env; + const std::shared_ptr<const PackageID> id; + + public: + AFinder(const Environment * const e, const std::shared_ptr<const PackageID> & i); + + void visit(const FetchableURISpecTree::NodeType<FetchableURIDepSpec>::Type & node); + + void visit(const FetchableURISpecTree::NodeType<URILabelsDepSpec>::Type & node); + + void visit(const FetchableURISpecTree::NodeType<AllDepSpec>::Type & node); + + void visit(const FetchableURISpecTree::NodeType<ConditionalDepSpec>::Type & node); + + typedef std::list<std::pair<const FetchableURIDepSpec *, + const URILabelsDepSpec *> >::const_iterator ConstIterator; + + ConstIterator begin(); + + ConstIterator end() const; + }; + } +} + +#endif diff --git a/paludis/repositories/e/check_userpriv.cc b/paludis/repositories/e/check_userpriv.cc new file mode 100644 index 000000000..d7a0bac46 --- /dev/null +++ b/paludis/repositories/e/check_userpriv.cc @@ -0,0 +1,65 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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/check_userpriv.hh> +#include <paludis/util/exception.hh> +#include <paludis/util/system.hh> +#include <paludis/util/fs_stat.hh> +#include <paludis/util/stringify.hh> +#include <paludis/util/log.hh> +#include <paludis/environment.hh> + +using namespace paludis; +using namespace paludis::erepository; + +bool +paludis::erepository::check_userpriv(const FSPath & f, const Environment * env, bool mandatory) +{ + Context c("When checking permissions on '" + stringify(f) + "' for userpriv:"); + + if (! getenv_with_default("PALUDIS_BYPASS_USERPRIV_CHECKS", "").empty()) + return false; + + FSStat f_stat(f); + if (f_stat.exists()) + { + if (f_stat.group() != env->reduced_gid()) + { + if (mandatory) + throw ConfigurationError("Directory '" + stringify(f) + "' owned by group '" + get_group_name(f_stat.group()) + + "', not '" + get_group_name(env->reduced_gid()) + "'"); + else + Log::get_instance()->message("e.ebuild.userpriv_disabled", ll_warning, lc_context) << "Directory '" << + f << "' owned by group '" << get_group_name(f_stat.group()) << "', not '" + << get_group_name(env->reduced_gid()) << "', so cannot enable userpriv"; + return false; + } + else if (0 == (f_stat.permissions() & S_IWGRP)) + { + if (mandatory) + throw ConfigurationError("Directory '" + stringify(f) + "' does not have group write permission"); + else + Log::get_instance()->message("e.ebuild.userpriv_disabled", ll_warning, lc_context) << "Directory '" << + f << "' does not have group write permission, cannot enable userpriv"; + return false; + } + } + + return true; +} diff --git a/paludis/repositories/e/check_userpriv.hh b/paludis/repositories/e/check_userpriv.hh new file mode 100644 index 000000000..1caa3d727 --- /dev/null +++ b/paludis/repositories/e/check_userpriv.hh @@ -0,0 +1,36 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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_CHECK_USERPRIV_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_E_CHECK_USERPRIV_HH 1 + +#include <paludis/util/fs_path.hh> +#include <paludis/environment-fwd.hh> + +namespace paludis +{ + namespace erepository + { + bool + check_userpriv(const FSPath & f, const Environment * env, bool mandatory); + } +} + + +#endif diff --git a/paludis/repositories/e/do_fetch_action.cc b/paludis/repositories/e/do_fetch_action.cc new file mode 100644 index 000000000..aa61857b4 --- /dev/null +++ b/paludis/repositories/e/do_fetch_action.cc @@ -0,0 +1,312 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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/do_fetch_action.hh> +#include <paludis/repositories/e/eapi.hh> +#include <paludis/repositories/e/eapi_phase.hh> +#include <paludis/repositories/e/check_userpriv.hh> +#include <paludis/repositories/e/a_finder.hh> +#include <paludis/repositories/e/aa_visitor.hh> +#include <paludis/repositories/e/check_fetched_files_visitor.hh> +#include <paludis/repositories/e/fetch_visitor.hh> +#include <paludis/repositories/e/make_use.hh> +#include <paludis/repositories/e/can_skip_phase.hh> +#include <paludis/repositories/e/ebuild.hh> +#include <paludis/util/strip.hh> +#include <paludis/util/make_named_values.hh> +#include <paludis/util/sequence.hh> +#include <paludis/util/wrapped_output_iterator.hh> +#include <paludis/dep_spec_flattener.hh> +#include <paludis/metadata_key.hh> +#include <paludis/environment.hh> +#include <paludis/action.hh> +#include <paludis/output_manager.hh> + +#include <algorithm> +#include <set> + +using namespace paludis; +using namespace paludis::erepository; + +void +paludis::erepository::do_fetch_action( + const Environment * const env, + const ERepository * const repo, + const std::shared_ptr<const ERepositoryID> & id, + const FetchAction & fetch_action) +{ + using namespace std::placeholders; + + Context context("When fetching '" + stringify(*id) + "':"); + + bool fetch_restrict(false), userpriv_restrict(false); + { + DepSpecFlattener<PlainTextSpecTree, PlainTextDepSpec> restricts(env); + if (id->restrict_key()) + id->restrict_key()->value()->top()->accept(restricts); + + for (DepSpecFlattener<PlainTextSpecTree, PlainTextDepSpec>::ConstIterator i(restricts.begin()), i_end(restricts.end()) ; + i != i_end ; ++i) + { + if (id->eapi()->supported()->ebuild_options()->restrict_fetch()->end() != + std::find(id->eapi()->supported()->ebuild_options()->restrict_fetch()->begin(), + id->eapi()->supported()->ebuild_options()->restrict_fetch()->end(), (*i)->text())) + fetch_restrict = true; + if ("userpriv" == (*i)->text() || "nouserpriv" == (*i)->text()) + userpriv_restrict = true; + } + } + + bool fetch_userpriv_ok(env->reduced_gid() != getgid() && + check_userpriv(FSPath(repo->params().distdir()), env, + id->eapi()->supported()->userpriv_cannot_use_root())); + + std::string archives, all_archives; + { + std::set<std::string> already_in_archives; + + /* make A */ + AFinder f(env, id); + if (id->fetches_key()) + id->fetches_key()->value()->top()->accept(f); + + for (AFinder::ConstIterator i(f.begin()), i_end(f.end()) ; i != i_end ; ++i) + { + const FetchableURIDepSpec * const spec(static_cast<const FetchableURIDepSpec *>(i->first)); + + if (already_in_archives.end() == already_in_archives.find(spec->filename())) + { + archives.append(spec->filename()); + already_in_archives.insert(spec->filename()); + } + archives.append(" "); + } + + /* make AA */ + if (! id->eapi()->supported()->ebuild_environment_variables()->env_aa().empty()) + { + AAVisitor g; + if (id->fetches_key()) + id->fetches_key()->value()->top()->accept(g); + std::set<std::string> already_in_all_archives; + + for (AAVisitor::ConstIterator gg(g.begin()), gg_end(g.end()) ; gg != gg_end ; ++gg) + { + if (already_in_all_archives.end() == already_in_all_archives.find(*gg)) + { + all_archives.append(*gg); + already_in_all_archives.insert(*gg); + } + all_archives.append(" "); + } + } + else + all_archives = "AA-not-set-for-this-EAPI"; + } + + /* Strip trailing space. Some ebuilds rely upon this. From kde-meta.eclass: + * [[ -n ${A/${TARBALL}/} ]] && unpack ${A/${TARBALL}/} + * Rather annoying. + */ + archives = strip_trailing(archives, " "); + all_archives = strip_trailing(all_archives, " "); + + std::shared_ptr<OutputManager> output_manager(fetch_action.options.make_output_manager()(fetch_action)); + + CheckFetchedFilesVisitor c(env, id, repo->params().distdir(), + fetch_action.options.fetch_parts()[fp_unneeded], fetch_restrict, + ((repo->layout()->package_directory(id->name())) / "Manifest"), + repo->params().use_manifest(), + output_manager, fetch_action.options.exclude_unmirrorable(), + fetch_action.options.ignore_unfetched(), + fetch_action.options.ignore_not_in_manifest()); + + if (id->fetches_key()) + { + /* always use mirror://gentoo/, where gentoo is the name of our first master repository, + * or our name if there's no master. */ + std::string mirrors_name( + (repo->params().master_repositories() && ! repo->params().master_repositories()->empty()) ? + stringify((*repo->params().master_repositories()->begin())->name()) : + stringify(repo->name())); + + if (fetch_action.options.fetch_parts()[fp_regulars] && ! fetch_action.options.ignore_unfetched()) + { + FetchVisitor f(env, id, *id->eapi(), + repo->params().distdir(), fetch_action.options.fetch_parts()[fp_unneeded], + fetch_userpriv_ok, mirrors_name, + id->fetches_key()->initial_label(), fetch_action.options.safe_resume(), + output_manager, std::bind(&ERepository::get_mirrors, repo, std::placeholders::_1)); + id->fetches_key()->value()->top()->accept(f); + } + + id->fetches_key()->value()->top()->accept(c); + } + + if ( (fetch_action.options.fetch_parts()[fp_extras]) && ((c.need_nofetch()) || + ((! fetch_action.options.ignore_unfetched()) && (! id->eapi()->supported()->ebuild_phases()->ebuild_fetch_extra().empty())))) + { + bool userpriv_ok((! userpriv_restrict) && (env->reduced_gid() != getgid()) && + check_userpriv(FSPath(repo->params().builddir()), env, + id->eapi()->supported()->userpriv_cannot_use_root())); + std::string use(make_use(env, *id, repo->profile())); + std::shared_ptr<Map<std::string, std::string> > expand_vars(make_expand( + env, *id, repo->profile())); + + std::shared_ptr<const FSPathSequence> exlibsdirs(repo->layout()->exlibsdirs(id->name())); + + EAPIPhases fetch_extra_phases(id->eapi()->supported()->ebuild_phases()->ebuild_fetch_extra()); + if ((! fetch_action.options.ignore_unfetched()) && (fetch_extra_phases.begin_phases() != fetch_extra_phases.end_phases())) + { + FSPath package_builddir(repo->params().builddir() / (stringify(id->name().category()) + "-" + + stringify(id->name().package()) + "-" + stringify(id->version()) + "-fetch_extra")); + + for (EAPIPhases::ConstIterator phase(fetch_extra_phases.begin_phases()), phase_end(fetch_extra_phases.end_phases()) ; + phase != phase_end ; ++phase) + { + bool skip(false); + do + { + switch (fetch_action.options.want_phase()(phase->equal_option("skipname"))) + { + case wp_yes: + continue; + + case wp_skip: + skip = true; + continue; + + case wp_abort: + throw ActionAbortedError("Told to abort fetch"); + + case last_wp: + break; + } + + throw InternalError(PALUDIS_HERE, "bad want_phase"); + } while (false); + + if (skip) + continue; + + if (can_skip_phase(id, *phase)) + continue; + + EbuildCommandParams command_params(make_named_values<EbuildCommandParams>( + n::builddir() = repo->params().builddir(), + n::clearenv() = phase->option("clearenv"), + n::commands() = join(phase->begin_commands(), phase->end_commands(), " "), + n::distdir() = repo->params().distdir(), + n::ebuild_dir() = repo->layout()->package_directory(id->name()), + n::ebuild_file() = id->fs_location_key()->value(), + n::eclassdirs() = repo->params().eclassdirs(), + n::environment() = env, + n::exlibsdirs() = exlibsdirs, + n::files_dir() = repo->layout()->package_directory(id->name()) / "files", + n::maybe_output_manager() = output_manager, + n::package_builddir() = package_builddir, + n::package_id() = id, + n::portdir() = + (repo->params().master_repositories() && ! repo->params().master_repositories()->empty()) ? + (*repo->params().master_repositories()->begin())->params().location() : repo->params().location(), + n::root() = "/", + n::sandbox() = phase->option("sandbox"), + n::sydbox() = phase->option("sydbox"), + n::userpriv() = phase->option("userpriv") && userpriv_ok + )); + + EbuildFetchExtraCommand fetch_extra_cmd(command_params, make_named_values<EbuildFetchExtraCommandParams>( + n::a() = archives, + n::aa() = all_archives, + n::expand_vars() = expand_vars, + n::loadsaveenv_dir() = package_builddir / "temp", + n::profiles() = repo->params().profiles(), + n::profiles_with_parents() = repo->profile()->profiles_with_parents(), + n::slot() = id->slot_key() ? stringify(id->slot_key()->value()) : "", + n::use() = use, + n::use_expand() = join(repo->profile()->use_expand()->begin(), repo->profile()->use_expand()->end(), " "), + n::use_expand_hidden() = join(repo->profile()->use_expand_hidden()->begin(), repo->profile()->use_expand_hidden()->end(), " ") + )); + + if (! fetch_extra_cmd()) + throw ActionFailedError("Fetch of '" + stringify(*id) + "' failed"); + } + } + + if (c.need_nofetch()) + { + EAPIPhases phases(id->eapi()->supported()->ebuild_phases()->ebuild_nofetch()); + for (EAPIPhases::ConstIterator phase(phases.begin_phases()), phase_end(phases.end_phases()) ; + phase != phase_end ; ++phase) + { + EbuildCommandParams command_params(make_named_values<EbuildCommandParams>( + n::builddir() = repo->params().builddir(), + n::clearenv() = phase->option("clearenv"), + n::commands() = join(phase->begin_commands(), phase->end_commands(), " "), + n::distdir() = repo->params().distdir(), + n::ebuild_dir() = repo->layout()->package_directory(id->name()), + n::ebuild_file() = id->fs_location_key()->value(), + n::eclassdirs() = repo->params().eclassdirs(), + n::environment() = env, + n::exlibsdirs() = exlibsdirs, + n::files_dir() = repo->layout()->package_directory(id->name()) / "files", + n::maybe_output_manager() = output_manager, + n::package_builddir() = repo->params().builddir() / (stringify(id->name().category()) + "-" + stringify(id->name().package()) + "-" + stringify(id->version()) + "-nofetch"), + n::package_id() = id, + n::portdir() = (repo->params().master_repositories() && ! repo->params().master_repositories()->empty()) ? + (*repo->params().master_repositories()->begin())->params().location() : repo->params().location(), + n::root() = "/", + n::sandbox() = phase->option("sandbox"), + n::sydbox() = phase->option("sydbox"), + n::userpriv() = phase->option("userpriv") && userpriv_ok + )); + + EbuildNoFetchCommand nofetch_cmd(command_params, + make_named_values<EbuildNoFetchCommandParams>( + n::a() = archives, + n::aa() = all_archives, + n::expand_vars() = expand_vars, + n::profiles() = repo->params().profiles(), + n::profiles_with_parents() = repo->profile()->profiles_with_parents(), + n::use() = use, + n::use_expand() = join(repo->profile()->use_expand()->begin(), repo->profile()->use_expand()->end(), " "), + n::use_expand_hidden() = join(repo->profile()->use_expand_hidden()->begin(), repo->profile()->use_expand_hidden()->end(), " ") + )); + + if (! nofetch_cmd()) + { + std::copy(c.failures()->begin(), c.failures()->end(), + fetch_action.options.errors()->back_inserter()); + throw ActionFailedError("Fetch of '" + stringify(*id) + "' failed"); + } + } + } + } + + if (! c.failures()->empty()) + { + std::copy(c.failures()->begin(), c.failures()->end(), + fetch_action.options.errors()->back_inserter()); + throw ActionFailedError("Fetch of '" + stringify(*id) + "' failed"); + } + + output_manager->succeeded(); +} + + diff --git a/paludis/repositories/e/do_fetch_action.hh b/paludis/repositories/e/do_fetch_action.hh new file mode 100644 index 000000000..5234eee1b --- /dev/null +++ b/paludis/repositories/e/do_fetch_action.hh @@ -0,0 +1,41 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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_DO_FETCH_ACTION_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_E_DO_FETCH_ACTION_HH 1 + +#include <paludis/repositories/e/e_repository.hh> +#include <paludis/repositories/e/e_repository_id.hh> +#include <paludis/environment-fwd.hh> +#include <paludis/action-fwd.hh> + +namespace paludis +{ + namespace erepository + { + void + do_fetch_action( + const Environment * const env, + const ERepository * const repo, + const std::shared_ptr<const ERepositoryID> & id, + const FetchAction & fetch_action); + } +} + +#endif diff --git a/paludis/repositories/e/do_info_action.cc b/paludis/repositories/e/do_info_action.cc new file mode 100644 index 000000000..a2bacb0b4 --- /dev/null +++ b/paludis/repositories/e/do_info_action.cc @@ -0,0 +1,127 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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/do_info_action.hh> +#include <paludis/repositories/e/eapi.hh> +#include <paludis/repositories/e/eapi_phase.hh> +#include <paludis/repositories/e/check_userpriv.hh> +#include <paludis/repositories/e/make_use.hh> +#include <paludis/repositories/e/ebuild.hh> +#include <paludis/util/indirect_iterator-impl.hh> +#include <paludis/util/make_named_values.hh> +#include <paludis/dep_spec_flattener.hh> +#include <paludis/action.hh> +#include <paludis/metadata_key.hh> +#include <paludis/environment.hh> +#include <paludis/output_manager.hh> + +#include <algorithm> + +using namespace paludis; +using namespace paludis::erepository; + +void +paludis::erepository::do_info_action( + const Environment * const env, + const ERepository * const repo, + const std::shared_ptr<const ERepositoryID> & id, + const InfoAction & a) +{ + using namespace std::placeholders; + + Context context("When infoing '" + stringify(*id) + "':"); + + std::shared_ptr<OutputManager> output_manager(a.options.make_output_manager()(a)); + + bool userpriv_restrict; + { + DepSpecFlattener<PlainTextSpecTree, PlainTextDepSpec> restricts(env); + if (id->restrict_key()) + id->restrict_key()->value()->top()->accept(restricts); + + userpriv_restrict = + indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), + std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "userpriv")) || + indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), + std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "nouserpriv")); + } + bool userpriv_ok((! userpriv_restrict) && (env->reduced_gid() != getgid()) && + check_userpriv(FSPath(repo->params().builddir()), env, id->eapi()->supported()->userpriv_cannot_use_root())); + + /* make use */ + std::string use(make_use(env, *id, repo->profile())); + + /* add expand to use (iuse isn't reliable for use_expand things), and make the expand + * environment variables */ + std::shared_ptr<Map<std::string, std::string> > expand_vars(make_expand( + env, *id, repo->profile())); + + std::shared_ptr<const FSPathSequence> exlibsdirs(repo->layout()->exlibsdirs(id->name())); + + EAPIPhases phases(id->eapi()->supported()->ebuild_phases()->ebuild_info()); + for (EAPIPhases::ConstIterator phase(phases.begin_phases()), phase_end(phases.end_phases()) ; + phase != phase_end ; ++phase) + { + if (phase->option("installed=true")) + continue; + + EbuildCommandParams command_params(make_named_values<EbuildCommandParams>( + n::builddir() = repo->params().builddir(), + n::clearenv() = phase->option("clearenv"), + n::commands() = join(phase->begin_commands(), phase->end_commands(), " "), + n::distdir() = repo->params().distdir(), + n::ebuild_dir() = repo->layout()->package_directory(id->name()), + n::ebuild_file() = id->fs_location_key()->value(), + n::eclassdirs() = repo->params().eclassdirs(), + n::environment() = env, + n::exlibsdirs() = exlibsdirs, + n::files_dir() = repo->layout()->package_directory(id->name()) / "files", + n::maybe_output_manager() = output_manager, + n::package_builddir() = repo->params().builddir() / (stringify(id->name().category()) + "-" + stringify(id->name().package()) + "-" + stringify(id->version()) + "-info"), + n::package_id() = id, + n::portdir() = + (repo->params().master_repositories() && ! repo->params().master_repositories()->empty()) ? + (*repo->params().master_repositories()->begin())->params().location() : repo->params().location(), + n::root() = stringify(env->preferred_root_key()->value()), + n::sandbox() = phase->option("sandbox"), + n::sydbox() = phase->option("sydbox"), + n::userpriv() = phase->option("userpriv") && userpriv_ok + )); + + EbuildInfoCommandParams info_params( + make_named_values<EbuildInfoCommandParams>( + n::expand_vars() = expand_vars, + n::info_vars() = repo->info_vars_key() ? + repo->info_vars_key()->value() : std::make_shared<const Set<std::string>>(), + n::load_environment() = static_cast<const FSPath *>(0), + n::profiles() = repo->params().profiles(), + n::profiles_with_parents() = repo->profile()->profiles_with_parents(), + n::use() = use, + n::use_ebuild_file() = true, + n::use_expand() = join(repo->profile()->use_expand()->begin(), repo->profile()->use_expand()->end(), " "), + n::use_expand_hidden() = join(repo->profile()->use_expand_hidden()->begin(), repo->profile()->use_expand_hidden()->end(), " ") + )); + + EbuildInfoCommand cmd(command_params, info_params); + cmd(); + } + + output_manager->succeeded(); +} + diff --git a/paludis/repositories/e/do_info_action.hh b/paludis/repositories/e/do_info_action.hh new file mode 100644 index 000000000..d5ea31e58 --- /dev/null +++ b/paludis/repositories/e/do_info_action.hh @@ -0,0 +1,41 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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_DO_INFO_ACTION_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_E_DO_INFO_ACTION_HH 1 + +#include <paludis/repositories/e/e_repository.hh> +#include <paludis/repositories/e/e_repository_id.hh> +#include <paludis/environment-fwd.hh> +#include <paludis/action-fwd.hh> + +namespace paludis +{ + namespace erepository + { + void + do_info_action( + const Environment * const env, + const ERepository * const repo, + const std::shared_ptr<const ERepositoryID> & id, + const InfoAction & a); + } +} + +#endif diff --git a/paludis/repositories/e/do_install_action.cc b/paludis/repositories/e/do_install_action.cc new file mode 100644 index 000000000..ea848f37f --- /dev/null +++ b/paludis/repositories/e/do_install_action.cc @@ -0,0 +1,438 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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/do_install_action.hh> +#include <paludis/repositories/e/a_finder.hh> +#include <paludis/repositories/e/eapi.hh> +#include <paludis/repositories/e/a_finder.hh> +#include <paludis/repositories/e/aa_visitor.hh> +#include <paludis/repositories/e/make_use.hh> +#include <paludis/repositories/e/check_userpriv.hh> +#include <paludis/repositories/e/eapi_phase.hh> +#include <paludis/repositories/e/can_skip_phase.hh> +#include <paludis/repositories/e/e_stripper.hh> +#include <paludis/repositories/e/ebuild.hh> +#include <paludis/util/indirect_iterator-impl.hh> +#include <paludis/util/accept_visitor.hh> +#include <paludis/util/strip.hh> +#include <paludis/util/fs_stat.hh> +#include <paludis/util/make_named_values.hh> +#include <paludis/util/log.hh> +#include <paludis/action.hh> +#include <paludis/dep_spec_flattener.hh> +#include <paludis/metadata_key.hh> +#include <paludis/choice.hh> +#include <paludis/elike_choices.hh> +#include <paludis/output_manager.hh> + +#include <algorithm> +#include <set> + +using namespace paludis; +using namespace paludis::erepository; + +namespace +{ + struct AcceptLicenseFinder + { + std::stringstream s; + + AcceptLicenseFinder() + { + s << "*"; + } + + void visit(const LicenseSpecTree::NodeType<AllDepSpec>::Type & node) + { + std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this)); + } + + void visit(const LicenseSpecTree::NodeType<AnyDepSpec>::Type & node) + { + std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this)); + } + + void visit(const LicenseSpecTree::NodeType<ConditionalDepSpec>::Type & node) + { + if (node.spec()->condition_met()) + std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this)); + } + + void visit(const LicenseSpecTree::NodeType<LicenseDepSpec>::Type & node) + { + s << " " << node.spec()->text(); + } + }; + + void used_this_for_config_protect(std::string & s, const std::string & v) + { + s = v; + } + + bool slot_is_same(const std::shared_ptr<const PackageID> & a, + const std::shared_ptr<const PackageID> & b) + { + if (a->slot_key()) + return b->slot_key() && a->slot_key()->value() == b->slot_key()->value(); + else + return ! b->slot_key(); + } + + bool ignore_merged(const std::shared_ptr<const FSPathSet> & s, const FSPath & f) + { + return s->end() != s->find(f); + } + + std::shared_ptr<OutputManager> this_output_manager(const std::shared_ptr<OutputManager> & o, const Action &) + { + return o; + } +} + +void +paludis::erepository::do_install_action( + const Environment * const env, + const ERepository * const repo, + const std::shared_ptr<const ERepositoryID> & id, + const InstallAction & install_action) +{ + using namespace std::placeholders; + + Context context("When installing '" + stringify(*id) + "'" + + (install_action.options.replacing()->empty() ? "" : " replacing { '" + + join(indirect_iterator(install_action.options.replacing()->begin()), + indirect_iterator(install_action.options.replacing()->end()), "', '") + "' }") + ":"); + + std::shared_ptr<OutputManager> output_manager(install_action.options.make_output_manager()(install_action)); + + bool userpriv_restrict, test_restrict, strip_restrict; + { + DepSpecFlattener<PlainTextSpecTree, PlainTextDepSpec> restricts(env); + if (id->restrict_key()) + id->restrict_key()->value()->top()->accept(restricts); + + userpriv_restrict = + indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), + std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "userpriv")) || + indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), + std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "nouserpriv")); + + test_restrict = + indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), + std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "test")); + + strip_restrict = + indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), + std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "strip")) || + indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), + std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "nostrip")); + } + + std::string archives, all_archives, accept_license; + { + std::set<std::string> already_in_archives; + + /* make A */ + AFinder f(env, id); + if (id->fetches_key()) + id->fetches_key()->value()->top()->accept(f); + + for (AFinder::ConstIterator i(f.begin()), i_end(f.end()) ; i != i_end ; ++i) + { + const FetchableURIDepSpec * const spec(static_cast<const FetchableURIDepSpec *>(i->first)); + + if (already_in_archives.end() == already_in_archives.find(spec->filename())) + { + archives.append(spec->filename()); + already_in_archives.insert(spec->filename()); + } + archives.append(" "); + } + + /* make AA */ + if (! id->eapi()->supported()->ebuild_environment_variables()->env_aa().empty()) + { + AAVisitor g; + if (id->fetches_key()) + id->fetches_key()->value()->top()->accept(g); + std::set<std::string> already_in_all_archives; + + for (AAVisitor::ConstIterator gg(g.begin()), gg_end(g.end()) ; gg != gg_end ; ++gg) + { + if (already_in_all_archives.end() == already_in_all_archives.find(*gg)) + { + all_archives.append(*gg); + already_in_all_archives.insert(*gg); + } + all_archives.append(" "); + } + } + else + all_archives = "AA-not-set-for-this-EAPI"; + + /* make ACCEPT_LICENSE */ + if (! id->eapi()->supported()->ebuild_environment_variables()->env_accept_license().empty()) + { + AcceptLicenseFinder g; + if (id->license_key()) + id->license_key()->value()->top()->accept(g); + + accept_license = g.s.str(); + } + else + accept_license = "ACCEPT_LICENSE-not-set-for-this-EAPI"; + } + + /* Strip trailing space. Some ebuilds rely upon this. From kde-meta.eclass: + * [[ -n ${A/${TARBALL}/} ]] && unpack ${A/${TARBALL}/} + * Rather annoying. + */ + archives = strip_trailing(archives, " "); + all_archives = strip_trailing(all_archives, " "); + + /* make use */ + std::string use(make_use(env, *id, repo->profile())); + + /* add expand to use (iuse isn't reliable for use_expand things), and make the expand + * environment variables */ + std::shared_ptr<Map<std::string, std::string> > expand_vars(make_expand(env, *id, repo->profile())); + + std::shared_ptr<const FSPathSequence> exlibsdirs(repo->layout()->exlibsdirs(id->name())); + + bool userpriv_ok((! userpriv_restrict) && (env->reduced_gid() != getgid()) && + check_userpriv(FSPath(repo->params().distdir()), env, id->eapi()->supported()->userpriv_cannot_use_root()) && + check_userpriv(FSPath(repo->params().builddir()), env, id->eapi()->supported()->userpriv_cannot_use_root())); + + FSPath package_builddir(repo->params().builddir() / (stringify(id->name().category()) + "-" + + stringify(id->name().package()) + "-" + stringify(id->version()))); + + std::string used_config_protect; + auto merged_entries(std::make_shared<FSPathSet>()); + + std::shared_ptr<const ChoiceValue> preserve_work_choice( + id->choices_key()->value()->find_by_name_with_prefix( + ELikePreserveWorkChoiceValue::canonical_name_with_prefix())); + + EAPIPhases phases(id->eapi()->supported()->ebuild_phases()->ebuild_install()); + for (EAPIPhases::ConstIterator phase(phases.begin_phases()), phase_end(phases.end_phases()) ; + phase != phase_end ; ++phase) + { + bool skip(false); + do + { + switch (install_action.options.want_phase()(phase->equal_option("skipname"))) + { + case wp_yes: + continue; + + case wp_skip: + skip = true; + continue; + + case wp_abort: + throw ActionAbortedError("Told to abort install"); + + case last_wp: + break; + } + + throw InternalError(PALUDIS_HERE, "bad want_phase"); + } while (false); + + if (skip) + continue; + + if (can_skip_phase(id, *phase)) + { + output_manager->stdout_stream() << "--- No need to do anything for " << phase->equal_option("skipname") << " phase" << std::endl; + continue; + } + + if (phase->option("tidyup") && preserve_work_choice && preserve_work_choice->enabled()) + { + output_manager->stdout_stream() << "--- Skipping " << phase->equal_option("skipname") + << " phase to preserve work" << std::endl; + continue; + } + + if (phase->option("merge")) + { + if (! (*install_action.options.destination()).destination_interface()) + throw ActionFailedError("Can't install '" + stringify(*id) + + "' to destination '" + stringify(install_action.options.destination()->name()) + + "' because destination does not provide destination_interface"); + + MergerOptions extra_merger_options; + if (preserve_work_choice && preserve_work_choice->enabled()) + extra_merger_options += mo_nondestructive; + + Timestamp build_start_time(FSPath(package_builddir / "temp" / "build_start_time").stat().mtim()); + (*install_action.options.destination()).destination_interface()->merge( + make_named_values<MergeParams>( + n::build_start_time() = build_start_time, + n::environment_file() = package_builddir / "temp" / "loadsaveenv", + n::image_dir() = package_builddir / "image", + n::merged_entries() = merged_entries, + n::options() = id->eapi()->supported()->merger_options() | extra_merger_options, + n::output_manager() = output_manager, + n::package_id() = id, + n::perform_uninstall() = install_action.options.perform_uninstall(), + n::used_this_for_config_protect() = std::bind( + &used_this_for_config_protect, std::ref(used_config_protect), std::placeholders::_1) + )); + } + else if (phase->option("strip")) + { + if ((! id->eapi()->supported()->is_pbin()) && (! strip_restrict)) + { + std::string libdir("lib"); + FSPath root(install_action.options.destination()->installed_root_key() ? + stringify(install_action.options.destination()->installed_root_key()->value()) : "/"); + if ((root / "usr" / "lib").stat().is_symlink()) + { + libdir = (root / "usr" / "lib").readlink(); + if (std::string::npos != libdir.find_first_of("./")) + libdir = "lib"; + } + + Log::get_instance()->message("e.ebuild.libdir", ll_debug, lc_context) << "Using '" << libdir << "' for libdir"; + + std::shared_ptr<const ChoiceValue> strip_choice(id->choices_key()->value()->find_by_name_with_prefix( + ELikeStripChoiceValue::canonical_name_with_prefix())); + std::shared_ptr<const ChoiceValue> split_choice(id->choices_key()->value()->find_by_name_with_prefix( + ELikeSplitChoiceValue::canonical_name_with_prefix())); + + EStripper stripper(make_named_values<EStripperOptions>( + n::debug_dir() = package_builddir / "image" / "usr" / libdir / "debug", + n::image_dir() = package_builddir / "image", + n::output_manager() = output_manager, + n::package_id() = id, + n::split() = split_choice && split_choice->enabled(), + n::strip() = strip_choice && strip_choice->enabled() + )); + stripper.strip(); + } + } + else if ((! phase->option("prepost")) || + ((*install_action.options.destination()).destination_interface() && + (*install_action.options.destination()).destination_interface()->want_pre_post_phases())) + { + if (phase->option("optional_tests")) + { + if (test_restrict) + continue; + + std::shared_ptr<const ChoiceValue> choice(id->choices_key()->value()->find_by_name_with_prefix( + ELikeOptionalTestsChoiceValue::canonical_name_with_prefix())); + if (choice && ! choice->enabled()) + continue; + } + else if (phase->option("recommended_tests")) + { + if (test_restrict) + continue; + + std::shared_ptr<const ChoiceValue> choice(id->choices_key()->value()->find_by_name_with_prefix( + ELikeRecommendedTestsChoiceValue::canonical_name_with_prefix())); + if (choice && ! choice->enabled()) + continue; + } + else if (phase->option("expensive_tests")) + { + std::shared_ptr<const ChoiceValue> choice(id->choices_key()->value()->find_by_name_with_prefix( + ELikeExpensiveTestsChoiceValue::canonical_name_with_prefix())); + if (choice && ! choice->enabled()) + continue; + } + + EbuildCommandParams command_params(make_named_values<EbuildCommandParams>( + n::builddir() = repo->params().builddir(), + n::clearenv() = phase->option("clearenv"), + n::commands() = join(phase->begin_commands(), phase->end_commands(), " "), + n::distdir() = repo->params().distdir(), + n::ebuild_dir() = repo->layout()->package_directory(id->name()), + n::ebuild_file() = id->fs_location_key()->value(), + n::eclassdirs() = repo->params().eclassdirs(), + n::environment() = env, + n::exlibsdirs() = exlibsdirs, + n::files_dir() = repo->layout()->package_directory(id->name()) / "files", + n::maybe_output_manager() = output_manager, + n::package_builddir() = package_builddir, + n::package_id() = id, + n::portdir() = + (repo->params().master_repositories() && ! repo->params().master_repositories()->empty()) ? + (*repo->params().master_repositories()->begin())->params().location() : repo->params().location(), + n::root() = install_action.options.destination()->installed_root_key() ? + stringify(install_action.options.destination()->installed_root_key()->value()) : + "/", + n::sandbox() = phase->option("sandbox"), + n::sydbox() = phase->option("sydbox"), + n::userpriv() = phase->option("userpriv") && userpriv_ok + )); + + EbuildInstallCommandParams install_params( + make_named_values<EbuildInstallCommandParams>( + n::a() = archives, + n::aa() = all_archives, + n::accept_license() = accept_license, + n::config_protect() = repo->environment_updated_profile_variable("CONFIG_PROTECT"), + n::config_protect_mask() = repo->environment_updated_profile_variable("CONFIG_PROTECT_MASK"), + n::destination() = install_action.options.destination(), + n::expand_vars() = expand_vars, + n::is_from_pbin() = id->eapi()->supported()->is_pbin(), + n::loadsaveenv_dir() = package_builddir / "temp", + n::profiles() = repo->params().profiles(), + n::profiles_with_parents() = repo->profile()->profiles_with_parents(), + n::replacing_ids() = install_action.options.replacing(), + n::slot() = id->slot_key() ? stringify(id->slot_key()->value()) : "", + n::use() = use, + n::use_expand() = join(repo->profile()->use_expand()->begin(), repo->profile()->use_expand()->end(), " "), + n::use_expand_hidden() = join(repo->profile()->use_expand_hidden()->begin(), repo->profile()->use_expand_hidden()->end(), " ") + )); + + EbuildInstallCommand cmd(command_params, install_params); + cmd(); + } + } + + for (PackageIDSequence::ConstIterator i(install_action.options.replacing()->begin()), i_end(install_action.options.replacing()->end()) ; + i != i_end ; ++i) + { + Context local_context("When cleaning '" + stringify(**i) + "':"); + if ((*i)->name() == id->name() && (*i)->version() == id->version()) + continue; + + if (id->eapi()->supported()->ebuild_phases()->ebuild_new_upgrade_phase_order()) + if ((*i)->name() == id->name() && slot_is_same(*i, id)) + continue; + + UninstallActionOptions uo(make_named_values<UninstallActionOptions>( + n::config_protect() = used_config_protect, + n::if_for_install_id() = id, + n::ignore_for_unmerge() = std::bind(&ignore_merged, merged_entries, + std::placeholders::_1), + n::is_overwrite() = false, + n::make_output_manager() = std::bind(&this_output_manager, output_manager, std::placeholders::_1) + )); + install_action.options.perform_uninstall()(*i, uo); + } + + output_manager->succeeded(); +} + diff --git a/paludis/repositories/e/do_install_action.hh b/paludis/repositories/e/do_install_action.hh new file mode 100644 index 000000000..b4cdad581 --- /dev/null +++ b/paludis/repositories/e/do_install_action.hh @@ -0,0 +1,42 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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_DO_INSTALL_ACTION_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_E_DO_INSTALL_ACTION_HH 1 + +#include <paludis/repositories/e/e_repository.hh> +#include <paludis/repositories/e/e_repository_id.hh> +#include <paludis/environment-fwd.hh> +#include <paludis/action-fwd.hh> + +namespace paludis +{ + namespace erepository + { + void + do_install_action( + const Environment * const env, + const ERepository * const repo, + const std::shared_ptr<const ERepositoryID> & id, + const InstallAction & install_action); + + } +} + +#endif diff --git a/paludis/repositories/e/do_pretend_action.cc b/paludis/repositories/e/do_pretend_action.cc new file mode 100644 index 000000000..01631fe52 --- /dev/null +++ b/paludis/repositories/e/do_pretend_action.cc @@ -0,0 +1,201 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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/do_pretend_action.hh> +#include <paludis/repositories/e/check_userpriv.hh> +#include <paludis/repositories/e/eapi.hh> +#include <paludis/repositories/e/eapi_phase.hh> +#include <paludis/repositories/e/make_use.hh> +#include <paludis/repositories/e/myoptions_requirements_verifier.hh> +#include <paludis/repositories/e/ebuild.hh> +#include <paludis/repositories/e/can_skip_phase.hh> +#include <paludis/util/indirect_iterator-impl.hh> +#include <paludis/util/make_named_values.hh> +#include <paludis/dep_spec_flattener.hh> +#include <paludis/metadata_key.hh> +#include <paludis/environment.hh> +#include <paludis/action.hh> + +#include <algorithm> + +using namespace paludis; +using namespace paludis::erepository; + +bool +paludis::erepository::do_pretend_action( + const Environment * const env, + const ERepository * const repo, + const std::shared_ptr<const ERepositoryID> & id, + const PretendAction & a) +{ + using namespace std::placeholders; + + Context context("When running pretend for '" + stringify(*id) + "':"); + + if (! id->eapi()->supported()) + return false; + + bool result(true); + + if (! id->raw_myoptions_key()) + if (id->eapi()->supported()->ebuild_phases()->ebuild_pretend().empty()) + return result; + + bool userpriv_restrict; + { + DepSpecFlattener<PlainTextSpecTree, PlainTextDepSpec> restricts(env); + if (id->restrict_key()) + id->restrict_key()->value()->top()->accept(restricts); + + userpriv_restrict = + indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), + std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "userpriv")) || + indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), + std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "nouserpriv")); + } + bool userpriv_ok((! userpriv_restrict) && (env->reduced_gid() != getgid()) && + check_userpriv(FSPath(repo->params().builddir()), env, id->eapi()->supported()->userpriv_cannot_use_root())); + + std::string use(make_use(env, *id, repo->profile())); + std::shared_ptr<Map<std::string, std::string> > expand_vars(make_expand( + env, *id, repo->profile())); + + std::shared_ptr<const FSPathSequence> exlibsdirs(repo->layout()->exlibsdirs(id->name())); + + std::shared_ptr<OutputManager> output_manager; + + if (id->raw_myoptions_key()) + { + MyOptionsRequirementsVerifier verifier(id); + id->raw_myoptions_key()->value()->top()->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) + { + if (! output_manager) + output_manager = a.options.make_output_manager()(a); + + EbuildCommandParams command_params(make_named_values<EbuildCommandParams>( + n::builddir() = repo->params().builddir(), + n::clearenv() = phase->option("clearenv"), + n::commands() = join(phase->begin_commands(), phase->end_commands(), " "), + n::distdir() = repo->params().distdir(), + n::ebuild_dir() = repo->layout()->package_directory(id->name()), + n::ebuild_file() = id->fs_location_key()->value(), + n::eclassdirs() = repo->params().eclassdirs(), + n::environment() = env, + n::exlibsdirs() = exlibsdirs, + n::files_dir() = repo->layout()->package_directory(id->name()) / "files", + n::maybe_output_manager() = output_manager, + n::package_builddir() = repo->params().builddir() / (stringify(id->name().category()) + "-" + stringify(id->name().package()) + "-" + stringify(id->version()) + "-bad_options"), + n::package_id() = id, + n::portdir() = + (repo->params().master_repositories() && ! repo->params().master_repositories()->empty()) ? + (*repo->params().master_repositories()->begin())->params().location() : repo->params().location(), + n::root() = a.options.destination()->installed_root_key() ? + stringify(a.options.destination()->installed_root_key()->value()) : + "/", + n::sandbox() = phase->option("sandbox"), + n::sydbox() = phase->option("sydbox"), + n::userpriv() = phase->option("userpriv") && userpriv_ok + )); + + EbuildBadOptionsCommand bad_options_cmd(command_params, + make_named_values<EbuildBadOptionsCommandParams>( + n::expand_vars() = expand_vars, + n::profiles() = repo->params().profiles(), + n::profiles_with_parents() = repo->profile()->profiles_with_parents(), + n::unmet_requirements() = verifier.unmet_requirements(), + n::use() = use, + n::use_expand() = join(repo->profile()->use_expand()->begin(), repo->profile()->use_expand()->end(), " "), + n::use_expand_hidden() = join(repo->profile()->use_expand_hidden()->begin(), repo->profile()->use_expand_hidden()->end(), " ") + )); + + if (! bad_options_cmd()) + throw ActionFailedError("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) + { + if (can_skip_phase(id, *phase)) + continue; + + if (! output_manager) + output_manager = a.options.make_output_manager()(a); + + EbuildCommandParams command_params(make_named_values<EbuildCommandParams>( + n::builddir() = repo->params().builddir(), + n::clearenv() = phase->option("clearenv"), + n::commands() = join(phase->begin_commands(), phase->end_commands(), " "), + n::distdir() = repo->params().distdir(), + n::ebuild_dir() = repo->layout()->package_directory(id->name()), + n::ebuild_file() = id->fs_location_key()->value(), + n::eclassdirs() = repo->params().eclassdirs(), + n::environment() = env, + n::exlibsdirs() = exlibsdirs, + n::files_dir() = repo->layout()->package_directory(id->name()) / "files", + n::maybe_output_manager() = output_manager, + n::package_builddir() = repo->params().builddir() / (stringify(id->name().category()) + "-" + stringify(id->name().package()) + "-" + stringify(id->version()) + "-pretend"), + n::package_id() = id, + n::portdir() = + (repo->params().master_repositories() && ! repo->params().master_repositories()->empty()) ? + (*repo->params().master_repositories()->begin())->params().location() : repo->params().location(), + n::root() = a.options.destination()->installed_root_key() ? + stringify(a.options.destination()->installed_root_key()->value()) : + "/", + n::sandbox() = phase->option("sandbox"), + n::sydbox() = phase->option("sydbox"), + n::userpriv() = phase->option("userpriv") && userpriv_ok + )); + + EbuildPretendCommand pretend_cmd(command_params, + make_named_values<EbuildPretendCommandParams>( + n::destination() = a.options.destination(), + n::expand_vars() = expand_vars, + n::is_from_pbin() = id->eapi()->supported()->is_pbin(), + n::profiles() = repo->params().profiles(), + n::profiles_with_parents() = repo->profile()->profiles_with_parents(), + n::replacing_ids() = a.options.replacing(), + n::use() = use, + n::use_expand() = join(repo->profile()->use_expand()->begin(), repo->profile()->use_expand()->end(), " "), + n::use_expand_hidden() = join(repo->profile()->use_expand_hidden()->begin(), repo->profile()->use_expand_hidden()->end(), " ") + )); + + if (! pretend_cmd()) + return false; + } + + return result; +} + diff --git a/paludis/repositories/e/do_pretend_action.hh b/paludis/repositories/e/do_pretend_action.hh new file mode 100644 index 000000000..eed243da4 --- /dev/null +++ b/paludis/repositories/e/do_pretend_action.hh @@ -0,0 +1,41 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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_DO_PRETEND_ACTION_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_E_DO_PRETEND_ACTION_HH 1 + +#include <paludis/repositories/e/e_repository.hh> +#include <paludis/repositories/e/e_repository_id.hh> +#include <paludis/environment-fwd.hh> +#include <paludis/action-fwd.hh> + +namespace paludis +{ + namespace erepository + { + bool + do_pretend_action( + const Environment * const env, + const ERepository * const repo, + const std::shared_ptr<const ERepositoryID> & id, + const PretendAction & a); + } +} + +#endif diff --git a/paludis/repositories/e/do_pretend_fetch_action.cc b/paludis/repositories/e/do_pretend_fetch_action.cc new file mode 100644 index 000000000..af9a0f0ed --- /dev/null +++ b/paludis/repositories/e/do_pretend_fetch_action.cc @@ -0,0 +1,47 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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/do_pretend_fetch_action.hh> +#include <paludis/repositories/e/pretend_fetch_visitor.hh> +#include <paludis/action.hh> +#include <paludis/metadata_key.hh> + +using namespace paludis; +using namespace paludis::erepository; + +void +paludis::erepository::do_pretend_fetch_action( + const Environment * const env, + const ERepository * const repo, + const std::shared_ptr<const ERepositoryID> & id, + PretendFetchAction & a) +{ + using namespace std::placeholders; + + Context context("When pretending to fetch ID '" + stringify(*id) + "':"); + + if (id->fetches_key()) + { + PretendFetchVisitor f(env, id, *id->eapi(), + repo->params().distdir(), a.options.fetch_parts()[fp_unneeded], + id->fetches_key()->initial_label(), a); + id->fetches_key()->value()->top()->accept(f); + } +} + diff --git a/paludis/repositories/e/do_pretend_fetch_action.hh b/paludis/repositories/e/do_pretend_fetch_action.hh new file mode 100644 index 000000000..c7a95e733 --- /dev/null +++ b/paludis/repositories/e/do_pretend_fetch_action.hh @@ -0,0 +1,41 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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_DO_PRETEND_FETCH_ACTION_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_E_DO_PRETEND_FETCH_ACTION_HH 1 + +#include <paludis/repositories/e/e_repository.hh> +#include <paludis/repositories/e/e_repository_id.hh> +#include <paludis/action-fwd.hh> +#include <paludis/environment-fwd.hh> + +namespace paludis +{ + namespace erepository + { + void + do_pretend_fetch_action( + const Environment * const env, + const ERepository * const repo, + const std::shared_ptr<const ERepositoryID> & id, + PretendFetchAction & a); + } +} + +#endif diff --git a/paludis/repositories/e/e_repository.cc b/paludis/repositories/e/e_repository.cc index ac3796110..ad6b565f3 100644 --- a/paludis/repositories/e/e_repository.cc +++ b/paludis/repositories/e/e_repository.cc @@ -36,15 +36,13 @@ #include <paludis/repositories/e/extra_distribution_data.hh> #include <paludis/repositories/e/memoised_hashes.hh> #include <paludis/repositories/e/ebuild_id.hh> -#include <paludis/repositories/e/check_fetched_files_visitor.hh> -#include <paludis/repositories/e/fetch_visitor.hh> #include <paludis/repositories/e/eapi_phase.hh> #include <paludis/repositories/e/can_skip_phase.hh> #include <paludis/repositories/e/ebuild.hh> -#include <paludis/repositories/e/pretend_fetch_visitor.hh> -#include <paludis/repositories/e/e_stripper.hh> -#include <paludis/repositories/e/myoptions_requirements_verifier.hh> #include <paludis/repositories/e/pbin_merger.hh> +#include <paludis/repositories/e/check_userpriv.hh> +#include <paludis/repositories/e/make_use.hh> +#include <paludis/repositories/e/a_finder.hh> #include <paludis/about.hh> #include <paludis/action.hh> @@ -1782,961 +1780,6 @@ ERepository::make_id(const QualifiedPackageName & q, const FSPath & f) const return result; } -namespace -{ - class AFinder - { - private: - std::list<std::pair<const FetchableURIDepSpec *, const URILabelsDepSpec *> > _specs; - std::list<const URILabelsDepSpec *> _labels; - - const Environment * const env; - const std::shared_ptr<const PackageID> id; - - public: - AFinder(const Environment * const e, const std::shared_ptr<const PackageID> & i) : - env(e), - id(i) - { - _labels.push_back(0); - } - - void visit(const FetchableURISpecTree::NodeType<FetchableURIDepSpec>::Type & node) - { - _specs.push_back(std::make_pair(node.spec().get(), *_labels.begin())); - } - - void visit(const FetchableURISpecTree::NodeType<URILabelsDepSpec>::Type & node) - { - *_labels.begin() = node.spec().get(); - } - - void visit(const FetchableURISpecTree::NodeType<AllDepSpec>::Type & node) - { - _labels.push_front(*_labels.begin()); - std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this)); - _labels.pop_front(); - } - - void visit(const FetchableURISpecTree::NodeType<ConditionalDepSpec>::Type & node) - { - if (node.spec()->condition_met()) - { - _labels.push_front(*_labels.begin()); - std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this)); - _labels.pop_front(); - } - } - - typedef std::list<std::pair<const FetchableURIDepSpec *, - const URILabelsDepSpec *> >::const_iterator ConstIterator; - - ConstIterator begin() - { - return _specs.begin(); - } - - ConstIterator end() const - { - return _specs.end(); - } - }; -} - -namespace -{ - std::string make_use(const Environment * const, - const ERepositoryID & id, - std::shared_ptr<const Profile> profile) - { - if (! id.eapi()->supported()) - { - Log::get_instance()->message("e.ebuild.unknown_eapi", ll_warning, lc_context) - << "Can't make the USE string for '" << id << "' because its EAPI is unsupported"; - return ""; - } - - std::string use; - - 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() == canonical_build_options_prefix()) - continue; - - for (Choice::ConstIterator i((*k)->begin()), i_end((*k)->end()) ; - i != i_end ; ++i) - if ((*i)->enabled()) - use += stringify((*i)->name_with_prefix()) + " "; - } - } - - if (! id.eapi()->supported()->ebuild_environment_variables()->env_arch().empty()) - use += profile->environment_variable(id.eapi()->supported()->ebuild_environment_variables()->env_arch()) + " "; - - return use; - } - - std::shared_ptr<Map<std::string, std::string> > - make_expand(const Environment * const, - const ERepositoryID & e, - std::shared_ptr<const Profile> profile) - { - std::shared_ptr<Map<std::string, std::string> > expand_vars(std::make_shared<Map<std::string, std::string> >()); - - if (! e.eapi()->supported()) - { - Log::get_instance()->message("e.ebuild.unknown_eapi", ll_warning, lc_context) - << "Can't make the USE_EXPAND strings for '" << e << "' because its EAPI is unsupported"; - return expand_vars; - } - - if (! e.choices_key()) - return expand_vars; - - for (Set<std::string>::ConstIterator x(profile->use_expand()->begin()), x_end(profile->use_expand()->end()) ; - x != x_end ; ++x) - { - expand_vars->insert(stringify(*x), ""); - - Choices::ConstIterator k(std::find_if(e.choices_key()->value()->begin(), e.choices_key()->value()->end(), - std::bind(std::equal_to<std::string>(), *x, - std::bind(std::mem_fn(&Choice::raw_name), std::placeholders::_1)))); - if (k == e.choices_key()->value()->end()) - continue; - - for (Choice::ConstIterator i((*k)->begin()), i_end((*k)->end()) ; - i != i_end ; ++i) - if ((*i)->enabled()) - { - std::string value; - Map<std::string, std::string>::ConstIterator v(expand_vars->find(stringify(*x))); - if (expand_vars->end() != v) - { - value = v->second; - if (! value.empty()) - value.append(" "); - expand_vars->erase(v); - } - value.append(stringify((*i)->unprefixed_name())); - expand_vars->insert(stringify(*x), value); - } - } - - return expand_vars; - } -} - -namespace -{ - bool - check_userpriv(const FSPath & f, const Environment * env, bool mandatory) - { - Context c("When checking permissions on '" + stringify(f) + "' for userpriv:"); - - if (! getenv_with_default("PALUDIS_BYPASS_USERPRIV_CHECKS", "").empty()) - return false; - - FSStat f_stat(f); - if (f_stat.exists()) - { - if (f_stat.group() != env->reduced_gid()) - { - if (mandatory) - throw ConfigurationError("Directory '" + stringify(f) + "' owned by group '" + get_group_name(f_stat.group()) - + "', not '" + get_group_name(env->reduced_gid()) + "'"); - else - Log::get_instance()->message("e.ebuild.userpriv_disabled", ll_warning, lc_context) << "Directory '" << - f << "' owned by group '" << get_group_name(f_stat.group()) << "', not '" - << get_group_name(env->reduced_gid()) << "', so cannot enable userpriv"; - return false; - } - else if (0 == (f_stat.permissions() & S_IWGRP)) - { - if (mandatory) - throw ConfigurationError("Directory '" + stringify(f) + "' does not have group write permission"); - else - Log::get_instance()->message("e.ebuild.userpriv_disabled", ll_warning, lc_context) << "Directory '" << - f << "' does not have group write permission, cannot enable userpriv"; - return false; - } - } - - return true; - } - - const std::shared_ptr<const MirrorsSequence> - get_mirrors_fn(const std::string & m, const MirrorMap & map) - { - MirrorMap::const_iterator i(map.find(m)); - if (i == map.end()) - return std::make_shared<MirrorsSequence>(); - else - return i->second; - } -} - -void -ERepository::fetch(const std::shared_ptr<const ERepositoryID> & id, - const FetchAction & fetch_action) const -{ - using namespace std::placeholders; - - Context context("When fetching '" + stringify(*id) + "':"); - - bool fetch_restrict(false), userpriv_restrict(false); - { - DepSpecFlattener<PlainTextSpecTree, PlainTextDepSpec> restricts(_imp->params.environment()); - if (id->restrict_key()) - id->restrict_key()->value()->top()->accept(restricts); - - for (DepSpecFlattener<PlainTextSpecTree, PlainTextDepSpec>::ConstIterator i(restricts.begin()), i_end(restricts.end()) ; - i != i_end ; ++i) - { - if (id->eapi()->supported()->ebuild_options()->restrict_fetch()->end() != - std::find(id->eapi()->supported()->ebuild_options()->restrict_fetch()->begin(), - id->eapi()->supported()->ebuild_options()->restrict_fetch()->end(), (*i)->text())) - fetch_restrict = true; - if ("userpriv" == (*i)->text() || "nouserpriv" == (*i)->text()) - userpriv_restrict = true; - } - } - - bool fetch_userpriv_ok(_imp->params.environment()->reduced_gid() != getgid() && - check_userpriv(FSPath(_imp->params.distdir()), _imp->params.environment(), - id->eapi()->supported()->userpriv_cannot_use_root())); - - std::string archives, all_archives; - { - std::set<std::string> already_in_archives; - - /* make A */ - AFinder f(_imp->params.environment(), id); - if (id->fetches_key()) - id->fetches_key()->value()->top()->accept(f); - - for (AFinder::ConstIterator i(f.begin()), i_end(f.end()) ; i != i_end ; ++i) - { - const FetchableURIDepSpec * const spec(static_cast<const FetchableURIDepSpec *>(i->first)); - - if (already_in_archives.end() == already_in_archives.find(spec->filename())) - { - archives.append(spec->filename()); - already_in_archives.insert(spec->filename()); - } - archives.append(" "); - } - - /* make AA */ - if (! id->eapi()->supported()->ebuild_environment_variables()->env_aa().empty()) - { - AAVisitor g; - if (id->fetches_key()) - id->fetches_key()->value()->top()->accept(g); - std::set<std::string> already_in_all_archives; - - for (AAVisitor::ConstIterator gg(g.begin()), gg_end(g.end()) ; gg != gg_end ; ++gg) - { - if (already_in_all_archives.end() == already_in_all_archives.find(*gg)) - { - all_archives.append(*gg); - already_in_all_archives.insert(*gg); - } - all_archives.append(" "); - } - } - else - all_archives = "AA-not-set-for-this-EAPI"; - } - - /* Strip trailing space. Some ebuilds rely upon this. From kde-meta.eclass: - * [[ -n ${A/${TARBALL}/} ]] && unpack ${A/${TARBALL}/} - * Rather annoying. - */ - archives = strip_trailing(archives, " "); - all_archives = strip_trailing(all_archives, " "); - - std::shared_ptr<OutputManager> output_manager(fetch_action.options.make_output_manager()(fetch_action)); - - CheckFetchedFilesVisitor c(_imp->params.environment(), id, _imp->params.distdir(), - fetch_action.options.fetch_parts()[fp_unneeded], fetch_restrict, - ((_imp->layout->package_directory(id->name())) / "Manifest"), - _imp->params.use_manifest(), - output_manager, fetch_action.options.exclude_unmirrorable(), - fetch_action.options.ignore_unfetched(), - fetch_action.options.ignore_not_in_manifest()); - - if (id->fetches_key()) - { - /* always use mirror://gentoo/, where gentoo is the name of our first master repository, - * or our name if there's no master. */ - std::string mirrors_name( - (_imp->params.master_repositories() && ! _imp->params.master_repositories()->empty()) ? - stringify((*_imp->params.master_repositories()->begin())->name()) : - stringify(name())); - - if (fetch_action.options.fetch_parts()[fp_regulars] && ! fetch_action.options.ignore_unfetched()) - { - need_mirrors(); - - FetchVisitor f(_imp->params.environment(), id, *id->eapi(), - _imp->params.distdir(), fetch_action.options.fetch_parts()[fp_unneeded], - fetch_userpriv_ok, mirrors_name, - id->fetches_key()->initial_label(), fetch_action.options.safe_resume(), - output_manager, std::bind(&get_mirrors_fn, std::placeholders::_1, std::cref(_imp->mirrors))); - id->fetches_key()->value()->top()->accept(f); - } - - id->fetches_key()->value()->top()->accept(c); - } - - if ( (fetch_action.options.fetch_parts()[fp_extras]) && ((c.need_nofetch()) || - ((! fetch_action.options.ignore_unfetched()) && (! id->eapi()->supported()->ebuild_phases()->ebuild_fetch_extra().empty())))) - { - bool userpriv_ok((! userpriv_restrict) && (_imp->params.environment()->reduced_gid() != getgid()) && - check_userpriv(FSPath(_imp->params.builddir()), _imp->params.environment(), - id->eapi()->supported()->userpriv_cannot_use_root())); - std::string use(make_use(_imp->params.environment(), *id, profile())); - std::shared_ptr<Map<std::string, std::string> > expand_vars(make_expand( - _imp->params.environment(), *id, profile())); - - std::shared_ptr<const FSPathSequence> exlibsdirs(layout()->exlibsdirs(id->name())); - - EAPIPhases fetch_extra_phases(id->eapi()->supported()->ebuild_phases()->ebuild_fetch_extra()); - if ((! fetch_action.options.ignore_unfetched()) && (fetch_extra_phases.begin_phases() != fetch_extra_phases.end_phases())) - { - FSPath package_builddir(_imp->params.builddir() / (stringify(id->name().category()) + "-" + - stringify(id->name().package()) + "-" + stringify(id->version()) + "-fetch_extra")); - - for (EAPIPhases::ConstIterator phase(fetch_extra_phases.begin_phases()), phase_end(fetch_extra_phases.end_phases()) ; - phase != phase_end ; ++phase) - { - bool skip(false); - do - { - switch (fetch_action.options.want_phase()(phase->equal_option("skipname"))) - { - case wp_yes: - continue; - - case wp_skip: - skip = true; - continue; - - case wp_abort: - throw ActionAbortedError("Told to abort fetch"); - - case last_wp: - break; - } - - throw InternalError(PALUDIS_HERE, "bad want_phase"); - } while (false); - - if (skip) - continue; - - if (can_skip_phase(id, *phase)) - continue; - - EbuildCommandParams command_params(make_named_values<EbuildCommandParams>( - n::builddir() = _imp->params.builddir(), - n::clearenv() = phase->option("clearenv"), - n::commands() = join(phase->begin_commands(), phase->end_commands(), " "), - n::distdir() = _imp->params.distdir(), - n::ebuild_dir() = layout()->package_directory(id->name()), - n::ebuild_file() = id->fs_location_key()->value(), - n::eclassdirs() = _imp->params.eclassdirs(), - n::environment() = _imp->params.environment(), - n::exlibsdirs() = exlibsdirs, - n::files_dir() = layout()->package_directory(id->name()) / "files", - n::maybe_output_manager() = output_manager, - n::package_builddir() = package_builddir, - n::package_id() = id, - n::portdir() = - (_imp->params.master_repositories() && ! _imp->params.master_repositories()->empty()) ? - (*_imp->params.master_repositories()->begin())->params().location() : _imp->params.location(), - n::root() = "/", - n::sandbox() = phase->option("sandbox"), - n::sydbox() = phase->option("sydbox"), - n::userpriv() = phase->option("userpriv") && userpriv_ok - )); - - EbuildFetchExtraCommand fetch_extra_cmd(command_params, make_named_values<EbuildFetchExtraCommandParams>( - n::a() = archives, - n::aa() = all_archives, - n::expand_vars() = expand_vars, - n::loadsaveenv_dir() = package_builddir / "temp", - n::profiles() = _imp->params.profiles(), - n::profiles_with_parents() = profile()->profiles_with_parents(), - n::slot() = id->slot_key() ? stringify(id->slot_key()->value()) : "", - n::use() = use, - n::use_expand() = join(profile()->use_expand()->begin(), profile()->use_expand()->end(), " "), - n::use_expand_hidden() = join(profile()->use_expand_hidden()->begin(), profile()->use_expand_hidden()->end(), " ") - )); - - if (! fetch_extra_cmd()) - throw ActionFailedError("Fetch of '" + stringify(*id) + "' failed"); - } - } - - if (c.need_nofetch()) - { - EAPIPhases phases(id->eapi()->supported()->ebuild_phases()->ebuild_nofetch()); - for (EAPIPhases::ConstIterator phase(phases.begin_phases()), phase_end(phases.end_phases()) ; - phase != phase_end ; ++phase) - { - EbuildCommandParams command_params(make_named_values<EbuildCommandParams>( - n::builddir() = _imp->params.builddir(), - n::clearenv() = phase->option("clearenv"), - n::commands() = join(phase->begin_commands(), phase->end_commands(), " "), - n::distdir() = _imp->params.distdir(), - n::ebuild_dir() = layout()->package_directory(id->name()), - n::ebuild_file() = id->fs_location_key()->value(), - n::eclassdirs() = _imp->params.eclassdirs(), - n::environment() = _imp->params.environment(), - n::exlibsdirs() = exlibsdirs, - n::files_dir() = layout()->package_directory(id->name()) / "files", - n::maybe_output_manager() = output_manager, - n::package_builddir() = _imp->params.builddir() / (stringify(id->name().category()) + "-" + stringify(id->name().package()) + "-" + stringify(id->version()) + "-nofetch"), - n::package_id() = id, - n::portdir() = (_imp->params.master_repositories() && ! _imp->params.master_repositories()->empty()) ? - (*_imp->params.master_repositories()->begin())->params().location() : _imp->params.location(), - n::root() = "/", - n::sandbox() = phase->option("sandbox"), - n::sydbox() = phase->option("sydbox"), - n::userpriv() = phase->option("userpriv") && userpriv_ok - )); - - EbuildNoFetchCommand nofetch_cmd(command_params, - make_named_values<EbuildNoFetchCommandParams>( - n::a() = archives, - n::aa() = all_archives, - n::expand_vars() = expand_vars, - n::profiles() = _imp->params.profiles(), - n::profiles_with_parents() = profile()->profiles_with_parents(), - n::use() = use, - n::use_expand() = join(profile()->use_expand()->begin(), profile()->use_expand()->end(), " "), - n::use_expand_hidden() = join(profile()->use_expand_hidden()->begin(), profile()->use_expand_hidden()->end(), " ") - )); - - if (! nofetch_cmd()) - { - std::copy(c.failures()->begin(), c.failures()->end(), - fetch_action.options.errors()->back_inserter()); - throw ActionFailedError("Fetch of '" + stringify(*id) + "' failed"); - } - } - } - } - - if (! c.failures()->empty()) - { - std::copy(c.failures()->begin(), c.failures()->end(), - fetch_action.options.errors()->back_inserter()); - throw ActionFailedError("Fetch of '" + stringify(*id) + "' failed"); - } - - output_manager->succeeded(); -} - -void -ERepository::pretend_fetch(const std::shared_ptr<const ERepositoryID> & id, - PretendFetchAction & a) const -{ - using namespace std::placeholders; - - Context context("When pretending to fetch ID '" + stringify(*id) + "':"); - - if (id->fetches_key()) - { - PretendFetchVisitor f(_imp->params.environment(), id, *id->eapi(), - params().distdir(), a.options.fetch_parts()[fp_unneeded], - id->fetches_key()->initial_label(), a); - id->fetches_key()->value()->top()->accept(f); - } -} - -namespace -{ - bool slot_is_same(const std::shared_ptr<const PackageID> & a, - const std::shared_ptr<const PackageID> & b) - { - if (a->slot_key()) - return b->slot_key() && a->slot_key()->value() == b->slot_key()->value(); - else - return ! b->slot_key(); - } - - void used_this_for_config_protect(std::string & s, const std::string & v) - { - s = v; - } - - std::shared_ptr<OutputManager> this_output_manager(const std::shared_ptr<OutputManager> & o, const Action &) - { - return o; - } - - void installed_this(const FSPath &) - { - } - - bool ignore_merged(const std::shared_ptr<const FSPathSet> & s, const FSPath & f) - { - return s->end() != s->find(f); - } - - struct AcceptLicenseFinder - { - std::stringstream s; - - AcceptLicenseFinder() - { - s << "*"; - } - - void visit(const LicenseSpecTree::NodeType<AllDepSpec>::Type & node) - { - std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this)); - } - - void visit(const LicenseSpecTree::NodeType<AnyDepSpec>::Type & node) - { - std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this)); - } - - void visit(const LicenseSpecTree::NodeType<ConditionalDepSpec>::Type & node) - { - if (node.spec()->condition_met()) - std::for_each(indirect_iterator(node.begin()), indirect_iterator(node.end()), accept_visitor(*this)); - } - - void visit(const LicenseSpecTree::NodeType<LicenseDepSpec>::Type & node) - { - s << " " << node.spec()->text(); - } - }; -} - -void -ERepository::install(const std::shared_ptr<const ERepositoryID> & id, - const InstallAction & install_action) const -{ - using namespace std::placeholders; - - Context context("When installing '" + stringify(*id) + "'" + - (install_action.options.replacing()->empty() ? "" : " replacing { '" - + join(indirect_iterator(install_action.options.replacing()->begin()), - indirect_iterator(install_action.options.replacing()->end()), "', '") + "' }") + ":"); - - std::shared_ptr<OutputManager> output_manager(install_action.options.make_output_manager()(install_action)); - - bool userpriv_restrict, test_restrict, strip_restrict; - { - DepSpecFlattener<PlainTextSpecTree, PlainTextDepSpec> restricts(_imp->params.environment()); - if (id->restrict_key()) - id->restrict_key()->value()->top()->accept(restricts); - - userpriv_restrict = - indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), - std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "userpriv")) || - indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), - std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "nouserpriv")); - - test_restrict = - indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), - std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "test")); - - strip_restrict = - indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), - std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "strip")) || - indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), - std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "nostrip")); - } - - std::string archives, all_archives, accept_license; - { - std::set<std::string> already_in_archives; - - /* make A */ - AFinder f(_imp->params.environment(), id); - if (id->fetches_key()) - id->fetches_key()->value()->top()->accept(f); - - for (AFinder::ConstIterator i(f.begin()), i_end(f.end()) ; i != i_end ; ++i) - { - const FetchableURIDepSpec * const spec(static_cast<const FetchableURIDepSpec *>(i->first)); - - if (already_in_archives.end() == already_in_archives.find(spec->filename())) - { - archives.append(spec->filename()); - already_in_archives.insert(spec->filename()); - } - archives.append(" "); - } - - /* make AA */ - if (! id->eapi()->supported()->ebuild_environment_variables()->env_aa().empty()) - { - AAVisitor g; - if (id->fetches_key()) - id->fetches_key()->value()->top()->accept(g); - std::set<std::string> already_in_all_archives; - - for (AAVisitor::ConstIterator gg(g.begin()), gg_end(g.end()) ; gg != gg_end ; ++gg) - { - if (already_in_all_archives.end() == already_in_all_archives.find(*gg)) - { - all_archives.append(*gg); - already_in_all_archives.insert(*gg); - } - all_archives.append(" "); - } - } - else - all_archives = "AA-not-set-for-this-EAPI"; - - /* make ACCEPT_LICENSE */ - if (! id->eapi()->supported()->ebuild_environment_variables()->env_accept_license().empty()) - { - AcceptLicenseFinder g; - if (id->license_key()) - id->license_key()->value()->top()->accept(g); - - accept_license = g.s.str(); - } - else - accept_license = "ACCEPT_LICENSE-not-set-for-this-EAPI"; - } - - /* Strip trailing space. Some ebuilds rely upon this. From kde-meta.eclass: - * [[ -n ${A/${TARBALL}/} ]] && unpack ${A/${TARBALL}/} - * Rather annoying. - */ - archives = strip_trailing(archives, " "); - all_archives = strip_trailing(all_archives, " "); - - /* make use */ - std::string use(make_use(_imp->params.environment(), *id, profile())); - - /* add expand to use (iuse isn't reliable for use_expand things), and make the expand - * environment variables */ - std::shared_ptr<Map<std::string, std::string> > expand_vars(make_expand( - _imp->params.environment(), *id, profile())); - - std::shared_ptr<const FSPathSequence> exlibsdirs(layout()->exlibsdirs(id->name())); - - bool userpriv_ok((! userpriv_restrict) && (_imp->params.environment()->reduced_gid() != getgid()) && - check_userpriv(FSPath(_imp->params.distdir()), _imp->params.environment(), id->eapi()->supported()->userpriv_cannot_use_root()) && - check_userpriv(FSPath(_imp->params.builddir()), _imp->params.environment(), id->eapi()->supported()->userpriv_cannot_use_root())); - - FSPath package_builddir(_imp->params.builddir() / (stringify(id->name().category()) + "-" + - stringify(id->name().package()) + "-" + stringify(id->version()))); - - std::string used_config_protect; - auto merged_entries(std::make_shared<FSPathSet>()); - - std::shared_ptr<const ChoiceValue> preserve_work_choice( - id->choices_key()->value()->find_by_name_with_prefix( - ELikePreserveWorkChoiceValue::canonical_name_with_prefix())); - - EAPIPhases phases(id->eapi()->supported()->ebuild_phases()->ebuild_install()); - for (EAPIPhases::ConstIterator phase(phases.begin_phases()), phase_end(phases.end_phases()) ; - phase != phase_end ; ++phase) - { - bool skip(false); - do - { - switch (install_action.options.want_phase()(phase->equal_option("skipname"))) - { - case wp_yes: - continue; - - case wp_skip: - skip = true; - continue; - - case wp_abort: - throw ActionAbortedError("Told to abort install"); - - case last_wp: - break; - } - - throw InternalError(PALUDIS_HERE, "bad want_phase"); - } while (false); - - if (skip) - continue; - - if (can_skip_phase(id, *phase)) - { - output_manager->stdout_stream() << "--- No need to do anything for " << phase->equal_option("skipname") << " phase" << std::endl; - continue; - } - - if (phase->option("tidyup") && preserve_work_choice && preserve_work_choice->enabled()) - { - output_manager->stdout_stream() << "--- Skipping " << phase->equal_option("skipname") - << " phase to preserve work" << std::endl; - continue; - } - - if (phase->option("merge")) - { - if (! (*install_action.options.destination()).destination_interface()) - throw ActionFailedError("Can't install '" + stringify(*id) - + "' to destination '" + stringify(install_action.options.destination()->name()) - + "' because destination does not provide destination_interface"); - - MergerOptions extra_merger_options; - if (preserve_work_choice && preserve_work_choice->enabled()) - extra_merger_options += mo_nondestructive; - - Timestamp build_start_time(FSPath(package_builddir / "temp" / "build_start_time").stat().mtim()); - (*install_action.options.destination()).destination_interface()->merge( - make_named_values<MergeParams>( - n::build_start_time() = build_start_time, - n::environment_file() = package_builddir / "temp" / "loadsaveenv", - n::image_dir() = package_builddir / "image", - n::merged_entries() = merged_entries, - n::options() = id->eapi()->supported()->merger_options() | extra_merger_options, - n::output_manager() = output_manager, - n::package_id() = id, - n::perform_uninstall() = install_action.options.perform_uninstall(), - n::used_this_for_config_protect() = std::bind( - &used_this_for_config_protect, std::ref(used_config_protect), std::placeholders::_1) - )); - } - else if (phase->option("strip")) - { - if ((! id->eapi()->supported()->is_pbin()) && (! strip_restrict)) - { - std::string libdir("lib"); - FSPath root(install_action.options.destination()->installed_root_key() ? - stringify(install_action.options.destination()->installed_root_key()->value()) : "/"); - if ((root / "usr" / "lib").stat().is_symlink()) - { - libdir = (root / "usr" / "lib").readlink(); - if (std::string::npos != libdir.find_first_of("./")) - libdir = "lib"; - } - - Log::get_instance()->message("e.ebuild.libdir", ll_debug, lc_context) << "Using '" << libdir << "' for libdir"; - - std::shared_ptr<const ChoiceValue> strip_choice(id->choices_key()->value()->find_by_name_with_prefix( - ELikeStripChoiceValue::canonical_name_with_prefix())); - std::shared_ptr<const ChoiceValue> split_choice(id->choices_key()->value()->find_by_name_with_prefix( - ELikeSplitChoiceValue::canonical_name_with_prefix())); - - EStripper stripper(make_named_values<EStripperOptions>( - n::debug_dir() = package_builddir / "image" / "usr" / libdir / "debug", - n::image_dir() = package_builddir / "image", - n::output_manager() = output_manager, - n::package_id() = id, - n::split() = split_choice && split_choice->enabled(), - n::strip() = strip_choice && strip_choice->enabled() - )); - stripper.strip(); - } - } - else if ((! phase->option("prepost")) || - ((*install_action.options.destination()).destination_interface() && - (*install_action.options.destination()).destination_interface()->want_pre_post_phases())) - { - if (phase->option("optional_tests")) - { - if (test_restrict) - continue; - - std::shared_ptr<const ChoiceValue> choice(id->choices_key()->value()->find_by_name_with_prefix( - ELikeOptionalTestsChoiceValue::canonical_name_with_prefix())); - if (choice && ! choice->enabled()) - continue; - } - else if (phase->option("recommended_tests")) - { - if (test_restrict) - continue; - - std::shared_ptr<const ChoiceValue> choice(id->choices_key()->value()->find_by_name_with_prefix( - ELikeRecommendedTestsChoiceValue::canonical_name_with_prefix())); - if (choice && ! choice->enabled()) - continue; - } - else if (phase->option("expensive_tests")) - { - std::shared_ptr<const ChoiceValue> choice(id->choices_key()->value()->find_by_name_with_prefix( - ELikeExpensiveTestsChoiceValue::canonical_name_with_prefix())); - if (choice && ! choice->enabled()) - continue; - } - - EbuildCommandParams command_params(make_named_values<EbuildCommandParams>( - n::builddir() = _imp->params.builddir(), - n::clearenv() = phase->option("clearenv"), - n::commands() = join(phase->begin_commands(), phase->end_commands(), " "), - n::distdir() = _imp->params.distdir(), - n::ebuild_dir() = layout()->package_directory(id->name()), - n::ebuild_file() = id->fs_location_key()->value(), - n::eclassdirs() = _imp->params.eclassdirs(), - n::environment() = _imp->params.environment(), - n::exlibsdirs() = exlibsdirs, - n::files_dir() = layout()->package_directory(id->name()) / "files", - n::maybe_output_manager() = output_manager, - n::package_builddir() = package_builddir, - n::package_id() = id, - n::portdir() = - (_imp->params.master_repositories() && ! _imp->params.master_repositories()->empty()) ? - (*_imp->params.master_repositories()->begin())->params().location() : _imp->params.location(), - n::root() = install_action.options.destination()->installed_root_key() ? - stringify(install_action.options.destination()->installed_root_key()->value()) : - "/", - n::sandbox() = phase->option("sandbox"), - n::sydbox() = phase->option("sydbox"), - n::userpriv() = phase->option("userpriv") && userpriv_ok - )); - - EbuildInstallCommandParams install_params( - make_named_values<EbuildInstallCommandParams>( - n::a() = archives, - n::aa() = all_archives, - n::accept_license() = accept_license, - n::config_protect() = environment_updated_profile_variable("CONFIG_PROTECT"), - n::config_protect_mask() = environment_updated_profile_variable("CONFIG_PROTECT_MASK"), - n::destination() = install_action.options.destination(), - n::expand_vars() = expand_vars, - n::is_from_pbin() = id->eapi()->supported()->is_pbin(), - n::loadsaveenv_dir() = package_builddir / "temp", - n::profiles() = _imp->params.profiles(), - n::profiles_with_parents() = profile()->profiles_with_parents(), - n::replacing_ids() = install_action.options.replacing(), - n::slot() = id->slot_key() ? stringify(id->slot_key()->value()) : "", - n::use() = use, - n::use_expand() = join(profile()->use_expand()->begin(), profile()->use_expand()->end(), " "), - n::use_expand_hidden() = join(profile()->use_expand_hidden()->begin(), profile()->use_expand_hidden()->end(), " ") - )); - - EbuildInstallCommand cmd(command_params, install_params); - cmd(); - } - } - - for (PackageIDSequence::ConstIterator i(install_action.options.replacing()->begin()), i_end(install_action.options.replacing()->end()) ; - i != i_end ; ++i) - { - Context local_context("When cleaning '" + stringify(**i) + "':"); - if ((*i)->name() == id->name() && (*i)->version() == id->version()) - continue; - - if (id->eapi()->supported()->ebuild_phases()->ebuild_new_upgrade_phase_order()) - if ((*i)->name() == id->name() && slot_is_same(*i, id)) - continue; - - UninstallActionOptions uo(make_named_values<UninstallActionOptions>( - n::config_protect() = used_config_protect, - n::if_for_install_id() = id, - n::ignore_for_unmerge() = std::bind(&ignore_merged, merged_entries, - std::placeholders::_1), - n::is_overwrite() = false, - n::make_output_manager() = std::bind(&this_output_manager, output_manager, std::placeholders::_1) - )); - install_action.options.perform_uninstall()(*i, uo); - } - - output_manager->succeeded(); -} - -void -ERepository::info(const std::shared_ptr<const ERepositoryID> & id, - const InfoAction & a) const -{ - using namespace std::placeholders; - - Context context("When infoing '" + stringify(*id) + "':"); - - std::shared_ptr<OutputManager> output_manager(a.options.make_output_manager()(a)); - - bool userpriv_restrict; - { - DepSpecFlattener<PlainTextSpecTree, PlainTextDepSpec> restricts(_imp->params.environment()); - if (id->restrict_key()) - id->restrict_key()->value()->top()->accept(restricts); - - userpriv_restrict = - indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), - std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "userpriv")) || - indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), - std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "nouserpriv")); - } - bool userpriv_ok((! userpriv_restrict) && (_imp->params.environment()->reduced_gid() != getgid()) && - check_userpriv(FSPath(_imp->params.builddir()), _imp->params.environment(), id->eapi()->supported()->userpriv_cannot_use_root())); - - /* make use */ - std::string use(make_use(_imp->params.environment(), *id, profile())); - - /* add expand to use (iuse isn't reliable for use_expand things), and make the expand - * environment variables */ - std::shared_ptr<Map<std::string, std::string> > expand_vars(make_expand( - _imp->params.environment(), *id, profile())); - - std::shared_ptr<const FSPathSequence> exlibsdirs(layout()->exlibsdirs(id->name())); - - EAPIPhases phases(id->eapi()->supported()->ebuild_phases()->ebuild_info()); - for (EAPIPhases::ConstIterator phase(phases.begin_phases()), phase_end(phases.end_phases()) ; - phase != phase_end ; ++phase) - { - if (phase->option("installed=true")) - continue; - - EbuildCommandParams command_params(make_named_values<EbuildCommandParams>( - n::builddir() = _imp->params.builddir(), - n::clearenv() = phase->option("clearenv"), - n::commands() = join(phase->begin_commands(), phase->end_commands(), " "), - n::distdir() = _imp->params.distdir(), - n::ebuild_dir() = layout()->package_directory(id->name()), - n::ebuild_file() = id->fs_location_key()->value(), - n::eclassdirs() = _imp->params.eclassdirs(), - n::environment() = _imp->params.environment(), - n::exlibsdirs() = exlibsdirs, - n::files_dir() = layout()->package_directory(id->name()) / "files", - n::maybe_output_manager() = output_manager, - n::package_builddir() = _imp->params.builddir() / (stringify(id->name().category()) + "-" + stringify(id->name().package()) + "-" + stringify(id->version()) + "-info"), - n::package_id() = id, - n::portdir() = - (_imp->params.master_repositories() && ! _imp->params.master_repositories()->empty()) ? - (*_imp->params.master_repositories()->begin())->params().location() : _imp->params.location(), - n::root() = stringify(_imp->params.environment()->preferred_root_key()->value()), - n::sandbox() = phase->option("sandbox"), - n::sydbox() = phase->option("sydbox"), - n::userpriv() = phase->option("userpriv") && userpriv_ok - )); - - EbuildInfoCommandParams info_params( - make_named_values<EbuildInfoCommandParams>( - n::expand_vars() = expand_vars, - n::info_vars() = info_vars_key() ? - info_vars_key()->value() : std::make_shared<const Set<std::string>>(), - n::load_environment() = static_cast<const FSPath *>(0), - n::profiles() = _imp->params.profiles(), - n::profiles_with_parents() = profile()->profiles_with_parents(), - n::use() = use, - n::use_ebuild_file() = true, - n::use_expand() = join(profile()->use_expand()->begin(), profile()->use_expand()->end(), " "), - n::use_expand_hidden() = join(profile()->use_expand_hidden()->begin(), profile()->use_expand_hidden()->end(), " ") - )); - - EbuildInfoCommand cmd(command_params, info_params); - cmd(); - } - - output_manager->succeeded(); -} - std::string ERepository::get_environment_variable( const std::shared_ptr<const PackageID> & id_uncasted, @@ -2954,166 +1997,6 @@ ERepository::extract_package_file_version(const QualifiedPackageName & n, const _imp->params.eapi_when_unknown())->supported()->version_spec_options()); } -bool -ERepository::pretend( - const std::shared_ptr<const ERepositoryID> & id, - const PretendAction & a) const -{ - using namespace std::placeholders; - - Context context("When running pretend for '" + stringify(*id) + "':"); - - if (! id->eapi()->supported()) - return false; - - bool result(true); - - if (! id->raw_myoptions_key()) - if (id->eapi()->supported()->ebuild_phases()->ebuild_pretend().empty()) - return result; - - bool userpriv_restrict; - { - DepSpecFlattener<PlainTextSpecTree, PlainTextDepSpec> restricts(_imp->params.environment()); - if (id->restrict_key()) - id->restrict_key()->value()->top()->accept(restricts); - - userpriv_restrict = - indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), - std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "userpriv")) || - indirect_iterator(restricts.end()) != std::find_if(indirect_iterator(restricts.begin()), indirect_iterator(restricts.end()), - std::bind(std::equal_to<std::string>(), std::bind(std::mem_fn(&StringDepSpec::text), _1), "nouserpriv")); - } - bool userpriv_ok((! userpriv_restrict) && (_imp->params.environment()->reduced_gid() != getgid()) && - check_userpriv(FSPath(_imp->params.builddir()), _imp->params.environment(), id->eapi()->supported()->userpriv_cannot_use_root())); - - std::string use(make_use(_imp->params.environment(), *id, profile())); - std::shared_ptr<Map<std::string, std::string> > expand_vars(make_expand( - _imp->params.environment(), *id, profile())); - - std::shared_ptr<const FSPathSequence> exlibsdirs(layout()->exlibsdirs(id->name())); - - std::shared_ptr<OutputManager> output_manager; - - if (id->raw_myoptions_key()) - { - MyOptionsRequirementsVerifier verifier(id); - id->raw_myoptions_key()->value()->top()->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) - { - if (! output_manager) - output_manager = a.options.make_output_manager()(a); - - EbuildCommandParams command_params(make_named_values<EbuildCommandParams>( - n::builddir() = _imp->params.builddir(), - n::clearenv() = phase->option("clearenv"), - n::commands() = join(phase->begin_commands(), phase->end_commands(), " "), - n::distdir() = _imp->params.distdir(), - n::ebuild_dir() = layout()->package_directory(id->name()), - n::ebuild_file() = id->fs_location_key()->value(), - n::eclassdirs() = _imp->params.eclassdirs(), - n::environment() = _imp->params.environment(), - n::exlibsdirs() = exlibsdirs, - n::files_dir() = layout()->package_directory(id->name()) / "files", - n::maybe_output_manager() = output_manager, - n::package_builddir() = _imp->params.builddir() / (stringify(id->name().category()) + "-" + stringify(id->name().package()) + "-" + stringify(id->version()) + "-bad_options"), - n::package_id() = id, - n::portdir() = - (_imp->params.master_repositories() && ! _imp->params.master_repositories()->empty()) ? - (*_imp->params.master_repositories()->begin())->params().location() : _imp->params.location(), - n::root() = a.options.destination()->installed_root_key() ? - stringify(a.options.destination()->installed_root_key()->value()) : - "/", - n::sandbox() = phase->option("sandbox"), - n::sydbox() = phase->option("sydbox"), - n::userpriv() = phase->option("userpriv") && userpriv_ok - )); - - EbuildBadOptionsCommand bad_options_cmd(command_params, - make_named_values<EbuildBadOptionsCommandParams>( - n::expand_vars() = expand_vars, - n::profiles() = _imp->params.profiles(), - n::profiles_with_parents() = profile()->profiles_with_parents(), - n::unmet_requirements() = verifier.unmet_requirements(), - n::use() = use, - n::use_expand() = join(profile()->use_expand()->begin(), profile()->use_expand()->end(), " "), - n::use_expand_hidden() = join(profile()->use_expand_hidden()->begin(), profile()->use_expand_hidden()->end(), " ") - )); - - if (! bad_options_cmd()) - throw ActionFailedError("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) - { - if (can_skip_phase(id, *phase)) - continue; - - if (! output_manager) - output_manager = a.options.make_output_manager()(a); - - EbuildCommandParams command_params(make_named_values<EbuildCommandParams>( - n::builddir() = _imp->params.builddir(), - n::clearenv() = phase->option("clearenv"), - n::commands() = join(phase->begin_commands(), phase->end_commands(), " "), - n::distdir() = _imp->params.distdir(), - n::ebuild_dir() = layout()->package_directory(id->name()), - n::ebuild_file() = id->fs_location_key()->value(), - n::eclassdirs() = _imp->params.eclassdirs(), - n::environment() = _imp->params.environment(), - n::exlibsdirs() = exlibsdirs, - n::files_dir() = layout()->package_directory(id->name()) / "files", - n::maybe_output_manager() = output_manager, - n::package_builddir() = _imp->params.builddir() / (stringify(id->name().category()) + "-" + stringify(id->name().package()) + "-" + stringify(id->version()) + "-pretend"), - n::package_id() = id, - n::portdir() = - (_imp->params.master_repositories() && ! _imp->params.master_repositories()->empty()) ? - (*_imp->params.master_repositories()->begin())->params().location() : _imp->params.location(), - n::root() = a.options.destination()->installed_root_key() ? - stringify(a.options.destination()->installed_root_key()->value()) : - "/", - n::sandbox() = phase->option("sandbox"), - n::sydbox() = phase->option("sydbox"), - n::userpriv() = phase->option("userpriv") && userpriv_ok - )); - - EbuildPretendCommand pretend_cmd(command_params, - make_named_values<EbuildPretendCommandParams>( - n::destination() = a.options.destination(), - n::expand_vars() = expand_vars, - n::is_from_pbin() = id->eapi()->supported()->is_pbin(), - n::profiles() = _imp->params.profiles(), - n::profiles_with_parents() = profile()->profiles_with_parents(), - n::replacing_ids() = a.options.replacing(), - n::use() = use, - n::use_expand() = join(profile()->use_expand()->begin(), profile()->use_expand()->end(), " "), - n::use_expand_hidden() = join(profile()->use_expand_hidden()->begin(), profile()->use_expand_hidden()->end(), " ") - )); - - if (! pretend_cmd()) - return false; - } - - return result; -} - const std::string ERepository::get_package_file_manifest_key(const FSPath & e, const QualifiedPackageName & q) const { @@ -3145,3 +2028,15 @@ ERepository::_guess_eapi(const QualifiedPackageName &, const FSPath & e) const return Suffixes::get_instance()->guess_eapi(suffix); } +const std::shared_ptr<const MirrorsSequence> +ERepository::get_mirrors(const std::string & m) const +{ + need_mirrors(); + + MirrorMap::const_iterator i(_imp->mirrors.find(m)); + if (i == _imp->mirrors.end()) + return std::make_shared<MirrorsSequence>(); + else + return i->second; +} + diff --git a/paludis/repositories/e/e_repository.hh b/paludis/repositories/e/e_repository.hh index 666f07927..1907135bf 100644 --- a/paludis/repositories/e/e_repository.hh +++ b/paludis/repositories/e/e_repository.hh @@ -197,6 +197,8 @@ namespace paludis const std::string eapi_for_file(const FSPath &) const PALUDIS_ATTRIBUTE((warn_unused_result)); + const std::shared_ptr<const MirrorsSequence> get_mirrors(const std::string & m) const; + ///\name Set methods ///\{ @@ -217,21 +219,6 @@ namespace paludis const QualifiedPackageName &, const FSPath &) const PALUDIS_ATTRIBUTE((warn_unused_result)); - void fetch(const std::shared_ptr<const erepository::ERepositoryID> &, - const FetchAction &) const; - - void pretend_fetch(const std::shared_ptr<const erepository::ERepositoryID> &, - PretendFetchAction &) const; - - void install(const std::shared_ptr<const erepository::ERepositoryID> &, - const InstallAction &) const; - - bool pretend(const std::shared_ptr<const erepository::ERepositoryID> &, - const PretendAction &) const; - - void info(const std::shared_ptr<const erepository::ERepositoryID> &, - const InfoAction &) const; - const std::string get_package_file_manifest_key(const FSPath &, const QualifiedPackageName &) const; const std::string binary_ebuild_name(const QualifiedPackageName &, const VersionSpec &, const std::string &) const diff --git a/paludis/repositories/e/ebuild_id.cc b/paludis/repositories/e/ebuild_id.cc index 050ee4f83..c7dee1835 100644 --- a/paludis/repositories/e/ebuild_id.cc +++ b/paludis/repositories/e/ebuild_id.cc @@ -29,6 +29,11 @@ #include <paludis/repositories/e/manifest2_reader.hh> #include <paludis/repositories/e/e_choice_value.hh> #include <paludis/repositories/e/metadata_xml.hh> +#include <paludis/repositories/e/do_pretend_action.hh> +#include <paludis/repositories/e/do_pretend_fetch_action.hh> +#include <paludis/repositories/e/do_install_action.hh> +#include <paludis/repositories/e/do_info_action.hh> +#include <paludis/repositories/e/do_fetch_action.hh> #include <paludis/name.hh> #include <paludis/version_spec.hh> @@ -1222,37 +1227,41 @@ namespace { struct PerformAction { + const Environment * const env; const std::shared_ptr<const PackageID> id; - PerformAction(const std::shared_ptr<const PackageID> i) : - id(i) - { - } - void visit(InstallAction & a) { - std::static_pointer_cast<const ERepository>(id->repository())->install( + do_install_action( + env, + std::static_pointer_cast<const ERepository>(id->repository()).get(), std::static_pointer_cast<const ERepositoryID>(id), - a.options); + a); } void visit(FetchAction & a) { - std::static_pointer_cast<const ERepository>(id->repository())->fetch( + do_fetch_action( + env, + std::static_pointer_cast<const ERepository>(id->repository()).get(), std::static_pointer_cast<const ERepositoryID>(id), - a.options); + a); } void visit(PretendFetchAction & a) { - std::static_pointer_cast<const ERepository>(id->repository())->pretend_fetch( + do_pretend_fetch_action( + env, + std::static_pointer_cast<const ERepository>(id->repository()).get(), std::static_pointer_cast<const ERepositoryID>(id), a); } void visit(PretendAction & action) { - if (! std::static_pointer_cast<const ERepository>(id->repository())->pretend( + if (! do_pretend_action( + env, + std::static_pointer_cast<const ERepository>(id->repository()).get(), std::static_pointer_cast<const ERepositoryID>(id), action)) action.set_failed(); @@ -1260,7 +1269,9 @@ namespace void visit(InfoAction & action) { - std::static_pointer_cast<const ERepository>(id->repository())->info( + do_info_action( + env, + std::static_pointer_cast<const ERepository>(id->repository()).get(), std::static_pointer_cast<const ERepositoryID>(id), action); } @@ -1286,7 +1297,7 @@ EbuildID::perform_action(Action & a) const if (! eapi()->supported()) throw ActionFailedError("Unsupported EAPI"); - PerformAction b(shared_from_this()); + PerformAction b{_imp->environment, shared_from_this()}; a.accept(b); } diff --git a/paludis/repositories/e/make_use.cc b/paludis/repositories/e/make_use.cc new file mode 100644 index 000000000..220a43562 --- /dev/null +++ b/paludis/repositories/e/make_use.cc @@ -0,0 +1,115 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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/make_use.hh> +#include <paludis/repositories/e/eapi.hh> +#include <paludis/util/log.hh> +#include <paludis/choice.hh> +#include <paludis/metadata_key.hh> +#include <paludis/elike_choices.hh> + +#include <algorithm> + +using namespace paludis; +using namespace paludis::erepository; + +std::string +paludis::erepository::make_use(const Environment * const, + const ERepositoryID & id, + std::shared_ptr<const Profile> profile) +{ + if (! id.eapi()->supported()) + { + Log::get_instance()->message("e.ebuild.unknown_eapi", ll_warning, lc_context) + << "Can't make the USE string for '" << id << "' because its EAPI is unsupported"; + return ""; + } + + std::string use; + + 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() == canonical_build_options_prefix()) + continue; + + for (Choice::ConstIterator i((*k)->begin()), i_end((*k)->end()) ; + i != i_end ; ++i) + if ((*i)->enabled()) + use += stringify((*i)->name_with_prefix()) + " "; + } + } + + if (! id.eapi()->supported()->ebuild_environment_variables()->env_arch().empty()) + use += profile->environment_variable(id.eapi()->supported()->ebuild_environment_variables()->env_arch()) + " "; + + return use; +} + +std::shared_ptr<Map<std::string, std::string> > +paludis::erepository::make_expand(const Environment * const, + const ERepositoryID & e, + std::shared_ptr<const Profile> profile) +{ + std::shared_ptr<Map<std::string, std::string> > expand_vars(std::make_shared<Map<std::string, std::string> >()); + + if (! e.eapi()->supported()) + { + Log::get_instance()->message("e.ebuild.unknown_eapi", ll_warning, lc_context) + << "Can't make the USE_EXPAND strings for '" << e << "' because its EAPI is unsupported"; + return expand_vars; + } + + if (! e.choices_key()) + return expand_vars; + + for (Set<std::string>::ConstIterator x(profile->use_expand()->begin()), x_end(profile->use_expand()->end()) ; + x != x_end ; ++x) + { + expand_vars->insert(stringify(*x), ""); + + Choices::ConstIterator k(std::find_if(e.choices_key()->value()->begin(), e.choices_key()->value()->end(), + std::bind(std::equal_to<std::string>(), *x, + std::bind(std::mem_fn(&Choice::raw_name), std::placeholders::_1)))); + if (k == e.choices_key()->value()->end()) + continue; + + for (Choice::ConstIterator i((*k)->begin()), i_end((*k)->end()) ; + i != i_end ; ++i) + if ((*i)->enabled()) + { + std::string value; + Map<std::string, std::string>::ConstIterator v(expand_vars->find(stringify(*x))); + if (expand_vars->end() != v) + { + value = v->second; + if (! value.empty()) + value.append(" "); + expand_vars->erase(v); + } + value.append(stringify((*i)->unprefixed_name())); + expand_vars->insert(stringify(*x), value); + } + } + + return expand_vars; +} diff --git a/paludis/repositories/e/make_use.hh b/paludis/repositories/e/make_use.hh new file mode 100644 index 000000000..acf40f008 --- /dev/null +++ b/paludis/repositories/e/make_use.hh @@ -0,0 +1,42 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2010 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_MAKE_USE_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_E_MAKE_USE_HH 1 + +#include <paludis/repositories/e/e_repository_id.hh> +#include <paludis/repositories/e/profile.hh> +#include <paludis/environment-fwd.hh> + +namespace paludis +{ + namespace erepository + { + std::string make_use(const Environment * const, + const ERepositoryID & id, + std::shared_ptr<const Profile> profile); + + std::shared_ptr<Map<std::string, std::string> > + make_expand(const Environment * const, + const ERepositoryID & e, + std::shared_ptr<const Profile> profile); + } +} + +#endif |