aboutsummaryrefslogtreecommitdiff
path: root/0.26.0_alpha1/paludis/repositories/gems
diff options
context:
space:
mode:
Diffstat (limited to '0.26.0_alpha1/paludis/repositories/gems')
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/Makefile.am156
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/exceptions.cc29
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/exceptions.hh50
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/gem_specification-fwd.hh32
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/gem_specification.cc680
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/gem_specification.hh127
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/gem_specification_TEST.cc162
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/gem_specifications.cc214
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/gem_specifications.hh73
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/gem_specifications_TEST.cc41
-rwxr-xr-x0.26.0_alpha1/paludis/repositories/gems/gems.bash55
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/gems_repository.cc310
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/gems_repository.hh84
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/gems_repository_TEST.cc52
-rwxr-xr-x0.26.0_alpha1/paludis/repositories/gems/gems_repository_TEST_cleanup.sh9
-rwxr-xr-x0.26.0_alpha1/paludis/repositories/gems/gems_repository_TEST_setup.sh6
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository.cc344
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository.hh104
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository_TEST.cc50
-rwxr-xr-x0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository_TEST_cleanup.sh9
-rwxr-xr-x0.26.0_alpha1/paludis/repositories/gems/installed_gems_repository_TEST_setup.sh10
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/params-fwd.hh32
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/params.cc26
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/params.hh41
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/params.sr28
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/registration.cc100
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/yaml-fwd.hh38
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/yaml.cc389
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/yaml.hh249
-rw-r--r--0.26.0_alpha1/paludis/repositories/gems/yaml_TEST.cc186
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;
+}
+