Exheredludis/paludis/repositories/unpackaged/installed_repository.cc
Saleem Abdulrasool 64ba7d5be8 modernize: use default method synthesis
Convert a number of destructors to default synthesized functions.  Try to
inline a few instances into the header.  It should be possible to inline all of
them, however, gcc seems to emit a number of warnings.  Furthermore, some of the
destructors are pure-virtualed, but provide an implementation.  Placing the
definition into the header causes ODR violations.
2016-08-06 11:58:04 -07:00

497 lines
18 KiB
C++

/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
* Copyright (c) 2007, 2008, 2009, 2010, 2011, 2013, 2014 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/unpackaged/installed_repository.hh>
#include <paludis/repositories/unpackaged/installed_id.hh>
#include <paludis/repositories/unpackaged/exceptions.hh>
#include <paludis/util/pimp-impl.hh>
#include <paludis/util/sequence.hh>
#include <paludis/util/stringify.hh>
#include <paludis/util/set.hh>
#include <paludis/util/system.hh>
#include <paludis/util/cookie.hh>
#include <paludis/util/visitor_cast.hh>
#include <paludis/util/make_named_values.hh>
#include <paludis/util/indirect_iterator-impl.hh>
#include <paludis/util/wrapped_forward_iterator.hh>
#include <paludis/util/safe_ofstream.hh>
#include <paludis/util/fs_iterator.hh>
#include <paludis/util/fs_stat.hh>
#include <paludis/util/return_literal_function.hh>
#include <paludis/ndbam.hh>
#include <paludis/ndbam_merger.hh>
#include <paludis/action.hh>
#include <paludis/environment.hh>
#include <paludis/metadata_key.hh>
#include <paludis/literal_metadata_key.hh>
#include <paludis/user_dep_spec.hh>
#include <paludis/generator.hh>
#include <paludis/filtered_generator.hh>
#include <paludis/filter.hh>
#include <paludis/selection.hh>
#include <paludis/hook.hh>
#include <paludis/common_sets.hh>
#include <paludis/unformatted_pretty_printer.hh>
#include <paludis/slot.hh>
#include <sstream>
#include <sys/time.h>
using namespace paludis;
using namespace paludis::unpackaged_repositories;
namespace
{
bool supported_installed_unpackaged(const std::string & s)
{
return s == "installed_unpackaged-1";
}
}
namespace paludis
{
template <>
struct Imp<InstalledUnpackagedRepository>
{
const InstalledUnpackagedRepositoryParams params;
mutable NDBAM ndbam;
std::shared_ptr<const MetadataValueKey<FSPath> > location_key;
std::shared_ptr<const MetadataValueKey<FSPath> > root_key;
std::shared_ptr<const MetadataValueKey<std::string> > format_key;
Imp(const InstalledUnpackagedRepositoryParams & p) :
params(p),
ndbam(p.location(), &supported_installed_unpackaged, "installed_unpackaged-1", user_version_spec_options()),
location_key(std::make_shared<LiteralMetadataValueKey<FSPath> >("location", "location",
mkt_significant, params.location())),
root_key(std::make_shared<LiteralMetadataValueKey<FSPath> >("root", "root",
mkt_normal, params.root())),
format_key(std::make_shared<LiteralMetadataValueKey<std::string> >(
"format", "format", mkt_significant, "installed_unpackaged"))
{
}
};
}
InstalledUnpackagedRepository::InstalledUnpackagedRepository(
const RepositoryName & n, const InstalledUnpackagedRepositoryParams & p) :
Repository(p.environment(), n, make_named_values<RepositoryCapabilities>(
n::destination_interface() = this,
n::environment_variable_interface() = static_cast<RepositoryEnvironmentVariableInterface *>(nullptr),
n::manifest_interface() = static_cast<RepositoryManifestInterface *>(nullptr)
)),
_imp(p)
{
_add_metadata_keys();
}
InstalledUnpackagedRepository::~InstalledUnpackagedRepository() = default;
void
InstalledUnpackagedRepository::_add_metadata_keys() const
{
clear_metadata_keys();
add_metadata_key(_imp->location_key);
add_metadata_key(_imp->root_key);
add_metadata_key(_imp->format_key);
}
std::shared_ptr<const PackageIDSequence>
InstalledUnpackagedRepository::package_ids(const QualifiedPackageName & q, const RepositoryContentMayExcludes &) const
{
std::shared_ptr<NDBAMEntrySequence> entries(_imp->ndbam.entries(q));
std::shared_ptr<PackageIDSequence> result(std::make_shared<PackageIDSequence>());
for (IndirectIterator<NDBAMEntrySequence::ConstIterator> e(entries->begin()), e_end(entries->end()) ;
e != e_end ; ++e)
{
std::unique_lock<std::mutex> l(*(*e).mutex());
if (! (*e).package_id())
(*e).package_id() = std::make_shared<InstalledUnpackagedID>(_imp->params.environment(), (*e).name(), (*e).version(),
(*e).slot(), name(), (*e).fs_location(), (*e).magic(), installed_root_key()->parse_value(), &_imp->ndbam);
result->push_back((*e).package_id());
}
return result;
}
std::shared_ptr<const QualifiedPackageNameSet>
InstalledUnpackagedRepository::package_names(const CategoryNamePart & c, const RepositoryContentMayExcludes &) const
{
return _imp->ndbam.package_names(c);
}
std::shared_ptr<const CategoryNamePartSet>
InstalledUnpackagedRepository::category_names(const RepositoryContentMayExcludes &) const
{
return _imp->ndbam.category_names();
}
std::shared_ptr<const CategoryNamePartSet>
InstalledUnpackagedRepository::category_names_containing_package(
const PackageNamePart & p, const RepositoryContentMayExcludes &) const
{
return _imp->ndbam.category_names_containing_package(p);
}
bool
InstalledUnpackagedRepository::has_package_named(const QualifiedPackageName & q, const RepositoryContentMayExcludes &) const
{
return _imp->ndbam.has_package_named(q);
}
bool
InstalledUnpackagedRepository::has_category_named(const CategoryNamePart & c, const RepositoryContentMayExcludes &) const
{
return _imp->ndbam.has_category_named(c);
}
bool
InstalledUnpackagedRepository::some_ids_might_support_action(const SupportsActionTestBase & test) const
{
return test.make_accept_returning(
[&] (const SupportsActionTest<UninstallAction> &) { return true; },
[&] (const SupportsActionTest<ConfigAction> &) { return false; },
[&] (const SupportsActionTest<InfoAction> &) { return false; },
[&] (const SupportsActionTest<PretendAction> &) { return false; },
[&] (const SupportsActionTest<FetchAction> &) { return false; },
[&] (const SupportsActionTest<PretendFetchAction> &) { return false; },
[&] (const SupportsActionTest<InstallAction> &) { return false; }
);
}
bool
InstalledUnpackagedRepository::some_ids_might_not_be_masked() const
{
return true;
}
const bool
InstalledUnpackagedRepository::is_unimportant() const
{
return false;
}
namespace
{
std::pair<uid_t, gid_t>
get_new_ids_or_minus_one(const Environment * const env, const int rewrite_ids_over_to_root, const FSPath & f)
{
uid_t uid;
gid_t gid;
FSStat f_stat(f);
if (f_stat.owner() == env->reduced_uid() || (rewrite_ids_over_to_root != -1
&& f_stat.owner() > static_cast<unsigned int>(rewrite_ids_over_to_root)))
uid = 0;
else
uid = -1;
if (f_stat.group() == env->reduced_gid() || (rewrite_ids_over_to_root != -1
&& f_stat.group() > static_cast<unsigned int>(rewrite_ids_over_to_root)))
gid = 0;
else
gid = -1;
return std::make_pair(uid, gid);
}
bool parallel_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()->parse_value().parallel_value() == b->slot_key()->parse_value().parallel_value();
else
return ! b->slot_key();
}
}
void
InstalledUnpackagedRepository::merge(const MergeParams & m)
{
using namespace std::placeholders;
Context context("When merging '" + stringify(*m.package_id()) + "' at '" + stringify(m.image_dir())
+ "' to InstalledUnpackagedRepository repository '" + stringify(name()) + "':");
if (! is_suitable_destination_for(m.package_id()))
throw ActionFailedError("Not a suitable destination for '" + stringify(*m.package_id()) + "'");
auto repo(_imp->params.environment()->fetch_repository(m.package_id()->repository_name()));
FSPath install_under("/");
{
Repository::MetadataConstIterator k(repo->find_metadata("install_under"));
if (k == repo->end_metadata())
throw ActionFailedError("Could not fetch install_under key from owning repository");
const MetadataValueKey<FSPath> * kk(visitor_cast<const MetadataValueKey<FSPath> >(**k));
if (! kk)
throw ActionFailedError("Fetched install_under key but did not get an FSPath key from owning repository");
install_under = kk->parse_value();
}
int rewrite_ids_over_to_root(-1);
{
Repository::MetadataConstIterator k(repo->find_metadata("rewrite_ids_over_to_root"));
if (k == repo->end_metadata())
throw ActionFailedError("Could not fetch rewrite_ids_over_to_root key from owning repository");
const MetadataValueKey<long> * kk(visitor_cast<const MetadataValueKey<long> >(**k));
if (! kk)
throw ActionFailedError("Fetched rewrite_ids_over_to_root key but did not get a long key from owning repository");
rewrite_ids_over_to_root = kk->parse_value();
}
std::shared_ptr<const PackageID> if_overwritten_id, if_same_name_id;
{
std::shared_ptr<const PackageIDSequence> ids(package_ids(m.package_id()->name(), { }));
for (PackageIDSequence::ConstIterator v(ids->begin()), v_end(ids->end()) ;
v != v_end ; ++v)
{
if_same_name_id = *v;
if ((*v)->version() == m.package_id()->version() && parallel_slot_is_same(*v, m.package_id()))
{
if_overwritten_id = *v;
break;
}
}
}
FSPath uid_dir(_imp->params.location());
if (if_same_name_id)
uid_dir = if_same_name_id->fs_location_key()->parse_value().dirname();
else
{
std::string uid(stringify(m.package_id()->name().category()) + "---" + stringify(m.package_id()->name().package()));
uid_dir /= "data";
if (! m.check())
uid_dir.mkdir(0755, { fspmkdo_ok_if_exists });
uid_dir /= uid;
if (! m.check())
uid_dir.mkdir(0755, { fspmkdo_ok_if_exists });
}
FSPath target_ver_dir(uid_dir);
target_ver_dir /= (stringify(m.package_id()->version()) + ":" + stringify(m.package_id()->slot_key()->parse_value().parallel_value()) + ":" + cookie());
if (target_ver_dir.stat().exists())
throw ActionFailedError("Temporary merge directory '" + stringify(target_ver_dir) + "' already exists, probably "
"due to a previous failed install. If it is safe to do so, please remove this directory and try again.");
if (! m.check())
target_ver_dir.mkdir(0755, { });
if (! m.check())
{
{
SafeOFStream source_repository_file(target_ver_dir / "source_repository", -1, true);
source_repository_file << m.package_id()->repository_name() << std::endl;
}
if (m.package_id()->short_description_key())
{
SafeOFStream description_file(target_ver_dir / "description", -1, true);
description_file << m.package_id()->short_description_key()->parse_value() << std::endl;
}
if (m.package_id()->build_dependencies_key())
{
SafeOFStream build_dependencies_file(target_ver_dir / "build_dependencies", -1, true);
build_dependencies_file << m.package_id()->build_dependencies_key()->pretty_print_value(UnformattedPrettyPrinter(), { }) << std::endl;
}
if (m.package_id()->run_dependencies_key())
{
SafeOFStream run_dependencies_file(target_ver_dir / "run_dependencies", -1, true);
run_dependencies_file << m.package_id()->run_dependencies_key()->pretty_print_value(UnformattedPrettyPrinter(), { }) << std::endl;
}
}
NDBAMMerger merger(
make_named_values<NDBAMMergerParams>(
n::config_protect() = getenv_with_default("CONFIG_PROTECT", ""),
n::config_protect_mask() = getenv_with_default("CONFIG_PROTECT_MASK", ""),
n::contents_file() = target_ver_dir / "contents",
n::environment() = _imp->params.environment(),
n::fix_mtimes_before() = m.build_start_time(),
n::fs_merger_options() = FSMergerOptions(),
n::get_new_ids_or_minus_one() = std::bind(&get_new_ids_or_minus_one,
_imp->params.environment(), rewrite_ids_over_to_root, _1),
n::image() = m.image_dir(),
n::install_under() = install_under,
n::is_volatile() = m.is_volatile(),
n::merged_entries() = std::make_shared<FSPathSet>(),
n::options() = m.options(),
n::output_manager() = m.output_manager(),
n::package_id() = m.package_id(),
n::parts() = m.parts(),
n::permit_destination() = m.permit_destination(),
n::root() = installed_root_key()->parse_value().realpath(),
n::should_merge() = nullptr
));
if (m.check())
{
if (! merger.check())
throw ActionFailedError("Not proceeding with install due to merge sanity check failing");
return;
}
merger.merge();
_imp->ndbam.index(m.package_id()->name(), uid_dir.basename());
if (if_overwritten_id)
{
std::static_pointer_cast<const InstalledUnpackagedID>(if_overwritten_id)->uninstall(true,
if_overwritten_id, m.output_manager());
}
}
bool
InstalledUnpackagedRepository::is_suitable_destination_for(const std::shared_ptr<const PackageID> & id) const
{
auto repo(_imp->params.environment()->fetch_repository(id->repository_name()));
std::string f(repo->format_key() ? repo->format_key()->parse_value() : "");
return f == "unpackaged";
}
bool
InstalledUnpackagedRepository::want_pre_post_phases() const
{
return true;
}
void
InstalledUnpackagedRepository::invalidate()
{
_imp.reset(new Imp<InstalledUnpackagedRepository>(_imp->params));
_add_metadata_keys();
}
void
InstalledUnpackagedRepository::deindex(const QualifiedPackageName & q) const
{
_imp->ndbam.deindex(q);
}
void
InstalledUnpackagedRepository::need_keys_added() const
{
}
const std::shared_ptr<const MetadataValueKey<std::string> >
InstalledUnpackagedRepository::format_key() const
{
return _imp->format_key;
}
const std::shared_ptr<const MetadataValueKey<FSPath> >
InstalledUnpackagedRepository::location_key() const
{
return _imp->location_key;
}
const std::shared_ptr<const MetadataValueKey<FSPath> >
InstalledUnpackagedRepository::installed_root_key() const
{
return _imp->root_key;
}
std::shared_ptr<Repository>
InstalledUnpackagedRepository::repository_factory_create(
Environment * const env,
const std::function<std::string (const std::string &)> & f)
{
Context context("When creating InstalledUnpackagedRepository:");
std::string location(f("location"));
if (location.empty())
throw unpackaged_repositories::RepositoryConfigurationError("Key 'location' not specified or empty");
std::string root(f("root"));
if (root.empty())
throw unpackaged_repositories::RepositoryConfigurationError("Key 'root' not specified or empty");
std::string name_str(f("name"));
if (name_str.empty())
name_str = "installed-unpackaged";
return std::make_shared<InstalledUnpackagedRepository>(RepositoryName(name_str),
make_named_values<unpackaged_repositories::InstalledUnpackagedRepositoryParams>(
n::environment() = env,
n::location() = location,
n::root() = root
));
}
RepositoryName
InstalledUnpackagedRepository::repository_factory_name(
const Environment * const,
const std::function<std::string (const std::string &)> &)
{
return RepositoryName("installed-unpackaged");
}
std::shared_ptr<const RepositoryNameSet>
InstalledUnpackagedRepository::repository_factory_dependencies(
const Environment * const,
const std::function<std::string (const std::string &)> &)
{
return std::make_shared<RepositoryNameSet>();
}
void
InstalledUnpackagedRepository::populate_sets() const
{
add_common_sets_for_installed_repo(_imp->params.environment(), *this);
}
HookResult
InstalledUnpackagedRepository::perform_hook(const Hook &, const std::shared_ptr<OutputManager> &)
{
return make_named_values<HookResult>(n::max_exit_status() = 0, n::output() = "");
}
bool
InstalledUnpackagedRepository::sync(
const std::string &,
const std::string &,
const std::shared_ptr<OutputManager> &) const
{
return false;
}
const std::shared_ptr<const MetadataCollectionKey<Map<std::string, std::string> > >
InstalledUnpackagedRepository::sync_host_key() const
{
return nullptr;
}
const std::shared_ptr<const Set<std::string> >
InstalledUnpackagedRepository::maybe_expand_licence_nonrecursively(const std::string &) const
{
return nullptr;
}