Exheredludis/paludis/repositories/gemcutter/gemcutter_repository_store.cc
2011-08-07 18:18:38 +01:00

197 lines
6.3 KiB
C++

/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
* Copyright (c) 2010, 2011 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/gemcutter/gemcutter_repository_store.hh>
#include <paludis/repositories/gemcutter/gemcutter_repository.hh>
#include <paludis/repositories/gemcutter/gemcutter_id.hh>
#include <paludis/repositories/gemcutter/json_things_handle.hh>
#include <paludis/util/pimp-impl.hh>
#include <paludis/util/stringify.hh>
#include <paludis/util/set.hh>
#include <paludis/util/sequence.hh>
#include <paludis/util/hashes.hh>
#include <paludis/util/is_file_with_extension.hh>
#include <paludis/util/log.hh>
#include <paludis/util/make_named_values.hh>
#include <paludis/util/fs_stat.hh>
#include <paludis/name.hh>
#include <paludis/version_spec.hh>
#include <paludis/literal_metadata_key.hh>
#include <paludis/environment.hh>
#include <functional>
#include <unordered_map>
#include <algorithm>
#include <set>
using namespace paludis;
using namespace paludis::gemcutter_repository;
typedef std::unordered_map<CategoryNamePart,
std::shared_ptr<QualifiedPackageNameSet>,
Hash<CategoryNamePart> > PackageNames;
typedef std::unordered_map<QualifiedPackageName,
std::shared_ptr<PackageIDSequence>,
Hash<QualifiedPackageName> > IDs;
namespace paludis
{
template <>
struct Imp<GemcutterRepositoryStore>
{
const Environment * const env;
const GemcutterRepository * const repo;
const FSPath location;
std::shared_ptr<CategoryNamePartSet> categories;
PackageNames package_names;
IDs ids;
Imp(const Environment * const e, const GemcutterRepository * const r, const FSPath & l) :
env(e),
repo(r),
location(l),
categories(std::make_shared<CategoryNamePartSet>())
{
}
};
}
GemcutterRepositoryStore::GemcutterRepositoryStore(
const Environment * const env,
const GemcutterRepository * const repo,
const FSPath & location) :
_imp(env, repo, location)
{
_populate();
}
GemcutterRepositoryStore::~GemcutterRepositoryStore()
{
}
void
GemcutterRepositoryStore::_populate()
{
Context context("When populating ::" + stringify(_imp->repo->name()) + ":");
FSPath all_gems(_imp->location / "all-gems.json");
if (! all_gems.stat().exists())
{
Log::get_instance()->message("gemcutter_repository.no_all_gems_file", ll_warning, lc_context)
<< "File '" << all_gems << "' does not exist, and it should, unless you have just created "
<< "the ::" << stringify(_imp->repo->name()) << " repository and not yet synced it";
return;
}
try
{
JSONThingsHandle::get_instance()->parse_all_gems(
all_gems,
std::bind(&GemcutterRepositoryStore::_populate_one, this, std::placeholders::_1));
}
catch (const Exception & e)
{
Log::get_instance()->message("gemcutter_repository.not_available", ll_warning, lc_context)
<< "Not loading '" << all_gems << "' for ::" << stringify(_imp->repo->name()) << " due to "
<< "exception '" << e.backtrace(": ") << ": " << e.message() << "' (" << e.what() << ")";
_imp->categories->clear();
_imp->package_names.clear();
_imp->ids.clear();
return;
}
}
void
GemcutterRepositoryStore::_populate_one(const GemJSONInfo & info)
{
Context context("When populating ::" + stringify(_imp->repo->name()) + " " +
stringify(info.name()) + " " + stringify(info.version()) + ":");
const std::shared_ptr<GemcutterID> id(std::make_shared<GemcutterID>(make_named_values<GemcutterIDParams>(
n::environment() = _imp->env,
n::info() = info,
n::repository() = _imp->repo->name()
)));
_imp->categories->insert(id->name().category());
PackageNames::iterator p(_imp->package_names.find(id->name().category()));
if (_imp->package_names.end() == p)
p = _imp->package_names.insert(std::make_pair(id->name().category(),
std::make_shared<QualifiedPackageNameSet>())).first;
p->second->insert(id->name());
IDs::iterator i(_imp->ids.find(id->name()));
if (_imp->ids.end() == i)
i = _imp->ids.insert(std::make_pair(id->name(), std::make_shared<PackageIDSequence>())).first;
i->second->push_back(id);
}
bool
GemcutterRepositoryStore::has_category_named(const CategoryNamePart & c) const
{
return _imp->categories->end() != _imp->categories->find(c);
}
bool
GemcutterRepositoryStore::has_package_named(const QualifiedPackageName & q) const
{
return _imp->ids.end() != _imp->ids.find(q);
}
std::shared_ptr<const CategoryNamePartSet>
GemcutterRepositoryStore::category_names() const
{
return _imp->categories;
}
std::shared_ptr<const CategoryNamePartSet>
GemcutterRepositoryStore::unimportant_category_names() const
{
std::shared_ptr<CategoryNamePartSet> result(std::make_shared<CategoryNamePartSet>());
return result;
}
std::shared_ptr<const QualifiedPackageNameSet>
GemcutterRepositoryStore::package_names(const CategoryNamePart & c) const
{
auto p(_imp->package_names.find(c));
if (_imp->package_names.end() == p)
return std::make_shared<QualifiedPackageNameSet>();
else
return p->second;
}
std::shared_ptr<const PackageIDSequence>
GemcutterRepositoryStore::package_ids(const QualifiedPackageName & p) const
{
auto i(_imp->ids.find(p));
if (_imp->ids.end() == i)
return std::make_shared<PackageIDSequence>();
else
return i->second;
}
namespace paludis
{
template class Pimp<gemcutter_repository::GemcutterRepositoryStore>;
}