diff options
author | 2008-08-12 19:25:21 +0100 | |
---|---|---|
committer | 2008-08-16 21:43:31 +0100 | |
commit | 767fb3805f9629ebc36888a35023eda943089819 (patch) | |
tree | 99f37ccbbd138ea72ea435b4005b57e5aa9698db | |
parent | 9035495cebefab9829c69d8abea3caf0e8b6ff2b (diff) | |
download | paludis-767fb3805f9629ebc36888a35023eda943089819.tar.gz paludis-767fb3805f9629ebc36888a35023eda943089819.tar.xz |
Support for Portage's flat_hash cache format. Fixes: ticket:630
Use flat_hash for the write_cache, and drop flat_list support for
non-Gentoo EAPIs.
-rw-r--r-- | paludis/repositories/e/eapi.cc | 4 | ||||
-rw-r--r-- | paludis/repositories/e/eapi.hh | 8 | ||||
-rw-r--r-- | paludis/repositories/e/eapis/0.conf | 46 | ||||
-rw-r--r-- | paludis/repositories/e/eapis/exheres-0.conf | 46 | ||||
-rw-r--r-- | paludis/repositories/e/eapis/kdebuild-1.conf | 3 | ||||
-rw-r--r-- | paludis/repositories/e/eapis/paludis-1.conf | 48 | ||||
-rw-r--r-- | paludis/repositories/e/eapis/pbin-1+0.conf | 3 | ||||
-rw-r--r-- | paludis/repositories/e/eapis/pbin-1+1.conf | 3 | ||||
-rw-r--r-- | paludis/repositories/e/eapis/pbin-1+exheres-0.conf | 2 | ||||
-rw-r--r-- | paludis/repositories/e/eapis/pbin-1+paludis-1.conf | 3 | ||||
-rw-r--r-- | paludis/repositories/e/ebuild_entries.cc | 2 | ||||
-rw-r--r-- | paludis/repositories/e/ebuild_flat_metadata_cache.cc | 890 | ||||
-rw-r--r-- | paludis/repositories/e/ebuild_flat_metadata_cache.hh | 21 | ||||
-rw-r--r-- | paludis/repositories/e/eclass_mtimes.cc | 79 | ||||
-rw-r--r-- | paludis/repositories/e/eclass_mtimes.hh | 16 |
15 files changed, 751 insertions, 423 deletions
diff --git a/paludis/repositories/e/eapi.cc b/paludis/repositories/e/eapi.cc index 44103dfc2..b77af586e 100644 --- a/paludis/repositories/e/eapi.cc +++ b/paludis/repositories/e/eapi.cc @@ -88,7 +88,7 @@ namespace { return make_named_values<EAPIMetadataVariable>( value_for<n::description>(check_get(k, "description_" + s)), - value_for<n::flat_cache_index>(destringify_key<int>(k, "flat_cache_" + s)), + value_for<n::flat_list_index>(destringify_key<int>(k, "flat_list_" + s)), value_for<n::name>(check_get(k, "metadata_" + s)) ); } @@ -106,7 +106,7 @@ namespace value_for<n::keywords>(make_metadata_variable(k, "keywords")), value_for<n::license>(make_metadata_variable(k, "license")), value_for<n::long_description>(make_metadata_variable(k, "long_description")), - value_for<n::minimum_flat_cache_size>(destringify_key<int>(k, "flat_cache_minimum_size")), + value_for<n::minimum_flat_list_size>(destringify_key<int>(k, "flat_list_minimum_size")), value_for<n::pdepend>(make_metadata_variable(k, "pdepend")), value_for<n::provide>(make_metadata_variable(k, "provide")), value_for<n::remote_ids>(make_metadata_variable(k, "remote_ids")), diff --git a/paludis/repositories/e/eapi.hh b/paludis/repositories/e/eapi.hh index e40382b8a..e26d444a2 100644 --- a/paludis/repositories/e/eapi.hh +++ b/paludis/repositories/e/eapi.hh @@ -82,7 +82,7 @@ namespace paludis struct exported_name; struct f_function_prefix; struct failure_is_fatal; - struct flat_cache_index; + struct flat_list_index; struct homepage; struct ignore_pivot_env_functions; struct ignore_pivot_env_variables; @@ -95,7 +95,7 @@ namespace paludis struct long_description; struct merger_options; struct metadata_key; - struct minimum_flat_cache_size; + struct minimum_flat_list_size; struct must_not_change_variables; struct name; struct no_slot_or_repo; @@ -237,7 +237,7 @@ namespace paludis struct EAPIMetadataVariable { NamedValue<n::description, std::string> description; - NamedValue<n::flat_cache_index, int> flat_cache_index; + NamedValue<n::flat_list_index, int> flat_list_index; NamedValue<n::name, std::string> name; }; @@ -253,7 +253,7 @@ namespace paludis NamedValue<n::keywords, EAPIMetadataVariable> keywords; NamedValue<n::license, EAPIMetadataVariable> license; NamedValue<n::long_description, EAPIMetadataVariable> long_description; - NamedValue<n::minimum_flat_cache_size, int> minimum_flat_cache_size; + NamedValue<n::minimum_flat_list_size, int> minimum_flat_list_size; NamedValue<n::pdepend, EAPIMetadataVariable> pdepend; NamedValue<n::provide, EAPIMetadataVariable> provide; NamedValue<n::remote_ids, EAPIMetadataVariable> remote_ids; diff --git a/paludis/repositories/e/eapis/0.conf b/paludis/repositories/e/eapis/0.conf index 97d389895..0440cc4dd 100644 --- a/paludis/repositories/e/eapis/0.conf +++ b/paludis/repositories/e/eapis/0.conf @@ -174,29 +174,29 @@ metadata_src_uri = SRC_URI metadata_use = metadata_dependencies = -flat_cache_minimum_size = 15 -flat_cache_build_depend = 0 -flat_cache_short_description = 7 -flat_cache_long_description = -1 -flat_cache_eapi = 14 -flat_cache_dependencies = -1 -flat_cache_homepage = 5 -flat_cache_inherited = 9 -flat_cache_iuse = 10 -flat_cache_keywords = 8 -flat_cache_license = 6 -flat_cache_pdepend = 12 -flat_cache_provide = 13 -flat_cache_restrict = 4 -flat_cache_run_depend = 1 -flat_cache_slot = 2 -flat_cache_src_uri = 3 -flat_cache_use = -1 -flat_cache_bugs_to = -1 -flat_cache_remote_ids = -1 -flat_cache_upstream_changelog = -1 -flat_cache_upstream_release_notes = -1 -flat_cache_upstream_documentation = -1 +flat_list_minimum_size = 15 +flat_list_build_depend = 0 +flat_list_short_description = 7 +flat_list_long_description = -1 +flat_list_eapi = 14 +flat_list_dependencies = -1 +flat_list_homepage = 5 +flat_list_inherited = 9 +flat_list_iuse = 10 +flat_list_keywords = 8 +flat_list_license = 6 +flat_list_pdepend = 12 +flat_list_provide = 13 +flat_list_restrict = 4 +flat_list_run_depend = 1 +flat_list_slot = 2 +flat_list_src_uri = 3 +flat_list_use = -1 +flat_list_bugs_to = -1 +flat_list_remote_ids = -1 +flat_list_upstream_changelog = -1 +flat_list_upstream_release_notes = -1 +flat_list_upstream_documentation = -1 env_use = USE env_use_expand = USE_EXPAND diff --git a/paludis/repositories/e/eapis/exheres-0.conf b/paludis/repositories/e/eapis/exheres-0.conf index cc2feca84..d3639bbf1 100644 --- a/paludis/repositories/e/eapis/exheres-0.conf +++ b/paludis/repositories/e/eapis/exheres-0.conf @@ -193,29 +193,29 @@ description_upstream_changelog = Upstream changelog description_upstream_release_notes = Upstream release notes description_upstream_documentation = Upstream documentation -flat_cache_minimum_size = 18 -flat_cache_build_depend = -1 -flat_cache_short_description = 7 -flat_cache_long_description = 11 -flat_cache_eapi = 14 -flat_cache_dependencies = 1 -flat_cache_homepage = 5 -flat_cache_inherited = 9 -flat_cache_iuse = 10 -flat_cache_keywords = 8 -flat_cache_license = 6 -flat_cache_pdepend = -1 -flat_cache_provide = -1 -flat_cache_restrict = 4 -flat_cache_run_depend = -1 -flat_cache_slot = 2 -flat_cache_src_uri = 3 -flat_cache_use = -1 -flat_cache_bugs_to = 12 -flat_cache_remote_ids = 13 -flat_cache_upstream_changelog = 15 -flat_cache_upstream_release_notes = 16 -flat_cache_upstream_documentation = 17 +flat_list_minimum_size = -1 +flat_list_build_depend = -1 +flat_list_short_description = -1 +flat_list_long_description = -1 +flat_list_eapi = -1 +flat_list_dependencies = -1 +flat_list_homepage = -1 +flat_list_inherited = -1 +flat_list_iuse = -1 +flat_list_keywords = -1 +flat_list_license = -1 +flat_list_pdepend = -1 +flat_list_provide = -1 +flat_list_restrict = -1 +flat_list_run_depend = -1 +flat_list_slot = -1 +flat_list_src_uri = -1 +flat_list_use = -1 +flat_list_bugs_to = -1 +flat_list_remote_ids = -1 +flat_list_upstream_changelog = -1 +flat_list_upstream_release_notes = -1 +flat_list_upstream_documentation = -1 env_use = OPTIONS env_use_expand = SUBOPTIONS diff --git a/paludis/repositories/e/eapis/kdebuild-1.conf b/paludis/repositories/e/eapis/kdebuild-1.conf index f191379e7..fe4d0fe56 100644 --- a/paludis/repositories/e/eapis/kdebuild-1.conf +++ b/paludis/repositories/e/eapis/kdebuild-1.conf @@ -20,7 +20,8 @@ ebuild_must_not_set_variables = ${ebuild_must_not_set_variables} PROVIDE must_not_change_variables = ${must_not_change_variables} EAPI description_provide = metadata_provide = -flat_cache_provide = -1 + +flat_list_minimum_size = -1 ebuild_install = \ : killold ; \ diff --git a/paludis/repositories/e/eapis/paludis-1.conf b/paludis/repositories/e/eapis/paludis-1.conf index 799d2bcfb..28a60998c 100644 --- a/paludis/repositories/e/eapis/paludis-1.conf +++ b/paludis/repositories/e/eapis/paludis-1.conf @@ -179,30 +179,30 @@ description_src_uri = Source URI description_use = Selected USE flags description_dependencies = -flat_cache_minimum_size = 15 -flat_cache_build_depend = 0 -flat_cache_short_description = 7 -flat_cache_long_description = -1 -flat_cache_eapi = 14 -flat_cache_dependencies = -1 -flat_cache_homepage = 5 -flat_cache_inherited = 9 -flat_cache_iuse = 10 -flat_cache_keywords = 8 -flat_cache_license = 6 -flat_cache_pdepend = 12 -flat_cache_provide = 13 -flat_cache_restrict = 4 -flat_cache_run_depend = 1 -flat_cache_slot = 2 -flat_cache_src_uri = 3 -flat_cache_use = -1 -flat_cache_use = -1 -flat_cache_bugs_to = -1 -flat_cache_remote_ids = -1 -flat_cache_upstream_changelog = -1 -flat_cache_upstream_release_notes = -1 -flat_cache_upstream_documentation = -1 +flat_list_minimum_size = -1 +flat_list_build_depend = -1 +flat_list_short_description = -1 +flat_list_long_description = -1 +flat_list_eapi = -1 +flat_list_dependencies = -1 +flat_list_homepage = -1 +flat_list_inherited = -1 +flat_list_iuse = -1 +flat_list_keywords = -1 +flat_list_license = -1 +flat_list_pdepend = -1 +flat_list_provide = -1 +flat_list_restrict = -1 +flat_list_run_depend = -1 +flat_list_slot = -1 +flat_list_src_uri = -1 +flat_list_use = -1 +flat_list_use = -1 +flat_list_bugs_to = -1 +flat_list_remote_ids = -1 +flat_list_upstream_changelog = -1 +flat_list_upstream_release_notes = -1 +flat_list_upstream_documentation = -1 env_use = USE env_use_expand = USE_EXPAND diff --git a/paludis/repositories/e/eapis/pbin-1+0.conf b/paludis/repositories/e/eapis/pbin-1+0.conf index accc1324a..fa035b64e 100644 --- a/paludis/repositories/e/eapis/pbin-1+0.conf +++ b/paludis/repositories/e/eapis/pbin-1+0.conf @@ -36,6 +36,5 @@ metadata_keywords = BINARY_KEYWORDS metadata_src_uri = BINARY_URI metadata_use = USE -flat_cache_minimum_size = 16 -flat_cache_use = 15 +flat_list_minimum_size = -1 diff --git a/paludis/repositories/e/eapis/pbin-1+1.conf b/paludis/repositories/e/eapis/pbin-1+1.conf index 986498012..529a6e7e1 100644 --- a/paludis/repositories/e/eapis/pbin-1+1.conf +++ b/paludis/repositories/e/eapis/pbin-1+1.conf @@ -36,6 +36,5 @@ metadata_keywords = BINARY_KEYWORDS metadata_src_uri = BINARY_URI metadata_use = USE -flat_cache_minimum_size = 16 -flat_cache_use = 15 +flat_list_minimum_size = -1 diff --git a/paludis/repositories/e/eapis/pbin-1+exheres-0.conf b/paludis/repositories/e/eapis/pbin-1+exheres-0.conf index 60e0616da..99272bb24 100644 --- a/paludis/repositories/e/eapis/pbin-1+exheres-0.conf +++ b/paludis/repositories/e/eapis/pbin-1+exheres-0.conf @@ -36,5 +36,5 @@ metadata_keywords = BINARY_PLATFORMS metadata_src_uri = BINARY_URI metadata_use = OPTIONS -flat_cache_use = 12 +flat_list_minimum_size = -1 diff --git a/paludis/repositories/e/eapis/pbin-1+paludis-1.conf b/paludis/repositories/e/eapis/pbin-1+paludis-1.conf index 8b7335fcc..7e87c476d 100644 --- a/paludis/repositories/e/eapis/pbin-1+paludis-1.conf +++ b/paludis/repositories/e/eapis/pbin-1+paludis-1.conf @@ -36,6 +36,5 @@ metadata_keywords = BINARY_KEYWORDS metadata_src_uri = BINARY_URI metadata_use = USE -flat_cache_minimum_size = 16 -flat_cache_use = 15 +flat_list_minimum_size = -1 diff --git a/paludis/repositories/e/ebuild_entries.cc b/paludis/repositories/e/ebuild_entries.cc index e8f9db6e2..82616f4ef 100644 --- a/paludis/repositories/e/ebuild_entries.cc +++ b/paludis/repositories/e/ebuild_entries.cc @@ -124,7 +124,7 @@ namespace paludis environment(e), e_repository(p), params(k), - eclass_mtimes(new EclassMtimes(k.eclassdirs)), + eclass_mtimes(new EclassMtimes(p, k.eclassdirs)), master_mtime(0) { FSEntry m(k.location / "metadata" / "timestamp"); diff --git a/paludis/repositories/e/ebuild_flat_metadata_cache.cc b/paludis/repositories/e/ebuild_flat_metadata_cache.cc index 0ad336637..4d570ed6c 100644 --- a/paludis/repositories/e/ebuild_flat_metadata_cache.cc +++ b/paludis/repositories/e/ebuild_flat_metadata_cache.cc @@ -2,6 +2,7 @@ /* * Copyright (c) 2006, 2007, 2008 Ciaran McCreesh + * Copyright (c) 2008 David Leverton * * 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 @@ -23,6 +24,7 @@ #include <paludis/util/join.hh> #include <paludis/util/visitor-impl.hh> #include <paludis/util/set.hh> +#include <paludis/util/destringify.hh> #include <paludis/repositories/e/dep_spec_pretty_printer.hh> #include <paludis/repositories/e/dep_parser.hh> #include <paludis/repositories/e/dependencies_rewriter.hh> @@ -31,6 +33,7 @@ #include <tr1/functional> #include <fstream> #include <set> +#include <map> #include <list> #include <vector> #include <functional> @@ -41,14 +44,230 @@ using namespace paludis; using namespace paludis::erepository; +namespace paludis +{ + template <> + struct Implementation<EbuildFlatMetadataCache> + { + const Environment * const env; + const FSEntry & filename; + const FSEntry & ebuild; + time_t master_mtime; + std::tr1::shared_ptr<const EclassMtimes> eclass_mtimes; + bool silent; + + Implementation(const Environment * const e, const FSEntry & f, const FSEntry & eb, + time_t m, const std::tr1::shared_ptr<const EclassMtimes> em, bool s) : + env(e), + filename(f), + ebuild(eb), + master_mtime(m), + eclass_mtimes(em), + silent(s) + { + } + }; +} + +namespace +{ + bool load_flat_list( + const std::tr1::shared_ptr<const EbuildID> & id, const std::vector<std::string> & lines, Implementation<EbuildFlatMetadataCache> * _imp) + { + Context ctx("When loading flat_list format cache file:"); + + if (lines.size() < 15) + { + Log::get_instance()->message("e.cache.flat_list.truncated", ll_warning, lc_no_context) + << "cache file has " << lines.size() << " lines, but expected at least 15"; + return false; + } + + id->set_eapi(lines[14]); + + if (id->eapi()->supported()) + { + const EAPIEbuildMetadataVariables & m(*id->eapi()->supported()->ebuild_metadata_variables()); + if (-1 == m.minimum_flat_list_size()) + { + Log::get_instance()->message("e.cache.flat_list.unsupported", ll_warning, lc_context) + << "flat_list cache is not supported for EAPI '" << id->eapi()->name() << "'"; + return false; + } + + if (static_cast<int>(lines.size()) < m.minimum_flat_list_size()) + { + Log::get_instance()->message("e.cache.flat_list.truncated", ll_warning, lc_context) + << "cache file has " << lines.size() << " lines, but expected at least " << m.minimum_flat_list_size(); + return false; + } + + { + time_t cache_time(std::max(_imp->master_mtime, _imp->filename.mtime())); + bool ok(_imp->ebuild.mtime() <= cache_time); + if (! ok) + Log::get_instance()->message("e.cache.flat_list.mtime", ll_debug, lc_context) + << "ebuild has mtime " << _imp->ebuild.mtime() << ", but expected at most " << cache_time; + + if (ok) + { + std::set<std::string> tokens; + tokenise_whitespace(lines[m.inherited().flat_list_index()], std::inserter(tokens, tokens.begin())); + FSEntry eclassdir(id->repository()->location_key()->value() / "eclass"); + for (std::set<std::string>::const_iterator it(tokens.begin()), + it_end(tokens.end()); it_end != it; ++it) + { + const FSEntry * eclass(_imp->eclass_mtimes->eclass(*it)); + if (! eclass) + { + Log::get_instance()->message("e.cache.flat_list.eclass.missing", ll_debug, lc_context) + << "Can't find cache-requested eclass '" << *it << "'"; + ok = false; + } + + else if (eclass->dirname() != eclassdir) + { + Log::get_instance()->message("e.cache.flat_list.eclass.wrong_location", ll_debug, lc_context) + << "Cache-requested eclass '" << *it << "' was found at '" + << eclass->dirname() << "', but expected '" << eclassdir << "'"; + ok = false; + } + + else if (eclass->mtime() > cache_time) + { + Log::get_instance()->message("e.cache.flat_list.eclass.wrong_mtime", ll_debug, lc_context) + << "Cache-requested eclass '" << *it << "' has mtime " + << eclass->mtime() << ", but expected at most " << cache_time; + ok = false; + } + + if (! ok) + break; + } + } + + if (! ok) + { + Log::get_instance()->message("e.cache.stale", ll_warning, lc_no_context) + << "Stale cache file at '" << _imp->filename << "'"; + return false; + } + } + + if (-1 != m.dependencies().flat_list_index() && ! m.dependencies().name().empty()) + { + DependenciesRewriter rewriter; + parse_depend(lines.at(m.dependencies().flat_list_index()), _imp->env, id, *id->eapi())->accept(rewriter); + id->load_build_depend(m.dependencies().name() + ".DEPEND", m.dependencies().description() + " (build)", rewriter.depend()); + id->load_run_depend(m.dependencies().name() + ".RDEPEND", m.dependencies().description() + " (run)", rewriter.rdepend()); + id->load_post_depend(m.dependencies().name() + ".PDEPEND", m.dependencies().description() + " (post)", rewriter.pdepend()); + } + + if (-1 != m.build_depend().flat_list_index() && ! m.build_depend().name().empty()) + id->load_build_depend(m.build_depend().name(), m.build_depend().description(), lines.at(m.build_depend().flat_list_index())); + + if (-1 != m.run_depend().flat_list_index() && ! m.run_depend().name().empty()) + id->load_run_depend(m.run_depend().name(), m.run_depend().description(), lines.at(m.run_depend().flat_list_index())); + + id->set_slot(SlotName(lines.at(m.slot().flat_list_index()))); + + if (-1 != m.src_uri().flat_list_index() && ! m.src_uri().name().empty()) + id->load_src_uri(m.src_uri().name(), m.src_uri().description(), lines.at(m.src_uri().flat_list_index())); + + if (-1 != m.restrictions().flat_list_index() && ! m.restrictions().name().empty()) + id->load_restrict(m.restrictions().name(), m.restrictions().description(), lines.at(m.restrictions().flat_list_index())); + + if (-1 != m.homepage().flat_list_index() && ! m.homepage().name().empty()) + id->load_homepage(m.homepage().name(), m.homepage().description(), lines.at(m.homepage().flat_list_index())); + + if (-1 != m.license().flat_list_index() && ! m.license().name().empty()) + id->load_license(m.license().name(), m.license().description(), lines.at(m.license().flat_list_index())); + + if (-1 != m.short_description().flat_list_index() && ! m.short_description().name().empty()) + id->load_short_description(m.short_description().name(), + m.short_description().description(), + lines.at(m.short_description().flat_list_index())); + + if (-1 != m.long_description().flat_list_index() && ! m.long_description().name().empty()) + { + std::string value(lines.at(m.long_description().flat_list_index())); + if (! value.empty()) + id->load_long_description(m.long_description().name(), + m.long_description().description(), value); + } + + if (-1 != m.keywords().flat_list_index() && ! m.keywords().name().empty()) + id->load_keywords(m.keywords().name(), m.keywords().description(), lines.at(m.keywords().flat_list_index())); + + if (-1 != m.inherited().flat_list_index() && ! m.inherited().name().empty()) + id->load_inherited(m.inherited().name(), m.inherited().description(), lines.at(m.inherited().flat_list_index())); + + if (-1 != m.iuse().flat_list_index() && ! m.iuse().name().empty()) + id->load_iuse(m.iuse().name(), m.iuse().description(), lines.at(m.iuse().flat_list_index())); + + if (-1 != m.pdepend().flat_list_index() && ! m.pdepend().name().empty()) + id->load_post_depend(m.pdepend().name(), m.pdepend().description(), lines.at(m.pdepend().flat_list_index())); + + if (-1 != m.provide().flat_list_index() && ! m.provide().name().empty()) + id->load_provide(m.provide().name(), m.provide().description(), lines.at(m.provide().flat_list_index())); + + if (-1 != m.use().flat_list_index() && ! m.use().name().empty()) + id->load_use(m.use().name(), m.use().description(), lines.at(m.use().flat_list_index())); + + if (-1 != m.upstream_changelog().flat_list_index() && ! m.upstream_changelog().name().empty()) + { + std::string value(lines.at(m.upstream_changelog().flat_list_index())); + if (! value.empty()) + id->load_upstream_changelog(m.upstream_changelog().name(), + m.upstream_changelog().description(), value); + } + + if (-1 != m.upstream_documentation().flat_list_index() && ! m.upstream_documentation().name().empty()) + { + std::string value(lines.at(m.upstream_documentation().flat_list_index())); + if (! value.empty()) + id->load_upstream_documentation(m.upstream_documentation().name(), + m.upstream_documentation().description(), value); + } + + if (-1 != m.upstream_release_notes().flat_list_index() && ! m.upstream_release_notes().name().empty()) + { + std::string value(lines.at(m.upstream_release_notes().flat_list_index())); + if (! value.empty()) + id->load_upstream_release_notes(m.upstream_release_notes().name(), + m.upstream_release_notes().description(), value); + } + + if (-1 != m.bugs_to().flat_list_index() && ! m.bugs_to().name().empty()) + { + std::string value(lines.at(m.bugs_to().flat_list_index())); + if (! value.empty()) + id->load_bugs_to(m.bugs_to().name(), + m.bugs_to().description(), value); + } + + if (-1 != m.remote_ids().flat_list_index() && ! m.remote_ids().name().empty()) + { + std::string value(lines.at(m.remote_ids().flat_list_index())); + if (! value.empty()) + id->load_remote_ids(m.remote_ids().name(), + m.remote_ids().description(), value); + } + } + else + id->set_slot(SlotName("UNKNOWN")); + + return true; + } +} + EbuildFlatMetadataCache::EbuildFlatMetadataCache(const Environment * const v, const FSEntry & f, const FSEntry & e, time_t t, std::tr1::shared_ptr<const EclassMtimes> m, bool s) : - _env(v), - _filename(f), - _ebuild(e), - _master_mtime(t), - _eclass_mtimes(m), - _silent(s) + PrivateImplementationPattern<EbuildFlatMetadataCache>(new Implementation<EbuildFlatMetadataCache>(v, f, e, t, m, s)) +{ +} + +EbuildFlatMetadataCache::~EbuildFlatMetadataCache() { } @@ -57,9 +276,9 @@ EbuildFlatMetadataCache::load(const std::tr1::shared_ptr<const EbuildID> & id) { using namespace std::tr1::placeholders; - Context context("When loading version metadata from '" + stringify(_filename) + "':"); + Context context("When loading version metadata from '" + stringify(_imp->filename) + "':"); - std::ifstream cache(stringify(_filename).c_str()); + std::ifstream cache(stringify(_imp->filename).c_str()); if (cache) { @@ -70,167 +289,282 @@ EbuildFlatMetadataCache::load(const std::tr1::shared_ptr<const EbuildID> & id) try { - if (lines.size() >= 15) + std::map<std::string, std::string> keys; + std::string duplicate; + for (std::vector<std::string>::const_iterator it(lines.begin()), + it_end(lines.end()); it_end != it; ++it) { - id->set_eapi(lines[14]); - bool ok(true); - - if (id->eapi()->supported()) + std::string::size_type equals(it->find('=')); + if (std::string::npos == equals) { - const EAPIEbuildMetadataVariables & m(*id->eapi()->supported()->ebuild_metadata_variables()); - - { - time_t cache_time(std::max(_master_mtime, _filename.mtime())); - std::set<std::string> tokens; - tokenise_whitespace(lines[9], std::inserter(tokens, tokens.begin())); - ok = _ebuild.mtime() <= cache_time; - - if (ok && ! tokens.empty()) - ok = tokens.end() == std::find_if(tokens.begin(), tokens.end(), - std::tr1::bind(std::greater<time_t>(), std::tr1::bind( - std::tr1::mem_fn(&EclassMtimes::mtime), _eclass_mtimes.get(), _1), cache_time)); - } - - if (ok) - ok = static_cast<int>(lines.size()) >= m.minimum_flat_cache_size(); - - if (ok) - { - if (-1 != m.dependencies().flat_cache_index()) - if (! m.dependencies().name().empty()) - { - DependenciesRewriter rewriter; - parse_depend(lines.at(m.dependencies().flat_cache_index()), _env, id, *id->eapi())->accept(rewriter); - id->load_build_depend(m.dependencies().name() + ".DEPEND", m.dependencies().description() + " (build)", rewriter.depend()); - id->load_run_depend(m.dependencies().name() + ".RDEPEND", m.dependencies().description() + " (run)", rewriter.rdepend()); - id->load_post_depend(m.dependencies().name() + ".PDEPEND", m.dependencies().description() + " (post)", rewriter.pdepend()); - } - - if (-1 != m.build_depend().flat_cache_index()) - if (! m.build_depend().name().empty()) - id->load_build_depend(m.build_depend().name(), m.build_depend().description(), lines.at(m.build_depend().flat_cache_index())); - - if (-1 != m.run_depend().flat_cache_index()) - if (! m.run_depend().name().empty()) - id->load_run_depend(m.run_depend().name(), m.run_depend().description(), lines.at(m.run_depend().flat_cache_index())); + Log::get_instance()->message("e.cache.flat_hash.not", ll_debug, lc_context) + << "cache file lacks = on line " << ((it - lines.begin()) + 1) << ", assuming flat_list"; + return load_flat_list(id, lines, _imp.get()); + } - id->set_slot(SlotName(lines.at(m.slot().flat_cache_index()))); + if (! keys.insert(std::make_pair(it->substr(0, equals), it->substr(equals + 1))).second) + duplicate = it->substr(0, equals); + } - if (-1 != m.src_uri().flat_cache_index()) - if (! m.src_uri().name().empty()) - id->load_src_uri(m.src_uri().name(), m.src_uri().description(), lines.at(m.src_uri().flat_cache_index())); + Context ctx("When loading flat_hash format cache file:"); - if (-1 != m.restrictions().flat_cache_index()) - if (! m.restrictions().name().empty()) - id->load_restrict(m.restrictions().name(), m.restrictions().description(), lines.at(m.restrictions().flat_cache_index())); + if (! duplicate.empty()) + { + Log::get_instance()->message("e.cache.flat_hash.broken", ll_warning, lc_context) + << "cache file contains duplicate key '" << duplicate << "'"; + return false; + } - if (-1 != m.homepage().flat_cache_index()) - if (! m.homepage().name().empty()) - id->load_homepage(m.homepage().name(), m.homepage().description(), lines.at(m.homepage().flat_cache_index())); + std::map<std::string, std::string>::const_iterator eapi(keys.find("EAPI")); + if (keys.end() == eapi) + { + Log::get_instance()->message("e.cache.flat_hash.broken", ll_warning, lc_context) + << "cache file contains no 'EAPI' key"; + return false; + } + id->set_eapi(eapi->second); - if (-1 != m.license().flat_cache_index()) - if (! m.license().name().empty()) - id->load_license(m.license().name(), m.license().description(), lines.at(m.license().flat_cache_index())); + if (id->eapi()->supported()) + { + const EAPIEbuildMetadataVariables & m(*id->eapi()->supported()->ebuild_metadata_variables()); - if (-1 != m.short_description().flat_cache_index()) - if (! m.short_description().name().empty()) - id->load_short_description(m.short_description().name(), - m.short_description().description(), - lines.at(m.short_description().flat_cache_index())); + { + bool ok(_imp->ebuild.mtime() == destringify<std::time_t>(keys["_mtime_"])); + if (! ok) + Log::get_instance()->message("e.cache.flat_hash.mtime", ll_debug, lc_context) + << "ebuild has mtime " << _imp->ebuild.mtime() << ", but expected " << keys["_mtime_"]; - if (-1 != m.long_description().flat_cache_index()) - if (! m.long_description().name().empty()) + if (ok && id->eapi()->supported()->ebuild_options()->support_eclasses()) + { + std::vector<std::string> eclasses; + tokenise<delim_kind::AnyOfTag, delim_mode::DelimiterTag>(keys["_eclasses_"], "\t", "", std::back_inserter(eclasses)); + FSEntry eclassdir(id->repository()->location_key()->value() / "eclass"); + for (std::vector<std::string>::const_iterator it(eclasses.begin()), + it_end(eclasses.end()); it_end != it; ++it) + { + std::string eclass_name(*it); + if (eclasses.end() == ++it) { - std::string value(lines.at(m.long_description().flat_cache_index())); - if (! value.empty()) - id->load_long_description(m.long_description().name(), - m.long_description().description(), value); + Log::get_instance()->message("e.cache.flat_hash.eclass.truncated", ll_warning, lc_context) + << "_eclasses_ entry is incomplete"; + return false; } + FSEntry eclass_dir(std::string::npos != it->find('/') ? *(it++) : eclassdir); + if (eclasses.end() == it) + { + Log::get_instance()->message("e.cache.flat_hash.eclass.truncated", ll_warning, lc_context) + << "_eclasses_ entry is incomplete"; + return false; + } + std::time_t eclass_mtime(destringify<std::time_t>(*it)); - if (-1 != m.keywords().flat_cache_index()) - if (! m.keywords().name().empty()) - id->load_keywords(m.keywords().name(), m.keywords().description(), lines.at(m.keywords().flat_cache_index())); - - if (-1 != m.inherited().flat_cache_index()) - if (! m.inherited().name().empty()) - id->load_inherited(m.inherited().name(), m.inherited().description(), lines.at(m.inherited().flat_cache_index())); - - if (-1 != m.iuse().flat_cache_index()) - if (! m.iuse().name().empty()) - id->load_iuse(m.iuse().name(), m.iuse().description(), lines.at(m.iuse().flat_cache_index())); + const FSEntry * eclass(_imp->eclass_mtimes->eclass(eclass_name)); + if (! eclass) + { + Log::get_instance()->message("e.cache.flat_hash.eclass.missing", ll_debug, lc_context) + << "Can't find cache-requested eclass '" << eclass_name << "'"; + ok = false; + } - if (-1 != m.pdepend().flat_cache_index()) - if (! m.pdepend().name().empty()) - id->load_post_depend(m.pdepend().name(), m.pdepend().description(), lines.at(m.pdepend().flat_cache_index())); + else if (eclass->dirname() != eclass_dir) + { + Log::get_instance()->message("e.cache.flat_hash.eclass.wrong_location", ll_debug, lc_context) + << "Cache-requested eclass '" << eclass_name << "' was found at '" + << eclass->dirname() << "', but expected '" << eclass_dir << "'"; + ok = false; + } - if (-1 != m.provide().flat_cache_index()) - if (! m.provide().name().empty()) - id->load_provide(m.provide().name(), m.provide().description(), lines.at(m.provide().flat_cache_index())); + else if (eclass->mtime() != eclass_mtime) + { + Log::get_instance()->message("e.cache.flat_hash.eclass.wrong_mtime", ll_debug, lc_context) + << "Cache-requested eclass '" << eclass_name << "' has mtime " + << eclass->mtime() << ", but expected " << eclass_mtime; + ok = false; + } - if (-1 != m.use().flat_cache_index()) - if (! m.use().name().empty()) - id->load_use(m.use().name(), m.use().description(), lines.at(m.use().flat_cache_index())); + if (! ok) + break; + } + } - if (-1 != m.upstream_changelog().flat_cache_index()) - if (! m.upstream_changelog().name().empty()) + else if (ok && id->eapi()->supported()->ebuild_options()->support_exlibs()) + { + std::vector<std::string> exlibs; + tokenise<delim_kind::AnyOfTag, delim_mode::DelimiterTag>(keys["_exlibs_"], "\t", "", std::back_inserter(exlibs)); + for (std::vector<std::string>::const_iterator it(exlibs.begin()), + it_end(exlibs.end()); it_end != it; ++it) + { + std::string exlib_name(*it); + if (exlibs.end() == ++it) { - std::string value(lines.at(m.upstream_changelog().flat_cache_index())); - if (! value.empty()) - id->load_upstream_changelog(m.upstream_changelog().name(), - m.upstream_changelog().description(), value); + Log::get_instance()->message("e.cache.flat_hash.exlib.truncated", ll_warning, lc_context) + << "_exlibs_ entry is incomplete"; + return false; } - - if (-1 != m.upstream_documentation().flat_cache_index()) - if (! m.upstream_documentation().name().empty()) + FSEntry exlib_dir(*it); + if (exlibs.end() == ++it) { - std::string value(lines.at(m.upstream_documentation().flat_cache_index())); - if (! value.empty()) - id->load_upstream_documentation(m.upstream_documentation().name(), - m.upstream_documentation().description(), value); + Log::get_instance()->message("e.cache.flat_hash.exlibs.truncated", ll_warning, lc_context) + << "_exlibs_ entry is incomplete"; + return false; } + std::time_t exlib_mtime(destringify<std::time_t>(*it)); - if (-1 != m.upstream_release_notes().flat_cache_index()) - if (! m.upstream_release_notes().name().empty()) + const FSEntry * exlib(_imp->eclass_mtimes->exlib(exlib_name, id->name())); + if (! exlib) { - std::string value(lines.at(m.upstream_release_notes().flat_cache_index())); - if (! value.empty()) - id->load_upstream_release_notes(m.upstream_release_notes().name(), - m.upstream_release_notes().description(), value); + Log::get_instance()->message("e.cache.flat_hash.exlib.missing", ll_debug, lc_context) + << "Can't find cache-requested exlib '" << exlib_name << "'"; + ok = false; } - if (-1 != m.bugs_to().flat_cache_index()) - if (! m.bugs_to().name().empty()) + else if (exlib->dirname() != exlib_dir) { - std::string value(lines.at(m.bugs_to().flat_cache_index())); - if (! value.empty()) - id->load_bugs_to(m.bugs_to().name(), - m.bugs_to().description(), value); + Log::get_instance()->message("e.cache.flat_hash.exlib.wrong_location", ll_debug, lc_context) + << "Cache-requested exlib '" << exlib_name << "' was found at '" + << exlib->dirname() << "', but expected '" << exlib_dir << "'"; + ok = false; } - if (-1 != m.remote_ids().flat_cache_index()) - if (! m.remote_ids().name().empty()) + else if (exlib->mtime() != exlib_mtime) { - std::string value(lines.at(m.remote_ids().flat_cache_index())); - if (! value.empty()) - id->load_remote_ids(m.remote_ids().name(), - m.remote_ids().description(), value); + Log::get_instance()->message("e.cache.flat_hash.exlib.wrong_mtime", ll_debug, lc_context) + << "Cache-requested exlib '" << exlib_name << "' has mtime " + << exlib->mtime() << ", but expected " << exlib_mtime; + ok = false; } + + if (! ok) + break; + } + } + + if (! ok) + { + Log::get_instance()->message("e.cache.stale", ll_warning, lc_no_context) + << "Stale cache file at '" << _imp->filename << "'"; + return false; } } - else - id->set_slot(SlotName("UNKNOWN")); - if (! ok) - Log::get_instance()->message("e.cache.stale", ll_warning, lc_no_context) << "Stale cache file at '" - << _filename << "'"; - return ok; + if (! m.dependencies().name().empty()) + { + DependenciesRewriter rewriter; + parse_depend(keys[m.dependencies().name()], _imp->env, id, *id->eapi())->accept(rewriter); + id->load_build_depend(m.dependencies().name() + ".DEPEND", m.dependencies().description() + " (build)", rewriter.depend()); + id->load_run_depend(m.dependencies().name() + ".RDEPEND", m.dependencies().description() + " (run)", rewriter.rdepend()); + id->load_post_depend(m.dependencies().name() + ".PDEPEND", m.dependencies().description() + " (post)", rewriter.pdepend()); + } + + if (! m.build_depend().name().empty()) + id->load_build_depend(m.build_depend().name(), m.build_depend().description(), keys[m.build_depend().name()]); + + if (! m.run_depend().name().empty()) + id->load_run_depend(m.run_depend().name(), m.run_depend().description(), keys[m.run_depend().name()]); + + id->set_slot(SlotName(keys[m.slot().name()])); + + if (! m.src_uri().name().empty()) + id->load_src_uri(m.src_uri().name(), m.src_uri().description(), keys[m.src_uri().name()]); + + if (! m.restrictions().name().empty()) + id->load_restrict(m.restrictions().name(), m.restrictions().description(), keys[m.restrictions().name()]); + + if (! m.homepage().name().empty()) + id->load_homepage(m.homepage().name(), m.homepage().description(), keys[m.homepage().name()]); + + if (! m.license().name().empty()) + id->load_license(m.license().name(), m.license().description(), keys[m.license().name()]); + + if (! m.short_description().name().empty()) + id->load_short_description(m.short_description().name(), + m.short_description().description(), + keys[m.short_description().name()]); + + if (! m.long_description().name().empty()) + { + std::string value(keys[m.long_description().name()]); + if (! value.empty()) + id->load_long_description(m.long_description().name(), + m.long_description().description(), value); + } + + if (! m.keywords().name().empty()) + id->load_keywords(m.keywords().name(), m.keywords().description(), keys[m.keywords().name()]); + + if (! m.inherited().name().empty()) + { + std::vector<std::string> full, brief; + if (id->eapi()->supported()->ebuild_options()->support_eclasses()) + tokenise<delim_kind::AnyOfTag, delim_mode::DelimiterTag>(keys["_eclasses_"], "\t", "", std::back_inserter(full)); + else if (id->eapi()->supported()->ebuild_options()->support_exlibs()) + tokenise<delim_kind::AnyOfTag, delim_mode::DelimiterTag>(keys["_exlibs_"], "\t", "", std::back_inserter(full)); + for (std::vector<std::string>::const_iterator it(full.begin()), + it_end(full.end()); it_end != it; ++it) + { + brief.push_back(*it); + if (std::string::npos != (++it)->find('/')) + ++it; + } + id->load_inherited(m.inherited().name(), m.inherited().description(), join(brief.begin(), brief.end(), " ")); + } + + if (! m.iuse().name().empty()) + id->load_iuse(m.iuse().name(), m.iuse().description(), keys[m.iuse().name()]); + + if (! m.pdepend().name().empty()) + id->load_post_depend(m.pdepend().name(), m.pdepend().description(), keys[m.pdepend().name()]); + + if (! m.provide().name().empty()) + id->load_provide(m.provide().name(), m.provide().description(), keys[m.provide().name()]); + + if (! m.use().name().empty()) + id->load_use(m.use().name(), m.use().description(), keys[m.use().name()]); + + if (! m.upstream_changelog().name().empty()) + { + std::string value(keys[m.upstream_changelog().name()]); + if (! value.empty()) + id->load_upstream_changelog(m.upstream_changelog().name(), + m.upstream_changelog().description(), value); + } + + if (! m.upstream_documentation().name().empty()) + { + std::string value(keys[m.upstream_documentation().name()]); + if (! value.empty()) + id->load_upstream_documentation(m.upstream_documentation().name(), + m.upstream_documentation().description(), value); + } + + if (! m.upstream_release_notes().name().empty()) + { + std::string value(keys[m.upstream_release_notes().name()]); + if (! value.empty()) + id->load_upstream_release_notes(m.upstream_release_notes().name(), + m.upstream_release_notes().description(), value); + } + + if (! m.bugs_to().name().empty()) + { + std::string value(keys[m.bugs_to().name()]); + if (! value.empty()) + id->load_bugs_to(m.bugs_to().name(), + m.bugs_to().description(), value); + } + + if (! m.remote_ids().name().empty()) + { + std::string value(keys[m.remote_ids().name()]); + if (! value.empty()) + id->load_remote_ids(m.remote_ids().name(), + m.remote_ids().description(), value); + } } else - { - Log::get_instance()->message("e.cache.incomplete", ll_warning, lc_no_context) << "Incomplete cache file at '" - << _filename << "'"; - return false; - } + id->set_slot(SlotName("UNKNOWN")); + + return true; } catch (const InternalError &) { @@ -239,14 +573,14 @@ EbuildFlatMetadataCache::load(const std::tr1::shared_ptr<const EbuildID> & id) catch (const Exception & e) { Log::get_instance()->message("e.cache.failure", ll_warning, lc_no_context) << "Not using cache file at '" - << _filename << "' due to exception '" << e.message() << "' (" << e.what() << ")"; + << _imp->filename << "' due to exception '" << e.message() << "' (" << e.what() << ")"; return false; } } else { - Log::get_instance()->message("e.cache.failure", _silent ? ll_debug : ll_warning, lc_no_context) - << "Couldn't use the cache file at '" << _filename << "'"; + Log::get_instance()->message("e.cache.failure", _imp->silent ? ll_debug : ll_warning, lc_no_context) + << "Couldn't use the cache file at '" << _imp->filename << "': " << std::strerror(errno); return false; } } @@ -269,17 +603,25 @@ namespace d->accept(p); return stringify(p); } + + template <typename T_> + void write_kv(std::ostream & stream, const std::string & key, const T_ & value) + { + std::string str_value(stringify(value)); + if (! str_value.empty()) + stream << key << "=" << str_value << std::endl; + } } void EbuildFlatMetadataCache::save(const std::tr1::shared_ptr<const EbuildID> & id) { - Context context("When saving version metadata to '" + stringify(_filename) + "':"); + Context context("When saving version metadata to '" + stringify(_imp->filename) + "':"); try { - _filename.dirname().dirname().mkdir(); - _filename.dirname().mkdir(); + _imp->filename.dirname().dirname().mkdir(); + _imp->filename.dirname().mkdir(); } catch (const FSError & e) { @@ -290,174 +632,120 @@ EbuildFlatMetadataCache::save(const std::tr1::shared_ptr<const EbuildID> & id) if (! id->eapi()->supported()) { Log::get_instance()->message("e.cache.save.eapi_unsupoprted", ll_warning, lc_no_context) << "Not writing cache file to '" - << _filename << "' because EAPI '" << id->eapi()->name() << "' is not supported"; + << _imp->filename << "' because EAPI '" << id->eapi()->name() << "' is not supported"; return; } std::ostringstream cache; + write_kv(cache, "_mtime_", _imp->ebuild.mtime()); + + if (id->eapi()->supported()->ebuild_options()->support_eclasses() && id->inherited_key()) + { + std::vector<std::string> eclasses; + for (Set<std::string>::ConstIterator it(id->inherited_key()->value()->begin()), + it_end(id->inherited_key()->value()->end()); it_end != it; ++it) + { + const FSEntry * eclass(_imp->eclass_mtimes->eclass(*it)); + if (! eclass) + throw InternalError(PALUDIS_HERE, "eclass '" + *it + "' disappeared?"); + eclasses.push_back(*it); + eclasses.push_back(stringify(eclass->dirname())); + eclasses.push_back(stringify(eclass->mtime())); + } + write_kv(cache, "_eclasses_", join(eclasses.begin(), eclasses.end(), "\t")); + } + + else if (id->eapi()->supported()->ebuild_options()->support_exlibs() && id->inherited_key()) + { + std::vector<std::string> exlibs; + for (Set<std::string>::ConstIterator it(id->inherited_key()->value()->begin()), + it_end(id->inherited_key()->value()->end()); it_end != it; ++it) + { + const FSEntry * exlib(_imp->eclass_mtimes->exlib(*it, id->name())); + if (! exlib) + throw InternalError(PALUDIS_HERE, "exlib '" + *it + "' for '" + stringify(id->name()) + "' disappeared?"); + exlibs.push_back(*it); + exlibs.push_back(stringify(exlib->dirname())); + exlibs.push_back(stringify(exlib->mtime())); + } + write_kv(cache, "_exlibs_", join(exlibs.begin(), exlibs.end(), "\t")); + } try { const EAPIEbuildMetadataVariables & m(*id->eapi()->supported()->ebuild_metadata_variables()); - for (int x(0), x_end(m.minimum_flat_cache_size()) ; x != x_end ; ++x) + + if (! m.dependencies().name().empty()) { - if (x == m.dependencies().flat_cache_index()) - { - std::string s; + std::string s; - if (id->build_dependencies_key()) - s.append(flatten(id->build_dependencies_key()->value()) + " "); - if (id->run_dependencies_key()) - s.append(flatten(id->run_dependencies_key()->value()) + " "); - if (id->post_dependencies_key()) - s.append(flatten(id->post_dependencies_key()->value()) + " "); + if (id->build_dependencies_key()) + s.append(flatten(id->build_dependencies_key()->value()) + " "); + if (id->run_dependencies_key()) + s.append(flatten(id->run_dependencies_key()->value()) + " "); + if (id->post_dependencies_key()) + s.append(flatten(id->post_dependencies_key()->value()) + " "); - cache << s << std::endl; - } - else if (x == m.use().flat_cache_index()) - { - if (id->use_key()) - cache << join(id->use_key()->value()->begin(), id->use_key()->value()->end(), " ") << std::endl; - else - cache << std::endl; - } - else if (x == m.build_depend().flat_cache_index()) - { - if (id->build_dependencies_key()) - cache << flatten(id->build_dependencies_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.run_depend().flat_cache_index()) - { - if (id->run_dependencies_key()) - cache << flatten(id->run_dependencies_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.slot().flat_cache_index()) - { - cache << normalise(id->slot()) << std::endl; - } - else if (x == m.src_uri().flat_cache_index()) - { - if (id->fetches_key()) - cache << flatten(id->fetches_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.restrictions().flat_cache_index()) - { - if (id->restrict_key()) - cache << flatten(id->restrict_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.homepage().flat_cache_index()) - { - if (id->homepage_key()) - cache << flatten(id->homepage_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.license().flat_cache_index()) - { - if (id->license_key()) - cache << flatten(id->license_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.short_description().flat_cache_index()) - { - if (id->short_description_key()) - cache << normalise(id->short_description_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.keywords().flat_cache_index()) - { - if (id->keywords_key()) - cache << join(id->keywords_key()->value()->begin(), id->keywords_key()->value()->end(), " ") << std::endl; - else - cache << std::endl; - } - else if (x == m.inherited().flat_cache_index()) - { - if (id->inherited_key()) - cache << join(id->inherited_key()->value()->begin(), id->inherited_key()->value()->end(), " ") << std::endl; - else - cache << std::endl; - } - else if (x == m.iuse().flat_cache_index()) - { - if (id->iuse_key()) - cache << join(id->iuse_key()->value()->begin(), id->iuse_key()->value()->end(), " ") << std::endl; - else - cache << std::endl; - } - else if (x == m.pdepend().flat_cache_index()) - { - if (id->post_dependencies_key()) - cache << flatten(id->post_dependencies_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.provide().flat_cache_index()) - { - if (id->provide_key()) - cache << flatten(id->provide_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.eapi().flat_cache_index()) - { - cache << normalise(id->eapi()->name()) << std::endl; - } - else if (x == m.long_description().flat_cache_index()) - { - if (id->long_description_key()) - cache << normalise(id->long_description_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.bugs_to().flat_cache_index()) - { - if (id->bugs_to_key()) - cache << flatten(id->bugs_to_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.remote_ids().flat_cache_index()) - { - if (id->remote_ids_key()) - cache << flatten(id->remote_ids_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.upstream_changelog().flat_cache_index()) - { - if (id->upstream_changelog_key()) - cache << flatten(id->upstream_changelog_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.upstream_documentation().flat_cache_index()) - { - if (id->upstream_documentation_key()) - cache << flatten(id->upstream_documentation_key()->value()) << std::endl; - else - cache << std::endl; - } - else if (x == m.upstream_release_notes().flat_cache_index()) - { - if (id->upstream_release_notes_key()) - cache << flatten(id->upstream_release_notes_key()->value()) << std::endl; - else - cache << std::endl; - } - else - cache << std::endl; + write_kv(cache, m.dependencies().name(), s); } + + if (! m.use().name().empty() && id->use_key()) + write_kv(cache, m.use().name(), join(id->use_key()->value()->begin(), id->use_key()->value()->end(), " ")); + + if (! m.build_depend().name().empty() && id->build_dependencies_key()) + write_kv(cache, m.build_depend().name(), flatten(id->build_dependencies_key()->value())); + + if (! m.run_depend().name().empty() && id->run_dependencies_key()) + write_kv(cache, m.run_depend().name(), flatten(id->run_dependencies_key()->value())); + + write_kv(cache, m.slot().name(), normalise(id->slot())); + + if (! m.src_uri().name().empty() && id->fetches_key()) + write_kv(cache, m.src_uri().name(), flatten(id->fetches_key()->value())); + + if (! m.restrictions().name().empty() && id->restrict_key()) + write_kv(cache, m.restrictions().name(), flatten(id->restrict_key()->value())); + + if (! m.homepage().name().empty() && id->homepage_key()) + write_kv(cache, m.homepage().name(), flatten(id->homepage_key()->value())); + + if (! m.license().name().empty() && id->license_key()) + write_kv(cache, m.license().name(), flatten(id->license_key()->value())); + + if (! m.short_description().name().empty() && id->short_description_key()) + write_kv(cache, m.short_description().name(), normalise(id->short_description_key()->value())); + + if (! m.keywords().name().empty() && id->keywords_key()) + write_kv(cache, m.keywords().name(), join(id->keywords_key()->value()->begin(), id->keywords_key()->value()->end(), " ")); + + if (! m.iuse().name().empty() && id->iuse_key()) + write_kv(cache, m.iuse().name(), join(id->iuse_key()->value()->begin(), id->iuse_key()->value()->end(), " ")); + + if (! m.pdepend().name().empty() && id->post_dependencies_key()) + write_kv(cache, m.pdepend().name(), flatten(id->post_dependencies_key()->value())); + + if (! m.provide().name().empty() && id->provide_key()) + write_kv(cache, m.provide().name(), flatten(id->provide_key()->value())); + + write_kv(cache, "EAPI", normalise(id->eapi()->name())); + + if (! m.long_description().name().empty() && id->long_description_key()) + write_kv(cache, m.long_description().name(), normalise(id->long_description_key()->value())); + + if (! m.bugs_to().name().empty() && id->bugs_to_key()) + write_kv(cache, m.bugs_to().name(), flatten(id->bugs_to_key()->value())); + + if (! m.remote_ids().name().empty() && id->remote_ids_key()) + write_kv(cache, m.remote_ids().name(), flatten(id->remote_ids_key()->value())); + + if (! m.upstream_changelog().name().empty() && id->upstream_changelog_key()) + write_kv(cache, m.upstream_changelog().name(), flatten(id->upstream_changelog_key()->value())); + + if (! m.upstream_documentation().name().empty() && id->upstream_documentation_key()) + write_kv(cache, m.upstream_documentation().name(), flatten(id->upstream_documentation_key()->value())); + + if (! m.upstream_release_notes().name().empty() && id->upstream_release_notes_key()) + write_kv(cache, m.upstream_release_notes().name(), flatten(id->upstream_release_notes_key()->value())); } catch (const InternalError &) { @@ -466,18 +754,20 @@ EbuildFlatMetadataCache::save(const std::tr1::shared_ptr<const EbuildID> & id) catch (const Exception & e) { Log::get_instance()->message("e.cache.save.failure", ll_warning, lc_no_context) << "Not writing cache file to '" - << _filename << "' due to exception '" << e.message() << "' (" << e.what() << ")"; + << _imp->filename << "' due to exception '" << e.message() << "' (" << e.what() << ")"; return; } - std::ofstream cache_file(stringify(_filename).c_str()); + std::ofstream cache_file(stringify(_imp->filename).c_str()); if (cache_file) cache_file << cache.str(); else { Log::get_instance()->message("e.cache.save.failure", ll_warning, lc_no_context) << "Couldn't write cache file to '" - << _filename << "': " << std::strerror(errno); + << _imp->filename << "': " << std::strerror(errno); } } +template class PrivateImplementationPattern<EbuildFlatMetadataCache>; + diff --git a/paludis/repositories/e/ebuild_flat_metadata_cache.hh b/paludis/repositories/e/ebuild_flat_metadata_cache.hh index 85ebf9f2c..88f6b52ae 100644 --- a/paludis/repositories/e/ebuild_flat_metadata_cache.hh +++ b/paludis/repositories/e/ebuild_flat_metadata_cache.hh @@ -24,36 +24,31 @@ #include <paludis/repositories/e/ebuild_id.hh> #include <paludis/util/fs_entry.hh> #include <paludis/repositories/e/eclass_mtimes.hh> +#include <paludis/util/private_implementation_pattern.hh> namespace paludis { namespace erepository { /** - * Implements flat file metadata cache handling for a ERepository - * using EbuildEntries. + * Implements metadata cache handling for a ERepository using + * EbuildEntries. * * \see EbuildEntries * \see ERepository * \ingroup grperepository * \nosubgrouping */ - class EbuildFlatMetadataCache + class EbuildFlatMetadataCache : + private PrivateImplementationPattern<EbuildFlatMetadataCache> { - private: - const Environment * const _env; - const FSEntry & _filename; - const FSEntry & _ebuild; - time_t _master_mtime; - std::tr1::shared_ptr<const EclassMtimes> _eclass_mtimes; - bool _silent; - public: ///\name Basic operations ///\{ EbuildFlatMetadataCache(const Environment * const, const FSEntry & filename, const FSEntry & ebuild, time_t master_mtime, std::tr1::shared_ptr<const EclassMtimes> eclass_mtimes, bool silent); + ~EbuildFlatMetadataCache(); ///\} @@ -66,6 +61,10 @@ namespace paludis ///\} }; } + +#ifdef PALUDIS_HAVE_EXTERN_TEMPLATE + extern template class PrivateImplementationPattern<erepository::EbuildFlatMetadataCache>; +#endif } #endif diff --git a/paludis/repositories/e/eclass_mtimes.cc b/paludis/repositories/e/eclass_mtimes.cc index 428dc0b02..e8136c73e 100644 --- a/paludis/repositories/e/eclass_mtimes.cc +++ b/paludis/repositories/e/eclass_mtimes.cc @@ -2,6 +2,7 @@ /* * Copyright (c) 2006, 2007, 2008 Ciaran McCreesh + * Copyright (c) 2008 David Leverton * * 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 @@ -18,6 +19,9 @@ */ #include "eclass_mtimes.hh" +#include <paludis/repositories/e/e_repository.hh> +#include <paludis/repositories/e/layout.hh> +#include <paludis/name.hh> #include <paludis/util/private_implementation_pattern-impl.hh> #include <paludis/util/sequence.hh> #include <paludis/util/fs_entry.hh> @@ -28,24 +32,58 @@ using namespace paludis; +namespace +{ + struct Cache + { + std::tr1::shared_ptr<const FSEntrySequence> dirs; + std::tr1::unordered_map<std::string, FSEntry, Hash<std::string> > files; + + Cache(const std::tr1::shared_ptr<const FSEntrySequence> & d) : + dirs(d) + { + } + }; + + const FSEntry * + lookup(const std::string & e, Cache & c) + { + std::tr1::unordered_map<std::string, FSEntry, Hash<std::string> >::const_iterator i(c.files.find(e)); + if (i != c.files.end()) + return & i->second; + + for (FSEntrySequence::ReverseConstIterator d(c.dirs->rbegin()), + d_end(c.dirs->rend()) ; d != d_end ; ++d) + { + FSEntry f(*d / e); + if (f.exists()) + return & c.files.insert(std::make_pair(e, f)).first->second; + } + + return 0; + } +} + namespace paludis { template<> struct Implementation<EclassMtimes> { - std::tr1::shared_ptr<const FSEntrySequence> eclass_dirs; + const ERepository * repo; + mutable Cache eclasses; + mutable std::tr1::unordered_map<QualifiedPackageName, Cache, Hash<QualifiedPackageName> > exlibs; mutable Mutex mutex; - mutable std::tr1::unordered_map<std::string, time_t, Hash<std::string> > eclass_mtimes; - Implementation(std::tr1::shared_ptr<const FSEntrySequence> d) : - eclass_dirs(d) + Implementation(const ERepository * r, const std::tr1::shared_ptr<const FSEntrySequence> & d) : + repo(r), + eclasses(d) { } }; } -EclassMtimes::EclassMtimes(std::tr1::shared_ptr<const FSEntrySequence> d) : - PrivateImplementationPattern<EclassMtimes>(new Implementation<EclassMtimes>(d)) +EclassMtimes::EclassMtimes(const ERepository * r, const std::tr1::shared_ptr<const FSEntrySequence> & d) : + PrivateImplementationPattern<EclassMtimes>(new Implementation<EclassMtimes>(r, d)) { } @@ -53,25 +91,20 @@ EclassMtimes::~EclassMtimes() { } -time_t -EclassMtimes::mtime(const std::string & e) const +const FSEntry * +EclassMtimes::eclass(const std::string & e) const { Lock l(_imp->mutex); + return lookup(e + ".eclass", _imp->eclasses); +} - std::tr1::unordered_map<std::string, time_t, Hash<std::string> >::const_iterator i(_imp->eclass_mtimes.find(e)); - if (i != _imp->eclass_mtimes.end()) - return i->second; - - time_t r(0); - for (FSEntrySequence::ConstIterator d(_imp->eclass_dirs->begin()), - d_end(_imp->eclass_dirs->end()) ; d != d_end ; ++d) - { - FSEntry f(*d / (e + ".eclass")); - if (f.exists()) - r = std::max(r, f.mtime()); - } - - _imp->eclass_mtimes.insert(std::make_pair(e, r)); - return r; +const FSEntry * +EclassMtimes::exlib(const std::string & e, const QualifiedPackageName & qpn) const +{ + Lock l(_imp->mutex); + std::tr1::unordered_map<QualifiedPackageName, Cache, Hash<QualifiedPackageName> >::iterator cache(_imp->exlibs.find(qpn)); + if (_imp->exlibs.end() == cache) + cache = _imp->exlibs.insert(std::make_pair(qpn, Cache(_imp->repo->layout()->exlibsdirs(qpn)))).first; + return lookup(e + ".exlib", cache->second); } diff --git a/paludis/repositories/e/eclass_mtimes.hh b/paludis/repositories/e/eclass_mtimes.hh index 891f29ea0..40ca5cbf3 100644 --- a/paludis/repositories/e/eclass_mtimes.hh +++ b/paludis/repositories/e/eclass_mtimes.hh @@ -20,14 +20,17 @@ #ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_E_ECLASS_MTIMES_HH #define PALUDIS_GUARD_PALUDIS_REPOSITORIES_E_ECLASS_MTIMES_HH 1 +#include <paludis/name-fwd.hh> #include <paludis/util/private_implementation_pattern.hh> #include <paludis/util/fs_entry-fwd.hh> #include <tr1/memory> namespace paludis { + class ERepository; + /** - * Holds an eclass mtimes cache for a ERepository. + * Holds an eclass mtimes cache for an ERepository. * * \see ERepository * \ingroup grperepository @@ -40,15 +43,20 @@ namespace paludis ///\name Basic operations ///\{ - EclassMtimes(std::tr1::shared_ptr<const FSEntrySequence>); + EclassMtimes(const ERepository *, const std::tr1::shared_ptr<const FSEntrySequence> &); ~EclassMtimes(); ///\} /** - * Fetch the mtime for a given eclass. + * Fetch the full path of a given eclass. + */ + const FSEntry * eclass(const std::string &) const; + + /** + * Fetch the full path of a given exlib, on the path of a given package. */ - time_t mtime(const std::string &) const; + const FSEntry * exlib(const std::string &, const QualifiedPackageName &) const; }; } |