diff options
Diffstat (limited to '0.8.0/paludis/repositories/portage')
37 files changed, 6541 insertions, 0 deletions
diff --git a/0.8.0/paludis/repositories/portage/Makefile.am b/0.8.0/paludis/repositories/portage/Makefile.am new file mode 100644 index 000000000..3d6ff9142 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/Makefile.am @@ -0,0 +1,127 @@ +CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda +DISTCLEANFILES = portage_repository-sr.hh portage_repository-sr.cc glsa-sr.hh glsa-sr.cc +MAINTAINERCLEANFILES = Makefile.in + +AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@ @PALUDIS_CXXFLAGS_VISIBILITY@ +DEFS= \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DLIBEXECDIR=\"$(libexecdir)\" \ + -DDATADIR=\"$(datadir)\" \ + -DLIBDIR=\"$(libdir)\" + +paludis_repositories_libdir = $(libdir)/paludis/repositories +paludis_repositories_lib_LTLIBRARIES = libpaludisportagerepository.la +paludis_repositories_portage_includedir = $(includedir)/paludis/repositories/portage/ +libpaludisportagerepository_la_LDFLAGS = -version-info @VERSION_LIB_CURRENT@:@VERSION_LIB_REVISION@:0 + +paludis_repositories_portage_include_HEADERS = \ + glsa.hh \ + glsa-sr.hh \ + portage_repository.hh \ + portage_repository_profile_file.hh \ + portage_repository_profile.hh \ + portage_repository_exceptions.hh \ + portage_repository_news.hh \ + portage_repository_params.hh \ + portage_repository_params-sr.hh \ + portage_repository_sets.hh \ + portage_repository_entries.hh \ + portage_repository_ebuild_entries.hh \ + portage_repository_ebin_entries.hh \ + make_ebuild_repository.hh \ + make_ebin_repository.hh + +libpaludisportagerepository_la_SOURCES = \ + glsa.cc \ + portage_repository.cc \ + portage_repository_profile_file.cc \ + portage_repository_profile.cc \ + portage_repository_exceptions.cc \ + portage_repository_news.cc \ + portage_repository_sets.cc \ + portage_repository_entries.cc \ + portage_repository_ebuild_entries.cc \ + portage_repository_ebin_entries.cc \ + portage_repository_params.cc \ + make_ebuild_repository.cc \ + make_ebin_repository.cc \ + $(paludis_repositories_portage_include_HEADERS) + +libpaludisportagerepository_la_LIBADD = \ + $(top_builddir)/paludis/util/libpaludisutil.la \ + $(top_builddir)/paludis/libpaludis.la \ + $(DYNAMIC_LD_LIBS) + +portage_repository_TEST_SOURCES = portage_repository_TEST.cc + +portage_repository_TEST_LDADD = \ + libpaludisportagerepository.la \ + $(top_builddir)/paludis/util/libpaludisutil.la \ + $(top_builddir)/paludis/util/test_extras.o \ + $(top_builddir)/paludis/libpaludis.la \ + $(top_builddir)/paludis/environment/test/libpaludistestenvironment.la \ + $(top_builddir)/test/libtest.a + +portage_repository_TEST_CXXFLAGS = -I$(top_srcdir) + +EXTRA_DIST = \ + glsa.sr \ + portage_repository_TEST.cc \ + portage_repository_TEST_setup.sh \ + portage_repository_TEST_cleanup.sh \ + portage_repository_params-sr.hh \ + portage_repository_params-sr.cc \ + portage_repository_params.sr \ + xml_things_TEST.cc \ + xml_things_TEST_setup.sh \ + xml_things_TEST_cleanup.sh + +BUILT_SOURCES = \ + portage_repository_params-sr.hh \ + portage_repository_params-sr.cc \ + glsa-sr.hh \ + glsa-sr.cc + +check_SCRIPTS = \ + portage_repository_TEST_setup.sh portage_repository_TEST_cleanup.sh \ + xml_things_TEST_setup.sh xml_things_TEST_cleanup.sh + +TESTS_ENVIRONMENT = env \ + PALUDIS_EBUILD_DIR="$(top_srcdir)/ebuild/" \ + PALUDIS_SKIP_CONFIG="yes" \ + TEST_SCRIPT_DIR="$(srcdir)/" \ + PALUDIS_REPOSITORY_SO_DIR="$(top_builddir)/paludis/repositories" \ + LD_LIBRARY_PATH="`$(top_srcdir)/ebuild/utils/canonicalise $(top_builddir)/paludis/repositories/portage/`" \ + bash $(top_srcdir)/test/run_test.sh + +portage_repository_params-sr.hh : portage_repository_params.sr $(top_srcdir)/misc/make_sr.bash + $(top_srcdir)/misc/make_sr.bash --header $(srcdir)/portage_repository_params.sr > $@ + +portage_repository_params-sr.cc : portage_repository_params.sr $(top_srcdir)/misc/make_sr.bash + $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/portage_repository_params.sr > $@ + +glsa-sr.hh : glsa.sr $(top_srcdir)/misc/make_sr.bash + $(top_srcdir)/misc/make_sr.bash --header $(srcdir)/glsa.sr > $@ + +glsa-sr.cc : glsa.sr $(top_srcdir)/misc/make_sr.bash + $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/glsa.sr > $@ + +if ENABLE_GLSA +lib_LTLIBRARIES = libpaludisportagerepositoryxmlthings.la +libpaludisportagerepositoryxmlthings_la_SOURCES = xml_things.cc +libpaludisportagerepositoryxmlthings_la_CXXFLAGS = @LIBXML2DEPS_CFLAGS@ +libpaludisportagerepositoryxmlthings_la_LIBADD = @LIBXML2DEPS_LIBS@ \ + $(top_builddir)/paludis/util/libpaludisutil.la \ + $(top_builddir)/paludis/libxml/libpaludislibxml.la + +GLSA_TESTS = xml_things_TEST +xml_things_TEST_SOURCES = xml_things_TEST.cc +xml_things_TEST_LDADD = \ + $(top_builddir)/paludis/util/test_extras.o \ + $(top_builddir)/test/libtest.a \ + libpaludisportagerepository.la +endif + +TESTS = portage_repository_TEST $(GLSA_TESTS) +check_PROGRAMS = $(TESTS) + diff --git a/0.8.0/paludis/repositories/portage/glsa.cc b/0.8.0/paludis/repositories/portage/glsa.cc new file mode 100644 index 000000000..8e44e9f14 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/glsa.cc @@ -0,0 +1,233 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 "glsa.hh" +#include <paludis/util/iterator.hh> +#include <paludis/util/stringify.hh> +#include <list> +#include <dlfcn.h> +#include "config.h" + +#define STUPID_CAST(type, val) reinterpret_cast<type>(reinterpret_cast<uintptr_t>(val)) + +using namespace paludis; + +#include "glsa-sr.cc" + +namespace paludis +{ + template<> + struct Implementation<GLSAPackage> : + InternalCounted<Implementation<GLSAPackage> > + { + QualifiedPackageName name; + std::list<UseFlagName> archs; + std::list<GLSARange> unaffected; + std::list<GLSARange> vulnerable; + + Implementation(const QualifiedPackageName & n) : + name(n) + { + } + }; + + template<> + struct Implementation<GLSA> : + InternalCounted<Implementation<GLSA> > + { + std::string id; + std::string title; + std::list<GLSAPackage::ConstPointer> packages; + }; +} + +GLSAPackage::GLSAPackage(const QualifiedPackageName & n) : + PrivateImplementationPattern<GLSAPackage>(new Implementation<GLSAPackage>(n)) +{ +} + +GLSAPackage::~GLSAPackage() +{ +} + +GLSAPackage::ArchsIterator +GLSAPackage::begin_archs() const +{ + return ArchsIterator(_imp->archs.begin()); +} + +GLSAPackage::ArchsIterator +GLSAPackage::end_archs() const +{ + return ArchsIterator(_imp->archs.end()); +} + +void +GLSAPackage::add_arch(const UseFlagName & n) +{ + _imp->archs.push_back(n); +} + +GLSAPackage::RangesIterator +GLSAPackage::begin_unaffected() const +{ + return RangesIterator(_imp->unaffected.begin()); +} + +GLSAPackage::RangesIterator +GLSAPackage::end_unaffected() const +{ + return RangesIterator(_imp->unaffected.end()); +} + +GLSAPackage::RangesIterator +GLSAPackage::begin_vulnerable() const +{ + return RangesIterator(_imp->vulnerable.begin()); +} + +GLSAPackage::RangesIterator +GLSAPackage::end_vulnerable() const +{ + return RangesIterator(_imp->vulnerable.end()); +} + +void +GLSAPackage::add_unaffected(const GLSARange & r) +{ + _imp->unaffected.push_back(r); +} + +void +GLSAPackage::add_vulnerable(const GLSARange & r) +{ + _imp->vulnerable.push_back(r); +} + +QualifiedPackageName +GLSAPackage::name() const +{ + return _imp->name; +} + +GLSA::GLSA() : + PrivateImplementationPattern<GLSA>(new Implementation<GLSA>) +{ +} + +GLSA::~GLSA() +{ +} + +GLSA::PackagesIterator +GLSA::begin_packages() const +{ + return PackagesIterator(indirect_iterator<const GLSAPackage>(_imp->packages.begin())); +} + +GLSA::PackagesIterator +GLSA::end_packages() const +{ + return PackagesIterator(indirect_iterator<const GLSAPackage>(_imp->packages.end())); +} + +void +GLSA::add_package(GLSAPackage::ConstPointer p) +{ + _imp->packages.push_back(p); +} + +void +GLSA::set_id(const std::string & s) +{ + _imp->id = s; +} + +void +GLSA::set_title(const std::string & s) +{ + _imp->title = s; +} + +std::string +GLSA::id() const +{ + return _imp->id; +} + +std::string +GLSA::title() const +{ + return _imp->title; +} + +namespace +{ + struct LibXMLHandle + { + void * handle; + GLSA::Pointer (* create_glsa_from_xml_file_handle)(const std::string &); + + LibXMLHandle() : + handle(0), + create_glsa_from_xml_file_handle(0) + { + } + + ~LibXMLHandle() + { + if (0 != handle) + dlclose(handle); + } + + } libxmlhandle; +} + +GLSA::Pointer +GLSA::create_from_xml_file(const std::string & filename) +{ +#if ENABLE_GLSA + if (0 == libxmlhandle.handle) + libxmlhandle.handle = dlopen("libpaludisportagerepositoryxmlthings.so", + RTLD_NOW | RTLD_GLOBAL); + if (0 == libxmlhandle.handle) + throw NotAvailableError("Cannot create GLSA from XML file '" + filename + "' due to error '" + + stringify(dlerror()) + "' when dlopen(libpaludisportagerepositoryxmlthings.so)"); +#else + /* avoid noreturn warning */ + if (0 == libxmlhandle.handle) + throw NotAvailableError("Cannot create GLSA from XML file '" + filename + "' because Paludis was built " + "without GLSA support"); +#endif + + if (0 == libxmlhandle.create_glsa_from_xml_file_handle) + libxmlhandle.create_glsa_from_xml_file_handle = STUPID_CAST(GLSA::Pointer (*)(const std::string &), + dlsym(libxmlhandle.handle, "create_glsa_from_xml_file")); + if (0 == libxmlhandle.create_glsa_from_xml_file_handle) + throw NotAvailableError("Cannot create GLSA from XML file '" + filename + "' due to error '" + + stringify(dlerror()) + "' when dlsym(libpaludisportagerepositoryxmlthings.so, create_glsa_from_xml_file)"); + + return (*libxmlhandle.create_glsa_from_xml_file_handle)(filename); +} + +GLSAError::GLSAError(const std::string & msg, const std::string & filename) throw () : + ConfigurationError("GLSA error: " + msg + (filename.empty() ? "" : " in file " + filename)) +{ +} + diff --git a/0.8.0/paludis/repositories/portage/glsa.hh b/0.8.0/paludis/repositories/portage/glsa.hh new file mode 100644 index 000000000..dc25d8f98 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/glsa.hh @@ -0,0 +1,97 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_GLSA_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_GLSA_HH 1 + +#include <paludis/util/private_implementation_pattern.hh> +#include <paludis/util/counted_ptr.hh> +#include <paludis/util/sr.hh> +#include <paludis/name.hh> +#include <paludis/version_spec.hh> +#include <libwrapiter/libwrapiter_forward_iterator.hh> + +#include <string> + +namespace paludis +{ + +#include <paludis/repositories/portage/glsa-sr.hh> + + class PALUDIS_VISIBLE GLSAError : + public ConfigurationError + { + public: + ///\name Basic operations + ///\{ + + GLSAError(const std::string & message, + const std::string & filename = "") throw (); + + ///\} + }; + + class PALUDIS_VISIBLE GLSAPackage : + private PrivateImplementationPattern<GLSAPackage>, + public InternalCounted<GLSAPackage> + { + public: + GLSAPackage(const QualifiedPackageName & name); + ~GLSAPackage(); + + typedef libwrapiter::ForwardIterator<GLSAPackage, const UseFlagName> ArchsIterator; + ArchsIterator begin_archs() const; + ArchsIterator end_archs() const; + void add_arch(const UseFlagName &); + + typedef libwrapiter::ForwardIterator<GLSAPackage, const GLSARange> RangesIterator; + RangesIterator begin_unaffected() const; + RangesIterator end_unaffected() const; + RangesIterator begin_vulnerable() const; + RangesIterator end_vulnerable() const; + void add_unaffected(const GLSARange &); + void add_vulnerable(const GLSARange &); + + QualifiedPackageName name() const; + }; + + class PALUDIS_VISIBLE GLSA : + private PrivateImplementationPattern<GLSA>, + public InternalCounted<GLSA> + { + public: + GLSA(); + ~GLSA(); + + static GLSA::Pointer create_from_xml_file(const std::string & filename); + + typedef libwrapiter::ForwardIterator<GLSA, const GLSAPackage> PackagesIterator; + PackagesIterator begin_packages() const; + PackagesIterator end_packages() const; + void add_package(GLSAPackage::ConstPointer); + + void set_id(const std::string &); + std::string id() const; + + void set_title(const std::string &); + std::string title() const; + }; +} + +#endif diff --git a/0.8.0/paludis/repositories/portage/glsa.sr b/0.8.0/paludis/repositories/portage/glsa.sr new file mode 100644 index 000000000..359ffeeff --- /dev/null +++ b/0.8.0/paludis/repositories/portage/glsa.sr @@ -0,0 +1,8 @@ +make_class_GLSARange() +{ + key op std::string; + # not a version, may be something like 1.3* + key version std::string; + + allow_named_args; +} diff --git a/0.8.0/paludis/repositories/portage/make_ebin_repository.cc b/0.8.0/paludis/repositories/portage/make_ebin_repository.cc new file mode 100644 index 000000000..66acaee20 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/make_ebin_repository.cc @@ -0,0 +1,114 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 "make_ebin_repository.hh" +#include <paludis/util/log.hh> +#include <paludis/util/collection_concrete.hh> +#include <paludis/util/tokeniser.hh> +#include <paludis/repositories/portage/portage_repository_exceptions.hh> + +using namespace paludis; + +CountedPtr<Repository> +paludis::make_ebin_repository( + const Environment * const env, + const PackageDatabase * const db, + AssociativeCollection<std::string, std::string>::ConstPointer m) +{ + std::string repo_file(m->end() == m->find("repo_file") ? std::string("?") : + m->find("repo_file")->second); + + Context context("When making ebin repository from repo_file '" + repo_file + "':"); + + std::string location; + if (m->end() == m->find("location") || ((location = m->find("location")->second)).empty()) + throw PortageRepositoryConfigurationError("Key 'location' not specified or empty"); + + FSEntryCollection::Pointer profiles(new FSEntryCollection::Concrete); + if (m->end() != m->find("profiles")) + WhitespaceTokeniser::get_instance()->tokenise(m->find("profiles")->second, + create_inserter<FSEntry>(std::back_inserter(*profiles))); + if (profiles->empty()) + throw PortageRepositoryConfigurationError("No profiles have been specified"); + + FSEntryCollection::Pointer eclassdirs(new FSEntryCollection::Concrete); + + std::string pkgdir; + if (m->end() == m->find("pkgdir") || ((pkgdir = m->find("pkgdir")->second)).empty()) + pkgdir = location + "/packages"; + + std::string setsdir; + if (m->end() == m->find("setsdir") || ((setsdir = m->find("setsdir")->second)).empty()) + setsdir = location + "/sets"; + + std::string securitydir; + if (m->end() == m->find("securitydir") || ((securitydir = m->find("securitydir")->second)).empty()) + securitydir = location + "/metadata/glsa"; + + std::string newsdir; + if (m->end() == m->find("newsdir") || ((newsdir = m->find("newsdir")->second)).empty()) + newsdir = location + "/metadata/news"; + + std::string sync; + if (m->end() == m->find("sync") || ((sync = m->find("sync")->second)).empty()) + ; // nothing + + std::string sync_exclude; + if (m->end() == m->find("sync_exclude") || ((sync_exclude = m->find("sync_exclude")->second)).empty()) + ; // nothing + + std::string root; + if (m->end() == m->find("root") || ((root = m->find("root")->second)).empty()) + root = "/"; + + std::string buildroot; + if (m->end() == m->find("buildroot") || ((buildroot = m->find("buildroot")->second)).empty()) + buildroot = "/var/tmp/paludis"; + + return CountedPtr<Repository>(new PortageRepository(PortageRepositoryParams::create() + .entry_format("ebin") + .environment(env) + .package_database(db) + .location(location) + .profiles(profiles) + .cache(FSEntry("/var/empty")) + .eclassdirs(eclassdirs) + .distdir(FSEntry("/var/empty")) + .pkgdir(pkgdir) + .securitydir(securitydir) + .setsdir(setsdir) + .newsdir(newsdir) + .sync(sync) + .sync_exclude(sync_exclude) + .root(root) + .buildroot(buildroot))); +} + +#ifdef PALUDIS_ENABLE_VISIBILITY +# pragma GCC visibility push(default) +#endif +namespace +{ + const RepositoryMaker::RegisterMaker register_portage_ebin_repository PALUDIS_ATTRIBUTE((used)) ( + "ebin", &make_ebin_repository); +} +#ifdef PALUDIS_ENABLE_VISIBILITY +# pragma GCC visibility pop +#endif + diff --git a/0.8.0/paludis/repositories/portage/make_ebin_repository.hh b/0.8.0/paludis/repositories/portage/make_ebin_repository.hh new file mode 100644 index 000000000..efcf2ce35 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/make_ebin_repository.hh @@ -0,0 +1,35 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_MAKE_EBIN_REPOSITORY_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_MAKE_EBIN_REPOSITORY_HH 1 + +#include <paludis/repositories/portage/portage_repository.hh> + +namespace paludis +{ + CountedPtr<Repository> + make_ebin_repository(const Environment * const, + const PackageDatabase * const, + AssociativeCollection<std::string, std::string>::ConstPointer) PALUDIS_VISIBLE; + +} + + +#endif diff --git a/0.8.0/paludis/repositories/portage/make_ebuild_repository.cc b/0.8.0/paludis/repositories/portage/make_ebuild_repository.cc new file mode 100644 index 000000000..b43ffedd7 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/make_ebuild_repository.cc @@ -0,0 +1,159 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 "make_ebuild_repository.hh" +#include <paludis/util/log.hh> +#include <paludis/util/collection_concrete.hh> +#include <paludis/util/tokeniser.hh> +#include <paludis/repositories/portage/portage_repository_exceptions.hh> + +using namespace paludis; + +CountedPtr<Repository> +paludis::make_ebuild_repository( + const Environment * const env, + const PackageDatabase * const db, + AssociativeCollection<std::string, std::string>::ConstPointer m) +{ + std::string repo_file(m->end() == m->find("repo_file") ? std::string("?") : + m->find("repo_file")->second); + + Context context("When making ebuild repository from repo_file '" + repo_file + "':"); + + std::string location; + if (m->end() == m->find("location") || ((location = m->find("location")->second)).empty()) + throw PortageRepositoryConfigurationError("Key 'location' not specified or empty"); + + FSEntryCollection::Pointer profiles(new FSEntryCollection::Concrete); + if (m->end() != m->find("profiles")) + WhitespaceTokeniser::get_instance()->tokenise(m->find("profiles")->second, + create_inserter<FSEntry>(std::back_inserter(*profiles))); + if (m->end() != m->find("profile") && ! m->find("profile")->second.empty()) + { + Log::get_instance()->message(ll_warning, lc_no_context, + "Key 'profile' in '" + repo_file + "' is deprecated, " + "use 'profiles = " + m->find("profile")->second + "' instead"); + if (profiles->empty()) + profiles->append(m->find("profile")->second); + else + throw PortageRepositoryConfigurationError("Both 'profile' and 'profiles' keys are present"); + } + if (profiles->empty()) + throw PortageRepositoryConfigurationError("No profiles have been specified"); + + FSEntryCollection::Pointer eclassdirs(new FSEntryCollection::Concrete); + if (m->end() != m->find("eclassdirs")) + WhitespaceTokeniser::get_instance()->tokenise(m->find("eclassdirs")->second, + create_inserter<FSEntry>(std::back_inserter(*eclassdirs))); + if (m->end() != m->find("eclassdir") && ! m->find("eclassdir")->second.empty()) + { + Log::get_instance()->message(ll_warning, lc_no_context, + "Key 'eclassdir' in '" + repo_file + "' is deprecated, " + "use 'eclassdirs = " + m->find("eclassdir")->second + "' instead"); + if (eclassdirs->empty()) + eclassdirs->append(m->find("eclassdir")->second); + else + throw PortageRepositoryConfigurationError("Both 'eclassdir' and 'eclassdirs' keys are present"); + } + if (eclassdirs->empty()) + eclassdirs->append(location + "/eclass"); + + std::string distdir; + if (m->end() == m->find("distdir") || ((distdir = m->find("distdir")->second)).empty()) + distdir = location + "/distfiles"; + + std::string setsdir; + if (m->end() == m->find("setsdir") || ((setsdir = m->find("setsdir")->second)).empty()) + setsdir = location + "/sets"; + + std::string securitydir; + if (m->end() == m->find("securitydir") || ((securitydir = m->find("securitydir")->second)).empty()) + securitydir = location + "/metadata/glsa"; + + std::string newsdir; + if (m->end() == m->find("newsdir") || ((newsdir = m->find("newsdir")->second)).empty()) + newsdir = location + "/metadata/news"; + + std::string cache; + if (m->end() == m->find("cache") || ((cache = m->find("cache")->second)).empty()) + { + cache = location + "/metadata/cache"; + if (! FSEntry(cache).exists()) + cache = "/var/empty"; + } + + std::string sync; + if (m->end() == m->find("sync") || ((sync = m->find("sync")->second)).empty()) + ; // nothing + + std::string sync_exclude; + if (m->end() == m->find("sync_exclude") || ((sync_exclude = m->find("sync_exclude")->second)).empty()) + ; // nothing + + std::string root; + if (m->end() == m->find("root") || ((root = m->find("root")->second)).empty()) + root = "/"; + + std::string buildroot; + if (m->end() == m->find("buildroot") || ((buildroot = m->find("buildroot")->second)).empty()) + buildroot = "/var/tmp/paludis"; + + return CountedPtr<Repository>(new PortageRepository(PortageRepositoryParams::create() + .entry_format("ebuild") + .environment(env) + .package_database(db) + .location(location) + .profiles(profiles) + .cache(cache) + .eclassdirs(eclassdirs) + .distdir(distdir) + .pkgdir(FSEntry("/var/empty")) + .securitydir(securitydir) + .setsdir(setsdir) + .newsdir(newsdir) + .sync(sync) + .sync_exclude(sync_exclude) + .root(root) + .buildroot(buildroot))); +} + +CountedPtr<Repository> +paludis::make_portage_repository( + const Environment * const env, + const PackageDatabase * const db, + AssociativeCollection<std::string, std::string>::ConstPointer m) +{ + return make_ebuild_repository(env, db, m); +} + +#ifdef PALUDIS_ENABLE_VISIBILITY +# pragma GCC visibility push(default) +#endif +namespace +{ + const RepositoryMaker::RegisterMaker register_portage_ebuild_repository PALUDIS_ATTRIBUTE((used)) ( + "ebuild", &make_ebuild_repository); + + const RepositoryMaker::RegisterMaker register_portage_portage_repository PALUDIS_ATTRIBUTE((used)) ( + "portage", &make_portage_repository); +} +#ifdef PALUDIS_ENABLE_VISIBILITY +# pragma GCC visibility pop +#endif + diff --git a/0.8.0/paludis/repositories/portage/make_ebuild_repository.hh b/0.8.0/paludis/repositories/portage/make_ebuild_repository.hh new file mode 100644 index 000000000..83d834f4c --- /dev/null +++ b/0.8.0/paludis/repositories/portage/make_ebuild_repository.hh @@ -0,0 +1,38 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_MAKE_EBUILD_REPOSITORY_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_MAKE_EBUILD_REPOSITORY_HH 1 + +#include <paludis/repositories/portage/portage_repository.hh> + +namespace paludis +{ + CountedPtr<Repository> + make_ebuild_repository(const Environment * const, + const PackageDatabase * const, + AssociativeCollection<std::string, std::string>::ConstPointer) PALUDIS_VISIBLE; + + CountedPtr<Repository> + make_portage_repository(const Environment * const, + const PackageDatabase * const, + AssociativeCollection<std::string, std::string>::ConstPointer) PALUDIS_VISIBLE; +} + +#endif diff --git a/0.8.0/paludis/repositories/portage/portage_repository.cc b/0.8.0/paludis/repositories/portage/portage_repository.cc new file mode 100644 index 000000000..127ce7ea4 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository.cc @@ -0,0 +1,1004 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * Copyright (c) 2006 Danny van Dyk <kugelfang@gentoo.org> + * + * 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 "config.h" + +#include <paludis/repositories/portage/portage_repository.hh> +#include <paludis/repositories/portage/portage_repository_profile.hh> +#include <paludis/repositories/portage/portage_repository_news.hh> +#include <paludis/repositories/portage/portage_repository_sets.hh> +#include <paludis/repositories/portage/portage_repository_exceptions.hh> +#include <paludis/repositories/portage/portage_repository_entries.hh> + +#include <paludis/config_file.hh> +#include <paludis/dep_atom.hh> +#include <paludis/dep_atom_flattener.hh> +#include <paludis/environment.hh> +#include <paludis/hashed_containers.hh> +#include <paludis/match_package.hh> +#include <paludis/package_database.hh> +#include <paludis/package_database_entry.hh> +#include <paludis/portage_dep_parser.hh> +#include <paludis/syncer.hh> +#include <paludis/util/collection_concrete.hh> +#include <paludis/util/dir_iterator.hh> +#include <paludis/util/fs_entry.hh> +#include <paludis/util/is_file_with_extension.hh> +#include <paludis/util/iterator.hh> +#include <paludis/util/log.hh> +#include <paludis/util/pstream.hh> +#include <paludis/util/random.hh> +#include <paludis/util/save.hh> +#include <paludis/util/stringify.hh> +#include <paludis/util/strip.hh> +#include <paludis/util/system.hh> +#include <paludis/util/tokeniser.hh> + +#include <map> +#include <fstream> +#include <functional> +#include <algorithm> +#include <vector> +#include <limits> + +#include <strings.h> +#include <ctype.h> + +/** \file + * Implementation of PortageRepository. + * + * \ingroup grpportagerepository + */ + +using namespace paludis; + +namespace paludis +{ + /// Map for versions. + typedef MakeHashedMap<QualifiedPackageName, VersionSpecCollection::Pointer>::Type VersionsMap; + + /// Map for repository masks. + typedef MakeHashedMap<QualifiedPackageName, std::list<PackageDepAtom::ConstPointer> >::Type RepositoryMaskMap; + + /// Map for categories. + typedef MakeHashedMap<CategoryNamePart, bool>::Type CategoryMap; + + /// Map for packages. + typedef MakeHashedMap<QualifiedPackageName, bool>::Type PackagesMap; + + /// Map for mirrors. + typedef MakeHashedMultiMap<std::string, std::string>::Type MirrorMap; + + /// Map for metadata. + typedef MakeHashedMap<std::pair<QualifiedPackageName, VersionSpec>, + VersionMetadata::Pointer>::Type MetadataMap; + + /// Map for virtuals. + typedef MakeHashedMap<QualifiedPackageName, PackageDepAtom::ConstPointer>::Type VirtualsMap; + + /** + * Implementation data for a PortageRepository. + * + * \ingroup grpportagerepository + */ + template <> + struct Implementation<PortageRepository> : + InternalCounted<Implementation<PortageRepository> > + { + /// Our parameters + const PortageRepositoryParams params; + + /// Have we loaded our category names? + mutable bool has_category_names; + + /// Our category names, and whether we have a fully loaded list + /// of package names for that category. + mutable CategoryMap category_names; + + /// Our package names, and whether we have a fully loaded list of + /// version specs for that category. + mutable PackagesMap package_names; + + /// Our version specs for each package. + mutable VersionsMap version_specs; + + /// Metadata cache. + mutable MetadataMap metadata; + + /// Repository mask. + mutable RepositoryMaskMap repo_mask; + + /// Have repository mask? + mutable bool has_repo_mask; + + /// Have virtual names? + mutable bool has_virtuals; + + /// Arch flags + mutable UseFlagNameCollection::Pointer arch_flags; + + /// Do we have mirrors? + mutable bool has_mirrors; + + /// Mirrors. + mutable MirrorMap mirrors; + + /// Constructor. + Implementation(PortageRepository * const, const PortageRepositoryParams &); + + /// Destructor. + ~Implementation(); + + /// Invalidate our cache. + void invalidate() const; + + /// (Empty) provides map. + const std::map<QualifiedPackageName, QualifiedPackageName> provide_map; + + /// Load profiles, if we haven't already. + inline void need_profiles() const; + + /// Our profile handler. + mutable PortageRepositoryProfile::Pointer profile_ptr; + + /// Our news handler. + mutable PortageRepositoryNews::Pointer news_ptr; + + /// Our sets handler. + mutable PortageRepositorySets::Pointer sets_ptr; + + /// Our metadata handler. + mutable PortageRepositoryEntries::Pointer entries_ptr; + + /// Our virtuals + mutable VirtualsMap our_virtuals; + + /// Have we loaded our virtuals? + bool has_our_virtuals; + }; + + Implementation<PortageRepository>::Implementation(PortageRepository * const repo, + const PortageRepositoryParams & p) : + params(p), + has_category_names(false), + has_repo_mask(false), + has_virtuals(false), + arch_flags(0), + has_mirrors(false), + profile_ptr(0), + news_ptr(new PortageRepositoryNews(params.environment, repo, p)), + sets_ptr(new PortageRepositorySets(params.environment, repo, p)), + entries_ptr(PortageRepositoryEntriesMaker::get_instance()->find_maker( + params.entry_format)(params.environment, repo, p)), + has_our_virtuals(false) + { + } + + Implementation<PortageRepository>::~Implementation() + { + } + + void + Implementation<PortageRepository>::need_profiles() const + { + if (profile_ptr) + return; + + profile_ptr.assign(new PortageRepositoryProfile( + params.environment, *params.profiles)); + } + + void + Implementation<PortageRepository>::invalidate() const + { + profile_ptr.zero(); + has_category_names = false; + category_names.clear(); + package_names.clear(); + version_specs.clear(); + metadata.clear(); + repo_mask.clear(); + has_repo_mask = false; + has_virtuals = false; + arch_flags.assign(0); + has_mirrors = false; + mirrors.clear(); + } +} + +PortageRepository::PortageRepository(const PortageRepositoryParams & p) : + Repository(PortageRepository::fetch_repo_name(stringify(p.location)), + RepositoryCapabilities::create() + .mask_interface(this) + .installable_interface(this) + .installed_interface(0) + .news_interface(this) + .sets_interface(this) + .syncable_interface(this) + .uninstallable_interface(0) + .use_interface(this) + .world_interface(0) + .environment_variable_interface(this) + .mirrors_interface(this) + .virtuals_interface(this) + .provides_interface(0)), + PrivateImplementationPattern<PortageRepository>(new Implementation<PortageRepository>(this, p)) +{ + // the info_vars and info_pkgs info is only added on demand, since it's + // fairly slow to calculate. + RepositoryInfoSection::Pointer config_info(new RepositoryInfoSection("Configuration information")); + + config_info->add_kv("location", stringify(_imp->params.location)); + config_info->add_kv("profiles", join(_imp->params.profiles->begin(), + _imp->params.profiles->end(), " ")); + config_info->add_kv("eclassdirs", join(_imp->params.eclassdirs->begin(), + _imp->params.eclassdirs->end(), " ")); + config_info->add_kv("cache", stringify(_imp->params.cache)); + config_info->add_kv("distdir", stringify(_imp->params.distdir)); + config_info->add_kv("pkgdir", stringify(_imp->params.pkgdir)); + config_info->add_kv("securitydir", stringify(_imp->params.securitydir)); + config_info->add_kv("setsdir", stringify(_imp->params.setsdir)); + config_info->add_kv("newsdir", stringify(_imp->params.newsdir)); + config_info->add_kv("format", "portage"); + config_info->add_kv("root", stringify(_imp->params.root)); + config_info->add_kv("buildroot", stringify(_imp->params.buildroot)); + config_info->add_kv("sync", _imp->params.sync); + config_info->add_kv("sync_exclude", _imp->params.sync_exclude); + + _info->add_section(config_info); +} + +PortageRepository::~PortageRepository() +{ +} + +bool +PortageRepository::do_has_category_named(const CategoryNamePart & c) const +{ + Context context("When checking for category '" + stringify(c) + + "' in " + stringify(name()) + ":"); + + need_category_names(); + return _imp->category_names.end() != + _imp->category_names.find(c); +} + +bool +PortageRepository::do_has_package_named(const QualifiedPackageName & q) const +{ + Context context("When checking for package '" + stringify(q) + "' in " + + stringify(name()) + ":"); + + need_category_names(); + + CategoryMap::iterator cat_iter(_imp->category_names.find(q.category)); + + if (_imp->category_names.end() == cat_iter) + return false; + + if (cat_iter->second) + return _imp->package_names.find(q) != + _imp->package_names.end(); + else + { + if (_imp->package_names.find(q) != + _imp->package_names.end()) + return true; + + FSEntry fs(_imp->params.location); + fs /= stringify(q.category); + fs /= stringify(q.package); + if (! fs.is_directory()) + return false; + _imp->package_names.insert(std::make_pair(q, false)); + return true; + } +} + +namespace +{ + /** + * Filter QualifiedPackageName instances by category. + * + * \ingroup grpportagerepository + */ + struct CategoryFilter : + std::unary_function<bool, QualifiedPackageName> + { + /// Our category. + CategoryNamePart category; + + /// Constructor. + CategoryFilter(const CategoryNamePart & c) : + category(c) + { + } + + /// Predicate. + bool operator() (const QualifiedPackageName & a) const + { + return a.category == category; + } + }; +} + +CategoryNamePartCollection::ConstPointer +PortageRepository::do_category_names() const +{ + Context context("When fetching category names in " + stringify(name()) + ":"); + + need_category_names(); + + CategoryNamePartCollection::Pointer result(new CategoryNamePartCollection::Concrete); + CategoryMap::const_iterator i(_imp->category_names.begin()), + i_end(_imp->category_names.end()); + for ( ; i != i_end ; ++i) + result->insert(i->first); + return result; +} + +QualifiedPackageNameCollection::ConstPointer +PortageRepository::do_package_names(const CategoryNamePart & c) const +{ + /* this isn't particularly fast because it isn't called very often. avoid + * changing the data structures used to make this faster at the expense of + * slowing down single item queries. */ + + Context context("When fetching package names in category '" + stringify(c) + + "' in " + stringify(name()) + ":"); + + need_category_names(); + + if (_imp->category_names.end() == _imp->category_names.find(c)) + return QualifiedPackageNameCollection::Pointer(new QualifiedPackageNameCollection::Concrete); + + if ((_imp->params.location / stringify(c)).is_directory()) + for (DirIterator d(_imp->params.location / stringify(c)), d_end ; d != d_end ; ++d) + { + if (! d->is_directory()) + continue; + if (DirIterator() == std::find_if(DirIterator(*d), DirIterator(), + IsFileWithExtension(_imp->entries_ptr->file_extension()))) + continue; + + try + { + _imp->package_names.insert(std::make_pair(c + PackageNamePart(d->basename()), false)); + } + catch (const NameError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Skipping entry '" + + d->basename() + "' in category '" + stringify(c) + "' in repository '" + + stringify(name()) + "' (" + e.message() + ")"); + } + } + + _imp->category_names[c] = true; + + QualifiedPackageNameCollection::Pointer result(new QualifiedPackageNameCollection::Concrete); + + std::copy(_imp->package_names.begin(), _imp->package_names.end(), + transform_inserter(filter_inserter(result->inserter(), CategoryFilter(c)), + SelectFirst<const QualifiedPackageName, bool>())); + + return result; +} + +VersionSpecCollection::ConstPointer +PortageRepository::do_version_specs(const QualifiedPackageName & n) const +{ + Context context("When fetching versions of '" + stringify(n) + "' in " + + stringify(name()) + ":"); + + if (has_package_named(n)) + { + need_version_names(n); + return _imp->version_specs.find(n)->second; + } + else + return VersionSpecCollection::Pointer(new VersionSpecCollection::Concrete); +} + +bool +PortageRepository::do_has_version(const QualifiedPackageName & q, + const VersionSpec & v) const +{ + Context context("When checking for version '" + stringify(v) + "' in '" + + stringify(q) + "' in " + stringify(name()) + ":"); + + if (has_package_named(q)) + { + need_version_names(q); + VersionSpecCollection::Pointer vv(_imp->version_specs.find(q)->second); + return vv->end() != vv->find(v); + } + else + return false; +} + +void +PortageRepository::need_category_names() const +{ + if (_imp->has_category_names) + return; + + Context context("When loading category names for " + stringify(name()) + ":"); + + if (! (_imp->params.location / "profiles" / "categories").exists()) + { + Log::get_instance()->message(ll_qa, lc_context, "No categories file for repository at '" + + stringify(_imp->params.location) + "', faking it"); + for (DirIterator d(_imp->params.location), d_end ; d != d_end ; ++d) + { + if (! d->is_directory()) + continue; + + std::string n(d->basename()); + if (n == "CVS" || n == "distfiles" || n == "scripts" || n == "eclass" || n == "licences" + || n == "packages") + continue; + + try + { + _imp->category_names.insert(std::make_pair(CategoryNamePart(n), false)); + } + catch (const NameError &) + { + } + } + } + else + { + LineConfigFile cats(_imp->params.location / "profiles" / "categories"); + + for (LineConfigFile::Iterator line(cats.begin()), line_end(cats.end()) ; + line != line_end ; ++line) + _imp->category_names.insert(std::make_pair(CategoryNamePart(*line), false)); + } + + _imp->has_category_names = true; +} + +void +PortageRepository::need_version_names(const QualifiedPackageName & n) const +{ + if (_imp->package_names[n]) + return; + + Context context("When loading versions for '" + stringify(n) + "' in " + + stringify(name()) + ":"); + + VersionSpecCollection::Pointer v(new VersionSpecCollection::Concrete); + + FSEntry path(_imp->params.location / stringify(n.category) / + stringify(n.package)); + + for (DirIterator e(path), e_end ; e != e_end ; ++e) + { + if (! IsFileWithExtension(stringify(n.package) + "-", + _imp->entries_ptr->file_extension())(*e)) + continue; + + try + { + v->insert(VersionSpec(strip_leading_string( + strip_trailing_string(e->basename(), _imp->entries_ptr->file_extension()), + stringify(n.package) + "-"))); + } + catch (const NameError &) + { + Log::get_instance()->message(ll_warning, lc_context, "Skipping entry '" + + stringify(*e) + "' for '" + stringify(n) + "' in repository '" + + stringify(name()) + "'"); + } + } + + _imp->version_specs.insert(std::make_pair(n, v)); + _imp->package_names[n] = true; +} + +RepositoryName +PortageRepository::fetch_repo_name(const std::string & location) +{ + try + { + do + { + FSEntry name_file(location); + name_file /= "profiles"; + name_file /= "repo_name"; + + if (! name_file.is_regular_file()) + break; + + LineConfigFile f(name_file); + if (f.begin() == f.end()) + break; + return RepositoryName(*f.begin()); + + } while (false); + } + catch (...) + { + } + Log::get_instance()->message(ll_qa, lc_no_context, "Couldn't open repo_name file in '" + + location + "/profiles/'. Falling back to a generated name."); + + std::string modified_location(FSEntry(location).basename()); + std::replace(modified_location.begin(), modified_location.end(), '/', '-'); + return RepositoryName("x-" + modified_location); +} + +VersionMetadata::ConstPointer +PortageRepository::do_version_metadata( + const QualifiedPackageName & q, const VersionSpec & v) const +{ + if (_imp->metadata.end() != _imp->metadata.find( + std::make_pair(q, v))) + return _imp->metadata.find(std::make_pair(q, v))->second; + + Context context("When fetching metadata for '" + stringify(q) + + "-" + stringify(v) + "':"); + + if (! has_version(q, v)) + throw NoSuchPackageError(stringify(PackageDatabaseEntry(q, v, name()))); + + VersionMetadata::Pointer result(_imp->entries_ptr->generate_version_metadata(q, v)); + _imp->metadata.insert(std::make_pair(std::make_pair(q, v), result)); + return result; +} + +bool +PortageRepository::do_query_repository_masks(const QualifiedPackageName & q, const VersionSpec & v) const +{ + if (! _imp->has_repo_mask) + { + Context context("When querying repository mask for '" + stringify(q) + "-" + + stringify(v) + "':"); + + FSEntry fff(_imp->params.location / "profiles" / "package.mask"); + if (fff.exists()) + { + LineConfigFile ff(fff); + for (LineConfigFile::Iterator line(ff.begin()), line_end(ff.end()) ; + line != line_end ; ++line) + { + PackageDepAtom::ConstPointer a(new PackageDepAtom(*line)); + _imp->repo_mask[a->package()].push_back(a); + } + } + + _imp->has_repo_mask = true; + } + + RepositoryMaskMap::iterator r(_imp->repo_mask.find(q)); + if (_imp->repo_mask.end() == r) + return false; + else + for (IndirectIterator<std::list<PackageDepAtom::ConstPointer>::const_iterator, const PackageDepAtom> + k(r->second.begin()), k_end(r->second.end()) ; k != k_end ; ++k) + if (match_package(_imp->params.environment, *k, PackageDatabaseEntry(q, v, name()))) + return true; + + return false; +} + +bool +PortageRepository::do_query_profile_masks(const QualifiedPackageName & n, + const VersionSpec & v) const +{ + _imp->need_profiles(); + return _imp->profile_ptr->profile_masked(n, v, name()); +} + +UseFlagState +PortageRepository::do_query_use(const UseFlagName & f, const PackageDatabaseEntry *) const +{ + _imp->need_profiles(); + return _imp->profile_ptr->use_state_ignoring_masks(f); +} + +bool +PortageRepository::do_query_use_mask(const UseFlagName & u, const PackageDatabaseEntry *e) const +{ + _imp->need_profiles(); + return _imp->profile_ptr->use_masked(u, e); +} + +bool +PortageRepository::do_query_use_force(const UseFlagName & u, const PackageDatabaseEntry *e) const +{ + _imp->need_profiles(); + return _imp->profile_ptr->use_forced(u, e); +} + +UseFlagNameCollection::ConstPointer +PortageRepository::do_arch_flags() const +{ + if (! _imp->arch_flags) + { + Context context("When loading arch list:"); + + LineConfigFile archs(_imp->params.location / "profiles" / "arch.list"); + _imp->arch_flags.assign(new UseFlagNameCollection::Concrete); + std::copy(archs.begin(), archs.end(), create_inserter<UseFlagName>(_imp->arch_flags->inserter())); + } + + return _imp->arch_flags; +} + +bool +PortageRepository::do_is_licence(const std::string & s) const +{ + FSEntry l(_imp->params.location); + l /= "licenses"; + + if (! l.is_directory()) + return false; + + l /= s; + return l.exists() && l.is_regular_file(); +} + +void +PortageRepository::need_mirrors() const +{ + if (! _imp->has_mirrors) + { + if ((_imp->params.location / "profiles" / "thirdpartymirrors").exists()) + { + LineConfigFile mirrors(_imp->params.location / "profiles" / "thirdpartymirrors"); + for (LineConfigFile::Iterator line(mirrors.begin()) ; line != mirrors.end() ; ++line) + { + std::vector<std::string> entries; + WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(entries)); + if (! entries.empty()) + { + /* pick up to five random mirrors only */ + static Random r; + std::random_shuffle(next(entries.begin()), entries.end(), r); + if (entries.size() > 6) + entries.resize(6); + for (std::vector<std::string>::const_iterator e(next(entries.begin())), + e_end(entries.end()) ; e != e_end ; ++e) + _imp->mirrors.insert(std::make_pair(entries.at(0), *e)); + } + } + } + else + Log::get_instance()->message(ll_warning, lc_no_context, + "No thirdpartymirrors file found in '" + + stringify(_imp->params.location / "profiles") + "', so mirror:// SRC_URI " + "components cannot be fetched"); + + _imp->has_mirrors = true; + } +} + +void +PortageRepository::do_install(const QualifiedPackageName & q, const VersionSpec & v, + const InstallOptions & o) const +{ + _imp->need_profiles(); + + if (! _imp->params.root.is_directory()) + throw PackageInstallActionError("Can't install '" + stringify(q) + "-" + + stringify(v) + "' since root ('" + stringify(_imp->params.root) + "') isn't a directory"); + + _imp->entries_ptr->install(q, v, o, _imp->profile_ptr); +} + +DepAtom::Pointer +PortageRepository::do_package_set(const std::string & s) const +{ + if (s == "system") + { + _imp->need_profiles(); + return _imp->profile_ptr->system_packages(); + } + + return _imp->sets_ptr->package_set(s); +} + +SetsCollection::ConstPointer +PortageRepository::sets_list() const +{ + return _imp->sets_ptr->sets_list(); +} + +bool +PortageRepository::do_sync() const +{ + Context context("When syncing repository '" + stringify(name()) + "':"); + + if (_imp->params.sync.empty()) + return false; + + std::string::size_type p(_imp->params.sync.find("://")), q(_imp->params.sync.find(":")); + if (std::string::npos == p) + throw NoSuchSyncerError(_imp->params.sync); + + SyncOptions opts(_imp->params.sync_exclude); + + SyncerMaker::get_instance()->find_maker(_imp->params.sync.substr(0, std::min(p, q)))( + stringify(_imp->params.location), + _imp->params.sync.substr(q < p ? q + 1 : 0))->sync(opts); + + return true; +} + +void +PortageRepository::invalidate() const +{ + _imp->invalidate(); +} + +void +PortageRepository::update_news() const +{ + _imp->news_ptr->update_news(); +} + +std::string +PortageRepository::get_environment_variable( + const PackageDatabaseEntry & for_package, + const std::string & var) const +{ + Context context("When fetching environment variable '" + var + "' from repository '" + + stringify(name()) + "':"); + + _imp->need_profiles(); + + return _imp->entries_ptr->get_environment_variable(for_package.name, + for_package.version, var, _imp->profile_ptr); +} + +RepositoryInfo::ConstPointer +PortageRepository::info(bool verbose) const +{ + RepositoryInfo::ConstPointer result_non_verbose(Repository::info(verbose)); + if (! verbose) + return result_non_verbose; + + RepositoryInfo::Pointer result(new RepositoryInfo); + + for (RepositoryInfo::SectionIterator s(result_non_verbose->begin_sections()), + s_end(result_non_verbose->end_sections()) ; s != s_end ; ++s) + result->add_section(*s); + + std::set<std::string> info_pkgs; + if ((_imp->params.location / "profiles" / "info_pkgs").exists()) + { + LineConfigFile vars(_imp->params.location / "profiles" / "info_pkgs"); + info_pkgs.insert(vars.begin(), vars.end()); + } + + if (! info_pkgs.empty()) + { + RepositoryInfoSection::Pointer package_info(new RepositoryInfoSection("Package information")); + for (std::set<std::string>::const_iterator i(info_pkgs.begin()), + i_end(info_pkgs.end()) ; i != i_end ; ++i) + { + PackageDatabaseEntryCollection::ConstPointer q( + _imp->params.environment->package_database()->query( + PackageDepAtom::ConstPointer(new PackageDepAtom(*i)), is_installed_only)); + if (q->empty()) + package_info->add_kv(*i, "(none)"); + else + { + std::set<VersionSpec> versions; + + /* don't use std::transform, it breaks g++4.1 */ + // std::transform(q->begin(), q->end(), std::inserter(versions, versions.end()), + // std::mem_fun_ref(&PackageDatabaseEntry::get<pde_version>)); + for (PackageDatabaseEntryCollection::Iterator qq(q->begin()), qq_end(q->end()) ; + qq != qq_end ; ++qq) + versions.insert(qq->version); + package_info->add_kv(*i, join(versions.begin(), versions.end(), ", ")); + } + } + + result->add_section(package_info); + } + + std::set<std::string> info_vars; + if ((_imp->params.location / "profiles" / "info_vars").exists()) + { + LineConfigFile vars(_imp->params.location / "profiles" / "info_vars"); + info_vars.insert(vars.begin(), vars.end()); + } + + if (! info_vars.empty() && ! info_pkgs.empty() && + ! version_specs(QualifiedPackageName(*info_pkgs.begin()))->empty()) + { + PackageDatabaseEntry e(QualifiedPackageName(*info_pkgs.begin()), + *version_specs(QualifiedPackageName(*info_pkgs.begin()))->last(), + name()); + RepositoryInfoSection::Pointer variable_info(new RepositoryInfoSection("Variable information")); + for (std::set<std::string>::const_iterator i(info_vars.begin()), + i_end(info_vars.end()) ; i != i_end ; ++i) + variable_info->add_kv(*i, get_environment_variable(e, *i)); + + result->add_section(variable_info); + } + else if (! info_vars.empty()) + Log::get_instance()->message(ll_warning, lc_no_context, + "Skipping info_vars for '" + stringify(name()) + + "' because info_pkgs is not usable"); + + return result; +} + +std::string +PortageRepository::profile_variable(const std::string & s) const +{ + _imp->need_profiles(); + + return _imp->profile_ptr->environment_variable(s); +} + +PortageRepository::MirrorsIterator +PortageRepository::begin_mirrors(const std::string & s) const +{ + need_mirrors(); + return MirrorsIterator(_imp->mirrors.equal_range(s).first); +} + +PortageRepository::MirrorsIterator +PortageRepository::end_mirrors(const std::string & s) const +{ + need_mirrors(); + return MirrorsIterator(_imp->mirrors.equal_range(s).second); +} + +PortageRepository::VirtualsCollection::ConstPointer +PortageRepository::virtual_packages() const +{ + Context context("When loading virtual packages for repository '" + + stringify(name()) + "'"); + + Log::get_instance()->message(ll_debug, lc_context, "Loading virtual packages for repository '" + + stringify(name()) + "'"); + + _imp->need_profiles(); + need_category_names(); + + VirtualsCollection::Pointer result(new VirtualsCollection::Concrete); + + for (PortageRepositoryProfile::VirtualsIterator i(_imp->profile_ptr->begin_virtuals()), + i_end(_imp->profile_ptr->end_virtuals()) ; i != i_end ; ++i) + result->insert(RepositoryVirtualsEntry::create() + .provided_by_atom(i->second) + .virtual_name(i->first)); + + Log::get_instance()->message(ll_debug, lc_context, "Loaded " + stringify(result->size()) + + " virtual packages for repository '" + stringify(name()) + "'"); + + return result; +} + +VersionMetadata::ConstPointer +PortageRepository::virtual_package_version_metadata(const RepositoryVirtualsEntry & p, + const VersionSpec & v) const +{ + VersionMetadata::ConstPointer m(version_metadata(p.provided_by_atom->package(), v)); + VersionMetadata::Virtual::Pointer result(new VersionMetadata::Virtual( + PortageDepParser::parse_depend, PackageDatabaseEntry( + p.provided_by_atom->package(), v, name()))); + + result->slot = m->slot; + result->license_string = m->license_string; + result->eapi = m->eapi; + result->deps = VersionMetadataDeps(&PortageDepParser::parse_depend, + "=" + stringify(p.provided_by_atom->package()) + "-" + stringify(v), + "=" + stringify(p.provided_by_atom->package()) + "-" + stringify(v), ""); + + return result; + +} + +UseFlagNameCollection::ConstPointer +PortageRepository::do_use_expand_flags() const +{ + _imp->need_profiles(); + + UseFlagNameCollection::Pointer result(new UseFlagNameCollection::Concrete); + for (PortageRepositoryProfile::UseExpandIterator i(_imp->profile_ptr->begin_use_expand()), + i_end(_imp->profile_ptr->end_use_expand()) ; i != i_end ; ++i) + { + std::list<std::string> values; + WhitespaceTokeniser::get_instance()->tokenise(_imp->profile_ptr->environment_variable( + stringify(*i)), std::back_inserter(values)); + for (std::list<std::string>::const_iterator j(values.begin()), j_end(values.end()) ; + j != j_end ; ++j) + { + std::string f(stringify(*i) + "_" + *j), lower_f; + std::transform(f.begin(), f.end(), std::back_inserter(lower_f), &::tolower); + result->insert(UseFlagName(lower_f)); + } + } + + return result; +} + +UseFlagNameCollection::ConstPointer +PortageRepository::do_use_expand_prefixes() const +{ + _imp->need_profiles(); + + UseFlagNameCollection::Pointer result(new UseFlagNameCollection::Concrete); + for (PortageRepositoryProfile::UseExpandIterator i(_imp->profile_ptr->begin_use_expand()), + i_end(_imp->profile_ptr->end_use_expand()) ; i != i_end ; ++i) + { + std::string lower_i; + std::transform(i->data().begin(), i->data().end(), std::back_inserter(lower_i), &::tolower); + result->insert(UseFlagName(lower_i)); + } + + return result; +} + +UseFlagNameCollection::ConstPointer +PortageRepository::do_use_expand_hidden_prefixes() const +{ + _imp->need_profiles(); + + UseFlagNameCollection::Pointer result(new UseFlagNameCollection::Concrete); + for (PortageRepositoryProfile::UseExpandIterator i(_imp->profile_ptr->begin_use_expand_hidden()), + i_end(_imp->profile_ptr->end_use_expand_hidden()) ; i != i_end ; ++i) + { + std::string lower_i; + std::transform(i->data().begin(), i->data().end(), std::back_inserter(lower_i), &::tolower); + result->insert(UseFlagName(lower_i)); + } + + return result; +} + +UseFlagName +PortageRepository::do_use_expand_name(const UseFlagName & u) const +{ + for (PortageRepositoryProfile::UseExpandIterator i(_imp->profile_ptr->begin_use_expand()), + i_end(_imp->profile_ptr->end_use_expand()) ; i != i_end ; ++i) + { + std::string lower_i; + std::transform(i->data().begin(), i->data().end(), std::back_inserter(lower_i), ::tolower); + if (0 == lower_i.compare(0, lower_i.length(), stringify(u), 0, lower_i.length())) + return *i; + } + + throw InternalError(PALUDIS_HERE, "Not a use expand name: '" + stringify(u) + "'"); +} + +UseFlagName +PortageRepository::do_use_expand_value(const UseFlagName & u) const +{ + for (PortageRepositoryProfile::UseExpandIterator i(_imp->profile_ptr->begin_use_expand()), + i_end(_imp->profile_ptr->end_use_expand()) ; i != i_end ; ++i) + { + std::string lower_i; + std::transform(i->data().begin(), i->data().end(), std::back_inserter(lower_i), ::tolower); + if (0 == lower_i.compare(0, lower_i.length(), stringify(u), 0, lower_i.length())) + return UseFlagName(stringify(u).substr(lower_i.length() + 1)); + } + + throw InternalError(PALUDIS_HERE, "Not a use expand name: '" + stringify(u) + "'"); +} + diff --git a/0.8.0/paludis/repositories/portage/portage_repository.hh b/0.8.0/paludis/repositories/portage/portage_repository.hh new file mode 100644 index 000000000..fc52d9ce4 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository.hh @@ -0,0 +1,166 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_PORTAGE_REPOSITORY_HH +#define PALUDIS_GUARD_PALUDIS_PORTAGE_REPOSITORY_HH 1 + +#include <paludis/repository.hh> +#include <paludis/util/fs_entry.hh> +#include <paludis/util/private_implementation_pattern.hh> +#include <paludis/repositories/portage/portage_repository_params.hh> +#include <string> + +/** \file + * Declaration for the PortageRepository class. + * + * \ingroup grpportagerepository + */ + +namespace paludis +{ + class PackageDatabase; + class PortageRepositoryProfile; + class PortageRepositoryNews; + + /** + * A PortageRepository is a Repository that handles the layout used by + * Portage for the main Gentoo tree. + * + * \ingroup grpportagerepository + */ + class PALUDIS_VISIBLE PortageRepository : + public Repository, + public RepositoryMaskInterface, + public RepositoryUseInterface, + public RepositoryInstallableInterface, + public RepositorySyncableInterface, + public RepositoryNewsInterface, + public RepositorySetsInterface, + public RepositoryEnvironmentVariableInterface, + public RepositoryMirrorsInterface, + public RepositoryVirtualsInterface, + private PrivateImplementationPattern<PortageRepository> + { + private: + void need_category_names() const; + void need_version_names(const QualifiedPackageName &) const; + void need_mirrors() const; + PackageDatabaseEntryCollection::Iterator find_best(PackageDatabaseEntryCollection & c, + const PackageDatabaseEntry & e) const; + + protected: + /** + * Try to get the repository name for a particular repository. + */ + static RepositoryName fetch_repo_name(const std::string & location); + + virtual bool do_has_category_named(const CategoryNamePart &) const; + + virtual bool do_has_package_named(const QualifiedPackageName &) const; + + virtual CategoryNamePartCollection::ConstPointer do_category_names() const; + + virtual QualifiedPackageNameCollection::ConstPointer do_package_names( + const CategoryNamePart &) const; + + virtual VersionSpecCollection::ConstPointer do_version_specs( + const QualifiedPackageName &) const; + + virtual bool do_has_version(const QualifiedPackageName &, const VersionSpec &) const; + + virtual VersionMetadata::ConstPointer do_version_metadata( + const QualifiedPackageName &, + const VersionSpec &) const; + + virtual bool do_query_repository_masks(const QualifiedPackageName &, + const VersionSpec &) const; + + virtual bool do_query_profile_masks(const QualifiedPackageName &, + const VersionSpec &) const; + + virtual bool do_is_licence(const std::string &) const; + + virtual void do_install(const QualifiedPackageName &, const VersionSpec &, + const InstallOptions &) const; + + virtual DepAtom::Pointer do_package_set(const std::string &) const; + + virtual SetsCollection::ConstPointer sets_list() const; + + virtual bool do_sync() const; + + virtual VirtualsCollection::ConstPointer virtual_packages() const; + + virtual VersionMetadata::ConstPointer virtual_package_version_metadata( + const RepositoryVirtualsEntry &, const VersionSpec & v) const; + + /* RepositoryUseInterface */ + + virtual UseFlagState do_query_use(const UseFlagName &, const PackageDatabaseEntry *) const; + virtual bool do_query_use_mask(const UseFlagName &, const PackageDatabaseEntry *) const; + virtual bool do_query_use_force(const UseFlagName &, const PackageDatabaseEntry *) const; + virtual UseFlagNameCollection::ConstPointer do_arch_flags() const; + virtual UseFlagNameCollection::ConstPointer do_use_expand_flags() const; + virtual UseFlagNameCollection::ConstPointer do_use_expand_hidden_prefixes() const; + virtual UseFlagName do_use_expand_name(const UseFlagName & u) const; + virtual UseFlagName do_use_expand_value(const UseFlagName & u) const; + virtual UseFlagNameCollection::ConstPointer do_use_expand_prefixes() const; + + /* end of RepositoryUseInterface */ + + public: + virtual RepositoryInfo::ConstPointer info(bool verbose) const; + + /** + * Constructor. + */ + PortageRepository(const PortageRepositoryParams &); + + /** + * Destructor. + */ + ~PortageRepository(); + + virtual void invalidate() const; + + virtual void update_news() const; + + virtual std::string get_environment_variable( + const PackageDatabaseEntry & for_package, + const std::string & var) const; + + virtual MirrorsIterator begin_mirrors(const std::string & s) const; + virtual MirrorsIterator end_mirrors(const std::string & s) const; + + typedef CountedPtr<PortageRepository, count_policy::InternalCountTag> Pointer; + typedef CountedPtr<const PortageRepository, count_policy::InternalCountTag> ConstPointer; + + ///\name Information about PortageRepository + ///\{ + + std::string profile_variable(const std::string &) const; + + typedef libwrapiter::ForwardIterator<PortageRepository, std::pair< + const QualifiedPackageName, PackageDepAtom::ConstPointer> > OurVirtualsIterator; + + ///\} + }; +} + +#endif diff --git a/0.8.0/paludis/repositories/portage/portage_repository_TEST.cc b/0.8.0/paludis/repositories/portage/portage_repository_TEST.cc new file mode 100644 index 000000000..1310d6e5a --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_TEST.cc @@ -0,0 +1,666 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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/portage/portage_repository.hh> +#include <paludis/repositories/portage/make_ebuild_repository.hh> +#include <paludis/util/collection_concrete.hh> +#include <paludis/environment/test/test_environment.hh> +#include <paludis/util/system.hh> +#include <test/test_framework.hh> +#include <test/test_runner.hh> + +using namespace test; +using namespace paludis; + +/** \file + * Test cases for PortageRepository. + * + * \ingroup grptestcases + */ + +namespace test_cases +{ + /** + * \test Test PortageRepository repository names. + * + * \ingroup grptestcases + */ + struct PortageRepositoryRepoNameTest : TestCase + { + PortageRepositoryRepoNameTest() : TestCase("repo name") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo1"); + keys->insert("profile", "portage_repository_TEST_dir/repo1/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + TEST_CHECK_STRINGIFY_EQUAL(repo->name(), "test-repo-1"); + } + } test_portage_repository_repo_name; + + /** + * \test Test PortageRepository repository with no names. + * + * \ingroup grptestcases + */ + struct PortageRepositoryNoRepoNameTest : TestCase + { + PortageRepositoryNoRepoNameTest() : TestCase("no repo name") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo2"); + keys->insert("profile", "portage_repository_TEST_dir/repo2/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + TEST_CHECK_STRINGIFY_EQUAL(repo->name(), "x-repo2"); + } + } test_portage_repository_no_repo_name; + + /** + * \test Test PortageRepository repository empty names. + * + * \ingroup grptestcases + */ + struct PortageRepositoryEmptyRepoNameTest : TestCase + { + PortageRepositoryEmptyRepoNameTest() : TestCase("empty repo name") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo3"); + keys->insert("profile", "portage_repository_TEST_dir/repo3/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + TEST_CHECK_STRINGIFY_EQUAL(repo->name(), "x-repo3"); + } + } test_portage_repository_empty_repo_name; + + /** + * \test Test PortageRepository repository has_category_named. + * + * \ingroup grptestcases + */ + struct PortageRepositoryHasCategoryNamedTest : TestCase + { + PortageRepositoryHasCategoryNamedTest() : TestCase("has category named") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo1"); + keys->insert("profile", "portage_repository_TEST_dir/repo1/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + + TEST_CHECK(repo->has_category_named(CategoryNamePart("cat-one"))); + TEST_CHECK(repo->has_category_named(CategoryNamePart("cat-two"))); + TEST_CHECK(repo->has_category_named(CategoryNamePart("cat-three"))); + TEST_CHECK(! repo->has_category_named(CategoryNamePart("cat-four"))); + } + } + } test_portage_repository_has_category_named; + + /** + * \test Test PortageRepository category_names. + * + * \ingroup grptestcases + */ + struct PortageRepositoryCategoryNamesTest : TestCase + { + PortageRepositoryCategoryNamesTest() : TestCase("category names") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo1"); + keys->insert("profile", "portage_repository_TEST_dir/repo1/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + + CategoryNamePartCollection::ConstPointer c(repo->category_names()); + TEST_CHECK(c->end() != c->find(CategoryNamePart("cat-one"))); + TEST_CHECK(c->end() != c->find(CategoryNamePart("cat-two"))); + TEST_CHECK(c->end() != c->find(CategoryNamePart("cat-three"))); + TEST_CHECK(c->end() == c->find(CategoryNamePart("cat-four"))); + TEST_CHECK_EQUAL(3, std::distance(c->begin(), c->end())); + } + } + } test_portage_repository_category_names; + + /** + * \test Test PortageRepository has_package_named. + * + * \ingroup grptestcases + */ + struct PortageRepositoryHasPackageNamedTest : TestCase + { + PortageRepositoryHasPackageNamedTest() : TestCase("has package named") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo4"); + keys->insert("profile", "portage_repository_TEST_dir/repo4/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + + TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-one/pkg-one"))); + TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-two/pkg-two"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-one/pkg-two"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-two/pkg-one"))); + TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-one/pkg-both"))); + TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-two/pkg-both"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-one/pkg-neither"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-two/pkg-neither"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-one"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-two"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-both"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-neither"))); + } + } + } test_portage_repository_has_package_named; + + /** + * \test Test PortageRepository has_package_named cached. + * + * \ingroup grptestcases + */ + struct PortageRepositoryHasPackageNamedCachedTest : TestCase + { + PortageRepositoryHasPackageNamedCachedTest() : TestCase("has package named cached") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo4"); + keys->insert("profile", "portage_repository_TEST_dir/repo4/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + repo->package_names(CategoryNamePart("cat-one")); + repo->package_names(CategoryNamePart("cat-two")); + repo->package_names(CategoryNamePart("cat-three")); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + + TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-one/pkg-one"))); + TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-two/pkg-two"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-one/pkg-two"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-two/pkg-one"))); + TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-one/pkg-both"))); + TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-two/pkg-both"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-one/pkg-neither"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-two/pkg-neither"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-one"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-two"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-both"))); + TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-neither"))); + } + } + } test_portage_repository_has_package_named_cached; + + /** + * \test Test PortageRepository package_names. + * + * \ingroup grptestcases + */ + struct PortageRepositoryPackageNamesTest : TestCase + { + PortageRepositoryPackageNamesTest() : TestCase("package names") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo4"); + keys->insert("profile", "portage_repository_TEST_dir/repo4/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + QualifiedPackageNameCollection::ConstPointer names(0); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + + names = repo->package_names(CategoryNamePart("cat-one")); + TEST_CHECK(! names->empty()); + TEST_CHECK(names->end() != names->find(QualifiedPackageName("cat-one/pkg-one"))); + TEST_CHECK(names->end() != names->find(QualifiedPackageName("cat-one/pkg-both"))); + TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-one/pkg-two"))); + TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-one/pkg-neither"))); + TEST_CHECK_EQUAL(2, std::distance(names->begin(), names->end())); + + names = repo->package_names(CategoryNamePart("cat-two")); + TEST_CHECK(! names->empty()); + TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-two/pkg-one"))); + TEST_CHECK(names->end() != names->find(QualifiedPackageName("cat-two/pkg-both"))); + TEST_CHECK(names->end() != names->find(QualifiedPackageName("cat-two/pkg-two"))); + TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-two/pkg-neither"))); + TEST_CHECK_EQUAL(2, std::distance(names->begin(), names->end())); + + names = repo->package_names(CategoryNamePart("cat-three")); + TEST_CHECK(names->empty()); + TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-three/pkg-one"))); + TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-three/pkg-both"))); + TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-three/pkg-two"))); + TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-three/pkg-neither"))); + TEST_CHECK_EQUAL(0, std::distance(names->begin(), names->end())); + } + } + } test_portage_repository_package_names; + + /** + * \test Test PortageRepository bad package names. + * + * \ingroup grptestcases + */ + struct PortageRepositoryBadPackageNamesTest : TestCase + { + PortageRepositoryBadPackageNamesTest() : TestCase("bad package names") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo5"); + keys->insert("profile", "portage_repository_TEST_dir/repo5/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + QualifiedPackageNameCollection::ConstPointer names(0); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + + names = repo->package_names(CategoryNamePart("cat-one")); + TEST_CHECK(! names->empty()); + TEST_CHECK(names->end() != names->find(QualifiedPackageName("cat-one/pkg-one"))); + TEST_CHECK_EQUAL(1, std::distance(names->begin(), names->end())); + } + } + } test_portage_repository_bad_package_names; + + /** + * \test Test PortageRepository has_version. + * + * \ingroup grptestcases + */ + struct PortageRepositoryHasVersionTest : TestCase + { + PortageRepositoryHasVersionTest() : TestCase("has version") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo4"); + keys->insert("profile", "portage_repository_TEST_dir/repo4/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + + TEST_CHECK(repo->has_version(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("1"))); + TEST_CHECK(repo->has_version(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("1.1-r1"))); + TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("2"))); + + TEST_CHECK(repo->has_version(QualifiedPackageName("cat-one/pkg-both"), VersionSpec("3.45"))); + TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-one/pkg-both"), VersionSpec("1"))); + TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-one/pkg-both"), VersionSpec("1.23"))); + + TEST_CHECK(repo->has_version(QualifiedPackageName("cat-two/pkg-two"), VersionSpec("2"))); + TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-two/pkg-two"), VersionSpec("1"))); + + TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-two/pkg-both"), VersionSpec("3.45"))); + TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-two/pkg-both"), VersionSpec("1"))); + TEST_CHECK(repo->has_version(QualifiedPackageName("cat-two/pkg-both"), VersionSpec("1.23"))); + + TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-two/pkg-neither"), VersionSpec("1"))); + } + } + } test_portage_repository_has_version; + + /** + * \test Test PortageRepository versions. + * + * \ingroup grptestcases + */ + struct PortageRepositoryVersionsTest : TestCase + { + PortageRepositoryVersionsTest() : TestCase("versions") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo4"); + keys->insert("profile", "portage_repository_TEST_dir/repo4/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + + VersionSpecCollection::ConstPointer versions(0); + + versions = repo->version_specs(QualifiedPackageName("cat-one/pkg-one")); + TEST_CHECK(! versions->empty()); + TEST_CHECK_EQUAL(2, std::distance(versions->begin(), versions->end())); + TEST_CHECK(versions->end() != versions->find(VersionSpec("1"))); + TEST_CHECK(versions->end() != versions->find(VersionSpec("1.1-r1"))); + TEST_CHECK(versions->end() == versions->find(VersionSpec("2"))); + + versions = repo->version_specs(QualifiedPackageName("cat-one/pkg-neither")); + TEST_CHECK(versions->empty()); + TEST_CHECK_EQUAL(0, std::distance(versions->begin(), versions->end())); + TEST_CHECK(versions->end() == versions->find(VersionSpec("1"))); + TEST_CHECK(versions->end() == versions->find(VersionSpec("1.1-r1"))); + TEST_CHECK(versions->end() == versions->find(VersionSpec("2"))); + } + } + } test_portage_repository_versions; + + /** + * \test Test PortageRepository duff versions. + * + * \ingroup grptestcases + */ + struct PortageRepositoryDuffVersionsTest : TestCase + { + PortageRepositoryDuffVersionsTest() : TestCase("duff versions") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo8"); + keys->insert("profile", "portage_repository_TEST_dir/repo8/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + + VersionSpecCollection::ConstPointer versions(0); + + versions = repo->version_specs(QualifiedPackageName("cat-one/pkg-one")); + TEST_CHECK(! versions->empty()); + TEST_CHECK_EQUAL(2, std::distance(versions->begin(), versions->end())); + TEST_CHECK(versions->end() != versions->find(VersionSpec("1"))); + TEST_CHECK(versions->end() != versions->find(VersionSpec("1.1-r1"))); + TEST_CHECK(versions->end() == versions->find(VersionSpec("2"))); + + versions = repo->version_specs(QualifiedPackageName("cat-one/pkg-neither")); + TEST_CHECK(versions->empty()); + TEST_CHECK_EQUAL(0, std::distance(versions->begin(), versions->end())); + TEST_CHECK(versions->end() == versions->find(VersionSpec("1"))); + TEST_CHECK(versions->end() == versions->find(VersionSpec("1.1-r1"))); + TEST_CHECK(versions->end() == versions->find(VersionSpec("2"))); + } + } + } test_portage_repository_duff_versions; + + /** + * \test Test PortageRepository cached metadata. + * + * \ingroup grptestcases + */ + struct PortageRepositoryMetadataCachedTest : TestCase + { + PortageRepositoryMetadataCachedTest() : TestCase("metadata cached") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo6"); + keys->insert("profile", "portage_repository_TEST_dir/repo6/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + VersionMetadata::ConstPointer m(0); + + m = repo->version_metadata(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("1")); + TEST_CHECK_EQUAL(m->description, "the-description"); + + TEST_CHECK_THROWS(repo->version_metadata(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("2")), + NoSuchPackageError); + TEST_CHECK_THROWS(repo->version_metadata(QualifiedPackageName("cat-two/pkg-one"), VersionSpec("1")), + NoSuchPackageError); + } + } + } test_portage_repository_metadata_cached; + + /** + * \test Test PortageRepository uncached metadata. + * + * \ingroup grptestcases + */ + struct PortageRepositoryMetadataUncachedTest : TestCase + { + PortageRepositoryMetadataUncachedTest() : TestCase("metadata uncached") { } + + bool skip() const + { + return ! getenv_with_default("SANDBOX_ON", "").empty(); + } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo7"); + keys->insert("profile", "portage_repository_TEST_dir/repo7/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + VersionMetadata::ConstPointer m(0); + + m = repo->version_metadata(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("1")); + TEST_CHECK_EQUAL(m->description, "The Description"); + TEST_CHECK_EQUAL(m->eapi, "0"); + } + } + } test_portage_repository_metadata_uncached; + + /** + * \test Test PortageRepository unparsable metadata. + * + * \ingroup grptestcases + */ + struct PortageRepositoryMetadataUnparsableTest : TestCase + { + PortageRepositoryMetadataUnparsableTest() : TestCase("metadata unparsable") { } + + bool skip() const + { + return ! getenv_with_default("SANDBOX_ON", "").empty(); + } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo7"); + keys->insert("profile", "portage_repository_TEST_dir/repo7/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + VersionMetadata::ConstPointer m(0); + + m = repo->version_metadata(QualifiedPackageName("cat-one/pkg-two"), VersionSpec("1")); + TEST_CHECK_EQUAL(m->eapi, "UNKNOWN"); + } + } + } test_portage_repository_metadata_unparsable; + + /** + * \test Test PortageRepository query_use and query_use_mask functions. + * + * \ingroup grptestcases + */ + struct PortageRepositoryQueryUseTest : TestCase + { + PortageRepositoryQueryUseTest() : TestCase("USE query") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo9"); + keys->insert("profile", "portage_repository_TEST_dir/repo9/profiles/profile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + + PackageDatabaseEntry p1(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("1"), + RepositoryName("test-repo-9")); + PackageDatabaseEntry p2(QualifiedPackageName("cat-two/pkg-two"), VersionSpec("1"), + RepositoryName("test-repo-9")); + PackageDatabaseEntry p3(QualifiedPackageName("cat-one/pkg-none"), VersionSpec("1"), + RepositoryName("test-repo-9")); + PackageDatabaseEntry p4(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("2"), + RepositoryName("test-repo-9")); + + TEST_CHECK(repo->query_use(UseFlagName("flag1"), &p1) == use_enabled); + TEST_CHECK(repo->query_use(UseFlagName("flag2"), &p1) == use_disabled); + TEST_CHECK(repo->query_use_mask(UseFlagName("flag2"), &p1)); + TEST_CHECK(repo->query_use_mask(UseFlagName("flag2"), &p3)); + TEST_CHECK(repo->query_use_mask(UseFlagName("flag3"), &p2)); + TEST_CHECK(! repo->query_use_mask(UseFlagName("flag3"), &p1)); + TEST_CHECK(repo->query_use_mask(UseFlagName("flag3"), &p4)); + TEST_CHECK(repo->query_use(UseFlagName("flag3"), &p1) == use_enabled); + TEST_CHECK(repo->query_use(UseFlagName("flag4"), &p3) == use_enabled); + TEST_CHECK(repo->query_use(UseFlagName("flag5"), &p2) == use_enabled); + TEST_CHECK(repo->query_use(UseFlagName("flag5"), &p1) == use_disabled); + } + } + } test_portage_repository_query_use; + + /** + * \test Test PortageRepository query_profile_masks functions. + * + * \ingroup grptestcases + */ + struct PortageRepositoryQueryProfileMasksTest : TestCase + { + PortageRepositoryQueryProfileMasksTest() : TestCase("profiles package.mask") { } + + void run() + { + TestEnvironment env; + AssociativeCollection<std::string, std::string>::Pointer keys( + new AssociativeCollection<std::string, std::string>::Concrete); + keys->insert("format", "portage"); + keys->insert("location", "portage_repository_TEST_dir/repo10"); + keys->insert("profiles", "portage_repository_TEST_dir/repo10/profiles/profile/subprofile"); + PortageRepository::Pointer repo(make_ebuild_repository( + &env, env.package_database().raw_pointer(), keys)); + + for (int pass = 1 ; pass <= 2 ; ++pass) + { + TestMessageSuffix pass_suffix(stringify(pass), true); + + TEST_CHECK(repo->query_profile_masks(QualifiedPackageName("cat/masked"), + VersionSpec("0"))); + TEST_CHECK(! repo->query_profile_masks(QualifiedPackageName("cat/not_masked"), + VersionSpec("0"))); + TEST_CHECK(! repo->query_profile_masks(QualifiedPackageName("cat/was_masked"), + VersionSpec("0"))); + } + } + } test_portage_repository_query_profile_masks; +} + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_TEST_cleanup.sh b/0.8.0/paludis/repositories/portage/portage_repository_TEST_cleanup.sh new file mode 100755 index 000000000..8c0b2902d --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_TEST_cleanup.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# vim: set ft=sh sw=4 sts=4 et : + +if [ -d portage_repository_TEST_dir ] ; then + rm -fr portage_repository_TEST_dir +else + true +fi + + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_TEST_setup.sh b/0.8.0/paludis/repositories/portage/portage_repository_TEST_setup.sh new file mode 100755 index 000000000..5fc9373ba --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_TEST_setup.sh @@ -0,0 +1,226 @@ +#!/bin/bash +# vim: set ft=sh sw=4 sts=4 et : + +mkdir portage_repository_TEST_dir || exit 1 +cd portage_repository_TEST_dir || exit 1 + +mkdir -p repo1/{eclass,distfiles,profiles/profile} || exit 1 +cd repo1 || exit 1 +echo "test-repo-1" > profiles/repo_name || exit 1 +cat <<END > profiles/categories || exit 1 +cat-one +cat-two +cat-three +END +cat <<END > profiles/profile/make.defaults +ARCH=test +END +cd .. + +mkdir -p repo2/{eclass,distfiles,profiles/profile} || exit 1 +cd repo2 || exit 1 +cat <<END > profiles/categories || exit 1 +END +cat <<END > profiles/profile/make.defaults +ARCH=test +END +cd .. + + +mkdir -p repo3/{eclass,distfiles,profiles/profile} || exit 1 +cd repo3 || exit 1 +echo "# test-repo-3" > profiles/repo_name || exit 1 +cat <<END > profiles/categories || exit 1 +END +cat <<END > profiles/profile/make.defaults +ARCH=test +END +cd .. + + +mkdir -p repo4/{eclass,distfiles,profiles/profile} || exit 1 +mkdir -p repo4/{cat-one/{pkg-one,pkg-both},cat-two/{pkg-two,pkg-both}} || exit 1 +cd repo4 || exit 1 +echo "test-repo-4" > profiles/repo_name || exit 1 +cat <<END > profiles/categories || exit 1 +cat-one +cat-two +END +cat <<END > profiles/profile/make.defaults +ARCH=test +END +cat <<END > cat-one/pkg-one/pkg-one-1.ebuild || exit 1 +END +cat <<END > cat-one/pkg-one/pkg-one-1.1-r1.ebuild || exit 1 +END +cat <<END > cat-one/pkg-both/pkg-both-3.45.ebuild || exit 1 +END +cat <<END > cat-two/pkg-two/pkg-two-2.ebuild || exit 1 +END +cat <<END > cat-two/pkg-both/pkg-both-1.23.ebuild || exit 1 +END +cd .. + + +mkdir -p repo5/{eclass,distfiles,profiles/profile} || exit 1 +mkdir -p repo5/cat-one/{pkg-one,pkg-1,pkg.one} || exit 1 +cd repo5 || exit 1 +echo "test-repo-5" > profiles/repo_name || exit 1 +cat <<END > profiles/categories || exit 1 +cat-one +END +cat <<END > profiles/profile/make.defaults +ARCH=test +END +cat <<END > cat-one/pkg-one/pkg-one-1.ebuild || exit 1 +END +cat <<END > cat-one/pkg-1/pkg-1-1.ebuild || exit 1 +END +cat <<END > cat-one/pkg.one/pkg.one-1.ebuild || exit 1 +END +cd .. + + +mkdir -p repo6/{eclass,distfiles,profiles/profile} || exit 1 +mkdir -p repo6/cat-one/pkg-one || exit 1 +mkdir -p repo6/metadata/cache/cat-one +cd repo6 || exit 1 +echo "test-repo-6" > profiles/repo_name || exit 1 +cat <<END > profiles/categories || exit 1 +cat-one +END +cat <<END > profiles/profile/make.defaults +ARCH=test +END +cat <<END > cat-one/pkg-one/pkg-one-1.ebuild || exit 1 +END +cat <<END > metadata/cache/cat-one/pkg-one-1 +the/depend +the/rdepend +the-slot +the-src-uri +the-restrict +the-homepage +the-license +the-description +the-keywords + +the-iuse +unused +the/pdepend +the/provide +0 +END +cd .. + + +mkdir -p repo7/{eclass,distfiles,profiles/profile} || exit 1 +mkdir -p repo7/cat-one/pkg-{one,two} || exit 1 +mkdir -p repo7/metadata/cache/cat-{one,two} +cd repo7 || exit 1 +echo "test-repo-7" > profiles/repo_name || exit 1 +cat <<END > profiles/categories || exit 1 +cat-one +END +cat <<END > profiles/profile/make.defaults +ARCH=test +END +cat <<END > cat-one/pkg-one/pkg-one-1.ebuild || exit 1 +DESCRIPTION="The Description" +HOMEPAGE="http://example.com/" +SRC_URI="" +SLOT="0" +IUSE="" +LICENSE="GPL-2" +KEYWORDS="test" +END +cat <<END > cat-one/pkg-two/pkg-two-1.ebuild || exit 1 +i am a fish +END +cd .. + + +mkdir -p repo8/{eclass,distfiles,profiles/profile} || exit 1 +mkdir -p repo8/{cat-one/{pkg-one,pkg-both},cat-two/{pkg-two,pkg-both}} || exit 1 +cd repo8 || exit 1 +echo "test-repo-8" > profiles/repo_name || exit 1 +cat <<END > profiles/categories || exit 1 +cat-one +cat-two +END +cat <<END > profiles/profile/make.defaults +ARCH=test +END +cat <<END > cat-one/pkg-one/pkg-one-1.ebuild || exit 1 +END +cat <<END > cat-one/pkg-one/pkg-one-1-monkey.ebuild || exit 1 +END +cat <<END > cat-one/pkg-one/pkg-one-1.1-r1.ebuild || exit 1 +END +cat <<END > cat-one/pkg-both/pkg-both-3.45.ebuild || exit 1 +END +cat <<END > cat-one/pkg-both/pkg-both-3.45_r1.ebuild || exit 1 +END +cat <<END > cat-two/pkg-two/pkg-two-2.ebuild || exit 1 +END +cat <<END > cat-two/pkg-both/pkg-both-1.23.ebuild || exit 1 +END +cat <<END > cat-two/pkg-both/pkg-both-.ebuild || exit 1 +END +cd .. + + +mkdir -p repo9/{eclass,distfiles,profiles/profile} || exit 1 +mkdir -p repo9/{cat-one/pkg-one,cat-two/pkg-two} || exit 1 +cd repo9 || exit 1 +echo "test-repo-9" > profiles/repo_name || exit 1 +cat <<END >profiles/categories || exit 1 +cat-one +cat-two +END +cat <<END >profiles/profile/make.defaults || exit 1 +ARCH=test +USE="flag1 flag2 flag3 -flag4 -flag5" +END +cat <<END >profiles/profile/use.mask || exit 1 +flag2 +END +cat <<END >profiles/profile/use.force || exit 1 +flag4 +END +cat <<END >profiles/profile/package.use.mask || exit 1 +cat-two/pkg-two flag3 +>=cat-one/pkg-one-2 flag3 +END +cat <<END >profiles/profile/package.use.force || exit 1 +cat-two/pkg-two flag5 +END +cat <<END > cat-one/pkg-one/pkg-one-1.ebuild || exit 1 +END +cat <<END > cat-one/pkg-one/pkg-one-2.ebuild || exit 1 +cat <<END > cat-two/pkg-two/pkg-two-1.ebuild || exit 1 +END +cd .. + +mkdir -p repo10/{eclass,distfiles,profiles/profile/subprofile} || exit 1 +cd repo10 || exit 1 +echo "test-repo-10" > profiles/repo_name || exit 1 +cat <<END >profiles/profile/make.defaults || exit 1 +ARCH=test +USE="flag1 flag2 flag3 -flag4 -flag5" +END +cat <<END >profiles/categories || exit 1 +cat +END +cat <<END >profiles/profile/package.mask +cat/masked +cat/was_masked +END +cat <<END >profiles/profile/subprofile/package.mask +-cat/was_masked +END +cat <<END >profiles/profile/subprofile/parent +.. +END +cd .. + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_ebin_entries.cc b/0.8.0/paludis/repositories/portage/portage_repository_ebin_entries.cc new file mode 100644 index 000000000..de948c691 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_ebin_entries.cc @@ -0,0 +1,379 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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/portage/portage_repository_ebin_entries.hh> +#include <paludis/repositories/portage/portage_repository.hh> + +#include <paludis/config_file.hh> +#include <paludis/dep_atom_flattener.hh> +#include <paludis/ebin.hh> +#include <paludis/environment.hh> +#include <paludis/portage_dep_parser.hh> +#include <paludis/version_metadata.hh> +#include <paludis/util/collection_concrete.hh> +#include <paludis/util/fs_entry.hh> +#include <paludis/util/log.hh> +#include <paludis/util/strip.hh> +#include <paludis/util/tokeniser.hh> + +#include <fstream> +#include <list> +#include <set> + +using namespace paludis; + +namespace paludis +{ + /** + * Implementation data for PortageRepositoryEbinEntries. + * + * \ingroup grpportagerepository + */ + template<> + struct Implementation<PortageRepositoryEbinEntries> : + InternalCounted<Implementation<PortageRepositoryEbinEntries> > + { + const Environment * const environment; + PortageRepository * const portage_repository; + const PortageRepositoryParams params; + + Implementation(const Environment * const e, PortageRepository * const p, + const PortageRepositoryParams & k) : + environment(e), + portage_repository(p), + params(k) + { + } + }; +} + +PortageRepositoryEbinEntries::PortageRepositoryEbinEntries( + const Environment * const e, PortageRepository * const p, const PortageRepositoryParams & k) : + PortageRepositoryEntries(".ebin"), + PrivateImplementationPattern<PortageRepositoryEbinEntries>(new + Implementation<PortageRepositoryEbinEntries>(e, p, k)) +{ +} + +PortageRepositoryEbinEntries::~PortageRepositoryEbinEntries() +{ +} + +VersionMetadata::Pointer +PortageRepositoryEbinEntries::generate_version_metadata(const QualifiedPackageName & q, + const VersionSpec & v) const +{ + VersionMetadata::Pointer result(new VersionMetadata::Ebin(PortageDepParser::parse_depend)); + + FSEntry ebin_file(_imp->params.location); + ebin_file /= stringify(q.category); + ebin_file /= stringify(q.package); + ebin_file /= (stringify(q.package) + "-" + stringify(v) + ".ebin"); + + if (ebin_file.is_regular_file()) + { + KeyValueConfigFile f(ebin_file); + result->deps.build_depend_string = f.get("depend"); + result->deps.run_depend_string = f.get("rdepend"); + result->deps.post_depend_string = f.get("pdepend"); + result->slot = SlotName(f.get("slot")); + result->license_string = f.get("license"); + result->eapi = f.get("eapi"); + result->homepage = f.get("homepage"); + result->description = f.get("description"); + result->get_ebuild_interface()->provide_string = f.get("provide"); + result->get_ebuild_interface()->restrict_string = f.get("restrict"); + result->get_ebuild_interface()->keywords = f.get("keywords"); + result->get_ebuild_interface()->iuse = f.get("iuse"); + result->get_ebuild_interface()->inherited = f.get("inherited"); + result->get_ebin_interface()->bin_uri = f.get("bin_uri"); + result->get_ebin_interface()->src_repository = RepositoryName(f.get("src_repository")); + } + else + throw NoSuchPackageError(stringify(PackageDatabaseEntry(q, v, _imp->portage_repository->name()))); + + return result; + +} + +void +PortageRepositoryEbinEntries::install(const QualifiedPackageName & q, const VersionSpec & v, + const InstallOptions & o, PortageRepositoryProfile::ConstPointer p) const +{ + VersionMetadata::ConstPointer metadata(_imp->portage_repository->version_metadata(q, v)); + + if (! _imp->portage_repository->has_version(q, v)) + throw PackageInstallActionError("Can't install '" + stringify(q) + "-" + + stringify(v) + "' since has_version failed"); + + PackageDatabaseEntry e(q, v, _imp->portage_repository->name()); + + std::string binaries, flat_bin_uri; + { + std::set<std::string> already_in_binaries; + + /* make B */ + DepAtom::ConstPointer f_atom(PortageDepParser::parse(metadata->get_ebin_interface()->bin_uri, + PortageDepParserPolicy<PlainTextDepAtom, false>::get_instance())); + DepAtomFlattener f(_imp->params.environment, &e, f_atom); + + for (DepAtomFlattener::Iterator ff(f.begin()), ff_end(f.end()) ; ff != ff_end ; ++ff) + { + std::string::size_type pos((*ff)->text().rfind('/')); + if (std::string::npos == pos) + { + if (already_in_binaries.end() == already_in_binaries.find((*ff)->text())) + { + binaries.append((*ff)->text()); + already_in_binaries.insert((*ff)->text()); + } + } + else + { + if (already_in_binaries.end() == already_in_binaries.find((*ff)->text().substr(pos + 1))) + { + binaries.append((*ff)->text().substr(pos + 1)); + already_in_binaries.insert((*ff)->text().substr(pos + 1)); + } + } + binaries.append(" "); + + /* add * mirror entries */ + for (Environment::MirrorIterator + m(_imp->params.environment->begin_mirrors("*")), + m_end(_imp->params.environment->end_mirrors("*")) ; + m != m_end ; ++m) + flat_bin_uri.append(m->second + "/" + (*ff)->text().substr(pos + 1) + " "); + + if (0 == (*ff)->text().compare(0, 9, "mirror://")) + { + std::string mirror((*ff)->text().substr(9)); + std::string::size_type s_pos(mirror.find('/')); + + if (std::string::npos == s_pos) + throw PackageInstallActionError("Can't install '" + stringify(q) + "-" + + stringify(v) + "' since SRC_URI is broken"); + + if (! _imp->portage_repository->is_mirror(mirror.substr(0, s_pos))) + throw PackageInstallActionError("Can't install '" + stringify(s_pos) + "-" + + stringify(v) + "' since SRC_URI references unknown mirror:// '" + + mirror.substr(0, s_pos) + "'"); + + for (Environment::MirrorIterator + m(_imp->params.environment->begin_mirrors(mirror.substr(0, s_pos))), + m_end(_imp->params.environment->end_mirrors(mirror.substr(0, s_pos))) ; + m != m_end ; ++m) + flat_bin_uri.append(m->second + "/" + mirror.substr(s_pos + 1) + " "); + + for (RepositoryMirrorsInterface::MirrorsIterator + m(_imp->portage_repository->begin_mirrors(mirror.substr(0, s_pos))), + m_end(_imp->portage_repository->end_mirrors(mirror.substr(0, s_pos))) ; + m != m_end ; ++m) + flat_bin_uri.append(m->second + "/" + mirror.substr(s_pos + 1) + " "); + } + else + flat_bin_uri.append((*ff)->text()); + flat_bin_uri.append(" "); + + /* add mirror://gentoo/ entries */ + std::string master_mirror(strip_trailing_string(stringify(_imp->portage_repository->name()), "x-")); + if (_imp->portage_repository->is_mirror(master_mirror)) + { + for (Environment::MirrorIterator + m(_imp->params.environment->begin_mirrors(master_mirror)), + m_end(_imp->params.environment->end_mirrors(master_mirror)) ; + m != m_end ; ++m) + flat_bin_uri.append(m->second + "/" + (*ff)->text().substr(pos + 1) + " "); + + for (RepositoryMirrorsInterface::MirrorsIterator + m(_imp->portage_repository->begin_mirrors(master_mirror)), + m_end(_imp->portage_repository->end_mirrors(master_mirror)) ; + m != m_end ; ++m) + flat_bin_uri.append(m->second + "/" + (*ff)->text().substr(pos + 1) + " "); + } + } + } + + std::string use; + { + std::set<UseFlagName> iuse; + WhitespaceTokeniser::get_instance()->tokenise(metadata->get_ebuild_interface()-> + iuse, create_inserter<UseFlagName>(std::inserter(iuse, iuse.begin()))); + for (std::set<UseFlagName>::const_iterator iuse_it(iuse.begin()), iuse_end(iuse.end()) ; + iuse_it != iuse_end; ++iuse_it) + if (_imp->params.environment->query_use(*iuse_it, &e)) + use += (*iuse_it).data() + " "; + } + + use += p->environment_variable("ARCH") + " "; + + /* add expand to use (iuse isn't reliable for use_expand things), and make the expand + * environment variables */ + AssociativeCollection<std::string, std::string>::Pointer expand_vars( + new AssociativeCollection<std::string, std::string>::Concrete); + for (PortageRepositoryProfile::UseExpandIterator x(p->begin_use_expand()), + x_end(p->end_use_expand()) ; x != x_end ; ++x) + { + std::string lower_x; + std::transform(x->data().begin(), x->data().end(), std::back_inserter(lower_x), &::tolower); + + /* possible values from profile */ + std::set<UseFlagName> possible_values; + WhitespaceTokeniser::get_instance()->tokenise(p->environment_variable(stringify(*x)), + create_inserter<UseFlagName>(std::inserter(possible_values, possible_values.end()))); + + /* possible values from environment */ + UseFlagNameCollection::ConstPointer possible_values_from_env(_imp->params.environment-> + known_use_expand_names(*x, &e)); + std::copy(possible_values_from_env->begin(), possible_values_from_env->end(), + std::inserter(possible_values, possible_values.end())); + + for (std::set<UseFlagName>::const_iterator u(possible_values.begin()), u_end(possible_values.end()) ; + u != u_end ; ++u) + { + if (! _imp->params.environment->query_use(UseFlagName(lower_x + "_" + stringify(*u)), &e)) + continue; + + use.append(lower_x + "_" + stringify(*u) + " "); + + std::string value; + AssociativeCollection<std::string, std::string>::Iterator i(expand_vars->find(stringify(*x))); + if (expand_vars->end() != i) + { + value = i->second + " "; + expand_vars->erase(i); + } + value.append(stringify(*u)); + expand_vars->insert(stringify(*x), value); + } + } + + binaries = strip_trailing(binaries, " "); + + EbinFetchCommand fetch_cmd(EbinCommandParams::create() + .environment(_imp->params.environment) + .db_entry(&e) + .src_repository(metadata->get_ebin_interface()->src_repository) + .ebin_dir(_imp->params.location / stringify(q.category) / + stringify(q.package)) + .pkgdir(_imp->params.pkgdir) + .buildroot(_imp->params.buildroot), + + EbinFetchCommandParams::create() + .b(binaries) + .flat_bin_uri(flat_bin_uri) + .root(stringify(_imp->params.root) + "/") + .profiles(_imp->params.profiles)); + + fetch_cmd(); + + if (o.fetch_only) + return; + + EbinInstallCommand install_cmd(EbinCommandParams::create() + .environment(_imp->params.environment) + .db_entry(&e) + .src_repository(metadata->get_ebin_interface()->src_repository) + .ebin_dir(_imp->params.location / stringify(q.category) / + stringify(q.package)) + .pkgdir(_imp->params.pkgdir) + .buildroot(_imp->params.buildroot), + + EbinInstallCommandParams::create() + .b(binaries) + .use(use) + .use_expand(join( + p->begin_use_expand(), + p->end_use_expand(), " ")) + .expand_vars(expand_vars) + .root(stringify(_imp->params.root) + "/") + .profiles(_imp->params.profiles) + .disable_cfgpro(o.no_config_protect) + .slot(SlotName(metadata->slot))); + + install_cmd(); +} + +std::string +PortageRepositoryEbinEntries::get_environment_variable(const QualifiedPackageName & q, + const VersionSpec & v, const std::string & s, + PortageRepositoryProfile::ConstPointer) const +{ + VersionMetadata::ConstPointer metadata(_imp->portage_repository->version_metadata(q, v)); + + if (s == "DEPEND") + return metadata->deps.build_depend_string; + if (s == "RDEPEND") + return metadata->deps.run_depend_string; + if (s == "PDEPEND") + return metadata->deps.post_depend_string; + + if (s == "SLOT") + return stringify(metadata->slot); + if (s == "LICENSE") + return metadata->license_string; + if (s == "EAPI") + return metadata->eapi; + if (s == "HOMEPAGE") + return metadata->homepage; + if (s == "DESCRIPTION") + return metadata->description; + + if (s == "PROVIDE") + return metadata->get_ebuild_interface()->provide_string; + if (s == "SRC_URI") + return metadata->get_ebuild_interface()->src_uri; + if (s == "RESTRICT") + return metadata->get_ebuild_interface()->restrict_string; + if (s == "KEYWORDS") + return metadata->get_ebuild_interface()->keywords; + if (s == "IUSE") + return metadata->get_ebuild_interface()->iuse; + if (s == "VIRTUAL") + return metadata->get_ebuild_interface()->inherited; + + if (s == "BIN_URI") + return metadata->get_ebin_interface()->bin_uri; + if (s == "SRC_REPOSITORY") + return stringify(metadata->get_ebin_interface()->src_repository); + + PackageDatabaseEntry for_package(q, v, _imp->portage_repository->name()); + throw EnvironmentVariableActionError("Couldn't get environment variable '" + + stringify(s) + "' for package '" + stringify(for_package) + "'"); +} + +PortageRepositoryEbinEntries::Pointer +PortageRepositoryEbinEntries::make_portage_repository_ebin_entries( + const Environment * const e, PortageRepository * const r, const PortageRepositoryParams & p) +{ + return Pointer(new PortageRepositoryEbinEntries(e, r, p)); +} + +#ifdef PALUDIS_ENABLE_VISIBILITY +# pragma GCC visibility push(default) +#endif +namespace +{ + const PortageRepositoryEntriesMaker::RegisterMaker register_portage_repository_ebin_entries PALUDIS_ATTRIBUTE((used)) ( + "ebin", &PortageRepositoryEbinEntries::make_portage_repository_ebin_entries); +} +#ifdef PALUDIS_ENABLE_VISIBILITY +# pragma GCC visibility pop +#endif + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_ebin_entries.hh b/0.8.0/paludis/repositories/portage/portage_repository_ebin_entries.hh new file mode 100644 index 000000000..bc7eda77b --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_ebin_entries.hh @@ -0,0 +1,71 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_EBIN_METADATA_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_EBIN_METADATA_HH 1 + +#include <paludis/repositories/portage/portage_repository_entries.hh> +#include <paludis/repositories/portage/portage_repository_params.hh> +#include <paludis/util/private_implementation_pattern.hh> + +/** \file + * Declaration for the PortageRepositoryEbinEntries class. + * + * \ingroup grpportagerepository + */ + +namespace paludis +{ + class FSEntry; + class PortageRepository; + + /** + * PortageRepositoryEntries handler for ebins. + * + * \ingroup grpportagerepository + */ + class PALUDIS_VISIBLE PortageRepositoryEbinEntries : + public PortageRepositoryEntries, + private PrivateImplementationPattern<PortageRepositoryEbinEntries> + { + public: + static PortageRepositoryEbinEntries::Pointer + make_portage_repository_ebin_entries(const Environment * const, + PortageRepository * const, const PortageRepositoryParams &); + + PortageRepositoryEbinEntries(const Environment * const, + PortageRepository * const portage_repository, + const PortageRepositoryParams &); + + virtual ~PortageRepositoryEbinEntries(); + + virtual VersionMetadata::Pointer generate_version_metadata(const QualifiedPackageName &, + const VersionSpec &) const; + + virtual std::string get_environment_variable(const QualifiedPackageName &, + const VersionSpec &, const std::string & var, + PortageRepositoryProfile::ConstPointer) const; + + virtual void install(const QualifiedPackageName &, const VersionSpec &, + const InstallOptions &, PortageRepositoryProfile::ConstPointer) const; + }; +} + +#endif + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_ebuild_entries.cc b/0.8.0/paludis/repositories/portage/portage_repository_ebuild_entries.cc new file mode 100644 index 000000000..562e93c63 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_ebuild_entries.cc @@ -0,0 +1,556 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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/portage/portage_repository_ebuild_entries.hh> +#include <paludis/repositories/portage/portage_repository.hh> + +#include <paludis/dep_atom_flattener.hh> +#include <paludis/ebuild.hh> +#include <paludis/environment.hh> +#include <paludis/portage_dep_parser.hh> +#include <paludis/version_metadata.hh> +#include <paludis/util/collection_concrete.hh> +#include <paludis/util/fs_entry.hh> +#include <paludis/util/log.hh> +#include <paludis/util/strip.hh> +#include <paludis/util/tokeniser.hh> + +#include <fstream> +#include <list> +#include <set> + +using namespace paludis; + +namespace paludis +{ + /** + * Implementation data for PortageRepositoryEbuildEntries. + * + * \ingroup grpportagerepository + */ + template<> + struct Implementation<PortageRepositoryEbuildEntries> : + InternalCounted<Implementation<PortageRepositoryEbuildEntries> > + { + const Environment * const environment; + PortageRepository * const portage_repository; + const PortageRepositoryParams params; + + Implementation(const Environment * const e, PortageRepository * const p, + const PortageRepositoryParams & k) : + environment(e), + portage_repository(p), + params(k) + { + } + }; +} + +PortageRepositoryEbuildEntries::PortageRepositoryEbuildEntries( + const Environment * const e, PortageRepository * const p, const PortageRepositoryParams & k) : + PortageRepositoryEntries(".ebuild"), + PrivateImplementationPattern<PortageRepositoryEbuildEntries>(new + Implementation<PortageRepositoryEbuildEntries>(e, p, k)) +{ +} + +PortageRepositoryEbuildEntries::~PortageRepositoryEbuildEntries() +{ +} + +VersionMetadata::Pointer +PortageRepositoryEbuildEntries::generate_version_metadata(const QualifiedPackageName & q, + const VersionSpec & v) const +{ + VersionMetadata::Pointer result(new VersionMetadata::Ebuild(PortageDepParser::parse_depend)); + + FSEntry cache_file(_imp->params.cache); + cache_file /= stringify(q.category); + cache_file /= stringify(q.package) + "-" + stringify(v); + + bool ok(false); + if (cache_file.is_regular_file()) + { + std::ifstream cache(stringify(cache_file).c_str()); + std::string line; + + if (cache) + { + std::getline(cache, line); result->deps.build_depend_string = line; + std::getline(cache, line); result->deps.run_depend_string = line; + std::getline(cache, line); result->slot = SlotName(line); + std::getline(cache, line); result->get_ebuild_interface()->src_uri = line; + std::getline(cache, line); result->get_ebuild_interface()->restrict_string = line; + std::getline(cache, line); result->homepage = line; + std::getline(cache, line); result->license_string = line; + std::getline(cache, line); result->description = line; + std::getline(cache, line); result->get_ebuild_interface()->keywords = line; + std::getline(cache, line); result->get_ebuild_interface()->inherited = line; + std::getline(cache, line); result->get_ebuild_interface()->iuse = line; + std::getline(cache, line); + std::getline(cache, line); result->deps.post_depend_string = line; + std::getline(cache, line); result->get_ebuild_interface()->provide_string = line; + std::getline(cache, line); result->eapi = line; + + // check mtimes + time_t cache_time(cache_file.mtime()); + ok = true; + + if ((_imp->params.location / stringify(q.category) / + stringify(q.package) / + (stringify(q.package) + "-" + stringify(v) + + ".ebuild")).mtime() > cache_time) + ok = false; + else + { + FSEntry timestamp(_imp->params.location / "metadata" / "timestamp"); + if (timestamp.exists()) + cache_time = timestamp.mtime(); + + std::list<std::string> inherits; + WhitespaceTokeniser::get_instance()->tokenise( + stringify(result->get_ebuild_interface()->inherited), + std::back_inserter(inherits)); + for (FSEntryCollection::Iterator e(_imp->params.eclassdirs->begin()), + e_end(_imp->params.eclassdirs->end()) ; e != e_end ; ++e) + for (std::list<std::string>::const_iterator i(inherits.begin()), + i_end(inherits.end()) ; i != i_end ; ++i) + { + if ((*e / (*i + ".eclass")).exists()) + if (((*e / (*i + ".eclass"))).mtime() > cache_time) + ok = false; + } + } + + if (! ok) + Log::get_instance()->message(ll_warning, lc_no_context, "Stale cache file at '" + + stringify(cache_file) + "'"); + } + else + Log::get_instance()->message(ll_warning, lc_no_context, + "Couldn't read the cache file at '" + + stringify(cache_file) + "'"); + } + + if (! ok) + { + if (_imp->params.cache.basename() != "empty") + Log::get_instance()->message(ll_warning, lc_no_context, + "No usable cache entry for '" + stringify(q) + + "-" + stringify(v) + "' in '" + stringify(_imp->portage_repository->name()) + "'"); + + PackageDatabaseEntry e(q, v, _imp->portage_repository->name()); + EbuildMetadataCommand cmd(EbuildCommandParams::create() + .environment(_imp->environment) + .db_entry(&e) + .ebuild_dir(_imp->params.location / stringify(q.category) / + stringify(q.package)) + .files_dir(_imp->params.location / stringify(q.category) / + stringify(q.package) / "files") + .eclassdirs(_imp->params.eclassdirs) + .portdir(_imp->params.location) + .distdir(_imp->params.distdir) + .buildroot(_imp->params.buildroot)); + + if (! cmd()) + Log::get_instance()->message(ll_warning, lc_no_context, + "No usable metadata for '" + stringify(q) + + "-" + stringify(v) + "' in '" + stringify(_imp->portage_repository->name()) + "'"); + + if (0 == ((result = cmd.metadata()))) + throw InternalError(PALUDIS_HERE, "cmd.metadata() is zero pointer???"); + } + + return result; + +} + +namespace +{ + class AAFinder : + private InstantiationPolicy<AAFinder, instantiation_method::NonCopyableTag>, + protected DepAtomVisitorTypes::ConstVisitor + { + private: + mutable std::list<const StringDepAtom *> _atoms; + + protected: + void visit(const AllDepAtom * a) + { + std::for_each(a->begin(), a->end(), accept_visitor( + static_cast<DepAtomVisitorTypes::ConstVisitor *>(this))); + } + + void visit(const AnyDepAtom *) PALUDIS_ATTRIBUTE((noreturn)) + { + throw InternalError(PALUDIS_HERE, "Found unexpected AnyDepAtom"); + } + + void visit(const UseDepAtom * a) + { + std::for_each(a->begin(), a->end(), accept_visitor( + static_cast<DepAtomVisitorTypes::ConstVisitor *>(this))); + } + + void visit(const PlainTextDepAtom * a) + { + _atoms.push_back(a); + } + + void visit(const PackageDepAtom * a) + { + _atoms.push_back(a); + } + + void visit(const BlockDepAtom * a) + { + _atoms.push_back(a); + } + + public: + AAFinder(const DepAtom::ConstPointer a) + { + a->accept(static_cast<DepAtomVisitorTypes::ConstVisitor *>(this)); + } + + typedef std::list<const StringDepAtom *>::const_iterator Iterator; + + Iterator begin() + { + return _atoms.begin(); + } + + Iterator end() const + { + return _atoms.end(); + } + }; + +} + +void +PortageRepositoryEbuildEntries::install(const QualifiedPackageName & q, const VersionSpec & v, + const InstallOptions & o, PortageRepositoryProfile::ConstPointer p) const +{ + if (! _imp->portage_repository->has_version(q, v)) + { + throw PackageInstallActionError("Can't install '" + stringify(q) + "-" + + stringify(v) + "' since has_version failed"); + } + + VersionMetadata::ConstPointer metadata(_imp->portage_repository->version_metadata(q, v)); + + PackageDatabaseEntry e(q, v, _imp->portage_repository->name()); + + bool fetch_restrict(false), no_mirror(false); + { + std::list<std::string> restricts; + WhitespaceTokeniser::get_instance()->tokenise( + metadata->get_ebuild_interface()->restrict_string, std::back_inserter(restricts)); + fetch_restrict = (restricts.end() != std::find(restricts.begin(), restricts.end(), "fetch")) || + (restricts.end() != std::find(restricts.begin(), restricts.end(), "nofetch")); + no_mirror = (restricts.end() != std::find(restricts.begin(), restricts.end(), "mirror")) || + (restricts.end() != std::find(restricts.begin(), restricts.end(), "nomirror")); + } + + std::string archives, all_archives, flat_src_uri; + { + std::set<std::string> already_in_archives; + + /* make A and FLAT_SRC_URI */ + DepAtom::ConstPointer f_atom(PortageDepParser::parse(metadata->get_ebuild_interface()->src_uri, + PortageDepParserPolicy<PlainTextDepAtom, false>::get_instance())); + DepAtomFlattener f(_imp->params.environment, &e, f_atom); + + for (DepAtomFlattener::Iterator ff(f.begin()), ff_end(f.end()) ; ff != ff_end ; ++ff) + { + std::string::size_type pos((*ff)->text().rfind('/')); + if (std::string::npos == pos) + { + if (already_in_archives.end() == already_in_archives.find((*ff)->text())) + { + archives.append((*ff)->text()); + already_in_archives.insert((*ff)->text()); + } + } + else + { + if (already_in_archives.end() == already_in_archives.find((*ff)->text().substr(pos + 1))) + { + archives.append((*ff)->text().substr(pos + 1)); + already_in_archives.insert((*ff)->text().substr(pos + 1)); + } + } + archives.append(" "); + + /* add * mirror entries */ + for (Environment::MirrorIterator + m(_imp->params.environment->begin_mirrors("*")), + m_end(_imp->params.environment->end_mirrors("*")) ; + m != m_end ; ++m) + flat_src_uri.append(m->second + "/" + (*ff)->text().substr(pos + 1) + " "); + + if (0 == (*ff)->text().compare(0, 9, "mirror://")) + { + std::string mirror((*ff)->text().substr(9)); + std::string::size_type spos(mirror.find('/')); + + if (std::string::npos == spos) + throw PackageInstallActionError("Can't install '" + stringify(q) + "-" + + stringify(v) + "' since SRC_URI is broken"); + + if (! _imp->portage_repository->is_mirror(mirror.substr(0, spos)) && + _imp->params.environment->begin_mirrors(mirror.substr(0, spos)) == + _imp->params.environment->end_mirrors(mirror.substr(0, spos))) + throw PackageInstallActionError("Can't install '" + stringify(q) + "-" + + stringify(v) + "' since SRC_URI references unknown mirror:// '" + + mirror.substr(0, spos) + "'"); + + for (Environment::MirrorIterator + m(_imp->params.environment->begin_mirrors(mirror.substr(0, spos))), + m_end(_imp->params.environment->end_mirrors(mirror.substr(0, spos))) ; + m != m_end ; ++m) + flat_src_uri.append(m->second + "/" + mirror.substr(spos + 1) + " "); + + for (RepositoryMirrorsInterface::MirrorsIterator + m(_imp->portage_repository->begin_mirrors(mirror.substr(0, spos))), + m_end(_imp->portage_repository->end_mirrors(mirror.substr(0, spos))) ; + m != m_end ; ++m) + flat_src_uri.append(m->second + "/" + mirror.substr(spos + 1) + " "); + } + else + flat_src_uri.append((*ff)->text()); + flat_src_uri.append(" "); + + /* add mirror://gentoo/ entries */ + std::string master_mirror(strip_trailing_string(stringify(_imp->portage_repository->name()), "x-")); + if (! no_mirror && _imp->portage_repository->is_mirror(master_mirror)) + { + for (Environment::MirrorIterator + m(_imp->params.environment->begin_mirrors(master_mirror)), + m_end(_imp->params.environment->end_mirrors(master_mirror)) ; + m != m_end ; ++m) + flat_src_uri.append(m->second + "/" + (*ff)->text().substr(pos + 1) + " "); + + for (RepositoryMirrorsInterface::MirrorsIterator + m(_imp->portage_repository->begin_mirrors(master_mirror)), + m_end(_imp->portage_repository->end_mirrors(master_mirror)) ; + m != m_end ; ++m) + flat_src_uri.append(m->second + "/" + (*ff)->text().substr(pos + 1) + " "); + } + } + + /* make AA */ + DepAtom::ConstPointer g_atom(PortageDepParser::parse( + metadata->get_ebuild_interface()->src_uri, + PortageDepParserPolicy<PlainTextDepAtom, false>::get_instance())); + AAFinder g(g_atom); + std::set<std::string> already_in_all_archives; + + for (AAFinder::Iterator gg(g.begin()), gg_end(g.end()) ; gg != gg_end ; ++gg) + { + std::string::size_type pos((*gg)->text().rfind('/')); + if (std::string::npos == pos) + { + if (already_in_all_archives.end() == already_in_all_archives.find((*gg)->text())) + { + all_archives.append((*gg)->text()); + already_in_all_archives.insert((*gg)->text()); + } + } + else + { + if (already_in_all_archives.end() == already_in_all_archives.find((*gg)->text().substr(pos + 1))) + { + all_archives.append((*gg)->text().substr(pos + 1)); + already_in_all_archives.insert((*gg)->text().substr(pos + 1)); + } + } + all_archives.append(" "); + } + } + + /* Strip trailing space. Some ebuilds rely upon this. From kde-meta.eclass: + * [[ -n ${A/${TARBALL}/} ]] && unpack ${A/${TARBALL}/} + * Rather annoying. + */ + archives = strip_trailing(archives, " "); + all_archives = strip_trailing(all_archives, " "); + + /* make use */ + std::string use; + { + std::set<UseFlagName> iuse; + WhitespaceTokeniser::get_instance()->tokenise(metadata->get_ebuild_interface()-> + iuse, create_inserter<UseFlagName>(std::inserter(iuse, iuse.begin()))); + for (std::set<UseFlagName>::const_iterator iuse_it(iuse.begin()), iuse_end(iuse.end()) ; + iuse_it != iuse_end; ++iuse_it) + if (_imp->params.environment->query_use(*iuse_it, &e)) + use += (*iuse_it).data() + " "; + } + + use += p->environment_variable("ARCH") + " "; + + /* add expand to use (iuse isn't reliable for use_expand things), and make the expand + * environment variables */ + AssociativeCollection<std::string, std::string>::Pointer expand_vars( + new AssociativeCollection<std::string, std::string>::Concrete); + for (PortageRepositoryProfile::UseExpandIterator x(p->begin_use_expand()), + x_end(p->end_use_expand()) ; x != x_end ; ++x) + { + std::string lower_x; + std::transform(x->data().begin(), x->data().end(), std::back_inserter(lower_x), &::tolower); + + expand_vars->insert(stringify(*x), ""); + + /* possible values from profile */ + std::set<UseFlagName> possible_values; + WhitespaceTokeniser::get_instance()->tokenise(p->environment_variable(stringify(*x)), + create_inserter<UseFlagName>(std::inserter(possible_values, possible_values.end()))); + + /* possible values from environment */ + UseFlagNameCollection::ConstPointer possible_values_from_env(_imp->params.environment-> + known_use_expand_names(*x, &e)); + for (UseFlagNameCollection::Iterator i(possible_values_from_env->begin()), + i_end(possible_values_from_env->end()) ; i != i_end ; ++i) + possible_values.insert(UseFlagName(stringify(*i).substr(lower_x.length() + 1))); + + for (std::set<UseFlagName>::const_iterator u(possible_values.begin()), u_end(possible_values.end()) ; + u != u_end ; ++u) + { + if (! _imp->params.environment->query_use(UseFlagName(lower_x + "_" + stringify(*u)), &e)) + continue; + + use.append(lower_x + "_" + stringify(*u) + " "); + + std::string value; + AssociativeCollection<std::string, std::string>::Iterator i(expand_vars->find(stringify(*x))); + if (expand_vars->end() != i) + { + value = i->second; + if (! value.empty()) + value.append(" "); + expand_vars->erase(i); + } + value.append(stringify(*u)); + expand_vars->insert(stringify(*x), value); + } + } + + EbuildFetchCommand fetch_cmd(EbuildCommandParams::create() + .environment(_imp->params.environment) + .db_entry(&e) + .ebuild_dir(_imp->params.location / stringify(q.category) / + stringify(q.package)) + .files_dir(_imp->params.location / stringify(q.category) / + stringify(q.package) / "files") + .eclassdirs(_imp->params.eclassdirs) + .portdir(_imp->params.location) + .distdir(_imp->params.distdir) + .buildroot(_imp->params.buildroot), + + EbuildFetchCommandParams::create() + .a(archives) + .aa(all_archives) + .use(use) + .use_expand(join(p->begin_use_expand(), p->end_use_expand(), " ")) + .expand_vars(expand_vars) + .flat_src_uri(flat_src_uri) + .root(stringify(_imp->params.root) + "/") + .profiles(_imp->params.profiles) + .no_fetch(fetch_restrict)); + + fetch_cmd(); + + if (o.fetch_only) + return; + + EbuildInstallCommand install_cmd(EbuildCommandParams::create() + .environment(_imp->params.environment) + .db_entry(&e) + .ebuild_dir(_imp->params.location / stringify(q.category) / + stringify(q.package)) + .files_dir(_imp->params.location / stringify(q.category) / + stringify(q.package) / "files") + .eclassdirs(_imp->params.eclassdirs) + .portdir(_imp->params.location) + .distdir(_imp->params.distdir) + .buildroot(_imp->params.buildroot), + + EbuildInstallCommandParams::create() + .use(use) + .a(archives) + .aa(all_archives) + .use_expand(join(p->begin_use_expand(), p->end_use_expand(), " ")) + .expand_vars(expand_vars) + .root(stringify(_imp->params.root) + "/") + .profiles(_imp->params.profiles) + .disable_cfgpro(o.no_config_protect) + .slot(SlotName(metadata->slot))); + + install_cmd(); +} + +std::string +PortageRepositoryEbuildEntries::get_environment_variable(const QualifiedPackageName & q, + const VersionSpec & v, const std::string & var, + PortageRepositoryProfile::ConstPointer) const +{ + PackageDatabaseEntry for_package(q, v, _imp->portage_repository->name()); + + EbuildVariableCommand cmd(EbuildCommandParams::create() + .environment(_imp->params.environment) + .db_entry(&for_package) + .ebuild_dir(_imp->params.location / stringify(q.category) / + stringify(q.package)) + .files_dir(_imp->params.location / stringify(q.category) / + stringify(q.package) / "files") + .eclassdirs(_imp->params.eclassdirs) + .portdir(_imp->params.location) + .distdir(_imp->params.distdir) + .buildroot(_imp->params.buildroot), + + var); + + if (! cmd()) + throw EnvironmentVariableActionError("Couldn't get environment variable '" + + stringify(var) + "' for package '" + stringify(for_package) + "'"); + + return cmd.result(); +} + +PortageRepositoryEbuildEntries::Pointer +PortageRepositoryEbuildEntries::make_portage_repository_ebuild_entries( + const Environment * const e, PortageRepository * const r, const PortageRepositoryParams & p) +{ + return Pointer(new PortageRepositoryEbuildEntries(e, r, p)); +} + +#ifdef PALUDIS_ENABLE_VISIBILITY +# pragma GCC visibility push(default) +#endif +namespace +{ + const PortageRepositoryEntriesMaker::RegisterMaker register_portage_repository_ebuild_entries PALUDIS_ATTRIBUTE((used)) ( + "ebuild", &PortageRepositoryEbuildEntries::make_portage_repository_ebuild_entries); +} +#ifdef PALUDIS_ENABLE_VISIBILITY +# pragma GCC visibility pop +#endif + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_ebuild_entries.hh b/0.8.0/paludis/repositories/portage/portage_repository_ebuild_entries.hh new file mode 100644 index 000000000..a3fb2f8eb --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_ebuild_entries.hh @@ -0,0 +1,70 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_EBUILD_METADATA_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_EBUILD_METADATA_HH 1 + +#include <paludis/repositories/portage/portage_repository_entries.hh> +#include <paludis/repositories/portage/portage_repository_params.hh> +#include <paludis/util/private_implementation_pattern.hh> + +/** \file + * Declaration for the PortageRepositoryEbuildEntries class. + * + * \ingroup grpportagerepository + */ + +namespace paludis +{ + class FSEntry; + class PortageRepository; + + /** + * PortageRepositoryEntries handler for ebuilds. + * + * \ingroup grpportagerepository + */ + class PALUDIS_VISIBLE PortageRepositoryEbuildEntries : + public PortageRepositoryEntries, + private PrivateImplementationPattern<PortageRepositoryEbuildEntries> + { + public: + static PortageRepositoryEbuildEntries::Pointer + make_portage_repository_ebuild_entries(const Environment * const, + PortageRepository * const, const PortageRepositoryParams &); + + PortageRepositoryEbuildEntries(const Environment * const, + PortageRepository * const portage_repository, + const PortageRepositoryParams &); + + virtual ~PortageRepositoryEbuildEntries(); + + virtual VersionMetadata::Pointer generate_version_metadata(const QualifiedPackageName &, + const VersionSpec &) const; + + virtual std::string get_environment_variable(const QualifiedPackageName &, + const VersionSpec &, const std::string & var, + PortageRepositoryProfile::ConstPointer) const; + + virtual void install(const QualifiedPackageName &, const VersionSpec &, + const InstallOptions &, PortageRepositoryProfile::ConstPointer) const; + }; +} + +#endif diff --git a/0.8.0/paludis/repositories/portage/portage_repository_entries.cc b/0.8.0/paludis/repositories/portage/portage_repository_entries.cc new file mode 100644 index 000000000..c891b04fe --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_entries.cc @@ -0,0 +1,38 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 "portage_repository_entries.hh" + +using namespace paludis; + +PortageRepositoryEntries::PortageRepositoryEntries(const std::string & ext) : + _ext(ext) +{ +} + +PortageRepositoryEntries::~PortageRepositoryEntries() +{ +} + +NoSuchPortageRepositoryEntriesType::NoSuchPortageRepositoryEntriesType(const std::string & format) throw (): + ConfigurationError("No available maker for Portage repository entries type '" + format + "'") +{ +} + + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_entries.hh b/0.8.0/paludis/repositories/portage/portage_repository_entries.hh new file mode 100644 index 000000000..0ba2f7a87 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_entries.hh @@ -0,0 +1,126 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_METADATA_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_METADATA_HH 1 + +#include <paludis/name.hh> +#include <paludis/repository.hh> +#include <paludis/version_spec.hh> +#include <paludis/version_metadata.hh> +#include <paludis/util/counted_ptr.hh> +#include <paludis/util/instantiation_policy.hh> +#include <paludis/util/virtual_constructor.hh> +#include <paludis/repositories/portage/portage_repository_profile.hh> +#include <paludis/repositories/portage/portage_repository_params.hh> +#include <string> + +/** \file + * Declaration for the PortageRepositoryEntries class. + * + * \ingroup grpportagerepository + */ + +namespace paludis +{ + class PortageRepository; + class Environment; + + /** + * Handle entries (for example, ebuilds) in a PortageRepository. + * + * \ingroup grpportagerepository + */ + class PALUDIS_VISIBLE PortageRepositoryEntries : + public InternalCounted<PortageRepositoryEntries> + { + private: + const std::string _ext; + + protected: + ///\name Basic operations + ///\{ + + /// Constructor, with our file extension + PortageRepositoryEntries(const std::string & ext); + + ///\} + + public: + ///\name Basic operations + ///\{ + + virtual ~PortageRepositoryEntries(); + + ///\} + + /** + * Return our file extension, including the dot. + */ + std::string file_extension() const + { + return _ext; + } + + /** + * Generate version metadata. + */ + virtual VersionMetadata::Pointer generate_version_metadata(const QualifiedPackageName &, + const VersionSpec &) const = 0; + + /** + * Fetch an environment variable. + */ + virtual std::string get_environment_variable(const QualifiedPackageName &, + const VersionSpec &, const std::string & var, + PortageRepositoryProfile::ConstPointer) const = 0; + + virtual void install(const QualifiedPackageName &, const VersionSpec &, + const InstallOptions &, PortageRepositoryProfile::ConstPointer) const = 0; + }; + + /** + * Thrown if a repository of the specified type does not exist. + * + * \ingroup grpexceptions + * \ingroup grprepository + */ + class PALUDIS_VISIBLE NoSuchPortageRepositoryEntriesType : public ConfigurationError + { + public: + /** + * Constructor. + */ + NoSuchPortageRepositoryEntriesType(const std::string & format) throw (); + }; + + /** + * Virtual constructor for PortageRepositoryEntries. + * + * \ingroup grprepository + */ + typedef VirtualConstructor<std::string, + PortageRepositoryEntries::Pointer (*) (const Environment * const, PortageRepository * const, + const PortageRepositoryParams &), + virtual_constructor_not_found::ThrowException<NoSuchPortageRepositoryEntriesType> > + PortageRepositoryEntriesMaker; + +} + +#endif diff --git a/0.8.0/paludis/repositories/portage/portage_repository_entry.cc b/0.8.0/paludis/repositories/portage/portage_repository_entry.cc new file mode 100644 index 000000000..ea568cd1f --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_entry.cc @@ -0,0 +1,32 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 "portage_repository_metadata.hh" + +using namespace paludis; + +PortageRepositoryMetadata::PortageRepositoryMetadata(const std::string & ext) : + _ext(ext) +{ +} + +PortageRepositoryMetadata::~PortageRepositoryMetadata() +{ +} + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_exceptions.cc b/0.8.0/paludis/repositories/portage/portage_repository_exceptions.cc new file mode 100644 index 000000000..f8e118697 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_exceptions.cc @@ -0,0 +1,29 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 "portage_repository_exceptions.hh" + +using namespace paludis; + +PortageRepositoryConfigurationError::PortageRepositoryConfigurationError( + const std::string & msg) throw () : + ConfigurationError("Portage repository configuration error: " + msg) +{ +} + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_exceptions.hh b/0.8.0/paludis/repositories/portage/portage_repository_exceptions.hh new file mode 100644 index 000000000..945182e5c --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_exceptions.hh @@ -0,0 +1,53 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_EXCEPTIONS_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_EXCEPTIONS_HH 1 + +#include <paludis/util/exception.hh> + +/** \file + * Declaration for the PortageRepository exception classes. + * + * \ingroup grpportagerepository + */ + +namespace paludis +{ + /** + * Thrown if invalid parameters are provided for + * PortageRepository::make_portage_repository. + * + * \ingroup grpexceptions + * \ingroup grpportagerepository + */ + class PALUDIS_VISIBLE PortageRepositoryConfigurationError : + public ConfigurationError + { + public: + /** + * Constructor. + */ + PortageRepositoryConfigurationError(const std::string & msg) throw (); + }; + + +} + +#endif diff --git a/0.8.0/paludis/repositories/portage/portage_repository_news.cc b/0.8.0/paludis/repositories/portage/portage_repository_news.cc new file mode 100644 index 000000000..8936219b3 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_news.cc @@ -0,0 +1,284 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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/portage/portage_repository.hh> +#include <paludis/repositories/portage/portage_repository_news.hh> + +#include <paludis/config_file.hh> +#include <paludis/environment.hh> +#include <paludis/util/dir_iterator.hh> +#include <paludis/util/fs_entry.hh> +#include <paludis/util/log.hh> +#include <paludis/util/strip.hh> + +#include <set> +#include <ostream> +#include <fstream> +#include <list> + +using namespace paludis; + +namespace paludis +{ + /** + * Implementation data for PortageRepositoryNews. + * + * \ingroup grpportagerepository + */ + template<> + struct Implementation<PortageRepositoryNews> : + InternalCounted<Implementation<PortageRepositoryNews> > + { + const Environment * const environment; + const PortageRepository * const portage_repository; + const PortageRepositoryParams params; + + const FSEntry skip_file; + const FSEntry unread_file; + + Implementation(const Environment * const e, const PortageRepository * const p, + const PortageRepositoryParams & k) : + environment(e), + portage_repository(p), + params(k), + skip_file(params.root / "var" / "lib" / "paludis" / "news" / + ("news-" + stringify(portage_repository->name()) + ".skip")), + unread_file(params.root / "var" / "lib" / "paludis" / "news" / + ("news-" + stringify(portage_repository->name()) + ".unread")) + { + } + }; +} + +PortageRepositoryNews::PortageRepositoryNews(const Environment * const e, const PortageRepository * const p, + const PortageRepositoryParams & k) : + PrivateImplementationPattern<PortageRepositoryNews>(new Implementation<PortageRepositoryNews>(e, p, k)) +{ +} + +PortageRepositoryNews::~PortageRepositoryNews() +{ +} + +void +PortageRepositoryNews::update_news() const +{ + Context context("When updating news at location '" + + stringify(_imp->params.newsdir) + "' for repository '" + + stringify(_imp->portage_repository->name()) + "':"); + + if (! _imp->params.newsdir.is_directory()) + return; + + std::set<std::string> skip; + + if (_imp->skip_file.is_regular_file()) + { + Context local_context("When handling news skip file '" + stringify( + _imp->skip_file) + "':"); + LineConfigFile s(_imp->skip_file); + std::copy(s.begin(), s.end(), std::inserter(skip, skip.end())); + } + + for (DirIterator d(_imp->params.newsdir), d_end ; d != d_end ; ++d) + { + Context local_context("When handling news entry '" + stringify(*d) + "':"); + + if (! d->is_directory()) + continue; + if (! (*d / (d->basename() + ".en.txt")).is_regular_file()) + continue; + + if (skip.end() != skip.find(d->basename())) + continue; + + try + { + NewsFile news(*d / (d->basename() + ".en.txt")); + bool show(true); + + if (news.begin_display_if_installed() != news.end_display_if_installed()) + { + bool local_show(false); + for (NewsFile::DisplayIfInstalledIterator i(news.begin_display_if_installed()), + i_end(news.end_display_if_installed()) ; i != i_end ; ++i) + if (! _imp->environment->package_database()->query(PackageDepAtom::Pointer( + new PackageDepAtom(*i)), is_installed_only)->empty()) + local_show = true; + show &= local_show; + } + + if (news.begin_display_if_keyword() != news.end_display_if_keyword()) + { + bool local_show(false); + for (NewsFile::DisplayIfKeywordIterator i(news.begin_display_if_keyword()), + i_end(news.end_display_if_keyword()) ; i != i_end && ! local_show ; ++i) + if (*i == _imp->portage_repository->profile_variable("ARCH")) + local_show = true; + show &= local_show; + } + + if (news.begin_display_if_profile() != news.end_display_if_profile()) + { + bool local_show(false); + FSEntryCollection::ConstPointer c(_imp->params.profiles); + for (FSEntryCollection::Iterator p(c->begin()), p_end(c->end()) ; p != p_end ; ++p) + { + std::string profile(strip_leading_string(strip_trailing_string( + strip_leading_string(stringify(p->realpath()), + stringify(p->realpath())), "/"), "/")); + Log::get_instance()->message(ll_debug, lc_no_context, + "Profile path is '" + profile + "'"); + for (NewsFile::DisplayIfProfileIterator i(news.begin_display_if_profile()), + i_end(news.end_display_if_profile()) ; i != i_end ; ++i) + if (profile == *i) + local_show = true; + } + show &= local_show; + } + + if (show) + { + std::ofstream s(stringify(_imp->skip_file).c_str(), + std::ios::out | std::ios::app); + if (! s) + Log::get_instance()->message(ll_warning, lc_no_context, + "Cannot append to news skip file '" + + stringify(_imp->skip_file) + + "', skipping news item '" + stringify(*d) + "'"); + + std::ofstream t(stringify(_imp->unread_file).c_str(), + std::ios::out | std::ios::app); + if (! t) + Log::get_instance()->message(ll_warning, lc_no_context, + "Cannot append to unread file '" + + stringify(_imp->unread_file) + + "', skipping news item '" + stringify(*d) + "'"); + + if (s && t) + { + s << d->basename() << std::endl; + t << d->basename() << std::endl; + } + } + } + catch (const ConfigFileError & e) + { + Log::get_instance()->message(ll_warning, lc_no_context, + "Skipping news item '" + + stringify(*d) + "' because of exception '" + e.message() + "' (" + + e.what() + ")"); + } + } + +} + +namespace paludis +{ + /** + * Implementation data for NewsFile. + * + * \ingroup grpnewsconfigfile + */ + template<> + struct Implementation<NewsFile> : + InternalCounted<Implementation<NewsFile> > + { + mutable bool in_header; + mutable std::list<std::string> display_if_installed; + mutable std::list<std::string> display_if_keyword; + mutable std::list<std::string> display_if_profile; + + Implementation() : + in_header(true) + { + } + }; +} + +NewsFile::NewsFile(const FSEntry & our_filename) : + ConfigFile(our_filename), + PrivateImplementationPattern<NewsFile>(new Implementation<NewsFile>) +{ + need_lines(); +} + +NewsFile::~NewsFile() +{ +} + +void +NewsFile::accept_line(const std::string & line) const +{ + if (_imp->in_header) + { + std::string::size_type p(line.find(':')); + if (std::string::npos == p) + _imp->in_header = false; + else + { + std::string k(strip_leading(strip_trailing(line.substr(0, p), " \t\n"), " \t\n")); + std::string v(strip_leading(strip_trailing(line.substr(p + 1), " \t\n"), " \t\n")); + if (k == "Display-If-Installed") + _imp->display_if_installed.push_back(v); + else if (k == "Display-If-Keyword") + _imp->display_if_keyword.push_back(v); + if (k == "Display-If-Profile") + _imp->display_if_profile.push_back(v); + } + } +} + +NewsFile::DisplayIfInstalledIterator +NewsFile::begin_display_if_installed() const +{ + return DisplayIfInstalledIterator(_imp->display_if_installed.begin()); +} + +NewsFile::DisplayIfInstalledIterator +NewsFile::end_display_if_installed() const +{ + return DisplayIfInstalledIterator(_imp->display_if_installed.end()); +} + +NewsFile::DisplayIfKeywordIterator +NewsFile::begin_display_if_keyword() const +{ + return DisplayIfKeywordIterator(_imp->display_if_keyword.begin()); +} + +NewsFile::DisplayIfKeywordIterator +NewsFile::end_display_if_keyword() const +{ + return DisplayIfKeywordIterator(_imp->display_if_keyword.end()); +} + +NewsFile::DisplayIfProfileIterator +NewsFile::begin_display_if_profile() const +{ + return DisplayIfProfileIterator(_imp->display_if_profile.begin()); +} + +NewsFile::DisplayIfProfileIterator +NewsFile::end_display_if_profile() const +{ + return DisplayIfProfileIterator(_imp->display_if_profile.end()); +} + + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_news.hh b/0.8.0/paludis/repositories/portage/portage_repository_news.hh new file mode 100644 index 000000000..2a7dacb70 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_news.hh @@ -0,0 +1,134 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_NEWS_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_NEWS_HH 1 + +#include <paludis/util/private_implementation_pattern.hh> +#include <paludis/util/instantiation_policy.hh> +#include <paludis/config_file.hh> + +/** \file + * Declaration for the PortageRepositoryNews class. + * + * \ingroup grpportagerepository + */ + +namespace paludis +{ + class Environment; + class FSEntry; + class PortageRepository; + + /** + * Holds the news/ data for a PortageRepository instance. + * + * \ingroup grpportagerepository + */ + class PALUDIS_VISIBLE PortageRepositoryNews : + private PrivateImplementationPattern<PortageRepositoryNews>, + private InstantiationPolicy<PortageRepositoryNews, instantiation_method::NonCopyableTag>, + public InternalCounted<PortageRepositoryNews> + { + public: + ///\name Basic operations + ///\{ + + PortageRepositoryNews(const Environment * const, const PortageRepository * const, + const PortageRepositoryParams &); + ~PortageRepositoryNews(); + + ///\} + + void update_news() const; + }; + + /** + * A NewsFile represents a GLEP 42 news file. + * + * \ingroup grpnewsconfigfile + */ + class PALUDIS_VISIBLE NewsFile : + protected ConfigFile, + private PrivateImplementationPattern<NewsFile> + { + protected: + void accept_line(const std::string &) const; + + public: + ///\name Basic operations + ///\{ + + /** + * Constructor, from a filename. + */ + NewsFile(const FSEntry & filename); + + ~NewsFile(); + + ///\} + + ///\name Iterate over our Display-If-Installed headers + ///\{ + + /// Tag for DisplayIfInstalledIterator. + struct DisplayIfInstalledIteratorTag; + + typedef libwrapiter::ForwardIterator<DisplayIfInstalledIteratorTag, + const std::string> DisplayIfInstalledIterator; + + DisplayIfInstalledIterator begin_display_if_installed() const; + + DisplayIfInstalledIterator end_display_if_installed() const; + + ///\} + + ///\name Iterate over our Display-If-Keyword headers + ///\{ + + /// Tag for DisplayIfKeywordIterator. + struct DisplayIfKeywordIteratorTag; + + typedef libwrapiter::ForwardIterator<DisplayIfKeywordIteratorTag, + const std::string> DisplayIfKeywordIterator; + + DisplayIfKeywordIterator begin_display_if_keyword() const; + + DisplayIfKeywordIterator end_display_if_keyword() const; + + ///\} + + ///\name Iterate over our Display-If-Profile headers + ///\{ + + /// Tag for DisplayIfProfileIterator. + struct DisplayIfProfileIteratorTag; + + typedef libwrapiter::ForwardIterator<DisplayIfProfileIteratorTag, + const std::string> DisplayIfProfileIterator; + + DisplayIfProfileIterator begin_display_if_profile() const; + + DisplayIfProfileIterator end_display_if_profile() const; + + ///\} + }; +} + +#endif diff --git a/0.8.0/paludis/repositories/portage/portage_repository_params.cc b/0.8.0/paludis/repositories/portage/portage_repository_params.cc new file mode 100644 index 000000000..d52072565 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_params.cc @@ -0,0 +1,8 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +#include "portage_repository_params.hh" + +using namespace paludis; + +#include <paludis/repositories/portage/portage_repository_params-sr.cc> + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_params.hh b/0.8.0/paludis/repositories/portage/portage_repository_params.hh new file mode 100644 index 000000000..538176680 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_params.hh @@ -0,0 +1,42 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_PARAMS_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_PARAMS_HH 1 + +#include <paludis/util/fs_entry.hh> +#include <paludis/util/collection.hh> +#include <paludis/util/sr.hh> + +/** \file + * Declaration for the PortageRepositoryParams class. + * + * \ingroup grpportagerepository + */ + +namespace paludis +{ + class Environment; + class PackageDatabase; + +#include <paludis/repositories/portage/portage_repository_params-sr.hh> + +} + +#endif diff --git a/0.8.0/paludis/repositories/portage/portage_repository_params.sr b/0.8.0/paludis/repositories/portage/portage_repository_params.sr new file mode 100644 index 000000000..61d2044dd --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_params.sr @@ -0,0 +1,34 @@ +#!/bin/bash +# vim: set sw=4 sts=4 et : + +make_class_PortageRepositoryParams() +{ + key entry_format std::string + key environment "const Environment *" + key package_database "const PackageDatabase *" + key location FSEntry + key profiles FSEntryCollection::ConstPointer + key cache FSEntry + key distdir FSEntry + key pkgdir FSEntry + key eclassdirs FSEntryCollection::ConstPointer + key setsdir FSEntry + key securitydir FSEntry + key newsdir FSEntry + key sync std::string + key sync_exclude std::string + key root FSEntry + key buildroot FSEntry + + doxygen_comment << "END" + /** + * Parameters used to create a PortageRepository + * + * \see PortageRepository + * \ingroup grpportagerepository + */ +END + + allow_named_args +} + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_profile.cc b/0.8.0/paludis/repositories/portage/portage_repository_profile.cc new file mode 100644 index 000000000..987973f9b --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_profile.cc @@ -0,0 +1,686 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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/portage/portage_repository_profile.hh> +#include <paludis/repositories/portage/portage_repository_profile_file.hh> +#include <paludis/repositories/portage/portage_repository_exceptions.hh> + +#include <paludis/util/log.hh> +#include <paludis/util/tokeniser.hh> +#include <paludis/util/iterator.hh> +#include <paludis/util/save.hh> + +#include <paludis/config_file.hh> +#include <paludis/environment.hh> +#include <paludis/match_package.hh> +#include <paludis/hashed_containers.hh> + +#include <list> +#include <algorithm> +#include <set> + +#include <strings.h> +#include <ctype.h> + +using namespace paludis; + +namespace paludis +{ + /** + * Implementation for PortageRepositoryProfile. + * + * \ingroup grpportagerepository + * \see PortageRepositoryProfile + */ + template<> + class Implementation<PortageRepositoryProfile> : + public InternalCounted<PortageRepositoryProfile> + { + public: + ///\name Convenience typedefs + ///\{ + + typedef MakeHashedMap<UseFlagName, UseFlagState>::Type UseMap; + typedef MakeHashedSet<UseFlagName>::Type UseFlagSet; + typedef MakeHashedMap<std::string, std::string>::Type EnvironmentVariablesMap; + typedef MakeHashedMap<QualifiedPackageName, + std::list<std::pair<PackageDepAtom::ConstPointer, UseFlagName> > >::Type PackageUseMaskMap; + typedef MakeHashedMap<QualifiedPackageName, PackageDepAtom::ConstPointer>::Type VirtualsMap; + typedef MakeHashedMap<QualifiedPackageName, std::list<PackageDepAtom::ConstPointer> >::Type PackageMaskMap; + + ///\} + + private: + void load_profile_directory_recursively(const FSEntry & dir); + void load_profile_parent(const FSEntry & dir); + void load_profile_make_defaults(const FSEntry & dir); + + void add_use_expand_to_use(); + void make_vars_from_file_vars(); + void handle_profile_arch_var(); + + ProfileFile use_mask_file; + ProfileFile package_use_mask_file; + ProfileFile use_force_file; + ProfileFile package_use_force_file; + ProfileFile packages_file; + ProfileFile virtuals_file; + ProfileFile package_mask_file; + + public: + ///\name General variables + ///\{ + + const Environment * const env; + + ///\} + + ///\name Use flags + ///\{ + + UseMap use; + UseFlagSet use_expand; + UseFlagSet use_expand_hidden; + UseFlagSet use_mask; + UseFlagSet use_force; + PackageUseMaskMap package_use_mask; + PackageUseMaskMap package_use_force; + + ///\} + + ///\name Environment variables + ///\{ + + EnvironmentVariablesMap environment_variables; + + ///\} + + ///\name System package set + ///\{ + + AllDepAtom::Pointer system_packages; + GeneralSetDepTag::Pointer system_tag; + + ///\} + + ///\name Virtuals + ///\{ + + VirtualsMap virtuals; + + ///\} + + ///\name Masks + ///\{ + + PackageMaskMap package_mask; + + ///\} + + ///\name Queries + ///\{ + + bool use_mask_or_force(const UseFlagName & u, const PackageDatabaseEntry * const e, + const std::string & mask_or_force, const UseFlagSet & global, + const PackageUseMaskMap & package) const; + + ///\} + + ///\name Basic operations + ///\{ + + Implementation(const Environment * const e, const FSEntryCollection & dirs) : + env(e), + system_packages(new AllDepAtom), + system_tag(new GeneralSetDepTag("system")) + { + for (FSEntryCollection::Iterator d(dirs.begin()), d_end(dirs.end()) ; + d != d_end ; ++d) + load_profile_directory_recursively(*d); + + add_use_expand_to_use(); + make_vars_from_file_vars(); + handle_profile_arch_var(); + } + + ~Implementation() + { + } + + ///\} + }; +} + +void +Implementation<PortageRepositoryProfile>::load_profile_directory_recursively(const FSEntry & dir) +{ + Context context("When adding profile directory '" + stringify(dir) + ":"); + Log::get_instance()->message(ll_debug, lc_context, "Loading profile directory '" + stringify(dir) + "'"); + + if (! dir.is_directory()) + { + Log::get_instance()->message(ll_warning, lc_context, + "Profile component '" + stringify(dir) + "' is not a directory"); + return; + } + + load_profile_parent(dir); + load_profile_make_defaults(dir); + + use_mask_file.add_file(dir / "use.mask"); + package_use_mask_file.add_file(dir / "package.use.mask"); + use_force_file.add_file(dir / "use.force"); + package_use_force_file.add_file(dir / "package.use.force"); + packages_file.add_file(dir / "packages"); + virtuals_file.add_file(dir / "virtuals"); + package_mask_file.add_file(dir / "package.mask"); +} + +void +Implementation<PortageRepositoryProfile>::load_profile_parent(const FSEntry & dir) +{ + Context context("When handling parent file for profile directory '" + stringify(dir) + ":"); + + if (! (dir / "parent").exists()) + return; + + LineConfigFile file(dir / "parent"); + + LineConfigFile::Iterator i(file.begin()), i_end(file.end()); + if (i == i_end) + Log::get_instance()->message(ll_warning, lc_context, "parent file is empty"); + else + for ( ; i != i_end ; ++i) + { + FSEntry parent_dir(dir); + do + { + try + { + parent_dir = (parent_dir / *i).realpath(); + } + catch (const FSError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Skipping parent '" + + *i + "' due to exception: " + e.message() + " (" + e.what() + ")"); + continue; + } + + load_profile_directory_recursively(parent_dir); + + } while (false); + } +} + +void +Implementation<PortageRepositoryProfile>::load_profile_make_defaults(const FSEntry & dir) +{ + Context context("When handling make.defaults file for profile directory '" + stringify(dir) + ":"); + + if (! (dir / "make.defaults").exists()) + return; + + KeyValueConfigFile file(dir / "make.defaults"); + + try + { + std::list<std::string> uses; + WhitespaceTokeniser::get_instance()->tokenise(file.get("USE"), std::back_inserter(uses)); + + for (std::list<std::string>::const_iterator u(uses.begin()), u_end(uses.end()) ; + u != u_end ; ++u) + if ('-' == u->at(0)) + use[UseFlagName(u->substr(1))] = use_disabled; + else + use[UseFlagName(*u)] = use_enabled; + } + catch (const NameError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Loading USE failed due to exception: " + + e.message() + " (" + e.what() + ")"); + } + + try + { + WhitespaceTokeniser::get_instance()->tokenise( + file.get("USE_EXPAND"), create_inserter<UseFlagName>( + std::inserter(use_expand, use_expand.begin()))); + } + catch (const NameError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Loading USE_EXPAND failed due to exception: " + + e.message() + " (" + e.what() + ")"); + } + + try + { + WhitespaceTokeniser::get_instance()->tokenise( + file.get("USE_EXPAND_HIDDEN"), create_inserter<UseFlagName>( + std::inserter(use_expand_hidden, use_expand_hidden.begin()))); + } + catch (const NameError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Loading USE_EXPAND_HIDDEN failed due to exception: " + + e.message() + " (" + e.what() + ")"); + } + + for (KeyValueConfigFile::Iterator k(file.begin()), k_end(file.end()) ; + k != k_end ; ++k) + { + Log::get_instance()->message(ll_debug, lc_context, "Profile environment variable '" + + stringify(k->first) + "' is '" + stringify(k->second) + "'"); + environment_variables[k->first] = k->second; + } +} + +void +Implementation<PortageRepositoryProfile>::make_vars_from_file_vars() +{ + try + { + Context context("When parsing use.mask:"); + std::copy(use_mask_file.begin(), use_mask_file.end(), create_inserter<UseFlagName>( + std::inserter(use_mask, use_mask.begin()))); + } + catch (const NameError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Loading use.mask " + " failed due to exception: " + stringify(e.message()) + " (" + e.what() + ")"); + } + + try + { + Context context("When parsing use.force:"); + std::copy(use_force_file.begin(), use_force_file.end(), create_inserter<UseFlagName>( + std::inserter(use_force, use_force.begin()))); + } + catch (const NameError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Loading use.force " + " failed due to exception: " + stringify(e.message()) + " (" + e.what() + ")"); + } + + try + { + Context context("When parsing package.use.mask:"); + + for (ProfileFile::Iterator line(package_use_mask_file.begin()), line_end(package_use_mask_file.end()) ; + line != line_end ; ++line) + { + std::list<std::string> tokens; + WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens)); + if (tokens.size() < 2) + continue; + + std::list<std::string>::const_iterator t(tokens.begin()), t_end(tokens.end()); + PackageDepAtom::ConstPointer d(new PackageDepAtom(*t++)); + QualifiedPackageName p(d->package()); + + PackageUseMaskMap::iterator i(package_use_mask.find(p)); + if (package_use_mask.end() == i) + i = package_use_mask.insert(std::make_pair(p, std::list<std::pair<PackageDepAtom::ConstPointer, + UseFlagName> >())).first; + + for ( ; t != t_end ; ++t) + { + if (0 == t->compare(0, 1, "-")) + { + UseFlagName r(t->substr(1)); + bool found(false); + for (std::list<std::pair<PackageDepAtom::ConstPointer, UseFlagName> >::iterator + e(i->second.begin()), e_end(i->second.end()) ; e != e_end ; ) + { + if (stringify(*e->first) == stringify(*d) && e->second == r) + { + found = true; + i->second.erase(e++); + } + else + ++e; + } + + if (! found) + Log::get_instance()->message(ll_qa, lc_context, "No match for '" + stringify(*line) + "'"); + } + else + i->second.push_back(std::make_pair(d, UseFlagName(*t))); + } + } + } + catch (const NameError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Loading package.use.mask " + " failed due to exception: " + stringify(e.message()) + " (" + e.what() + ")"); + } + + try + { + Context context("When parsing package.use.force:"); + + for (ProfileFile::Iterator line(package_use_force_file.begin()), line_end(package_use_force_file.end()) ; + line != line_end ; ++line) + { + std::list<std::string> tokens; + WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens)); + if (tokens.size() < 2) + continue; + + std::list<std::string>::const_iterator t(tokens.begin()), t_end(tokens.end()); + PackageDepAtom::ConstPointer d(new PackageDepAtom(*t++)); + QualifiedPackageName p(d->package()); + + PackageUseMaskMap::iterator i(package_use_force.find(p)); + if (package_use_force.end() == i) + i = package_use_force.insert(std::make_pair(p, std::list<std::pair<PackageDepAtom::ConstPointer, + UseFlagName> >())).first; + + for ( ; t != t_end ; ++t) + { + if (0 == t->compare(0, 1, "-")) + { + UseFlagName r(t->substr(1)); + bool found(false); + for (std::list<std::pair<PackageDepAtom::ConstPointer, UseFlagName> >::iterator + e(i->second.begin()), e_end(i->second.end()) ; e != e_end ; ) + { + if (stringify(*e->first) == stringify(*d) && e->second == r) + { + found = true; + i->second.erase(e++); + } + else + ++e; + } + + if (! found) + Log::get_instance()->message(ll_qa, lc_context, "No match for '" + stringify(*line) + "'"); + } + else + i->second.push_back(std::make_pair(d, UseFlagName(*t))); + } + } + } + catch (const NameError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Loading package.use.mask " + " failed due to exception: " + e.message() + " (" + e.what() + ")"); + } + + try + { + for (ProfileFile::Iterator i(packages_file.begin()), i_end(packages_file.end()) ; i != i_end ; ++i) + { + if (0 != i->compare(0, 1, "*", 0, 1)) + continue; + + Context context_atom("When parsing '" + *i + "':"); + PackageDepAtom::Pointer atom(new PackageDepAtom(i->substr(1))); + atom->set_tag(system_tag); + system_packages->add_child(atom); + } + } + catch (const NameError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Loading packages " + " failed due to exception: " + e.message() + " (" + e.what() + ")"); + } + + try + { + for (ProfileFile::Iterator line(virtuals_file.begin()), line_end(virtuals_file.end()) ; + line != line_end ; ++line) + { + std::vector<std::string> tokens; + WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens)); + if (tokens.size() < 2) + continue; + + QualifiedPackageName v(tokens[0]); + virtuals.erase(v); + virtuals.insert(std::make_pair(v, PackageDepAtom::Pointer(new PackageDepAtom(tokens[1])))); + } + } + catch (const NameError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Loading virtuals " + " failed due to exception: " + e.message() + " (" + e.what() + ")"); + } + + for (ProfileFile::Iterator line(package_mask_file.begin()), line_end(package_mask_file.end()) ; + line != line_end ; ++line) + { + if (line->empty()) + continue; + + try + { + PackageDepAtom::ConstPointer a(new PackageDepAtom(*line)); + package_mask[a->package()].push_back(a); + } + catch (const NameError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Loading package.mask atom '" + + stringify(*line) + "' failed due to exception '" + e.message() + "' (" + + e.what() + ")"); + } + } +} + +bool +Implementation<PortageRepositoryProfile>::use_mask_or_force( + const UseFlagName & u, const PackageDatabaseEntry * const e, const std::string & mask_or_force, + const UseFlagSet & global, const PackageUseMaskMap & package) const +{ + Context context("When querying profile use " + mask_or_force + " status of '" + stringify(u) + + (e ? "' for '" + stringify(*e) + "'" : "'")); + + if (global.end() != global.find(u)) + return true; + + if (0 == e) + return false; + + PackageUseMaskMap::const_iterator i(package.find(e->name)); + if (package.end() == i) + return false; + + for (std::list<std::pair<PackageDepAtom::ConstPointer, UseFlagName> >::const_iterator + j(i->second.begin()), j_end(i->second.end()) ; j != j_end ; ++j) + { + static int depth(0); + if (depth > 3) + { + Log::get_instance()->message(ll_warning, lc_context, + "depth > 3 on entry '" + stringify(*j->first) + "'"); + + if (j->first->use_requirements_ptr()) + continue; + if (u == j->second && match_package(env, j->first, e)) + return true; + } + else + { + Save<int> save_depth(&depth, depth + 1); + if (u == j->second && match_package(env, j->first, e)) + return true; + } + } + + return false; +} + +void +Implementation<PortageRepositoryProfile>::add_use_expand_to_use() +{ + Context context("When adding USE_EXPAND to USE:"); + + for (UseFlagSet::const_iterator x(use_expand.begin()), x_end(use_expand.end()) ; + x != x_end ; ++x) + { + std::string lower_x; + std::transform(x->data().begin(), x->data().end(), std::back_inserter(lower_x), + &::tolower); + + std::list<std::string> uses; + WhitespaceTokeniser::get_instance()->tokenise(environment_variables[stringify(*x)], + std::back_inserter(uses)); + for (std::list<std::string>::const_iterator u(uses.begin()), u_end(uses.end()) ; + u != u_end ; ++u) + use[UseFlagName(lower_x + "_" + *u)] = use_enabled; + } +} + +void +Implementation<PortageRepositoryProfile>::handle_profile_arch_var() +{ + Context context("When handling profile ARCH variable:"); + + std::string arch_s(environment_variables["ARCH"]); + if (arch_s.empty()) + throw PortageRepositoryConfigurationError("ARCH variable is unset or empty"); + + try + { + UseFlagName arch(arch_s); + + use[arch] = use_enabled; + use_force.insert(arch); + if (use_mask.end() != use_mask.find(arch)) + throw PortageRepositoryConfigurationError("ARCH USE '" + arch_s + "' is use masked"); + } + catch (const NameError & e) + { + throw PortageRepositoryConfigurationError("ARCH variable has invalid value '" + arch_s + "'"); + } +} + +PortageRepositoryProfile::PortageRepositoryProfile( + const Environment * const env, const FSEntryCollection & location) : + PrivateImplementationPattern<PortageRepositoryProfile>( + new Implementation<PortageRepositoryProfile>(env, location)) +{ +} + +PortageRepositoryProfile::~PortageRepositoryProfile() +{ +} + +bool +PortageRepositoryProfile::use_masked(const UseFlagName & u, + const PackageDatabaseEntry * const e) const +{ + return _imp->use_mask_or_force(u, e, "mask", _imp->use_mask, _imp->package_use_mask); +} + +bool +PortageRepositoryProfile::use_forced(const UseFlagName & u, + const PackageDatabaseEntry * const e) const +{ + return _imp->use_mask_or_force(u, e, "force", _imp->use_force, _imp->package_use_force); +} + +UseFlagState +PortageRepositoryProfile::use_state_ignoring_masks(const UseFlagName & u) const +{ + Implementation<PortageRepositoryProfile>::UseMap::const_iterator p(_imp->use.find(u)); + if (_imp->use.end() == p) + return use_unspecified; + return p->second; +} + +std::string +PortageRepositoryProfile::environment_variable(const std::string & s) const +{ + Implementation<PortageRepositoryProfile>::EnvironmentVariablesMap::const_iterator i( + _imp->environment_variables.find(s)); + if (_imp->environment_variables.end() == i) + { + Log::get_instance()->message(ll_debug, lc_no_context, "Environment variable '" + s + "' is unset"); + return ""; + } + else + { + Log::get_instance()->message(ll_debug, lc_no_context, "Environment variable '" + s + + "' is '" + i->second + "'"); + return i->second; + } +} + +AllDepAtom::Pointer +PortageRepositoryProfile::system_packages() const +{ + return _imp->system_packages; +} + +PortageRepositoryProfile::UseExpandIterator +PortageRepositoryProfile::begin_use_expand() const +{ + return UseExpandIterator(_imp->use_expand.begin()); +} + +PortageRepositoryProfile::UseExpandIterator +PortageRepositoryProfile::end_use_expand() const +{ + return UseExpandIterator(_imp->use_expand.end()); +} + +PortageRepositoryProfile::UseExpandIterator +PortageRepositoryProfile::begin_use_expand_hidden() const +{ + return UseExpandIterator(_imp->use_expand_hidden.begin()); +} + +PortageRepositoryProfile::UseExpandIterator +PortageRepositoryProfile::end_use_expand_hidden() const +{ + return UseExpandIterator(_imp->use_expand_hidden.end()); +} + +PortageRepositoryProfile::VirtualsIterator +PortageRepositoryProfile::begin_virtuals() const +{ + return VirtualsIterator(_imp->virtuals.begin()); +} + +PortageRepositoryProfile::VirtualsIterator +PortageRepositoryProfile::end_virtuals() const +{ + return VirtualsIterator(_imp->virtuals.end()); +} + +bool +PortageRepositoryProfile::profile_masked(const QualifiedPackageName & n, + const VersionSpec & v, const RepositoryName & r) const +{ + Implementation<PortageRepositoryProfile>::PackageMaskMap::const_iterator rr( + _imp->package_mask.find(n)); + if (_imp->package_mask.end() == rr) + return false; + else + { + PackageDatabaseEntry dbe(n, v, r); + for (std::list<PackageDepAtom::ConstPointer>::const_iterator k(rr->second.begin()), + k_end(rr->second.end()) ; k != k_end ; ++k) + if (match_package(_imp->env, **k, dbe)) + return true; + } + + return false; +} + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_profile.hh b/0.8.0/paludis/repositories/portage/portage_repository_profile.hh new file mode 100644 index 000000000..c1520dd32 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_profile.hh @@ -0,0 +1,125 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_PROFILE_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_PROFILE_HH 1 + +#include <paludis/dep_atom.hh> +#include <paludis/package_database_entry.hh> +#include <paludis/util/fs_entry.hh> +#include <paludis/util/private_implementation_pattern.hh> +#include <paludis/util/instantiation_policy.hh> + +#include <libwrapiter/libwrapiter_forward_iterator.hh> +#include <string> + +/** \file + * Declaration for the PortageRepositoryProfile class. + * + * \ingroup grpportagerepository + */ + +namespace paludis +{ + class Environment; + + /** + * Holds the profile data (but <em>not</em> the profiles/ top level data) for + * a PortageRepository instance. + * + * \ingroup grpportagerepository + */ + class PALUDIS_VISIBLE PortageRepositoryProfile : + private PrivateImplementationPattern<PortageRepositoryProfile>, + private InstantiationPolicy<PortageRepositoryProfile, instantiation_method::NonCopyableTag>, + public InternalCounted<PortageRepositoryProfile> + { + public: + ///\name Basic operations + ///\{ + + PortageRepositoryProfile(const Environment * const env, const FSEntryCollection & location); + ~PortageRepositoryProfile(); + + ///\} + + ///\name Use flag queries + ///\{ + + /// Is a use flag masked? + bool use_masked(const UseFlagName &, const PackageDatabaseEntry * const) const; + + /// Is a use flag forced? + bool use_forced(const UseFlagName &, const PackageDatabaseEntry * const) const; + + /// Use flag state, ignoring mask and force? + UseFlagState use_state_ignoring_masks(const UseFlagName &) const; + + ///\} + + ///\name Iterate over USE_EXPAND, USE_EXPAND_HIDDEN + ///\{ + + typedef libwrapiter::ForwardIterator<PortageRepositoryProfile, const UseFlagName> UseExpandIterator; + + UseExpandIterator begin_use_expand() const; + UseExpandIterator end_use_expand() const; + UseExpandIterator begin_use_expand_hidden() const; + UseExpandIterator end_use_expand_hidden() const; + + ///\} + + ///\name Environment variable queries + ///\{ + + /// What is the value of an environment variable? + std::string environment_variable(const std::string &) const; + + ///\} + + ///\name Masks + ///\{ + + bool profile_masked(const QualifiedPackageName &, const VersionSpec &, + const RepositoryName &) const; + + ///\} + + ///\name System package set + ///\{ + + AllDepAtom::Pointer system_packages() const; + + ///\} + + ///\name Virtuals + ///\{ + + typedef libwrapiter::ForwardIterator<PortageRepositoryProfile, + const std::pair<const QualifiedPackageName, PackageDepAtom::ConstPointer> > VirtualsIterator; + + VirtualsIterator begin_virtuals() const; + VirtualsIterator end_virtuals() const; + VirtualsIterator find_virtual() const; + + ///\} + }; +} + +#endif diff --git a/0.8.0/paludis/repositories/portage/portage_repository_profile_file.cc b/0.8.0/paludis/repositories/portage/portage_repository_profile_file.cc new file mode 100644 index 000000000..1301e0e80 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_profile_file.cc @@ -0,0 +1,81 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 "portage_repository_profile_file.hh" +#include <paludis/util/log.hh> +#include <paludis/config_file.hh> +#include <list> + +using namespace paludis; + +namespace paludis +{ + template <> + struct Implementation<ProfileFile> : + InternalCounted<Implementation<ProfileFile> > + { + std::list<std::string> lines; + }; +} + +void +ProfileFile::add_file(const FSEntry & f) +{ + Context context("When adding profile configuration file '" + stringify(f) + "':"); + + if (! f.exists()) + return; + + LineConfigFile file(f); + for (LineConfigFile::Iterator line(file.begin()), line_end(file.end()) ; line != line_end ; ++line) + { + if (0 == line->compare(0, 1, "-", 0, 1)) + { + std::list<std::string>::iterator i(std::find(_imp->lines.begin(), _imp->lines.end(), line->substr(1))); + if (_imp->lines.end() == i) + Log::get_instance()->message(ll_qa, lc_context, "No match for '" + *line + "'"); + else + _imp->lines.erase(i); + } + else + _imp->lines.push_back(*line); + } +} + +ProfileFile::ProfileFile() : + PrivateImplementationPattern<ProfileFile>(new Implementation<ProfileFile>) +{ +} + +ProfileFile::~ProfileFile() +{ +} + +ProfileFile::Iterator +ProfileFile::begin() const +{ + return Iterator(_imp->lines.begin()); +} + +ProfileFile::Iterator +ProfileFile::end() const +{ + return Iterator(_imp->lines.end()); +} + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_profile_file.hh b/0.8.0/paludis/repositories/portage/portage_repository_profile_file.hh new file mode 100644 index 000000000..2cda5ed2c --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_profile_file.hh @@ -0,0 +1,45 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_PROFILE_FILE_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_PROFILE_FILE_HH 1 + +#include <paludis/util/private_implementation_pattern.hh> +#include <paludis/util/attributes.hh> +#include <paludis/util/fs_entry.hh> +#include <libwrapiter/libwrapiter_forward_iterator.hh> + +namespace paludis +{ + class PALUDIS_VISIBLE ProfileFile : + private PrivateImplementationPattern<ProfileFile> + { + public: + ProfileFile(); + ~ProfileFile(); + + void add_file(const FSEntry &); + + typedef libwrapiter::ForwardIterator<ProfileFile, const std::string> Iterator; + Iterator begin() const; + Iterator end() const; + }; +} + +#endif diff --git a/0.8.0/paludis/repositories/portage/portage_repository_sets.cc b/0.8.0/paludis/repositories/portage/portage_repository_sets.cc new file mode 100644 index 000000000..91262639c --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_sets.cc @@ -0,0 +1,379 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * Copyright (c) 2006 Danny van Dyk <kugelfang@gentoo.org> + * + * 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/portage/portage_repository.hh> +#include <paludis/repositories/portage/portage_repository_sets.hh> +#include <paludis/repositories/portage/glsa.hh> + +#include <paludis/dep_list.hh> +#include <paludis/environment.hh> +#include <paludis/config_file.hh> +#include <paludis/portage_dep_parser.hh> +#include <paludis/util/collection_concrete.hh> +#include <paludis/util/dir_iterator.hh> +#include <paludis/util/fs_entry.hh> +#include <paludis/util/is_file_with_extension.hh> +#include <paludis/util/log.hh> +#include <paludis/util/tokeniser.hh> + +#include <list> +#include <set> + +#include "config.h" + +using namespace paludis; + +namespace paludis +{ + /** + * Implementation data for PortageRepositorySets. + * + * \ingroup grpportagerepository + */ + template<> + struct Implementation<PortageRepositorySets> : + InternalCounted<Implementation<PortageRepositorySets> > + { + const Environment * const environment; + const PortageRepository * const portage_repository; + const PortageRepositoryParams params; + + Implementation(const Environment * const e, const PortageRepository * const p, + const PortageRepositoryParams & k) : + environment(e), + portage_repository(p), + params(k) + { + } + }; +} + +PortageRepositorySets::PortageRepositorySets(const Environment * const e, const PortageRepository * const p, + const PortageRepositoryParams & k) : + PrivateImplementationPattern<PortageRepositorySets>(new Implementation<PortageRepositorySets>(e, p, k)) +{ +} + +PortageRepositorySets::~PortageRepositorySets() +{ +} + + +DepAtom::Pointer +PortageRepositorySets::package_set(const std::string & s) const +{ + if ("system" == s) + throw InternalError(PALUDIS_HERE, "system set should've been handled by PortageRepository"); + else if ("security" == s) + return security_set(false); + else if ("insecurity" == s) + return security_set(true); + else if ((_imp->params.setsdir / (s + ".conf")).exists()) + { + GeneralSetDepTag::Pointer tag(new GeneralSetDepTag(s)); + + FSEntry ff(_imp->params.setsdir / (s + ".conf")); + Context context("When loading package set '" + s + "' from '" + stringify(ff) + "':"); + + AllDepAtom::Pointer result(new AllDepAtom); + LineConfigFile f(ff); + for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ; + line != line_end ; ++line) + { + std::vector<std::string> tokens; + WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens)); + if (tokens.empty()) + continue; + + if (1 == tokens.size()) + { + Log::get_instance()->message(ll_warning, lc_context, + "Line '" + *line + "' in set file '" + + stringify(ff) + "' does not specify '*' or '?', assuming '*'"); + PackageDepAtom::Pointer atom(new PackageDepAtom(tokens.at(0))); + atom->set_tag(tag); + result->add_child(atom); + } + else if ("*" == tokens.at(0)) + { + PackageDepAtom::Pointer atom(new PackageDepAtom(tokens.at(1))); + atom->set_tag(tag); + result->add_child(atom); + } + else if ("?" == tokens.at(0)) + { + PackageDepAtom::Pointer p(new PackageDepAtom(tokens.at(1))); + p->set_tag(tag); + if (! _imp->environment->package_database()->query( + PackageDepAtom::Pointer(new PackageDepAtom(p->package())), + is_installed_only)->empty()) + result->add_child(p); + } + else + Log::get_instance()->message(ll_warning, lc_context, + "Line '" + *line + "' in set file '" + + stringify(ff) + "' does not start with '*' or '?' token, skipping"); + + if (tokens.size() > 2) + Log::get_instance()->message(ll_warning, lc_context, + "Line '" + *line + "' in set file '" + + stringify(ff) + "' has trailing garbage"); + } + + return result; + } + else + return DepAtom::Pointer(0); +} + +SetsCollection::ConstPointer +PortageRepositorySets::sets_list() const +{ + Context context("While generating the list of sets:"); + + SetsCollection::Pointer result(new SetsCollection::Concrete); + result->insert("security"); + result->insert("system"); + + /* + * TODO: get rid of unnecessary copying and just put this in a for loop + * (need to read some doxygen pages on FSEntry first) + */ + try + { + std::list<FSEntry> repo_sets; + std::copy(DirIterator(_imp->params.setsdir), DirIterator(), + filter_inserter(std::back_inserter(repo_sets), + IsFileWithExtension(".conf"))); + + std::list<FSEntry>::const_iterator f(repo_sets.begin()), + f_end(repo_sets.end()); + + for ( ; f != f_end ; ++f) + result->insert(stringify(*f)); + } + catch (const paludis::DirOpenError & e) + { + } + + return result; +} + +namespace +{ + inline + PackageDepAtom::Pointer make_atom(const PackageDatabaseEntry & e) + { + QualifiedPackageName n(e.name); + VersionSpec v(e.version); + + std::string s("=" + stringify(n) + "-" + stringify(v)); + return PackageDepAtom::Pointer(new PackageDepAtom(s)); + } +} + +PackageDatabaseEntryCollection::Iterator +PortageRepositorySets::find_best(PackageDatabaseEntryCollection & c, const PackageDatabaseEntry & e) const +{ + Context local("When finding best update for '" + stringify(e.name) + "-" + + stringify(e.version) + "':"); + // Find an entry in c that matches e best. e is not in c. + QualifiedPackageName n(e.name); + SlotName s(_imp->environment->package_database()->fetch_repository( + e.repository)->version_metadata(e.name, e.version)->slot); + PackageDatabaseEntryCollection::Iterator i(c.begin()), i_end(c.end()), i_best(c.end()); + for ( ; i != i_end; ++i) + { + if (n != i->name) + continue; + if (s != _imp->environment->package_database()->fetch_repository( + i->repository)->version_metadata( + i->name, i->version)->slot) + continue; + + i_best = i; + } + + return i_best; +} + +namespace +{ + bool + match_range(const PackageDatabaseEntry & e, const GLSARange & r) + { + VersionOperatorValue our_op(static_cast<VersionOperatorValue>(-1)); + std::string ver(r.version); + if (r.op == "le") + our_op = vo_less_equal; + if (r.op == "lt") + our_op = vo_less; + if (r.op == "eq") + { + if (! ver.empty() && '*' == ver.at(ver.length() - 1)) + { + ver.erase(ver.length() - 1); + our_op = vo_equal_star; + } + else + our_op = vo_equal; + } + if (r.op == "gt") + our_op = vo_greater; + if (r.op == "ge") + our_op = vo_greater_equal; + + if (-1 != our_op) + return (e.version.*(VersionOperator(our_op).as_version_spec_operator()))(VersionSpec(ver)); + + if (0 == r.op.compare(0, 1, "r")) + { + return (e.version.*(VersionOperator(vo_tilde).as_version_spec_operator()))(VersionSpec(ver)) && + match_range(e, GLSARange::create().op(r.op.substr(1)).version(r.version)); + } + + throw GLSAError("Got bad op '" + r.op + "'"); + } + + bool + is_vulnerable(const GLSAPackage & glsa_pkg, const PackageDatabaseEntry & c) + { + /* a package is affected if it matches any vulnerable line, except if it matches + * any unaffected line. */ + bool vulnerable(false); + for (GLSAPackage::RangesIterator r(glsa_pkg.begin_vulnerable()), r_end(glsa_pkg.end_vulnerable()) ; + r != r_end && ! vulnerable ; ++r) + if (match_range(c, *r)) + vulnerable = true; + + if (! vulnerable) + return false; + + for (GLSAPackage::RangesIterator r(glsa_pkg.begin_unaffected()), r_end(glsa_pkg.end_unaffected()) ; + r != r_end && vulnerable ; ++r) + if (match_range(c, *r)) + vulnerable = false; + + return vulnerable; + } +} + +DepAtom::Pointer +PortageRepositorySets::security_set(bool insecurity) const +{ + Context context("When building security or insecurity package set:"); + AllDepAtom::Pointer security_packages(new AllDepAtom); + + if (!_imp->params.securitydir.is_directory()) + return security_packages; + + std::map<std::string, GLSADepTag::Pointer> glsa_tags; + + for (DirIterator f(_imp->params.securitydir), f_end ; f != f_end; ++f) + { + if (! IsFileWithExtension("glsa-", ".xml")(*f)) + continue; + + Context local_context("When parsing security advisory '" + stringify(*f) + "':"); + + try + { + GLSA::ConstPointer glsa(GLSA::create_from_xml_file(stringify(*f))); + Context local_local_context("When handling GLSA '" + glsa->id() + "' from '" + + stringify(*f) + "':"); + + for (GLSA::PackagesIterator glsa_pkg(glsa->begin_packages()), + glsa_pkg_end(glsa->end_packages()) ; glsa_pkg != glsa_pkg_end ; ++glsa_pkg) + { + PackageDatabaseEntryCollection::ConstPointer candidates(_imp->environment->package_database()->query( + PackageDepAtom::Pointer(new PackageDepAtom(stringify(glsa_pkg->name()))), + insecurity ? is_either : is_installed_only)); + for (PackageDatabaseEntryCollection::Iterator c(candidates->begin()), c_end(candidates->end()) ; + c != c_end ; ++c) + { + if (! is_vulnerable(*glsa_pkg, *c)) + continue; + + if (glsa_tags.end() == glsa_tags.find(glsa->id())) + glsa_tags.insert(std::make_pair(glsa->id(), GLSADepTag::Pointer( + new GLSADepTag(glsa->id(), glsa->title())))); + + if (insecurity) + { + PackageDepAtom::Pointer atom(new PackageDepAtom( + "=" + stringify(c->name) + "-" + stringify(c->version) + + "::" + stringify(c->repository))); + atom->set_tag(glsa_tags.find(glsa->id())->second); + security_packages->add_child(atom); + } + else + { + /* we need to find the best not vulnerable installable package that isn't masked + * that's in the same slot as our vulnerable installed package. */ + bool ok(false); + SlotName wanted_slot(_imp->environment->package_database()->fetch_repository( + c->repository)->version_metadata(c->name, c->version)->slot); + + PackageDatabaseEntryCollection::ConstPointer available( + _imp->environment->package_database()->query(PackageDepAtom::Pointer( + new PackageDepAtom(stringify(glsa_pkg->name()))), is_uninstalled_only)); + for (PackageDatabaseEntryCollection::ReverseIterator r(available->rbegin()), + r_end(available->rend()) ; r != r_end ; ++r) + { + if (_imp->environment->mask_reasons(*r).any()) + continue; + if (_imp->environment->package_database()->fetch_repository(r->repository)->version_metadata( + r->name, r->version)->slot != wanted_slot) + continue; + if (is_vulnerable(*glsa_pkg, *r)) + continue; + + PackageDepAtom::Pointer atom(new PackageDepAtom( + "=" + stringify(r->name) + "-" + stringify(r->version) + + "::" + stringify(r->repository))); + atom->set_tag(glsa_tags.find(glsa->id())->second); + security_packages->add_child(atom); + ok = true; + break; + } + + if (! ok) + throw GLSAError("Could not determine upgrade path to resolve '" + + glsa->id() + ": " + glsa->title() + "' for package '" + + stringify(*c) + "'"); + } + } + } + } + catch (const GLSAError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Cannot use GLSA '" + + stringify(*f) + "' due to exception '" + e.message() + "' (" + e.what() + ")"); + } + catch (const NameError & e) + { + Log::get_instance()->message(ll_warning, lc_context, "Cannot use GLSA '" + + stringify(*f) + "' due to exception '" + e.message() + "' (" + e.what() + ")"); + } + } + + return security_packages; +} + diff --git a/0.8.0/paludis/repositories/portage/portage_repository_sets.hh b/0.8.0/paludis/repositories/portage/portage_repository_sets.hh new file mode 100644 index 000000000..85b361b8f --- /dev/null +++ b/0.8.0/paludis/repositories/portage/portage_repository_sets.hh @@ -0,0 +1,80 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * Copyright (c) 2006 Danny van Dyk <kugelfang@gentoo.org> + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_SETS_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_SETS_HH 1 + +#include <paludis/dep_atom.hh> +#include <paludis/repository.hh> + +/** \file + * Declaration for the PortageRepositorySets class. + * + * \ingroup grpportagerepository + */ + +namespace paludis +{ + class Environment; + class PortageRepository; + + /** + * Holds the information about sets, except system, for a PortageRepository. + * + * \ingroup grpportagerepository + */ + class PALUDIS_VISIBLE PortageRepositorySets : + private PrivateImplementationPattern<PortageRepositorySets>, + private InstantiationPolicy<PortageRepositorySets, instantiation_method::NonCopyableTag>, + public InternalCounted<PortageRepositorySets> + { + private: + PackageDatabaseEntryCollection::Iterator + find_best(PackageDatabaseEntryCollection & c, const PackageDatabaseEntry & e) const; + + public: + ///\name Basic operations + ///\{ + + PortageRepositorySets(const Environment * const env, const PortageRepository * const, + const PortageRepositoryParams &); + ~PortageRepositorySets(); + + ///\} + + /** + * Fetch a package set other than system. + */ + DepAtom::Pointer package_set(const std::string & s) const; + + /** + * Fetch the security or insecurity set. + */ + DepAtom::Pointer security_set(bool insecure) const; + + /** + * Give a list of all the sets in this repo. + */ + SetsCollection::ConstPointer sets_list() const; + }; +} + + +#endif diff --git a/0.8.0/paludis/repositories/portage/xml_things.cc b/0.8.0/paludis/repositories/portage/xml_things.cc new file mode 100644 index 000000000..bfca7710c --- /dev/null +++ b/0.8.0/paludis/repositories/portage/xml_things.cc @@ -0,0 +1,188 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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 <libxml/tree.h> +#include <libxml/parser.h> +#include <paludis/repositories/portage/glsa.hh> +#include <paludis/util/tokeniser.hh> +#include <paludis/config_file.hh> +#include <paludis/libxml/libxml.hh> +#include <set> + +using namespace paludis; + +extern "C" +{ + GLSA::Pointer create_glsa_from_xml_file(const std::string &); +} + +namespace +{ + class Handler + { + private: + GLSA::Pointer _glsa; + + public: + Handler() : + _glsa(new GLSA) + { + } + + void handle_glsa_attrs(xmlDocPtr doc, xmlAttr * const attr) + { + for (xmlAttr * a(attr) ; a ; a = a->next) + { + if (a->type == XML_ATTRIBUTE_NODE) + { + std::string name(retarded_libxml_string_to_string(a->name)); + if (name == "id") + _glsa->set_id(normalise(retarded_libxml_string_to_string(xmlNodeListGetString(doc, + a->xmlChildrenNode, 1)))); + } + } + } + + void handle_package_name(xmlDocPtr doc, xmlAttr * const attr, std::string & str) + { + for (xmlAttr * a(attr) ; a ; a = a->next) + { + if (a->type == XML_ATTRIBUTE_NODE) + { + std::string name(retarded_libxml_string_to_string(a->name)); + if (name == "name") + str = normalise(retarded_libxml_string_to_string(xmlNodeListGetString(doc, + a->xmlChildrenNode, 1))); + } + } + } + + void handle_package_archs(xmlDocPtr doc, xmlAttr * const attr, GLSAPackage::Pointer pkg) + { + for (xmlAttr * a(attr) ; a ; a = a->next) + { + if (a->type == XML_ATTRIBUTE_NODE) + { + std::string name(retarded_libxml_string_to_string(a->name)); + if (name == "arch") + { + std::set<std::string> archs; + WhitespaceTokeniser::get_instance()->tokenise(retarded_libxml_string_to_string( + xmlNodeListGetString(doc, a->xmlChildrenNode, 1)), + std::inserter(archs, archs.end())); + archs.erase("*"); + for (std::set<std::string>::const_iterator r(archs.begin()), r_end(archs.end()) ; + r != r_end ; ++r) + pkg->add_arch(UseFlagName(*r)); + } + } + } + } + + void handle_range_range(xmlDocPtr doc, xmlAttr * const attr, std::string & op) + { + for (xmlAttr * a(attr) ; a ; a = a->next) + { + if (a->type == XML_ATTRIBUTE_NODE) + { + std::string name(retarded_libxml_string_to_string(a->name)); + if (name == "range") + op = normalise(retarded_libxml_string_to_string(xmlNodeListGetString(doc, + a->xmlChildrenNode, 1))); + } + } + } + + void handle_package_children(xmlDocPtr doc, xmlNode * const node, GLSAPackage::Pointer pkg) + { + for (xmlNode * n(node) ; n ; n = n->next) + { + if (n->type == XML_ELEMENT_NODE) + { + std::string name(retarded_libxml_string_to_string(n->name)); + if (name == "unaffected" || name == "vulnerable") + { + std::string op; + handle_range_range(doc, n->properties, op); + std::string version(normalise(retarded_libxml_string_to_string( + xmlNodeListGetString(doc, n->xmlChildrenNode, 1)))); + ((*pkg).*(name == "unaffected" ? &GLSAPackage::add_unaffected : &GLSAPackage::add_vulnerable)) + (GLSARange::create().op(op).version(version)); + } + else + handle_node(doc, n->children); + } + else + handle_node(doc, n->children); + } + + } + + void handle_node(xmlDocPtr doc, xmlNode * const node) + { + for (xmlNode * n(node) ; n ; n = n->next) + { + if (n->type == XML_ELEMENT_NODE) + { + std::string name(retarded_libxml_string_to_string(n->name)); + if (name == "glsa") + { + handle_glsa_attrs(doc, n->properties); + handle_node(doc, n->children); + } + else if (name == "title") + _glsa->set_title(normalise(retarded_libxml_string_to_string(xmlNodeListGetString(doc, + n->xmlChildrenNode, 1)))); + else if (name == "package") + { + std::string name; + handle_package_name(doc, n->properties, name); + GLSAPackage::Pointer pkg(new GLSAPackage(QualifiedPackageName(name))); + handle_package_archs(doc, n->properties, pkg); + handle_package_children(doc, n->children, pkg); + _glsa->add_package(pkg); + } + else + handle_node(doc, n->children); + } + else + handle_node(doc, n->children); + } + + } + + GLSA::Pointer glsa() + { + return _glsa; + } + }; +} + +GLSA::Pointer +create_glsa_from_xml_file(const std::string & filename) +{ + LibXmlPtrHolder<xmlDocPtr> xml_doc(xmlReadFile(filename.c_str(), 0, 0), &xmlFreeDoc); + if (! xml_doc) + throw GLSAError("Could not parse GLSA", filename); + + Handler h; + h.handle_node(xml_doc, xmlDocGetRootElement(xml_doc)); + return h.glsa(); +} + diff --git a/0.8.0/paludis/repositories/portage/xml_things_TEST.cc b/0.8.0/paludis/repositories/portage/xml_things_TEST.cc new file mode 100644 index 000000000..748fc0836 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/xml_things_TEST.cc @@ -0,0 +1,92 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org> + * + * 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/portage/glsa.hh> +#include <paludis/util/join.hh> +#include <test/test_framework.hh> +#include <test/test_runner.hh> + +using namespace test; +using namespace paludis; + +namespace test_cases +{ + struct GLSA123456_78Test : TestCase + { + GLSA123456_78Test() : TestCase("glsa 123456-78") { } + + void run() + { + GLSA::Pointer glsa(GLSA::create_from_xml_file("xml_things_TEST_dir/glsa-123456-78.xml")); + TEST_CHECK(glsa); + + TEST_CHECK_EQUAL("123456-78", glsa->id()); + TEST_CHECK_EQUAL("Kittens: Too Adorable", glsa->title()); + + TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages(), glsa->end_packages())); + TEST_CHECK_STRINGIFY_EQUAL("animal-feline/kitten", glsa->begin_packages()->name()); + TEST_CHECK_STRINGIFY_EQUAL("0", std::distance(glsa->begin_packages()->begin_archs(), + glsa->begin_packages()->end_archs())); + + TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages()->begin_unaffected(), + glsa->begin_packages()->end_unaffected())); + TEST_CHECK_STRINGIFY_EQUAL("ge", glsa->begin_packages()->begin_unaffected()->op); + TEST_CHECK_STRINGIFY_EQUAL("1.23", glsa->begin_packages()->begin_unaffected()->version); + + TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages(), glsa->end_packages())); + TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages()->begin_vulnerable(), + glsa->begin_packages()->end_vulnerable())); + TEST_CHECK_STRINGIFY_EQUAL("lt", glsa->begin_packages()->begin_vulnerable()->op); + TEST_CHECK_STRINGIFY_EQUAL("1.22", glsa->begin_packages()->begin_vulnerable()->version); + } + } glsa_test_123456_78; + + struct GLSA987654_32Test : TestCase + { + GLSA987654_32Test() : TestCase("glsa 987654-32") { } + + void run() + { + GLSA::Pointer glsa(GLSA::create_from_xml_file("xml_things_TEST_dir/glsa-987654-32.xml")); + TEST_CHECK(glsa); + + TEST_CHECK_EQUAL("987654-32", glsa->id()); + TEST_CHECK_EQUAL("Python: Retarded", glsa->title()); + + TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages(), glsa->end_packages())); + TEST_CHECK_STRINGIFY_EQUAL("dev-lang/python", glsa->begin_packages()->name()); + TEST_CHECK_STRINGIFY_EQUAL("3", std::distance(glsa->begin_packages()->begin_archs(), + glsa->begin_packages()->end_archs())); + TEST_CHECK_STRINGIFY_EQUAL("mips,sparc,x86", join(glsa->begin_packages()->begin_archs(), + glsa->begin_packages()->end_archs(), ",")); + + TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages()->begin_unaffected(), + glsa->begin_packages()->end_unaffected())); + TEST_CHECK_STRINGIFY_EQUAL("ge", glsa->begin_packages()->begin_unaffected()->op); + TEST_CHECK_STRINGIFY_EQUAL("12.34", glsa->begin_packages()->begin_unaffected()->version); + + TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages(), glsa->end_packages())); + TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages()->begin_vulnerable(), + glsa->begin_packages()->end_vulnerable())); + TEST_CHECK_STRINGIFY_EQUAL("lt", glsa->begin_packages()->begin_vulnerable()->op); + TEST_CHECK_STRINGIFY_EQUAL("12.34", glsa->begin_packages()->begin_vulnerable()->version); + } + } glsa_test_987654_32; +} + diff --git a/0.8.0/paludis/repositories/portage/xml_things_TEST_cleanup.sh b/0.8.0/paludis/repositories/portage/xml_things_TEST_cleanup.sh new file mode 100755 index 000000000..5e0843fa2 --- /dev/null +++ b/0.8.0/paludis/repositories/portage/xml_things_TEST_cleanup.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# vim: set ft=sh sw=4 sts=4 et : + +if [ -d xml_things_TEST_dir ] ; then + rm -fr xml_things_TEST_dir +else + true +fi + + + diff --git a/0.8.0/paludis/repositories/portage/xml_things_TEST_setup.sh b/0.8.0/paludis/repositories/portage/xml_things_TEST_setup.sh new file mode 100755 index 000000000..530af804b --- /dev/null +++ b/0.8.0/paludis/repositories/portage/xml_things_TEST_setup.sh @@ -0,0 +1,115 @@ +#!/bin/bash +# vim: set ft=sh sw=4 sts=4 et : + +mkdir xml_things_TEST_dir || exit 1 +cd xml_things_TEST_dir || exit 1 + +cat <<"END" > glsa-123456-78.xml +<?xml version="1.0" encoding="utf-8"?> +<?xml-stylesheet href="/xsl/glsa.xsl" type="text/xsl"?> +<?xml-stylesheet href="/xsl/guide.xsl" type="text/xsl"?> +<!DOCTYPE glsa SYSTEM "http://www.gentoo.org/dtd/glsa.dtd"> + +<glsa id="123456-78"> + <title> + Kittens: Too Adorable + </title> + <synopsis> + Kittens are too adorable. This can lead to excess cuteness. + </synopsis> + <product type="ebuild">kitten</product> + <announced>October 10, 2006</announced> + <revised>October 10, 2006: 01</revised> + <bug>123456</bug> + <access>remote</access> + <affected> + <package name="animal-feline/kitten" auto="yes" arch="*"> + <unaffected range="ge">1.23</unaffected> + <vulnerable range="lt">1.22</vulnerable> + </package> + </affected> + <background> + <p> + Kittens are small cats. + </p> + </background> + <description> + <p> + By being adorable, kittens can get away with too much misbehaviour. + </p> + </description> + <impact type="high"> + <p> + A kitten could get away with going undrowned because of its adorableness. + </p> + </impact> + <workaround> + <p> + There is no known workaround at this time. + </p> + </workaround> + <resolution> + <p> + All kitten users should upgrade to the latest version. + </p> + </resolution> + <references> + </references> +</glsa> +END + +cat <<"END" > glsa-987654-32.xml +<?xml version="1.0" encoding="utf-8"?> +<?xml-stylesheet href="/xsl/glsa.xsl" type="text/xsl"?> +<?xml-stylesheet href="/xsl/guide.xsl" type="text/xsl"?> +<!DOCTYPE glsa SYSTEM "http://www.gentoo.org/dtd/glsa.dtd"> + +<glsa id="987654-32"> + <title> + Python: Retarded + </title> + <synopsis> + Python is retarded. Reading it can make your eyes bleed. + </synopsis> + <product type="ebuild">python</product> + <announced>October 10, 2006</announced> + <revised>October 10, 2006: 01</revised> + <bug>987654</bug> + <access>remote</access> + <affected> + <package name="dev-lang/python" auto="yes" arch="x86 sparc mips"> + <unaffected range="ge">12.34</unaffected> + <vulnerable range="lt">12.34</vulnerable> + </package> + </affected> + <background> + <p> + Python purports to be a programming language. + </p> + </background> + <description> + <p> + Python abuses whitespace for block structures. This makes anyone reading it + suffer severe brain ache. + </p> + </description> + <impact type="high"> + <p> + Anyone reading python code could go crazy. + </p> + </impact> + <workaround> + <p> + Use a real programming language. + </p> + </workaround> + <resolution> + <p> + All python users should get their brains examined. + </p> + </resolution> + <references> + </references> +</glsa> +END + |