diff options
Diffstat (limited to '0.26.0_alpha1/paludis/repositories/gems')
30 files changed, 3686 insertions, 0 deletions
diff --git a/0.26.0_alpha1/paludis/repositories/gems/Makefile.am b/0.26.0_alpha1/paludis/repositories/gems/Makefile.am new file mode 100644 index 000000000..6186067b4 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/Makefile.am @@ -0,0 +1,156 @@ +SUBDIRS = . +CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda +DISTCLEANFILES = params-sr.hh params-sr.cc +MAINTAINERCLEANFILES = Makefile.in + +AM_CXXFLAGS = -I$(top_srcdir) -I$(top_builddir) @PALUDIS_CXXFLAGS@ @PALUDIS_CXXFLAGS_VISIBILITY@ +DEFS = \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DLIBEXECDIR=\"$(libexecdir)\" \ + -DDATADIR=\"$(datadir)\" \ + -DLIBDIR=\"$(libdir)\" + +paludis_repositories_libdir = $(libdir)/paludis/repositories +paludis_gems_libexecdir = $(libexecdir)/paludis/gems + +paludis_repositories_lib_LTLIBRARIES = libpaludisgemsrepository.la + +paludis_repositories_gems_includedir = $(includedir)/paludis-$(PALUDIS_PC_SLOT)/paludis/repositories/gems/ +libpaludisgemsrepository_la_LDFLAGS = -version-info @VERSION_LIB_CURRENT@:@VERSION_LIB_REVISION@:0 + +paludis_repositories_gems_include_HEADERS = \ + gems_repository.hh \ + installed_gems_repository.hh \ + exceptions.hh \ + yaml.hh yaml-fwd.hh \ + gem_specification.hh gem_specification-fwd.hh \ + gem_specifications.hh \ + params-fwd.hh params.hh params-sr.hh + +libpaludisgemsrepository_la_SOURCES = \ + gems_repository.cc \ + installed_gems_repository.cc \ + params.cc \ + exceptions.cc \ + yaml.cc \ + gem_specification.cc \ + gem_specifications.cc \ + registration.cc \ + $(paludis_repositories_gems_include_HEADERS) + +libpaludisgemsrepository_la_LIBADD = \ + $(top_builddir)/paludis/libpaludis.la \ + $(top_builddir)/paludis/util/libpaludisutil.la \ + -lsyck + +gems_repository_TEST_SOURCES = gems_repository_TEST.cc +installed_gems_repository_TEST_SOURCES = gems_repository_TEST.cc +yaml_TEST_SOURCES = yaml_TEST.cc +gem_specification_TEST_SOURCES = gem_specification_TEST.cc +gem_specifications_TEST_SOURCES = gem_specifications_TEST.cc + +gems_repository_TEST_LDADD = \ + libpaludisgemsrepository.la \ + $(top_builddir)/paludis/util/libpaludisutil.la \ + $(top_builddir)/paludis/util/test_extras.o \ + $(top_builddir)/paludis/libpaludis.la \ + $(top_builddir)/paludis/environments/test/libpaludistestenvironment.la \ + $(top_builddir)/test/libtest.a \ + -lsyck + +installed_gems_repository_TEST_LDADD = \ + libpaludisgemsrepository.la \ + $(top_builddir)/paludis/util/libpaludisutil.la \ + $(top_builddir)/paludis/util/test_extras.o \ + $(top_builddir)/paludis/libpaludis.la \ + $(top_builddir)/paludis/environments/test/libpaludistestenvironment.la \ + $(top_builddir)/test/libtest.a \ + -lsyck + +yaml_TEST_LDADD = \ + libpaludisgemsrepository.la \ + $(top_builddir)/paludis/util/libpaludisutil.la \ + $(top_builddir)/paludis/util/test_extras.o \ + $(top_builddir)/paludis/libpaludis.la \ + $(top_builddir)/paludis/environments/test/libpaludistestenvironment.la \ + $(top_builddir)/test/libtest.a \ + -lsyck + +gem_specification_TEST_LDADD = \ + libpaludisgemsrepository.la \ + $(top_builddir)/paludis/util/libpaludisutil.la \ + $(top_builddir)/paludis/util/test_extras.o \ + $(top_builddir)/paludis/libpaludis.la \ + $(top_builddir)/paludis/environments/test/libpaludistestenvironment.la \ + $(top_builddir)/test/libtest.a \ + -lsyck + +gem_specifications_TEST_LDADD = \ + libpaludisgemsrepository.la \ + $(top_builddir)/paludis/util/libpaludisutil.la \ + $(top_builddir)/paludis/util/test_extras.o \ + $(top_builddir)/paludis/libpaludis.la \ + $(top_builddir)/paludis/environments/test/libpaludistestenvironment.la \ + $(top_builddir)/test/libtest.a \ + -lsyck + +gems_repository_TEST_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir) +installed_gems_repository_TEST_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir) +yaml_TEST_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir) +gem_specification_TEST_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir) +gem_specifications_TEST_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir) + +EXTRA_DIST = \ + installed_gems_repository_TEST.cc \ + installed_gems_repository_TEST_setup.sh \ + installed_gems_repository_TEST_cleanup.sh \ + gems_repository_TEST.cc \ + gems_repository_TEST_setup.sh \ + gems_repository_TEST_cleanup.sh \ + yaml_TEST.cc \ + gem_specification_TEST.cc \ + gem_specifications_TEST.cc \ + params-sr.hh \ + params-sr.cc \ + params.sr + +BUILT_SOURCES = \ + params-sr.hh params-sr.cc + +check_SCRIPTS = \ + gems_repository_TEST_setup.sh gems_repository_TEST_cleanup.sh + +paludis_gems_libexec_SCRIPTS = gems.bash + +TESTS_ENVIRONMENT = env \ + PALUDIS_GEMS_DIR="`$(top_srcdir)/paludis/repositories/e/ebuild/utils/canonicalise $(top_srcdir)/paludis/repositories/gems/`" \ + PALUDIS_EAPIS_DIR="$(top_srcdir)/paludis/eapis/" \ + PALUDIS_DISTRIBUTIONS_DIR="$(top_srcdir)/paludis/distributions/" \ + PALUDIS_DISTRIBUTION="gentoo" \ + PALUDIS_SKIP_CONFIG="yes" \ + TEST_SCRIPT_DIR="$(srcdir)/" \ + PALUDIS_REPOSITORY_SO_DIR="$(top_builddir)/paludis/repositories" \ + LD_LIBRARY_PATH="`echo $$LD_LIBRARY_PATH: | sed -e 's,^:,,'`` \ + $(top_srcdir)/paludis/repositories/e/ebuild/utils/canonicalise $(top_builddir)/paludis/repositories/gems/`:` \ + $(top_srcdir)/paludis/repositories/e/ebuild/utils/canonicalise $(top_builddir)/paludis/repositories/gems/.libs/`" \ + bash $(top_srcdir)/test/run_test.sh + +TESTS = gems_repository_TEST installed_gems_repository_TEST yaml_TEST gem_specification_TEST gem_specifications_TEST +check_PROGRAMS = $(TESTS) + +built-sources : $(BUILT_SOURCES) + for s in `echo $(SUBDIRS) | tr -d .` ; do $(MAKE) -C $$s built-sources || exit 1 ; done + +params-sr.hh : params.sr $(top_srcdir)/misc/make_sr.bash + if ! $(top_srcdir)/misc/make_sr.bash --header $(srcdir)/params.sr > $@ ; then rm -f $@ ; exit 1 ; fi + +params-sr.cc : params.sr $(top_srcdir)/misc/make_sr.bash + if ! $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/params.sr > $@ ; then rm -f $@ ; exit 1 ; fi + +distcheck-deps-local : $(DISTCHECK_DEPS) + +distcheck-deps : distcheck-deps-subdirs + +distcheck-deps-subdirs : + for s in $(SUBDIRS) . ; do if test x$$s = x. ; then $(MAKE) distcheck-deps-local || exit 1 ; \ + else $(MAKE) -C $$s distcheck-deps || exit 1 ; fi ; done diff --git a/0.26.0_alpha1/paludis/repositories/gems/exceptions.cc b/0.26.0_alpha1/paludis/repositories/gems/exceptions.cc new file mode 100644 index 000000000..e2fa93a30 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/exceptions.cc @@ -0,0 +1,29 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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 "exceptions.hh" + +using namespace paludis; +using namespace paludis::gems; + +RepositoryConfigurationError::RepositoryConfigurationError(const std::string & s) throw () : + ConfigurationError(s) +{ +} + diff --git a/0.26.0_alpha1/paludis/repositories/gems/exceptions.hh b/0.26.0_alpha1/paludis/repositories/gems/exceptions.hh new file mode 100644 index 000000000..ea0a1cd05 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/exceptions.hh @@ -0,0 +1,50 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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_GEMS_EXCEPTIONS_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_GEMS_EXCEPTIONS_HH 1 + +#include <paludis/util/exception.hh> + +namespace paludis +{ + namespace gems + { + /** + * Thrown if a Gems repository is misconfigured. + * + * \ingroup grpexceptions + * \ingroup grpgemsrepository + * \nosubgrouping + */ + class PALUDIS_VISIBLE RepositoryConfigurationError : + public ConfigurationError + { + public: + ///\name Basic operations + ///\{ + + RepositoryConfigurationError(const std::string &) throw (); + + ///\} + }; + } +} + +#endif diff --git a/0.26.0_alpha1/paludis/repositories/gems/gem_specification-fwd.hh b/0.26.0_alpha1/paludis/repositories/gems/gem_specification-fwd.hh new file mode 100644 index 000000000..283345962 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/gem_specification-fwd.hh @@ -0,0 +1,32 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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_GEMS_GEM_SPECIFICATION_FWD_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_GEMS_GEM_SPECIFICATION_FWD_HH 1 + +namespace paludis +{ + namespace gems + { + class BadSpecificationError; + class GemSpecification; + } +} + +#endif diff --git a/0.26.0_alpha1/paludis/repositories/gems/gem_specification.cc b/0.26.0_alpha1/paludis/repositories/gems/gem_specification.cc new file mode 100644 index 000000000..4dfcb77cf --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/gem_specification.cc @@ -0,0 +1,680 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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/gems/gem_specification.hh> +#include <paludis/repositories/gems/yaml.hh> +#include <paludis/util/private_implementation_pattern-impl.hh> +#include <paludis/util/visitor-impl.hh> +#include <paludis/util/mutex.hh> +#include <paludis/util/tr1_functional.hh> +#include <paludis/util/stringify.hh> +#include <paludis/name.hh> +#include <paludis/version_spec.hh> +#include <paludis/repository.hh> +#include <paludis/metadata_key.hh> +#include <paludis/action.hh> +#include <paludis/environment.hh> + +#include <libwrapiter/libwrapiter_forward_iterator.hh> +#include <libwrapiter/libwrapiter_output_iterator.hh> + +using namespace paludis; +using namespace paludis::gems; + +namespace +{ + class GemMetadataStringKey : + public MetadataStringKey + { + private: + const std::string _value; + + public: + GemMetadataStringKey(const std::string &, const std::string &, const std::string &, + const MetadataKeyType); + + virtual const std::string value() const + PALUDIS_ATTRIBUTE((warn_unused_result)); + }; + + + GemMetadataStringKey::GemMetadataStringKey(const std::string & r, const std::string & h, const std::string & v, + const MetadataKeyType t) : + MetadataStringKey(r, h, t), + _value(v) + { + } + + const std::string + GemMetadataStringKey::value() const + { + return _value; + } + + class GemMetadataFSEntryKey : + public MetadataFSEntryKey + { + private: + const FSEntry _value; + + public: + GemMetadataFSEntryKey(const std::string &, const std::string &, const FSEntry &, + const MetadataKeyType); + + virtual const FSEntry value() const + PALUDIS_ATTRIBUTE((warn_unused_result)); + }; + + + GemMetadataFSEntryKey::GemMetadataFSEntryKey(const std::string & r, const std::string & h, + const FSEntry & v, const MetadataKeyType t) : + MetadataFSEntryKey(r, h, t), + _value(v) + { + } + + const FSEntry + GemMetadataFSEntryKey::value() const + { + return _value; + } +} + +namespace paludis +{ + template <> + struct Implementation<GemSpecification> + { + mutable Mutex mutex; + + std::string name_part; + std::string version; + std::string date; + std::string platform; + std::string homepage; + + tr1::shared_ptr<GemMetadataStringKey> description_key; + tr1::shared_ptr<GemMetadataStringKey> summary_key; + tr1::shared_ptr<GemMetadataStringKey> authors_key; + tr1::shared_ptr<GemMetadataStringKey> rubyforge_project_key; + tr1::shared_ptr<GemMetadataFSEntryKey> fs_location_key; + + tr1::shared_ptr<const FSEntry> load_from_file; + + const Environment * const environment; + const tr1::shared_ptr<const Repository> repository; + + mutable bool has_masks; + + Implementation(const Environment * const e, const tr1::shared_ptr<const Repository> & r) : + environment(e), + repository(r), + has_masks(false) + { + } + }; +} + +namespace +{ + std::string extract_text_only(const yaml::Node & n, const std::string & extra); + + struct VersionVisitor : + ConstVisitor<yaml::NodeVisitorTypes> + { + std::string text; + + void visit(const yaml::StringNode & n) PALUDIS_ATTRIBUTE((noreturn)); + void visit(const yaml::SequenceNode & n) PALUDIS_ATTRIBUTE((noreturn)); + + void visit(const yaml::MapNode & n) + { + yaml::MapNode::ConstIterator i(n.find("version")); + if (i == n.end()) + throw BadSpecificationError("Version has no version: key"); + text = extract_text_only(*i->second, "for Version version: key"); + } + }; + + void VersionVisitor::visit(const yaml::StringNode &) + { + throw BadSpecificationError("Version child node is string, not map"); + } + + void VersionVisitor::visit(const yaml::SequenceNode &) + { + throw BadSpecificationError("Version child node is sequence, not map"); + } + + struct ExtractTextVisitor : + ConstVisitor<yaml::NodeVisitorTypes> + { + const std::string extra; + const bool accept_sequence; + std::string result; + + ExtractTextVisitor(const std::string & s, const bool b) : + extra(s), + accept_sequence(b) + { + } + + void visit(const yaml::StringNode & n) + { + result = n.text(); + } + + void visit(const yaml::SequenceNode & s) + { + if (! accept_sequence) + throw BadSpecificationError("Found sequence rather than text " + extra); + + bool w(false); + for (yaml::SequenceNode::ConstIterator i(s.begin()), i_end(s.end()) ; i != i_end ; ++i) + { + if (w) + result.append(", "); + result.append(extract_text_only(**i, extra)); + w = true; + } + } + + void visit(const yaml::MapNode &) PALUDIS_ATTRIBUTE((noreturn)); + }; + + void ExtractTextVisitor::visit(const yaml::MapNode &) + { + throw BadSpecificationError("Found map rather than text " + extra); + } + + std::string extract_text_only(const yaml::Node & n, const std::string & extra) + { + ExtractTextVisitor v(extra, false); + n.accept(v); + return v.result; + } + + std::string extract_text_sequence(const yaml::Node & n, const std::string & extra) + { + ExtractTextVisitor v(extra, true); + n.accept(v); + return v.result; + } + + std::string required_text_only_key(const yaml::MapNode & n, const std::string & k) + { + yaml::MapNode::ConstIterator i(n.find(k)); + if (i == n.end()) + throw BadSpecificationError("Key '" + k + "' not defined"); + return extract_text_only(*i->second, "for key '" + k + "'"); + } + + std::string optional_text_sequence_key(const yaml::MapNode & n, const std::string & k) + { + yaml::MapNode::ConstIterator i(n.find(k)); + if (i == n.end()) + return ""; + return extract_text_sequence(*i->second, "for key '" + k + "'"); + } + + std::string optional_text_only_key(const yaml::MapNode & n, const std::string & k) + { + yaml::MapNode::ConstIterator i(n.find(k)); + if (i == n.end()) + return ""; + return extract_text_only(*i->second, "for key '" + k + "'"); + } + + std::string required_version(const yaml::MapNode & n, const std::string & k) + { + yaml::MapNode::ConstIterator i(n.find(k)); + if (i == n.end()) + throw BadSpecificationError("Key '" + k + "' not defined"); + + VersionVisitor v; + i->second->accept(v); + return v.text; + } + + struct TopVisitor : + ConstVisitor<yaml::NodeVisitorTypes> + { + Implementation<GemSpecification> * const _imp; + + TopVisitor(Implementation<GemSpecification> * const i) : + _imp(i) + { + } + + void visit(const yaml::MapNode & n) + { + std::string summary(required_text_only_key(n, "summary")); + if (! summary.empty()) + _imp->summary_key.reset(new GemMetadataStringKey("summary", "Summary", summary, mkt_significant)); + + std::string description(optional_text_only_key(n, "description")); + if (! description.empty()) + _imp->description_key.reset(new GemMetadataStringKey("description", "Description", description, mkt_normal)); + + std::string authors(optional_text_sequence_key(n, "authors")); + if (! authors.empty()) + _imp->authors_key.reset(new GemMetadataStringKey("authors", "Authors", authors, mkt_normal)); + + std::string rubyforge_project(optional_text_sequence_key(n, "rubyforge_project")); + if (! rubyforge_project.empty()) + _imp->rubyforge_project_key.reset(new GemMetadataStringKey("rubyforge_project", "Rubyforge Project", rubyforge_project, + mkt_normal)); + + _imp->date = required_text_only_key(n, "date"); + _imp->platform = required_text_only_key(n, "platform"); + _imp->name_part = required_text_only_key(n, "name"); + _imp->version = required_version(n, "version"); + } + + void visit(const yaml::SequenceNode & n) PALUDIS_ATTRIBUTE((noreturn)); + + void visit(const yaml::StringNode & n) PALUDIS_ATTRIBUTE((noreturn)); + }; + + void TopVisitor::visit(const yaml::SequenceNode &) + { + throw BadSpecificationError("Top level node is sequence, not map"); + } + + void TopVisitor::visit(const yaml::StringNode & n) + { + throw BadSpecificationError("Top level node is text '" + n.text() + "', not map"); + } +} + +GemSpecification::GemSpecification(const Environment * const e, + const tr1::shared_ptr<const Repository> & r, const yaml::Node & node) : + PrivateImplementationPattern<GemSpecification>(new Implementation<GemSpecification>(e, r)), + _imp(PrivateImplementationPattern<GemSpecification>::_imp.get()) +{ + TopVisitor v(_imp); + node.accept(v); + + if (_imp->summary_key) + add_metadata_key(_imp->summary_key); + + if (_imp->description_key) + add_metadata_key(_imp->description_key); + + if (_imp->authors_key) + add_metadata_key(_imp->authors_key); + + if (_imp->rubyforge_project_key) + add_metadata_key(_imp->rubyforge_project_key); +} + + +GemSpecification::GemSpecification(const Environment * const e, const tr1::shared_ptr<const Repository> & r, + const PackageNamePart & q, const VersionSpec & v, const FSEntry & f) : + PrivateImplementationPattern<GemSpecification>(new Implementation<GemSpecification>(e, r)), + _imp(PrivateImplementationPattern<GemSpecification>::_imp.get()) +{ + _imp->name_part = stringify(q); + _imp->version = stringify(v); + _imp->load_from_file.reset(new FSEntry(f)); + _imp->fs_location_key.reset(new GemMetadataFSEntryKey("GEM", "Gem Location", f, mkt_internal)); + add_metadata_key(_imp->fs_location_key); +} + +GemSpecification::~GemSpecification() +{ +} + +BadSpecificationError::BadSpecificationError(const std::string & s) throw () : + Exception("Bad gem specification: " + s) +{ +} + +const std::string +GemSpecification::canonical_form(const PackageIDCanonicalForm f) const +{ + switch (f) + { + case idcf_full: + return stringify(name()) + "-" + stringify(version()) + "::" + stringify(repository()->name()); + + case idcf_version: + return stringify(version()); + + case idcf_no_version: + return stringify(name()) + "::" + stringify(_imp->repository->name()); + + case last_idcf: + break; + } + + throw InternalError(PALUDIS_HERE, "Bad PackageIDCanonicalForm"); +} + +const QualifiedPackageName +GemSpecification::name() const +{ + return QualifiedPackageName(CategoryNamePart("gems") + PackageNamePart(_imp->name_part)); +} + +const VersionSpec +GemSpecification::version() const +{ + return VersionSpec(_imp->version); +} + +const SlotName +GemSpecification::slot() const +{ + return SlotName(_imp->version); +} + +const tr1::shared_ptr<const Repository> +GemSpecification::repository() const +{ + return _imp->repository; +} + +const tr1::shared_ptr<const MetadataPackageIDKey> +GemSpecification::virtual_for_key() const +{ + return tr1::shared_ptr<const MetadataPackageIDKey>(); +} + +const tr1::shared_ptr<const MetadataSetKey<KeywordNameSet> > +GemSpecification::keywords_key() const +{ + return tr1::shared_ptr<const MetadataSetKey<KeywordNameSet> >(); +} + +const tr1::shared_ptr<const MetadataSetKey<IUseFlagSet> > +GemSpecification::iuse_key() const +{ + return tr1::shared_ptr<const MetadataSetKey<IUseFlagSet> >(); +} + +const tr1::shared_ptr<const MetadataSpecTreeKey<ProvideSpecTree> > +GemSpecification::provide_key() const +{ + return tr1::shared_ptr<const MetadataSpecTreeKey<ProvideSpecTree> >(); +} + +const tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> > +GemSpecification::build_dependencies_key() const +{ + return tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> >(); +} + +const tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> > +GemSpecification::run_dependencies_key() const +{ + return tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> >(); +} + +const tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> > +GemSpecification::post_dependencies_key() const +{ + return tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> >(); +} + +const tr1::shared_ptr<const MetadataSpecTreeKey<FetchableURISpecTree> > +GemSpecification::fetches_key() const +{ + return tr1::shared_ptr<const MetadataSpecTreeKey<FetchableURISpecTree> >(); +} + +const tr1::shared_ptr<const MetadataSpecTreeKey<SimpleURISpecTree> > +GemSpecification::homepage_key() const +{ + return tr1::shared_ptr<const MetadataSpecTreeKey<SimpleURISpecTree> >(); +} + +const tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> > +GemSpecification::suggested_dependencies_key() const +{ + return tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> >(); +} + +const tr1::shared_ptr<const MetadataStringKey> +GemSpecification::short_description_key() const +{ + return _imp->summary_key; +} + +const tr1::shared_ptr<const MetadataStringKey> +GemSpecification::long_description_key() const +{ + return _imp->description_key; +} + +const tr1::shared_ptr<const MetadataFSEntryKey> +GemSpecification::fs_location_key() const +{ + return _imp->fs_location_key; +} + +const tr1::shared_ptr<const MetadataContentsKey> +GemSpecification::contents_key() const +{ + return tr1::shared_ptr<const MetadataContentsKey>(); +} + +const tr1::shared_ptr<const MetadataTimeKey> +GemSpecification::installed_time_key() const +{ + return tr1::shared_ptr<const MetadataTimeKey>(); +} + +const tr1::shared_ptr<const MetadataStringKey> +GemSpecification::source_origin_key() const +{ + return tr1::shared_ptr<const MetadataStringKey>(); +} + +const tr1::shared_ptr<const MetadataStringKey> +GemSpecification::binary_origin_key() const +{ + return tr1::shared_ptr<const MetadataStringKey>(); +} + +const tr1::shared_ptr<const MetadataSetKey<PackageIDSequence> > +GemSpecification::contains_key() const +{ + return tr1::shared_ptr<const MetadataSetKey<PackageIDSequence> >(); +} + +const tr1::shared_ptr<const MetadataPackageIDKey> +GemSpecification::contained_in_key() const +{ + return tr1::shared_ptr<const MetadataPackageIDKey>(); +} + +bool +GemSpecification::arbitrary_less_than_comparison(const PackageID &) const +{ + return false; +} + +std::size_t +GemSpecification::extra_hash_value() const +{ + return 0; +} + +void +GemSpecification::need_keys_added() const +{ + if (_imp->load_from_file) + throw InternalError(PALUDIS_HERE, "Got to do the load from file thing"); +} + +#if 0 +InstalledGemsRepository::need_version_metadata(const QualifiedPackageName & q, const VersionSpec & v) const +{ + MetadataMap::const_iterator i(_imp->metadata.find(std::make_pair(q, v))); + if (i != _imp->metadata.end()) + return; + + Context c("When loading version metadata for '" + stringify(PackageDatabaseEntry(q, v, name())) + "':"); + + tr1::shared_ptr<gems::InstalledGemMetadata> m(new gems::InstalledGemMetadata(v)); + _imp->metadata.insert(std::make_pair(std::make_pair(q, v), m)); + + Command cmd(getenv_with_default("PALUDIS_GEMS_DIR", LIBEXECDIR "/paludis") + + "/gems/gems.bash specification '" + stringify(q.package) + "' '" + stringify(v) + "'"); + cmd.with_stderr_prefix(stringify(q) + "-" + stringify(v) + "::" + stringify(name()) + "> "); + cmd.with_sandbox(); + cmd.with_uid_gid(_imp->params.environment->reduced_uid(), _imp->params.environment->reduced_gid()); + + PStream p(cmd); + std::string output((std::istreambuf_iterator<char>(p)), std::istreambuf_iterator<char>()); + + if (0 != p.exit_status()) + { + Log::get_instance()->message(ll_warning, lc_context) << "Version metadata extraction returned non-zero"; + return; + } + + yaml::Document spec_doc(output); + gems::GemSpecification spec(*spec_doc.top()); + m->populate_from_specification(spec); + m->eapi = EAPIData::get_instance()->eapi_from_string("gems-1"); +} +#endif + +bool +GemSpecification::supports_action(const SupportsActionTestBase & b) const +{ + return repository()->some_ids_might_support_action(b); +} + +namespace +{ + struct PerformAction : + ConstVisitor<ActionVisitorTypes> + { + const PackageID * const id; + + PerformAction(const PackageID * const i) : + id(i) + { + } + + void visit(const InstallAction & a) + { + SupportsActionTest<InstallAction> t; + if (! id->repository()->some_ids_might_support_action(t)) + throw UnsupportedActionError(*id, a); + } + + void visit(const InstalledAction & a) + { + SupportsActionTest<InstalledAction> t; + if (! id->repository()->some_ids_might_support_action(t)) + throw UnsupportedActionError(*id, a); + } + + void visit(const UninstallAction & a) + { + SupportsActionTest<UninstallAction> t; + if (! id->repository()->some_ids_might_support_action(t)) + throw UnsupportedActionError(*id, a); + } + + void visit(const ConfigAction & a) + { + SupportsActionTest<ConfigAction> t; + if (! id->repository()->some_ids_might_support_action(t)) + throw UnsupportedActionError(*id, a); + } + + void visit(const FetchAction & a) + { + SupportsActionTest<FetchAction> t; + if (! id->repository()->some_ids_might_support_action(t)) + throw UnsupportedActionError(*id, a); + } + + void visit(const InfoAction & a) + { + SupportsActionTest<InfoAction> t; + if (! id->repository()->some_ids_might_support_action(t)) + throw UnsupportedActionError(*id, a); + } + + void visit(const PretendAction & a) + { + SupportsActionTest<PretendAction> t; + if (! id->repository()->some_ids_might_support_action(t)) + throw UnsupportedActionError(*id, a); + } + }; +} + +void +GemSpecification::perform_action(Action & a) const +{ + PerformAction b(this); + a.accept(b); +} + +void +GemSpecification::need_masks_added() const +{ + Lock l(_imp->mutex); + + if (_imp->has_masks) + return; + + _imp->has_masks = true; + + Context context("When generating masks for ID '" + canonical_form(idcf_full) + "':"); + + if (! _imp->environment->unmasked_by_user(*this)) + { + /* user */ + tr1::shared_ptr<const Mask> user_mask(_imp->environment->mask_for_user(*this)); + if (user_mask) + add_mask(user_mask); + } + + /* break portage */ + tr1::shared_ptr<const Mask> breaks_mask(_imp->environment->mask_for_breakage(*this)); + if (breaks_mask) + add_mask(breaks_mask); +} + +void +GemSpecification::invalidate_masks() const +{ + Lock l(_imp->mutex); + + if (! _imp->has_masks) + return; + + _imp->has_masks = false; + PackageID::invalidate_masks(); +} + +bool +GemSpecification::breaks_portage() const +{ + return true; +} + diff --git a/0.26.0_alpha1/paludis/repositories/gems/gem_specification.hh b/0.26.0_alpha1/paludis/repositories/gems/gem_specification.hh new file mode 100644 index 000000000..edb9d41ae --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/gem_specification.hh @@ -0,0 +1,127 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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_GEMS_GEM_SPECIFICATION_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_GEMS_GEM_SPECIFICATION_HH 1 + +#include <paludis/repositories/gems/gem_specification-fwd.hh> +#include <paludis/repositories/gems/yaml-fwd.hh> +#include <paludis/package_id.hh> +#include <paludis/name-fwd.hh> +#include <paludis/util/attributes.hh> +#include <paludis/util/private_implementation_pattern.hh> +#include <paludis/util/exception.hh> +#include <paludis/util/fs_entry-fwd.hh> +#include <string> + +namespace paludis +{ + namespace gems + { + /** + * Thrown if a bad Gem specification is encountered. + * + * \ingroup grpexceptions + * \ingroup grpgemsrepository + * \nosubgrouping + */ + class PALUDIS_VISIBLE BadSpecificationError : + public Exception + { + public: + ///\name Basic operations + ///\{ + + BadSpecificationError(const std::string &) throw (); + + ///\} + }; + + /** + * Represents a Gem specification. + * + * \ingroup grpgemsrepository + * \nosubgrouping + */ + class PALUDIS_VISIBLE GemSpecification : + private PrivateImplementationPattern<GemSpecification>, + public PackageID + { + private: + Implementation<GemSpecification> * const _imp; + + protected: + void need_keys_added() const; + virtual void need_masks_added() const; + + public: + ///\name Basic operations + ///\{ + + GemSpecification(const Environment * const e, const tr1::shared_ptr<const Repository> &, const yaml::Node &); + GemSpecification(const Environment * const e, const tr1::shared_ptr<const Repository> &, const PackageNamePart &, + const VersionSpec &, const FSEntry &); + + ~GemSpecification(); + + ///\} + + /* PackageID */ + virtual const std::string canonical_form(const PackageIDCanonicalForm) const; + + virtual const QualifiedPackageName name() const; + virtual const VersionSpec version() const; + virtual const SlotName slot() const; + virtual const tr1::shared_ptr<const Repository> repository() const; + + virtual const tr1::shared_ptr<const MetadataPackageIDKey> virtual_for_key() const; + virtual const tr1::shared_ptr<const MetadataSetKey<KeywordNameSet> > keywords_key() const; + virtual const tr1::shared_ptr<const MetadataSetKey<IUseFlagSet> > iuse_key() const; + virtual const tr1::shared_ptr<const MetadataSpecTreeKey<ProvideSpecTree> > provide_key() const; + virtual const tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> > build_dependencies_key() const; + virtual const tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> > run_dependencies_key() const; + virtual const tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> > post_dependencies_key() const; + virtual const tr1::shared_ptr<const MetadataSpecTreeKey<DependencySpecTree> > suggested_dependencies_key() const; + virtual const tr1::shared_ptr<const MetadataSpecTreeKey<FetchableURISpecTree> > fetches_key() const; + virtual const tr1::shared_ptr<const MetadataSpecTreeKey<SimpleURISpecTree> > homepage_key() const; + virtual const tr1::shared_ptr<const MetadataStringKey> short_description_key() const; + virtual const tr1::shared_ptr<const MetadataStringKey> long_description_key() const; + virtual const tr1::shared_ptr<const MetadataSetKey<PackageIDSequence> > contains_key() const; + virtual const tr1::shared_ptr<const MetadataPackageIDKey> contained_in_key() const; + + virtual const tr1::shared_ptr<const MetadataFSEntryKey> fs_location_key() const; + virtual const tr1::shared_ptr<const MetadataContentsKey> contents_key() const; + virtual const tr1::shared_ptr<const MetadataTimeKey> installed_time_key() const; + virtual const tr1::shared_ptr<const MetadataStringKey> source_origin_key() const; + virtual const tr1::shared_ptr<const MetadataStringKey> binary_origin_key() const; + + virtual bool supports_action(const SupportsActionTestBase &) const PALUDIS_ATTRIBUTE((warn_unused_result)); + virtual void perform_action(Action &) const; + + virtual bool arbitrary_less_than_comparison(const PackageID &) const; + virtual std::size_t extra_hash_value() const; + + virtual bool breaks_portage() const PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual void invalidate_masks() const; + }; + } +} + +#endif diff --git a/0.26.0_alpha1/paludis/repositories/gems/gem_specification_TEST.cc b/0.26.0_alpha1/paludis/repositories/gems/gem_specification_TEST.cc new file mode 100644 index 000000000..22f5b27b3 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/gem_specification_TEST.cc @@ -0,0 +1,162 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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 <test/test_runner.hh> +#include <test/test_framework.hh> +#include <paludis/repositories/gems/gem_specification.hh> +#include <paludis/repositories/gems/yaml.hh> +#include <paludis/environments/test/test_environment.hh> +#include <paludis/util/visitor-impl.hh> +#include <paludis/name.hh> +#include <paludis/metadata_key.hh> +#include <paludis/version_spec.hh> +#include <libwrapiter/libwrapiter_forward_iterator.hh> + +using namespace test; +using namespace paludis; +using namespace paludis::gems; + +namespace +{ + struct ExtractValueVisitor : + ConstVisitor<MetadataKeyVisitorTypes> + { + std::string s; + + void visit(const MetadataStringKey & k) + { + s = k.value(); + } + + void visit(const MetadataPackageIDKey &) + { + } + + void visit(const MetadataSetKey<KeywordNameSet> &) + { + } + + void visit(const MetadataSetKey<UseFlagNameSet> &) + { + } + + void visit(const MetadataSetKey<IUseFlagSet> &) + { + } + + void visit(const MetadataSetKey<Set<std::string> > &) + { + } + + void visit(const MetadataSetKey<PackageIDSequence> &) + { + } + + void visit(const MetadataSpecTreeKey<DependencySpecTree> &) + { + } + + void visit(const MetadataSpecTreeKey<LicenseSpecTree> &) + { + } + + void visit(const MetadataSpecTreeKey<ProvideSpecTree> &) + { + } + + void visit(const MetadataSpecTreeKey<RestrictSpecTree> &) + { + } + + void visit(const MetadataSpecTreeKey<FetchableURISpecTree> &) + { + } + + void visit(const MetadataSpecTreeKey<SimpleURISpecTree> &) + { + } + + void visit(const MetadataContentsKey &) + { + } + + void visit(const MetadataTimeKey &) + { + } + + void visit(const MetadataRepositoryMaskInfoKey &) + { + } + + void visit(const MetadataFSEntryKey &) + { + } + }; +} + +namespace test_cases +{ + struct SpecificationTest : TestCase + { + SpecificationTest() : TestCase("gem specification") { } + + void run() + { + std::string spec_text( + "--- !ruby/object:Gem::Specification\n" + "name: demo\n" + "version: !ruby/object:Gem::Version\n" + " version: 1.2.3\n" + "summary: This is the summary\n" + "homepage:\n" + "rubyforge_project:\n" + "description: A longer description\n" + "platform: ruby\n" + "date: 1234\n" + "authors: [ Fred , Barney ]\n" + ); + + yaml::Document spec_doc(spec_text); + TEST_CHECK(spec_doc.top()); + + TestEnvironment env; + GemSpecification spec(&env, tr1::shared_ptr<Repository>(), *spec_doc.top()); + + TEST_CHECK(spec.short_description_key()); + TEST_CHECK_EQUAL(spec.short_description_key()->value(), "This is the summary"); + TEST_CHECK_EQUAL(spec.name(), QualifiedPackageName("gems/demo")); + TEST_CHECK_EQUAL(spec.version(), VersionSpec("1.2.3")); + TEST_CHECK(spec.find_metadata("rubyforge_project") == spec.end_metadata()); + TEST_CHECK(spec.long_description_key()); + TEST_CHECK_EQUAL(spec.long_description_key()->value(), "A longer description"); + + TEST_CHECK(spec.find_metadata("authors") != spec.end_metadata()); + ExtractValueVisitor v; + (*spec.find_metadata("authors"))->accept(v); + TEST_CHECK_EQUAL(v.s, "Fred, Barney"); + +#if 0 + TEST_CHECK_EQUAL(spec.homepage(), ""); + TEST_CHECK_EQUAL(spec.rubyforge_project(), ""); + TEST_CHECK_EQUAL(spec.date(), "1234"); +#endif + } + } test_specification; +} + diff --git a/0.26.0_alpha1/paludis/repositories/gems/gem_specifications.cc b/0.26.0_alpha1/paludis/repositories/gems/gem_specifications.cc new file mode 100644 index 000000000..fad1d9a9b --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/gem_specifications.cc @@ -0,0 +1,214 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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/gems/gem_specifications.hh> +#include <paludis/repositories/gems/gem_specification.hh> +#include <paludis/repositories/gems/yaml.hh> +#include <paludis/name.hh> +#include <paludis/version_spec.hh> +#include <paludis/util/private_implementation_pattern-impl.hh> +#include <paludis/util/visitor-impl.hh> +#include <paludis/util/log.hh> +#include <paludis/util/stringify.hh> +#include <paludis/util/make_shared_ptr.hh> +#include <paludis/hashed_containers.hh> +#include <libwrapiter/libwrapiter_forward_iterator.hh> +#include <libwrapiter/libwrapiter_output_iterator.hh> + +using namespace paludis; +using namespace paludis::gems; + +typedef MakeHashedMap<std::pair<QualifiedPackageName, VersionSpec>, tr1::shared_ptr<const GemSpecification> >::Type Specs; + +namespace paludis +{ + template <> + struct Implementation<GemSpecifications> + { + Specs specs; + }; +} + +namespace +{ + std::string extract_text_only(const yaml::Node & n, const std::string & extra); + + struct ExtractTextVisitor : + ConstVisitor<yaml::NodeVisitorTypes> + { + const std::string extra; + const bool accept_sequence; + std::string result; + + ExtractTextVisitor(const std::string & s, const bool b) : + extra(s), + accept_sequence(b) + { + } + + void visit(const yaml::StringNode & n) + { + result = n.text(); + } + + void visit(const yaml::SequenceNode & s) + { + if (! accept_sequence) + throw BadSpecificationError("Found sequence rather than text " + extra); + + bool w(false); + for (yaml::SequenceNode::ConstIterator i(s.begin()), i_end(s.end()) ; i != i_end ; ++i) + { + if (w) + result.append(", "); + result.append(extract_text_only(**i, extra)); + w = true; + } + } + + void visit(const yaml::MapNode &) PALUDIS_ATTRIBUTE((noreturn)); + }; + + void ExtractTextVisitor::visit(const yaml::MapNode &) + { + throw BadSpecificationError("Found map rather than text " + extra); + } + + std::string extract_text_only(const yaml::Node & n, const std::string & extra) + { + ExtractTextVisitor v(extra, false); + n.accept(v); + return v.result; + } + + struct GemsVisitor : + ConstVisitor<yaml::NodeVisitorTypes> + { + Implementation<GemSpecifications> * const _imp; + const Environment * const environment; + const tr1::shared_ptr<const Repository> repository; + + GemsVisitor(const Environment * const e, + const tr1::shared_ptr<const Repository> & r, Implementation<GemSpecifications> * const i) : + _imp(i), + environment(e), + repository(r) + { + } + + void visit(const yaml::MapNode & n) + { + for (yaml::MapNode::ConstIterator i(n.begin()), i_end(n.end()) ; i != i_end ; ++i) + { + std::string pv(extract_text_only(*i->first, " as key for gem")); + Context c_item("When handling Gem entry '" + pv + "':"); + + try + { + tr1::shared_ptr<GemSpecification> spec(new GemSpecification(environment, repository, *i->second)); + _imp->specs.insert(std::make_pair(std::make_pair(spec->name(), spec->version()), spec)); + } + catch (const Exception & e) + { + Log::get_instance()->message(ll_qa, lc_context) << "Skipping entry '" + << pv << "' due to exception '" << e.message() << "' (" << e.what() << ")"; + } + } + } + + void visit(const yaml::SequenceNode & n) PALUDIS_ATTRIBUTE((noreturn)); + + void visit(const yaml::StringNode & n) PALUDIS_ATTRIBUTE((noreturn)); + }; + + void GemsVisitor::visit(const yaml::SequenceNode &) + { + throw BadSpecificationError("Top level 'gems' right hand node is sequence, not map"); + } + + void GemsVisitor::visit(const yaml::StringNode & n) + { + throw BadSpecificationError("Top level 'gems' right hand node is text '" + n.text() + "', not map"); + } + + struct TopVisitor : + ConstVisitor<yaml::NodeVisitorTypes> + { + Implementation<GemSpecifications> * const _imp; + const Environment * const environment; + const tr1::shared_ptr<const Repository> repository; + + TopVisitor(const Environment * const e, + const tr1::shared_ptr<const Repository> & r, Implementation<GemSpecifications> * const i) : + _imp(i), + environment(e), + repository(r) + { + } + + void visit(const yaml::MapNode & n) + { + yaml::MapNode::ConstIterator i(n.find("gems")); + if (n.end() == i) + throw BadSpecificationError("Top level map does not contain 'gems' node"); + + GemsVisitor g(environment, repository, _imp); + i->second->accept(g); + } + + void visit(const yaml::SequenceNode & n) PALUDIS_ATTRIBUTE((noreturn)); + + void visit(const yaml::StringNode & n) PALUDIS_ATTRIBUTE((noreturn)); + }; + + void TopVisitor::visit(const yaml::SequenceNode &) + { + throw BadSpecificationError("Top level node is sequence, not map"); + } + + void TopVisitor::visit(const yaml::StringNode & n) + { + throw BadSpecificationError("Top level node is text '" + n.text() + "', not map"); + } +} + +GemSpecifications::GemSpecifications(const Environment * const e, + const tr1::shared_ptr<const Repository> & r, const yaml::Node & n) : + PrivateImplementationPattern<GemSpecifications>(new Implementation<GemSpecifications>) +{ + TopVisitor v(e, r, _imp.get()); + n.accept(v); +} + +GemSpecifications::~GemSpecifications() +{ +} + +GemSpecifications::ConstIterator +GemSpecifications::begin() const +{ + return ConstIterator(_imp->specs.begin()); +} + +GemSpecifications::ConstIterator +GemSpecifications::end() const +{ + return ConstIterator(_imp->specs.end()); +} + diff --git a/0.26.0_alpha1/paludis/repositories/gems/gem_specifications.hh b/0.26.0_alpha1/paludis/repositories/gems/gem_specifications.hh new file mode 100644 index 000000000..b5830708a --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/gem_specifications.hh @@ -0,0 +1,73 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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_GEMS_GEM_SPECIFICATIONS_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_GEMS_GEM_SPECIFICATIONS_HH 1 + +#include <paludis/repositories/gems/gem_specification-fwd.hh> +#include <paludis/repositories/gems/yaml-fwd.hh> +#include <paludis/util/attributes.hh> +#include <paludis/util/private_implementation_pattern.hh> +#include <paludis/util/exception.hh> +#include <paludis/util/tr1_memory.hh> +#include <paludis/name-fwd.hh> +#include <paludis/version_spec-fwd.hh> +#include <paludis/repository-fwd.hh> +#include <libwrapiter/libwrapiter_forward_iterator-fwd.hh> +#include <string> + +namespace paludis +{ + namespace gems + { + /** + * Represents a collection of Gem specifications held in a master yaml + * file. + * + * \ingroup grpgemsrepository + * \nosubgrouping + */ + class PALUDIS_VISIBLE GemSpecifications : + private PrivateImplementationPattern<GemSpecifications> + { + public: + ///\name Basic operations + ///\{ + + GemSpecifications(const Environment * const, const tr1::shared_ptr<const Repository> &, const yaml::Node &); + ~GemSpecifications(); + + ///\} + + ///\name Iterate over our specifications + ///\{ + + typedef libwrapiter::ForwardIterator<GemSpecifications, + const std::pair<const std::pair<QualifiedPackageName, VersionSpec>, tr1::shared_ptr<const GemSpecification> > > + ConstIterator; + ConstIterator begin() const PALUDIS_ATTRIBUTE((warn_unused_result)); + ConstIterator end() const PALUDIS_ATTRIBUTE((warn_unused_result)); + + ///\} + }; + } +} + +#endif + diff --git a/0.26.0_alpha1/paludis/repositories/gems/gem_specifications_TEST.cc b/0.26.0_alpha1/paludis/repositories/gems/gem_specifications_TEST.cc new file mode 100644 index 000000000..944c84213 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/gem_specifications_TEST.cc @@ -0,0 +1,41 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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 <test/test_runner.hh> +#include <test/test_framework.hh> +#include <paludis/repositories/gems/gem_specification.hh> +#include <paludis/repositories/gems/yaml.hh> + +using namespace test; +using namespace paludis; +using namespace paludis::gems; + +namespace test_cases +{ + struct SpecificationsTest : TestCase + { + SpecificationsTest() : TestCase("gem specifications") { } + + void run() + { + } + } test_specifications; +} + + diff --git a/0.26.0_alpha1/paludis/repositories/gems/gems.bash b/0.26.0_alpha1/paludis/repositories/gems/gems.bash new file mode 100755 index 000000000..87d3774d6 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/gems.bash @@ -0,0 +1,55 @@ +#!/bin/bash +# vim: set sw=4 sts=4 et : + +# Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> +# +# 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 + +unalias -a +set +C +unset GZIP BZIP BZIP2 CDPATH GREP_OPTIONS GREP_COLOR GLOBIGNORE +eval unset LANG ${!LC_*} + +if [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] ; then + export SANDBOX_WRITE="${SANDBOX_WRITE}/dev/shm:/dev/stdout:/dev/stderr:/dev/null:/dev/tty:/dev/pts" + export SANDBOX_WRITE="${SANDBOX_WRITE}:/proc/self/attr:/proc/self/task:/selinux/context" + export SANDBOX_ON="1" + export SANDBOX_BASHRC="/dev/null" + unset BASH_ENV +fi + +shopt -s expand_aliases +shopt -s extglob + +case "${1}" in + specification) + gem specification "${2}" -v "${3}" + exit $? + ;; + + install) + gem install "${2}" -v "${3}" + exit $? + ;; + + uninstall) + gem uninstall "${2}" -v "${3}" -i -x + exit $? + ;; + + *) + echo "Unknown action ${1}" 1>&2 + exit 1 + ;; +esac diff --git a/0.26.0_alpha1/paludis/repositories/gems/gems_repository.cc b/0.26.0_alpha1/paludis/repositories/gems/gems_repository.cc new file mode 100644 index 000000000..6efd5dac6 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/gems_repository.cc @@ -0,0 +1,310 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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/gems/gems_repository.hh> +#include <paludis/repositories/gems/params.hh> +#include <paludis/repositories/gems/yaml.hh> +#include <paludis/repositories/gems/gem_specification.hh> +#include <paludis/repositories/gems/gem_specifications.hh> +#include <paludis/repository_info.hh> +#include <paludis/util/stringify.hh> +#include <paludis/util/private_implementation_pattern-impl.hh> +#include <paludis/util/make_shared_ptr.hh> +#include <paludis/util/system.hh> +#include <paludis/util/set.hh> +#include <paludis/util/sequence.hh> +#include <paludis/util/mutex.hh> +#include <paludis/util/visitor-impl.hh> +#include <paludis/hashed_containers.hh> +#include <paludis/action.hh> +#include <libwrapiter/libwrapiter_forward_iterator.hh> +#include <libwrapiter/libwrapiter_output_iterator.hh> +#include <fstream> + +using namespace paludis; + +namespace paludis +{ + template <> + struct Implementation<GemsRepository> + { + const gems::RepositoryParams params; + + const tr1::shared_ptr<Mutex> big_nasty_mutex; + + mutable tr1::shared_ptr<const CategoryNamePartSet> category_names; + mutable MakeHashedMap<CategoryNamePart, tr1::shared_ptr<const QualifiedPackageNameSet> >::Type package_names; + mutable MakeHashedMap<QualifiedPackageName, tr1::shared_ptr<PackageIDSequence> >::Type ids; + + mutable bool has_category_names; + mutable bool has_ids; + + Implementation(const gems::RepositoryParams p, tr1::shared_ptr<Mutex> m = make_shared_ptr(new Mutex)) : + params(p), + big_nasty_mutex(m), + has_category_names(false), + has_ids(false) + { + } + }; +} + +GemsRepository::GemsRepository(const gems::RepositoryParams & params) : + Repository(RepositoryName("gems"), + RepositoryCapabilities::create() + .installed_interface(0) + .sets_interface(0) + .syncable_interface(0) + .use_interface(0) + .world_interface(0) + .environment_variable_interface(0) + .mirrors_interface(0) + .virtuals_interface(0) + .provides_interface(0) + .destination_interface(0) + .licenses_interface(0) + .e_interface(0) + .qa_interface(0) + .make_virtuals_interface(0) + .hook_interface(0) + .manifest_interface(0), + "gems"), + PrivateImplementationPattern<GemsRepository>(new Implementation<GemsRepository>(params)) +{ + tr1::shared_ptr<RepositoryInfoSection> config_info(new RepositoryInfoSection("Configuration information")); + + config_info->add_kv("location", stringify(_imp->params.location)); + config_info->add_kv("install_dir", stringify(_imp->params.install_dir)); + config_info->add_kv("builddir", stringify(_imp->params.builddir)); + config_info->add_kv("sync", _imp->params.sync); + config_info->add_kv("sync_options", _imp->params.sync_options); + + _info->add_section(config_info); +} + +GemsRepository::~GemsRepository() +{ +} + +void +GemsRepository::invalidate() +{ + Lock l(*_imp->big_nasty_mutex); + + _imp.reset(new Implementation<GemsRepository>(_imp->params, _imp->big_nasty_mutex)); +} + +void +GemsRepository::invalidate_masks() +{ + Lock l(*_imp->big_nasty_mutex); + + for (MakeHashedMap<QualifiedPackageName, tr1::shared_ptr<PackageIDSequence> >::Type::iterator it(_imp->ids.begin()), it_end(_imp->ids.end()); + it_end != it; ++it) + for (PackageIDSequence::ConstIterator it2(it->second->begin()), it2_end(it->second->end()); + it2_end != it2; ++it2) + (*it2)->invalidate_masks(); +} + +bool +GemsRepository::do_has_category_named(const CategoryNamePart & c) const +{ + Lock l(*_imp->big_nasty_mutex); + + need_category_names(); + return _imp->category_names->end() != _imp->category_names->find(c); +} + +bool +GemsRepository::do_has_package_named(const QualifiedPackageName & q) const +{ + Lock l(*_imp->big_nasty_mutex); + + if (! do_has_category_named(q.category)) + return false; + + need_ids(); + return _imp->package_names.find(q.category)->second->end() != _imp->package_names.find(q.category)->second->find(q); +} + +tr1::shared_ptr<const CategoryNamePartSet> +GemsRepository::do_category_names() const +{ + Lock l(*_imp->big_nasty_mutex); + + need_category_names(); + return _imp->category_names; +} + +tr1::shared_ptr<const QualifiedPackageNameSet> +GemsRepository::do_package_names(const CategoryNamePart & c) const +{ + Lock l(*_imp->big_nasty_mutex); + + if (! has_category_named(c)) + return make_shared_ptr(new QualifiedPackageNameSet); + + need_ids(); + + MakeHashedMap<CategoryNamePart, tr1::shared_ptr<const QualifiedPackageNameSet> >::Type::const_iterator i( + _imp->package_names.find(c)); + if (i == _imp->package_names.end()) + return make_shared_ptr(new QualifiedPackageNameSet); + return i->second; +} + +tr1::shared_ptr<const PackageIDSequence> +GemsRepository::do_package_ids(const QualifiedPackageName & q) const +{ + Lock l(*_imp->big_nasty_mutex); + + if (! has_package_named(q)) + return make_shared_ptr(new PackageIDSequence); + + need_ids(); + + MakeHashedMap<QualifiedPackageName, tr1::shared_ptr<PackageIDSequence> >::Type::const_iterator i( + _imp->ids.find(q)); + if (i == _imp->ids.end()) + return make_shared_ptr(new PackageIDSequence); + + return i->second; +} + +void +GemsRepository::need_category_names() const +{ + Lock l(*_imp->big_nasty_mutex); + + if (_imp->has_category_names) + return; + + tr1::shared_ptr<CategoryNamePartSet> cat(new CategoryNamePartSet); + _imp->category_names = cat; + + cat->insert(CategoryNamePart("gems")); + _imp->has_category_names = true; +} + +void +GemsRepository::need_ids() const +{ + Lock l(*_imp->big_nasty_mutex); + + if (_imp->has_ids) + return; + + need_category_names(); + + tr1::shared_ptr<QualifiedPackageNameSet> pkgs(new QualifiedPackageNameSet); + _imp->package_names.insert(std::make_pair(CategoryNamePart("gems"), pkgs)); + + Context context("When loading gems yaml file:"); + + std::ifstream yaml_file(stringify(_imp->params.location / "yaml").c_str()); + if (! yaml_file) + throw ConfigurationError("Gems yaml file '" + stringify(_imp->params.location / "yaml") + "' not readable"); + + std::string output((std::istreambuf_iterator<char>(yaml_file)), std::istreambuf_iterator<char>()); + yaml::Document master_doc(output); + gems::GemSpecifications specs(_imp->params.environment, shared_from_this(), *master_doc.top()); + + for (gems::GemSpecifications::ConstIterator i(specs.begin()), i_end(specs.end()) ; + i != i_end ; ++i) + { + pkgs->insert(i->first.first); + + MakeHashedMap<QualifiedPackageName, tr1::shared_ptr<PackageIDSequence> >::Type::iterator v(_imp->ids.find(i->first.first)); + if (_imp->ids.end() == v) + v = _imp->ids.insert(std::make_pair(i->first.first, make_shared_ptr(new PackageIDSequence))).first; + + v->second->push_back(i->second); + } + + _imp->has_ids = true; +} + +#if 0 +void +GemsRepository::do_install(const tr1::shared_ptr<const PackageID> & id, const InstallOptions & o) const +{ + if (o.fetch_only) + return; + + Command cmd(getenv_with_default("PALUDIS_GEMS_DIR", LIBEXECDIR "/paludis") + + "/gems/gems.bash install '" + stringify(id->name().package) + "' '" + stringify(id->version()) + "'"); + cmd.with_stderr_prefix(stringify(*id) + "> "); + cmd.with_setenv("GEMCACHE", stringify(_imp->params.location / "yaml")); + + if (0 != run_command(cmd)) + throw PackageInstallActionError("Install of '" + stringify(*id) + "' failed"); +} +#endif + +namespace +{ + struct SupportsActionQuery : + ConstVisitor<SupportsActionTestVisitorTypes> + { + bool result; + + SupportsActionQuery() : + result(false) + { + } + + void visit(const SupportsActionTest<InstalledAction> &) + { + } + + void visit(const SupportsActionTest<InstallAction> &) + { + result = true; + } + + void visit(const SupportsActionTest<FetchAction> &) + { + } + + void visit(const SupportsActionTest<ConfigAction> &) + { + } + + void visit(const SupportsActionTest<PretendAction> &) + { + } + + void visit(const SupportsActionTest<InfoAction> &) + { + } + + void visit(const SupportsActionTest<UninstallAction> &) + { + } + }; +} + +bool +GemsRepository::do_some_ids_might_support_action(const SupportsActionTestBase & a) const +{ + SupportsActionQuery q; + a.accept(q); + return q.result; +} + diff --git a/0.26.0_alpha1/paludis/repositories/gems/gems_repository.hh b/0.26.0_alpha1/paludis/repositories/gems/gems_repository.hh new file mode 100644 index 000000000..1159ee628 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/gems_repository.hh @@ -0,0 +1,84 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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_GEMS_GEMS_REPOSITORY_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_GEMS_GEMS_REPOSITORY_HH 1 + +#include <paludis/repository.hh> +#include <paludis/repositories/gems/params-fwd.hh> +#include <paludis/util/private_implementation_pattern.hh> +#include <paludis/util/tr1_memory.hh> + +namespace paludis +{ + /** + * Repository for Gem packages. + * + * \ingroup grpgemsrepository + * \nosubgrouping + */ + class PALUDIS_VISIBLE GemsRepository : + public Repository, + private PrivateImplementationPattern<GemsRepository>, + public tr1::enable_shared_from_this<GemsRepository> + { + private: + void need_category_names() const; + void need_ids() const; + + protected: + /* Repository */ + + virtual tr1::shared_ptr<const PackageIDSequence> do_package_ids( + const QualifiedPackageName &) const + PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual tr1::shared_ptr<const QualifiedPackageNameSet> do_package_names( + const CategoryNamePart &) const + PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual tr1::shared_ptr<const CategoryNamePartSet> do_category_names() const + PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual bool do_has_package_named(const QualifiedPackageName &) const + PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual bool do_has_category_named(const CategoryNamePart &) const + PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual bool do_some_ids_might_support_action(const SupportsActionTestBase &) const; + + public: + /** + * Constructor. + */ + GemsRepository(const gems::RepositoryParams &); + + /** + * Destructor. + */ + ~GemsRepository(); + + virtual void invalidate(); + + virtual void invalidate_masks(); + }; +} + +#endif diff --git a/0.26.0_alpha1/paludis/repositories/gems/gems_repository_TEST.cc b/0.26.0_alpha1/paludis/repositories/gems/gems_repository_TEST.cc new file mode 100644 index 000000000..5be62de2b --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/gems_repository_TEST.cc @@ -0,0 +1,52 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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/environments/test/test_environment.hh> +#include <paludis/repositories/gems/gems_repository.hh> +#include <paludis/repositories/gems/params.hh> +#include <paludis/package_database.hh> +#include <paludis/util/make_shared_ptr.hh> +#include <test/test_framework.hh> +#include <test/test_runner.hh> + +using namespace test; +using namespace paludis; + +namespace test_cases +{ + struct CreationTest : TestCase + { + CreationTest() : TestCase("creation") { } + + void run() + { + TestEnvironment env; + env.package_database()->add_repository(1, make_shared_ptr(new GemsRepository( + gems::RepositoryParams::create() + .location(FSEntry("gems_repository_TEST_dir/repo")) + .install_dir(FSEntry("gems_repository_TEST_dir/install")) + .sync("") + .sync_options("") + .environment(&env) + .builddir(FSEntry("gems_repository_TEST_dir/build")) + ))); + } + } test_creation; +} + diff --git a/0.26.0_alpha1/paludis/repositories/gems/gems_repository_TEST_cleanup.sh b/0.26.0_alpha1/paludis/repositories/gems/gems_repository_TEST_cleanup.sh new file mode 100755 index 000000000..5d20e5c2b --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/gems_repository_TEST_cleanup.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# vim: set ft=sh sw=4 sts=4 et : + +if [ -d gems_repository_TEST_dir ] ; then + rm -fr gems_repository_TEST_dir +else + true +fi + diff --git a/0.26.0_alpha1/paludis/repositories/gems/gems_repository_TEST_setup.sh b/0.26.0_alpha1/paludis/repositories/gems/gems_repository_TEST_setup.sh new file mode 100755 index 000000000..bbe7b9879 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/gems_repository_TEST_setup.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# vim: set ft=sh sw=4 sts=4 et : + +mkdir gems_repository_TEST_dir || exit 1 +cd gems_repository_TEST_dir || exit 1 + diff --git a/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository.cc b/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository.cc new file mode 100644 index 000000000..ad0109658 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository.cc @@ -0,0 +1,344 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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/gems/installed_gems_repository.hh> +#include <paludis/repositories/gems/params.hh> +#include <paludis/repositories/gems/gem_specification.hh> +#include <paludis/repositories/gems/yaml.hh> +#include <paludis/repository_info.hh> +#include <paludis/package_database.hh> +#include <paludis/environment.hh> +#include <paludis/util/stringify.hh> +#include <paludis/util/private_implementation_pattern-impl.hh> +#include <paludis/util/dir_iterator.hh> +#include <paludis/util/set.hh> +#include <paludis/util/sequence.hh> +#include <paludis/util/is_file_with_extension.hh> +#include <paludis/util/make_shared_ptr.hh> +#include <paludis/util/pstream.hh> +#include <paludis/util/visitor-impl.hh> +#include <paludis/util/system.hh> +#include <paludis/util/mutex.hh> +#include <paludis/util/log.hh> +#include <paludis/util/strip.hh> +#include <paludis/hashed_containers.hh> +#include <paludis/action.hh> + +#include <libwrapiter/libwrapiter_forward_iterator.hh> +#include <libwrapiter/libwrapiter_output_iterator.hh> + +using namespace paludis; + +typedef MakeHashedMap<QualifiedPackageName, tr1::shared_ptr<PackageIDSequence> >::Type IDMap; + +namespace paludis +{ + template <> + struct Implementation<InstalledGemsRepository> + { + const tr1::shared_ptr<Mutex> big_nasty_mutex; + + const gems::InstalledRepositoryParams params; + + mutable tr1::shared_ptr<const CategoryNamePartSet> category_names; + mutable MakeHashedMap<CategoryNamePart, tr1::shared_ptr<const QualifiedPackageNameSet> >::Type package_names; + mutable IDMap ids; + + mutable bool has_category_names; + mutable bool has_ids; + + Implementation(const gems::InstalledRepositoryParams p, + tr1::shared_ptr<Mutex> m = make_shared_ptr(new Mutex)) : + big_nasty_mutex(m), + params(p), + has_category_names(false), + has_ids(false) + { + } + }; +} + +InstalledGemsRepository::InstalledGemsRepository(const gems::InstalledRepositoryParams & params) : + Repository(RepositoryName("installed-gems"), + RepositoryCapabilities::create() + .installed_interface(this) + .sets_interface(0) + .syncable_interface(0) + .use_interface(0) + .world_interface(0) + .environment_variable_interface(0) + .mirrors_interface(0) + .virtuals_interface(0) + .provides_interface(0) + .destination_interface(this) + .licenses_interface(0) + .e_interface(0) + .qa_interface(0) + .make_virtuals_interface(0) + .hook_interface(0) + .manifest_interface(0), + "installed_gems"), + PrivateImplementationPattern<InstalledGemsRepository>(new Implementation<InstalledGemsRepository>(params)) +{ + tr1::shared_ptr<RepositoryInfoSection> config_info(new RepositoryInfoSection("Configuration information")); + + config_info->add_kv("install_dir", stringify(_imp->params.install_dir)); + config_info->add_kv("builddir", stringify(_imp->params.builddir)); + + _info->add_section(config_info); +} + +InstalledGemsRepository::~InstalledGemsRepository() +{ +} + +void +InstalledGemsRepository::invalidate() +{ + Lock l(*_imp->big_nasty_mutex); + + _imp.reset(new Implementation<InstalledGemsRepository>(_imp->params, _imp->big_nasty_mutex)); +} + +void +InstalledGemsRepository::invalidate_masks() +{ +} + +bool +InstalledGemsRepository::do_has_category_named(const CategoryNamePart & c) const +{ + Lock l(*_imp->big_nasty_mutex); + + need_category_names(); + return _imp->category_names->end() != _imp->category_names->find(c); +} + +bool +InstalledGemsRepository::do_has_package_named(const QualifiedPackageName & q) const +{ + Lock l(*_imp->big_nasty_mutex); + + if (! do_has_category_named(q.category)) + return false; + + need_ids(); + return _imp->package_names.find(q.category)->second->end() != _imp->package_names.find(q.category)->second->find(q); +} + +tr1::shared_ptr<const CategoryNamePartSet> +InstalledGemsRepository::do_category_names() const +{ + Lock l(*_imp->big_nasty_mutex); + + need_category_names(); + return _imp->category_names; +} + +tr1::shared_ptr<const QualifiedPackageNameSet> +InstalledGemsRepository::do_package_names(const CategoryNamePart & c) const +{ + Lock l(*_imp->big_nasty_mutex); + + if (! has_category_named(c)) + return make_shared_ptr(new QualifiedPackageNameSet); + + need_ids(); + + MakeHashedMap<CategoryNamePart, tr1::shared_ptr<const QualifiedPackageNameSet> >::Type::const_iterator i( + _imp->package_names.find(c)); + if (i == _imp->package_names.end()) + return make_shared_ptr(new QualifiedPackageNameSet); + return i->second; +} + +tr1::shared_ptr<const PackageIDSequence> +InstalledGemsRepository::do_package_ids(const QualifiedPackageName & q) const +{ + Lock l(*_imp->big_nasty_mutex); + + if (! has_package_named(q)) + return make_shared_ptr(new PackageIDSequence); + + need_ids(); + + IDMap::const_iterator i(_imp->ids.find(q)); + if (i == _imp->ids.end()) + return make_shared_ptr(new PackageIDSequence); + + return i->second; +} + +void +InstalledGemsRepository::need_category_names() const +{ + Lock l(*_imp->big_nasty_mutex); + + if (_imp->has_category_names) + return; + + tr1::shared_ptr<CategoryNamePartSet> cat(new CategoryNamePartSet); + _imp->category_names = cat; + + cat->insert(CategoryNamePart("gems")); + _imp->has_category_names = true; +} + +void +InstalledGemsRepository::need_ids() const +{ + Lock l(*_imp->big_nasty_mutex); + + if (_imp->has_ids) + return; + + static CategoryNamePart gems("gems"); + + Context c("When loading entries for repository '" + stringify(name()) + "':"); + + need_category_names(); + + tr1::shared_ptr<QualifiedPackageNameSet> pkgs(new QualifiedPackageNameSet); + _imp->package_names.insert(std::make_pair(gems, pkgs)); + + for (DirIterator d(_imp->params.install_dir / "specifications"), d_end ; d != d_end ; ++d) + { + if (! is_file_with_extension(*d, ".gemspec", IsFileWithOptions())) + continue; + + std::string s(strip_trailing_string(d->basename(), ".gemspec")); + std::string::size_type h(s.rfind('-')); + if (std::string::npos == h) + { + Log::get_instance()->message(ll_qa, lc_context) << "Unrecognised file name format '" + << *d << "' (no hyphen)"; + continue; + } + + VersionSpec v(s.substr(h + 1)); + PackageNamePart p(s.substr(0, h)); + pkgs->insert(gems + p); + + if (_imp->ids.end() == _imp->ids.find(gems + p)) + _imp->ids.insert(std::make_pair(gems + p, make_shared_ptr(new PackageIDSequence))); + _imp->ids.find(gems + p)->second->push_back(make_shared_ptr(new gems::GemSpecification( + _imp->params.environment, shared_from_this(), p, v, *d))); + } +} + +bool +InstalledGemsRepository::is_suitable_destination_for(const PackageID & e) const +{ + Lock l(*_imp->big_nasty_mutex); + + std::string f(e.repository()->format()); + return f == "gems"; +} + +bool +InstalledGemsRepository::is_default_destination() const +{ + return true; +} + +bool +InstalledGemsRepository::want_pre_post_phases() const +{ + return true; +} + +void +InstalledGemsRepository::merge(const MergeOptions &) +{ + throw InternalError(PALUDIS_HERE, "Invalid target for merge"); +} + +FSEntry +InstalledGemsRepository::root() const +{ + return FSEntry("/"); +} + +#if 0 +void +InstalledGemsRepository::do_uninstall(const tr1::shared_ptr<const PackageID> & id, + const UninstallOptions &) const +{ + Command cmd(getenv_with_default("PALUDIS_GEMS_DIR", LIBEXECDIR "/paludis") + + "/gems/gems.bash uninstall '" + stringify(id->name().package) + "' '" + stringify(id->version()) + "'"); + cmd.with_stderr_prefix(stringify(*id) + "> "); + cmd.with_setenv("GEM_HOME", stringify(_imp->params.install_dir)); + + if (0 != run_command(cmd)) + throw PackageInstallActionError("Uninstall of '" + stringify(*id) + "' failed"); +} +#endif + +namespace +{ + struct SupportsActionQuery : + ConstVisitor<SupportsActionTestVisitorTypes> + { + bool result; + + SupportsActionQuery() : + result(false) + { + } + + void visit(const SupportsActionTest<InstalledAction> &) + { + result = true; + } + + void visit(const SupportsActionTest<InstallAction> &) + { + } + + void visit(const SupportsActionTest<ConfigAction> &) + { + } + + void visit(const SupportsActionTest<PretendAction> &) + { + } + + void visit(const SupportsActionTest<FetchAction> &) + { + } + + void visit(const SupportsActionTest<InfoAction> &) + { + } + + void visit(const SupportsActionTest<UninstallAction> &) + { + result = true; + } + }; +} + +bool +InstalledGemsRepository::do_some_ids_might_support_action(const SupportsActionTestBase & a) const +{ + SupportsActionQuery q; + a.accept(q); + return q.result; +} + diff --git a/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository.hh b/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository.hh new file mode 100644 index 000000000..8d1cf2aba --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository.hh @@ -0,0 +1,104 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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_GEMS_INSTALLED_GEMS_REPOSITORY_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_GEMS_INSTALLED_GEMS_REPOSITORY_HH 1 + +#include <paludis/repository.hh> +#include <paludis/repositories/gems/params-fwd.hh> +#include <paludis/util/private_implementation_pattern.hh> +#include <paludis/util/tr1_memory.hh> + +namespace paludis +{ + /** + * Repository for installed Gem packages. + * + * \ingroup grpgemsrepository + * \nosubgrouping + */ + class PALUDIS_VISIBLE InstalledGemsRepository : + public Repository, + public RepositoryDestinationInterface, + public RepositoryInstalledInterface, + public tr1::enable_shared_from_this<InstalledGemsRepository>, + private PrivateImplementationPattern<InstalledGemsRepository> + { + private: + void need_category_names() const; + void need_ids() const; + + protected: + /* RepositoryInstalledInterface */ + + virtual FSEntry root() const PALUDIS_ATTRIBUTE((warn_unused_result)); + + /* Repository */ + + virtual tr1::shared_ptr<const PackageIDSequence> do_package_ids( + const QualifiedPackageName &) const + PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual tr1::shared_ptr<const QualifiedPackageNameSet> do_package_names( + const CategoryNamePart &) const + PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual tr1::shared_ptr<const CategoryNamePartSet> do_category_names() const + PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual bool do_has_package_named(const QualifiedPackageName &) const + PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual bool do_has_category_named(const CategoryNamePart &) const + PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual bool do_some_ids_might_support_action(const SupportsActionTestBase &) const; + + public: + /** + * Constructor. + */ + InstalledGemsRepository(const gems::InstalledRepositoryParams &); + + /** + * Destructor. + */ + ~InstalledGemsRepository(); + + virtual void invalidate(); + + virtual void invalidate_masks(); + + /* RepositoryDestinationInterface */ + + virtual bool is_suitable_destination_for(const PackageID &) const + PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual bool is_default_destination() const + PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual bool want_pre_post_phases() const + PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual void merge(const MergeOptions &) PALUDIS_ATTRIBUTE((noreturn)); + }; +} + + +#endif diff --git a/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository_TEST.cc b/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository_TEST.cc new file mode 100644 index 000000000..130240885 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository_TEST.cc @@ -0,0 +1,50 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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/environments/test/test_environment.hh> +#include <paludis/repositories/gems/gems_repository.hh> +#include <paludis/repositories/gems/params.hh> +#include <paludis/package_database.hh> +#include <paludis/util/make_shared_ptr.hh> +#include <test/test_framework.hh> +#include <test/test_runner.hh> + +using namespace test; +using namespace paludis; + +namespace test_cases +{ + struct CreationTest : TestCase + { + CreationTest() : TestCase("creation") { } + + void run() + { + TestEnvironment env; + env.package_database()->add_repository(1, make_shared_ptr(new InstalledGemsRepository( + gems::InstalledRepositoryParams::create() + .location(FSEntry("gems_repository_TEST_dir/installed-repo")) + .environment(&env) + .builddir(FSEntry("gems_repository_TEST_dir/build")) + .install_dir(FSEntry("gems_repository_TEST_dir/install_dir")) + ))); + } + } test_creation; +} + diff --git a/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository_TEST_cleanup.sh b/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository_TEST_cleanup.sh new file mode 100755 index 000000000..2d8baec44 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository_TEST_cleanup.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# vim: set ft=sh sw=4 sts=4 et : + +if [ -d installed_gems_repository_TEST_dir ] ; then + rm -fr installed_gems_repository_TEST_dir +else + true +fi + diff --git a/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository_TEST_setup.sh b/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository_TEST_setup.sh new file mode 100755 index 000000000..4edf8ac08 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository_TEST_setup.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# vim: set ft=sh sw=4 sts=4 et : + +mkdir installed_gems_repository_TEST_dir || exit 1 +cd installed_gems_repository_TEST_dir || exit 1 + +mkdir -p installed-repo/installed_dir/specifications +cat <<END > installed-repo/yaml +END + diff --git a/0.26.0_alpha1/paludis/repositories/gems/params-fwd.hh b/0.26.0_alpha1/paludis/repositories/gems/params-fwd.hh new file mode 100644 index 000000000..a59e4ac20 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/params-fwd.hh @@ -0,0 +1,32 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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_GEMS_PARAMS_FWD_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_GEMS_PARAMS_FWD_HH 1 + +namespace paludis +{ + namespace gems + { + class RepositoryParams; + class InstalledRepositoryParams; + } +} + +#endif diff --git a/0.26.0_alpha1/paludis/repositories/gems/params.cc b/0.26.0_alpha1/paludis/repositories/gems/params.cc new file mode 100644 index 000000000..54498a5cb --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/params.cc @@ -0,0 +1,26 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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 "params.hh" + +using namespace paludis; +using namespace paludis::gems; + +#include <paludis/repositories/gems/params-sr.cc> + diff --git a/0.26.0_alpha1/paludis/repositories/gems/params.hh b/0.26.0_alpha1/paludis/repositories/gems/params.hh new file mode 100644 index 000000000..72d751b2a --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/params.hh @@ -0,0 +1,41 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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_GEMS_PARAMS_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_GEMS_PARAMS_HH 1 + +#include <paludis/repositories/gems/params-fwd.hh> +#include <paludis/util/attributes.hh> +#include <paludis/util/fs_entry.hh> +#include <paludis/util/sr.hh> +#include <string> + +namespace paludis +{ + class Environment; + + namespace gems + { + +#include <paludis/repositories/gems/params-sr.hh> + + } +} + +#endif diff --git a/0.26.0_alpha1/paludis/repositories/gems/params.sr b/0.26.0_alpha1/paludis/repositories/gems/params.sr new file mode 100644 index 000000000..254c71630 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/params.sr @@ -0,0 +1,28 @@ +#!/bin/bash +# vim: set sw=4 sts=4 et : + +make_class_RepositoryParams() +{ + visible + + key environment "Environment *" + key location FSEntry + key install_dir FSEntry + key sync std::string + key sync_options std::string + key builddir FSEntry + + allow_named_args +} + +make_class_InstalledRepositoryParams() +{ + visible + + key environment "Environment *" + key builddir FSEntry + key install_dir FSEntry + + allow_named_args +} + diff --git a/0.26.0_alpha1/paludis/repositories/gems/registration.cc b/0.26.0_alpha1/paludis/repositories/gems/registration.cc new file mode 100644 index 000000000..0be9d5559 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/registration.cc @@ -0,0 +1,100 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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/repository_maker.hh> +#include <paludis/repositories/gems/gems_repository.hh> +#include <paludis/repositories/gems/installed_gems_repository.hh> +#include <paludis/repositories/gems/params.hh> +#include <paludis/repositories/gems/exceptions.hh> +#include <paludis/util/make_shared_ptr.hh> +#include <paludis/util/map.hh> +#include <paludis/distribution.hh> +#include <paludis/environment.hh> +#include <libwrapiter/libwrapiter_forward_iterator.hh> +#include <libwrapiter/libwrapiter_output_iterator.hh> + +using namespace paludis; + +namespace +{ + tr1::shared_ptr<Repository> + make_gems_repository( + Environment * const env, + tr1::shared_ptr<const Map<std::string, std::string> > m) + { + std::string location; + if (m->end() == m->find("location") || ((location = m->find("location")->second)).empty()) + throw gems::RepositoryConfigurationError("Key 'location' not specified or empty"); + + std::string install_dir; + if (m->end() == m->find("install_dir") || ((install_dir = m->find("install_dir")->second)).empty()) + throw gems::RepositoryConfigurationError("Key 'install_dir' not specified or empty"); + + std::string sync; + if (m->end() != m->find("sync")) + sync = m->find("sync")->second; + + std::string sync_options; + if (m->end() != m->find("sync_options")) + sync_options = m->find("sync_options")->second; + + std::string builddir; + if (m->end() == m->find("builddir") || ((builddir = m->find("builddir")->second)).empty()) + builddir = DistributionData::get_instance()->distribution_from_string(env->default_distribution())->default_ebuild_builddir; + + return make_shared_ptr(new GemsRepository(gems::RepositoryParams::create() + .location(location) + .sync(sync) + .sync_options(sync_options) + .environment(env) + .install_dir(install_dir) + .builddir(builddir))); + } + + tr1::shared_ptr<Repository> + make_installed_gems_repository( + Environment * const env, + tr1::shared_ptr<const Map<std::string, std::string> > m) + { + std::string install_dir; + if (m->end() == m->find("install_dir") || ((install_dir = m->find("install_dir")->second)).empty()) + throw gems::RepositoryConfigurationError("Key 'install_dir' not specified or empty"); + + std::string builddir; + if (m->end() == m->find("builddir") || ((builddir = m->find("builddir")->second)).empty()) + builddir = DistributionData::get_instance()->distribution_from_string(env->default_distribution())->default_ebuild_builddir; + + return make_shared_ptr(new InstalledGemsRepository(gems::InstalledRepositoryParams::create() + .environment(env) + .install_dir(install_dir) + .builddir(builddir))); + } +} + +extern "C" +{ + void PALUDIS_VISIBLE register_repositories(RepositoryMaker * maker); +} + +void register_repositories(RepositoryMaker * maker) +{ + maker->register_maker("gems", &make_gems_repository); + maker->register_maker("installed_gems", &make_installed_gems_repository); +} + diff --git a/0.26.0_alpha1/paludis/repositories/gems/yaml-fwd.hh b/0.26.0_alpha1/paludis/repositories/gems/yaml-fwd.hh new file mode 100644 index 000000000..ac27e42e1 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/yaml-fwd.hh @@ -0,0 +1,38 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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_GEMS_YAML_FWD_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_GEMS_YAML_FWD_HH 1 + +namespace paludis +{ + namespace yaml + { + class Node; + class StringNode; + class SequenceNode; + class MapNode; + class NodeVisitorTypes; + class Document; + class NodeManager; + class ParseError; + } +} + +#endif diff --git a/0.26.0_alpha1/paludis/repositories/gems/yaml.cc b/0.26.0_alpha1/paludis/repositories/gems/yaml.cc new file mode 100644 index 000000000..3c4b37810 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/yaml.cc @@ -0,0 +1,389 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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 "yaml.hh" +#include <paludis/util/private_implementation_pattern-impl.hh> +#include <paludis/util/instantiation_policy-impl.hh> +#include <paludis/util/visitor-impl.hh> +#include <paludis/util/tr1_functional.hh> +#include <paludis/util/make_shared_ptr.hh> +#include <libwrapiter/libwrapiter_forward_iterator.hh> +#include <libwrapiter/libwrapiter_output_iterator.hh> +#include <syck.h> +#include <cstring> +#include <algorithm> +#include <map> + +using namespace paludis; +using namespace paludis::yaml; + +Node::~Node() +{ +} + +namespace paludis +{ + template <> + struct Implementation<StringNode> + { + const std::string text; + + Implementation(const std::string & t) : + text(t) + { + } + }; +} + +StringNode::StringNode(const std::string & t) : + PrivateImplementationPattern<StringNode>(new Implementation<StringNode>(t)) +{ +} + +StringNode::~StringNode() +{ +} + +std::string +StringNode::text() const +{ + return _imp->text; +} + +namespace paludis +{ + template <> + struct Implementation<SequenceNode> + { + std::list<const Node *> nodes; + }; +} + +SequenceNode::SequenceNode() : + PrivateImplementationPattern<SequenceNode>(new Implementation<SequenceNode>) +{ +} + +SequenceNode::~SequenceNode() +{ +} + +void +SequenceNode::push_back(const Node * const n) +{ + _imp->nodes.push_back(n); +} + +SequenceNode::ConstIterator +SequenceNode::begin() const +{ + return ConstIterator(_imp->nodes.begin()); +} + +SequenceNode::ConstIterator +SequenceNode::end() const +{ + return ConstIterator(_imp->nodes.end()); +} + +namespace paludis +{ + template <> + struct Implementation<MapNode> + { + std::list<std::pair<const Node *, const Node *> > nodes; + }; +} + +MapNode::MapNode() : + PrivateImplementationPattern<MapNode>(new Implementation<MapNode>) +{ +} + +MapNode::~MapNode() +{ +} + +void +MapNode::push_back(const std::pair<const Node *, const Node *> & p) +{ + _imp->nodes.push_back(p); +} + +MapNode::ConstIterator +MapNode::begin() const +{ + return ConstIterator(_imp->nodes.begin()); +} + +MapNode::ConstIterator +MapNode::end() const +{ + return ConstIterator(_imp->nodes.end()); +} + +namespace +{ + struct MatchStringVisitor : + ConstVisitor<NodeVisitorTypes> + { + bool found; + const std::string target; + + MatchStringVisitor(const std::string & s) : + found(false), + target(s) + { + } + + void visit(const StringNode & n) + { + found = n.text() == target; + } + + void visit(const MapNode &) + { + } + + void visit(const SequenceNode &) + { + } + }; + + bool match_string_node(const std::string & s, const Node * const n) + { + MatchStringVisitor v(s); + n->accept(v); + return v.found; + } +} + +MapNode::ConstIterator +MapNode::find(const std::string & s) const +{ + using namespace tr1::placeholders; + return std::find_if(begin(), end(), + tr1::bind(match_string_node, s, tr1::bind<const Node *>(tr1::mem_fn(&std::pair<const Node *, const Node *>::first), _1))); +} + +namespace +{ + static Mutex document_error_table_mutex; + static std::map<void *, std::string> document_error_table; + + template <typename R_, typename T_> + struct CallUnlessNull + { + R_ (* function) (T_ *); + + CallUnlessNull(R_ (*f) (T_ *)) : + function(f) + { + } + + void operator() (T_ * const t) const + { + if (t) + function(t); + } + }; + + template <typename R_, typename T_> + CallUnlessNull<R_, T_> + call_unless_null(R_ (* f) (T_ *)) + { + return CallUnlessNull<R_, T_>(f); + } + + SYMID node_handler(SyckParser * p, SyckNode * n) + { + Node * node(0); + + switch (n->kind) + { + case syck_str_kind: + { + node = new StringNode(std::string(n->data.str->ptr, n->data.str->len)); + NodeManager::get_instance()->manage_node(p, node); + } + break; + + case syck_seq_kind: + { + SequenceNode * s(new SequenceNode); + NodeManager::get_instance()->manage_node(p, s); + for (int i = 0 ; i < n->data.list->idx ; ++i) + { + SYMID v_id(syck_seq_read(n, i)); + char * v(0); + syck_lookup_sym(p, v_id, &v); + s->push_back(reinterpret_cast<Node *>(v)); + } + node = s; + } + break; + + case syck_map_kind: + { + MapNode * m(new MapNode); + NodeManager::get_instance()->manage_node(p, m); + for (int i = 0 ; i < n->data.pairs->idx ; ++i) + { + SYMID k_id(syck_map_read(n, map_key, i)), v_id(syck_map_read(n, map_value, i)); + char * k(0), * v(0); + syck_lookup_sym(p, k_id, &k); + syck_lookup_sym(p, v_id, &v); + m->push_back(std::make_pair(reinterpret_cast<Node *>(k), reinterpret_cast<Node *>(v))); + } + node = m; + } + break; + } + + return syck_add_sym(p, reinterpret_cast<char *>(node)); + } + + void error_handler(SyckParser * p, char * s) + { + Lock l(document_error_table_mutex); + document_error_table[p] = s; + } +} + +namespace paludis +{ + template <> + struct Implementation<Document> + { + struct Register + { + Implementation<Document> * _imp; + + Register(Implementation<Document> * imp) : + _imp(imp) + { + NodeManager::get_instance()->register_document(_imp->parser.get()); + } + + ~Register() + { + NodeManager::get_instance()->deregister_document(_imp->parser.get()); + } + }; + + Node * top; + tr1::shared_ptr<SyckParser> parser; + tr1::shared_ptr<char> data; + unsigned data_length; + + Register reg; + + Implementation(const std::string & s) : + top(0), + parser(syck_new_parser(), call_unless_null(syck_free_parser)), + data(strdup(s.c_str()), call_unless_null(std::free)), + data_length(s.length()), + reg(this) + { + } + }; +} + +Document::Document(const std::string & s) : + PrivateImplementationPattern<Document>(new Implementation<Document>(s)) +{ + Context c("When parsing yaml document:"); + + syck_parser_str(_imp->parser.get(), _imp->data.get(), _imp->data_length, 0); + syck_parser_handler(_imp->parser.get(), node_handler); + syck_parser_error_handler(_imp->parser.get(), error_handler); + + SYMID root_id(syck_parse(_imp->parser.get())); + + { + Lock l(document_error_table_mutex); + if (document_error_table.end() != document_error_table.find(_imp->parser.get())) + { + std::string e(document_error_table.find(_imp->parser.get())->second); + document_error_table.erase(_imp->parser.get()); + throw ParseError(e); + } + } + + char * root_uncasted(0); + syck_lookup_sym(_imp->parser.get(), root_id, &root_uncasted); + _imp->top = reinterpret_cast<Node *>(root_uncasted); +} + +Document::~Document() +{ +} + +const Node * +Document::top() const +{ + return _imp->top; +} + +namespace paludis +{ + template <> + struct Implementation<NodeManager> + { + std::map<const void *, std::list<tr1::shared_ptr<const Node> > > store; + }; +} + +NodeManager::NodeManager() : + PrivateImplementationPattern<NodeManager>(new Implementation<NodeManager>) +{ +} + +NodeManager::~NodeManager() +{ +} + +void +NodeManager::register_document(const void * const d) +{ + if (! _imp->store.insert(std::make_pair(d, std::list<tr1::shared_ptr<const Node> >())).second) + throw InternalError(PALUDIS_HERE, "duplicate document"); +} + +void +NodeManager::deregister_document(const void * const d) +{ + if (0 == _imp->store.erase(d)) + throw InternalError(PALUDIS_HERE, "no such document"); +} + +void +NodeManager::manage_node(const void * const d, const Node * const n) +{ + std::map<const void *, std::list<tr1::shared_ptr<const Node> > >::iterator i(_imp->store.find(d)); + if (i == _imp->store.end()) + throw InternalError(PALUDIS_HERE, "no such document"); + i->second.push_back(make_shared_ptr(n)); +} + +ParseError::ParseError(const std::string & s) throw () : + Exception(s) +{ +} + diff --git a/0.26.0_alpha1/paludis/repositories/gems/yaml.hh b/0.26.0_alpha1/paludis/repositories/gems/yaml.hh new file mode 100644 index 000000000..ae6f266c8 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/yaml.hh @@ -0,0 +1,249 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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_GEMS_YAML_HH +#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_GEMS_YAML_HH 1 + +#include <paludis/repositories/gems/yaml-fwd.hh> +#include <paludis/util/visitor.hh> +#include <paludis/util/attributes.hh> +#include <paludis/util/instantiation_policy.hh> +#include <paludis/util/private_implementation_pattern.hh> +#include <paludis/util/exception.hh> + +namespace paludis +{ + namespace yaml + { + class Node; + class StringNode; + class SequenceNode; + class MapNode; + + /** + * Visitor types for a yaml node heirarchy. + * + * \ingroup grpgemsrepository + * \nosubgrouping + */ + struct NodeVisitorTypes : + VisitorTypes< + NodeVisitorTypes, + Node, + StringNode, + SequenceNode, + MapNode> + { + }; + + /** + * A node in a yaml document. + * + * \ingroup grpgemsrepository + * \nosubgrouping + */ + class PALUDIS_VISIBLE Node : + public virtual ConstAcceptInterface<NodeVisitorTypes> + { + public: + ///\name Basic operations + ///\{ + + virtual ~Node() = 0; + + ///\} + }; + + /** + * A string node in a yaml document. + * + * \ingroup grpgemsrepository + * \nosubgrouping + */ + class PALUDIS_VISIBLE StringNode : + public Node, + public ConstAcceptInterfaceVisitsThis<NodeVisitorTypes, StringNode>, + private PrivateImplementationPattern<StringNode> + { + public: + ///\name Basic operations + ///\{ + + StringNode(const std::string &); + ~StringNode(); + + ///\} + + /** + * The node's raw text. + */ + std::string text() const PALUDIS_ATTRIBUTE((warn_unused_result)); + }; + + /** + * A sequence node in a yaml document. + * + * \ingroup grpgemsrepository + * \nosubgrouping + */ + class PALUDIS_VISIBLE SequenceNode : + public Node, + public ConstAcceptInterfaceVisitsThis<NodeVisitorTypes, SequenceNode>, + private PrivateImplementationPattern<SequenceNode> + { + public: + ///\name Basic operations + ///\{ + + SequenceNode(); + ~SequenceNode(); + + ///\} + + /** + * Add a child node. + */ + void push_back(const Node * const); + + ///\name Iterate over our child nodes. + ///\{ + + typedef libwrapiter::ForwardIterator<SequenceNode, const Node * const> ConstIterator; + ConstIterator begin() const PALUDIS_ATTRIBUTE((warn_unused_result)); + ConstIterator end() const PALUDIS_ATTRIBUTE((warn_unused_result)); + + ///\} + }; + + /** + * A mapping node in a yaml document. + * + * \ingroup grpgemsrepository + * \nosubgrouping + */ + class PALUDIS_VISIBLE MapNode : + public Node, + public ConstAcceptInterfaceVisitsThis<NodeVisitorTypes, MapNode>, + private PrivateImplementationPattern<MapNode> + { + public: + ///\name Basic operations + ///\{ + + MapNode(); + ~MapNode(); + + ///\} + + /** + * Add a child node pair. + */ + void push_back(const std::pair<const Node *, const Node *> &); + + ///\name Iterate over and find our child nodes. + ///\{ + + typedef libwrapiter::ForwardIterator<MapNode, const std::pair<const Node *, const Node *> > ConstIterator; + ConstIterator begin() const PALUDIS_ATTRIBUTE((warn_unused_result)); + ConstIterator end() const PALUDIS_ATTRIBUTE((warn_unused_result)); + ConstIterator find(const std::string &) const PALUDIS_ATTRIBUTE((warn_unused_result)); + + ///\} + }; + + /** + * A yaml document. + * + * \ingroup grpgemsrepository + * \nosubgrouping + */ + class PALUDIS_VISIBLE Document : + private PrivateImplementationPattern<Document> + { + public: + ///\name Basic operations + ///\{ + + Document(const std::string &); + ~Document(); + + ///\} + + /** + * The top node in our document. + */ + const Node * top() const PALUDIS_ATTRIBUTE((warn_unused_result)); + }; + + /** + * Handles memory management for yaml nodes, since syck assumes garbage + * collection. + * + * \ingroup grpgemsrepository + * \nosubgrouping + */ + class PALUDIS_VISIBLE NodeManager : + private PrivateImplementationPattern<NodeManager>, + public InstantiationPolicy<NodeManager, instantiation_method::SingletonTag> + { + friend class InstantiationPolicy<NodeManager, instantiation_method::SingletonTag>; + + private: + ///\name Basic operations + ///\{ + + NodeManager(); + ~NodeManager(); + + ///\} + + public: + ///\name Memory management operations + ///\{ + + void register_document(const void * const); + void deregister_document(const void * const); + + void manage_node(const void * const, const Node * const); + + ///\} + }; + + /** + * Thrown if a yaml document cannot be parsed. + * + * \ingroup grpgemsrepository + * \ingroup grpexceptions + * \nosubgrouping + */ + class PALUDIS_VISIBLE ParseError : + public Exception + { + public: + ///\name Basic operations + ///\{ + + ParseError(const std::string &) throw (); + + ///\} + }; + } +} + +#endif diff --git a/0.26.0_alpha1/paludis/repositories/gems/yaml_TEST.cc b/0.26.0_alpha1/paludis/repositories/gems/yaml_TEST.cc new file mode 100644 index 000000000..76a309d29 --- /dev/null +++ b/0.26.0_alpha1/paludis/repositories/gems/yaml_TEST.cc @@ -0,0 +1,186 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2007 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk> + * + * 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 <test/test_runner.hh> +#include <test/test_framework.hh> +#include <paludis/repositories/gems/yaml.hh> +#include <paludis/util/iterator.hh> +#include <paludis/util/visitor-impl.hh> +#include <libwrapiter/libwrapiter_forward_iterator.hh> +#include <algorithm> +#include <sstream> + +using namespace test; +using namespace paludis; +using namespace paludis::yaml; + +namespace +{ + struct CountedStringNode : + StringNode + { + static unsigned alloc_count; + + void * operator new (const std::size_t sz) throw (std::bad_alloc) + { + ++alloc_count; + return ::operator new (sz); + } + + void operator delete (void * n) throw () + { + --alloc_count; + ::operator delete (n); + } + + CountedStringNode() : + StringNode("x") + { + } + }; + + unsigned CountedStringNode::alloc_count(0); + + struct FakeDocument + { + FakeDocument() + { + NodeManager::get_instance()->register_document(this); + } + + ~FakeDocument() + { + NodeManager::get_instance()->deregister_document(this); + } + }; + + struct Dumper : + ConstVisitor<NodeVisitorTypes> + { + std::stringstream s; + + void visit(const StringNode & n) + { + s << "str(" << n.text() << ")"; + } + + void visit(const MapNode & n) + { + s << "map("; + bool w(false); + for (MapNode::ConstIterator i(n.begin()), i_end(n.end()) ; i != i_end ; ++i) + { + if (w) + s << ", "; + + i->first->accept(*this); + s << " -> "; + i->second->accept(*this); + w = true; + } + s << ")"; + } + + void visit(const SequenceNode & n) + { + s << "seq("; + bool w(false); + for (SequenceNode::ConstIterator i(n.begin()), i_end(n.end()) ; i != i_end ; ++i) + { + if (w) + s << ", "; + (*i)->accept(*this); + w = true; + } + s << ")"; + } + }; +} + +namespace test_cases +{ + struct ManagementTest : TestCase + { + ManagementTest() : TestCase("management") { } + + void run() + { + TEST_CHECK_EQUAL(CountedStringNode::alloc_count, 0u); + { + FakeDocument d; + NodeManager::get_instance()->manage_node(&d, new CountedStringNode); + NodeManager::get_instance()->manage_node(&d, new CountedStringNode); + NodeManager::get_instance()->manage_node(&d, new CountedStringNode); + TEST_CHECK_EQUAL(CountedStringNode::alloc_count, 3u); + } + TEST_CHECK_EQUAL(CountedStringNode::alloc_count, 0u); + } + } test_management; + + struct ParseTest : TestCase + { + ParseTest() : TestCase("parse") { } + + void run() + { + Document doc("foo: [ bar, baz ]"); + TEST_CHECK(doc.top()); + + Dumper dumper; + doc.top()->accept(dumper); + TEST_CHECK_EQUAL(dumper.s.str(), "map(str(foo) -> seq(str(bar), str(baz)))"); + } + } test_parse; + + struct ParseErrorTest : TestCase + { + ParseErrorTest() : TestCase("parse error") { } + + void run() + { + TEST_CHECK_THROWS(Document("foo: [ bar, baz"), ParseError); + } + } test_parse_error; + + struct MapFindTest : TestCase + { + MapFindTest() : TestCase("map find") { } + + void run() + { + Document doc("{ foo: bar, bar: baz, monkey: pants }"); + TEST_CHECK(doc.top()); + + Dumper dumper; + doc.top()->accept(dumper); + TEST_CHECK_EQUAL(dumper.s.str(), "map(str(foo) -> str(bar), str(bar) -> str(baz), str(monkey) -> str(pants))"); + + const MapNode * m(static_cast<const MapNode *>(doc.top())); + TEST_CHECK(m->find("foo") != m->end()); + TEST_CHECK(m->find("bar") != m->end()); + TEST_CHECK(m->find("monkey") != m->end()); + TEST_CHECK(m->find("baz") == m->end()); + + TEST_CHECK_EQUAL(static_cast<const StringNode *>(m->find("foo")->second)->text(), "bar"); + TEST_CHECK_EQUAL(static_cast<const StringNode *>(m->find("bar")->second)->text(), "baz"); + TEST_CHECK_EQUAL(static_cast<const StringNode *>(m->find("monkey")->second)->text(), "pants"); + } + } test_map_find; +} + |