aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar David Leverton <levertond@googlemail.com> 2008-03-30 21:24:06 +0000
committerAvatar David Leverton <levertond@googlemail.com> 2008-03-30 21:24:06 +0000
commit84def64976fb62df7c8ff6d9fa0ced2164e63c67 (patch)
tree23ca7c76aa40452a544a845c2b2d8b47ea111e69
parenta0a1066a8feeba19f89337f40591b13d7687b69d (diff)
downloadpaludis-84def64976fb62df7c8ff6d9fa0ced2164e63c67.tar.gz
paludis-84def64976fb62df7c8ff6d9fa0ced2164e63c67.tar.xz
Regenerate the VDB names cache incrementally after install and uninstall.
-rw-r--r--paludis/repositories/e/vdb_repository.cc16
-rw-r--r--paludis/repositories/e/vdb_repository_TEST.cc267
-rwxr-xr-xpaludis/repositories/e/vdb_repository_TEST_setup.sh23
-rw-r--r--paludis/repository_name_cache.cc191
-rw-r--r--paludis/repository_name_cache.hh10
5 files changed, 452 insertions, 55 deletions
diff --git a/paludis/repositories/e/vdb_repository.cc b/paludis/repositories/e/vdb_repository.cc
index 447eb1b..6597433 100644
--- a/paludis/repositories/e/vdb_repository.cc
+++ b/paludis/repositories/e/vdb_repository.cc
@@ -441,6 +441,21 @@ VDBRepository::perform_uninstall(const tr1::shared_ptr<const ERepositoryID> & id
for (DirIterator d(pkg_dir, DirIteratorOptions() + dio_include_dotfiles), d_end ; d != d_end ; ++d)
FSEntry(*d).unlink();
pkg_dir.rmdir();
+
+ if (! reinstalling)
+ {
+ tr1::shared_ptr<const PackageIDSequence> ids(package_ids(id->name()));
+ bool only(true);
+ for (PackageIDSequence::ConstIterator it(ids->begin()),
+ it_end(ids->end()); it_end != it; ++it)
+ if (*tr1::static_pointer_cast<const PackageID>(id) != **it)
+ {
+ only = false;
+ break;
+ }
+ if (only)
+ _imp->names_cache->remove(id->name());
+ }
}
void
@@ -781,6 +796,7 @@ VDBRepository::merge(const MergeParams & m)
(k::root(), installed_root_key()->value()));
post_merge_command();
+ _imp->names_cache->add(m[k::package_id()]->name());
}
void
diff --git a/paludis/repositories/e/vdb_repository_TEST.cc b/paludis/repositories/e/vdb_repository_TEST.cc
index 95c172e..aefc24d 100644
--- a/paludis/repositories/e/vdb_repository_TEST.cc
+++ b/paludis/repositories/e/vdb_repository_TEST.cc
@@ -27,6 +27,8 @@
#include <paludis/util/sequence.hh>
#include <paludis/util/visitor-impl.hh>
#include <paludis/util/options.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/tr1_functional.hh>
#include <paludis/query.hh>
#include <paludis/dep_spec.hh>
#include <paludis/user_dep_spec.hh>
@@ -34,8 +36,11 @@
#include <paludis/action.hh>
#include <test/test_framework.hh>
#include <test/test_runner.hh>
+#include <algorithm>
#include <fstream>
+#include <functional>
#include <iterator>
+#include <vector>
using namespace test;
using namespace paludis;
@@ -510,5 +515,267 @@ namespace test_cases
}
} test_vdb_vars_eapi_0("0"), test_vdb_vars_eapi_1("1"), test_vdb_vars_eapi_exheres_0("exheres-0"),
test_vdb_vars_eapi_kdebuild_1("kdebuild-1");
+
+ struct NamesCacheIncrementalTest : TestCase
+ {
+ FSEntry names_cache;
+
+ NamesCacheIncrementalTest() :
+ TestCase("names cache incremental"),
+ names_cache("vdb_repository_TEST_dir/namesincrtest/.cache/names/installed")
+ {
+ }
+
+ bool repeatable() const
+ {
+ return false;
+ }
+
+ unsigned max_run_time() const
+ {
+ return 3000;
+ }
+
+ void run()
+ {
+ TestEnvironment env;
+ env.set_paludis_command("/bin/false");
+ tr1::shared_ptr<Map<std::string, std::string> > keys(new Map<std::string, std::string>);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "vdb_repository_TEST_dir/namesincrtest_src");
+ keys->insert("profiles", "vdb_repository_TEST_dir/namesincrtest_src/profiles/profile");
+ keys->insert("layout", "traditional");
+ keys->insert("eapi_when_unknown", "0");
+ keys->insert("eapi_when_unspecified", "0");
+ keys->insert("profile_eapi", "0");
+ keys->insert("distdir", stringify(FSEntry::cwd() / "vdb_repository_TEST_dir" / "distdir"));
+ keys->insert("builddir", stringify(FSEntry::cwd() / "vdb_repository_TEST_dir" / "build"));
+ keys->insert("root", stringify(FSEntry("vdb_repository_TEST_dir/root").realpath()));
+ tr1::shared_ptr<ERepository> repo(make_ebuild_repository(&env, keys));
+ env.package_database()->add_repository(1, repo);
+
+ keys.reset(new Map<std::string, std::string>);
+ keys->insert("format", "vdb");
+ keys->insert("names_cache", stringify(names_cache.dirname()));
+ keys->insert("provides_cache", "/var/empty");
+ keys->insert("location", "vdb_repository_TEST_dir/namesincrtest");
+ keys->insert("builddir", stringify(FSEntry::cwd() / "vdb_repository_TEST_dir" / "build"));
+ keys->insert("root", stringify(FSEntry("vdb_repository_TEST_dir/root").realpath()));
+ tr1::shared_ptr<Repository> vdb_repo(VDBRepository::make_vdb_repository(&env, keys));
+ env.package_database()->add_repository(0, vdb_repo);
+
+ InstallAction install_action(InstallActionOptions::named_create()
+ (k::debug_build(), iado_none)
+ (k::checks(), iaco_default)
+ (k::no_config_protect(), false)
+ (k::destination(), vdb_repo)
+ );
+
+ UninstallAction uninstall_action(UninstallActionOptions::named_create()
+ (k::no_config_protect(), false)
+ );
+
+ {
+ std::vector<FSEntry> cache_contents;
+ read_cache(cache_contents);
+ TEST_CHECK_EQUAL(cache_contents.size(), 0U);
+ }
+
+ {
+ TestMessageSuffix suffix("install", true);
+ const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+ PackageDepSpec(parse_user_package_dep_spec("=cat1/pkg1-1::namesincrtest_src",
+ UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+ id->perform_action(install_action);
+ vdb_repo->invalidate();
+
+ std::vector<FSEntry> cache_contents;
+ read_cache(cache_contents);
+ TEST_CHECK_EQUAL(cache_contents.size(), 1U);
+ TEST_CHECK_EQUAL(cache_contents.front().basename(), "pkg1");
+ TEST_CHECK_EQUAL(read_file(names_cache / "pkg1"), "cat1\n");
+ }
+
+ {
+ TestMessageSuffix suffix("reinstall", true);
+ const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+ PackageDepSpec(parse_user_package_dep_spec("=cat1/pkg1-1::namesincrtest_src",
+ UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+ id->perform_action(install_action);
+ vdb_repo->invalidate();
+
+ std::vector<FSEntry> cache_contents;
+ read_cache(cache_contents);
+ TEST_CHECK_EQUAL(cache_contents.size(), 1U);
+ TEST_CHECK_EQUAL(cache_contents.front().basename(), "pkg1");
+ TEST_CHECK_EQUAL(read_file(names_cache / "pkg1"), "cat1\n");
+ }
+
+ {
+ TestMessageSuffix suffix("upgrade", true);
+ const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+ PackageDepSpec(parse_user_package_dep_spec("=cat1/pkg1-1.1::namesincrtest_src",
+ UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+ const tr1::shared_ptr<const PackageID> inst_id(*env.package_database()->query(query::Matches(
+ PackageDepSpec(parse_user_package_dep_spec("=cat1/pkg1-1::installed",
+ UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+ id->perform_action(install_action);
+ vdb_repo->invalidate();
+ inst_id->perform_action(uninstall_action);
+ vdb_repo->invalidate();
+
+ std::vector<FSEntry> cache_contents;
+ read_cache(cache_contents);
+ TEST_CHECK_EQUAL(cache_contents.size(), 1U);
+ TEST_CHECK_EQUAL(cache_contents.front().basename(), "pkg1");
+ TEST_CHECK_EQUAL(read_file(names_cache / "pkg1"), "cat1\n");
+ }
+
+ {
+ TestMessageSuffix suffix("downgrade", true);
+ const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+ PackageDepSpec(parse_user_package_dep_spec("=cat1/pkg1-1::namesincrtest_src",
+ UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+ const tr1::shared_ptr<const PackageID> inst_id(*env.package_database()->query(query::Matches(
+ PackageDepSpec(parse_user_package_dep_spec("=cat1/pkg1-1.1::installed",
+ UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+ id->perform_action(install_action);
+ vdb_repo->invalidate();
+ inst_id->perform_action(uninstall_action);
+ vdb_repo->invalidate();
+
+ std::vector<FSEntry> cache_contents;
+ read_cache(cache_contents);
+ TEST_CHECK_EQUAL(cache_contents.size(), 1U);
+ TEST_CHECK_EQUAL(cache_contents.front().basename(), "pkg1");
+ TEST_CHECK_EQUAL(read_file(names_cache / "pkg1"), "cat1\n");
+ }
+
+ {
+ TestMessageSuffix suffix("new slot", true);
+ const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+ PackageDepSpec(parse_user_package_dep_spec("=cat1/pkg1-2::namesincrtest_src",
+ UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+ id->perform_action(install_action);
+ vdb_repo->invalidate();
+
+ std::vector<FSEntry> cache_contents;
+ read_cache(cache_contents);
+ TEST_CHECK_EQUAL(cache_contents.size(), 1U);
+ TEST_CHECK_EQUAL(cache_contents.front().basename(), "pkg1");
+ TEST_CHECK_EQUAL(read_file(names_cache / "pkg1"), "cat1\n");
+ }
+
+ {
+ TestMessageSuffix suffix("remove other slot", true);
+ const tr1::shared_ptr<const PackageID> inst_id(*env.package_database()->query(query::Matches(
+ PackageDepSpec(parse_user_package_dep_spec("=cat1/pkg1-2::installed",
+ UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+ inst_id->perform_action(uninstall_action);
+ vdb_repo->invalidate();
+
+ std::vector<FSEntry> cache_contents;
+ read_cache(cache_contents);
+ TEST_CHECK_EQUAL(cache_contents.size(), 1U);
+ TEST_CHECK_EQUAL(cache_contents.front().basename(), "pkg1");
+ TEST_CHECK_EQUAL(read_file(names_cache / "pkg1"), "cat1\n");
+ }
+
+ {
+ TestMessageSuffix suffix("new package", true);
+ const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+ PackageDepSpec(parse_user_package_dep_spec("=cat1/pkg2-1::namesincrtest_src",
+ UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+ id->perform_action(install_action);
+ vdb_repo->invalidate();
+
+ std::vector<FSEntry> cache_contents;
+ read_cache(cache_contents);
+ TEST_CHECK_EQUAL(cache_contents.size(), 2U);
+ TEST_CHECK_EQUAL(cache_contents.front().basename(), "pkg1");
+ TEST_CHECK_EQUAL(cache_contents.back().basename(), "pkg2");
+ TEST_CHECK_EQUAL(read_file(names_cache / "pkg1"), "cat1\n");
+ TEST_CHECK_EQUAL(read_file(names_cache / "pkg2"), "cat1\n");
+ }
+
+ {
+ TestMessageSuffix suffix("remove other package", true);
+ const tr1::shared_ptr<const PackageID> inst_id(*env.package_database()->query(query::Matches(
+ PackageDepSpec(parse_user_package_dep_spec("=cat1/pkg2-1::installed",
+ UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+ inst_id->perform_action(uninstall_action);
+ vdb_repo->invalidate();
+
+ std::vector<FSEntry> cache_contents;
+ read_cache(cache_contents);
+ TEST_CHECK_EQUAL(cache_contents.size(), 1U);
+ TEST_CHECK_EQUAL(cache_contents.front().basename(), "pkg1");
+ TEST_CHECK_EQUAL(read_file(names_cache / "pkg1"), "cat1\n");
+ }
+
+ {
+ TestMessageSuffix suffix("new category", true);
+ const tr1::shared_ptr<const PackageID> id(*env.package_database()->query(query::Matches(
+ PackageDepSpec(parse_user_package_dep_spec("=cat2/pkg1-1::namesincrtest_src",
+ UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+ id->perform_action(install_action);
+ vdb_repo->invalidate();
+
+ std::vector<FSEntry> cache_contents;
+ read_cache(cache_contents);
+ TEST_CHECK_EQUAL(cache_contents.size(), 1U);
+ TEST_CHECK_EQUAL(cache_contents.front().basename(), "pkg1");
+ TEST_CHECK_EQUAL(read_file(names_cache / "pkg1"), "cat1\ncat2\n");
+ }
+
+ {
+ TestMessageSuffix suffix("remove other category", true);
+ const tr1::shared_ptr<const PackageID> inst_id(*env.package_database()->query(query::Matches(
+ PackageDepSpec(parse_user_package_dep_spec("=cat2/pkg1-1::installed",
+ UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+ inst_id->perform_action(uninstall_action);
+ vdb_repo->invalidate();
+
+ std::vector<FSEntry> cache_contents;
+ read_cache(cache_contents);
+ TEST_CHECK_EQUAL(cache_contents.size(), 1U);
+ TEST_CHECK_EQUAL(cache_contents.front().basename(), "pkg1");
+ TEST_CHECK_EQUAL(read_file(names_cache / "pkg1"), "cat1\n");
+ }
+
+ {
+ TestMessageSuffix suffix("uninstall", true);
+ const tr1::shared_ptr<const PackageID> inst_id(*env.package_database()->query(query::Matches(
+ PackageDepSpec(parse_user_package_dep_spec("=cat1/pkg1-1::installed",
+ UserPackageDepSpecOptions()))), qo_require_exactly_one)->last());
+ inst_id->perform_action(uninstall_action);
+ vdb_repo->invalidate();
+
+ std::vector<FSEntry> cache_contents;
+ read_cache(cache_contents);
+ TEST_CHECK_EQUAL(cache_contents.size(), 0U);
+ }
+ }
+
+ void read_cache(std::vector<FSEntry> & vec)
+ {
+ using namespace tr1::placeholders;
+ std::remove_copy_if(DirIterator(names_cache, DirIteratorOptions() + dio_include_dotfiles),
+ DirIterator(), std::back_inserter(vec),
+ tr1::bind(&std::equal_to<std::string>::operator(),
+ std::equal_to<std::string>(),
+ "_VERSION_", tr1::bind(&FSEntry::basename, _1)));
+ }
+
+ std::string read_file(const FSEntry & f)
+ {
+ std::ifstream s(stringify(f).c_str());
+ std::stringstream ss;
+ std::copy(std::istreambuf_iterator<char>(s), std::istreambuf_iterator<char>(),
+ std::ostreambuf_iterator<char>(ss));
+ return ss.str();
+ }
+ } test_names_cache;
}
diff --git a/paludis/repositories/e/vdb_repository_TEST_setup.sh b/paludis/repositories/e/vdb_repository_TEST_setup.sh
index 943573b..9a87a86 100755
--- a/paludis/repositories/e/vdb_repository_TEST_setup.sh
+++ b/paludis/repositories/e/vdb_repository_TEST_setup.sh
@@ -355,3 +355,26 @@ pkg_config() {
}
END
+mkdir -p namesincrtest/.cache/names/installed namesincrtest_src/{eclass,profiles/profile,cat1/{pkg1,pkg2},cat2/pkg1} || exit 1
+echo paludis-2 >namesincrtest/.cache/names/installed/_VERSION_
+echo installed >>namesincrtest/.cache/names/installed/_VERSION_
+
+cat <<END > namesincrtest_src/profiles/profile/make.defaults
+ARCH=test
+USERLAND="GNU"
+KERNEL="linux"
+CHOST="i286-badger-linux-gnu"
+END
+echo namesincrtest_src >namesincrtest_src/profiles/repo_name
+echo cat1 >namesincrtest_src/profiles/categories
+echo cat2 >>namesincrtest_src/profiles/categories
+
+cat <<END >namesincrtest_src/cat1/pkg1/pkg1-1.ebuild
+KEYWORDS="test"
+SLOT="${PV:0:1}"
+END
+cp namesincrtest_src/cat1/pkg1/pkg1-{1,1.1}.ebuild
+cp namesincrtest_src/cat1/pkg1/pkg1-{1,2}.ebuild
+cp namesincrtest_src/cat1/{pkg1/pkg1,pkg2/pkg2}-1.ebuild
+cp namesincrtest_src/{cat1,cat2}/pkg1/pkg1-1.ebuild
+
diff --git a/paludis/repository_name_cache.cc b/paludis/repository_name_cache.cc
index 049365f..230e80c 100644
--- a/paludis/repository_name_cache.cc
+++ b/paludis/repository_name_cache.cc
@@ -30,14 +30,16 @@
#include <paludis/util/mutex.hh>
#include <paludis/util/wrapped_forward_iterator.hh>
#include <paludis/util/wrapped_output_iterator.hh>
-#include <list>
+#include <set>
#include <fstream>
+#include <cstring>
+#include <cerrno>
using namespace paludis;
namespace paludis
{
- typedef MakeHashedMap<PackageNamePart, std::list<CategoryNamePart> >::Type NameCacheMap;
+ typedef MakeHashedMap<PackageNamePart, std::set<CategoryNamePart> >::Type NameCacheMap;
template<>
struct Implementation<RepositoryNameCache>
@@ -58,101 +60,142 @@ namespace paludis
checked_name_cache_map(false)
{
}
- };
-}
-
-RepositoryNameCache::RepositoryNameCache(
- const FSEntry & location,
- const Repository * const repo) :
- PrivateImplementationPattern<RepositoryNameCache>(new Implementation<RepositoryNameCache>(
- location, repo))
-{
-}
-RepositoryNameCache::~RepositoryNameCache()
-{
+ NameCacheMap::iterator find(const PackageNamePart &) const;
+ void update(const PackageNamePart & p, NameCacheMap::iterator r);
+ };
}
-tr1::shared_ptr<const CategoryNamePartSet>
-RepositoryNameCache::category_names_containing_package(const PackageNamePart & p) const
+NameCacheMap::iterator
+Implementation<RepositoryNameCache>::find(const PackageNamePart & p) const
{
- Lock l(_imp->mutex);
-
- if (! _imp->usable)
- return tr1::shared_ptr<const CategoryNamePartSet>();
+ NameCacheMap::iterator r(name_cache_map.find(p));
- Context context("When using name cache at '" + stringify(_imp->location) + "':");
-
- tr1::shared_ptr<CategoryNamePartSet> result(new CategoryNamePartSet);
- NameCacheMap::iterator r(_imp->name_cache_map.find(p));
+ location = FSEntry(stringify(location));
- _imp->location = FSEntry(stringify(_imp->location));
-
- if (_imp->name_cache_map.end() == r)
+ if (name_cache_map.end() == r)
{
- r = _imp->name_cache_map.insert(std::make_pair(p, std::list<CategoryNamePart>())).first;
+ r = name_cache_map.insert(std::make_pair(p, std::set<CategoryNamePart>())).first;
- if (! _imp->checked_name_cache_map)
+ if (! checked_name_cache_map)
{
- if (_imp->location.is_directory() && (_imp->location / "_VERSION_").exists())
+ if (location.is_directory() && (location / "_VERSION_").exists())
{
- std::ifstream vvf(stringify(_imp->location / "_VERSION_").c_str());
+ std::ifstream vvf(stringify(location / "_VERSION_").c_str());
std::string line;
std::getline(vvf, line);
if (line != "paludis-2")
{
- Log::get_instance()->message(ll_warning, lc_context, "Names cache for '" + stringify(_imp->repo->name())
+ Log::get_instance()->message(ll_warning, lc_context, "Names cache for '" + stringify(repo->name())
+ "' has version string '" + line + "', which is not supported. Was it generated using "
"a different Paludis version?");
- _imp->usable = false;
- return tr1::shared_ptr<const CategoryNamePartSet>();
+ usable = false;
+ return name_cache_map.end();
}
std::getline(vvf, line);
- if (line != stringify(_imp->repo->name()))
+ if (line != stringify(repo->name()))
{
- Log::get_instance()->message(ll_warning, lc_context, "Names cache for '" + stringify(_imp->repo->name())
+ Log::get_instance()->message(ll_warning, lc_context, "Names cache for '" + stringify(repo->name())
+ "' was generated for repository '" + line + "', so it cannot be used. You must not "
"have multiple name caches at the same location.");
- _imp->usable = false;
- return tr1::shared_ptr<const CategoryNamePartSet>();
+ usable = false;
+ return name_cache_map.end();
}
- _imp->checked_name_cache_map = true;
+ checked_name_cache_map = true;
}
- else if ((_imp->location.dirname() / "_VERSION_").exists())
+ else if ((location.dirname() / "_VERSION_").exists())
{
- Log::get_instance()->message(ll_warning, lc_context, "Names cache for '" + stringify(_imp->repo->name())
- + "' does not exist at '" + stringify(_imp->location) + "', but a names cache exists at '" +
- stringify(_imp->location.dirname()) + "'. This was probably generated by a Paludis version "
+ Log::get_instance()->message(ll_warning, lc_context, "Names cache for '" + stringify(repo->name())
+ + "' does not exist at '" + stringify(location) + "', but a names cache exists at '" +
+ stringify(location.dirname()) + "'. This was probably generated by a Paludis version "
"older than 0.18.0. The names cache now automatically appends the repository name to the "
- "directory. You probably want to manually remove '" + stringify(_imp->location.dirname()) +
+ "directory. You probably want to manually remove '" + stringify(location.dirname()) +
"' and then regenerate the cache.");
- _imp->usable = false;
- return tr1::shared_ptr<const CategoryNamePartSet>();
+ usable = false;
+ return name_cache_map.end();
}
else
{
- Log::get_instance()->message(ll_warning, lc_context, "Names cache for '" + stringify(_imp->repo->name())
+ Log::get_instance()->message(ll_warning, lc_context, "Names cache for '" + stringify(repo->name())
+ "' has no version information, so cannot be used. Either it was generated using "
"an older Paludis version or it has not yet been generated.");
- _imp->usable = false;
- return tr1::shared_ptr<const CategoryNamePartSet>();
+ usable = false;
+ return name_cache_map.end();
}
}
- FSEntry ff(_imp->location / stringify(p));
+ FSEntry ff(location / stringify(p));
if (ff.exists())
{
std::ifstream f(stringify(ff).c_str());
if (! f)
- Log::get_instance()->message(ll_warning, lc_context, "Cannot read '" + stringify(ff) + "'");
+ Log::get_instance()->message(ll_warning, lc_context, "Cannot read '" + stringify(ff) + "': " + std::strerror(errno));
std::string line;
while (std::getline(f, line))
- r->second.push_back(CategoryNamePart(line));
+ r->second.insert(CategoryNamePart(line));
}
}
- std::copy(r->second.begin(), r->second.end(), result->inserter());
+ return r;
+}
+
+void
+Implementation<RepositoryNameCache>::update(const PackageNamePart & p, NameCacheMap::iterator r)
+{
+ FSEntry ff(location / stringify(p));
+ if (r->second.empty() && ff.exists())
+ {
+ try
+ {
+ ff.unlink();
+ }
+ catch (const FSError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Cannot unlink '" + stringify(ff) + "': " + e.message() + " (" + e.what() + ")");
+ }
+ return;
+ }
+ std::ofstream f(stringify(ff).c_str());
+ if (! f)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Cannot write '" + stringify(ff) + "': " + std::strerror(errno));
+ return;
+ }
+
+ for (std::set<CategoryNamePart>::const_iterator it(r->second.begin()),
+ it_end(r->second.end()); it_end != it; ++it)
+ f << *it << std::endl;
+}
+
+RepositoryNameCache::RepositoryNameCache(
+ const FSEntry & location,
+ const Repository * const repo) :
+ PrivateImplementationPattern<RepositoryNameCache>(new Implementation<RepositoryNameCache>(
+ location, repo))
+{
+}
+
+RepositoryNameCache::~RepositoryNameCache()
+{
+}
+
+tr1::shared_ptr<const CategoryNamePartSet>
+RepositoryNameCache::category_names_containing_package(const PackageNamePart & p) const
+{
+ Lock l(_imp->mutex);
+
+ if (! usable())
+ return tr1::shared_ptr<const CategoryNamePartSet>();
+
+ Context context("When using name cache at '" + stringify(_imp->location) + "':");
+
+ tr1::shared_ptr<CategoryNamePartSet> result(new CategoryNamePartSet);
+ NameCacheMap::iterator r(_imp->find(p));
+ if (_imp->name_cache_map.end() == r)
+ return tr1::shared_ptr<const CategoryNamePartSet>();
+
+ std::copy(r->second.begin(), r->second.end(), result->inserter());
return result;
}
@@ -195,7 +238,7 @@ RepositoryNameCache::regenerate_cache() const
if (! f)
{
Log::get_instance()->message(ll_warning, lc_context, "Cannot write to '"
- + stringify(_imp->location) + "'");
+ + stringify(_imp->location) + "': " + std::strerror(errno));
continue;
}
f << e->second;
@@ -209,7 +252,45 @@ RepositoryNameCache::regenerate_cache() const
}
else
Log::get_instance()->message(ll_warning, lc_context, "Cannot write to '"
- + stringify(_imp->location) + "'");
+ + stringify(_imp->location) + "': " + std::strerror(errno));
+}
+
+void
+RepositoryNameCache::add(const QualifiedPackageName & q)
+{
+ Lock l(_imp->mutex);
+
+ if (! usable())
+ return;
+
+ Context context("When adding '" + stringify(q) + "' to name cache at '" + stringify(_imp->location) + "':");
+
+ tr1::shared_ptr<CategoryNamePartSet> result(new CategoryNamePartSet);
+ NameCacheMap::iterator r(_imp->find(q.package));
+ if (_imp->name_cache_map.end() == r)
+ return;
+
+ r->second.insert(q.category);
+ _imp->update(q.package, r);
+}
+
+void
+RepositoryNameCache::remove(const QualifiedPackageName & q)
+{
+ Lock l(_imp->mutex);
+
+ if (! usable())
+ return;
+
+ Context context("When removing '" + stringify(q) + "' from name cache at '" + stringify(_imp->location) + "':");
+
+ tr1::shared_ptr<CategoryNamePartSet> result(new CategoryNamePartSet);
+ NameCacheMap::iterator r(_imp->find(q.package));
+ if (_imp->name_cache_map.end() == r)
+ return;
+
+ r->second.erase(q.category);
+ _imp->update(q.package, r);
}
bool
diff --git a/paludis/repository_name_cache.hh b/paludis/repository_name_cache.hh
index 3bc646c..3f26d8d 100644
--- a/paludis/repository_name_cache.hh
+++ b/paludis/repository_name_cache.hh
@@ -89,6 +89,16 @@ namespace paludis
*/
void regenerate_cache() const;
+ /**
+ * Add a new package to the cache.
+ */
+ void add(const QualifiedPackageName &);
+
+ /**
+ * Remove a package from the cache.
+ */
+ void remove(const QualifiedPackageName &);
+
///\}
};
}