aboutsummaryrefslogtreecommitdiff
path: root/paludis/repositories/gentoo
diff options
context:
space:
mode:
Diffstat (limited to 'paludis/repositories/gentoo')
-rw-r--r--paludis/repositories/gentoo/Makefile.am263
-rw-r--r--paludis/repositories/gentoo/ebuild/Makefile.am75
-rw-r--r--paludis/repositories/gentoo/ebuild/build_functions.bash110
-rw-r--r--paludis/repositories/gentoo/ebuild/builtin_fetch.bash137
-rw-r--r--paludis/repositories/gentoo/ebuild/builtin_init.bash74
-rw-r--r--paludis/repositories/gentoo/ebuild/builtin_merge.bash140
-rw-r--r--paludis/repositories/gentoo/ebuild/builtin_metadata.bash38
-rw-r--r--paludis/repositories/gentoo/ebuild/builtin_strip.bash80
-rw-r--r--paludis/repositories/gentoo/ebuild/builtin_tidyup.bash43
-rw-r--r--paludis/repositories/gentoo/ebuild/builtin_unmerge.bash115
-rw-r--r--paludis/repositories/gentoo/ebuild/builtin_variable.bash23
-rw-r--r--paludis/repositories/gentoo/ebuild/digests/Makefile.am31
-rw-r--r--paludis/repositories/gentoo/ebuild/digests/domd5.cc54
-rw-r--r--paludis/repositories/gentoo/ebuild/digests/dormd160.cc53
-rw-r--r--paludis/repositories/gentoo/ebuild/digests/dosha256.cc52
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/ebuild.bash352
-rw-r--r--paludis/repositories/gentoo/ebuild/echo_functions.bash.in238
-rw-r--r--paludis/repositories/gentoo/ebuild/echo_functions_TEST.bash45
-rw-r--r--paludis/repositories/gentoo/ebuild/eclass_functions.bash85
-rw-r--r--paludis/repositories/gentoo/ebuild/install_functions.bash109
-rw-r--r--paludis/repositories/gentoo/ebuild/kernel_functions.bash59
-rw-r--r--paludis/repositories/gentoo/ebuild/kernel_functions_TEST.bash41
-rw-r--r--paludis/repositories/gentoo/ebuild/list_functions.bash70
-rw-r--r--paludis/repositories/gentoo/ebuild/list_functions_TEST.bash74
-rw-r--r--paludis/repositories/gentoo/ebuild/merge.cc451
-rw-r--r--paludis/repositories/gentoo/ebuild/merge_TEST.bash223
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/merge_TEST_cleanup.sh10
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/merge_TEST_setup.sh74
-rw-r--r--paludis/repositories/gentoo/ebuild/merge_common.cc99
-rw-r--r--paludis/repositories/gentoo/ebuild/merge_common.hh50
-rw-r--r--paludis/repositories/gentoo/ebuild/multilib_functions.bash66
-rw-r--r--paludis/repositories/gentoo/ebuild/pkg_config.bash58
-rw-r--r--paludis/repositories/gentoo/ebuild/pkg_nofetch.bash62
-rw-r--r--paludis/repositories/gentoo/ebuild/pkg_postinst.bash58
-rw-r--r--paludis/repositories/gentoo/ebuild/pkg_postrm.bash59
-rw-r--r--paludis/repositories/gentoo/ebuild/pkg_preinst.bash58
-rw-r--r--paludis/repositories/gentoo/ebuild/pkg_prerm.bash58
-rw-r--r--paludis/repositories/gentoo/ebuild/pkg_setup.bash58
-rw-r--r--paludis/repositories/gentoo/ebuild/portage_stubs.bash86
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/run_test.bash47
-rw-r--r--paludis/repositories/gentoo/ebuild/sandbox.bash42
-rw-r--r--paludis/repositories/gentoo/ebuild/src_compile.bash59
-rw-r--r--paludis/repositories/gentoo/ebuild/src_install.bash56
-rw-r--r--paludis/repositories/gentoo/ebuild/src_test.bash84
-rw-r--r--paludis/repositories/gentoo/ebuild/src_unpack.bash54
-rw-r--r--paludis/repositories/gentoo/ebuild/unmerge.cc320
-rw-r--r--paludis/repositories/gentoo/ebuild/unmerge_TEST.bash94
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/unmerge_TEST_cleanup.sh11
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/unmerge_TEST_setup.sh15
-rw-r--r--paludis/repositories/gentoo/ebuild/usage_error.bash31
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/Makefile.am92
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/utils/canonicalise6
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/utils/dobin48
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/dobin_TEST.bash70
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/doconfd32
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/dodir34
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/dodoc55
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/doenvd32
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/doexe58
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/dohard34
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/dohtml122
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/doinfo55
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/doinitd32
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/doins89
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/dolib62
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/dolib.a.in27
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/dolib.so.in26
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/doman85
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/domo54
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/donewins40
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/dosbin45
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/dosed52
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/dosym42
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/utils/dounpack114
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/utils/emake22
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/fowners24
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/fperms24
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/utils/getfsize5
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/utils/getfsize_TEST.bash44
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/utils/getmtime5
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/newbin38
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/newconfd38
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/newdoc38
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/newenvd38
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/newexe38
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/newinitd38
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/newins38
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/newlib.a.in38
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/newlib.so.in38
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/newman38
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/newsbin38
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/prep.in21
-rw-r--r--paludis/repositories/gentoo/ebuild/utils/run_test.bash62
-rw-r--r--paludis/repositories/gentoo/ebuild/work_around_broken_utilities.bash.in26
-rw-r--r--paludis/repositories/gentoo/ebuild_entries.cc532
-rw-r--r--paludis/repositories/gentoo/ebuild_entries.hh70
-rw-r--r--paludis/repositories/gentoo/ebuild_flat_metadata_cache.cc147
-rw-r--r--paludis/repositories/gentoo/ebuild_flat_metadata_cache.hh67
-rw-r--r--paludis/repositories/gentoo/eclass_mtimes.cc68
-rw-r--r--paludis/repositories/gentoo/eclass_mtimes.hh55
-rw-r--r--paludis/repositories/gentoo/glsa.cc251
-rw-r--r--paludis/repositories/gentoo/glsa.hh113
-rw-r--r--paludis/repositories/gentoo/glsa.sr8
-rw-r--r--paludis/repositories/gentoo/make_ebuild_repository.cc186
-rw-r--r--paludis/repositories/gentoo/make_ebuild_repository.hh44
-rw-r--r--paludis/repositories/gentoo/portage_repository.cc1243
-rw-r--r--paludis/repositories/gentoo/portage_repository.hh189
-rw-r--r--paludis/repositories/gentoo/portage_repository.sr10
-rw-r--r--paludis/repositories/gentoo/portage_repository_TEST.cc665
-rwxr-xr-xpaludis/repositories/gentoo/portage_repository_TEST_cleanup.sh10
-rwxr-xr-xpaludis/repositories/gentoo/portage_repository_TEST_setup.sh226
-rw-r--r--paludis/repositories/gentoo/portage_repository_entries.cc43
-rw-r--r--paludis/repositories/gentoo/portage_repository_entries.hh133
-rw-r--r--paludis/repositories/gentoo/portage_repository_entry.cc32
-rw-r--r--paludis/repositories/gentoo/portage_repository_exceptions.cc29
-rw-r--r--paludis/repositories/gentoo/portage_repository_exceptions.hh53
-rw-r--r--paludis/repositories/gentoo/portage_repository_news.cc284
-rw-r--r--paludis/repositories/gentoo/portage_repository_news.hh135
-rw-r--r--paludis/repositories/gentoo/portage_repository_params.cc8
-rw-r--r--paludis/repositories/gentoo/portage_repository_params.hh43
-rw-r--r--paludis/repositories/gentoo/portage_repository_params.sr36
-rw-r--r--paludis/repositories/gentoo/portage_repository_profile.cc715
-rw-r--r--paludis/repositories/gentoo/portage_repository_profile.hh127
-rw-r--r--paludis/repositories/gentoo/portage_repository_profile_file.cc85
-rw-r--r--paludis/repositories/gentoo/portage_repository_profile_file.hh52
-rw-r--r--paludis/repositories/gentoo/portage_repository_sets.cc376
-rw-r--r--paludis/repositories/gentoo/portage_repository_sets.hh80
-rw-r--r--paludis/repositories/gentoo/portage_virtual_version_metadata.cc45
-rw-r--r--paludis/repositories/gentoo/portage_virtual_version_metadata.hh38
-rw-r--r--paludis/repositories/gentoo/registration.cc64
-rw-r--r--paludis/repositories/gentoo/use_desc.cc95
-rw-r--r--paludis/repositories/gentoo/use_desc.hh59
-rw-r--r--paludis/repositories/gentoo/vdb_repository.cc1542
-rw-r--r--paludis/repositories/gentoo/vdb_repository.hh207
-rw-r--r--paludis/repositories/gentoo/vdb_repository.sr26
-rw-r--r--paludis/repositories/gentoo/vdb_repository_TEST.cc249
-rwxr-xr-xpaludis/repositories/gentoo/vdb_repository_TEST_cleanup.sh11
-rwxr-xr-xpaludis/repositories/gentoo/vdb_repository_TEST_setup.sh35
-rw-r--r--paludis/repositories/gentoo/vdb_version_metadata.cc65
-rw-r--r--paludis/repositories/gentoo/vdb_version_metadata.hh50
-rw-r--r--paludis/repositories/gentoo/xml_things.cc219
-rw-r--r--paludis/repositories/gentoo/xml_things.hh30
-rw-r--r--paludis/repositories/gentoo/xml_things_TEST.cc92
-rwxr-xr-xpaludis/repositories/gentoo/xml_things_TEST_cleanup.sh11
-rwxr-xr-xpaludis/repositories/gentoo/xml_things_TEST_setup.sh115
145 files changed, 15669 insertions, 0 deletions
diff --git a/paludis/repositories/gentoo/Makefile.am b/paludis/repositories/gentoo/Makefile.am
new file mode 100644
index 0000000..7d8f166
--- /dev/null
+++ b/paludis/repositories/gentoo/Makefile.am
@@ -0,0 +1,263 @@
+SUBDIRS = ebuild .
+CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda
+DISTCLEANFILES = \
+ portage_repository-sr.hh portage_repository-sr.cc \
+ glsa-sr.hh glsa-sr.cc \
+ portage_repository_params-sr.hh portage_repository_params-sr.cc \
+ vdb_repository-sr.hh vdb_repository-sr.cc
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@ @PALUDIS_CXXFLAGS_VISIBILITY@
+DEFS= \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DDATADIR=\"$(datadir)\" \
+ -DLIBDIR=\"$(libdir)\"
+
+paludis_repositories_libdir = $(libdir)/paludis/repositories
+
+if MONOLITHIC
+
+if ENABLE_GLSA
+
+noinst_LTLIBRARIES = \
+ libpaludisgentoorepository.la \
+ libpaludisgentoorepositoryxmlthings.la
+
+else
+
+noinst_LTLIBRARIES = \
+ libpaludisgentoorepository.la
+
+endif
+
+else
+
+paludis_repositories_lib_LTLIBRARIES = libpaludisgentoorepository.la
+
+if ENABLE_GLSA
+
+lib_LTLIBRARIES = libpaludisgentoorepositoryxmlthings.la
+
+endif
+
+endif
+
+paludis_repositories_gentoo_includedir = $(includedir)/paludis/repositories/gentoo/
+libpaludisgentoorepository_la_LDFLAGS = -version-info @VERSION_LIB_CURRENT@:@VERSION_LIB_REVISION@:0
+
+paludis_repositories_gentoo_include_HEADERS = \
+ glsa.hh \
+ glsa-sr.hh \
+ portage_repository-sr.hh \
+ portage_repository.hh \
+ portage_repository_profile_file.hh \
+ portage_repository_profile.hh \
+ portage_repository_exceptions.hh \
+ portage_repository_news.hh \
+ portage_repository_params.hh \
+ portage_repository_params-sr.hh \
+ portage_repository_sets.hh \
+ portage_repository_entries.hh \
+ ebuild_entries.hh \
+ ebuild_flat_metadata_cache.hh \
+ eclass_mtimes.hh \
+ make_ebuild_repository.hh \
+ use_desc.hh \
+ portage_virtual_version_metadata.hh \
+ vdb_repository.hh \
+ vdb_version_metadata.hh \
+ vdb_repository-sr.hh
+
+libpaludisgentoorepository_la_SOURCES = \
+ glsa.cc \
+ portage_repository.cc \
+ portage_repository_profile_file.cc \
+ portage_repository_profile.cc \
+ portage_repository_exceptions.cc \
+ portage_repository_news.cc \
+ portage_repository_sets.cc \
+ portage_repository_entries.cc \
+ ebuild_entries.cc \
+ ebuild_flat_metadata_cache.cc \
+ eclass_mtimes.cc \
+ portage_repository_params.cc \
+ make_ebuild_repository.cc \
+ use_desc.cc \
+ portage_virtual_version_metadata.cc \
+ registration.cc \
+ vdb_repository.cc \
+ vdb_version_metadata.cc
+ $(paludis_repositories_gentoo_include_HEADERS)
+
+if MONOLITHIC
+
+libpaludisgentoorepository_la_LIBADD = \
+ libpaludisgentoorepositoryxmlthings.la \
+ $(DYNAMIC_LD_LIBS)
+
+else
+
+libpaludisgentoorepository_la_LIBADD = \
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ $(top_builddir)/paludis/libpaludis.la \
+ $(DYNAMIC_LD_LIBS)
+
+endif
+
+portage_repository_TEST_SOURCES = portage_repository_TEST.cc
+
+if MONOLITHIC
+
+portage_repository_TEST_LDADD = \
+ libpaludisgentoorepository.la \
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ $(top_builddir)/paludis/util/test_extras.o \
+ $(top_builddir)/paludis/libpaludis.la \
+ $(top_builddir)/paludis/environment/test/libpaludistestenvironment.la \
+ $(top_builddir)/test/libtest.a \
+ $(DYNAMIC_LD_LIBS)
+
+else
+
+portage_repository_TEST_LDADD = \
+ libpaludisgentoorepository.la \
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ $(top_builddir)/paludis/util/test_extras.o \
+ $(top_builddir)/paludis/libpaludis.la \
+ $(top_builddir)/paludis/environment/test/libpaludistestenvironment.la \
+ $(top_builddir)/test/libtest.a \
+ $(DYNAMIC_LD_LIBS)
+
+endif
+
+portage_repository_TEST_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir)
+
+EXTRA_DIST = \
+ glsa.sr \
+ portage_repository_TEST.cc \
+ portage_repository_TEST_setup.sh \
+ portage_repository_TEST_cleanup.sh \
+ portage_repository_params-sr.hh \
+ portage_repository_params-sr.cc \
+ portage_repository_params.sr \
+ portage_repository-sr.hh \
+ portage_repository-sr.cc \
+ portage_repository.sr \
+ xml_things_TEST.cc \
+ xml_things_TEST_setup.sh \
+ xml_things_TEST_cleanup.sh \
+ vdb_repository_TEST.cc \
+ vdb_repository_TEST_setup.sh \
+ vdb_repository_TEST_cleanup.sh \
+ vdb_repository-sr.hh \
+ vdb_repository-sr.cc \
+ vdb_repository.sr
+
+BUILT_SOURCES = \
+ portage_repository_params-sr.hh \
+ portage_repository_params-sr.cc \
+ portage_repository-sr.hh \
+ portage_repository-sr.cc \
+ glsa-sr.hh \
+ glsa-sr.cc \
+ vdb_repository-sr.hh \
+ vdb_repository-sr.cc
+
+check_SCRIPTS = \
+ portage_repository_TEST_setup.sh portage_repository_TEST_cleanup.sh \
+ xml_things_TEST_setup.sh xml_things_TEST_cleanup.sh \
+ vdb_repository_TEST_setup.sh vdb_repository_TEST_cleanup.sh
+
+TESTS_ENVIRONMENT = env \
+ PALUDIS_EBUILD_DIR="$(top_srcdir)/paludis/repositories/gentoo/ebuild/" \
+ PALUDIS_SKIP_CONFIG="yes" \
+ TEST_SCRIPT_DIR="$(srcdir)/" \
+ PALUDIS_REPOSITORY_SO_DIR="$(top_builddir)/paludis/repositories" \
+ LD_LIBRARY_PATH="`$(top_srcdir)/paludis/repositories/gentoo/ebuild/utils/canonicalise $(top_builddir)/paludis/repositories/gentoo/`:` \
+ $(top_srcdir)/paludis/repositories/gentoo/ebuild/utils/canonicalise $(top_builddir)/paludis/repositories/gentoo/.libs/`" \
+ bash $(top_srcdir)/test/run_test.sh
+
+portage_repository-sr.hh : portage_repository.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --header $(srcdir)/portage_repository.sr > $@
+
+portage_repository-sr.cc : portage_repository.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/portage_repository.sr > $@
+
+portage_repository_params-sr.hh : portage_repository_params.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --header $(srcdir)/portage_repository_params.sr > $@
+
+portage_repository_params-sr.cc : portage_repository_params.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/portage_repository_params.sr > $@
+
+glsa-sr.hh : glsa.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --header $(srcdir)/glsa.sr > $@
+
+glsa-sr.cc : glsa.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/glsa.sr > $@
+
+vdb_repository-sr.hh : vdb_repository.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --header $(srcdir)/vdb_repository.sr > $@
+
+vdb_repository-sr.cc : vdb_repository.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/vdb_repository.sr > $@
+
+
+libpaludisgentoorepositoryxmlthings_la_SOURCES = xml_things.cc xml_things.hh
+libpaludisgentoorepositoryxmlthings_la_CXXFLAGS = $(AM_CXXFLAGS) @LIBXML2DEPS_CFLAGS@
+
+if MONOLITHIC
+
+libpaludisgentoorepositoryxmlthings_la_LIBADD = @LIBXML2DEPS_LIBS@ \
+ $(DYNAMIC_LD_LIBS)
+
+else
+
+libpaludisgentoorepositoryxmlthings_la_LIBADD = @LIBXML2DEPS_LIBS@ \
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ $(top_builddir)/paludis/libpaludis.la
+
+endif
+
+libpaludisgentoorepositoryxmlthings_la_LDFLAGS = -version-info @VERSION_LIB_CURRENT@:@VERSION_LIB_REVISION@:0
+
+if ENABLE_GLSA
+
+GLSA_TESTS = xml_things_TEST
+xml_things_TEST_SOURCES = xml_things_TEST.cc
+
+if MONOLITHIC
+
+xml_things_TEST_LDADD = \
+ $(top_builddir)/paludis/util/test_extras.o \
+ $(top_builddir)/test/libtest.a \
+ libpaludisgentoorepository.la \
+ $(top_builddir)/paludis/libpaludis.la \
+ $(top_builddir)/paludis/environment/test/libpaludistestenvironment.la \
+ $(top_builddir)/test/libtest.a \
+ libpaludisgentoorepositoryxmlthings.la \
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ $(DYNAMIC_LD_LIBS)
+
+else
+
+xml_things_TEST_LDADD = \
+ $(top_builddir)/paludis/util/test_extras.o \
+ $(top_builddir)/test/libtest.a \
+ libpaludisgentoorepository.la \
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ $(top_builddir)/paludis/libpaludis.la \
+ $(top_builddir)/paludis/environment/test/libpaludistestenvironment.la \
+ $(top_builddir)/test/libtest.a \
+ $(DYNAMIC_LD_LIBS)
+
+endif
+
+endif
+
+TESTS = portage_repository_TEST $(GLSA_TESTS)
+check_PROGRAMS = $(TESTS)
+
+built-sources : $(BUILT_SOURCES)
+ for s in `echo $(SUBDIRS) | tr -d .` ; do $(MAKE) -C $$s built-sources || exit 1 ; done
+
diff --git a/paludis/repositories/gentoo/ebuild/Makefile.am b/paludis/repositories/gentoo/ebuild/Makefile.am
new file mode 100644
index 0000000..431ebc8
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/Makefile.am
@@ -0,0 +1,75 @@
+MAINTAINERCLEANFILES = Makefile.in
+CLEANFILES = *~
+SUBDIRS = . digests utils
+
+AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@
+
+libexecprogdir = $(libexecdir)/paludis/
+
+libexecprog_SCRIPTS = \
+ build_functions.bash \
+ builtin_fetch.bash \
+ builtin_init.bash \
+ builtin_merge.bash \
+ builtin_metadata.bash \
+ builtin_strip.bash \
+ builtin_tidyup.bash \
+ builtin_unmerge.bash \
+ builtin_variable.bash \
+ ebuild.bash \
+ echo_functions.bash \
+ kernel_functions.bash \
+ eclass_functions.bash \
+ install_functions.bash \
+ list_functions.bash \
+ multilib_functions.bash \
+ pkg_config.bash \
+ pkg_nofetch.bash \
+ pkg_postinst.bash \
+ pkg_postrm.bash \
+ pkg_preinst.bash \
+ pkg_prerm.bash \
+ pkg_setup.bash \
+ portage_stubs.bash \
+ sandbox.bash \
+ src_compile.bash \
+ src_install.bash \
+ src_test.bash \
+ src_unpack.bash \
+ usage_error.bash \
+ work_around_broken_utilities.bash
+
+TESTS_ENVIRONMENT = env \
+ PALUDIS_EBUILD_DIR="$(top_srcdir)/paludis/repositories/gentoo/ebuild/" \
+ PALUDIS_EBUILD_LOG_LEVEL="warning" \
+ TOP_BUILD_DIR="`$(top_srcdir)/paludis/repositories/gentoo/ebuild/utils/canonicalise $(top_builddir)/`" \
+ TEST_SCRIPT_DIR="$(srcdir)/" \
+ bash $(top_srcdir)/test/run_test.sh $(top_srcdir)/paludis/repositories/gentoo/ebuild/run_test.bash
+
+TESTS = echo_functions_TEST.bash list_functions_TEST.bash kernel_functions_TEST.bash \
+ merge_TEST.bash unmerge_TEST.bash
+
+libexecprog_PROGRAMS = merge unmerge
+merge_SOURCES = merge.cc merge_common.cc merge_common.hh
+merge_LDADD = \
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ $(top_builddir)/paludis/digests/libpaludisdigests.la \
+ $(top_builddir)/paludis/selinux/libpaludisselinux.la \
+ $(DYNAMIC_LD_LIBS)
+
+unmerge_SOURCES = unmerge.cc merge_common.cc merge_common.hh
+unmerge_LDADD = \
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ $(top_builddir)/paludis/digests/libpaludisdigests.la
+
+check_SCRIPTS = $(TESTS) \
+ merge_TEST_setup.sh merge_TEST_cleanup.sh \
+ unmerge_TEST_setup.sh unmerge_TEST_cleanup.sh \
+ run_test.bash $(TESTS)
+
+EXTRA_DIST = $(libexecprog_SCRIPTS) run_test.bash $(TESTS) $(check_SCRIPTS)
+
+built-sources : $(BUILT_SOURCES)
+ for s in `echo $(SUBDIRS) | tr -d .` ; do $(MAKE) -C $$s built-sources || exit 1 ; done
+
+
diff --git a/paludis/repositories/gentoo/ebuild/build_functions.bash b/paludis/repositories/gentoo/ebuild/build_functions.bash
new file mode 100644
index 0000000..6e7aa11
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/build_functions.bash
@@ -0,0 +1,110 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+econf()
+{
+ local LOCAL_EXTRA_ECONF="${EXTRA_ECONF}"
+ local LOCAL_ECONF_WRAPPER="${ECONF_WRAPPER}"
+
+ [[ -z "${ECONF_SOURCE}" ]] && ECONF_SOURCE=.
+
+ if [[ -x "${ECONF_SOURCE}/configure" ]] ; then
+ if [[ -d /usr/share/gnuconfig ]] ; then
+ local f
+ for f in $(find "${WORKDIR}" -type f -name config.guess -or -name config.sub ) ; do
+ echo "econf: updating ${f} with /usr/share/gnuconfig/${f##*/}"
+ cp -f /usr/share/gnuconfig/${f##*/} ${f}
+ done
+ fi
+
+ [[ -z "${CBUILD}" ]] || LOCAL_EXTRA_ECONF="--build=${CBUILD} ${LOCAL_EXTRA_ECONF}"
+ [[ -z "${CTARGET}" ]] || LOCAL_EXTRA_ECONF="--target=${CTARGET} ${LOCAL_EXTRA_ECONF}"
+
+ # If the ebuild passed in --prefix, use that to set --libdir. KDE at least needs this.
+
+ ECONF_PREFIX=/usr
+ for i in "$@"; do
+ if [[ ${i} == --prefix=* ]]; then
+ ECONF_PREFIX=${i#--prefix=}
+ elif [[ ${i} == --exec-prefix=* ]]; then
+ ECONF_PREFIX=${i#--exec-prefix=}
+ fi
+ done
+
+ local libcmd=
+ if [[ -n "${ABI}" ]] ; then
+ local v="LIBDIR_${ABI}"
+ if [[ -n "${!v}" ]] ; then
+ libcmd="--libdir=${ECONF_PREFIX}/$(ebuild_get_libdir)"
+ fi
+ fi
+
+ echo ${LOCAL_ECONF_WRAPPER} ${ECONF_SOURCE}/configure \
+ --prefix=/usr \
+ --host=${CHOST} \
+ --mandir=/usr/share/man \
+ --infodir=/usr/share/info \
+ --datadir=/usr/share \
+ --sysconfdir=/etc \
+ --localstatedir=/var/lib \
+ ${libcmd} "$@" ${LOCAL_EXTRA_ECONF} 1>&2
+
+ ${LOCAL_ECONF_WRAPPER} ${ECONF_SOURCE}/configure \
+ --prefix=/usr \
+ --host=${CHOST} \
+ --mandir=/usr/share/man \
+ --infodir=/usr/share/info \
+ --datadir=/usr/share \
+ --sysconfdir=/etc \
+ --localstatedir=/var/lib \
+ ${libcmd} "$@" ${LOCAL_EXTRA_ECONF} || die "econf failed"
+
+ else
+ die "No configure script for econf"
+ fi
+}
+
+einstall()
+{
+ if [[ -f Makefile ]] || [[ -f makefile ]] || [[ -f GNUmakefile ]] ; then
+ local makecmd=""
+ type -p gmake &>/dev/null && makecmd="gmake" || makecmd="make"
+ local cmd="${EINSTALL_WRAPPER} ${makecmd} prefix=${D}/usr"
+ cmd="${cmd} mandir=${D}/usr/share/man"
+ cmd="${cmd} infodir=${D}/usr/share/info"
+ cmd="${cmd} datadir=${D}/usr/share"
+ cmd="${cmd} sysconfdir=${D}/etc"
+ cmd="${cmd} localstatedir=${D}/var/lib"
+ cmd="${cmd} libdir=${D}/usr/$(ebuild_get_libdir)"
+ cmd="${cmd} ${EXTRA_EINSTALL} ${@} install"
+ echo "${cmd}" 1>&2
+ ${cmd} || die "einstall failed"
+ else
+ die "No Makefile for einstall"
+ fi
+}
+
+unpack()
+{
+ dounpack ${@} || die "unpack failed"
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/builtin_fetch.bash b/paludis/repositories/gentoo/ebuild/builtin_fetch.bash
new file mode 100644
index 0000000..c3f6402
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/builtin_fetch.bash
@@ -0,0 +1,137 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License, version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+builtin_fetch()
+{
+ [[ -d "${DISTDIR}" ]] || die "DISTDIR \"${DISTDIR}\" is not a directory"
+
+ local a nofetch unique_aa old_aa
+ for a in ${FLAT_SRC_URI} ; do
+ local aa=${a##*/}
+ hasq "${aa}" ${unique_aa} || unique_aa="${unique_aa} ${aa}"
+
+ if [[ -f "${DISTDIR}/${aa}" ]] && [[ "0" != $(getfsize "${DISTDIR}/${aa}") ]] ; then
+ if [[ "${old_aa}" != "${aa}" ]] ; then
+ ebuild_section "Already have ${aa}"
+ old_aa="${aa}"
+ fi
+ else
+ if [[ -f "${DISTDIR}/${aa}" ]] ; then
+ ebuild_section "Trying to remove existing ${aa}..."
+ rm -f "${DISTDIR}/${aa}"
+ fi
+
+ if ! hasq fetch ${RESTRICT} ; then
+ if [[ "${old_aa}" != "${aa}" ]] ; then
+ ebuild_section "Need to fetch ${aa}"
+ old_aa="${aa}"
+ fi
+ local d
+ for d in ${PALUDIS_FETCHERS_DIRS:-${PALUDIS_EBUILD_DIR}/fetchers/} ; do
+ prg=${d}/do$(echo ${a%%://*} | tr '[:upper:]' '[:lower:]' )
+ ebuild_notice "debug" "fetcher program candidate for '${a}' is '${prg}'"
+ [[ -x "${prg}" ]] && break
+ done
+ if [[ -x "${prg}" ]] ; then
+ ${prg} "${a}" "${DISTDIR}/${aa}"
+ else
+ eerror "Don't know how to fetch '${a}'"
+ fi
+ else
+ if ! [[ "${old_aa}" != "${aa}" ]] ; then
+ ebuild_section "Can't fetch ${aa}"
+ old_aa="${aa}"
+ fi
+ fi
+ fi
+ done
+
+ for a in ${unique_aa} ; do
+ [[ -f ${DISTDIR}/${a} ]] || nofetch="${nofetch} ${a}"
+ done
+
+ if [[ -n "${nofetch}" ]] ; then
+ local c
+ echo
+ eerror "Couldn't fetch the following components:"
+ for c in ${nofetch} ; do
+ eerror " * ${c}"
+ done
+ echo
+ die "builtin_fetch failed"
+ fi
+
+ local badfetch=
+ if [[ -f "${FILESDIR}/digest-${PN}-${PVR%-r0}" ]] ; then
+ local line items prg
+ while read line ; do
+ line=( ${line} )
+ if ! hasq "${line[2]}" ${A} ; then
+ ebuild_section "Skipping check for ${line[2]}"
+ continue
+ fi
+
+ prg="${PALUDIS_EBUILD_DIR}/digests/do$(echo ${line[0]} | tr \
+ '[[:upper:]]' '[[:lower:]]')"
+ if [[ -x "${prg}" ]] ; then
+ ebegin_unhooked "Checking ${line[0]} for ${line[2]}"
+ if [[ $("${prg}" "${DISTDIR}/${line[2]}" ) == "${line[1]}" ]] ; then
+ eend 0
+ else
+ eend 1
+ hasq "${line[2]}" ${badfetch} || badfetch="${badfetch} ${line[2]}"
+ fi
+ else
+ einfo_unhooked "Can't check ${line[0]} for ${line[2]}"
+ fi
+
+ done < "${FILESDIR}"/digest-${PN}-${PVR%-r0}
+ else
+ ebuild_section "No digest file, skipping integrity checks"
+ fi
+
+ if [[ -n "${badfetch}" ]] ; then
+ local c
+ echo
+ eerror "Bad digests encountered for the following components:"
+ for c in ${badfetch} ; do
+ eerror " * ${c}"
+ done
+ echo
+ die "builtin_fetch failed"
+ fi
+}
+
+ebuild_f_fetch()
+{
+ local old_sandbox_write="${SANDBOX_WRITE}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}${DISTDIR}"
+ if hasq "fetch" ${RESTRICT} ; then
+ ebuild_section "Skipping builtin_fetch (RESTRICT)"
+ elif hasq "fetch" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping builtin_fetch (SKIP_FUNCTIONS)"
+ else
+ ebuild_section "Starting builtin_fetch"
+ builtin_fetch
+ ebuild_section "Done builtin_fetch"
+ fi
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${old_sandbox_write}"
+ true
+}
+
+
diff --git a/paludis/repositories/gentoo/ebuild/builtin_init.bash b/paludis/repositories/gentoo/ebuild/builtin_init.bash
new file mode 100644
index 0000000..d7c5042
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/builtin_init.bash
@@ -0,0 +1,74 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License, version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+builtin_init()
+{
+ export ROOT="${ROOT//+(\/)//}"
+
+ local a
+ for a in P PV PR PN PVR PF CATEGORY FILESDIR ECLASSDIR PORTDIR \
+ DISTDIR KV PALUDIS_TMPDIR PALUDIS_EBUILD_LOG_LEVEL PALUDIS_EBUILD_DIR \
+ USERLAND KERNEL ARCH CHOST PALUDIS_COMMAND ROOT ; do
+ [[ -z "${!a}" ]] && die "\$${a} unset or empty"
+ declare -r ${a}="${!a}"
+ done
+
+ for a in FILESDIR ECLASSDIR PORTDIR DISTDIR ; do
+ [[ -d "${!a}" ]] || die "\$${a} (\"${!a}\") not a directory"
+ done
+
+ if [[ -e "${PALUDIS_TMPDIR}/${CATEGORY}/${PF}" ]] ; then
+ if type -p chflags &>/dev/null; then
+ chflags -R 0 "${PALUDIS_TMPDIR}/${CATEGORY}/${PF}" || die "Couldn't remove flags from workdir"
+ fi
+ rm -fr "${PALUDIS_TMPDIR}/${CATEGORY}/${PF}" || die "Couldn't remove previous work"
+ fi
+
+ export WORKDIR="${PALUDIS_TMPDIR}/${CATEGORY}/${PF}/work"
+ mkdir -p "${WORKDIR}" || die "Couldn't create \$WORKDIR (\"${WORKDIR}\")"
+ declare -r WORKDIR="${WORKDIR}"
+
+ export T="${PALUDIS_TMPDIR}/${CATEGORY}/${PF}/temp/"
+ mkdir -p "${T}" || die "Couldn't create \$T (\"${T}\")"
+ declare -r T="${T}"
+ export HOME="${T}"
+
+ export D="${PALUDIS_TMPDIR}/${CATEGORY}/${PF}/image/"
+ export D="${D//+(\/)//}"
+ mkdir -p "${D}" || die "Couldn't create \$D (\"${D}\")"
+ declare -r D="${D}"
+
+ export IMAGE="${D}"
+ declare -r IMAGE="${IMAGE}"
+
+ export S="${WORKDIR}/${P}"
+}
+
+ebuild_f_init()
+{
+ if hasq "init" ${RESTRICT} ; then
+ ebuild_section "Skipping builtin_init (RESTRICT)"
+ elif hasq "init" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping builtin_init (SKIP_FUNCTIONS)"
+ else
+ ebuild_section "Starting builtin_init"
+ builtin_init
+ ebuild_section "Done builtin_init"
+ fi
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/builtin_merge.bash b/paludis/repositories/gentoo/ebuild/builtin_merge.bash
new file mode 100644
index 0000000..452468e
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/builtin_merge.bash
@@ -0,0 +1,140 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License, version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+builtin_merge()
+{
+ ebuild_section "Merging to '${ROOT:-/}'..."
+
+ shopt -q dotglob
+ local olddotglob=$?
+ shopt -s dotglob
+
+ local v=$(vdb_path)
+ if [[ -z "${v}" ]] ; then
+ v=${ROOT}/var/db/pkg
+ fi
+ local dbdir="${v}/${CATEGORY}/${PF}"
+ ebuild_section "Writing VDB entry to '${dbdir}'..."
+ install -d "${dbdir}" || die "couldn't make pkg db directory (\"${dbdir}\")"
+ install -d "${v}/".cache || die "couldn't make pkg db cache"
+
+ local v VDB_FORMAT="paludis-2" COUNTER="$(date +%s )"
+ for v in CATEGORY CBUILD CHOST COUNTER DEPEND DESCRIPTION EAPI \
+ FEATURES HOMEPAGE INHERITED IUSE KEYWORDS LICENSE PDEPEND PF \
+ PROVIDE RDEPEND SLOT SRC_URI USE CONFIG_PROTECT CONFIG_PROTECT_MASK \
+ VDB_FORMAT PKGMANAGER ; do
+ echo "${!v}" > "${dbdir}"/${v} || die "pkg db write ${v} failed"
+ ebuild_notice "debug" "Writing VDB key ${v}=${!v}"
+ done
+ for v in ASFLAGS CBUILD CC CFLAGS CHOST CTARGET CXX CXXFLAGS \
+ EXTRA_ECONF EXTRA_EINSTALL EXTRA_EMAKE LDFLAGS LIBCXXFLAGS \
+ REPOSITORY ; do
+ [[ -z "${!v}" ]] && continue
+ echo "${!v}" > "${dbdir}"/${v} || die "pkg db write ${v} failed"
+ ebuild_notice "debug" "Writing VDB key ${v}=${!v}"
+ done
+
+ if [[ -n ${PALUDIS_EBUILD_OVERRIDE_CONFIG_PROTECT} ]]; then
+ CONFIG_PROTECT=${PALUDIS_EBUILD_OVERRIDE_CONFIG_PROTECT}
+ fi
+ if [[ -n ${PALUDIS_EBUILD_OVERRIDE_CONFIG_PROTECT_MASK} ]]; then
+ CONFIG_PROTECT_MASK=${PALUDIS_EBUILD_OVERRIDE_CONFIG_PROTECT_MASK}
+ fi
+
+ export CONFIG_PROTECT="${CONFIG_PROTECT}"
+ export CONFIG_PROTECT_MASK="${CONFIG_PROTECT_MASK}"
+
+ [[ -f "${EBUILD}" ]] && cp "${EBUILD}" ${dbdir}/
+
+ local reinstall=
+ if [[ -f "${dbdir}/CONTENTS" ]] ; then
+ mv "${dbdir}/CONTENTS" "${dbdir}/OLDCONTENTS" || die "save contents failed"
+ reinstall="yes"
+ fi
+
+ ebuild_notice "debug" "Writing VDB environment.bz2"
+ for v in ${USE_EXPAND} ; do
+ ebuild_notice "debug" "USE_EXPAND ${v}=${!v}"
+ done
+ ( set ; export -p | sed 's:^declare -rx:declare -x:' ) | bzip2 > ${dbdir}/environment.bz2
+ > ${dbdir}/CONTENTS
+
+ local merge=${PALUDIS_EBUILD_DIR}/merge
+ [[ -x "${merge}" ]] || merge="${PALUDIS_EBUILD_DIR_FALLBACK}"/merge
+ [[ -x "${merge}" ]] || die "Couldn't find merge"
+
+ local unmerge=${PALUDIS_EBUILD_DIR}/unmerge
+ [[ -x "${unmerge}" ]] || unmerge="${PALUDIS_EBUILD_DIR_FALLBACK}"/unmerge
+ [[ -x "${unmerge}" ]] || die "Couldn't find unmerge"
+
+ if [[ -n "${D}" ]] && [[ -d "${D}" ]] ; then
+ install -d "${ROOT%/}/" || die "couldn't make \${ROOT} (\"${ROOT}\")"
+ if [[ -d "${D}" ]] ; then
+ ${merge} "${D%/}/" "${ROOT%/}/" "${dbdir}/CONTENTS" || die "merge failed"
+ fi
+ fi
+
+ echo hash -r
+ hash -r
+
+ if ! /bin/sh -c 'echo Good, our shell is still usable' ; then
+ echo "Looks like our shell broke. Trying an ldconfig to fix it..."
+ ldconfig -r ${ROOT}
+ fi
+
+ if [[ -n "${reinstall}" ]] ; then
+ ${unmerge} "${ROOT%/}/" "${dbdir}/OLDCONTENTS" || die "unmerge failed"
+
+ echo hash -r
+ hash -r
+
+ if ! /bin/sh -c 'echo Good, our shell is still usable' ; then
+ echo "Looks like our shell broke. Trying an ldconfig to fix it..."
+ ldconfig -r ${ROOT}
+ fi
+
+ rm -f "${dbdir}/OLDCONTENTS"
+ fi
+
+ [[ $olddotglob != 0 ]] && shopt -u dotglob
+ shopt -q dotglob
+ [[ $olddotglob == $? ]] || ebuild_notice "warning" "shopt dotglob restore failed"
+}
+
+ebuild_f_merge()
+{
+ local old_sandbox_write="${SANDBOX_WRITE}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}${ROOT%/}/"
+ local old_sandbox_on="${SANDBOX_ON}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && [[ "$(canonicalise ${ROOT} )" != "/" ]] || SANDBOX_ON=0
+
+ if hasq "merge" ${RESTRICT} ; then
+ ebuild_section "Skipping builtin_merge (RESTRICT)"
+ elif hasq "merge" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping builtin_merge (SKIP_FUNCTIONS)"
+ else
+ ebuild_section "Starting builtin_merge"
+ builtin_merge
+ ebuild_section "Done builtin_merge"
+ fi
+
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${old_sandbox_write}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_ON="${old_sandbox_on}"
+ true
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/builtin_metadata.bash b/paludis/repositories/gentoo/ebuild/builtin_metadata.bash
new file mode 100644
index 0000000..dbc951f
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/builtin_metadata.bash
@@ -0,0 +1,38 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+ebuild_f_metadata()
+{
+ local key
+
+ for key in DEPEND RDEPEND PDEPEND IUSE SLOT SRC_URI RESTRICT LICENSE \
+ KEYWORDS INHERITED PROVIDE EAPI HOMEPAGE DESCRIPTION E_IUSE \
+ E_DEPEND E_RDEPEND E_PDEPEND E_KEYWORDS ; do
+ set -o noglob
+ local k=${!key}
+ k=${k/\\/\\\\}
+ k=${k/\"/\\\"}
+ echo "${key}=\""${k}"\""
+ set +o noglob
+ done
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/builtin_strip.bash b/paludis/repositories/gentoo/ebuild/builtin_strip.bash
new file mode 100644
index 0000000..9a4168e
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/builtin_strip.bash
@@ -0,0 +1,80 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License, version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+builtin_strip()
+{
+ STRIP=${STRIP:-${CHOST}-strip}
+ if ! type -p -- ${STRIP} >/dev/null; then
+ STRIP=strip
+ fi
+ PALUDIS_STRIP_FLAGS=${PALUDIS_STRIP_FLAGS:---strip-unneeded}
+
+ if [[ "${PALUDIS_DEBUG_BUILD}" == "split" ]] ; then
+ OBJCOPY=${OBJCOPY:-${CHOST}-objcopy}
+ if ! type -p -- "${OBJCOPY}" &>/dev/null ; then
+ OBJCOPY=objcopy
+ fi
+ if ! type -p -- "${OBJCOPY}" &>/dev/null ; then
+ die "Can't work out what OBJCOPY should be"
+ fi
+ fi
+
+ for fn in $(find "${D}" -type f \
+ \( -perm -0100 -or -perm -0010 -or -perm -0001 -or -name '*.so' -or -name '*.so.*' \)); do
+ local ft=$(file "${fn}")
+ if [[ $? != 0 || -z ${ft} ]]; then
+ return 1
+ fi
+
+ if [[ ${ft} == *"current ar archive"* ]]; then
+ if [[ "${PALUDIS_DEBUG_BUILD}" != "internal" ]] ; then
+ echo ${STRIP} -g "${fn}"
+ ${STRIP} -g "${fn}"
+ fi
+ elif [[ ${ft} == *"SB executable"* || ${ft} == *"SB shared object"* ]]; then
+ if [[ "${PALUDIS_DEBUG_BUILD}" == "split" ]] ; then
+ local fd="${D}usr/lib/debug/${fn:${#D}}.debug"
+ mkdir -p "$(dirname "${fd}" )"
+ echo ${OBJCOPY} --only-keep-debug "${fn}" "${fd}"
+ ${OBJCOPY} --only-keep-debug "${fn}" "${fd}"
+ echo ${OBJCOPY} --add-gnu-debuglink="${fd}" "${fn}"
+ ${OBJCOPY} --add-gnu-debuglink="${fd}" "${fn}"
+ chmod a-x,o-w "${fd}"
+ fi
+ if [[ "${PALUDIS_DEBUG_BUILD}" != "internal" ]] ; then
+ echo ${STRIP} ${PALUDIS_STRIP_FLAGS} "${fn}"
+ ${STRIP} ${PALUDIS_STRIP_FLAGS} "${fn}"
+ fi
+ fi
+ done
+}
+
+ebuild_f_strip()
+{
+ if hasq "strip" ${RESTRICT} ; then
+ ebuild_section "Skipping builtin_strip (RESTRICT)"
+ elif hasq "strip" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping builtin_strip (SKIP_FUNCTIONS)"
+ else
+ ebuild_section "Starting builtin_strip"
+ builtin_strip
+ ebuild_section "Done builtin_strip"
+ fi
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/builtin_tidyup.bash b/paludis/repositories/gentoo/ebuild/builtin_tidyup.bash
new file mode 100644
index 0000000..8927d23
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/builtin_tidyup.bash
@@ -0,0 +1,43 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License, version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+builtin_tidyup()
+{
+ if [[ -e "${PALUDIS_TMPDIR}/${CATEGORY}/${PF}" ]] ; then
+ if type -p chflags &>/dev/null; then
+ echo chflags -R 0 "${PALUDIS_TMPDIR}/${CATEGORY}/${PF}" 1>&2
+ chflags -R 0 "${PALUDIS_TMPDIR}/${CATEGORY}/${PF}" || die "Couldn't remove flags from workdir"
+ fi
+ echo rm -fr "${PALUDIS_TMPDIR}/${CATEGORY}/${PF}" 1>&2
+ rm -fr "${PALUDIS_TMPDIR}/${CATEGORY}/${PF}" || die "Couldn't remove work"
+ fi
+}
+
+ebuild_f_tidyup()
+{
+ if hasq "tidyup" ${RESTRICT} ; then
+ ebuild_section "Skipping builtin_tidyup (RESTRICT)"
+ elif hasq "tidyup" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping builtin_tidyup (SKIP_FUNCTIONS)"
+ else
+ ebuild_section "Starting builtin_tidyup"
+ builtin_tidyup
+ ebuild_section "Done builtin_tidyup"
+ fi
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/builtin_unmerge.bash b/paludis/repositories/gentoo/ebuild/builtin_unmerge.bash
new file mode 100644
index 0000000..e358d8a
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/builtin_unmerge.bash
@@ -0,0 +1,115 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License, version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+builtin_unmerge()
+{
+ local v=$(${PALUDIS_COMMAND} --configuration-variable installed location 2>/dev/null )
+ if [[ -z "${v}" ]] ; then
+ v=${ROOT}/var/db/pkg
+ fi
+
+ local dbdir="${v}/${CATEGORY}/${PF}" entry
+ [[ -d "${dbdir}" ]] || die "couldn't find pkg db directory (\"${dbdir}\")"
+
+ for v in CATEGORY CBUILD CHOST DEPEND DESCRIPTION EAPI \
+ FEATURES HOMEPAGE INHERITED IUSE KEYWORDS LICENSE PDEPEND PF \
+ PROVIDE RDEPEND SLOT SRC_URI USE CONFIG_PROTECT CONFIG_PROTECT_MASK \
+ VDB_FORMAT ASFLAGS CBUILD CC CFLAGS CHOST CTARGET CXX CXXFLAGS \
+ EXTRA_ECONF EXTRA_EINSTALL EXTRA_EMAKE LDFLAGS LIBCXXFLAGS \
+ REPOSITORY ; do
+ if [[ -f "${dbdir}/${v}" ]] ; then
+ eval "${v}=\$(< ${dbdir}/${v} ) || die \"Load key ${v} failed\""
+ else
+ eval "${v}="
+ fi
+ done
+
+ if [[ -f ${dbdir}/CONFIG_PROTECT ]]; then
+ CONFIG_PROTECT="$(< ${dbdir}/CONFIG_PROTECT) ${CONFIG_PROTECT}"
+ if [[ -f ${dbdir}/CONFIG_PROTECT_MASK ]]; then
+ CONFIG_PROTECT_MASK="$(< ${dbdir}/CONFIG_PROTECT_MASK)"
+ fi
+ else
+ local old_CONFIG_PROTECT="${CONFIG_PROTECT:+${CONFIG_PROTECT} }/etc"
+ eval $(bzcat "${dbdir}/environment.bz2" | while read line; do
+ line=${line//\'}
+ if [[ ${line%%=*} == CONFIG_PROTECT ]]; then
+ echo "CONFIG_PROTECT='${line#*=} ${CONFIG_PROTECT}'"
+ elif [[ ${line%%=*} == CONFIG_PROTECT_MASK ]]; then
+ echo "CONFIG_PROTECT_MASK='${line#*=}'"
+ fi
+ done)
+
+ # catalyst creates things with an empty CONFIG_PROTECT...
+ if [[ -z "${CONFIG_PROTECT// }" ]] ; then
+ ewarn "CONFIG_PROTECT from environment.bz2 is empty"
+ ewarn "Using a fallback of '${old_CONFIG_PROTECT}'"
+ CONFIG_PROTECT="${old_CONFIG_PROTECT}"
+ fi
+ fi
+
+ if [[ -n ${PALUDIS_EBUILD_OVERRIDE_CONFIG_PROTECT} ]]; then
+ CONFIG_PROTECT=${PALUDIS_EBUILD_OVERRIDE_CONFIG_PROTECT}
+ fi
+ if [[ -n ${PALUDIS_EBUILD_OVERRIDE_CONFIG_PROTECT_MASK} ]]; then
+ CONFIG_PROTECT_MASK=${PALUDIS_EBUILD_OVERRIDE_CONFIG_PROTECT_MASK}
+ fi
+
+ export CONFIG_PROTECT="${CONFIG_PROTECT}"
+ export CONFIG_PROTECT_MASK="${CONFIG_PROTECT_MASK}"
+
+ local unmerge=${PALUDIS_EBUILD_DIR}/unmerge
+ [[ -x "${unmerge}" ]] || unmerge="${PALUDIS_EBUILD_DIR_FALLBACK}"/unmerge
+ [[ -x "${unmerge}" ]] || die "Couldn't find unmerge"
+
+ ${unmerge} "${ROOT}/" "${dbdir}/CONTENTS" || die "unmerge failed"
+
+ echo hash -r
+ hash -r
+
+ if ! /bin/sh -c 'echo Good, our shell is still usable' ; then
+ echo "Looks like our shell broke. Trying an ldconfig to fix it..."
+ ldconfig -r ${ROOT}
+ fi
+
+ rm -fr "${dbdir}"
+}
+
+ebuild_f_unmerge()
+{
+ local old_sandbox_write="${SANDBOX_WRITE}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}${ROOT%/}/"
+ local old_sandbox_on="${SANDBOX_ON}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && [[ "$(canonicalise ${ROOT} )" != "/" ]] || SANDBOX_ON=0
+
+ if hasq "unmerge" ${RESTRICT} ; then
+ ebuild_section "Skipping builtin_unmerge (RESTRICT)"
+ elif hasq "unmerge" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping builtin_unmerge (SKIP_FUNCTIONS)"
+ else
+ ebuild_section "Starting builtin_unmerge"
+ builtin_unmerge
+ ebuild_section "Done builtin_unmerge"
+ fi
+
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${old_sandbox_write}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_ON="${old_sandbox_on}"
+ true
+}
+
+
diff --git a/paludis/repositories/gentoo/ebuild/builtin_variable.bash b/paludis/repositories/gentoo/ebuild/builtin_variable.bash
new file mode 100644
index 0000000..e140188
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/builtin_variable.bash
@@ -0,0 +1,23 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License, version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+ebuild_f_variable()
+{
+ echo "${!PALUDIS_VARIABLE}"
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/digests/Makefile.am b/paludis/repositories/gentoo/ebuild/digests/Makefile.am
new file mode 100644
index 0000000..d4ad645
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/digests/Makefile.am
@@ -0,0 +1,31 @@
+MAINTAINERCLEANFILES = Makefile.in
+CLEANFILES = *~
+SUBDIRS = .
+
+libexecprogdir = $(libexecdir)/paludis/digests/
+
+libexecprog_PROGRAMS = \
+ dosha256 \
+ dormd160 \
+ domd5
+
+dosha256_SOURCES = dosha256.cc
+dosha256_LDADD = $(top_builddir)/paludis/digests/libpaludisdigests.la
+
+dormd160_SOURCES = dormd160.cc
+dormd160_LDADD = $(top_builddir)/paludis/digests/libpaludisdigests.la
+
+domd5_SOURCES = domd5.cc
+domd5_LDADD = $(top_builddir)/paludis/digests/libpaludisdigests.la
+
+TESTS_ENVIRONMENT = env \
+ PALUDIS_EBUILD_DIR="$(srcdir)/ebuild/" \
+ TEST_SCRIPT_DIR="$(srcdir)/" \
+ bash $(top_srcdir)/test/run_test.sh
+
+AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@
+
+built-sources : $(BUILT_SOURCES)
+ for s in `echo $(SUBDIRS) | tr -d .` ; do $(MAKE) -C $$s built-sources || exit 1 ; done
+
+
diff --git a/paludis/repositories/gentoo/ebuild/digests/domd5.cc b/paludis/repositories/gentoo/ebuild/digests/domd5.cc
new file mode 100644
index 0000000..d139f47
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/digests/domd5.cc
@@ -0,0 +1,54 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/digests/md5.hh>
+#include <iostream>
+#include <cstdlib>
+#include <fstream>
+
+int
+main(int argc, char * argv[])
+{
+ if (argc >= 3)
+ {
+ std::cerr << "usage: " << argv[0] << " [filename]" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (argc == 2)
+ {
+ std::ifstream f(argv[1]);
+ if (! f)
+ {
+ std::cerr << argv[0] << ": could not open '" << argv[1] << "'" << std::endl;
+ return EXIT_FAILURE;
+ }
+ paludis::MD5 sum(f);
+ std::cout << sum.hexsum() << std::endl;
+ }
+ else
+ {
+ paludis::MD5 sum(std::cin);
+ std::cout << sum.hexsum() << std::endl;
+ }
+
+}
+
+
+
diff --git a/paludis/repositories/gentoo/ebuild/digests/dormd160.cc b/paludis/repositories/gentoo/ebuild/digests/dormd160.cc
new file mode 100644
index 0000000..47fcd7f
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/digests/dormd160.cc
@@ -0,0 +1,53 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/digests/rmd160.hh>
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+
+int
+main(int argc, char * argv[])
+{
+ if (argc >= 3)
+ {
+ std::cerr << "usage: " << argv[0] << " [filename]" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (argc == 2)
+ {
+ std::ifstream f(argv[1]);
+ if (! f)
+ {
+ std::cerr << argv[0] << ": could not open '" << argv[1] << "'" << std::endl;
+ return EXIT_FAILURE;
+ }
+ paludis::RMD160 sum(f);
+ std::cout << sum.hexsum() << std::endl;
+ }
+ else
+ {
+ paludis::RMD160 sum(std::cin);
+ std::cout << sum.hexsum() << std::endl;
+ }
+
+}
+
+
diff --git a/paludis/repositories/gentoo/ebuild/digests/dosha256.cc b/paludis/repositories/gentoo/ebuild/digests/dosha256.cc
new file mode 100644
index 0000000..056ce5a
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/digests/dosha256.cc
@@ -0,0 +1,52 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/digests/sha256.hh>
+#include <iostream>
+#include <cstdlib>
+#include <fstream>
+
+int
+main(int argc, char * argv[])
+{
+ if (argc >= 3)
+ {
+ std::cerr << "usage: " << argv[0] << " [filename]" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (argc == 2)
+ {
+ std::ifstream f(argv[1]);
+ if (! f)
+ {
+ std::cerr << argv[0] << ": could not open '" << argv[1] << "'" << std::endl;
+ return EXIT_FAILURE;
+ }
+ paludis::SHA256 sum(f);
+ std::cout << sum.hexsum() << std::endl;
+ }
+ else
+ {
+ paludis::SHA256 sum(std::cin);
+ std::cout << sum.hexsum() << std::endl;
+ }
+
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/ebuild.bash b/paludis/repositories/gentoo/ebuild/ebuild.bash
new file mode 100755
index 0000000..ec3b179
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/ebuild.bash
@@ -0,0 +1,352 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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_PREDICT="${SANDBOX_PREDICT+${SANDBOX_PREDICT}:}"
+ export SANDBOX_PREDICT="${SANDBOX_PREDICT}/proc/self/maps:/dev/console:/dev/random"
+ export SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}"
+ export SANDBOX_WRITE="${SANDBOX_WRITE}/dev/shm:/dev/stdout:/dev/stderr:/dev/null:/dev/tty"
+ export SANDBOX_WRITE="${SANDBOX_WRITE}:${PALUDIS_TMPDIR}:/var/cache"
+ 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
+export REAL_CHOST="${CHOST}"
+
+shopt -s expand_aliases
+shopt -s extglob
+
+EBUILD_KILL_PID=$$
+alias die='diefunc "$FUNCNAME" "$LINENO"'
+alias assert='_pipestatus="${PIPESTATUS[*]}"; [[ -z "${_pipestatus//[ 0]/}" ]] || diefunc "$FUNCNAME" "$LINENO" "$_pipestatus"'
+trap 'echo "die trap: exiting with error." 1>&2 ; exit 250' 15
+
+export EBUILD_PROGRAM_NAME="$0"
+
+diefunc()
+{
+ local func="$1" line="$2"
+ shift 2
+ echo 1>&2
+ echo "!!! ERROR in ${CATEGORY:-?}/${PF:-?}:" 1>&2
+ echo "!!! In ${func:-?} at line ${line:-?}" 1>&2
+ echo "!!! ${*:-(no message provided)}" 1>&2
+ echo 1>&2
+
+ echo "!!! Call stack:" 1>&2
+ for (( n = 1 ; n < ${#FUNCNAME[@]} ; ++n )) ; do
+ funcname=${FUNCNAME[${n}]}
+ sourcefile=${BASH_SOURCE[${n}]}
+ lineno=${BASH_LINENO[$(( n - 1 ))]}
+ echo "!!! * ${funcname} (${sourcefile}:${lineno})" 1>&2
+ done
+ echo 1>&2
+
+ if [[ -n "${PALUDIS_EXTRA_DIE_MESSAGE}" ]] ; then
+ echo "${PALUDIS_EXTRA_DIE_MESSAGE}" 1>&2
+ echo 1>&2
+ fi
+
+ kill ${EBUILD_KILL_PID}
+ exit 249
+}
+
+if [[ -n "${PALUDIS_EBUILD_DIR_FALLBACK}" ]] ; then
+ export PATH="${PALUDIS_EBUILD_DIR_FALLBACK}/utils:${PATH}"
+fi
+export PATH="${PALUDIS_EBUILD_DIR}/utils:${PATH}"
+EBUILD_MODULES_DIR=$(canonicalise $(dirname $0 ) )
+[[ -d ${EBUILD_MODULES_DIR} ]] || die "${EBUILD_MODULES_DIR} is not a directory"
+export PALUDIS_EBUILD_MODULES_DIR="${EBUILD_MODULES_DIR}"
+
+ebuild_load_module()
+{
+ source "${EBUILD_MODULES_DIR}/${1}.bash" || die "Error loading module ${1}"
+}
+
+ebuild_load_module echo_functions
+ebuild_load_module kernel_functions
+ebuild_load_module sandbox
+ebuild_load_module portage_stubs
+ebuild_load_module list_functions
+ebuild_load_module multilib_functions
+ebuild_load_module install_functions
+ebuild_load_module build_functions
+ebuild_load_module eclass_functions
+ebuild_load_module work_around_broken_utilities
+
+export PALUDIS_HOME="$(canonicalise ${PALUDIS_HOME:-${HOME}} )"
+
+ebuild_source_profile()
+{
+ if [[ -f ${1}/parent ]] ; then
+ while read line ; do
+ grep --silent '^[[:space:]]*#' <<<"${line}" && continue
+ grep --silent '[^[:space:]]' <<<"${line}" || continue
+ ebuild_source_profile $(canonicalise ${1}/${line} )
+ done <${1}/parent
+ fi
+
+ if [[ -f ${1}/make.defaults ]] ; then
+ eval "$(sed -e 's/^\([a-zA-Z0-9\-_]\+=\)/export \1/' ${1}/make.defaults )" \
+ || die "Couldn't source ${1}/make.defaults"
+ fi
+
+ if [[ -f ${1}/bashrc ]] ; then
+ source ${1}/bashrc || die "Couldn't source ${1}/bashrc"
+ fi
+}
+
+save_vars="USE USE_EXPAND USE_EXPAND_HIDDEN ${USE_EXPAND}"
+default_save_vars="CONFIG_PROTECT CONFIG_PROTECT_MASK"
+
+for var in ${save_vars} ${default_save_vars} ; do
+ ebuild_notice "debug" "Saving ${var}=${!var}"
+ eval "export save_var_${var}='${!var}'"
+done
+
+if [[ -n "${PALUDIS_PROFILE_DIRS}" ]] ; then
+ for var in ${PALUDIS_PROFILE_DIRS} ; do
+ ebuild_source_profile $(canonicalise "${var}")
+ done
+elif [[ -n "${PALUDIS_PROFILE_DIR}" ]] ; then
+ ebuild_source_profile $(canonicalise "${PALUDIS_PROFILE_DIR}")
+fi
+
+unset ${save_vars}
+
+for f in ${PALUDIS_BASHRC_FILES} ; do
+ if [[ -f ${f} ]] ; then
+ ebuild_notice "debug" "Loading bashrc file ${f}"
+ source ${f}
+ else
+ ebuild_notice "debug" "Skipping bashrc file ${f}"
+ fi
+done
+
+for var in ${save_vars} ; do
+ if [[ -n ${!var} ]] ; then
+ die "${var} should not be set in bashrc. Aborting."
+ fi
+done
+
+for var in ${save_vars} ; do
+ eval "export ${var}=\${save_var_${var}}"
+done
+
+for var in ${default_save_vars} ; do
+ if [[ -z ${!var} ]] ; then
+ eval "export ${var}=\${save_var_${var}}"
+ else
+ ebuild_notice "debug" "Not restoring ${var}"
+ fi
+done
+
+[[ -z "${CBUILD}" ]] && export CBUILD="${CHOST}"
+
+ebuild_load_ebuild()
+{
+ if [[ -n "${PALUDIS_LOAD_ENVIRONMENT}" ]] ; then
+ [[ -d ${PALUDIS_TMPDIR} ]] \
+ || die "You need to create PALUDIS_TMPDIR (${PALUDIS_TMPDIR})."
+
+ local save_PALUDIS_EXTRA_DIE_MESSAGE="${PALUDIS_EXTRA_DIE_MESSAGE}"
+ local real_PALUDIS_EXTRA_DIE_MESSAGE="
+!!! Could not extract the saved environment file. This is usually
+!!! caused by a broken environment.bz2 that was generated by an old
+!!! Portage version. The file that needs repairing is:
+!!! ${PALUDIS_LOAD_ENVIRONMENT}
+!!! Try copying this file, bunzip2ing it and sourcing it using a new
+!!! bash shell (do not continue to use said shell afterwards). You
+!!! should get an error that give you a rough idea of where the
+!!! problem lies.
+"
+ export PALUDIS_EXTRA_DIE_MESSAGE="${real_PALUDIS_EXTRA_DIE_MESSAGE}"
+
+ bunzip2 < "${PALUDIS_LOAD_ENVIRONMENT}" > ${PALUDIS_TMPDIR}/environment-${CATEGORY}-${PF} \
+ || die "Can't extract ${PALUDIS_LOAD_ENVIRONMENT}"
+
+ sed -i \
+ -e '/^diefunc ()/,/^}/d' \
+ -e '/^perform_hook ()/,/^}/d' \
+ -e '/^inherit ()/,/^}/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?ROOTPATH=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?PATH=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?T=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?PALUDIS_TMPDIR=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?PALUDIS_EBUILD_LOG_LEVEL=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?PORTDIR=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?FILESDIR=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?ECLASSDIR=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?DISTDIR=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?PALUDIS_EBUILD_DIR=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?PALUDIS_COMMAND=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?PALUDIS_CLIENT=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?\(PALUDIS\|CONTRARIUS\|GTKPALUDIS\)_CMDLINE_.*=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?\(ADJUTRIX\|QUALUDIS\)_CMDLINE_.*=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?\(PALUDIS\|CONTRARIUS\|GTKPALUDIS\)_OPTIONS=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?\(ADJUTRIX\|QUALUDIS\)_OPTIONS=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?PALUDIS_HOME=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?PALUDIS_PID=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?EBUILD_KILL_PID=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?ROOT=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?SANDBOX/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?BASH_/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?SHELLOPTS/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?..\?ID=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?LD_/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?CATEGORY=/d' \
+ -e '/^\(declare \(-[^ ]\+ \)\?\)\?\(PN\|PV\|P\|PVR\|PF\)=/d' \
+ "${PALUDIS_TMPDIR}/environment-${CATEGORY}-${PF}"
+
+ export PALUDIS_EXTRA_DIE_MESSAGE="${real_PALUDIS_EXTRA_DIE_MESSAGE}"
+
+ echo source "${PALUDIS_TMPDIR}/environment-${CATEGORY}-${PF}" 1>&2
+ source "${PALUDIS_TMPDIR}/environment-${CATEGORY}-${PF}" \
+ || die "Can't load saved environment"
+
+ export PALUDIS_EXTRA_DIE_MESSAGE="${save_PALUDIS_EXTRA_DIE_MESSAGE}"
+
+ rm "${PALUDIS_TMPDIR}/environment-${CATEGORY}-${PF}"
+ fi
+
+ export EBUILD="${1}"
+ unset IUSE DEPEND RDEPEND PDEPEND KEYWORDS
+
+ if [[ "${CATEGORY}" == "virtual" ]] ; then
+ if [[ -f "${1}" ]] ; then
+ source ${1} || die "Error sourcing ebuild '${1}'"
+ elif [[ -e "${1}" ]] ; then
+ die "'${1}' exists but is not a regular file"
+ fi
+ else
+ [[ -f "${1}" ]] || die "Ebuild '${1}' is not a file"
+ source ${1} || die "Error sourcing ebuild '${1}'"
+ fi
+ [[ ${RDEPEND-unset} == "unset" ]] && RDEPEND="${DEPEND}"
+
+ IUSE="${IUSE} ${E_IUSE}"
+ DEPEND="${DEPEND} ${E_DEPEND}"
+ RDEPEND="${RDEPEND} ${E_RDEPEND}"
+ PDEPEND="${PDEPEND} ${E_PDEPEND}"
+ KEYWORDS="${KEYWORDS} ${E_KEYWORDS}"
+ [[ ${EAPI-unset} == "unset" ]] && EAPI="0"
+}
+
+perform_hook()
+{
+ export HOOK=${1}
+ ebuild_notice "debug" "Starting hook '${HOOK}'"
+
+ local old_sandbox_on="${SANDBOX_ON}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && export SANDBOX_ON="0"
+
+ local hook_dir
+ for hook_dir in ${PALUDIS_HOOK_DIRS} ; do
+ [[ -d "${hook_dir}/${HOOK}" ]] || continue
+ local hook_file
+ for hook_file in "${hook_dir}/${HOOK}/"*.bash ; do
+ [[ -e "${hook_file}" ]] || continue
+ ebuild_notice "debug" "Starting hook script '${hook_file}' for '${HOOK}'"
+ if ! ( source "${hook_file}" ) ; then
+ ebuild_notice "warning" "Hook '${hook_file}' returned failure"
+ else
+ ebuild_notice "debug" "Hook '${hook_file}' returned success"
+ fi
+ done
+ done
+
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && export SANDBOX_ON="${old_sandbox_on}"
+ true
+}
+
+ebuild_main()
+{
+ if ! [[ -e /proc/self ]] && [[ "$(uname -s)" == Linux ]] ; then
+ ebuild_notice "warning" "/proc appears to be unmounted or unreadable."
+ ebuild_notice "warning" "This will cause problems."
+ fi
+
+ local action ebuild="$1"
+ shift
+
+ for action in $@ ; do
+ case ${action} in
+ metadata|variable|init|fetch|merge|unmerge|tidyup|strip)
+ ebuild_load_module builtin_${action}
+ ;;
+
+ unpack|compile|install|test)
+ ebuild_load_module src_${action}
+ ;;
+
+ setup|config|nofetch|preinst|postinst|prerm|postrm)
+ ebuild_load_module pkg_${action}
+ ;;
+
+ *)
+ ebuild_load_module usage_error
+ ebuild_f_usage_error "Unknown action '${action}'"
+ exit 1
+ ;;
+ esac
+ done
+
+ if [[ $1 == metadata ]] || [[ $1 == variable ]] ; then
+ perform_hook ebuild_${action}_pre
+ if [[ $1 != variable ]] || [[ -n "${ebuild}" ]] ; then
+ for f in cut tr date ; do
+ eval "export ebuild_real_${f}=\"$(which $f )\""
+ eval "${f}() { ebuild_notice qa 'global scope ${f}' ; $(which $f ) \"\$@\" ; }"
+ done
+ PATH="" ebuild_load_ebuild "${ebuild}"
+ fi
+ if ! ebuild_f_${1} ; then
+ perform_hook ebuild_${action}_fail
+ die "${1} failed"
+ fi
+ perform_hook ebuild_${action}_post
+ else
+ ebuild_load_ebuild "${ebuild}"
+ for action in $@ ; do
+ export EBUILD_PHASE="${action}"
+ perform_hook ebuild_${action}_pre
+ if ! ebuild_f_${action} ; then
+ perform_hook ebuild_${action}_fail
+ die "${action} failed"
+ fi
+ if [[ ${action} == "init" ]] ; then
+ ebuild_load_ebuild "${ebuild}"
+ fi
+ perform_hook ebuild_${action}_post
+ done
+ fi
+}
+
+ebuild_main $@
+
diff --git a/paludis/repositories/gentoo/ebuild/echo_functions.bash.in b/paludis/repositories/gentoo/ebuild/echo_functions.bash.in
new file mode 100644
index 0000000..279121c
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/echo_functions.bash.in
@@ -0,0 +1,238 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+@GENERATED_FILE@
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+[[ -z ${PALUDIS_COLOURS} ]] && PALUDIS_COLOURS=@COLOURSCHEME@
+
+COLOUR_GREEN=$'\e[32;01m'
+COLOUR_YELLOW=$'\e[33;01m'
+COLOUR_RED=$'\e[31;01m'
+COLOUR_BLUE=$'\e[34;01m'
+COLOUR_PINK=$'\e[35;01m'
+
+if [[ ${PALUDIS_COLOURS} == pink ]]; then
+ COLOUR_GOOD=${COLOUR_PINK}
+ COLOUR_WARN=${COLOUR_YELLOW}
+ COLOUR_BAD=${COLOUR_RED}
+ COLOUR_BRACKET=${COLOUR_PINK}
+else
+ COLOUR_GOOD=${COLOUR_GREEN}
+ COLOUR_WARN=${COLOUR_YELLOW}
+ COLOUR_BAD=${COLOUR_RED}
+ COLOUR_BRACKET=${COLOUR_BLUE}
+fi
+
+COLOUR_NORMAL=$'\e[0m'
+PALUDIS_ENDCOL=$'\e[A\e['$(( ${COLUMNS:-80} - 7 ))'G'
+
+paludis_ecmd()
+{
+ local cmd="$1" hook="$2" prefix="$3" message="$4" newline="$5"
+
+ echo -n "${prefix}${message}"
+ [[ -z "${newline}" ]] && echo
+
+ if type perform_hook &>/dev/null ; then
+ if [[ -n "${hook}" ]] ; then
+ MESSAGE="${message}" perform_hook "${hook}"
+ fi
+ fi
+}
+
+einfon()
+{
+ paludis_ecmd \
+ "einfon" \
+ "einfo" \
+ "`echo -ne " ${COLOUR_GOOD}*${COLOUR_NORMAL} "`" \
+ "$*" \
+ "no"
+}
+
+einfo()
+{
+ paludis_ecmd \
+ "einfo" \
+ "einfo" \
+ "`echo -ne " ${COLOUR_GOOD}*${COLOUR_NORMAL} "`" \
+ "$*"
+}
+
+einfo_unhooked()
+{
+ paludis_ecmd \
+ "einfo" \
+ "" \
+ "`echo -ne " ${COLOUR_GOOD}*${COLOUR_NORMAL} "`" \
+ "$*"
+}
+
+elog()
+{
+ paludis_ecmd \
+ "elog" \
+ "einfo" \
+ "`echo -ne " ${COLOUR_GOOD}*${COLOUR_NORMAL} "`" \
+ "$*"
+
+ if [[ -n "${PALUDIS_ELOG_FILE}" ]] ; then
+ echo "$@" >> "${PALUDIS_ELOG_FILE}"
+ fi
+}
+
+ewarn()
+{
+ paludis_ecmd \
+ "ewarn" \
+ "ewarn" \
+ "`echo -ne " ${COLOUR_WARN}*${COLOUR_NORMAL} "`" \
+ "$*"
+}
+
+eerror()
+{
+ paludis_ecmd \
+ "eerror" \
+ "eerror" \
+ "`echo -ne " ${COLOUR_BAD}*${COLOUR_NORMAL} "`" \
+ "$*"
+}
+
+ebegin()
+{
+ paludis_ecmd \
+ "ebegin" \
+ "einfo" \
+ "`echo -ne " ${COLOUR_GOOD}*${COLOUR_NORMAL} "`" \
+ "$* ..."
+}
+
+ebegin_unhooked()
+{
+ paludis_ecmd \
+ "ebegin" \
+ "" \
+ "`echo -ne " ${COLOUR_GOOD}*${COLOUR_NORMAL} "`" \
+ "$* ..."
+}
+
+_eend()
+{
+ local retval=${1:-0} efunc=${2:-eerror} msg
+ shift 2
+
+ if [[ ${retval} == 0 ]]; then
+ msg="${COLOUR_BRACKET}[ ${COLOUR_GOOD}ok${COLOUR_BRACKET} ]${COLOUR_NORMAL}"
+ else
+ if [[ -n "$*" ]]; then
+ ${efunc} $*
+ fi
+ msg="${COLOUR_BRACKET}[ ${COLOUR_BAD}!!${COLOUR_BRACKET} ]${COLOUR_NORMAL}"
+ fi
+
+ echo -e "${PALUDIS_ENDCOL} ${msg}"
+
+ return ${retval}
+}
+
+eend()
+{
+ local retval=${1:-0}
+ shift
+ _eend ${retval} eerror "$*"
+ return ${retval}
+}
+
+ewend()
+{
+ local retval=${1:-0}
+ shift
+ _eend ${retval} ewarn "$*"
+ return ${retval}
+}
+
+use_with()
+{
+ if useq "${1}" ; then
+ echo "--with-${2:-${1}}${3+=${3}}"
+ else
+ echo "--without-${2:-${1}}"
+ fi
+}
+
+use_enable()
+{
+ if useq "${1}" ; then
+ echo "--enable-${2:-${1}}${3+=${3}}"
+ else
+ echo "--disable-${2:-${1}}"
+ fi
+}
+
+ebuild_notice_level()
+{
+ case "$1" in
+ debug)
+ echo "1";
+ ;;
+
+ qa)
+ echo "2";
+ ;;
+
+ warning)
+ echo "3";
+ ;;
+
+ silent)
+ echo "4";
+ ;;
+
+ *)
+ echo "[WARNING.EBUILD] Bad value '$1' for qa level" 1>&2
+ echo "2";
+ ;;
+ esac
+}
+
+ebuild_notice()
+{
+ local level="$1"
+ shift
+
+ local level_num=$(ebuild_notice_level "${level}" )
+ local min_level_num=$(ebuild_notice_level "${PALUDIS_EBUILD_LOG_LEVEL}" )
+
+ if [[ "${level_num}" -ge "${min_level_num}" ]] ; then
+ local upper_level=$(echo ${level} | ${ebuild_real_tr:-tr} '[:lower:]' '[:upper:]' )
+ echo -n "${EBUILD_PROGRAM_NAME:-ebuild.bash}@$(${ebuild_real_date:-date} +%s ): " 1>&2
+ echo "[${upper_level}.EBUILD] $* (from ${EBUILD:-?})" 1>&2
+ fi
+ true
+}
+
+ebuild_section()
+{
+ echo ">>> $*"
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/echo_functions_TEST.bash b/paludis/repositories/gentoo/ebuild/echo_functions_TEST.bash
new file mode 100644
index 0000000..6e4ad27
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/echo_functions_TEST.bash
@@ -0,0 +1,45 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+use_with_TEST()
+{
+ export USE="foo"
+ test_equality "$(use_with foo )" "--with-foo"
+ test_equality "$(use_with foo bar )" "--with-bar"
+ test_equality "$(use_with foo bar baz )" "--with-bar=baz"
+
+ export USE="oink"
+ test_equality "$(use_with foo )" "--without-foo"
+ test_equality "$(use_with foo bar )" "--without-bar"
+ test_equality "$(use_with foo bar baz )" "--without-bar"
+}
+
+
+use_enable_TEST()
+{
+ export USE="foo"
+ test_equality "$(use_enable foo )" "--enable-foo"
+ test_equality "$(use_enable foo bar )" "--enable-bar"
+ test_equality "$(use_enable foo bar baz )" "--enable-bar=baz"
+
+ export USE="oink"
+ test_equality "$(use_enable foo )" "--disable-foo"
+ test_equality "$(use_enable foo bar )" "--disable-bar"
+ test_equality "$(use_enable foo bar baz )" "--disable-bar"
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/eclass_functions.bash b/paludis/repositories/gentoo/ebuild/eclass_functions.bash
new file mode 100644
index 0000000..9c6334d
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/eclass_functions.bash
@@ -0,0 +1,85 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+EXPORT_FUNCTIONS()
+{
+ [[ -z "${ECLASS}" ]] && die "EXPORT_FUNCTIONS called but ECLASS undefined"
+
+ local e
+ for e in "$@" ; do
+ case "$e" in
+ pkg_nofetch|pkg_setup|pkg_prerm|pkg_postrm|pkg_preinst|pkg_postinst|pkg_config)
+ eval "${e}() { ${ECLASS}_${e} \"\$@\" ; }"
+ ;;
+
+ src_unpack|src_compile|src_install|src_test)
+ eval "${e}() { ${ECLASS}_${e} \"\$@\" ; }"
+ ;;
+
+ *)
+ eval "${e}() { ${ECLASS}_${e} \"\$@\" ; }"
+ ebuild_notice "qa" "$e should not be in EXPORT_FUNCTIONS for ${ECLASS}"
+ ;;
+ esac
+ done
+}
+
+inherit()
+{
+ [[ -n "${PALUDIS_SKIP_INHERIT}" ]] && return
+
+ local e ee location=
+ for e in "$@" ; do
+ for ee in ${ECLASSDIRS:-${ECLASSDIR}} ; do
+ [[ -f "${ee}/${e}.eclass" ]] && location="${ee}/${e}.eclass"
+ done
+ local old_ECLASS="${ECLASS}"
+ export ECLASS="${e}"
+
+ local current_IUSE="${IUSE}" unset_IUSE="${IUSE-unset}"
+ local current_DEPEND="${DEPEND}" unset_DEPEND="${DEPEND-unset}"
+ local current_RDEPEND="${RDEPEND}" unset_RDEPEND="${RDEPEND-unset}"
+ local current_PDEPEND="${PDEPEND}" unset_PDEPEND="${PDEPEND-unset}"
+ local current_KEYWORDS="${KEYWORDS}" unset_KEYWORDS="${KEYWORDS-unset}"
+
+ unset IUSE DEPEND RDEPEND PDEPEND KEYWORDS
+
+ [[ -z "${location}" ]] && die "Error finding eclass ${e}"
+ source "${location}" || die "Error sourcing eclass ${e}"
+ hasq "${ECLASS}" ${INHERITED} || export INHERITED="${INHERITED} ${ECLASS}"
+
+ E_IUSE="${E_IUSE} ${IUSE}"
+ E_PDEPEND="${E_PDEPEND} ${PDEPEND}"
+ E_RDEPEND="${E_RDEPEND} ${RDEPEND}"
+ E_DEPEND="${E_DEPEND} ${DEPEND}"
+ E_KEYWORDS="${KEYWORDS:+${KEYWORDS} }${E_KEYWORDS}"
+
+ [[ "unset" == "${unset_IUSE}" ]] && unset IUSE || IUSE="${current_IUSE}"
+ [[ "unset" == "${unset_DEPEND}" ]] && unset DEPEND || DEPEND="${current_DEPEND}"
+ [[ "unset" == "${unset_RDEPEND}" ]] && unset RDEPEND || RDEPEND="${current_RDEPEND}"
+ [[ "unset" == "${unset_PDEPEND}" ]] && unset PDEPEND || PDEPEND="${current_PDEPEND}"
+ [[ "unset" == "${unset_KEYWORDS}" ]] && unset KEYWORDS || KEYWORDS="${current_KEYWORDS}"
+
+ export ECLASS="${old_ECLASS}"
+ done
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/install_functions.bash b/paludis/repositories/gentoo/ebuild/install_functions.bash
new file mode 100644
index 0000000..e23628c
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/install_functions.bash
@@ -0,0 +1,109 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+umask 022
+export DESTTREE="/usr"
+export INSDESTTREE=""
+export EXEDESTTREE=""
+export DOCDESTTREE=""
+export INSOPTIONS="-m0644"
+export EXEOPTIONS="-m0755"
+export LIBOPTIONS="-m0644"
+export DIROPTIONS="-m0755"
+export MOPREFIX="${PN}"
+
+keepdir()
+{
+ dodir "$@"
+ if [[ "${1}" == "-R" ]] || [[ "${1}" == "-r" ]] ; then
+ shift
+ find "$@" -type d -printf "${D}/%p/.keep\0" | xargs -0 touch
+ assert "Failed to create .keep files"
+ else
+ local f
+ for f in "$@" ; do
+ touch "${D}/${f}/.keep" || die "Couldn't touch .keep in ${f}"
+ done
+ fi
+}
+
+into()
+{
+ if [[ "${1}" == "/" ]] ; then
+ export DESTTREE=
+ else
+ export DESTTREE="${1}"
+ [[ -d "${D}${DESTTREE}" ]] || install -d "${D}${DESTTREE}"
+ fi
+}
+
+insinto()
+{
+ if [[ "${1}" == "/" ]] ; then
+ export INSDESTTREE=
+ else
+ export INSDESTTREE="${1}"
+ [[ -d "${D}${INSDESTTREE}" ]] || install -d "${D}${INSDESTTREE}"
+ fi
+}
+
+exeinto()
+{
+ if [[ "${1}" == "/" ]] ; then
+ export EXEDESTTREE=
+ else
+ export EXEDESTTREE="${1}"
+ [[ -d "${D}${EXEDESTTREE}" ]] || install -d "${D}${EXEDESTTREE}"
+ fi
+}
+
+docinto()
+{
+ if [[ "${1}" == "/" ]] ; then
+ export DOCDESTTREE=
+ else
+ export DOCDESTTREE="${1}"
+ [[ -d "${D}usr/share/doc/${PF}/${DOCDESTTREE}" ]] || \
+ install -d "${D}usr/share/doc/${PF}/${DOCDESTTREE}"
+ fi
+}
+
+insopts()
+{
+ export INSOPTIONS="$@"
+}
+
+diropts()
+{
+ export DIROPTIONS="$@"
+}
+
+exeopts()
+{
+ export EXEOPTIONS="$@"
+}
+
+libopts()
+{
+ export LIBOPTIONS="$@"
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/kernel_functions.bash b/paludis/repositories/gentoo/ebuild/kernel_functions.bash
new file mode 100644
index 0000000..9126376
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/kernel_functions.bash
@@ -0,0 +1,59 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon functions.sh from Baselayout, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+KV_major()
+{
+ [[ -z $1 ]] && return 1
+ local KV=$@
+ echo ${KV%%.*}
+}
+
+KV_minor()
+{
+ [[ -z $1 ]] && return 1
+ local KV=$@
+ KV=${KV#*.}
+ echo ${KV%%.*}
+}
+
+KV_micro()
+{
+ [[ -z $1 ]] && return 1
+ local KV=$@
+ KV=${KV#*.*.}
+ echo ${KV%%[^[:digit:]]*}
+}
+
+KV_to_int()
+{
+ [[ -z $1 ]] && return 1
+
+ local major=$(KV_major "$1")
+ local minor=$(KV_minor "$1")
+ local micro=$(KV_micro "$1")
+ echo $(( major * 65536 + minor * 256 + micro ))
+}
+
+get_KV()
+{
+ echo $(KV_to_int "$(uname -r)")
+}
diff --git a/paludis/repositories/gentoo/ebuild/kernel_functions_TEST.bash b/paludis/repositories/gentoo/ebuild/kernel_functions_TEST.bash
new file mode 100644
index 0000000..4b3271d
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/kernel_functions_TEST.bash
@@ -0,0 +1,41 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License, version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+KV_major_TEST()
+{
+ test_equality "$(KV_major 2.4.6)" "2"
+}
+
+KV_minor_TEST()
+{
+ test_equality "$(KV_minor 2.6.16)" "6"
+ test_equality "$(KV_minor 2.6.7-gentoo-r1)" "6"
+ test_equality "$(KV_minor 2.4.18-rc1)" "4"
+}
+
+KV_micro_TEST()
+{
+ test_equality "$(KV_micro 2.6.0)" "0"
+ test_equality "$(KV_micro 2.5.63-mm8)" "63"
+ test_equality "$(KV_micro 2.2.0-foo1)" "0"
+}
+
+KV_to_int_TEST()
+{
+ test_equality "$(KV_to_int 2.6.16)" "132624"
+}
diff --git a/paludis/repositories/gentoo/ebuild/list_functions.bash b/paludis/repositories/gentoo/ebuild/list_functions.bash
new file mode 100644
index 0000000..d34ba64
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/list_functions.bash
@@ -0,0 +1,70 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+use()
+{
+ useq "${1}"
+}
+
+usev()
+{
+ if useq "${1}" ; then
+ echo "${1#!}"
+ return 0
+ else
+ return 1
+ fi
+}
+
+useq()
+{
+ if [[ "${1:0:1}" == "!" ]] ; then
+ ! hasq "${1#!}" "${USE}"
+ else
+ hasq "${1}" "${USE}"
+ fi
+}
+
+has()
+{
+ hasq "${@}"
+}
+
+hasv()
+{
+ if hasq "${@}" ; then
+ echo "${1}"
+ return 0
+ else
+ return 1
+ fi
+}
+
+hasq()
+{
+ local x= want="$1"
+ shift
+ for x in $@ ; do
+ [[ "${x}" == "${want}" ]] && return 0
+ done
+ return 1
+}
diff --git a/paludis/repositories/gentoo/ebuild/list_functions_TEST.bash b/paludis/repositories/gentoo/ebuild/list_functions_TEST.bash
new file mode 100644
index 0000000..c3ba14f
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/list_functions_TEST.bash
@@ -0,0 +1,74 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+use_TEST()
+{
+ export USE="foo bar"
+
+ use foo ; test_return_code
+ use bar ; test_return_code
+ ! use baz ; test_return_code
+ ! use foofoo ; test_return_code
+ ! use fo ; test_return_code
+
+ ! use !foo ; test_return_code
+ ! use !bar ; test_return_code
+ use !baz ; test_return_code
+ use !foofoo ; test_return_code
+ use !fo ; test_return_code
+}
+
+usev_TEST()
+{
+ export USE="foo bar"
+ usev foo 1>/dev/null ; test_return_code
+ test_equality "$(usev foo)" "foo"
+
+ usev bar 1>/dev/null ; test_return_code
+ test_equality "$(usev bar)" "bar"
+
+ ! usev baz 1>/dev/null ; test_return_code
+ test_equality "$(usev baz)" ""
+
+ ! usev !foo 1>/dev/null ; test_return_code
+ test_equality "$(usev !foo)" ""
+
+ ! usev !bar 1>/dev/null ; test_return_code
+ test_equality "$(usev !bar)" ""
+
+ ! usev baz 1>/dev/null ; test_return_code
+ test_equality "$(usev !baz)" "baz"
+}
+
+useq_TEST()
+{
+ export USE="foo bar"
+
+ useq foo ; test_return_code
+ useq bar ; test_return_code
+ ! useq baz ; test_return_code
+ ! useq foofoo ; test_return_code
+ ! useq fo ; test_return_code
+
+ ! useq !foo ; test_return_code
+ ! useq !bar ; test_return_code
+ useq !baz ; test_return_code
+ useq !foofoo ; test_return_code
+ useq !fo ; test_return_code
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/merge.cc b/paludis/repositories/gentoo/ebuild/merge.cc
new file mode 100644
index 0000000..1b1781e
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/merge.cc
@@ -0,0 +1,451 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "merge_common.hh"
+
+#include <paludis/digests/md5.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/fd_output_stream.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/pstream.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/fd_holder.hh>
+#include <paludis/selinux/security_context.hh>
+
+#include <algorithm>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <iterator>
+#include <string>
+#include <vector>
+
+#include <cstdlib>
+#include <errno.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "config.h"
+
+using namespace paludis;
+using namespace merge;
+
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::ifstream;
+using std::ofstream;
+using std::istreambuf_iterator;
+using std::ostreambuf_iterator;
+
+namespace
+{
+ int exit_status;
+
+ FSEntry
+ make_config_protect_name(const FSEntry & name, const FSEntry & file_to_install)
+ {
+ int n(0);
+ std::string file_to_install_name(stringify(file_to_install));
+
+ ifstream our_md5_file(file_to_install_name.c_str());
+ if (! our_md5_file)
+ throw Failure("Could not get md5 for '" + file_to_install_name + "'");
+ MD5 our_md5(our_md5_file);
+
+ FSEntry result(name);
+ std::string result_name(stringify(name));
+ while (true)
+ {
+ if (! result.exists())
+ return result;
+ else if (result.is_regular_file())
+ {
+ ifstream other_md5_file(result_name.c_str());
+ if (! other_md5_file)
+ throw Failure("Could not get md5 for '" + result_name + "'");
+ MD5 other_md5(other_md5_file);
+
+ if (our_md5.hexsum() == other_md5.hexsum())
+ return result;
+ }
+
+ std::stringstream s;
+ s << std::setw(4) << std::setfill('0') << std::right << n++;
+ result = FSEntry(stringify(name.dirname() / ("._cfg" + s.str() + "_"
+ + name.basename())));
+ result_name = stringify(result);
+ }
+ }
+
+ void
+ do_dir(const FSEntry & root, const FSEntry & src_dir,
+ const FSEntry & dst_dir, ofstream * const contents)
+ {
+ std::string root_str(stringify(root)), dst_dir_str(stringify(dst_dir.dirname()));
+
+ Context context("Installing directory in root '" + root_str + "' from '"
+ + stringify(src_dir) + "' to '" + stringify(dst_dir) + "':");
+
+ if (root_str == "/")
+ root_str.clear();
+ if (0 != dst_dir_str.compare(0, root_str.length(), root_str))
+ throw Failure("do_dir confused: '" + root_str + "' '" + dst_dir_str + "'");
+ if (dst_dir_str == "/")
+ dst_dir_str.clear();
+
+ cout << ">>> " << std::setw(5) << std::left << "[dir]" << " " <<
+ dst_dir_str.substr(root_str.length()) << "/" << dst_dir.basename();
+
+ if (dst_dir.is_directory())
+ {
+ cout << " <dir>" << endl;
+ }
+ else if (dst_dir.is_symbolic_link() && dst_dir.realpath().is_directory())
+ {
+ Log::get_instance()->message(ll_qa, lc_no_context, "Expected '" + stringify(dst_dir) +
+ "' to be a directory or non-existent, but found a symlink to a directory");
+ cout << " <sym -> dir>" << endl;
+ }
+ else if (dst_dir.exists())
+ {
+ cout << " <obj>" << endl;
+ throw Failure("Expected '" + stringify(dst_dir) +
+ "' to be a directory or non-existent, but found a file");
+ }
+ else
+ {
+ cout << " <new>" << endl;
+
+ mode_t mode(src_dir.permissions());
+
+#ifdef HAVE_SELINUX
+ std::tr1::shared_ptr<FSCreateCon> createcon;
+ if (MatchPathCon::get_instance()->good())
+ {
+ FSCreateCon *p = new FSCreateCon(MatchPathCon::get_instance()->match(dst_dir_str.substr(root_str.length()),
+ mode));
+ createcon.reset(p);
+ }
+#endif
+
+ FSEntry dst_dir_copy(dst_dir);
+ dst_dir_copy.mkdir(mode);
+ dst_dir_copy.chown(src_dir.owner(), src_dir.group());
+ /* the chmod is needed to pick up fancy set*id bits */
+ dst_dir_copy.chmod(src_dir.permissions());
+ }
+
+ *contents << "dir " << dst_dir_str.substr(root_str.length()) << "/" <<
+ dst_dir.basename() << endl;
+ }
+
+ void
+ copy_file_contents(int input_fd, int fd)
+ {
+ char buf[4096];
+ ssize_t count;
+ while ((count = read(input_fd, buf, 4096)) > 0)
+ write(fd, buf, count);
+ }
+
+ void
+ do_obj(const FSEntry & root, const FSEntry & src,
+ const FSEntry & dst, ofstream * const contents)
+ {
+ std::string root_str(stringify(root)), dst_dir_str(stringify(dst.dirname())),
+ src_str(stringify(src));
+
+ Context context("Installing object in root '" + root_str + "' from '"
+ + stringify(src) + "' to '" + stringify(dst) + "':");
+
+ if (root_str == "/")
+ root_str.clear();
+ if (0 != dst_dir_str.compare(0, root_str.length(), root_str))
+ throw Failure("do_obj confused: '" + root_str + "' '" + dst_dir_str + "'");
+ if (dst_dir_str == "/")
+ dst_dir_str.clear();
+
+ cout << ">>> " << std::setw(5) << std::left << "[obj]" << " " <<
+ dst_dir_str.substr(root_str.length()) << "/" << dst.basename();
+
+ if (dst.is_directory())
+ {
+ cout << " <dir>" << endl;
+ throw Failure("Cannot overwrite directory '" + stringify(dst) + "' with a file");
+ }
+ else
+ {
+ FSEntry real_dst(dst);
+
+ FDHolder input_fd(::open(src_str.c_str(), O_RDONLY), false);
+ if (-1 == input_fd)
+ throw Failure("Cannot read '" + src_str + "'");
+
+ if (dst.exists())
+ {
+ if (is_config_protected(root, dst))
+ {
+ real_dst = make_config_protect_name(dst, src);
+ if (dst != real_dst)
+ cout << " -> " << real_dst << endl;
+ else
+ cout << endl;
+ }
+ else
+ {
+ if (dst.is_regular_file())
+ {
+ cout << " <obj>" << endl;
+
+ mode_t mode(dst.permissions());
+ if ((mode & S_ISUID) || (mode & S_ISGID))
+ {
+ mode &= 0400;
+ FSEntry(dst).chmod(mode);
+ }
+ FSEntry(dst).unlink();
+ }
+ else if (dst.is_symbolic_link())
+ {
+ cout << " <sym>" << endl;
+ FSEntry(dst).unlink();
+ }
+ else
+ {
+ cout << " <?""?""?>" << endl;
+ FSEntry(dst).unlink();
+ }
+ }
+ }
+ else
+ cout << " <new>" << endl;
+
+ /* FDHolder must be destroyed before we do the md5 thing, or the
+ * disk write may not have synced. */
+ {
+#ifdef HAVE_SELINUX
+ std::tr1::shared_ptr<FSCreateCon> createcon;
+ if (MatchPathCon::get_instance()->good())
+ createcon.reset(new
+ FSCreateCon(MatchPathCon::get_instance()->match(dst_dir_str.substr(root_str.length()) + "/"
+ + dst.basename(), src.permissions())));
+#endif
+ FDHolder fd(::open(stringify(real_dst).c_str(), O_WRONLY | O_CREAT, src.permissions()));
+ if (-1 == fd)
+ throw Failure("Cannot open '" + stringify(real_dst) + "' for write");
+
+ if (0 != ::fchown(fd, src.owner(), src.group()))
+ throw Failure("Cannot fchown '" + stringify(real_dst) + "': " +
+ stringify(::strerror(errno)));
+
+ /* the chmod is needed for set*id bits, which are dropped by
+ * umask in the ::open */
+ if (0 != ::fchmod(fd, src.permissions()))
+ throw Failure("Cannot fchmod '" + stringify(real_dst) + "': " +
+ stringify(::strerror(errno)));
+
+ copy_file_contents(input_fd, fd);
+ }
+
+ ifstream dst_file(stringify(dst).c_str());
+ if (! dst_file)
+ throw Failure("Could not get md5 for '" + stringify(dst_file) + "'");
+ MD5 md5(dst_file);
+
+ *contents << "obj " << dst_dir_str.substr(root_str.length()) << "/" <<
+ dst.basename() << " " << md5.hexsum() << " " <<
+ FSEntry(stringify(dst)).mtime() << endl;
+ }
+ }
+
+ void
+ do_sym(const FSEntry & root, const FSEntry & src,
+ const FSEntry & dst, ofstream * const contents)
+ {
+ std::string root_str(stringify(root)), dst_dir_str(stringify(dst.dirname()));
+
+ Context context("Installing symlink in root '" + root_str + "' from '"
+ + stringify(src) + "' to '" + stringify(dst) + "':");
+
+ if (root_str == "/")
+ root_str.clear();
+ if (0 != dst_dir_str.compare(0, root_str.length(), root_str))
+ throw Failure("do_sym confused: '" + root_str + "' '" + dst_dir_str + "'");
+ if (dst_dir_str == "/")
+ dst_dir_str.clear();
+
+ cout << ">>> " << std::setw(5) << std::left << "[sym]" << " " <<
+ dst_dir_str.substr(root_str.length()) << "/" << dst.basename();
+
+ if (dst.exists())
+ {
+ if (dst.is_directory())
+ throw Failure("Can't overwrite directory '" + stringify(dst) +
+ "' with symlink to '" + src.readlink() + "'");
+ else if (dst.is_symbolic_link())
+ {
+ cout << " <sym>" << endl;
+ FSEntry(dst).unlink();
+ }
+ else
+ {
+ cout << " <obj>" << endl;
+ mode_t mode(dst.permissions());
+ if ((mode & S_ISUID) || (mode & S_ISGID))
+ {
+ mode &= 0400;
+ FSEntry(dst).chmod(mode);
+ }
+ FSEntry(dst).unlink();
+ }
+ }
+ else
+ cout << " <new>" << endl;
+
+#ifdef HAVE_SELINUX
+ // permissions() on a symlink does weird things, but matchpathcon only cares about the file type,
+ // so just pass S_IFLNK.
+ std::tr1::shared_ptr<FSCreateCon> createcon;
+ if (MatchPathCon::get_instance()->good())
+ createcon.reset(new
+ FSCreateCon(MatchPathCon::get_instance()->match(dst_dir_str.substr(root_str.length()) + "/"
+ + dst.basename(), S_IFLNK)));
+#endif
+
+ if (0 != ::symlink(src.readlink().c_str(), stringify(dst).c_str()))
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "Couldn't create symlink '"
+ + src.readlink() + "' at '" + stringify(dst) + "'");
+ exit_status |= 2;
+ }
+
+ *contents << "sym " << dst_dir_str.substr(root_str.length()) << "/" <<
+ dst.basename() << " -> " << dst.readlink() << " " <<
+ FSEntry(stringify(dst)).mtime() << endl;
+ }
+
+ void
+ merge_this(const FSEntry & root, const FSEntry & src_dir, const FSEntry & dst_dir,
+ ofstream * const contents)
+ {
+ Context context("Merging under root '" + stringify(root) + "' from '"
+ + stringify(src_dir) + "' to '" + stringify(dst_dir) + "':");
+
+ if (! root.is_directory())
+ throw Failure("merge_this called with bad root '" + stringify(root) + "'");
+ if (! src_dir.is_directory())
+ throw Failure("merge_this called with bad src_dir '" + stringify(src_dir) + "'");
+ if (! dst_dir.is_directory())
+ throw Failure("merge_this called with bad dst_dir '" + stringify(dst_dir) + "'");
+
+ for (DirIterator d(src_dir, false), d_end ; d != d_end ; ++d)
+ {
+ if (d->is_regular_file())
+ do_obj(root, src_dir / d->basename(), dst_dir / d->basename(), contents);
+ else if (d->is_symbolic_link())
+ do_sym(root, src_dir / d->basename(), dst_dir / d->basename(), contents);
+ else if (d->is_directory())
+ {
+ do_dir(root, src_dir / d->basename(), dst_dir / d->basename(), contents);
+ merge_this(root, (src_dir / d->basename()).realpath(), (dst_dir / d->basename()).realpath(), contents);
+ }
+ else
+ throw Failure("Don't know how to merge '" + stringify(*d) + "'");
+ }
+ }
+}
+
+int
+main(int argc, char * argv[])
+{
+ Context context("In main program:");
+
+#ifdef HAVE_SELINUX
+ // If the MatchPathCon initialisation fails, don't attempt to match contexts when merging.
+ if (! MatchPathCon::get_instance()->good())
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "matchpathcon_init failed; not setting security contexts");
+#endif
+
+ exit_status = 0;
+ try
+ {
+ if (argc != 4)
+ throw Failure("Usage: " + stringify(argv[0]) + " src dst contents");
+
+ Log::get_instance()->set_program_name(argv[0]);
+ std::string log_level(getenv_with_default("PALUDIS_EBUILD_LOG_LEVEL", "qa"));
+
+ if (log_level == "debug")
+ Log::get_instance()->set_log_level(ll_debug);
+ else if (log_level == "qa")
+ Log::get_instance()->set_log_level(ll_qa);
+ else if (log_level == "warning")
+ Log::get_instance()->set_log_level(ll_warning);
+ else if (log_level == "silent")
+ Log::get_instance()->set_log_level(ll_silent);
+ else
+ throw Failure("bad value for log level");
+
+ Log::get_instance()->message(ll_debug, lc_no_context,
+ "CONFIG_PROTECT is " + getenv_with_default("CONFIG_PROTECT", "(unset)"));
+ Log::get_instance()->message(ll_debug, lc_no_context,
+ "CONFIG_PROTECT_MASK is " + getenv_with_default("CONFIG_PROTECT_MASK", "(unset)"));
+
+ FSEntry src(argv[1]), dst(argv[2]), contents(argv[3]);
+
+ if (! ((src = src.realpath())).is_directory())
+ throw Failure(stringify(argv[1]) + ": not a directory");
+ if (! ((dst = dst.realpath())).is_directory())
+ throw Failure(stringify(argv[2]) + ": not a directory");
+
+ ofstream contents_file(stringify(contents).c_str());
+ if (! contents_file)
+ throw Failure(stringify(contents) + ": not writeable");
+
+ ::umask(0000);
+ merge_this(dst, src, dst, &contents_file);
+ return exit_status;
+ }
+ catch (const Failure & f)
+ {
+ cerr << argv[0] << ": fatal error: " << f.message << endl;
+ return EXIT_FAILURE;
+ }
+ catch (const Exception & e)
+ {
+ cerr << argv[0] << ": fatal error:" << endl
+ << " * " << e.backtrace("\n * ") << e.message()
+ << " (" << e.what() << ")" << endl;
+ return EXIT_FAILURE;
+ }
+ catch (const std::exception & e)
+ {
+ cerr << argv[0] << ": fatal error: " << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/merge_TEST.bash b/paludis/repositories/gentoo/ebuild/merge_TEST.bash
new file mode 100644
index 0000000..c4f5253
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/merge_TEST.bash
@@ -0,0 +1,223 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+merge_empty_TEST()
+{
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/merge "merge_TEST_dir/empty_src" \
+ "merge_TEST_dir/empty_dst" \
+ "merge_TEST_dir/empty_contents" 1>/dev/null
+ test_return_code
+}
+
+merge_files_TEST()
+{
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/merge "merge_TEST_dir/files_src" \
+ "merge_TEST_dir/files_dst" \
+ "merge_TEST_dir/files_contents" 1>/dev/null
+ test_return_code
+
+ [[ -f "merge_TEST_dir/files_dst/one" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/files_dst/one)" "contents of one"
+
+ [[ -f "merge_TEST_dir/files_dst/two" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/files_dst/two)" "contents of two"
+}
+
+merge_dirs_TEST()
+{
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/merge "merge_TEST_dir/dirs_src" \
+ "merge_TEST_dir/dirs_dst" \
+ "merge_TEST_dir/dirs_contents" 1>/dev/null
+ test_return_code
+
+ [[ -d "merge_TEST_dir/dirs_dst/dir_one" ]] ; test_return_code
+ [[ -d "merge_TEST_dir/dirs_dst/dir_two" ]] ; test_return_code
+ [[ -d "merge_TEST_dir/dirs_dst/dir_two/dir_three" ]] ; test_return_code
+
+ [[ -f "merge_TEST_dir/dirs_dst/dir_one/one" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/dirs_dst/dir_one/one)" "contents of one"
+
+ [[ -f "merge_TEST_dir/dirs_dst/dir_two/two" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/dirs_dst/dir_two/two)" "contents of two"
+
+ [[ -f "merge_TEST_dir/dirs_dst/dir_two/dir_three/three" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/dirs_dst/dir_two/dir_three/three)" "contents of three"
+}
+
+merge_dirs_over_TEST()
+{
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/merge "merge_TEST_dir/dirs_over_src" \
+ "merge_TEST_dir/dirs_over_dst" \
+ "merge_TEST_dir/dirs_over_contents" 1>/dev/null
+ test_return_code
+
+ [[ -d "merge_TEST_dir/dirs_over_dst/dir_one/" ]] ; test_return_code
+ [[ -d "merge_TEST_dir/dirs_over_dst/dir_two/" ]] ; test_return_code
+ [[ -d "merge_TEST_dir/dirs_over_dst/dir_two/dir_three/" ]] ; test_return_code
+
+ [[ -f "merge_TEST_dir/dirs_over_dst/dir_one/one" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/dirs_over_dst/dir_one/one)" "contents of one"
+
+ [[ -f "merge_TEST_dir/dirs_over_dst/dir_two/two" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/dirs_over_dst/dir_two/two)" "contents of two"
+
+ [[ -f "merge_TEST_dir/dirs_over_dst/dir_two/dir_three/three" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/dirs_over_dst/dir_two/dir_three/three)" "contents of three"
+}
+
+merge_links_TEST()
+{
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/merge "merge_TEST_dir/links_src" \
+ "merge_TEST_dir/links_dst" \
+ "merge_TEST_dir/links_contents" 1>/dev/null
+ test_return_code
+
+ [[ -f "merge_TEST_dir/links_dst/one" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/links_dst/one)" "contents of one"
+
+ [[ -f "merge_TEST_dir/links_dst/two" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/links_dst/two)" "contents of two"
+
+ [[ -f "merge_TEST_dir/links_dst/link_to_two" ]] ; test_return_code
+ [[ -L "merge_TEST_dir/links_dst/link_to_two" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/links_dst/link_to_two)" "contents of two"
+}
+
+merge_links_over_TEST()
+{
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/merge "merge_TEST_dir/links_over_src" \
+ "merge_TEST_dir/links_over_dst" \
+ "merge_TEST_dir/links_over_contents" 1>/dev/null
+ test_return_code
+
+ [[ -f "merge_TEST_dir/links_over_dst/one" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/links_over_dst/one)" "contents of one"
+
+ [[ -f "merge_TEST_dir/links_over_dst/two" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/links_over_dst/two)" "contents of two"
+
+ [[ -f "merge_TEST_dir/links_over_dst/link_to_two" ]] ; test_return_code
+ [[ -L "merge_TEST_dir/links_over_dst/link_to_two" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/links_over_dst/link_to_two)" "contents of two"
+
+ [[ -f "merge_TEST_dir/links_over_dst/link_to_three" ]] ; test_return_code
+ [[ -L "merge_TEST_dir/links_over_dst/link_to_three" ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/links_over_dst/link_to_three)" "contents of three"
+}
+
+merge_links_over_dir_TEST()
+{
+ ! ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/merge "merge_TEST_dir/links_over_dir_src" \
+ "merge_TEST_dir/links_over_dir_dst" \
+ "merge_TEST_dir/links_over_dir_contents" &>/dev/null
+ test_return_code
+}
+
+merge_config_protect_TEST()
+{
+ export CONFIG_PROTECT=/dir
+
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/merge "merge_TEST_dir/config_pro_src" \
+ "merge_TEST_dir/config_pro_dst" \
+ "merge_TEST_dir/config_pro_contents" 1>/dev/null
+ test_return_code
+
+ echo -n "[one]"
+
+ [[ -f merge_TEST_dir/config_pro_dst/dir/one ]] ; test_return_code
+ [[ -f merge_TEST_dir/config_pro_dst/dir/._cfg0000_one ]] ; test_return_code
+ ! [[ -f merge_TEST_dir/config_pro_dst/dir/._cfg0001_one ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/config_pro_dst/dir/one)" "i am a fish"
+ test_equality "$(< merge_TEST_dir/config_pro_dst/dir/._cfg0000_one)" "contents of one"
+
+ echo -n "[two]"
+
+ [[ -f merge_TEST_dir/config_pro_dst/dir/two ]] ; test_return_code
+ ! [[ -f merge_TEST_dir/config_pro_dst/dir/._cfg0000_two ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/config_pro_dst/dir/two)" "contents of two"
+
+ echo -n "[three]"
+
+ [[ -f merge_TEST_dir/config_pro_dst/dir/three ]] ; test_return_code
+ [[ -f merge_TEST_dir/config_pro_dst/dir/._cfg0000_three ]] ; test_return_code
+ [[ -f merge_TEST_dir/config_pro_dst/dir/._cfg0001_three ]] ; test_return_code
+ [[ -f merge_TEST_dir/config_pro_dst/dir/._cfg0002_three ]] ; test_return_code
+ ! [[ -f merge_TEST_dir/config_pro_dst/dir/._cfg0003_three ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/config_pro_dst/dir/three)" "i am a fish"
+ test_equality "$(< merge_TEST_dir/config_pro_dst/dir/._cfg0000_three)" "i am a dish"
+ test_equality "$(< merge_TEST_dir/config_pro_dst/dir/._cfg0001_three)" "i am a fist"
+ test_equality "$(< merge_TEST_dir/config_pro_dst/dir/._cfg0002_three)" "contents of three"
+
+ echo -n "[four]"
+
+ [[ -f merge_TEST_dir/config_pro_dst/dir/four ]] ; test_return_code
+ [[ -f merge_TEST_dir/config_pro_dst/dir/._cfg0000_four ]] ; test_return_code
+ [[ -f merge_TEST_dir/config_pro_dst/dir/._cfg0001_four ]] ; test_return_code
+ ! [[ -f merge_TEST_dir/config_pro_dst/dir/._cfg0002_four ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/config_pro_dst/dir/four)" "i am a fish"
+ test_equality "$(< merge_TEST_dir/config_pro_dst/dir/._cfg0000_four)" "contents of four"
+ test_equality "$(< merge_TEST_dir/config_pro_dst/dir/._cfg0001_four)" "i am a fist"
+}
+
+merge_config_protect_noroot_TEST()
+{
+ export CONFIG_PROTECT=$(${PALUDIS_EBUILD_DIR}/utils/canonicalise `pwd` )/merge_TEST_dir/noroot_dst/dir
+
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/merge "merge_TEST_dir/config_pro_noroot_src" \
+ "/" \
+ "merge_TEST_dir/config_pro_slash_root_contents" 1>/dev/null
+ test_return_code
+
+ echo -n "[one]"
+
+ [[ -f merge_TEST_dir/noroot_dst/dir/one ]] ; test_return_code
+ [[ -f merge_TEST_dir/noroot_dst/dir/._cfg0000_one ]] ; test_return_code
+ ! [[ -f merge_TEST_dir/noroot_dst/dir/._cfg0001_one ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/noroot_dst/dir/one)" "i am a fish"
+ test_equality "$(< merge_TEST_dir/noroot_dst/dir/._cfg0000_one)" "contents of one"
+
+ echo -n "[two]"
+
+ [[ -f merge_TEST_dir/noroot_dst/dir/two ]] ; test_return_code
+ ! [[ -f merge_TEST_dir/noroot_dst/dir/._cfg0000_two ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/noroot_dst/dir/two)" "contents of two"
+
+ echo -n "[three]"
+
+ [[ -f merge_TEST_dir/noroot_dst/dir/three ]] ; test_return_code
+ [[ -f merge_TEST_dir/noroot_dst/dir/._cfg0000_three ]] ; test_return_code
+ [[ -f merge_TEST_dir/noroot_dst/dir/._cfg0001_three ]] ; test_return_code
+ [[ -f merge_TEST_dir/noroot_dst/dir/._cfg0002_three ]] ; test_return_code
+ ! [[ -f merge_TEST_dir/noroot_dst/dir/._cfg0003_three ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/noroot_dst/dir/three)" "i am a fish"
+ test_equality "$(< merge_TEST_dir/noroot_dst/dir/._cfg0000_three)" "i am a dish"
+ test_equality "$(< merge_TEST_dir/noroot_dst/dir/._cfg0001_three)" "i am a fist"
+ test_equality "$(< merge_TEST_dir/noroot_dst/dir/._cfg0002_three)" "contents of three"
+
+ echo -n "[four]"
+
+ [[ -f merge_TEST_dir/noroot_dst/dir/four ]] ; test_return_code
+ [[ -f merge_TEST_dir/noroot_dst/dir/._cfg0000_four ]] ; test_return_code
+ [[ -f merge_TEST_dir/noroot_dst/dir/._cfg0001_four ]] ; test_return_code
+ ! [[ -f merge_TEST_dir/noroot_dst/dir/._cfg0002_four ]] ; test_return_code
+ test_equality "$(< merge_TEST_dir/noroot_dst/dir/four)" "i am a fish"
+ test_equality "$(< merge_TEST_dir/noroot_dst/dir/._cfg0000_four)" "contents of four"
+ test_equality "$(< merge_TEST_dir/noroot_dst/dir/._cfg0001_four)" "i am a fist"
+
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/merge_TEST_cleanup.sh b/paludis/repositories/gentoo/ebuild/merge_TEST_cleanup.sh
new file mode 100755
index 0000000..4b40b8f
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/merge_TEST_cleanup.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d merge_TEST_dir ] ; then
+ rm -fr merge_TEST_dir
+else
+ true
+fi
+
+
diff --git a/paludis/repositories/gentoo/ebuild/merge_TEST_setup.sh b/paludis/repositories/gentoo/ebuild/merge_TEST_setup.sh
new file mode 100755
index 0000000..4af857d
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/merge_TEST_setup.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir -p merge_TEST_dir/{empty_src,empty_dst} || exit 2
+
+mkdir -p merge_TEST_dir/{files_src,files_dst} || exit 2
+echo "contents of one" > merge_TEST_dir/files_src/one
+echo "contents of two" > merge_TEST_dir/files_src/two
+
+mkdir -p merge_TEST_dir/{dirs_src/{dir_one,dir_two/dir_three},dirs_dst} || exit 3
+echo "contents of one" > merge_TEST_dir/dirs_src/dir_one/one
+echo "contents of two" > merge_TEST_dir/dirs_src/dir_two/two
+echo "contents of three" > merge_TEST_dir/dirs_src/dir_two/dir_three/three
+
+mkdir -p merge_TEST_dir/{dirs_over_src/{dir_one,dir_two/dir_three},dirs_over_dst} || exit 4
+mkdir -p merge_TEST_dir/dirs_over_dst/{one,real}
+ln -s real merge_TEST_dir/dirs_over_dst/two
+echo "contents of one" > merge_TEST_dir/dirs_over_src/dir_one/one
+echo "contents of two" > merge_TEST_dir/dirs_over_src/dir_two/two
+echo "contents of three" > merge_TEST_dir/dirs_over_src/dir_two/dir_three/three
+
+mkdir -p merge_TEST_dir/{links_src,links_dst} || exit 5
+echo "contents of one" > merge_TEST_dir/links_src/one
+echo "contents of two" > merge_TEST_dir/links_src/two
+ln -s two merge_TEST_dir/links_src/link_to_two
+
+mkdir -p merge_TEST_dir/{links_over_src,links_over_dst} || exit 5
+echo "contents of one" > merge_TEST_dir/links_over_src/one
+echo "contents of two" > merge_TEST_dir/links_over_src/two
+echo "contents of three" > merge_TEST_dir/links_over_src/three
+ln -s two merge_TEST_dir/links_over_src/link_to_two
+ln -s three merge_TEST_dir/links_over_src/link_to_three
+echo "existing file" > merge_TEST_dir/link_to_two
+ln -s ../ merge_TEST_dir/links_over_dst/link_to_three
+
+mkdir -p merge_TEST_dir/{links_over_dir_src,links_over_dir_dst} || exit 5
+echo "contents of one" > merge_TEST_dir/links_over_dir_src/one
+echo "contents of two" > merge_TEST_dir/links_over_dir_src/two
+echo "contents of three" > merge_TEST_dir/links_over_dir_src/three
+ln -s two merge_TEST_dir/links_over_dir_src/link_to_two
+ln -s three merge_TEST_dir/links_over_dir_src/link_to_three
+mkdir merge_TEST_dir/links_over_dir_dst/link_to_two
+echo "existing file" > merge_TEST_dir/links_over_dir_dst/link_to_three
+
+mkdir -p merge_TEST_dir/{config_pro_src/dir,config_pro_dst/dir} || exit 6
+echo "contents of one" > merge_TEST_dir/config_pro_src/dir/one
+echo "contents of two" > merge_TEST_dir/config_pro_src/dir/two
+echo "contents of three" > merge_TEST_dir/config_pro_src/dir/three
+echo "contents of four" > merge_TEST_dir/config_pro_src/dir/four
+echo "i am a fish" > merge_TEST_dir/config_pro_dst/dir/one
+echo "contents of two" > merge_TEST_dir/config_pro_dst/dir/two
+echo "i am a fish" > merge_TEST_dir/config_pro_dst/dir/three
+echo "i am a dish" > merge_TEST_dir/config_pro_dst/dir/._cfg0000_three
+echo "i am a fist" > merge_TEST_dir/config_pro_dst/dir/._cfg0001_three
+echo "i am a fish" > merge_TEST_dir/config_pro_dst/dir/four
+echo "contents of four" > merge_TEST_dir/config_pro_dst/dir/._cfg0000_four
+echo "i am a fist" > merge_TEST_dir/config_pro_dst/dir/._cfg0001_four
+
+d=merge_TEST_dir/config_pro_noroot_src/$(${PALUDIS_EBUILD_DIR}/utils/canonicalise `pwd` )/merge_TEST_dir/noroot_dst/dir
+mkdir -p "${d}" || exit 7
+mkdir -p merge_TEST_dir/noroot_dst/dir || exit 7
+echo "contents of one" > ${d}/one
+echo "contents of two" > ${d}/two
+echo "contents of three" > ${d}/three
+echo "contents of four" > ${d}/four
+echo "i am a fish" > merge_TEST_dir/noroot_dst/dir/one
+echo "contents of two" > merge_TEST_dir/noroot_dst/dir/two
+echo "i am a fish" > merge_TEST_dir/noroot_dst/dir/three
+echo "i am a dish" > merge_TEST_dir/noroot_dst/dir/._cfg0000_three
+echo "i am a fist" > merge_TEST_dir/noroot_dst/dir/._cfg0001_three
+echo "i am a fish" > merge_TEST_dir/noroot_dst/dir/four
+echo "contents of four" > merge_TEST_dir/noroot_dst/dir/._cfg0000_four
+echo "i am a fist" > merge_TEST_dir/noroot_dst/dir/._cfg0001_four
+
diff --git a/paludis/repositories/gentoo/ebuild/merge_common.cc b/paludis/repositories/gentoo/ebuild/merge_common.cc
new file mode 100644
index 0000000..27b9e11
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/merge_common.cc
@@ -0,0 +1,99 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "merge_common.hh"
+
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/pstream.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/tokeniser.hh>
+
+#include <algorithm>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <iterator>
+#include <string>
+#include <vector>
+
+#include <cstdlib>
+#include <errno.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+using namespace paludis;
+
+std::vector<std::string>
+merge::get_config_var(const std::string & var)
+{
+ std::vector<std::string> result, preresult;
+ WhitespaceTokeniser::get_instance()->tokenise(getenv_with_default(var, ""),
+ std::back_inserter(preresult));
+ result.reserve(preresult.size());
+
+ for (std::vector<std::string>::const_iterator i(preresult.begin()), i_end(preresult.end()) ;
+ i != i_end ; ++i)
+ {
+ if (i->empty())
+ continue;
+ if ("-*" == *i)
+ result.clear();
+ else if ('-' == i->at(0))
+ result.erase(std::remove(result.begin(), result.end(), i->substr(1)), result.end());
+ else
+ result.push_back(*i);
+ }
+ return result;
+}
+
+bool
+merge::is_config_protected(const FSEntry & root, const FSEntry & file)
+{
+ static std::vector<std::string> cfg_pro(get_config_var("CONFIG_PROTECT")),
+ cfg_pro_mask(get_config_var("CONFIG_PROTECT_MASK"));
+
+ std::string file_str(stringify(file)), root_str(stringify(root));
+ if (0 != file_str.compare(0, root_str.length(), root_str))
+ throw Failure("is_config_protected confused: '" + root_str + "' '" + file_str + "'");
+ file_str.erase(0, root_str.length());
+ if (file_str.empty())
+ file_str = "/";
+ if ('/' != file_str.at(0))
+ file_str = "/" + file_str;
+
+ bool result(false);
+ for (std::vector<std::string>::const_iterator c(cfg_pro.begin()),
+ c_end(cfg_pro.end()) ; c != c_end && ! result ; ++c)
+ if (0 == fnmatch((*c + "/*").c_str(), file_str.c_str(), 0))
+ result = true;
+
+ for (std::vector<std::string>::const_iterator c(cfg_pro_mask.begin()),
+ c_end(cfg_pro_mask.end()) ; c != c_end && result ; ++c)
+ if (0 == fnmatch((*c + "/*").c_str(), file_str.c_str(), 0))
+ result = false;
+
+ return result;
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/merge_common.hh b/paludis/repositories/gentoo/ebuild/merge_common.hh
new file mode 100644
index 0000000..6f06648
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/merge_common.hh
@@ -0,0 +1,50 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_EBUILD_UTILS_MERGE_COMMON_HH
+#define PALUDIS_GUARD_EBUILD_UTILS_MERGE_COMMON_HH 1
+
+#include <string>
+#include <vector>
+
+namespace paludis
+{
+ class FSEntry;
+}
+
+namespace merge
+{
+ struct Failure
+ {
+ std::string message;
+
+ Failure(const std::string & m) :
+ message(m)
+ {
+ };
+ };
+
+ std::vector<std::string>
+ get_config_var(const std::string & var);
+
+ bool
+ is_config_protected(const paludis::FSEntry & root, const paludis::FSEntry & file);
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/ebuild/multilib_functions.bash b/paludis/repositories/gentoo/ebuild/multilib_functions.bash
new file mode 100644
index 0000000..f656933
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/multilib_functions.bash
@@ -0,0 +1,66 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+# Default values. Those used on a non-multilib profile.
+export MULTILIB_ABIS=${MULTILIB_ABIS:-"default"}
+export DEFAULT_ABI=${DEFAULT_ABI:-"default"}
+export CFLAGS_default
+export LDFLAGS_default
+export CHOST_default=${CHOST_default:-${CHOST}}
+export CTARGET_default=${CTARGET_default:-${CTARGET:-${CHOST_default}}}
+export LIBDIR_default=${CONF_LIBDIR:-"lib"}
+export CDEFINE_default
+
+
+ebuild_get_libdir() {
+ local CONF_LIBDIR
+ if [[ -n "${CONF_LIBDIR_OVERRIDE}" ]]; then
+ echo ${CONF_LIBDIR_OVERRIDE}
+ else
+ ebuild_get_abi_LIBDIR
+ fi
+}
+
+ebuild_get_abi_var() {
+ local flag=$1
+ local abi
+ if [[ $# -gt 1 ]]; then
+ abi=${2}
+ elif [[ -n "${ABI}" ]]; then
+ abi=${ABI}
+ elif [[ -n "${DEFAULT_ABI}" ]]; then
+ abi=${DEFAULT_ABI}
+ else
+ abi="default"
+ fi
+
+ local var="${flag}_${abi}"
+ echo ${!var}
+}
+
+ebuild_get_abi_CFLAGS() { ebuild_get_abi_var CFLAGS "$@"; }
+ebuild_get_abi_LDFLAGS() { ebuild_get_abi_var LDFLAGS "$@"; }
+ebuild_get_abi_CHOST() { ebuild_get_abi_var CHOST "$@"; }
+ebuild_get_abi_CTARGET() { ebuild_get_abi_var CTARGET "$@"; }
+ebuild_get_abi_FAKE_TARGETS() { ebuild_get_abi_var FAKE_TARGETS "$@"; }
+ebuild_get_abi_CDEFINE() { ebuild_get_abi_var CDEFINE "$@"; }
+ebuild_get_abi_LIBDIR() { ebuild_get_abi_var LIBDIR "$@"; }
diff --git a/paludis/repositories/gentoo/ebuild/pkg_config.bash b/paludis/repositories/gentoo/ebuild/pkg_config.bash
new file mode 100644
index 0000000..f0bb49a
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/pkg_config.bash
@@ -0,0 +1,58 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+pkg_config()
+{
+ eerror "No configuration function is defined"
+}
+
+ebuild_f_config()
+{
+ local old_sandbox_write="${SANDBOX_WRITE}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}${ROOT%/}/"
+
+ if hasq "config" ${RESTRICT} ; then
+ ebuild_section "Skipping pkg_config (RESTRICT)"
+ elif hasq "config" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping pkg_config (SKIP_FUNCTIONS)"
+ else
+ if [[ $(type -t pre_pkg_config ) == "function" ]] ; then
+ ebuild_section "Starting pre_pkg_config"
+ pre_pkg_config
+ ebuild_section "Done pre_pkg_config"
+ fi
+
+ ebuild_section "Starting pkg_config"
+ pkg_config
+ ebuild_section "Done pkg_config"
+
+ if [[ $(type -t post_pkg_config ) == "function" ]] ; then
+ ebuild_section "Starting post_pkg_config"
+ post_pkg_config
+ ebuild_section "Done post_pkg_config"
+ fi
+ fi
+
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${old_sandbox_write}"
+ true
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/pkg_nofetch.bash b/paludis/repositories/gentoo/ebuild/pkg_nofetch.bash
new file mode 100644
index 0000000..09c1791
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/pkg_nofetch.bash
@@ -0,0 +1,62 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+pkg_nofetch()
+{
+ [[ -z "${A}" ]] && return
+
+ local f g=
+ for f in ${A} ; do
+ [[ -f "${DISTDIR}/${A}" ]] && continue
+ if [[ -z "${g}" ]] ; then
+ echo "The following files could not be fetched automatically for ${PN}:"
+ g=no
+ fi
+ echo "* ${f}"
+ done
+}
+
+ebuild_f_nofetch()
+{
+ local old_sandbox_write="${SANDBOX_WRITE}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}${DISTDIR}"
+ if hasq "nofetch" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping pkg_nofetch (SKIP_FUNCTIONS)"
+ else
+ local a f=
+ for a in ${A} ; do
+ [[ -f "${DISTDIR}/${a}" ]] && continue
+ f=yes
+ done
+
+ if [[ -z "${f}" ]] ; then
+ ebuild_section "Skipping pkg_nofetch (fully fetched already)"
+ else
+ ebuild_section "Starting pkg_nofetch"
+ pkg_nofetch
+ ebuild_section "Done pkg_nofetch"
+ die "Manual fetching is required"
+ fi
+ fi
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${old_sandbox_write}"
+ true
+}
diff --git a/paludis/repositories/gentoo/ebuild/pkg_postinst.bash b/paludis/repositories/gentoo/ebuild/pkg_postinst.bash
new file mode 100644
index 0000000..9eb7c6c
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/pkg_postinst.bash
@@ -0,0 +1,58 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+pkg_postinst()
+{
+ :
+}
+
+ebuild_f_postinst()
+{
+ local old_sandbox_write="${SANDBOX_WRITE}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}${ROOT%/}/"
+
+ if hasq "postinst" ${RESTRICT} ; then
+ ebuild_section "Skipping pkg_postinst (RESTRICT)"
+ elif hasq "postinst" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping pkg_postinst (SKIP_FUNCTIONS)"
+ else
+ if [[ $(type -t pre_pkg_postinst ) == "function" ]] ; then
+ ebuild_section "Starting pre_pkg_postinst"
+ pre_pkg_postinst
+ ebuild_section "Done pre_pkg_postinst"
+ fi
+
+ ebuild_section "Starting pkg_postinst"
+ pkg_postinst
+ ebuild_section "Done pkg_postinst"
+
+ if [[ $(type -t post_pkg_postinst ) == "function" ]] ; then
+ ebuild_section "Starting post_pkg_postinst"
+ post_pkg_postinst
+ ebuild_section "Done post_pkg_postinst"
+ fi
+ fi
+
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${old_sandbox_write}"
+ true
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/pkg_postrm.bash b/paludis/repositories/gentoo/ebuild/pkg_postrm.bash
new file mode 100644
index 0000000..9fc7855
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/pkg_postrm.bash
@@ -0,0 +1,59 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+pkg_postrm()
+{
+ :
+}
+
+ebuild_f_postrm()
+{
+ local old_sandbox_write="${SANDBOX_WRITE}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}${ROOT%/}/"
+
+ if hasq "postrm" ${RESTRICT} ; then
+ ebuild_section "Skipping pkg_postrm (RESTRICT)"
+ elif hasq "postrm" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping pkg_postrm (SKIP_FUNCTIONS)"
+ else
+ if [[ $(type -t pre_pkg_postrm ) == "function" ]] ; then
+ ebuild_section "Starting pre_pkg_postrm"
+ pre_pkg_postrm
+ ebuild_section "Done pre_pkg_postrm"
+ fi
+
+ ebuild_section "Starting pkg_postrm"
+ pkg_postrm
+ ebuild_section "Done pkg_postrm"
+
+ if [[ $(type -t post_pkg_postrm ) == "function" ]] ; then
+ ebuild_section "Starting post_pkg_postrm"
+ post_pkg_postrm
+ ebuild_section "Done post_pkg_postrm"
+ fi
+ fi
+
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${old_sandbox_write}"
+ true
+}
+
+
diff --git a/paludis/repositories/gentoo/ebuild/pkg_preinst.bash b/paludis/repositories/gentoo/ebuild/pkg_preinst.bash
new file mode 100644
index 0000000..70a3461
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/pkg_preinst.bash
@@ -0,0 +1,58 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+pkg_preinst()
+{
+ :
+}
+
+ebuild_f_preinst()
+{
+ local old_sandbox_write="${SANDBOX_WRITE}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}${ROOT%/}/"
+
+ if hasq "preinst" ${RESTRICT} ; then
+ ebuild_section "Skipping pkg_preinst (RESTRICT)"
+ elif hasq "preinst" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping pkg_preinst (SKIP_FUNCTIONS)"
+ else
+ if [[ $(type -t pre_pkg_preinst ) == "function" ]] ; then
+ ebuild_section "Starting pre_pkg_preinst"
+ pre_pkg_preinst
+ ebuild_section "Done pre_pkg_preinst"
+ fi
+
+ ebuild_section "Starting pkg_preinst"
+ pkg_preinst
+ ebuild_section "Done pkg_preinst"
+
+ if [[ $(type -t post_pkg_preinst ) == "function" ]] ; then
+ ebuild_section "Starting post_pkg_preinst"
+ post_pkg_preinst
+ ebuild_section "Done post_pkg_preinst"
+ fi
+ fi
+
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${old_sandbox_write}"
+ true
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/pkg_prerm.bash b/paludis/repositories/gentoo/ebuild/pkg_prerm.bash
new file mode 100644
index 0000000..ca28d79
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/pkg_prerm.bash
@@ -0,0 +1,58 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+pkg_prerm()
+{
+ :
+}
+
+ebuild_f_prerm()
+{
+ local old_sandbox_write="${SANDBOX_WRITE}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}${ROOT%/}/"
+
+ if hasq "prerm" ${RESTRICT} ; then
+ ebuild_section "Skipping pkg_prerm (RESTRICT)"
+ elif hasq "prerm" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping pkg_prerm (SKIP_FUNCTIONS)"
+ else
+ if [[ $(type -t pre_pkg_prerm ) == "function" ]] ; then
+ ebuild_section "Starting pre_pkg_prerm"
+ pre_pkg_prerm
+ ebuild_section "Done pre_pkg_prerm"
+ fi
+
+ ebuild_section "Starting pkg_prerm"
+ pkg_prerm
+ ebuild_section "Done pkg_prerm"
+
+ if [[ $(type -t post_pkg_prerm ) == "function" ]] ; then
+ ebuild_section "Starting post_pkg_prerm"
+ post_pkg_prerm
+ ebuild_section "Done post_pkg_prerm"
+ fi
+ fi
+
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${old_sandbox_write}"
+ true
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/pkg_setup.bash b/paludis/repositories/gentoo/ebuild/pkg_setup.bash
new file mode 100644
index 0000000..51b83a4
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/pkg_setup.bash
@@ -0,0 +1,58 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+pkg_setup()
+{
+ :
+}
+
+ebuild_f_setup()
+{
+ local old_sandbox_write="${SANDBOX_WRITE}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}${ROOT%/}/"
+
+ if hasq "setup" ${RESTRICT} ; then
+ ebuild_section "Skipping pkg_setup (RESTRICT)"
+ elif hasq "setup" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping pkg_setup (SKIP_FUNCTIONS)"
+ else
+ if [[ $(type -t pre_pkg_setup ) == "function" ]] ; then
+ ebuild_section "Starting pre_pkg_setup"
+ pre_pkg_setup
+ ebuild_section "Done pre_pkg_setup"
+ fi
+
+ ebuild_section "Starting pkg_setup"
+ pkg_setup
+ ebuild_section "Done pkg_setup"
+
+ if [[ $(type -t post_pkg_setup ) == "function" ]] ; then
+ ebuild_section "Starting post_pkg_setup"
+ post_pkg_setup
+ ebuild_section "Done post_pkg_setup"
+ fi
+ fi
+
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${old_sandbox_write}"
+ true
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/portage_stubs.bash b/paludis/repositories/gentoo/ebuild/portage_stubs.bash
new file mode 100644
index 0000000..5fc6840
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/portage_stubs.bash
@@ -0,0 +1,86 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+has_version()
+{
+ ${PALUDIS_COMMAND} --has-version "$@"
+}
+
+portageq()
+{
+ # \todo Make this suck less...
+ if [[ "$1" == "has_version" ]] ; then
+ if [[ "$(canonicalise $2 )" != "$(canonicalise $ROOT )" ]] ; then
+ eerror "Error emulating 'portageq $@':"
+ die "portageq has_version emulation only works on current ROOT"
+ else
+ shift ; shift
+ has_version "$@"
+ fi
+ elif [[ "$1" == "best_version" ]] ; then
+ if [[ "$(canonicalise $2 )" != "$(canonicalise $ROOT )" ]] ; then
+ eerror "Error emulating 'portageq $@':"
+ die "portageq best_version emulation only works on current ROOT"
+ else
+ shift ; shift
+ best_version "$@"
+ fi
+ elif [[ "$1" == "vdb_path" ]] ; then
+ vdb_path
+ else
+ eerror "Error emulating 'portageq $@':"
+ die "portageq emulation for $1 not implemented"
+ fi
+}
+
+best_version()
+{
+ ${PALUDIS_COMMAND} --best-version "$@"
+}
+
+vdb_path()
+{
+ if ! ${PALUDIS_COMMAND} --configuration-variable installed location ; then
+ die "Could not find vdb_path"
+ fi
+}
+
+check_KV()
+{
+ die "check_KV not implemented"
+}
+
+debug-print()
+{
+ :
+}
+
+debug-print-function()
+{
+ :
+}
+
+debug-print-section()
+{
+ :
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/run_test.bash b/paludis/repositories/gentoo/ebuild/run_test.bash
new file mode 100755
index 0000000..b5587b9
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/run_test.bash
@@ -0,0 +1,47 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+shopt -s expand_aliases
+shopt -s extglob
+set +o posix
+
+export TEST_STATUS=
+export PALUDIS_IN_TEST_FRAMEWORK="yes"
+
+test_return_code()
+{
+ local r="$?"
+ if [[ "0" == "${r}" ]] ; then
+ echo -n "."
+ else
+ echo -n "!{retcode: ${r}}"
+ export local_test_status="fail"
+ export TEST_STATUS="fail"
+ fi
+}
+
+test_equality()
+{
+ if [[ "${1}" == "${2}" ]] ; then
+ echo -n "."
+ else
+ echo -n "!{'${1}' not equal to '${2}'}"
+ export local_test_status="fail"
+ export TEST_STATUS="fail"
+ fi
+}
+
+echo "Test program ${1}:"
+source "$(dirname ${1} )/ebuild.bash" || exit 200
+source "${1}" || exit 200
+
+for testname in $(set | grep '_TEST *() *$' ) ; do
+ [[ ${testname/()} != ${testname} ]] && continue
+ echo -n "* ${testname%_TEST}: "
+ export local_test_status=""
+ ${testname}
+ [[ -z "$local_test_status" ]] && echo " OK" || echo " FAIL"
+done
+
+[[ -z "$TEST_STATUS" ]]
+
diff --git a/paludis/repositories/gentoo/ebuild/sandbox.bash b/paludis/repositories/gentoo/ebuild/sandbox.bash
new file mode 100644
index 0000000..cd504ae
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/sandbox.bash
@@ -0,0 +1,42 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+addread()
+{
+ export SANDBOX_READ="${SANDBOX_READ+${SANDBOX_READ}:}${1}"
+}
+
+addwrite()
+{
+ export SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}${1}"
+}
+
+adddeny()
+{
+ export SANDBOX_DENY="${SANDBOX_DENY+${SANDBOX_DENY}:}${1}"
+}
+
+addpredict()
+{
+ export SANDBOX_PREDICT="${SANDBOX_PREDICT+${SANDBOX_PREDICT}:}${1}"
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/src_compile.bash b/paludis/repositories/gentoo/ebuild/src_compile.bash
new file mode 100644
index 0000000..42c8de1
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/src_compile.bash
@@ -0,0 +1,59 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+src_compile()
+{
+ [[ -x ./configure ]] && econf
+ if [[ -f Makefile ]] || [[ -f makefile ]] || [[ -f GNUmakefile ]] ; then
+ emake || die "emake failed"
+ fi
+}
+
+ebuild_f_compile()
+{
+ if [[ -d "${S}" ]]; then
+ cd "${S}" || die "cd to \${S} (\"${S}\") failed"
+ fi
+
+ if hasq "compile" ${RESTRICT} ; then
+ ebuild_section "Skipping src_compile (RESTRICT)"
+ elif hasq "compile" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping src_compile (SKIP_FUNCTIONS)"
+ else
+ if [[ $(type -t pre_src_compile ) == "function" ]] ; then
+ ebuild_section "Starting pre_src_compile"
+ pre_src_compile
+ ebuild_section "Done pre_src_compile"
+ fi
+
+ ebuild_section "Starting src_compile"
+ src_compile
+ ebuild_section "Done src_compile"
+
+ if [[ $(type -t post_src_compile ) == "function" ]] ; then
+ ebuild_section "Starting post_src_compile"
+ post_src_compile
+ ebuild_section "Done post_src_compile"
+ fi
+ fi
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/src_install.bash b/paludis/repositories/gentoo/ebuild/src_install.bash
new file mode 100644
index 0000000..d7a67cd
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/src_install.bash
@@ -0,0 +1,56 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+src_install()
+{
+ :
+}
+
+ebuild_f_install()
+{
+ if [[ -d "${S}" ]]; then
+ cd "${S}" || die "cd to \${S} (\"${S}\") failed"
+ fi
+
+ if hasq "install" ${RESTRICT} ; then
+ ebuild_section "Skipping src_install (RESTRICT)"
+ elif hasq "install" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping src_install (SKIP_FUNCTIONS)"
+ else
+ if [[ $(type -t pre_src_install ) == "function" ]] ; then
+ ebuild_section "Starting pre_src_install"
+ pre_src_install
+ ebuild_section "Done pre_src_install"
+ fi
+
+ ebuild_section "Starting src_install"
+ src_install
+ ebuild_section "Done src_install"
+
+ if [[ $(type -t post_src_install ) == "function" ]] ; then
+ ebuild_section "Starting post_src_install"
+ post_src_install
+ ebuild_section "Done post_src_install"
+ fi
+ fi
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/src_test.bash b/paludis/repositories/gentoo/ebuild/src_test.bash
new file mode 100644
index 0000000..24ff3d6
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/src_test.bash
@@ -0,0 +1,84 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+src_test()
+{
+ if [[ -f Makefile ]] || [[ -f GNUmakefile ]] || [[ -f makefile ]] ; then
+ echo "Makefile found, looking for potential test targets"
+ if make -j1 -n check ; then
+ echo "Found check target"
+ emake -j1 check || die "make check failed"
+ elif make -j1 -n test ; then
+ echo "Found test target"
+ emake -j1 test || die "make test failed"
+ else
+ echo "No check or test target, skipping tests"
+ fi
+ else
+ echo "No Makefile, skipping tests"
+ fi
+}
+
+ebuild_f_test()
+{
+ local old_sandbox_predict="${SANDBOX_PREDICT}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_PREDICT="${SANDBOX_PREDICT+${SANDBOX_PREDICT}:}/"
+
+ local save_PALUDIS_EXTRA_DIE_MESSAGE="${PALUDIS_EXTRA_DIE_MESSAGE}"
+ export PALUDIS_EXTRA_DIE_MESSAGE="
+!!! This package failed inside the test phase. You should read
+!!! http://paludis.pioto.org/faq.html
+!!! for more information on packages with test phase failures.
+"
+
+ if [[ -d "${S}" ]]; then
+ cd "${S}" || die "cd to \${S} (\"${S}\") failed"
+ fi
+
+ if hasq "test" ${RESTRICT} ; then
+ ebuild_section "Skipping src_test (RESTRICT)"
+ elif hasq "test" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping src_test (SKIP_FUNCTIONS)"
+ else
+ if [[ $(type -t pre_src_test ) == "function" ]] ; then
+ ebuild_section "Starting pre_src_test"
+ pre_src_test
+ ebuild_section "Done pre_src_test"
+ fi
+
+ ebuild_section "Starting src_test"
+ src_test
+ ebuild_section "Done src_test"
+
+ if [[ $(type -t post_src_test ) == "function" ]] ; then
+ ebuild_section "Starting post_src_test"
+ post_src_test
+ ebuild_section "Done post_src_test"
+ fi
+ fi
+
+ export PALUDIS_EXTRA_DIE_MESSAGE="${save_PALUDIS_EXTRA_DIE_MESSAGE}"
+
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_PREDICT="${old_sandbox_predict}"
+ true
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/src_unpack.bash b/paludis/repositories/gentoo/ebuild/src_unpack.bash
new file mode 100644
index 0000000..02ce83e
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/src_unpack.bash
@@ -0,0 +1,54 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+src_unpack()
+{
+ [[ -n "${A}" ]] && unpack ${A}
+}
+
+ebuild_f_unpack()
+{
+ cd ${WORKDIR} || die "cd to \${WORKDIR} (\"${WORKDIR}\") failed"
+
+ if hasq "unpack" ${RESTRICT} ; then
+ ebuild_section "Skipping src_unpack (RESTRICT)"
+ elif hasq "unpack" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping src_unpack (SKIP_FUNCTIONS)"
+ else
+ if [[ $(type -t pre_src_unpack ) == "function" ]] ; then
+ ebuild_section "Starting pre_src_unpack"
+ pre_src_unpack
+ ebuild_section "Done pre_src_unpack"
+ fi
+
+ ebuild_section "Starting src_unpack"
+ src_unpack
+ ebuild_section "Done src_unpack"
+
+ if [[ $(type -t post_src_unpack ) == "function" ]] ; then
+ ebuild_section "Starting post_src_unpack"
+ post_src_unpack
+ ebuild_section "Done post_src_unpack"
+ fi
+ fi
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/unmerge.cc b/paludis/repositories/gentoo/ebuild/unmerge.cc
new file mode 100644
index 0000000..367b42c
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/unmerge.cc
@@ -0,0 +1,320 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "merge_common.hh"
+
+#include <paludis/digests/md5.hh>
+
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/pstream.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/tokeniser.hh>
+
+#include <algorithm>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <iterator>
+#include <string>
+#include <vector>
+#include <list>
+
+#include <cstdlib>
+#include <errno.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+using namespace paludis;
+using namespace merge;
+
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::ifstream;
+
+namespace
+{
+ int exit_status;
+
+ template <typename Iter_>
+ void unmerge_contents(const FSEntry & root, const Iter_ begin, const Iter_ end)
+ {
+ using std::istreambuf_iterator;
+
+ for (Iter_ cur(begin) ; cur != end ; ++cur)
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*cur, std::back_inserter(tokens));
+ if (tokens.empty())
+ continue;
+
+ if ("obj" == tokens.at(0))
+ {
+ while (tokens.size() > 4)
+ {
+ if (std::string::npos != tokens.at(4).find('='))
+ break;
+
+ tokens.at(1).append(" " + tokens.at(2));
+ for (unsigned i = 2 ; i < tokens.size() - 1 ; ++i)
+ tokens.at(i) = tokens.at(i + 1);
+ tokens.pop_back();
+ }
+
+ if (tokens.size() != 4)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "Malformed VDB entry '" + *cur + "'");
+ exit_status |= 4;
+ }
+ else if (! (root / tokens.at(1)).is_regular_file())
+ cout << "--- [!type] " << tokens.at(1) << endl;
+ else if (stringify((root / tokens.at(1)).mtime()) != tokens.at(3))
+ cout << "--- [!time] " << tokens.at(1) << endl;
+ else
+ {
+ ifstream md5_file(stringify(root / tokens.at(1)).c_str());
+ if (! md5_file)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "Couldn't get md5 for '" + stringify(root / tokens.at(1)) + "'");
+ cout << "--- [!md5?] " << tokens.at(1) << endl;
+ }
+ else if (MD5(md5_file).hexsum() != tokens.at(2))
+ cout << "--- [!md5 ] " << tokens.at(1) << endl;
+ else if (is_config_protected(root, root / tokens.at(1)))
+ cout << "--- [cfgpr] " << tokens.at(1) << endl;
+ else
+ {
+ cout << "<<< " << tokens.at(1) << endl;
+
+ mode_t mode((root / tokens.at(1)).permissions());
+ if ((mode & S_ISUID) || (mode & S_ISGID))
+ {
+ mode &= 0400;
+ (root / tokens.at(1)).chmod(mode);
+ }
+ (root / tokens.at(1)).unlink();
+ }
+ }
+ }
+ else if ("sym" == tokens.at(0))
+ {
+ while (tokens.size() > 5)
+ {
+ if (std::string::npos != tokens.at(2).find('='))
+ break;
+
+ if (tokens.at(2) == "->")
+ break;
+
+ tokens.at(1).append(" " + tokens.at(2));
+ for (unsigned i = 2 ; i < tokens.size() - 1; ++i)
+ tokens.at(i) = tokens.at(i + 1);
+ tokens.pop_back();
+ }
+
+ while (tokens.size() > 5)
+ {
+ if (std::string::npos != tokens.at(2).find('='))
+ break;
+
+ if (tokens.at(4) == "->")
+ break;
+
+ tokens.at(3).append(" " + tokens.at(4));
+ for (unsigned i = 4 ; i < tokens.size() - 1; ++i)
+ tokens.at(i) = tokens.at(i + 1);
+ tokens.pop_back();
+ }
+
+ if (tokens.size() != 5)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "Malformed VDB entry '" + *cur + "'");
+ exit_status |= 4;
+ }
+ else if (! (root / tokens.at(1)).is_symbolic_link())
+ cout << "--- [!type] " << tokens.at(1) << endl;
+ else if (stringify((root / tokens.at(1)).mtime()) != tokens.at(4))
+ cout << "--- [!time] " << tokens.at(1) << endl;
+ else if ((root / tokens.at(1)).readlink() != tokens.at(3))
+ cout << "--- [!dest] " << tokens.at(1) << endl;
+ else
+ {
+ cout << "<<< " << tokens.at(1) << endl;
+ (root / tokens.at(1)).unlink();
+ }
+ }
+ else if ("misc" == tokens.at(0))
+ {
+ }
+ else if ("fif" == tokens.at(0) || "dev" == tokens.at(0))
+ {
+ while (tokens.size() > 2)
+ {
+ if (std::string::npos != tokens.at(2).find('='))
+ break;
+
+ tokens.at(1).append(" " + tokens.at(2));
+ for (unsigned i = 2 ; i < tokens.size() - 1; ++i)
+ tokens.at(i) = tokens.at(i + 1);
+ tokens.pop_back();
+ }
+
+ if (tokens.size() != 2)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "Malformed VDB entry '" + *cur + "'");
+ exit_status |= 8;
+ }
+ else if ("fif" == tokens.at(0) && ! (root / tokens.at(1)).is_fifo())
+ cout << "--- [!type] " << tokens.at(1) << endl;
+ else if ("dev" == tokens.at(0) && ! (root / tokens.at(1)).is_device())
+ cout << "--- [!type] " << tokens.at(1) << endl;
+ else
+ {
+ cout << "<<< " << tokens.at(1) << endl;
+ (root / tokens.at(1)).unlink();
+ }
+ }
+ else if ("dir" == tokens.at(0))
+ /* nothing */ ;
+ else
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "Skipping unknown VDB entry '" + *cur + "'");
+ exit_status |= 2;
+ }
+ }
+ }
+
+ template <typename Iter_>
+ void unmerge_directories(const FSEntry & root, const Iter_ begin, const Iter_ end)
+ {
+ using std::istreambuf_iterator;
+
+ for (Iter_ cur(begin) ; cur != end ; ++cur)
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*cur, std::back_inserter(tokens));
+ if (tokens.empty())
+ continue;
+
+ if ("dir" == tokens.at(0))
+ {
+ while (tokens.size() > 2)
+ {
+ if (std::string::npos != tokens.at(2).find('='))
+ break;
+
+ tokens.at(1).append(" " + tokens.at(2));
+ for (unsigned i = 2 ; i < tokens.size() - 1; ++i)
+ tokens.at(i) = tokens.at(i + 1);
+ tokens.pop_back();
+ }
+
+ if (tokens.size() != 2)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "Malformed VDB entry '" + *cur + "'");
+ exit_status |= 8;
+ }
+ else if (! (root / tokens.at(1)).is_directory())
+ cout << "--- [!type] " << tokens.at(1) << endl;
+ else if (DirIterator((root / tokens.at(1)), false) != DirIterator())
+ cout << "--- [!empt] " << tokens.at(1) << endl;
+ else
+ {
+ cout << "<<< " << tokens.at(1) << endl;
+ (root / tokens.at(1)).rmdir();
+ }
+ }
+ }
+ }
+}
+
+int
+main(int argc, char * argv[])
+{
+ Context context("In main program:");
+ exit_status = 0;
+ try
+ {
+ if (argc != 3)
+ throw Failure("Usage: " + stringify(argv[0]) + " root contents");
+
+ Log::get_instance()->set_program_name(argv[0]);
+ std::string log_level(getenv_with_default("PALUDIS_EBUILD_LOG_LEVEL", "qa"));
+
+ if (log_level == "debug")
+ Log::get_instance()->set_log_level(ll_debug);
+ else if (log_level == "qa")
+ Log::get_instance()->set_log_level(ll_qa);
+ else if (log_level == "warning")
+ Log::get_instance()->set_log_level(ll_warning);
+ else if (log_level == "silent")
+ Log::get_instance()->set_log_level(ll_silent);
+ else
+ throw Failure("bad value for log level");
+
+ FSEntry root(argv[1]), contents(argv[2]);
+
+ if (! ((root = root.realpath())).is_directory())
+ throw Failure(stringify(argv[1]) + ": not a directory");
+
+ ifstream contents_file(stringify(contents).c_str());
+ if (! contents_file)
+ throw Failure(stringify(contents) + ": not readable");
+
+ std::list<std::string> lines;
+ std::string line;
+ while (std::getline(contents_file, line))
+ lines.push_back(line);
+
+ unmerge_contents(root, lines.begin(), lines.end());
+ unmerge_directories(root, lines.rbegin(), lines.rend());
+ return exit_status;
+ }
+ catch (const Failure & f)
+ {
+ cerr << argv[0] << ": fatal error: " << f.message << endl;
+ return EXIT_FAILURE;
+ }
+ catch (const Exception & e)
+ {
+ cerr << argv[0] << ": fatal error:" << endl
+ << " * " << e.backtrace("\n * ") << e.message()
+ << " (" << e.what() << ")" << endl;
+ return EXIT_FAILURE;
+ }
+ catch (const std::exception & e)
+ {
+ cerr << argv[0] << ": fatal error: " << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+}
+
+
diff --git a/paludis/repositories/gentoo/ebuild/unmerge_TEST.bash b/paludis/repositories/gentoo/ebuild/unmerge_TEST.bash
new file mode 100644
index 0000000..bd59a91
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/unmerge_TEST.bash
@@ -0,0 +1,94 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+unmerge_empty_TEST()
+{
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/merge "unmerge_TEST_dir/empty_src" \
+ "unmerge_TEST_dir/empty_dst" \
+ "unmerge_TEST_dir/empty_contents" 1>/dev/null
+ test_return_code
+
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/unmerge "unmerge_TEST_dir/empty_dst" \
+ "unmerge_TEST_dir/empty_contents" 1>/dev/null
+ test_return_code
+
+ ok=
+ for a in unmerge_TEST_dir/empty_dst/* ; do
+ [[ -e "$a" ]] || continue
+ test_equality "$a" ""
+ ok=no
+ done
+ test_equality "$ok" ""
+}
+
+unmerge_files_TEST()
+{
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/merge "unmerge_TEST_dir/files_src" \
+ "unmerge_TEST_dir/files_dst" \
+ "unmerge_TEST_dir/files_contents" 1>/dev/null
+ test_return_code
+
+ ok=
+ for a in unmerge_TEST_dir/files_dst/* ; do
+ [[ -e "$a" ]] || continue
+ ok=yes
+ break
+ done
+ test_equality "$ok" "yes"
+
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/unmerge "unmerge_TEST_dir/files_dst" \
+ "unmerge_TEST_dir/files_contents" 1>/dev/null
+ test_return_code
+
+ ok=
+ for a in unmerge_TEST_dir/files_dst/* ; do
+ [[ -e "$a" ]] || continue
+ test_equality "$a" ""
+ ok=no
+ done
+ test_equality "$ok" ""
+}
+
+unmerge_spaces_TEST()
+{
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/merge "unmerge_TEST_dir/spaces_src" \
+ "unmerge_TEST_dir/spaces_dst" \
+ "unmerge_TEST_dir/spaces_contents"
+ test_return_code
+
+ ok=
+ for a in unmerge_TEST_dir/spaces_dst/* ; do
+ [[ -e "$a" ]] || continue
+ ok=yes
+ break
+ done
+ test_equality "$ok" "yes"
+
+ ${TOP_BUILD_DIR}/paludis/repositories/gentoo/ebuild/unmerge "unmerge_TEST_dir/spaces_dst" \
+ "unmerge_TEST_dir/spaces_contents"
+ test_return_code
+
+ ok=
+ for a in unmerge_TEST_dir/spaces_dst/* ; do
+ [[ -e "$a" ]] || continue
+ test_equality "$a" ""
+ ok=no
+ done
+ test_equality "$ok" ""
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/unmerge_TEST_cleanup.sh b/paludis/repositories/gentoo/ebuild/unmerge_TEST_cleanup.sh
new file mode 100755
index 0000000..e0f01b6
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/unmerge_TEST_cleanup.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d unmerge_TEST_dir ] ; then
+ rm -fr unmerge_TEST_dir
+else
+ true
+fi
+
+
+
diff --git a/paludis/repositories/gentoo/ebuild/unmerge_TEST_setup.sh b/paludis/repositories/gentoo/ebuild/unmerge_TEST_setup.sh
new file mode 100755
index 0000000..33643aa
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/unmerge_TEST_setup.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir -p unmerge_TEST_dir/{empty_src,empty_dst} || exit 2
+
+mkdir -p unmerge_TEST_dir/{files_src,files_dst} || exit 3
+echo "file one" > unmerge_TEST_dir/files_src/one
+echo "file two" > unmerge_TEST_dir/files_src/two
+
+mkdir -p unmerge_TEST_dir/{spaces_src,spaces_dst} || exit 4
+echo "file one" > unmerge_TEST_dir/spaces_src/"file one"
+mkdir -p unmerge_TEST_dir/spaces_src/"dir two"
+echo "file two" > unmerge_TEST_dir/spaces_src/"dir two"/"file two"
+ln -s "link three" unmerge_TEST_dir/spaces_src/"link three"
+
diff --git a/paludis/repositories/gentoo/ebuild/usage_error.bash b/paludis/repositories/gentoo/ebuild/usage_error.bash
new file mode 100644
index 0000000..0af5b2d
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/usage_error.bash
@@ -0,0 +1,31 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+ebuild_f_usage_error()
+{
+ if [[ -z ${1} ]] ; then
+ die "Usage error"
+ else
+ die "Usage error: ${1}"
+ fi
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/utils/Makefile.am b/paludis/repositories/gentoo/ebuild/utils/Makefile.am
new file mode 100644
index 0000000..c0f2447
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/Makefile.am
@@ -0,0 +1,92 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+libexecprogdir = $(libexecdir)/paludis/utils
+
+libexecprog_SCRIPTS = \
+ canonicalise \
+ dobin \
+ doconfd \
+ dodir \
+ dodoc \
+ doenvd \
+ doexe \
+ dohard \
+ dohtml \
+ doinfo \
+ doinitd \
+ doins \
+ dolib \
+ dolib.a \
+ dolib.so \
+ doman \
+ domo \
+ donewins \
+ dosbin \
+ dosed \
+ dosym \
+ dounpack \
+ emake \
+ fowners \
+ fperms \
+ getmtime \
+ getfsize \
+ newbin \
+ newconfd \
+ newdoc \
+ newenvd \
+ newexe \
+ newinitd \
+ newins \
+ newlib.a \
+ newlib.so \
+ newman \
+ newsbin \
+ prepall \
+ prepallstrip \
+ prepstrip \
+ prepallman \
+ prepman \
+ prepallinfo \
+ prepinfo \
+ prepdocs \
+ prepalldocs
+
+AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@
+
+TESTS_ENVIRONMENT = env \
+ PALUDIS_EBUILD_DIR="`$(top_srcdir)/paludis/repositories/gentoo/ebuild/utils/canonicalise \
+ $(top_srcdir)/paludis/repositories/gentoo/ebuild/`" \
+ TOP_BUILD_DIR="`$(top_srcdir)/paludis/repositories/gentoo/ebuild/utils/canonicalise $(top_builddir)/`" \
+ PALUDIS_EBUILD_LOG_LEVEL="silent" \
+ TEST_SCRIPT_DIR="$(srcdir)/" \
+ bash $(top_srcdir)/paludis/repositories/gentoo/ebuild/utils/run_test.bash
+
+TESTS = dobin_TEST.bash getfsize_TEST.bash
+
+prep_scripts = prepall prepallstrip prepallman prepallinfo prepstrip prepman prepinfo prepdocs prepalldocs
+
+EXTRA_DIST = $(libexecprog_SCRIPTS) $(check_SCRIPTS) run_test.bash \
+ newlib.so.in newlib.a.in dolib.so.in dolib.a.in prep.in $(TESTS)
+
+CLEANFILES = *~ newlib.so newlib.a dolib.so dolib.a $(prep_scripts)
+
+newlib.a : newlib.a.in
+ cat $? > $@
+
+newlib.so : newlib.so.in
+ cat $? > $@
+
+dolib.so : dolib.so.in
+ cat $? > $@
+
+dolib.a : dolib.a.in
+ cat $? > $@
+
+$(prep_scripts) : prep.in
+ cat $? > $@
+
+check_PROGRAMS =
+
+built-sources : $(BUILT_SOURCES)
+ for s in `echo $(SUBDIRS) | tr -d .` ; do $(MAKE) -C $$s built-sources || exit 1 ; done
+
diff --git a/paludis/repositories/gentoo/ebuild/utils/canonicalise b/paludis/repositories/gentoo/ebuild/utils/canonicalise
new file mode 100755
index 0000000..b186eba
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/canonicalise
@@ -0,0 +1,6 @@
+#!/bin/bash
+case $(uname -s) in
+ FreeBSD) realpath "$@" ;;
+ *) readlink -f "$@" ;;
+esac
+
diff --git a/paludis/repositories/gentoo/ebuild/utils/dobin b/paludis/repositories/gentoo/ebuild/utils/dobin
new file mode 100755
index 0000000..506f50f
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/dobin
@@ -0,0 +1,48 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon dobin from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -lt 1 ]]; then
+ echo "${0}: at least one argument needed" >&2
+ exit 1
+fi
+
+if [[ ! -d "${D}${DESTTREE}/bin" ]]; then
+ install -d "${D}${DESTTREE}/bin" || exit 3
+fi
+
+ret=0
+for x in "$@" ; do
+ if [[ -x "${x}" ]]; then
+ install "${x}" "${D}${DESTTREE}/bin" || ret=2
+ else
+ echo ">>> ${0}: making ${x} executable..."
+ install -m0755 -o root -g 0 "${x}" "${D}${DESTTREE}/bin" || ret=2
+ fi
+done
+
+exit ${ret}
diff --git a/paludis/repositories/gentoo/ebuild/utils/dobin_TEST.bash b/paludis/repositories/gentoo/ebuild/utils/dobin_TEST.bash
new file mode 100644
index 0000000..1af7700
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/dobin_TEST.bash
@@ -0,0 +1,70 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+source ${PALUDIS_EBUILD_DIR}/install_functions.bash
+
+dobin_TEST()
+{
+ mkdir -p dobin_TEST_dir/src dobin_TEST_dir/dst ; test_return_code
+
+ echo "one contents" > dobin_TEST_dir/src/one ; test_return_code
+ chmod +x dobin_TEST_dir/src/one ; test_return_code
+
+ echo "two contents" > dobin_TEST_dir/src/two ; test_return_code
+ chmod +x dobin_TEST_dir/src/two ; test_return_code
+
+ echo "three contents" > dobin_TEST_dir/src/three ; test_return_code
+ chmod +x dobin_TEST_dir/src/three ; test_return_code
+
+ export D=dobin_TEST_dir/dst
+ ${PALUDIS_EBUILD_DIR}/utils/dobin dobin_TEST_dir/src/one &>/dev/null ; test_return_code
+ ${PALUDIS_EBUILD_DIR}/utils/dobin dobin_TEST_dir/src/two dobin_TEST_dir/src/three &>/dev/null ; test_return_code
+
+ [[ -f dobin_TEST_dir/dst/usr/bin/one ]] ; test_return_code
+ [[ -f dobin_TEST_dir/dst/usr/bin/two ]] ; test_return_code
+ [[ -f dobin_TEST_dir/dst/usr/bin/three ]] ; test_return_code
+
+ test_equality "$(< dobin_TEST_dir/dst/usr/bin/one)" "one contents"
+ test_equality "$(< dobin_TEST_dir/dst/usr/bin/two)" "two contents"
+ test_equality "$(< dobin_TEST_dir/dst/usr/bin/three)" "three contents"
+
+ rm -fr dobin_TEST_dir
+}
+
+dobin_fail_TEST()
+{
+ mkdir -p dobin_TEST_dir/src dobin_TEST_dir/dst ; test_return_code
+ echo "one contents" > dobin_TEST_dir/src/one ; test_return_code
+ echo "two contents" > dobin_TEST_dir/src/two ; test_return_code
+ echo "three contents" > dobin_TEST_dir/src/three ; test_return_code
+
+ export D=dobin_TEST_dir/dst
+ ! ${PALUDIS_EBUILD_DIR}/utils/dobin dobin_TEST_dir/src/four &>/dev/null ; test_return_code
+ ! ${PALUDIS_EBUILD_DIR}/utils/dobin dobin_TEST_dir/src/one dobin_TEST_dir/src/seven &>/dev/null ; test_return_code
+ ! ${PALUDIS_EBUILD_DIR}/utils/dobin dobin_TEST_dir/src/eight dobin_TEST_dir/src/one &>/dev/null ; test_return_code
+
+ [[ -f dobin_TEST_dir/dst/usr/bin/one ]] ; test_return_code
+ ! [[ -f dobin_TEST_dir/dst/usr/bin/four ]] ; test_return_code
+ ! [[ -f dobin_TEST_dir/dst/usr/bin/five ]] ; test_return_code
+ ! [[ -f dobin_TEST_dir/dst/usr/bin/six ]] ; test_return_code
+
+ test_equality "$(< dobin_TEST_dir/dst/usr/bin/one)" "one contents"
+
+ rm -fr dobin_TEST_dir
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/utils/doconfd b/paludis/repositories/gentoo/ebuild/utils/doconfd
new file mode 100644
index 0000000..37c453c
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/doconfd
@@ -0,0 +1,32 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon doconfd from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [ ${#} -lt 1 ]; then
+ echo "${0}: at least one argument needed" >&2
+ exit 1
+fi
+
+INSDESTTREE=/etc/conf.d/
+doins "$@" || exit 2
diff --git a/paludis/repositories/gentoo/ebuild/utils/dodir b/paludis/repositories/gentoo/ebuild/utils/dodir
new file mode 100644
index 0000000..52b7c20
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/dodir
@@ -0,0 +1,34 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon dodir from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 247
+fi
+
+ret=0
+for x in "$@"; do
+ install -d ${DIROPTIONS} "${D}${x}" || ret=2
+done
+
+exit ${ret}
diff --git a/paludis/repositories/gentoo/ebuild/utils/dodoc b/paludis/repositories/gentoo/ebuild/utils/dodoc
new file mode 100644
index 0000000..bfff299
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/dodoc
@@ -0,0 +1,55 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon dodoc from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ $# -lt 1 ]]; then
+ echo "${0}: at least one argument needed" >&2
+ exit 1
+fi
+
+if [[ -z ${PALUDIS_COMPRESS} ]]; then
+ PALUDIS_COMPRESS="gzip -f -9"
+fi
+
+dir="${D}usr/share/doc/${PF}/${DOCDESTTREE}"
+if [[ ! -d "${dir}" ]]; then
+ install -d "${dir}" || exit 3
+fi
+
+ret=0
+
+for x in "$@"; do
+ if [[ -s "${x}" ]]; then
+ install -m0644 "${x}" "${dir}"
+ ${PALUDIS_COMPRESS} "${dir}/${x##*/}"
+ elif [[ ! -e "${x}" ]]; then
+ echo "${0}: ${x} does not exist" >&2
+ ret=2
+ fi
+done
+
+exit ${ret}
diff --git a/paludis/repositories/gentoo/ebuild/utils/doenvd b/paludis/repositories/gentoo/ebuild/utils/doenvd
new file mode 100644
index 0000000..7299776
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/doenvd
@@ -0,0 +1,32 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon doenvd from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ${#} -lt 1 ]]; then
+ echo "${0}: at least one argument needed" >&2
+ exit 1
+fi
+
+export INSDESTTREE=/etc/env.d/
+doins "$@"
diff --git a/paludis/repositories/gentoo/ebuild/utils/doexe b/paludis/repositories/gentoo/ebuild/utils/doexe
new file mode 100644
index 0000000..a67166b
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/doexe
@@ -0,0 +1,58 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon doexe from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -lt 1 ]]; then
+ echo "${0}: at least one argument needed"
+ exit 1
+fi
+
+if [[ ! -d "${D}${EXEDESTTREE}" ]]; then
+ install -d "${D}${EXEDESTTREE}" || exit 3
+fi
+
+ret=0
+
+for x in "$@"; do
+ if [[ -L ${x} ]]; then
+ cp "${x}" "${T}"
+ mysrc="${T}/$(/usr/bin/basename "${x}")"
+ elif [[ -d ${x} ]]; then
+ echo "${0}: skipping directory ${x}" >&2
+ continue
+ else
+ mysrc="${x}"
+ fi
+ install ${EXEOPTIONS} "${mysrc}" "${D}${EXEDESTTREE}" || ret=2
+done
+
+exit ${ret}
diff --git a/paludis/repositories/gentoo/ebuild/utils/dohard b/paludis/repositories/gentoo/ebuild/utils/dohard
new file mode 100644
index 0000000..b0758e5
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/dohard
@@ -0,0 +1,34 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon dohard from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed" >&2
+ exit 1
+fi
+
+ln -f "${D}${1}" "${D}${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/dohtml b/paludis/repositories/gentoo/ebuild/utils/dohtml
new file mode 100644
index 0000000..09743c9
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/dohtml
@@ -0,0 +1,122 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon dohtml from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+source ${PALUDIS_EBUILD_DIR}/list_functions.bash
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 247
+fi
+
+allowed_exts="png gif html htm jpg css jps"
+disallowed_dirs=""
+allowed_files=""
+recurse=0
+args=( )
+
+split_names() {
+ list=$1
+ if [[ ${list} == *,* ]]; then
+ echo -n "${list%%,*} "
+ split_names ${list#*,}
+ else
+ echo ${list}
+ fi
+}
+
+parse_args() {
+ while [[ ${#} -gt 0 ]]; do
+ case $1 in
+ -r)
+ recurse=1 ;;
+ -V)
+ verbose=1 ;;
+ -A)
+ allowed_exts="${allowed_exts} $(split_names $2)"
+ shift
+ ;;
+ -a)
+ allowed_exts="$(split_names $2)"
+ shift
+ ;;
+ -f)
+ allowed_files="$(split_names $2)"
+ shift
+ ;;
+ -x)
+ disallowed_dirs="$(split_names $2)"
+ shift
+ ;;
+ *)
+ args=( "${args[@]}" "$1" ) ;;
+ esac
+ shift
+ done
+}
+
+install_file() {
+ local bn=${1}
+ local dn=${2}
+ local prefix=${3}
+ local ret=0
+
+ path=${bn}
+ [[ -n ${prefix} ]] && path="${prefix}/${path}"
+ [[ -n ${dn} ]] && path="${dn}/${path}"
+
+ [[ -z ${DOCDESTTREE} ]] && DOCDESTTREE="html"
+
+ dir="${D}usr/share/doc/${PF}/${DOCDESTTREE}/${prefix}"
+
+ if [[ -f ${path} ]]; then
+ ext="$(basename ${path})"
+ ext="${ext##*.}"
+ if ([[ -n ${ext} ]] && has $ext $allowed_exts) || has $bn $allowed_files
+ then
+ [[ ! -d ${dir} ]] && install -d "${dir}"
+ echo "install -m0644 ${path} ${dir}"
+ install -m0644 "${path}" "${dir}/${bn}"
+ fi
+ elif [[ $recurse == 1 && -d ${path} ]] &&
+ ! has "${bn}" ${disallowed_dirs}; then
+ for f in ${path}/*; do
+ pfx=${bn}
+ [[ -n ${prefix} ]] && pfx="${prefix}/${pfx}"
+ install_file "$(basename "${f}")" "${dn}" "${pfx}"
+ (( ret += $? ))
+ done
+ else
+ (( ++ret ))
+ fi
+ return ${ret}
+}
+
+parse_args "$@"
+
+retval=0
+for i in "${args[@]}"; do
+ install_file "$(basename "${i}")" "$(dirname "${i}")"
+ (( retval += $? ))
+done
+
+exit $retval
diff --git a/paludis/repositories/gentoo/ebuild/utils/doinfo b/paludis/repositories/gentoo/ebuild/utils/doinfo
new file mode 100644
index 0000000..746812c
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/doinfo
@@ -0,0 +1,55 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon doinfo from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 1
+fi
+
+if [[ ${#} -lt 1 ]]; then
+ echo "${0}: at least one argument needed" >&2
+ exit 1
+fi
+
+if [[ ! -d "${D}usr/share/info" ]]; then
+ install -d "${D}usr/share/info" || exit 3
+fi
+
+if [[ -z ${PALUDIS_COMPRESS} ]]; then
+ PALUDIS_COMPRESS="gzip -f -9"
+fi
+
+ret=0
+
+for x in "$@"; do
+ if [[ -e "${x}" ]]; then
+ install -m0644 "${x}" "${D}usr/share/info"
+ ${PALUDIS_COMPRESS} "${D}usr/share/info/$(basename "${x}")"
+ else
+ echo "${0}: ${x} does not exist"
+ ret=2
+ fi
+done
+
+exit ${ret}
+
diff --git a/paludis/repositories/gentoo/ebuild/utils/doinitd b/paludis/repositories/gentoo/ebuild/utils/doinitd
new file mode 100644
index 0000000..8fc7080
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/doinitd
@@ -0,0 +1,32 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon doinitd from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ${#} -lt 1 ]]; then
+ echo "${0}: at least one argument needed" >&2
+ exit 1
+fi
+
+EXEDESTTREE=/etc/init.d
+doexe "$@"
diff --git a/paludis/repositories/gentoo/ebuild/utils/doins b/paludis/repositories/gentoo/ebuild/utils/doins
new file mode 100644
index 0000000..2d70f5a
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/doins
@@ -0,0 +1,89 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon doins from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -lt 1 ]]; then
+ echo "${0}: at least one argument needed" >&2
+ exit 1
+fi
+
+if [[ ${1} == "-r" ]]; then
+ DOINSRECUR=y
+ shift
+else
+ DOINSRECUR=n
+fi
+
+if [[ -z "${INSDEPTH}" ]]; then
+ declare -i INSDEPTH=0
+fi
+
+if [[ ${INSDESTTREE} == ${D}* ]]; then
+ echo "-------------------------------------------------------" >&2
+ echo "You should not use \${D} with helpers." >&2
+ echo " --> ${INSDESTTREE}" >&2
+ echo "-------------------------------------------------------" >&2
+ exit 248
+fi
+
+if [[ ! -d "${D}${INSDESTTREE}" ]]; then
+ dodir "${INSDESTTREE}"
+fi
+
+ret=0
+
+for x in "$@"; do
+ if [[ -L ${x} ]]; then
+ cp "${x}" "${T}"
+ mysrc="${T}/$(basename "${x}")"
+ elif [[ -d ${x} ]]; then
+ if [[ ${DOINSRECUR} == "n" ]]; then
+ continue
+ fi
+
+ mydir="${INSDESTTREE}/$(basename "${x}")"
+ find "${x}" -mindepth 1 -maxdepth 1 -exec \
+ env \
+ INSDESTTREE="${mydir}" \
+ INSDEPTH=$((INSDEPTH+1)) \
+ ${0} -r {} \;
+ continue
+ else
+ mysrc="${x}"
+ fi
+
+ install ${INSOPTIONS} "${mysrc}" "${D}${INSDESTTREE}" || ret=2
+done
+
+exit ${ret}
diff --git a/paludis/repositories/gentoo/ebuild/utils/dolib b/paludis/repositories/gentoo/ebuild/utils/dolib
new file mode 100644
index 0000000..c35b202
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/dolib
@@ -0,0 +1,62 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon dolib from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ! -d ${PALUDIS_EBUILD_MODULES_DIR} ]]; then
+ echo "${0}: \${PALUDIS_EBUILD_MODULES_DIR} not valid; aborting" >&2
+ exit 1
+fi
+
+source "${PALUDIS_EBUILD_MODULES_DIR}/multilib_functions.bash"
+
+libdir="${D}${DESTTREE}/$(ebuild_get_libdir)"
+
+if [[ ${#} -lt 1 ]]; then
+ echo "${0}: at least one argument needed"
+ exit 1
+fi
+
+if [[ ! -d ${libdir} ]]; then
+ install -d "${libdir}" || exit 3
+fi
+
+ret=0
+
+for x in "$@"; do
+ if [[ -e ${x} ]]; then
+ if [[ ! -L ${x} ]]; then
+ install ${LIBOPTIONS} "${x}" "${libdir}" || ret=2
+ else
+ ln -s "$(readlink "${x}")" "${libdir}/$(basename "${x}")" || ret=2
+ fi
+ else
+ echo "${0}: ${x} does not exist"
+ ret=2
+ fi
+done
+
+exit ${ret}
diff --git a/paludis/repositories/gentoo/ebuild/utils/dolib.a.in b/paludis/repositories/gentoo/ebuild/utils/dolib.a.in
new file mode 100644
index 0000000..e766554
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/dolib.a.in
@@ -0,0 +1,27 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon dolib.a from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+LIBOPTIONS="-m0644" dolib "$@"
+
diff --git a/paludis/repositories/gentoo/ebuild/utils/dolib.so.in b/paludis/repositories/gentoo/ebuild/utils/dolib.so.in
new file mode 100644
index 0000000..d4dcb4a
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/dolib.so.in
@@ -0,0 +1,26 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon dolib.so from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+LIBOPTIONS="-m0755" dolib "$@"
diff --git a/paludis/repositories/gentoo/ebuild/utils/doman b/paludis/repositories/gentoo/ebuild/utils/doman
new file mode 100644
index 0000000..3a24689
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/doman
@@ -0,0 +1,85 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon doman from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -lt 1 ]]; then
+ echo "${0}: at least one argument needed" >&2
+ exit 1
+fi
+
+if [[ -z ${PALUDIS_COMPRESS} ]]; then
+ PALUDIS_COMPRESS="gzip -f -9"
+fi
+
+BASE="/usr/share"
+i18n=""
+
+for x in "$@"; do
+ if [[ ${x:0:6} == "-i18n=" ]]; then
+ i18n="${x:6}/"
+ continue
+ fi
+ if [[ ${x} == .keep ]]; then
+ continue
+ fi
+
+ suffix=${x##*.}
+
+ if [[ ${suffix} == "gz" ]]; then
+ compressed="gz"
+ realname=${x%.*}
+ suffix=${realname##*.}
+ else
+ realname=${x}
+ compressed=""
+ fi
+
+ mandir="${i18n}man${suffix:0:1}"
+ match='man[0-9n](|f|p|pm)$'
+
+ if [[ ${mandir} =~ ${match} ]]; then
+ if [[ -s ${x} ]]; then
+ if [[ ! -d "${D}${BASE}/man/${mandir}" ]]; then
+ install -d "${D}${BASE}/man/${mandir}"
+ fi
+
+ install -m0644 "${x}" "${D}${BASE}/man/${mandir}" || ret=2
+
+ if [[ -z ${compressed} ]]; then
+ ${PALUDIS_COMPRESS} "${D}${BASE}/man/${mandir}/$(basename "${x}")"
+ fi
+ else
+ echo "${0}: ${x} does not exist" >&2
+ ret=2
+ fi
+ else
+ echo "${0}: '${x}' is probably not a man page; skipping" >&2
+ ret=2
+ fi
+done
+
+exit ${ret}
diff --git a/paludis/repositories/gentoo/ebuild/utils/domo b/paludis/repositories/gentoo/ebuild/utils/domo
new file mode 100644
index 0000000..b7a0dd4
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/domo
@@ -0,0 +1,54 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon domo from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -lt 1 ]]; then
+ echo "${0}: at least one argument needed" >&2
+ exit 1
+fi
+
+if [[ ! -d "${D}${DESTTREE}/share/locale" ]]; then
+ install -d "${D}${DESTTREE}/share/locale" || exit 3
+fi
+
+ret=0
+
+for x in "$@"; do
+ if [[ -e ${x} ]]; then
+ mytiny="$(basename "${x}")"
+ mydir="${D}${DESTTREE}/share/local/${mytiny%.*}/LC_MESSAGES"
+ if [[ ! -d ${mydir} ]]; then
+ install -d "${mydir}"
+ fi
+ install -m0644 "${x}" "${mydir}/${MOPREFIX}.mo" || ret=2
+ else
+ echo "${0}: ${x} does not exist" >&2
+ ret=2
+ fi
+done
+
+exit ${ret}
diff --git a/paludis/repositories/gentoo/ebuild/utils/donewins b/paludis/repositories/gentoo/ebuild/utils/donewins
new file mode 100644
index 0000000..90f0377
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/donewins
@@ -0,0 +1,40 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon donewins from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed." >&2
+ exit 1
+fi
+
+ebuild_notice "qa" "${0} is retarded. Don't use it; use newins instead."
+
+rm -rf "${T}/${2}"
+cp "${1}" "${T}/${2}"
+doins "${T}/${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/dosbin b/paludis/repositories/gentoo/ebuild/utils/dosbin
new file mode 100644
index 0000000..25c6258
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/dosbin
@@ -0,0 +1,45 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon dosbin from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -lt 1 ]]; then
+ echo "${0}: at least one argument needed" >&2
+ exit 1
+fi
+
+if [[ ! -d "${D}${DESTTREE}/sbin" ]]; then
+ install -d "${D}${DESTTREE}/sbin" || exit 3
+fi
+
+for x in "$@"; do
+ if [[ -x ${x} ]]; then
+ install -m0755 "${x}" "${D}${DESTTREE}/sbin" || exit 2
+ else
+ echo ">>> dosbin: making ${x} executable..."
+ install -m0755 -o root -g 0 "${x}" "${D}${DESTTREE}/sbin" || exit 2
+ fi
+done
diff --git a/paludis/repositories/gentoo/ebuild/utils/dosed b/paludis/repositories/gentoo/ebuild/utils/dosed
new file mode 100644
index 0000000..ca9dc04
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/dosed
@@ -0,0 +1,52 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon dosed from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -lt 1 ]]; then
+ echo "${0}: at least one argument needed" >&2
+ exit 1
+fi
+
+mysed="s:${D}::g"
+
+ret=0
+
+for x in "$@"; do
+ y="${D}${x}"
+ if [[ -e ${y} ]]; then
+ if [[ -f "${y}" ]]; then
+ sed -i -e "${mysed}" "${y}" || ret=2
+ else
+ echo "${0}: ${y} is not a regular file"
+ ret=2
+ fi
+ else
+ mysed="${x}"
+ fi
+done
+
+exit ${ret}
diff --git a/paludis/repositories/gentoo/ebuild/utils/dosym b/paludis/repositories/gentoo/ebuild/utils/dosym
new file mode 100644
index 0000000..818ef1a
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/dosym
@@ -0,0 +1,42 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon dosym from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+source ${PALUDIS_EBUILD_DIR}/echo_functions.bash
+
+if [[ ! -d ${D} ]]; then
+ echo "${0}: \${D} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed" >&2
+ exit 1
+fi
+
+if [[ ! -d $(dirname "${D}$2") ]]; then
+ ebuild_notice "qa" "$0: target directory ${D}$2 does not exist; creating. Please fix the ebuild to create it explicitly."
+ dodir $(dirname $2)
+fi
+
+ln -snf "${1}" "${D}${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/dounpack b/paludis/repositories/gentoo/ebuild/utils/dounpack
new file mode 100755
index 0000000..2af875f
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/dounpack
@@ -0,0 +1,114 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+die()
+{
+ echo "dounpack: error: $@" 1>&2
+ exit 123
+}
+
+unpack_one()
+{
+ [[ -z "$1" ]] && die "Bad argument for unpack_one"
+ [[ -e "$1" ]] || die "${1} doesn't exist"
+
+ case "${x}" in
+ *.tar)
+ echo tar xf "${1}" --no-same-owner "${TAR_OPTIONS[@]}" 1>&2
+ tar xf "${1}" --no-same-owner "${TAR_OPTIONS[@]}" || die "Couldn't unpack ${1}"
+ ;;
+
+ *.tar.gz|*.tgz|*.tar.Z)
+ echo tar zxf "${1}" --no-same-owner "${TAR_OPTIONS[@]}" 1>&2
+ tar zxf "${1}" --no-same-owner "${TAR_OPTIONS[@]}" || die "Couldn't unpack ${1}"
+ ;;
+
+ *.tar.bz2|*.tbz2)
+ echo tar jxf "${1}" --no-same-owner "${TAR_OPTIONS[@]}" 1>&2
+ tar jxf "${1}" --no-same-owner "${TAR_OPTIONS[@]}" || die "Couldn't unpack ${1}"
+ ;;
+
+ *.zip|*.ZIP|*.jar)
+ echo unzip -qo "${1}" 1>&2
+ unzip -qo "${1}" || die "Couldn't unpack ${1}"
+ ;;
+
+ *.gz|*.Z|*.z)
+ echo gzip -dc "${1}" > ${UNPACKTODIR}/$(basename "${1%.*}" ) 1>&2
+ gzip -dc "${1}" > ${UNPACKTODIR}/$(basename "${1%.*}" ) || die "Couldn't unpack ${1}"
+ ;;
+
+ *.bz2)
+ echo bzip2 -dc "${1}" > ${UNPACKTODIR}/$(basename "${1%.*}" ) 1>&2
+ bzip2 -dc "${1}" > ${UNPACKTODIR}/$(basename "${1%.*}" ) || die "Couldn't unpack ${1}"
+ ;;
+
+ *.rar|*.RAR)
+ echo unrar x -idq "${1}" 1>&2
+ unrar x -idq "${1}" || die "Couldn't unpack ${1}"
+ ;;
+
+ *.LHa|*.LHA|*.lha|*.lzh)
+ echo lha xqf "${1}" 1>&2
+ lha xqf "${1}" || die "Couldn't unpack ${1}"
+ ;;
+
+ *.a|*.deb)
+ echo ar x "${1}" 1&>2
+ ar x "${1}" 1>&2
+ ;;
+
+ *)
+ echo "Skipping unpack for ${1}"
+ ;;
+ esac
+
+}
+
+export UNPACKFROMDIR="${DISTDIR}"
+export UNPACKTODIR="${PWD}"
+
+if [[ "${1}" == "--binary" ]] ; then
+ export UNPACKFROMDIR="${PKGDIR}"
+ export UNPACKTODIR="${IMAGE}"
+ shift
+fi
+
+TAR_OPTIONS=( )
+while [[ "${1}" == --tar-option=* ]] ; do
+ TAR_OPTIONS+=( "${1#*=}" )
+ shift
+done
+
+[[ -z "$@" ]] && die "No arguments given to unpack"
+
+for x in "$@" ; do
+ x=$(echo $x )
+ echo ">>> Unpacking ${x} to ${UNPACKTODIR}"
+ [[ "${x:0:2}" == "./" ]] || x="${UNPACKFROMDIR}/${x}"
+ mkdir -p ${UNPACKTODIR}
+ cd ${UNPACKTODIR}
+ unpack_one "${x}"
+done
+
+
diff --git a/paludis/repositories/gentoo/ebuild/utils/emake b/paludis/repositories/gentoo/ebuild/utils/emake
new file mode 100755
index 0000000..57ffa4c
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/emake
@@ -0,0 +1,22 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+echo ${EMAKE_WRAPPER} ${MAKE:-make} ${MAKEOPTS} ${EXTRA_EMAKE} "$@" 1>&2
+${EMAKE_WRAPPER} ${MAKE:-make} ${MAKEOPTS} ${EXTRA_EMAKE} "$@"
+
diff --git a/paludis/repositories/gentoo/ebuild/utils/fowners b/paludis/repositories/gentoo/ebuild/utils/fowners
new file mode 100644
index 0000000..4eb208c
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/fowners
@@ -0,0 +1,24 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon fowners from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+chown "${@/#\//${D}/}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/fperms b/paludis/repositories/gentoo/ebuild/utils/fperms
new file mode 100644
index 0000000..04c5db7
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/fperms
@@ -0,0 +1,24 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon fperms from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+chmod "${@/#\//${D}/}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/getfsize b/paludis/repositories/gentoo/ebuild/utils/getfsize
new file mode 100755
index 0000000..38a271b
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/getfsize
@@ -0,0 +1,5 @@
+#!/bin/bash
+case $(uname -s) in
+ FreeBSD) stat -f '%z' "$@" ;;
+ *) stat -c '%s' "$@" ;;
+esac
diff --git a/paludis/repositories/gentoo/ebuild/utils/getfsize_TEST.bash b/paludis/repositories/gentoo/ebuild/utils/getfsize_TEST.bash
new file mode 100755
index 0000000..3688bdf
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/getfsize_TEST.bash
@@ -0,0 +1,44 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License version 2, as published by the Free Software Foundation.
+#
+# Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+
+getfsize_TEST()
+{
+ mkdir -p getfsize_TEST_dir ; test_return_code
+
+ echo -n "12345" > getfsize_TEST_dir/five
+ echo "12345" > getfsize_TEST_dir/six
+
+ ${PALUDIS_EBUILD_DIR}/utils/getfsize getfsize_TEST_dir/five >/dev/null ; test_return_code
+ ${PALUDIS_EBUILD_DIR}/utils/getfsize getfsize_TEST_dir/six >/dev/null ; test_return_code
+
+ [[ $(${PALUDIS_EBUILD_DIR}/utils/getfsize getfsize_TEST_dir/five ) == "5" ]] ; test_return_code
+ [[ $(${PALUDIS_EBUILD_DIR}/utils/getfsize getfsize_TEST_dir/six ) == "6" ]] ; test_return_code
+
+ rm -fr getfsize_TEST_dir
+}
+
+getfsize_fail_TEST()
+{
+ mkdir -p getfsize_TEST_dir ; test_return_code
+
+ ! ${PALUDIS_EBUILD_DIR}/utils/getfsize getfsize_TEST_dir/seven 2>/dev/null ; test_return_code
+
+ rm -fr getfsize_TEST_dir
+}
+
+
diff --git a/paludis/repositories/gentoo/ebuild/utils/getmtime b/paludis/repositories/gentoo/ebuild/utils/getmtime
new file mode 100755
index 0000000..88a74b2
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/getmtime
@@ -0,0 +1,5 @@
+#!/bin/bash
+case $(uname -s) in
+ FreeBSD) stat -f '%m' "$@" ;;
+ *) stat -c '%Y' "$@" ;;
+esac
diff --git a/paludis/repositories/gentoo/ebuild/utils/newbin b/paludis/repositories/gentoo/ebuild/utils/newbin
new file mode 100644
index 0000000..21792c6
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/newbin
@@ -0,0 +1,38 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon newbin from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed" >&2
+ exit 1
+fi
+
+rm -rf "${T}/${2}"
+cp "${1}" "${T}/${2}"
+dobin "${T}/${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/newconfd b/paludis/repositories/gentoo/ebuild/utils/newconfd
new file mode 100644
index 0000000..7783865
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/newconfd
@@ -0,0 +1,38 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon newconfd from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed" >&2
+ exit 1
+fi
+
+rm -rf "${T}/${2}"
+cp "${1}" "${T}/${2}"
+doconfd "${T}/${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/newdoc b/paludis/repositories/gentoo/ebuild/utils/newdoc
new file mode 100644
index 0000000..b4cb507
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/newdoc
@@ -0,0 +1,38 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon newdoc from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed" >&2
+ exit 1
+fi
+
+rm -rf "${T}/${2}"
+cp "${1}" "${T}/${2}"
+dodoc "${T}/${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/newenvd b/paludis/repositories/gentoo/ebuild/utils/newenvd
new file mode 100644
index 0000000..76f0a7f
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/newenvd
@@ -0,0 +1,38 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon newenvd from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed" >&2
+ exit 1
+fi
+
+rm -rf "${T}/${2}"
+cp "${1}" "${T}/${2}"
+doenvd "${T}/${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/newexe b/paludis/repositories/gentoo/ebuild/utils/newexe
new file mode 100644
index 0000000..9a5cb35
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/newexe
@@ -0,0 +1,38 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon newexe from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed" >&2
+ exit 1
+fi
+
+rm -rf "${T}/${2}"
+cp "${1}" "${T}/${2}"
+doexe "${T}/${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/newinitd b/paludis/repositories/gentoo/ebuild/utils/newinitd
new file mode 100644
index 0000000..01ca12b
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/newinitd
@@ -0,0 +1,38 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon newinitd from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed" >&2
+ exit 1
+fi
+
+rm -rf "${T}/${2}"
+cp "${1}" "${T}/${2}"
+doinitd "${T}/${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/newins b/paludis/repositories/gentoo/ebuild/utils/newins
new file mode 100644
index 0000000..2b692ad
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/newins
@@ -0,0 +1,38 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon newins from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed" >&2
+ exit 1
+fi
+
+rm -rf "${T}/${2}"
+cp "${1}" "${T}/${2}"
+doins "${T}/${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/newlib.a.in b/paludis/repositories/gentoo/ebuild/utils/newlib.a.in
new file mode 100644
index 0000000..415a057
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/newlib.a.in
@@ -0,0 +1,38 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon newlib.a from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed" >&2
+ exit 1
+fi
+
+rm -rf "${T}/${2}"
+cp "${1}" "${T}/${2}"
+dolib.a "${T}/${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/newlib.so.in b/paludis/repositories/gentoo/ebuild/utils/newlib.so.in
new file mode 100644
index 0000000..0701351
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/newlib.so.in
@@ -0,0 +1,38 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon newlib.so from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed" >&2
+ exit 1
+fi
+
+rm -rf "${T}/${2}"
+cp "${1}" "${T}/${2}"
+dolib.so "${T}/${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/newman b/paludis/repositories/gentoo/ebuild/utils/newman
new file mode 100644
index 0000000..0dab5fc
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/newman
@@ -0,0 +1,38 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon newman from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed" >&2
+ exit 1
+fi
+
+rm -rf "${T}/${2}"
+cp "${1}" "${T}/${2}"
+doman "${T}/${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/newsbin b/paludis/repositories/gentoo/ebuild/utils/newsbin
new file mode 100644
index 0000000..da94577
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/newsbin
@@ -0,0 +1,38 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# Based in part upon newsbin from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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 as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+export PATH="${PALUDIS_EBUILD_DIR:+${PALUDIS_EBUILD_DIR}/utils:}${PATH}"
+
+if [[ ! -d ${T} ]]; then
+ echo "${0}: \${T} not valid; aborting" >&2
+ exit 247
+fi
+
+if [[ ${#} -ne 2 ]]; then
+ echo "${0}: exactly two arguments needed" >&2
+ exit 1
+fi
+
+rm -rf "${T}/${2}"
+cp "${1}" "${T}/${2}"
+dosbin "${T}/${2}"
diff --git a/paludis/repositories/gentoo/ebuild/utils/prep.in b/paludis/repositories/gentoo/ebuild/utils/prep.in
new file mode 100644
index 0000000..fcb6495
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/prep.in
@@ -0,0 +1,21 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+#
+# This file is part of the Paludis package manager. Paludis is free software;
+# you can redistribute it and/or modify it under the terms of the GNU General
+# Public License as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+# 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
+
+ebuild_notice "qa" "Ebuilds shouldn't be calling $0 manually."
+
diff --git a/paludis/repositories/gentoo/ebuild/utils/run_test.bash b/paludis/repositories/gentoo/ebuild/utils/run_test.bash
new file mode 100644
index 0000000..1f9db4e
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/utils/run_test.bash
@@ -0,0 +1,62 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+shopt -s expand_aliases
+shopt -s extglob
+set +o posix
+
+export TEST_STATUS=
+export PALUDIS_IN_TEST_FRAMEWORK="yes"
+
+test_return_code()
+{
+ local r="$?"
+ if [[ "0" == "${r}" ]] ; then
+ echo -n "."
+ else
+ echo -n "!{retcode: ${r}}"
+ export local_test_status="fail"
+ export TEST_STATUS="fail"
+ fi
+}
+
+test_equality()
+{
+ if [[ "${1}" == "${2}" ]] ; then
+ echo -n "."
+ else
+ echo -n "!{'${1}' not equal to '${2}'}"
+ export local_test_status="fail"
+ export TEST_STATUS="fail"
+ fi
+}
+
+if test -f "$TEST_SCRIPT_DIR""${1%.bash}"_"setup.sh" ; then
+ echo ">>> setup for test ${1%.bash}"
+ if ! "$TEST_SCRIPT_DIR""${1%.bash}"_"setup.sh" ; then
+ echo ">>> exiting with error for test ${1%.bash}"
+ exit 255
+ fi
+fi
+
+echo "Test program ${1%.bash}:"
+source "${1}" || exit 200
+
+for testname in $(set | grep '_TEST *() *$' ) ; do
+ [[ ${testname/()} != ${testname} ]] && continue
+ echo -n "* ${testname%_TEST}: "
+ export local_test_status=""
+ ${testname}
+ [[ -z "$local_test_status" ]] && echo " OK" || echo " FAIL"
+done
+
+if test -f "$TEST_SCRIPT_DIR""${1%.bash}"_"cleanup.sh" ; then
+ echo ">>> cleanup for test ${1%.bash}"
+ if ! "$TEST_SCRIPT_DIR""${1%.bash}"_"cleanup.sh" ; then
+ echo ">>> exiting with error for test ${1%.bash}"
+ exit 255
+ fi
+fi
+
+[[ -z "$TEST_STATUS" ]]
+
diff --git a/paludis/repositories/gentoo/ebuild/work_around_broken_utilities.bash.in b/paludis/repositories/gentoo/ebuild/work_around_broken_utilities.bash.in
new file mode 100644
index 0000000..cb97656
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/work_around_broken_utilities.bash.in
@@ -0,0 +1,26 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+# Copyright (c) 2006 Timothy Redaelli <drizzt@gentoo.org>
+#
+# Based in part upon ebuild.sh from Portage, which is Copyright 1995-2005
+# Gentoo Foundation and distributed under the terms of the GNU General
+# Public License v2.
+#
+# 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
+
+@NEED_SED_WRAPPER_TRUE@alias sed=gsed
+@NEED_AWK_WRAPPER_TRUE@alias awk=gawk
+@NEED_MAKE_WRAPPER_TRUE@alias make=gmake
+@NEED_PATCH_WRAPPER_TRUE@alias patch=gpatch
diff --git a/paludis/repositories/gentoo/ebuild_entries.cc b/paludis/repositories/gentoo/ebuild_entries.cc
new file mode 100644
index 0000000..122f72b
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild_entries.cc
@@ -0,0 +1,532 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/repositories/gentoo/ebuild_entries.hh>
+#include <paludis/repositories/gentoo/ebuild_flat_metadata_cache.hh>
+#include <paludis/repositories/gentoo/portage_repository.hh>
+
+#include <paludis/dep_atom_flattener.hh>
+#include <paludis/ebuild.hh>
+#include <paludis/environment.hh>
+#include <paludis/portage_dep_parser.hh>
+#include <paludis/version_metadata.hh>
+#include <paludis/util/collection_concrete.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/util/tokeniser.hh>
+
+#include <fstream>
+#include <list>
+#include <set>
+
+using namespace paludis;
+
+namespace paludis
+{
+ /**
+ * Implementation data for EbuildEntries.
+ *
+ * \ingroup grpportagerepository
+ */
+ template<>
+ struct Implementation<EbuildEntries>
+ {
+ const Environment * const environment;
+ PortageRepository * const portage_repository;
+ const PortageRepositoryParams params;
+
+ std::tr1::shared_ptr<EclassMtimes> eclass_mtimes;
+ time_t master_mtime;
+
+ Implementation(const Environment * const e, PortageRepository * const p,
+ const PortageRepositoryParams & k) :
+ environment(e),
+ portage_repository(p),
+ params(k),
+ eclass_mtimes(new EclassMtimes(k.eclassdirs)),
+ master_mtime(0)
+ {
+ FSEntry m(k.location / "metadata" / "timestamp");
+ if (m.exists())
+ master_mtime = m.mtime();
+ }
+ };
+}
+
+EbuildEntries::EbuildEntries(
+ const Environment * const e, PortageRepository * const p, const PortageRepositoryParams & k) :
+ PortageRepositoryEntries(".ebuild"),
+ PrivateImplementationPattern<EbuildEntries>(new
+ Implementation<EbuildEntries>(e, p, k))
+{
+}
+
+EbuildEntries::~EbuildEntries()
+{
+}
+
+std::tr1::shared_ptr<VersionMetadata>
+EbuildEntries::generate_version_metadata(const QualifiedPackageName & q,
+ const VersionSpec & v) const
+{
+ Context context("When generating version metadata for '" + stringify(q) + "-" + stringify(v) + "':");
+
+ std::tr1::shared_ptr<EbuildVersionMetadata> result(new EbuildVersionMetadata);
+
+ FSEntry ebuild_file(_imp->params.location / stringify(q.category) /
+ stringify(q.package) / (stringify(q.package) + "-" + stringify(v) + ".ebuild"));
+
+ FSEntry cache_file(_imp->params.cache);
+ cache_file /= stringify(q.category);
+ cache_file /= stringify(q.package) + "-" + stringify(v);
+
+ FSEntry write_cache_file(_imp->params.write_cache);
+ write_cache_file /= stringify(_imp->portage_repository->name());
+ write_cache_file /= stringify(q.category);
+ write_cache_file /= stringify(q.package) + "-" + stringify(v);
+
+ bool ok(false);
+ if (_imp->params.cache.basename() != "empty")
+ {
+
+ EbuildFlatMetadataCache metadata_cache(cache_file, ebuild_file, _imp->master_mtime,
+ _imp->eclass_mtimes, false);
+ if (metadata_cache.load(result))
+ ok = true;
+ }
+
+ if ((! ok) && _imp->params.write_cache.basename() != "empty")
+ {
+ EbuildFlatMetadataCache write_metadata_cache(write_cache_file, ebuild_file, _imp->master_mtime,
+ _imp->eclass_mtimes, true);
+ if (write_metadata_cache.load(result))
+ ok = true;
+ else if (write_cache_file.exists())
+ write_cache_file.unlink();
+ }
+
+ if (! ok)
+ {
+ if (_imp->params.cache.basename() != "empty")
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "No usable cache entry for '" + stringify(q) +
+ "-" + stringify(v) + "' in '" + stringify(_imp->portage_repository->name()) + "'");
+
+ PackageDatabaseEntry e(q, v, _imp->portage_repository->name());
+ EbuildMetadataCommand cmd(EbuildCommandParams::create()
+ .environment(_imp->environment)
+ .db_entry(&e)
+ .ebuild_dir(_imp->params.location / stringify(q.category) /
+ stringify(q.package))
+ .files_dir(_imp->params.location / stringify(q.category) /
+ stringify(q.package) / "files")
+ .eclassdirs(_imp->params.eclassdirs)
+ .portdir(_imp->params.master_repository ? _imp->params.master_repository->params().location :
+ _imp->params.location)
+ .distdir(_imp->params.distdir)
+ .buildroot(_imp->params.buildroot));
+
+ if (! cmd())
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "No usable metadata for '" + stringify(q)
+ + "-" + stringify(v) + "' in '" + stringify(_imp->portage_repository->name()) + "'");
+
+ if (0 == ((result = cmd.metadata())))
+ throw InternalError(PALUDIS_HERE, "cmd.metadata() is zero pointer???");
+
+ if (_imp->params.write_cache.basename() != "empty" && result->eapi != "UNKNOWN")
+ {
+ EbuildFlatMetadataCache metadata_cache(write_cache_file, ebuild_file, _imp->master_mtime,
+ _imp->eclass_mtimes, false);
+ metadata_cache.save(result);
+ }
+ }
+
+ return result;
+}
+
+namespace
+{
+ class AAFinder :
+ private InstantiationPolicy<AAFinder, instantiation_method::NonCopyableTag>,
+ protected DepAtomVisitorTypes::ConstVisitor
+ {
+ private:
+ mutable std::list<const StringDepAtom *> _atoms;
+
+ protected:
+ void visit(const AllDepAtom * a)
+ {
+ std::for_each(a->begin(), a->end(), accept_visitor(
+ static_cast<DepAtomVisitorTypes::ConstVisitor *>(this)));
+ }
+
+ void visit(const AnyDepAtom *) PALUDIS_ATTRIBUTE((noreturn))
+ {
+ throw InternalError(PALUDIS_HERE, "Found unexpected AnyDepAtom");
+ }
+
+ void visit(const UseDepAtom * a)
+ {
+ std::for_each(a->begin(), a->end(), accept_visitor(
+ static_cast<DepAtomVisitorTypes::ConstVisitor *>(this)));
+ }
+
+ void visit(const PlainTextDepAtom * a)
+ {
+ _atoms.push_back(a);
+ }
+
+ void visit(const PackageDepAtom * a)
+ {
+ _atoms.push_back(a);
+ }
+
+ void visit(const BlockDepAtom * a)
+ {
+ _atoms.push_back(a);
+ }
+
+ public:
+ AAFinder(const std::tr1::shared_ptr<const DepAtom> a)
+ {
+ a->accept(static_cast<DepAtomVisitorTypes::ConstVisitor *>(this));
+ }
+
+ typedef std::list<const StringDepAtom *>::const_iterator Iterator;
+
+ Iterator begin()
+ {
+ return _atoms.begin();
+ }
+
+ Iterator end() const
+ {
+ return _atoms.end();
+ }
+ };
+
+}
+
+void
+EbuildEntries::install(const QualifiedPackageName & q, const VersionSpec & v,
+ const InstallOptions & o, std::tr1::shared_ptr<const PortageRepositoryProfile> p) const
+{
+ if (! _imp->portage_repository->has_version(q, v))
+ {
+ throw PackageInstallActionError("Can't install '" + stringify(q) + "-"
+ + stringify(v) + "' since has_version failed");
+ }
+
+ std::tr1::shared_ptr<const VersionMetadata> metadata(_imp->portage_repository->version_metadata(q, v));
+
+ PackageDatabaseEntry e(q, v, _imp->portage_repository->name());
+
+ bool fetch_restrict(false), no_mirror(false);
+ {
+ std::list<std::string> restricts;
+ WhitespaceTokeniser::get_instance()->tokenise(
+ metadata->ebuild_interface->restrict_string, std::back_inserter(restricts));
+ fetch_restrict = (restricts.end() != std::find(restricts.begin(), restricts.end(), "fetch")) ||
+ (restricts.end() != std::find(restricts.begin(), restricts.end(), "nofetch"));
+ no_mirror = (restricts.end() != std::find(restricts.begin(), restricts.end(), "mirror")) ||
+ (restricts.end() != std::find(restricts.begin(), restricts.end(), "nomirror"));
+ }
+
+ std::string archives, all_archives, flat_src_uri;
+ {
+ std::set<std::string> already_in_archives;
+
+ /* make A and FLAT_SRC_URI */
+ std::tr1::shared_ptr<const DepAtom> f_atom(PortageDepParser::parse(metadata->ebuild_interface->src_uri,
+ PortageDepParserPolicy<PlainTextDepAtom, false>::get_instance()));
+ DepAtomFlattener f(_imp->params.environment, &e, f_atom);
+
+ for (DepAtomFlattener::Iterator ff(f.begin()), ff_end(f.end()) ; ff != ff_end ; ++ff)
+ {
+ std::string::size_type pos((*ff)->text().rfind('/'));
+ if (std::string::npos == pos)
+ {
+ if (already_in_archives.end() == already_in_archives.find((*ff)->text()))
+ {
+ archives.append((*ff)->text());
+ already_in_archives.insert((*ff)->text());
+ }
+ }
+ else
+ {
+ if (already_in_archives.end() == already_in_archives.find((*ff)->text().substr(pos + 1)))
+ {
+ archives.append((*ff)->text().substr(pos + 1));
+ already_in_archives.insert((*ff)->text().substr(pos + 1));
+ }
+ }
+ archives.append(" ");
+
+ /* add * mirror entries */
+ for (Environment::MirrorIterator
+ m(_imp->params.environment->begin_mirrors("*")),
+ m_end(_imp->params.environment->end_mirrors("*")) ;
+ m != m_end ; ++m)
+ flat_src_uri.append(m->second + "/" + (*ff)->text().substr(pos + 1) + " ");
+
+ if (0 == (*ff)->text().compare(0, 9, "mirror://"))
+ {
+ std::string mirror((*ff)->text().substr(9));
+ std::string::size_type spos(mirror.find('/'));
+
+ if (std::string::npos == spos)
+ throw PackageInstallActionError("Can't install '" + stringify(q) + "-"
+ + stringify(v) + "' since SRC_URI is broken");
+
+ if (! _imp->portage_repository->is_mirror(mirror.substr(0, spos)) &&
+ _imp->params.environment->begin_mirrors(mirror.substr(0, spos)) ==
+ _imp->params.environment->end_mirrors(mirror.substr(0, spos)))
+ throw PackageInstallActionError("Can't install '" + stringify(q) + "-"
+ + stringify(v) + "' since SRC_URI references unknown mirror:// '" +
+ mirror.substr(0, spos) + "'");
+
+ for (Environment::MirrorIterator
+ m(_imp->params.environment->begin_mirrors(mirror.substr(0, spos))),
+ m_end(_imp->params.environment->end_mirrors(mirror.substr(0, spos))) ;
+ m != m_end ; ++m)
+ flat_src_uri.append(m->second + "/" + mirror.substr(spos + 1) + " ");
+
+ for (RepositoryMirrorsInterface::MirrorsIterator
+ m(_imp->portage_repository->begin_mirrors(mirror.substr(0, spos))),
+ m_end(_imp->portage_repository->end_mirrors(mirror.substr(0, spos))) ;
+ m != m_end ; ++m)
+ flat_src_uri.append(m->second + "/" + mirror.substr(spos + 1) + " ");
+ }
+ else
+ flat_src_uri.append((*ff)->text());
+ flat_src_uri.append(" ");
+
+ /* add mirror://gentoo/ entries */
+ std::string master_mirror(strip_trailing_string(stringify(_imp->portage_repository->name()), "x-"));
+ if (! no_mirror && _imp->portage_repository->is_mirror(master_mirror))
+ {
+ for (Environment::MirrorIterator
+ m(_imp->params.environment->begin_mirrors(master_mirror)),
+ m_end(_imp->params.environment->end_mirrors(master_mirror)) ;
+ m != m_end ; ++m)
+ flat_src_uri.append(m->second + "/" + (*ff)->text().substr(pos + 1) + " ");
+
+ for (RepositoryMirrorsInterface::MirrorsIterator
+ m(_imp->portage_repository->begin_mirrors(master_mirror)),
+ m_end(_imp->portage_repository->end_mirrors(master_mirror)) ;
+ m != m_end ; ++m)
+ flat_src_uri.append(m->second + "/" + (*ff)->text().substr(pos + 1) + " ");
+ }
+ }
+
+ /* make AA */
+ std::tr1::shared_ptr<const DepAtom> g_atom(PortageDepParser::parse(
+ metadata->ebuild_interface->src_uri,
+ PortageDepParserPolicy<PlainTextDepAtom, false>::get_instance()));
+ AAFinder g(g_atom);
+ std::set<std::string> already_in_all_archives;
+
+ for (AAFinder::Iterator gg(g.begin()), gg_end(g.end()) ; gg != gg_end ; ++gg)
+ {
+ std::string::size_type pos((*gg)->text().rfind('/'));
+ if (std::string::npos == pos)
+ {
+ if (already_in_all_archives.end() == already_in_all_archives.find((*gg)->text()))
+ {
+ all_archives.append((*gg)->text());
+ already_in_all_archives.insert((*gg)->text());
+ }
+ }
+ else
+ {
+ if (already_in_all_archives.end() == already_in_all_archives.find((*gg)->text().substr(pos + 1)))
+ {
+ all_archives.append((*gg)->text().substr(pos + 1));
+ already_in_all_archives.insert((*gg)->text().substr(pos + 1));
+ }
+ }
+ all_archives.append(" ");
+ }
+ }
+
+ /* Strip trailing space. Some ebuilds rely upon this. From kde-meta.eclass:
+ * [[ -n ${A/${TARBALL}/} ]] && unpack ${A/${TARBALL}/}
+ * Rather annoying.
+ */
+ archives = strip_trailing(archives, " ");
+ all_archives = strip_trailing(all_archives, " ");
+
+ /* make use */
+ std::string use;
+ {
+ std::set<UseFlagName> iuse;
+ WhitespaceTokeniser::get_instance()->tokenise(metadata->ebuild_interface->
+ iuse, create_inserter<UseFlagName>(std::inserter(iuse, iuse.begin())));
+ for (std::set<UseFlagName>::const_iterator iuse_it(iuse.begin()), iuse_end(iuse.end()) ;
+ iuse_it != iuse_end; ++iuse_it)
+ if (_imp->params.environment->query_use(*iuse_it, &e))
+ use += (*iuse_it).data() + " ";
+ }
+
+ use += p->environment_variable("ARCH") + " ";
+
+ /* add expand to use (iuse isn't reliable for use_expand things), and make the expand
+ * environment variables */
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > expand_vars(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ for (PortageRepositoryProfile::UseExpandIterator x(p->begin_use_expand()),
+ x_end(p->end_use_expand()) ; x != x_end ; ++x)
+ {
+ std::string lower_x;
+ std::transform(x->data().begin(), x->data().end(), std::back_inserter(lower_x), &::tolower);
+
+ expand_vars->insert(stringify(*x), "");
+
+ /* possible values from profile */
+ std::set<UseFlagName> possible_values;
+ WhitespaceTokeniser::get_instance()->tokenise(p->environment_variable(stringify(*x)),
+ create_inserter<UseFlagName>(std::inserter(possible_values, possible_values.end())));
+
+ /* possible values from environment */
+ std::tr1::shared_ptr<const UseFlagNameCollection> possible_values_from_env(_imp->params.environment->
+ known_use_expand_names(*x, &e));
+ for (UseFlagNameCollection::Iterator i(possible_values_from_env->begin()),
+ i_end(possible_values_from_env->end()) ; i != i_end ; ++i)
+ possible_values.insert(UseFlagName(stringify(*i).substr(lower_x.length() + 1)));
+
+ for (std::set<UseFlagName>::const_iterator u(possible_values.begin()), u_end(possible_values.end()) ;
+ u != u_end ; ++u)
+ {
+ if (! _imp->params.environment->query_use(UseFlagName(lower_x + "_" + stringify(*u)), &e))
+ continue;
+
+ use.append(lower_x + "_" + stringify(*u) + " ");
+
+ std::string value;
+ AssociativeCollection<std::string, std::string>::Iterator i(expand_vars->find(stringify(*x)));
+ if (expand_vars->end() != i)
+ {
+ value = i->second;
+ if (! value.empty())
+ value.append(" ");
+ expand_vars->erase(i);
+ }
+ value.append(stringify(*u));
+ expand_vars->insert(stringify(*x), value);
+ }
+ }
+
+ EbuildFetchCommand fetch_cmd(EbuildCommandParams::create()
+ .environment(_imp->params.environment)
+ .db_entry(&e)
+ .ebuild_dir(_imp->params.location / stringify(q.category) /
+ stringify(q.package))
+ .files_dir(_imp->params.location / stringify(q.category) /
+ stringify(q.package) / "files")
+ .eclassdirs(_imp->params.eclassdirs)
+ .portdir(_imp->params.master_repository ? _imp->params.master_repository->params().location :
+ _imp->params.location)
+ .distdir(_imp->params.distdir)
+ .buildroot(_imp->params.buildroot),
+
+ EbuildFetchCommandParams::create()
+ .a(archives)
+ .aa(all_archives)
+ .use(use)
+ .use_expand(join(p->begin_use_expand(), p->end_use_expand(), " "))
+ .expand_vars(expand_vars)
+ .flat_src_uri(flat_src_uri)
+ .root(o.destination->installed_interface ?
+ stringify(o.destination->installed_interface->root()) : "/")
+ .profiles(_imp->params.profiles)
+ .no_fetch(fetch_restrict)
+ .safe_resume(o.safe_resume));
+
+ fetch_cmd();
+
+ if (o.fetch_only)
+ return;
+
+ EbuildInstallCommand install_cmd(EbuildCommandParams::create()
+ .environment(_imp->params.environment)
+ .db_entry(&e)
+ .ebuild_dir(_imp->params.location / stringify(q.category) /
+ stringify(q.package))
+ .files_dir(_imp->params.location / stringify(q.category) /
+ stringify(q.package) / "files")
+ .eclassdirs(_imp->params.eclassdirs)
+ .portdir(_imp->params.master_repository ? _imp->params.master_repository->params().location :
+ _imp->params.location)
+ .distdir(_imp->params.distdir)
+ .buildroot(_imp->params.buildroot),
+
+ EbuildInstallCommandParams::create()
+ .use(use)
+ .a(archives)
+ .aa(all_archives)
+ .use_expand(join(p->begin_use_expand(), p->end_use_expand(), " "))
+ .expand_vars(expand_vars)
+ .root(o.destination->installed_interface ?
+ stringify(o.destination->installed_interface->root()) : "/")
+ .profiles(_imp->params.profiles)
+ .disable_cfgpro(o.no_config_protect)
+ .debug_build(o.debug_build)
+ .slot(SlotName(metadata->slot)));
+
+ install_cmd();
+}
+
+std::string
+EbuildEntries::get_environment_variable(const QualifiedPackageName & q,
+ const VersionSpec & v, const std::string & var,
+ std::tr1::shared_ptr<const PortageRepositoryProfile>) const
+{
+ PackageDatabaseEntry for_package(q, v, _imp->portage_repository->name());
+
+ EbuildVariableCommand cmd(EbuildCommandParams::create()
+ .environment(_imp->params.environment)
+ .db_entry(&for_package)
+ .ebuild_dir(_imp->params.location / stringify(q.category) /
+ stringify(q.package))
+ .files_dir(_imp->params.location / stringify(q.category) /
+ stringify(q.package) / "files")
+ .eclassdirs(_imp->params.eclassdirs)
+ .portdir(_imp->params.master_repository ? _imp->params.master_repository->params().location :
+ _imp->params.location)
+ .distdir(_imp->params.distdir)
+ .buildroot(_imp->params.buildroot),
+
+ var);
+
+ if (! cmd())
+ throw EnvironmentVariableActionError("Couldn't get environment variable '" +
+ stringify(var) + "' for package '" + stringify(for_package) + "'");
+
+ return cmd.result();
+}
+
+std::tr1::shared_ptr<PortageRepositoryEntries>
+EbuildEntries::make_ebuild_entries(
+ const Environment * const e, PortageRepository * const r, const PortageRepositoryParams & p)
+{
+ return std::tr1::shared_ptr<PortageRepositoryEntries>(new EbuildEntries(e, r, p));
+}
+
diff --git a/paludis/repositories/gentoo/ebuild_entries.hh b/paludis/repositories/gentoo/ebuild_entries.hh
new file mode 100644
index 0000000..7755081
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild_entries.hh
@@ -0,0 +1,70 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_EBUILD_METADATA_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_EBUILD_METADATA_HH 1
+
+#include <paludis/repositories/gentoo/portage_repository_entries.hh>
+#include <paludis/repositories/gentoo/portage_repository_params.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+
+/** \file
+ * Declaration for the EbuildEntries class.
+ *
+ * \ingroup grpportagerepository
+ */
+
+namespace paludis
+{
+ class FSEntry;
+ class PortageRepository;
+
+ /**
+ * PortageRepositoryEntries handler for ebuilds.
+ *
+ * \ingroup grpportagerepository
+ */
+ class PALUDIS_VISIBLE EbuildEntries :
+ public PortageRepositoryEntries,
+ private PrivateImplementationPattern<EbuildEntries>
+ {
+ public:
+ static std::tr1::shared_ptr<PortageRepositoryEntries>
+ make_ebuild_entries(const Environment * const,
+ PortageRepository * const, const PortageRepositoryParams &);
+
+ EbuildEntries(const Environment * const,
+ PortageRepository * const portage_repository,
+ const PortageRepositoryParams &);
+
+ virtual ~EbuildEntries();
+
+ virtual std::tr1::shared_ptr<VersionMetadata> generate_version_metadata(const QualifiedPackageName &,
+ const VersionSpec &) const;
+
+ virtual std::string get_environment_variable(const QualifiedPackageName &,
+ const VersionSpec &, const std::string & var,
+ std::tr1::shared_ptr<const PortageRepositoryProfile>) const;
+
+ virtual void install(const QualifiedPackageName &, const VersionSpec &,
+ const InstallOptions &, std::tr1::shared_ptr<const PortageRepositoryProfile>) const;
+ };
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/ebuild_flat_metadata_cache.cc b/paludis/repositories/gentoo/ebuild_flat_metadata_cache.cc
new file mode 100644
index 0000000..e5873e4
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild_flat_metadata_cache.cc
@@ -0,0 +1,147 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ebuild_flat_metadata_cache.hh"
+#include <paludis/util/log.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/join.hh>
+#include <fstream>
+#include <set>
+#include <list>
+
+using namespace paludis;
+
+EbuildFlatMetadataCache::EbuildFlatMetadataCache(const FSEntry & f,
+ const FSEntry & e, time_t t, std::tr1::shared_ptr<const EclassMtimes> m, bool s) :
+ _filename(f),
+ _ebuild(e),
+ _master_mtime(t),
+ _eclass_mtimes(m),
+ _silent(s)
+{
+}
+
+bool
+EbuildFlatMetadataCache::load(std::tr1::shared_ptr<EbuildVersionMetadata> result)
+{
+ Context context("When loading version metadata to '" + stringify(_filename) + "':");
+
+ std::ifstream cache(stringify(_filename).c_str());
+ std::string line;
+
+ if (cache)
+ {
+ std::getline(cache, line); result->build_depend_string = line;
+ std::getline(cache, line); result->run_depend_string = line;
+ std::getline(cache, line); result->slot = SlotName(line);
+ std::getline(cache, line); result->src_uri = line;
+ std::getline(cache, line); result->restrict_string = line;
+ std::getline(cache, line); result->homepage = line;
+ std::getline(cache, line); result->license_string = line;
+ std::getline(cache, line); result->description = line;
+ std::getline(cache, line); result->keywords = line;
+ std::getline(cache, line); result->inherited = line;
+ std::getline(cache, line); result->iuse = line;
+ std::getline(cache, line);
+ std::getline(cache, line); result->post_depend_string = line;
+ std::getline(cache, line); result->provide_string = line;
+ std::getline(cache, line); result->eapi = line;
+
+ // check mtimes
+ time_t cache_time(std::max(_master_mtime, _filename.mtime()));
+ bool ok = true;
+
+ if (_ebuild.mtime() > cache_time)
+ ok = false;
+ else
+ {
+ std::set<std::string> inherits;
+ WhitespaceTokeniser::get_instance()->tokenise(
+ stringify(result->inherited),
+ std::inserter(inherits, inherits.end()));
+
+ for (std::set<std::string>::const_iterator i(inherits.begin()),
+ i_end(inherits.end()) ; i != i_end ; ++i)
+ if (_eclass_mtimes->mtime(*i) > cache_time)
+ {
+ ok = false;
+ break;
+ }
+ }
+
+ if (! ok)
+ Log::get_instance()->message(ll_warning, lc_no_context, "Stale cache file at '"
+ + stringify(_filename) + "'");
+
+ return ok;
+ }
+ else
+ {
+ Log::get_instance()->message(_silent ? ll_debug : ll_warning, lc_no_context,
+ "Couldn't use the cache file at '" + stringify(_filename) + "'");
+ return false;
+ }
+}
+
+namespace
+{
+ template <typename T_>
+ std::string normalise(const T_ & s)
+ {
+ std::list<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(stringify(s), std::back_inserter(tokens));
+ return join(tokens.begin(), tokens.end(), " ");
+ }
+}
+
+void
+EbuildFlatMetadataCache::save(std::tr1::shared_ptr<const EbuildVersionMetadata> v)
+{
+ Context context("When saving version metadata to '" + stringify(_filename) + "':");
+
+ _filename.dirname().dirname().mkdir();
+ _filename.dirname().mkdir();
+ std::ofstream cache(stringify(_filename).c_str());
+
+ if (cache)
+ {
+ cache << normalise(v->build_depend_string) << std::endl;
+ cache << normalise(v->run_depend_string) << std::endl;
+ cache << normalise(v->slot) << std::endl;
+ cache << normalise(v->src_uri) << std::endl;
+ cache << normalise(v->restrict_string) << std::endl;
+ cache << normalise(v->homepage) << std::endl;
+ cache << normalise(v->license_string) << std::endl;
+ cache << normalise(v->description) << std::endl;
+ cache << normalise(v->keywords) << std::endl;
+ cache << normalise(v->inherited) << std::endl;
+ cache << normalise(v->iuse) << std::endl;
+ cache << std::endl;
+ cache << normalise(v->post_depend_string) << std::endl;
+ cache << normalise(v->provide_string) << std::endl;
+ cache << normalise(v->eapi) << std::endl;
+ }
+ else
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "Couldn't write cache file to '" + stringify(_filename) + "'");
+ }
+
+}
+
diff --git a/paludis/repositories/gentoo/ebuild_flat_metadata_cache.hh b/paludis/repositories/gentoo/ebuild_flat_metadata_cache.hh
new file mode 100644
index 0000000..3310eed
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild_flat_metadata_cache.hh
@@ -0,0 +1,67 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_EBUILD_FLAT_METADATA_CACHE_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_EBUILD_FLAT_METADATA_CACHE_HH 1
+
+#include <paludis/ebuild.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/version_metadata.hh>
+#include <paludis/repositories/gentoo/eclass_mtimes.hh>
+
+namespace paludis
+{
+ /**
+ * Implements flat file metadata cache handling for a PortageRepository
+ * using EbuildEntries.
+ *
+ * \see EbuildEntries
+ * \see PortageRepository
+ * \ingroup grpportagerepository
+ * \nosubgrouping
+ */
+ class EbuildFlatMetadataCache
+ {
+ private:
+ const FSEntry & _filename;
+ const FSEntry & _ebuild;
+ time_t _master_mtime;
+ std::tr1::shared_ptr<const EclassMtimes> _eclass_mtimes;
+ bool _silent;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ EbuildFlatMetadataCache(const FSEntry & filename, const FSEntry & ebuild,
+ time_t master_mtime, std::tr1::shared_ptr<const EclassMtimes> eclass_mtimes, bool silent);
+
+ ///\}
+
+ ///\name Cache operations
+ ///\{
+
+ bool load(std::tr1::shared_ptr<EbuildVersionMetadata>);
+ void save(std::tr1::shared_ptr<const EbuildVersionMetadata>);
+
+ ///\}
+ };
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/eclass_mtimes.cc b/paludis/repositories/gentoo/eclass_mtimes.cc
new file mode 100644
index 0000000..abc7e20
--- /dev/null
+++ b/paludis/repositories/gentoo/eclass_mtimes.cc
@@ -0,0 +1,68 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "eclass_mtimes.hh"
+#include <paludis/hashed_containers.hh>
+
+using namespace paludis;
+
+namespace paludis
+{
+ template<>
+ struct Implementation<EclassMtimes>
+ {
+ std::tr1::shared_ptr<const FSEntryCollection> eclass_dirs;
+ mutable MakeHashedMap<std::string, time_t>::Type eclass_mtimes;
+
+ Implementation(std::tr1::shared_ptr<const FSEntryCollection> d) :
+ eclass_dirs(d)
+ {
+ }
+ };
+}
+
+EclassMtimes::EclassMtimes(std::tr1::shared_ptr<const FSEntryCollection> d) :
+ PrivateImplementationPattern<EclassMtimes>(new Implementation<EclassMtimes>(d))
+{
+}
+
+EclassMtimes::~EclassMtimes()
+{
+}
+
+time_t
+EclassMtimes::mtime(const std::string & e) const
+{
+ MakeHashedMap<std::string, time_t>::Type::const_iterator i(_imp->eclass_mtimes.find(e));
+ if (i != _imp->eclass_mtimes.end())
+ return i->second;
+
+ time_t r(0);
+ for (FSEntryCollection::Iterator d(_imp->eclass_dirs->begin()),
+ d_end(_imp->eclass_dirs->end()) ; d != d_end ; ++d)
+ {
+ FSEntry f(*d / (e + ".eclass"));
+ if (f.exists())
+ r = std::max(r, f.mtime());
+ }
+
+ _imp->eclass_mtimes.insert(std::make_pair(e, r));
+ return r;
+}
+
diff --git a/paludis/repositories/gentoo/eclass_mtimes.hh b/paludis/repositories/gentoo/eclass_mtimes.hh
new file mode 100644
index 0000000..1bfdc46
--- /dev/null
+++ b/paludis/repositories/gentoo/eclass_mtimes.hh
@@ -0,0 +1,55 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_ECLASS_MTIMES_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_ECLASS_MTIMES_HH 1
+
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/collection.hh>
+
+namespace paludis
+{
+ /**
+ * Holds an eclass mtimes cache for a PortageRepository.
+ *
+ * \see PortageRepository
+ * \ingroup grpportagerepository
+ * \nosubgrouping
+ */
+ class EclassMtimes :
+ private PrivateImplementationPattern<EclassMtimes>
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ EclassMtimes(std::tr1::shared_ptr<const FSEntryCollection>);
+ ~EclassMtimes();
+
+ ///\}
+
+ /**
+ * Fetch the mtime for a given eclass.
+ */
+ time_t mtime(const std::string &) const;
+ };
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/glsa.cc b/paludis/repositories/gentoo/glsa.cc
new file mode 100644
index 0000000..28ddd51
--- /dev/null
+++ b/paludis/repositories/gentoo/glsa.cc
@@ -0,0 +1,251 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "glsa.hh"
+#include <paludis/util/iterator.hh>
+#include <paludis/util/stringify.hh>
+#include <list>
+#include <dlfcn.h>
+#include <stdint.h>
+#include "config.h"
+
+#define STUPID_CAST(type, val) reinterpret_cast<type>(reinterpret_cast<uintptr_t>(val))
+
+using namespace paludis;
+
+#include "glsa-sr.cc"
+
+#ifdef MONOLITHIC
+# include <paludis/repositories/portage/xml_things.hh>
+#endif
+
+namespace paludis
+{
+ template<>
+ struct Implementation<GLSAPackage>
+ {
+ QualifiedPackageName name;
+ std::list<UseFlagName> archs;
+ std::list<GLSARange> unaffected;
+ std::list<GLSARange> vulnerable;
+
+ Implementation(const QualifiedPackageName & n) :
+ name(n)
+ {
+ }
+ };
+
+ template<>
+ struct Implementation<GLSA>
+ {
+ std::string id;
+ std::string title;
+ std::list<std::tr1::shared_ptr<const GLSAPackage> > packages;
+ };
+}
+
+GLSAPackage::GLSAPackage(const QualifiedPackageName & n) :
+ PrivateImplementationPattern<GLSAPackage>(new Implementation<GLSAPackage>(n))
+{
+}
+
+GLSAPackage::~GLSAPackage()
+{
+}
+
+GLSAPackage::ArchsIterator
+GLSAPackage::begin_archs() const
+{
+ return ArchsIterator(_imp->archs.begin());
+}
+
+GLSAPackage::ArchsIterator
+GLSAPackage::end_archs() const
+{
+ return ArchsIterator(_imp->archs.end());
+}
+
+void
+GLSAPackage::add_arch(const UseFlagName & n)
+{
+ _imp->archs.push_back(n);
+}
+
+GLSAPackage::RangesIterator
+GLSAPackage::begin_unaffected() const
+{
+ return RangesIterator(_imp->unaffected.begin());
+}
+
+GLSAPackage::RangesIterator
+GLSAPackage::end_unaffected() const
+{
+ return RangesIterator(_imp->unaffected.end());
+}
+
+GLSAPackage::RangesIterator
+GLSAPackage::begin_vulnerable() const
+{
+ return RangesIterator(_imp->vulnerable.begin());
+}
+
+GLSAPackage::RangesIterator
+GLSAPackage::end_vulnerable() const
+{
+ return RangesIterator(_imp->vulnerable.end());
+}
+
+void
+GLSAPackage::add_unaffected(const GLSARange & r)
+{
+ _imp->unaffected.push_back(r);
+}
+
+void
+GLSAPackage::add_vulnerable(const GLSARange & r)
+{
+ _imp->vulnerable.push_back(r);
+}
+
+QualifiedPackageName
+GLSAPackage::name() const
+{
+ return _imp->name;
+}
+
+GLSA::GLSA() :
+ PrivateImplementationPattern<GLSA>(new Implementation<GLSA>)
+{
+}
+
+GLSA::~GLSA()
+{
+}
+
+GLSA::PackagesIterator
+GLSA::begin_packages() const
+{
+ return PackagesIterator(indirect_iterator<const GLSAPackage>(_imp->packages.begin()));
+}
+
+GLSA::PackagesIterator
+GLSA::end_packages() const
+{
+ return PackagesIterator(indirect_iterator<const GLSAPackage>(_imp->packages.end()));
+}
+
+void
+GLSA::add_package(std::tr1::shared_ptr<const GLSAPackage> p)
+{
+ _imp->packages.push_back(p);
+}
+
+void
+GLSA::set_id(const std::string & s)
+{
+ _imp->id = s;
+}
+
+void
+GLSA::set_title(const std::string & s)
+{
+ _imp->title = s;
+}
+
+std::string
+GLSA::id() const
+{
+ return _imp->id;
+}
+
+std::string
+GLSA::title() const
+{
+ return _imp->title;
+}
+
+#ifndef MONOLITHIC
+
+namespace
+{
+ struct LibXMLHandle
+ {
+ void * handle;
+ std::tr1::shared_ptr<GLSA> (* create_glsa_from_xml_file_handle)(const std::string &);
+
+ LibXMLHandle() :
+ handle(0),
+ create_glsa_from_xml_file_handle(0)
+ {
+ }
+
+ ~LibXMLHandle()
+ {
+ if (0 != handle)
+ dlclose(handle);
+ }
+
+ } libxmlhandle;
+}
+
+#endif
+
+std::tr1::shared_ptr<GLSA>
+GLSA::create_from_xml_file(const std::string & filename)
+{
+#if ENABLE_GLSA
+# ifdef MONOLITHIC
+
+# else
+ if (0 == libxmlhandle.handle)
+ libxmlhandle.handle = dlopen("libpaludisgentoorepositoryxmlthings.so",
+ RTLD_NOW | RTLD_GLOBAL);
+ if (0 == libxmlhandle.handle)
+ throw NotAvailableError("Cannot create GLSA from XML file '" + filename + "' due to error '"
+ + stringify(dlerror()) + "' when dlopen(libpaludisgentoorepositoryxmlthings.so)");
+
+ if (0 == libxmlhandle.create_glsa_from_xml_file_handle)
+ libxmlhandle.create_glsa_from_xml_file_handle = STUPID_CAST(std::tr1::shared_ptr<GLSA> (*)(const std::string &),
+ dlsym(libxmlhandle.handle, "create_glsa_from_xml_file"));
+ if (0 == libxmlhandle.create_glsa_from_xml_file_handle)
+ throw NotAvailableError("Cannot create GLSA from XML file '" + filename + "' due to error '"
+ + stringify(dlerror()) + "' when dlsym(libpaludisgentoorepositoryxmlthings.so, create_glsa_from_xml_file)");
+
+# endif
+#else
+# ifndef MONOLITHIC
+ /* avoid noreturn warning */
+ if (0 == libxmlhandle.handle)
+ throw NotAvailableError("Cannot create GLSA from XML file '" + filename + "' because Paludis was built "
+ "without GLSA support");
+# endif
+#endif
+
+#ifdef MONOLITHIC
+ return create_glsa_from_xml_file(filename);
+#else
+ return (*libxmlhandle.create_glsa_from_xml_file_handle)(filename);
+#endif
+}
+
+GLSAError::GLSAError(const std::string & msg, const std::string & filename) throw () :
+ ConfigurationError("GLSA error: " + msg + (filename.empty() ? "" : " in file " + filename))
+{
+}
+
diff --git a/paludis/repositories/gentoo/glsa.hh b/paludis/repositories/gentoo/glsa.hh
new file mode 100644
index 0000000..69e7a57
--- /dev/null
+++ b/paludis/repositories/gentoo/glsa.hh
@@ -0,0 +1,113 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_GLSA_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_GLSA_HH 1
+
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/sr.hh>
+#include <paludis/name.hh>
+#include <paludis/version_spec.hh>
+#include <libwrapiter/libwrapiter_forward_iterator.hh>
+
+#include <string>
+
+namespace paludis
+{
+
+#include <paludis/repositories/gentoo/glsa-sr.hh>
+
+ /**
+ * Thrown if a bad GLSA is found.
+ *
+ * \ingroup grpexceptions
+ * \nosubgrouping
+ */
+ class PALUDIS_VISIBLE GLSAError :
+ public ConfigurationError
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ GLSAError(const std::string & message,
+ const std::string & filename = "") throw ();
+
+ ///\}
+ };
+
+ /**
+ * Represents a package entry in a GLSA.
+ *
+ * \see GLSA
+ * \ingroup grpportagerepository
+ * \nosubgrouping
+ */
+ class PALUDIS_VISIBLE GLSAPackage :
+ private PrivateImplementationPattern<GLSAPackage>
+ {
+ public:
+ GLSAPackage(const QualifiedPackageName & name);
+ ~GLSAPackage();
+
+ typedef libwrapiter::ForwardIterator<GLSAPackage, const UseFlagName> ArchsIterator;
+ ArchsIterator begin_archs() const;
+ ArchsIterator end_archs() const;
+ void add_arch(const UseFlagName &);
+
+ typedef libwrapiter::ForwardIterator<GLSAPackage, const GLSARange> RangesIterator;
+ RangesIterator begin_unaffected() const;
+ RangesIterator end_unaffected() const;
+ RangesIterator begin_vulnerable() const;
+ RangesIterator end_vulnerable() const;
+ void add_unaffected(const GLSARange &);
+ void add_vulnerable(const GLSARange &);
+
+ QualifiedPackageName name() const;
+ };
+
+ /**
+ * Represents a GLSA (security advisory).
+ *
+ * \ingroup grpportagerepository
+ * \nosubgrouping
+ */
+ class PALUDIS_VISIBLE GLSA :
+ private PrivateImplementationPattern<GLSA>
+ {
+ public:
+ GLSA();
+ ~GLSA();
+
+ static std::tr1::shared_ptr<GLSA> create_from_xml_file(const std::string & filename);
+
+ typedef libwrapiter::ForwardIterator<GLSA, const GLSAPackage> PackagesIterator;
+ PackagesIterator begin_packages() const;
+ PackagesIterator end_packages() const;
+ void add_package(std::tr1::shared_ptr<const GLSAPackage>);
+
+ void set_id(const std::string &);
+ std::string id() const;
+
+ void set_title(const std::string &);
+ std::string title() const;
+ };
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/glsa.sr b/paludis/repositories/gentoo/glsa.sr
new file mode 100644
index 0000000..359ffee
--- /dev/null
+++ b/paludis/repositories/gentoo/glsa.sr
@@ -0,0 +1,8 @@
+make_class_GLSARange()
+{
+ key op std::string;
+ # not a version, may be something like 1.3*
+ key version std::string;
+
+ allow_named_args;
+}
diff --git a/paludis/repositories/gentoo/make_ebuild_repository.cc b/paludis/repositories/gentoo/make_ebuild_repository.cc
new file mode 100644
index 0000000..97e37d6
--- /dev/null
+++ b/paludis/repositories/gentoo/make_ebuild_repository.cc
@@ -0,0 +1,186 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "make_ebuild_repository.hh"
+#include <paludis/util/log.hh>
+#include <paludis/util/collection_concrete.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/repositories/gentoo/portage_repository_exceptions.hh>
+#include <paludis/environment.hh>
+
+using namespace paludis;
+
+std::tr1::shared_ptr<PortageRepository>
+paludis::make_ebuild_repository(
+ Environment * const env,
+ std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> > m)
+{
+ std::string repo_file(m->end() == m->find("repo_file") ? std::string("?") :
+ m->find("repo_file")->second);
+
+ Context context("When making ebuild repository from repo_file '" + repo_file + "':");
+
+ std::string location;
+ if (m->end() == m->find("location") || ((location = m->find("location")->second)).empty())
+ throw PortageRepositoryConfigurationError("Key 'location' not specified or empty");
+
+ std::tr1::shared_ptr<const RepositoryName> master_repository_name;
+ std::tr1::shared_ptr<const PortageRepository> master_repository;
+ if (m->end() != m->find("master_repository") && ! m->find("master_repository")->second.empty())
+ {
+ Context context_local("When finding configuration information for master_repository '"
+ + stringify(m->find("master_repository")->second) + "':");
+
+ master_repository_name.reset(new RepositoryName(m->find("master_repository")->second));
+
+ std::tr1::shared_ptr<const Repository> master_repository_uncasted(
+ env->package_database()->fetch_repository(*master_repository_name));
+
+ if (master_repository_uncasted->format() != "ebuild")
+ throw PortageRepositoryConfigurationError("Master repository format is '" +
+ stringify(master_repository_uncasted->format()) + "', not 'ebuild'");
+
+ master_repository = std::tr1::static_pointer_cast<const PortageRepository>(master_repository_uncasted);
+
+ if (master_repository->params().master_repository)
+ throw PortageRepositoryConfigurationError("Requested master repository has a master_repository of '" +
+ stringify(master_repository->params().master_repository->name()) + "', so it cannot "
+ "be used as a master repository");
+ }
+
+ std::tr1::shared_ptr<FSEntryCollection> profiles(new FSEntryCollection::Concrete);
+ if (m->end() != m->find("profiles"))
+ WhitespaceTokeniser::get_instance()->tokenise(m->find("profiles")->second,
+ create_inserter<FSEntry>(std::back_inserter(*profiles)));
+
+ if (profiles->empty())
+ {
+ if (master_repository)
+ std::copy(master_repository->params().profiles->begin(),
+ master_repository->params().profiles->end(), profiles->inserter());
+ else
+ throw PortageRepositoryConfigurationError("No profiles have been specified");
+ }
+
+ std::tr1::shared_ptr<FSEntryCollection> eclassdirs(new FSEntryCollection::Concrete);
+
+ if (m->end() != m->find("eclassdirs"))
+ WhitespaceTokeniser::get_instance()->tokenise(m->find("eclassdirs")->second,
+ create_inserter<FSEntry>(std::back_inserter(*eclassdirs)));
+
+ if (eclassdirs->empty())
+ {
+ if (master_repository)
+ std::copy(master_repository->params().eclassdirs->begin(),
+ master_repository->params().eclassdirs->end(), eclassdirs->inserter());
+
+ eclassdirs->append(location + "/eclass");
+ }
+
+ std::string distdir;
+ if (m->end() == m->find("distdir") || ((distdir = m->find("distdir")->second)).empty())
+ {
+ if (master_repository)
+ distdir = stringify(master_repository->params().distdir);
+ else
+ distdir = location + "/distfiles";
+ }
+
+ std::string setsdir;
+ if (m->end() == m->find("setsdir") || ((setsdir = m->find("setsdir")->second)).empty())
+ setsdir = location + "/sets";
+
+ std::string securitydir;
+ if (m->end() == m->find("securitydir") || ((securitydir = m->find("securitydir")->second)).empty())
+ securitydir = location + "/metadata/glsa";
+
+ std::string newsdir;
+ if (m->end() == m->find("newsdir") || ((newsdir = m->find("newsdir")->second)).empty())
+ newsdir = location + "/metadata/news";
+
+ std::string cache;
+ if (m->end() == m->find("cache") || ((cache = m->find("cache")->second)).empty())
+ {
+ cache = location + "/metadata/cache";
+ if (! FSEntry(cache).exists())
+ cache = "/var/empty";
+ }
+
+ std::string write_cache;
+ if (m->end() == m->find("write_cache") || ((write_cache = m->find("write_cache")->second)).empty())
+ write_cache = "/var/empty";
+
+ std::string names_cache;
+ if (m->end() == m->find("names_cache") || ((names_cache = m->find("names_cache")->second)).empty())
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "The names_cache key is not set in '"
+ + repo_file + "'. You should read http://paludis.pioto.org/cachefiles.html and select an "
+ "appropriate value.");
+ names_cache = "/var/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;
+
+ if (m->end() != m->find("sync_exclude"))
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "The sync_exclude key in '"
+ + repo_file + "' is deprecated in favour of sync_options = --exclude-from=");
+ if (! sync_options.empty())
+ sync_options += " ";
+ sync_options += "--exclude-from='" + m->find("sync_exclude")->second + "'";
+ }
+
+ std::string buildroot;
+ if (m->end() == m->find("buildroot") || ((buildroot = m->find("buildroot")->second)).empty())
+ buildroot = "/var/tmp/paludis";
+
+ return std::tr1::shared_ptr<PortageRepository>(new PortageRepository(PortageRepositoryParams::create()
+ .entry_format("ebuild")
+ .environment(env)
+ .location(location)
+ .profiles(profiles)
+ .cache(cache)
+ .write_cache(write_cache)
+ .names_cache(names_cache)
+ .eclassdirs(eclassdirs)
+ .distdir(distdir)
+ .pkgdir(FSEntry("/var/empty"))
+ .securitydir(securitydir)
+ .setsdir(setsdir)
+ .newsdir(newsdir)
+ .sync(sync)
+ .sync_options(sync_options)
+ .master_repository(master_repository)
+ .buildroot(buildroot)));
+}
+
+std::tr1::shared_ptr<Repository>
+paludis::make_ebuild_repository_wrapped(
+ Environment * const env,
+ std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> > m)
+{
+ return make_ebuild_repository(env, m);
+}
+
diff --git a/paludis/repositories/gentoo/make_ebuild_repository.hh b/paludis/repositories/gentoo/make_ebuild_repository.hh
new file mode 100644
index 0000000..d3c7713
--- /dev/null
+++ b/paludis/repositories/gentoo/make_ebuild_repository.hh
@@ -0,0 +1,44 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_MAKE_EBUILD_REPOSITORY_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_MAKE_EBUILD_REPOSITORY_HH 1
+
+#include <paludis/repositories/gentoo/portage_repository.hh>
+
+namespace paludis
+{
+ /**
+ * Create an ebuild format repository.
+ *
+ * \see PortageRepository
+ * \ingroup grpportagerepository
+ */
+ std::tr1::shared_ptr<PortageRepository>
+ make_ebuild_repository(
+ Environment * const,
+ std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> >) PALUDIS_VISIBLE;
+
+ std::tr1::shared_ptr<Repository>
+ make_ebuild_repository_wrapped(
+ Environment * const env,
+ std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> > m);
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/portage_repository.cc b/paludis/repositories/gentoo/portage_repository.cc
new file mode 100644
index 0000000..850a66a
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository.cc
@@ -0,0 +1,1243 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ * Copyright (c) 2006 Danny van Dyk <kugelfang@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+
+#include <paludis/repositories/gentoo/portage_repository.hh>
+#include <paludis/repositories/gentoo/portage_repository_profile.hh>
+#include <paludis/repositories/gentoo/portage_repository_news.hh>
+#include <paludis/repositories/gentoo/portage_repository_sets.hh>
+#include <paludis/repositories/gentoo/portage_repository_exceptions.hh>
+#include <paludis/repositories/gentoo/portage_repository_entries.hh>
+#include <paludis/repositories/gentoo/portage_virtual_version_metadata.hh>
+#include <paludis/repositories/gentoo/use_desc.hh>
+
+#include <paludis/config_file.hh>
+#include <paludis/dep_atom.hh>
+#include <paludis/dep_atom_flattener.hh>
+#include <paludis/environment.hh>
+#include <paludis/hashed_containers.hh>
+#include <paludis/match_package.hh>
+#include <paludis/package_database.hh>
+#include <paludis/package_database_entry.hh>
+#include <paludis/portage_dep_parser.hh>
+#include <paludis/query.hh>
+#include <paludis/repository_name_cache.hh>
+#include <paludis/syncer.hh>
+#include <paludis/util/collection_concrete.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/is_file_with_extension.hh>
+#include <paludis/util/iterator.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/pstream.hh>
+#include <paludis/util/random.hh>
+#include <paludis/util/save.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/tokeniser.hh>
+
+#include <map>
+#include <fstream>
+#include <functional>
+#include <algorithm>
+#include <vector>
+#include <limits>
+
+#include <strings.h>
+#include <ctype.h>
+
+/** \file
+ * Implementation of PortageRepository.
+ *
+ * \ingroup grpportagerepository
+ */
+
+using namespace paludis;
+
+#include <paludis/repositories/gentoo/portage_repository-sr.cc>
+
+namespace paludis
+{
+ /// Map for versions.
+ typedef MakeHashedMap<QualifiedPackageName, std::tr1::shared_ptr<VersionSpecCollection> >::Type VersionsMap;
+
+ /// Map for repository masks.
+ typedef MakeHashedMap<QualifiedPackageName, std::list<std::tr1::shared_ptr<const PackageDepAtom> > >::Type RepositoryMaskMap;
+
+ /// Map for categories.
+ typedef MakeHashedMap<CategoryNamePart, bool>::Type CategoryMap;
+
+ /// Map for packages.
+ typedef MakeHashedMap<QualifiedPackageName, bool>::Type PackagesMap;
+
+ /// Map for mirrors.
+ typedef MakeHashedMultiMap<std::string, std::string>::Type MirrorMap;
+
+ /// Map for metadata.
+ typedef MakeHashedMap<std::pair<QualifiedPackageName, VersionSpec>,
+ std::tr1::shared_ptr<VersionMetadata> >::Type MetadataMap;
+
+ /// Map for virtuals.
+ typedef MakeHashedMap<QualifiedPackageName, std::tr1::shared_ptr<const PackageDepAtom> >::Type VirtualsMap;
+
+ typedef std::list<PortageRepositoryProfilesDescLine> ProfilesDesc;
+
+ /**
+ * Implementation data for a PortageRepository.
+ *
+ * \ingroup grpportagerepository
+ */
+ template <>
+ struct Implementation<PortageRepository>
+ {
+ /// Our parameters
+ const PortageRepositoryParams params;
+
+ /// Have we loaded our category names?
+ mutable bool has_category_names;
+
+ /// Our category names, and whether we have a fully loaded list
+ /// of package names for that category.
+ mutable CategoryMap category_names;
+
+ /// Our package names, and whether we have a fully loaded list of
+ /// version specs for that category.
+ mutable PackagesMap package_names;
+
+ /// Our version specs for each package.
+ mutable VersionsMap version_specs;
+
+ /// Metadata cache.
+ mutable MetadataMap metadata;
+
+ /// Repository mask.
+ mutable RepositoryMaskMap repo_mask;
+
+ /// Have repository mask?
+ mutable bool has_repo_mask;
+
+ /// Have virtual names?
+ mutable bool has_virtuals;
+
+ /// Arch flags
+ mutable std::tr1::shared_ptr<UseFlagNameCollection> arch_flags;
+
+ /// Do we have mirrors?
+ mutable bool has_mirrors;
+
+ /// Mirrors.
+ mutable MirrorMap mirrors;
+
+ /// Constructor.
+ Implementation(PortageRepository * const, const PortageRepositoryParams &);
+
+ /// Destructor.
+ ~Implementation();
+
+ /// (Empty) provides map.
+ const std::map<QualifiedPackageName, QualifiedPackageName> provide_map;
+
+ /// Load profiles, if we haven't already.
+ inline void need_profiles() const;
+
+ void need_profiles_desc() const;
+
+ /// Our profile handler.
+ mutable std::tr1::shared_ptr<PortageRepositoryProfile> profile_ptr;
+
+ std::list<FSEntry> profiles_dir_locations;
+
+ /// Our news handler.
+ mutable std::tr1::shared_ptr<PortageRepositoryNews> news_ptr;
+
+ /// Our sets handler.
+ mutable std::tr1::shared_ptr<PortageRepositorySets> sets_ptr;
+
+ /// Our metadata handler.
+ mutable std::tr1::shared_ptr<PortageRepositoryEntries> entries_ptr;
+
+ /// Our virtuals
+ mutable VirtualsMap our_virtuals;
+
+ /// Have we loaded our virtuals?
+ bool has_our_virtuals;
+
+ mutable bool has_profiles_desc;
+
+ mutable ProfilesDesc profiles_desc;
+
+ std::tr1::shared_ptr<RepositoryNameCache> names_cache;
+
+ mutable std::list<std::tr1::shared_ptr<UseDesc> > use_desc;
+
+ PortageRepository * const repo;
+ };
+
+ Implementation<PortageRepository>::Implementation(PortageRepository * const r,
+ const PortageRepositoryParams & p) :
+ params(p),
+ has_category_names(false),
+ has_repo_mask(false),
+ has_virtuals(false),
+ has_mirrors(false),
+ sets_ptr(new PortageRepositorySets(params.environment, r, p)),
+ entries_ptr(PortageRepositoryEntriesMaker::get_instance()->find_maker(
+ params.entry_format)(params.environment, r, p)),
+ has_our_virtuals(false),
+ has_profiles_desc(false),
+ names_cache(new RepositoryNameCache(p.names_cache, r)),
+ repo(r)
+ {
+ if (params.master_repository)
+ profiles_dir_locations.push_back(params.master_repository->params().location / "profiles");
+
+ if ((params.location / "profiles").exists())
+ profiles_dir_locations.push_back(params.location / "profiles");
+ }
+
+ Implementation<PortageRepository>::~Implementation()
+ {
+ }
+
+ void
+ Implementation<PortageRepository>::need_profiles() const
+ {
+ if (profile_ptr)
+ return;
+
+ profile_ptr.reset(new PortageRepositoryProfile(
+ params.environment, repo->name(), *params.profiles));
+ }
+
+ void
+ Implementation<PortageRepository>::need_profiles_desc() const
+ {
+ if (has_profiles_desc)
+ return;
+
+ Context context("When loading profiles.desc:");
+
+ bool found_one(false);
+ for (std::list<FSEntry>::const_iterator p(profiles_dir_locations.begin()),
+ p_end(profiles_dir_locations.end()) ; p != p_end ; ++p)
+ {
+ if (! (*p / "profiles.desc").exists())
+ continue;
+
+ found_one = true;
+
+ LineConfigFile f(*p / "profiles.desc");
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ; line != line_end ; ++line)
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*line,
+ std::back_inserter(tokens));
+ if (tokens.size() < 3)
+ continue;
+
+ FSEntryCollection::Concrete profiles;
+ profiles.push_back(*p / tokens.at(1));
+ profiles_desc.push_back(PortageRepositoryProfilesDescLine::create()
+ .arch(tokens.at(0))
+ .path(*profiles.begin())
+ .status(tokens.at(2))
+ .profile(std::tr1::shared_ptr<PortageRepositoryProfile>(new PortageRepositoryProfile(
+ params.environment, repo->name(), profiles))));
+ }
+ }
+
+ if (! found_one)
+ throw PortageRepositoryConfigurationError("No profiles.desc found");
+
+ has_profiles_desc = true;
+ }
+}
+
+PortageRepository::PortageRepository(const PortageRepositoryParams & p) :
+ Repository(PortageRepository::fetch_repo_name(stringify(p.location)),
+ RepositoryCapabilities::create()
+ .mask_interface(this)
+ .installable_interface(this)
+ .installed_interface(0)
+ .news_interface(this)
+ .sets_interface(this)
+ .syncable_interface(this)
+ .uninstallable_interface(0)
+ .use_interface(this)
+ .world_interface(0)
+ .environment_variable_interface(this)
+ .mirrors_interface(this)
+ .virtuals_interface(this)
+ .provides_interface(0)
+ .contents_interface(0)
+ .config_interface(0)
+ .destination_interface(0),
+ p.entry_format),
+ PrivateImplementationPattern<PortageRepository>(new Implementation<PortageRepository>(this, p))
+{
+ // the info_vars and info_pkgs info is only added on demand, since it's
+ // fairly slow to calculate.
+ std::tr1::shared_ptr<RepositoryInfoSection> config_info(new RepositoryInfoSection("Configuration information"));
+
+ config_info->add_kv("location", stringify(_imp->params.location));
+ config_info->add_kv("profiles", join(_imp->params.profiles->begin(),
+ _imp->params.profiles->end(), " "));
+ config_info->add_kv("eclassdirs", join(_imp->params.eclassdirs->begin(),
+ _imp->params.eclassdirs->end(), " "));
+ config_info->add_kv("cache", stringify(_imp->params.cache));
+ config_info->add_kv("write_cache", stringify(_imp->params.write_cache));
+ config_info->add_kv("names_cache", stringify(_imp->params.names_cache));
+ config_info->add_kv("distdir", stringify(_imp->params.distdir));
+ config_info->add_kv("pkgdir", stringify(_imp->params.pkgdir));
+ config_info->add_kv("securitydir", stringify(_imp->params.securitydir));
+ config_info->add_kv("setsdir", stringify(_imp->params.setsdir));
+ config_info->add_kv("newsdir", stringify(_imp->params.newsdir));
+ config_info->add_kv("format", _imp->params.entry_format);
+ config_info->add_kv("buildroot", stringify(_imp->params.buildroot));
+ config_info->add_kv("sync", _imp->params.sync);
+ config_info->add_kv("sync_options", _imp->params.sync_options);
+ if (_imp->params.master_repository)
+ config_info->add_kv("master_repository", stringify(_imp->params.master_repository->name()));
+
+ _info->add_section(config_info);
+}
+
+PortageRepository::~PortageRepository()
+{
+}
+
+bool
+PortageRepository::do_has_category_named(const CategoryNamePart & c) const
+{
+ Context context("When checking for category '" + stringify(c) +
+ "' in " + stringify(name()) + ":");
+
+ need_category_names();
+ return _imp->category_names.end() !=
+ _imp->category_names.find(c);
+}
+
+bool
+PortageRepository::do_has_package_named(const QualifiedPackageName & q) const
+{
+ Context context("When checking for package '" + stringify(q) + "' in " +
+ stringify(name()) + ":");
+
+ need_category_names();
+
+ CategoryMap::iterator cat_iter(_imp->category_names.find(q.category));
+
+ if (_imp->category_names.end() == cat_iter)
+ return false;
+
+ if (cat_iter->second)
+ return _imp->package_names.find(q) !=
+ _imp->package_names.end();
+ else
+ {
+ if (_imp->package_names.find(q) !=
+ _imp->package_names.end())
+ return true;
+
+ FSEntry fs(_imp->params.location);
+ fs /= stringify(q.category);
+ fs /= stringify(q.package);
+ if (! fs.is_directory())
+ return false;
+ _imp->package_names.insert(std::make_pair(q, false));
+ return true;
+ }
+}
+
+namespace
+{
+ /**
+ * Filter QualifiedPackageName instances by category.
+ *
+ * \ingroup grpportagerepository
+ */
+ struct CategoryFilter :
+ std::unary_function<bool, QualifiedPackageName>
+ {
+ /// Our category.
+ CategoryNamePart category;
+
+ /// Constructor.
+ CategoryFilter(const CategoryNamePart & c) :
+ category(c)
+ {
+ }
+
+ /// Predicate.
+ bool operator() (const QualifiedPackageName & a) const
+ {
+ return a.category == category;
+ }
+ };
+}
+
+std::tr1::shared_ptr<const CategoryNamePartCollection>
+PortageRepository::do_category_names() const
+{
+ Context context("When fetching category names in " + stringify(name()) + ":");
+
+ need_category_names();
+
+ std::tr1::shared_ptr<CategoryNamePartCollection> result(new CategoryNamePartCollection::Concrete);
+ CategoryMap::const_iterator i(_imp->category_names.begin()),
+ i_end(_imp->category_names.end());
+ for ( ; i != i_end ; ++i)
+ result->insert(i->first);
+ return result;
+}
+
+std::tr1::shared_ptr<const QualifiedPackageNameCollection>
+PortageRepository::do_package_names(const CategoryNamePart & c) const
+{
+ /* this isn't particularly fast because it isn't called very often. avoid
+ * changing the data structures used to make this faster at the expense of
+ * slowing down single item queries. */
+
+ Context context("When fetching package names in category '" + stringify(c)
+ + "' in " + stringify(name()) + ":");
+
+ need_category_names();
+
+ if (_imp->category_names.end() == _imp->category_names.find(c))
+ return std::tr1::shared_ptr<QualifiedPackageNameCollection>(new QualifiedPackageNameCollection::Concrete);
+
+ if ((_imp->params.location / stringify(c)).is_directory())
+ for (DirIterator d(_imp->params.location / stringify(c)), d_end ; d != d_end ; ++d)
+ {
+ if (! d->is_directory())
+ continue;
+ if (DirIterator() == std::find_if(DirIterator(*d), DirIterator(),
+ IsFileWithExtension(_imp->entries_ptr->file_extension())))
+ continue;
+
+ try
+ {
+ _imp->package_names.insert(std::make_pair(c + PackageNamePart(d->basename()), false));
+ }
+ catch (const NameError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Skipping entry '" +
+ d->basename() + "' in category '" + stringify(c) + "' in repository '"
+ + stringify(name()) + "' (" + e.message() + ")");
+ }
+ }
+
+ _imp->category_names[c] = true;
+
+ std::tr1::shared_ptr<QualifiedPackageNameCollection> result(new QualifiedPackageNameCollection::Concrete);
+
+ std::copy(_imp->package_names.begin(), _imp->package_names.end(),
+ transform_inserter(filter_inserter(result->inserter(), CategoryFilter(c)),
+ SelectFirst<const QualifiedPackageName, bool>()));
+
+ return result;
+}
+
+std::tr1::shared_ptr<const VersionSpecCollection>
+PortageRepository::do_version_specs(const QualifiedPackageName & n) const
+{
+ Context context("When fetching versions of '" + stringify(n) + "' in "
+ + stringify(name()) + ":");
+
+ if (has_package_named(n))
+ {
+ need_version_names(n);
+ return _imp->version_specs.find(n)->second;
+ }
+ else
+ return std::tr1::shared_ptr<VersionSpecCollection>(new VersionSpecCollection::Concrete);
+}
+
+bool
+PortageRepository::do_has_version(const QualifiedPackageName & q,
+ const VersionSpec & v) const
+{
+ Context context("When checking for version '" + stringify(v) + "' in '"
+ + stringify(q) + "' in " + stringify(name()) + ":");
+
+ if (has_package_named(q))
+ {
+ need_version_names(q);
+ std::tr1::shared_ptr<VersionSpecCollection> vv(_imp->version_specs.find(q)->second);
+ return vv->end() != vv->find(v);
+ }
+ else
+ return false;
+}
+
+void
+PortageRepository::need_category_names() const
+{
+ if (_imp->has_category_names)
+ return;
+
+ Context context("When loading category names for " + stringify(name()) + ":");
+
+ Log::get_instance()->message(ll_debug, lc_context, "need_category_names");
+
+ bool found_one(false);
+
+ for (std::list<FSEntry>::const_iterator p(_imp->profiles_dir_locations.begin()),
+ p_end(_imp->profiles_dir_locations.end()) ; p != p_end ; ++p)
+ {
+ if (! (*p / "categories").exists())
+ continue;
+
+ LineConfigFile cats(*p / "categories");
+
+ for (LineConfigFile::Iterator line(cats.begin()), line_end(cats.end()) ;
+ line != line_end ; ++line)
+ {
+ try
+ {
+ _imp->category_names.insert(std::make_pair(CategoryNamePart(*line), false));
+ }
+ catch (const NameError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Skipping line '"
+ + *line + "' in '" + stringify(*p / "categories") + "' due to exception '"
+ + stringify(e.message()) + "' ('" + e.what() + ")");
+ }
+ }
+
+ found_one = true;
+ }
+
+ if (! found_one)
+ {
+ Log::get_instance()->message(ll_qa, lc_context, "No categories file for repository at '"
+ + stringify(_imp->params.location) + "', faking it");
+ for (DirIterator d(_imp->params.location), d_end ; d != d_end ; ++d)
+ {
+ if (! d->is_directory())
+ continue;
+
+ std::string n(d->basename());
+ if (n == "CVS" || n == "distfiles" || n == "scripts" || n == "eclass" || n == "licences"
+ || n == "packages")
+ continue;
+
+ try
+ {
+ _imp->category_names.insert(std::make_pair(CategoryNamePart(n), false));
+ }
+ catch (const NameError &)
+ {
+ }
+ }
+ }
+
+ _imp->has_category_names = true;
+}
+
+void
+PortageRepository::need_version_names(const QualifiedPackageName & n) const
+{
+ if (_imp->package_names[n])
+ return;
+
+ Context context("When loading versions for '" + stringify(n) + "' in "
+ + stringify(name()) + ":");
+
+ Log::get_instance()->message(ll_debug, lc_context, "need_version_names '" + stringify(n) + "'");
+
+ std::tr1::shared_ptr<VersionSpecCollection> v(new VersionSpecCollection::Concrete);
+
+ FSEntry path(_imp->params.location / stringify(n.category) /
+ stringify(n.package));
+
+ for (DirIterator e(path), e_end ; e != e_end ; ++e)
+ {
+ if (! IsFileWithExtension(stringify(n.package) + "-",
+ _imp->entries_ptr->file_extension())(*e))
+ continue;
+
+ try
+ {
+ v->insert(VersionSpec(strip_leading_string(
+ strip_trailing_string(e->basename(), _imp->entries_ptr->file_extension()),
+ stringify(n.package) + "-")));
+ }
+ catch (const NameError &)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Skipping entry '"
+ + stringify(*e) + "' for '" + stringify(n) + "' in repository '"
+ + stringify(name()) + "'");
+ }
+ }
+
+ _imp->version_specs.insert(std::make_pair(n, v));
+ _imp->package_names[n] = true;
+}
+
+RepositoryName
+PortageRepository::fetch_repo_name(const std::string & location)
+{
+ try
+ {
+ do
+ {
+ FSEntry name_file(location);
+ name_file /= "profiles";
+ name_file /= "repo_name";
+
+ if (! name_file.is_regular_file())
+ break;
+
+ LineConfigFile f(name_file);
+ if (f.begin() == f.end())
+ break;
+ return RepositoryName(*f.begin());
+
+ } while (false);
+ }
+ catch (...)
+ {
+ }
+ Log::get_instance()->message(ll_qa, lc_no_context, "Couldn't open repo_name file in '"
+ + location + "/profiles/', falling back to a generated name (ignore this message if "
+ "you have yet to sync this repository).");
+
+ std::string modified_location(FSEntry(location).basename());
+ std::replace(modified_location.begin(), modified_location.end(), '/', '-');
+ return RepositoryName("x-" + modified_location);
+}
+
+std::tr1::shared_ptr<const VersionMetadata>
+PortageRepository::do_version_metadata(
+ const QualifiedPackageName & q, const VersionSpec & v) const
+{
+ if (_imp->metadata.end() != _imp->metadata.find(
+ std::make_pair(q, v)))
+ return _imp->metadata.find(std::make_pair(q, v))->second;
+
+ Context context("When fetching metadata for '" + stringify(q) +
+ "-" + stringify(v) + "':");
+
+ if (! has_version(q, v))
+ throw NoSuchPackageError(stringify(PackageDatabaseEntry(q, v, name())));
+
+ std::tr1::shared_ptr<VersionMetadata> result(_imp->entries_ptr->generate_version_metadata(q, v));
+ _imp->metadata.insert(std::make_pair(std::make_pair(q, v), result));
+ return result;
+}
+
+bool
+PortageRepository::do_query_repository_masks(const QualifiedPackageName & q, const VersionSpec & v) const
+{
+ if (! _imp->has_repo_mask)
+ {
+ Context context("When querying repository mask for '" + stringify(q) + "-"
+ + stringify(v) + "':");
+
+ for (std::list<FSEntry>::const_iterator p(_imp->profiles_dir_locations.begin()),
+ p_end(_imp->profiles_dir_locations.end()) ; p != p_end ; ++p)
+ {
+ FSEntry fff(*p / "package.mask");
+ if (fff.exists())
+ {
+ LineConfigFile ff(fff);
+ for (LineConfigFile::Iterator line(ff.begin()), line_end(ff.end()) ;
+ line != line_end ; ++line)
+ {
+ std::tr1::shared_ptr<const PackageDepAtom> a(new PackageDepAtom(*line));
+ _imp->repo_mask[a->package()].push_back(a);
+ }
+ }
+ }
+
+ _imp->has_repo_mask = true;
+ }
+
+ RepositoryMaskMap::iterator r(_imp->repo_mask.find(q));
+ if (_imp->repo_mask.end() == r)
+ return false;
+ else
+ for (IndirectIterator<std::list<std::tr1::shared_ptr<const PackageDepAtom> >::const_iterator, const PackageDepAtom>
+ k(r->second.begin()), k_end(r->second.end()) ; k != k_end ; ++k)
+ if (match_package(*_imp->params.environment, *k, PackageDatabaseEntry(q, v, name())))
+ return true;
+
+ return false;
+}
+
+bool
+PortageRepository::do_query_profile_masks(const QualifiedPackageName & n,
+ const VersionSpec & v) const
+{
+ _imp->need_profiles();
+ return _imp->profile_ptr->profile_masked(n, v, name());
+}
+
+UseFlagState
+PortageRepository::do_query_use(const UseFlagName & f, const PackageDatabaseEntry * e) const
+{
+ _imp->need_profiles();
+ return _imp->profile_ptr->use_state_ignoring_masks(f, e);
+}
+
+bool
+PortageRepository::do_query_use_mask(const UseFlagName & u, const PackageDatabaseEntry * e) const
+{
+ _imp->need_profiles();
+ return _imp->profile_ptr->use_masked(u, e) ||
+ (arch_flags()->end() != arch_flags()->find(u) && use_enabled != do_query_use(u, e));
+}
+
+bool
+PortageRepository::do_query_use_force(const UseFlagName & u, const PackageDatabaseEntry * e) const
+{
+ _imp->need_profiles();
+ return _imp->profile_ptr->use_forced(u, e);
+}
+
+std::tr1::shared_ptr<const UseFlagNameCollection>
+PortageRepository::do_arch_flags() const
+{
+ if (! _imp->arch_flags)
+ {
+ Context context("When loading arch list:");
+ _imp->arch_flags.reset(new UseFlagNameCollection::Concrete);
+
+ bool found_one(false);
+ for (std::list<FSEntry>::const_iterator p(_imp->profiles_dir_locations.begin()),
+ p_end(_imp->profiles_dir_locations.end()) ; p != p_end ; ++p)
+ {
+ FSEntry a(*p / "arch.list");
+ if (! a.exists())
+ continue;
+
+ LineConfigFile archs(a);
+ std::copy(archs.begin(), archs.end(), create_inserter<UseFlagName>(_imp->arch_flags->inserter()));
+ found_one = true;
+ }
+
+ if (! found_one)
+ {
+ Log::get_instance()->message(ll_qa, lc_no_context, "Couldn't find arch.list file for repository '"
+ + stringify(name()) + "', arch flags may incorrectly show up as unmasked");
+ }
+ }
+
+ return _imp->arch_flags;
+}
+
+bool
+PortageRepository::do_is_licence(const std::string & s) const
+{
+ FSEntry l(_imp->params.location);
+ l /= "licenses";
+
+ if (! l.is_directory())
+ return false;
+
+ l /= s;
+ return l.exists() && l.is_regular_file();
+}
+
+void
+PortageRepository::need_mirrors() const
+{
+ if (! _imp->has_mirrors)
+ {
+ bool found_one(false);
+ for (std::list<FSEntry>::const_iterator p(_imp->profiles_dir_locations.begin()),
+ p_end(_imp->profiles_dir_locations.end()) ; p != p_end ; ++p)
+ {
+ if ((*p / "thirdpartymirrors").exists())
+ {
+ LineConfigFile mirrors(*p / "thirdpartymirrors");
+ for (LineConfigFile::Iterator line(mirrors.begin()) ; line != mirrors.end() ; ++line)
+ {
+ std::vector<std::string> entries;
+ WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(entries));
+ if (! entries.empty())
+ {
+ /* pick up to five random mirrors only */
+ static Random r;
+ std::random_shuffle(next(entries.begin()), entries.end(), r);
+ if (entries.size() > 6)
+ entries.resize(6);
+ for (std::vector<std::string>::const_iterator e(next(entries.begin())),
+ e_end(entries.end()) ; e != e_end ; ++e)
+ _imp->mirrors.insert(std::make_pair(entries.at(0), *e));
+ }
+ }
+ }
+
+ found_one = true;
+ }
+
+ if (! found_one)
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "No thirdpartymirrors file found in '"
+ + stringify(_imp->params.location / "profiles") + "', so mirror:// SRC_URI "
+ "components cannot be fetched");
+
+ _imp->has_mirrors = true;
+ }
+}
+
+void
+PortageRepository::do_install(const QualifiedPackageName & q, const VersionSpec & v,
+ const InstallOptions & o) const
+{
+ _imp->need_profiles();
+
+ if (o.destination->installed_interface && ! o.destination->installed_interface->root().is_directory())
+ throw PackageInstallActionError("Can't install '" + stringify(q) + "-"
+ + stringify(v) + "' since root ('" + stringify(
+ o.destination->installed_interface->root()) + "') isn't a directory");
+
+ _imp->entries_ptr->install(q, v, o, _imp->profile_ptr);
+}
+
+std::tr1::shared_ptr<DepAtom>
+PortageRepository::do_package_set(const SetName & s) const
+{
+ if (s.data() == "system")
+ {
+ _imp->need_profiles();
+ return _imp->profile_ptr->system_packages();
+ }
+
+ return _imp->sets_ptr->package_set(s);
+}
+
+std::tr1::shared_ptr<const SetsCollection>
+PortageRepository::sets_list() const
+{
+ return _imp->sets_ptr->sets_list();
+}
+
+bool
+PortageRepository::do_sync() const
+{
+ Context context("When syncing repository '" + stringify(name()) + "':");
+
+ if (_imp->params.sync.empty())
+ return false;
+
+ std::list<std::string> sync_list;
+ WhitespaceTokeniser::get_instance()->tokenise(_imp->params.sync, std::back_inserter(sync_list));
+
+ bool ok(false);
+ for (std::list<std::string>::const_iterator s(sync_list.begin()),
+ s_end(sync_list.end()) ; s != s_end ; ++s)
+ {
+ DefaultSyncer syncer(SyncerParams::create()
+ .environment(_imp->params.environment)
+ .local(stringify(_imp->params.location))
+ .remote(*s));
+ SyncOptions opts(_imp->params.sync_options);
+ try
+ {
+ syncer.sync(opts);
+ }
+ catch (const SyncFailedError & e)
+ {
+ continue;
+ }
+
+ ok=true;
+ break;
+ }
+
+ if (! ok)
+ throw SyncFailedError(stringify(_imp->params.location), _imp->params.sync);
+
+ return true;
+}
+
+void
+PortageRepository::invalidate()
+{
+ _imp.reset(new Implementation<PortageRepository>(this, _imp->params));
+}
+
+void
+PortageRepository::update_news() const
+{
+ if (! _imp->news_ptr)
+ _imp->news_ptr.reset(new PortageRepositoryNews(_imp->params.environment, this, _imp->params));
+
+ _imp->news_ptr->update_news();
+}
+
+std::string
+PortageRepository::get_environment_variable(
+ const PackageDatabaseEntry & for_package,
+ const std::string & var) const
+{
+ Context context("When fetching environment variable '" + var + "' from repository '"
+ + stringify(name()) + "':");
+
+ _imp->need_profiles();
+
+ return _imp->entries_ptr->get_environment_variable(for_package.name,
+ for_package.version, var, _imp->profile_ptr);
+}
+
+std::tr1::shared_ptr<const RepositoryInfo>
+PortageRepository::info(bool verbose) const
+{
+ std::tr1::shared_ptr<const RepositoryInfo> result_non_verbose(Repository::info(verbose));
+ if (! verbose)
+ return result_non_verbose;
+
+ std::tr1::shared_ptr<RepositoryInfo> result(new RepositoryInfo);
+
+ for (RepositoryInfo::SectionIterator s(result_non_verbose->begin_sections()),
+ s_end(result_non_verbose->end_sections()) ; s != s_end ; ++s)
+ result->add_section(*s);
+
+ // don't inherit from master_repository, just causes clutter
+ std::set<std::string> info_pkgs;
+ if ((_imp->params.location / "profiles" / "info_pkgs").exists())
+ {
+ LineConfigFile vars(_imp->params.location / "profiles" / "info_pkgs");
+ info_pkgs.insert(vars.begin(), vars.end());
+ }
+
+ if (! info_pkgs.empty())
+ {
+ std::tr1::shared_ptr<RepositoryInfoSection> package_info(new RepositoryInfoSection("Package information"));
+ for (std::set<std::string>::const_iterator i(info_pkgs.begin()),
+ i_end(info_pkgs.end()) ; i != i_end ; ++i)
+ {
+ std::tr1::shared_ptr<const PackageDatabaseEntryCollection> q(
+ _imp->params.environment->package_database()->query(
+ query::Matches(PackageDepAtom(*i)) & query::InstalledAtRoot(_imp->params.environment->root()),
+ qo_order_by_version));
+ if (q->empty())
+ package_info->add_kv(*i, "(none)");
+ else
+ {
+ std::set<VersionSpec> versions;
+
+ /* don't use std::transform, it breaks g++4.1 */
+ // std::transform(q->begin(), q->end(), std::inserter(versions, versions.end()),
+ // std::mem_fun_ref(&PackageDatabaseEntry::get<pde_version>));
+ for (PackageDatabaseEntryCollection::Iterator qq(q->begin()), qq_end(q->end()) ;
+ qq != qq_end ; ++qq)
+ versions.insert(qq->version);
+ package_info->add_kv(*i, join(versions.begin(), versions.end(), ", "));
+ }
+ }
+
+ result->add_section(package_info);
+ }
+
+ // don't inherit from master_repository, just causes clutter
+ std::set<std::string> info_vars;
+ if ((_imp->params.location / "profiles" / "info_vars").exists())
+ {
+ LineConfigFile vars(_imp->params.location / "profiles" / "info_vars");
+ info_vars.insert(vars.begin(), vars.end());
+ }
+
+ if (! info_vars.empty() && ! info_pkgs.empty() &&
+ ! version_specs(QualifiedPackageName(*info_pkgs.begin()))->empty())
+ {
+ PackageDatabaseEntry e(QualifiedPackageName(*info_pkgs.begin()),
+ *version_specs(QualifiedPackageName(*info_pkgs.begin()))->last(),
+ name());
+ std::tr1::shared_ptr<RepositoryInfoSection> variable_info(new RepositoryInfoSection("Variable information"));
+ for (std::set<std::string>::const_iterator i(info_vars.begin()),
+ i_end(info_vars.end()) ; i != i_end ; ++i)
+ variable_info->add_kv(*i, get_environment_variable(e, *i));
+
+ result->add_section(variable_info);
+ }
+ else if (! info_vars.empty())
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "Skipping info_vars for '" + stringify(name()) +
+ "' because info_pkgs is not usable");
+
+ return result;
+}
+
+std::string
+PortageRepository::profile_variable(const std::string & s) const
+{
+ _imp->need_profiles();
+
+ return _imp->profile_ptr->environment_variable(s);
+}
+
+PortageRepository::MirrorsIterator
+PortageRepository::begin_mirrors(const std::string & s) const
+{
+ need_mirrors();
+ return MirrorsIterator(_imp->mirrors.equal_range(s).first);
+}
+
+PortageRepository::MirrorsIterator
+PortageRepository::end_mirrors(const std::string & s) const
+{
+ need_mirrors();
+ return MirrorsIterator(_imp->mirrors.equal_range(s).second);
+}
+
+std::tr1::shared_ptr<const PortageRepository::VirtualsCollection>
+PortageRepository::virtual_packages() const
+{
+ Context context("When loading virtual packages for repository '" +
+ stringify(name()) + "'");
+
+ Log::get_instance()->message(ll_debug, lc_context, "Loading virtual packages for repository '"
+ + stringify(name()) + "'");
+
+ _imp->need_profiles();
+ need_category_names();
+
+ std::tr1::shared_ptr<VirtualsCollection> result(new VirtualsCollection::Concrete);
+
+ for (PortageRepositoryProfile::VirtualsIterator i(_imp->profile_ptr->begin_virtuals()),
+ i_end(_imp->profile_ptr->end_virtuals()) ; i != i_end ; ++i)
+ result->insert(RepositoryVirtualsEntry::create()
+ .provided_by_atom(i->second)
+ .virtual_name(i->first));
+
+ Log::get_instance()->message(ll_debug, lc_context, "Loaded " + stringify(result->size()) +
+ " virtual packages for repository '" + stringify(name()) + "'");
+
+ return result;
+}
+
+std::tr1::shared_ptr<const VersionMetadata>
+PortageRepository::virtual_package_version_metadata(const RepositoryVirtualsEntry & p,
+ const VersionSpec & v) const
+{
+ std::tr1::shared_ptr<const VersionMetadata> m(version_metadata(p.provided_by_atom->package(), v));
+ std::tr1::shared_ptr<PortageVirtualVersionMetadata> result(new PortageVirtualVersionMetadata(
+ m->slot, PackageDatabaseEntry(p.provided_by_atom->package(), v, name())));
+
+ result->eapi = m->eapi;
+ result->build_depend_string = "=" + stringify(p.provided_by_atom->package()) + "-" + stringify(v);
+ result->run_depend_string = "=" + stringify(p.provided_by_atom->package()) + "-" + stringify(v);
+
+ return result;
+
+}
+
+std::tr1::shared_ptr<const UseFlagNameCollection>
+PortageRepository::do_use_expand_flags() const
+{
+ _imp->need_profiles();
+
+ std::tr1::shared_ptr<UseFlagNameCollection> result(new UseFlagNameCollection::Concrete);
+ for (PortageRepositoryProfile::UseExpandIterator i(_imp->profile_ptr->begin_use_expand()),
+ i_end(_imp->profile_ptr->end_use_expand()) ; i != i_end ; ++i)
+ {
+ std::list<std::string> values;
+ WhitespaceTokeniser::get_instance()->tokenise(_imp->profile_ptr->environment_variable(
+ stringify(*i)), std::back_inserter(values));
+ for (std::list<std::string>::const_iterator j(values.begin()), j_end(values.end()) ;
+ j != j_end ; ++j)
+ {
+ std::string f(stringify(*i) + "_" + *j), lower_f;
+ std::transform(f.begin(), f.end(), std::back_inserter(lower_f), &::tolower);
+ result->insert(UseFlagName(lower_f));
+ }
+ }
+
+ return result;
+}
+
+std::tr1::shared_ptr<const UseFlagNameCollection>
+PortageRepository::do_use_expand_prefixes() const
+{
+ _imp->need_profiles();
+
+ std::tr1::shared_ptr<UseFlagNameCollection> result(new UseFlagNameCollection::Concrete);
+ for (PortageRepositoryProfile::UseExpandIterator i(_imp->profile_ptr->begin_use_expand()),
+ i_end(_imp->profile_ptr->end_use_expand()) ; i != i_end ; ++i)
+ {
+ std::string lower_i;
+ std::transform(i->data().begin(), i->data().end(), std::back_inserter(lower_i), &::tolower);
+ result->insert(UseFlagName(lower_i));
+ }
+
+ return result;
+}
+
+std::tr1::shared_ptr<const UseFlagNameCollection>
+PortageRepository::do_use_expand_hidden_prefixes() const
+{
+ _imp->need_profiles();
+
+ std::tr1::shared_ptr<UseFlagNameCollection> result(new UseFlagNameCollection::Concrete);
+ for (PortageRepositoryProfile::UseExpandIterator i(_imp->profile_ptr->begin_use_expand_hidden()),
+ i_end(_imp->profile_ptr->end_use_expand_hidden()) ; i != i_end ; ++i)
+ {
+ std::string lower_i;
+ std::transform(i->data().begin(), i->data().end(), std::back_inserter(lower_i), &::tolower);
+ result->insert(UseFlagName(lower_i));
+ }
+
+ return result;
+}
+
+UseFlagName
+PortageRepository::do_use_expand_name(const UseFlagName & u) const
+{
+ for (PortageRepositoryProfile::UseExpandIterator i(_imp->profile_ptr->begin_use_expand()),
+ i_end(_imp->profile_ptr->end_use_expand()) ; i != i_end ; ++i)
+ {
+ std::string lower_i;
+ std::transform(i->data().begin(), i->data().end(), std::back_inserter(lower_i), ::tolower);
+ if (0 == lower_i.compare(0, lower_i.length(), stringify(u), 0, lower_i.length()))
+ return *i;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Not a use expand name: '" + stringify(u) + "'");
+}
+
+UseFlagName
+PortageRepository::do_use_expand_value(const UseFlagName & u) const
+{
+ for (PortageRepositoryProfile::UseExpandIterator i(_imp->profile_ptr->begin_use_expand()),
+ i_end(_imp->profile_ptr->end_use_expand()) ; i != i_end ; ++i)
+ {
+ std::string lower_i;
+ std::transform(i->data().begin(), i->data().end(), std::back_inserter(lower_i), ::tolower);
+ if (0 == lower_i.compare(0, lower_i.length(), stringify(u), 0, lower_i.length()))
+ return UseFlagName(stringify(u).substr(lower_i.length() + 1));
+ }
+
+ throw InternalError(PALUDIS_HERE, "Not a use expand name: '" + stringify(u) + "'");
+}
+
+void
+PortageRepository::regenerate_cache() const
+{
+ _imp->names_cache->regenerate_cache();
+}
+
+std::tr1::shared_ptr<const CategoryNamePartCollection>
+PortageRepository::do_category_names_containing_package(const PackageNamePart & p) const
+{
+ if (! _imp->names_cache->usable())
+ return Repository::do_category_names_containing_package(p);
+
+ std::tr1::shared_ptr<const CategoryNamePartCollection> result(
+ _imp->names_cache->category_names_containing_package(p));
+
+ return result ? result : Repository::do_category_names_containing_package(p);
+}
+
+PortageRepository::ProfilesIterator
+PortageRepository::begin_profiles() const
+{
+ _imp->need_profiles_desc();
+ return ProfilesIterator(_imp->profiles_desc.begin());
+}
+
+PortageRepository::ProfilesIterator
+PortageRepository::end_profiles() const
+{
+ _imp->need_profiles_desc();
+ return ProfilesIterator(_imp->profiles_desc.end());
+}
+
+PortageRepository::ProfilesIterator
+PortageRepository::find_profile(const FSEntry & location) const
+{
+ _imp->need_profiles_desc();
+ for (ProfilesDesc::const_iterator i(_imp->profiles_desc.begin()),
+ i_end(_imp->profiles_desc.end()) ; i != i_end ; ++i)
+ if (i->path == location)
+ return ProfilesIterator(i);
+ return ProfilesIterator(_imp->profiles_desc.end());
+}
+
+void
+PortageRepository::set_profile(const ProfilesIterator & iter)
+{
+ Context context("When setting profile by iterator:");
+
+ _imp->profile_ptr = iter->profile;
+
+ try
+ {
+ _imp->params.environment->package_database()->fetch_repository(
+ RepositoryName("virtuals"))->invalidate();
+ }
+ catch (const NoSuchRepositoryError &)
+ {
+ }
+}
+
+void
+PortageRepository::set_profile_by_arch(const UseFlagName & arch)
+{
+ Context context("When setting profile by arch '" + stringify(arch) + "':");
+
+ for (ProfilesIterator p(begin_profiles()), p_end(end_profiles()) ; p != p_end ; ++p)
+ if (p->arch == stringify(arch) && p->status == "stable")
+ {
+ set_profile(p);
+ return;
+ }
+
+ for (ProfilesIterator p(begin_profiles()), p_end(end_profiles()) ; p != p_end ; ++p)
+ if (p->arch == stringify(arch))
+ {
+ set_profile(p);
+ return;
+ }
+
+ throw ConfigurationError("Cannot find a profile appropriate for '" + stringify(arch) + "'");
+}
+
+std::string
+PortageRepository::do_describe_use_flag(const UseFlagName & f,
+ const PackageDatabaseEntry * const e) const
+{
+ if (_imp->use_desc.empty())
+ for (std::list<FSEntry>::const_iterator p(_imp->profiles_dir_locations.begin()),
+ p_end(_imp->profiles_dir_locations.end()) ; p != p_end ; ++p)
+ _imp->use_desc.push_back(std::tr1::shared_ptr<UseDesc>(new UseDesc(*p)));
+
+ std::string result;
+ for (std::list<std::tr1::shared_ptr<UseDesc> >::const_iterator i(_imp->use_desc.begin()),
+ i_end(_imp->use_desc.end()) ; i != i_end ; ++i)
+ {
+ std::string new_result((*i)->describe(f, e));
+ if (! new_result.empty())
+ result = new_result;
+ }
+ return result;
+}
+
+const PortageRepositoryParams &
+PortageRepository::params() const
+{
+ return _imp->params;
+}
+
diff --git a/paludis/repositories/gentoo/portage_repository.hh b/paludis/repositories/gentoo/portage_repository.hh
new file mode 100644
index 0000000..26a0803
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository.hh
@@ -0,0 +1,189 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_PORTAGE_REPOSITORY_HH
+#define PALUDIS_GUARD_PALUDIS_PORTAGE_REPOSITORY_HH 1
+
+#include <paludis/repository.hh>
+#include <paludis/package_database.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/repositories/gentoo/portage_repository_params.hh>
+#include <paludis/repositories/gentoo/portage_repository_profile.hh>
+#include <string>
+
+/** \file
+ * Declaration for the PortageRepository class.
+ *
+ * \ingroup grpportagerepository
+ */
+
+namespace paludis
+{
+ class PortageRepositoryProfile;
+ class PortageRepositoryNews;
+
+#include <paludis/repositories/gentoo/portage_repository-sr.hh>
+
+ /**
+ * A PortageRepository is a Repository that handles the layout used by
+ * Portage for the main Gentoo tree.
+ *
+ * \ingroup grpportagerepository
+ * \nosubgrouping
+ */
+ class PALUDIS_VISIBLE PortageRepository :
+ public Repository,
+ public RepositoryMaskInterface,
+ public RepositoryUseInterface,
+ public RepositoryInstallableInterface,
+ public RepositorySyncableInterface,
+ public RepositoryNewsInterface,
+ public RepositorySetsInterface,
+ public RepositoryEnvironmentVariableInterface,
+ public RepositoryMirrorsInterface,
+ public RepositoryVirtualsInterface,
+ private PrivateImplementationPattern<PortageRepository>
+ {
+ private:
+ void need_category_names() const;
+ void need_version_names(const QualifiedPackageName &) const;
+ void need_mirrors() const;
+ PackageDatabaseEntryCollection::Iterator find_best(PackageDatabaseEntryCollection & c,
+ const PackageDatabaseEntry & e) const;
+
+ protected:
+ /**
+ * Try to get the repository name for a particular repository.
+ */
+ static RepositoryName fetch_repo_name(const std::string & location);
+
+ virtual bool do_has_category_named(const CategoryNamePart &) const;
+
+ virtual bool do_has_package_named(const QualifiedPackageName &) const;
+
+ virtual std::tr1::shared_ptr<const CategoryNamePartCollection> do_category_names() const;
+
+ std::tr1::shared_ptr<const CategoryNamePartCollection> do_category_names_containing_package(
+ const PackageNamePart & p) const;
+
+ virtual std::tr1::shared_ptr<const QualifiedPackageNameCollection> do_package_names(
+ const CategoryNamePart &) const;
+
+ virtual std::tr1::shared_ptr<const VersionSpecCollection> do_version_specs(
+ const QualifiedPackageName &) const;
+
+ virtual bool do_has_version(const QualifiedPackageName &, const VersionSpec &) const;
+
+ virtual std::tr1::shared_ptr<const VersionMetadata> do_version_metadata(
+ const QualifiedPackageName &,
+ const VersionSpec &) const;
+
+ virtual bool do_query_repository_masks(const QualifiedPackageName &,
+ const VersionSpec &) const;
+
+ virtual bool do_query_profile_masks(const QualifiedPackageName &,
+ const VersionSpec &) const;
+
+ virtual bool do_is_licence(const std::string &) const;
+
+ virtual void do_install(const QualifiedPackageName &, const VersionSpec &,
+ const InstallOptions &) const;
+
+ virtual std::tr1::shared_ptr<DepAtom> do_package_set(const SetName &) const;
+
+ virtual std::tr1::shared_ptr<const SetsCollection> sets_list() const;
+
+ virtual bool do_sync() const;
+
+ virtual std::tr1::shared_ptr<const VirtualsCollection> virtual_packages() const;
+
+ virtual std::tr1::shared_ptr<const VersionMetadata> virtual_package_version_metadata(
+ const RepositoryVirtualsEntry &, const VersionSpec & v) const;
+
+ /* RepositoryUseInterface */
+
+ virtual UseFlagState do_query_use(const UseFlagName &, const PackageDatabaseEntry *) const;
+ virtual bool do_query_use_mask(const UseFlagName &, const PackageDatabaseEntry *) const;
+ virtual bool do_query_use_force(const UseFlagName &, const PackageDatabaseEntry *) const;
+ virtual std::tr1::shared_ptr<const UseFlagNameCollection> do_arch_flags() const;
+ virtual std::tr1::shared_ptr<const UseFlagNameCollection> do_use_expand_flags() const;
+ virtual std::tr1::shared_ptr<const UseFlagNameCollection> do_use_expand_hidden_prefixes() const;
+ virtual UseFlagName do_use_expand_name(const UseFlagName & u) const;
+ virtual UseFlagName do_use_expand_value(const UseFlagName & u) const;
+ virtual std::tr1::shared_ptr<const UseFlagNameCollection> do_use_expand_prefixes() const;
+ virtual std::string do_describe_use_flag(const UseFlagName &,
+ const PackageDatabaseEntry * const) const;
+
+ /* end of RepositoryUseInterface */
+
+ public:
+ virtual std::tr1::shared_ptr<const RepositoryInfo> info(bool verbose) const;
+
+ /**
+ * Constructor.
+ */
+ PortageRepository(const PortageRepositoryParams &);
+
+ /**
+ * Destructor.
+ */
+ ~PortageRepository();
+
+ virtual void invalidate();
+ virtual void regenerate_cache() const;
+
+ virtual void update_news() const;
+
+ virtual std::string get_environment_variable(
+ const PackageDatabaseEntry & for_package,
+ const std::string & var) const;
+
+ virtual MirrorsIterator begin_mirrors(const std::string & s) const;
+ virtual MirrorsIterator end_mirrors(const std::string & s) const;
+
+ ///\name Information about PortageRepository
+ ///\{
+
+ std::string profile_variable(const std::string &) const;
+
+ typedef libwrapiter::ForwardIterator<PortageRepository, std::pair<
+ const QualifiedPackageName, std::tr1::shared_ptr<const PackageDepAtom> > > OurVirtualsIterator;
+
+ const PortageRepositoryParams & params() const;
+
+ ///\}
+
+ ///\name Profile setting and querying functions
+ ///\{
+
+ typedef libwrapiter::ForwardIterator<PortageRepository,
+ const PortageRepositoryProfilesDescLine> ProfilesIterator;
+ ProfilesIterator begin_profiles() const;
+ ProfilesIterator end_profiles() const;
+
+ ProfilesIterator find_profile(const FSEntry & location) const;
+ void set_profile(const ProfilesIterator & iter);
+ void set_profile_by_arch(const UseFlagName &);
+
+ ///\}
+ };
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/portage_repository.sr b/paludis/repositories/gentoo/portage_repository.sr
new file mode 100644
index 0000000..5f4c515
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository.sr
@@ -0,0 +1,10 @@
+make_class_PortageRepositoryProfilesDescLine()
+{
+ key path FSEntry
+ key arch std::string
+ key status std::string
+ key profile "std::tr1::shared_ptr<PortageRepositoryProfile>"
+ allow_named_args
+}
+
+
diff --git a/paludis/repositories/gentoo/portage_repository_TEST.cc b/paludis/repositories/gentoo/portage_repository_TEST.cc
new file mode 100644
index 0000000..3f8c7a3
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_TEST.cc
@@ -0,0 +1,665 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/repositories/gentoo/portage_repository.hh>
+#include <paludis/repositories/gentoo/make_ebuild_repository.hh>
+#include <paludis/util/collection_concrete.hh>
+#include <paludis/environment/test/test_environment.hh>
+#include <paludis/util/system.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for PortageRepository.
+ *
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test PortageRepository repository names.
+ *
+ */
+ struct PortageRepositoryRepoNameTest : TestCase
+ {
+ PortageRepositoryRepoNameTest() : TestCase("repo name") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo1");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo1/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+ TEST_CHECK_STRINGIFY_EQUAL(repo->name(), "test-repo-1");
+ }
+ } test_portage_repository_repo_name;
+
+ /**
+ * \test Test PortageRepository repository with no names.
+ *
+ */
+ struct PortageRepositoryNoRepoNameTest : TestCase
+ {
+ PortageRepositoryNoRepoNameTest() : TestCase("no repo name") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo2");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo2/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+ TEST_CHECK_STRINGIFY_EQUAL(repo->name(), "x-repo2");
+ }
+ } test_portage_repository_no_repo_name;
+
+ /**
+ * \test Test PortageRepository repository empty names.
+ *
+ */
+ struct PortageRepositoryEmptyRepoNameTest : TestCase
+ {
+ PortageRepositoryEmptyRepoNameTest() : TestCase("empty repo name") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo3");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo3/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+ TEST_CHECK_STRINGIFY_EQUAL(repo->name(), "x-repo3");
+ }
+ } test_portage_repository_empty_repo_name;
+
+ /**
+ * \test Test PortageRepository repository has_category_named.
+ *
+ */
+ struct PortageRepositoryHasCategoryNamedTest : TestCase
+ {
+ PortageRepositoryHasCategoryNamedTest() : TestCase("has category named") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo1");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo1/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+
+ TEST_CHECK(repo->has_category_named(CategoryNamePart("cat-one")));
+ TEST_CHECK(repo->has_category_named(CategoryNamePart("cat-two")));
+ TEST_CHECK(repo->has_category_named(CategoryNamePart("cat-three")));
+ TEST_CHECK(! repo->has_category_named(CategoryNamePart("cat-four")));
+ }
+ }
+ } test_portage_repository_has_category_named;
+
+ /**
+ * \test Test PortageRepository category_names.
+ *
+ */
+ struct PortageRepositoryCategoryNamesTest : TestCase
+ {
+ PortageRepositoryCategoryNamesTest() : TestCase("category names") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo1");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo1/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+
+ std::tr1::shared_ptr<const CategoryNamePartCollection> c(repo->category_names());
+ TEST_CHECK(c->end() != c->find(CategoryNamePart("cat-one")));
+ TEST_CHECK(c->end() != c->find(CategoryNamePart("cat-two")));
+ TEST_CHECK(c->end() != c->find(CategoryNamePart("cat-three")));
+ TEST_CHECK(c->end() == c->find(CategoryNamePart("cat-four")));
+ TEST_CHECK_EQUAL(3, std::distance(c->begin(), c->end()));
+ }
+ }
+ } test_portage_repository_category_names;
+
+ /**
+ * \test Test PortageRepository has_package_named.
+ *
+ */
+ struct PortageRepositoryHasPackageNamedTest : TestCase
+ {
+ PortageRepositoryHasPackageNamedTest() : TestCase("has package named") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo4");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo4/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+
+ TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-one/pkg-one")));
+ TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-two/pkg-two")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-one/pkg-two")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-two/pkg-one")));
+ TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-one/pkg-both")));
+ TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-two/pkg-both")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-one/pkg-neither")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-two/pkg-neither")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-one")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-two")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-both")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-neither")));
+ }
+ }
+ } test_portage_repository_has_package_named;
+
+ /**
+ * \test Test PortageRepository has_package_named cached.
+ *
+ */
+ struct PortageRepositoryHasPackageNamedCachedTest : TestCase
+ {
+ PortageRepositoryHasPackageNamedCachedTest() : TestCase("has package named cached") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo4");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo4/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ repo->package_names(CategoryNamePart("cat-one"));
+ repo->package_names(CategoryNamePart("cat-two"));
+ repo->package_names(CategoryNamePart("cat-three"));
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+
+ TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-one/pkg-one")));
+ TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-two/pkg-two")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-one/pkg-two")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-two/pkg-one")));
+ TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-one/pkg-both")));
+ TEST_CHECK(repo->has_package_named(QualifiedPackageName("cat-two/pkg-both")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-one/pkg-neither")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-two/pkg-neither")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-one")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-two")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-both")));
+ TEST_CHECK(! repo->has_package_named(QualifiedPackageName("cat-three/pkg-neither")));
+ }
+ }
+ } test_portage_repository_has_package_named_cached;
+
+ /**
+ * \test Test PortageRepository package_names.
+ *
+ */
+ struct PortageRepositoryPackageNamesTest : TestCase
+ {
+ PortageRepositoryPackageNamesTest() : TestCase("package names") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo4");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo4/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ std::tr1::shared_ptr<const QualifiedPackageNameCollection> names;
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+
+ names = repo->package_names(CategoryNamePart("cat-one"));
+ TEST_CHECK(! names->empty());
+ TEST_CHECK(names->end() != names->find(QualifiedPackageName("cat-one/pkg-one")));
+ TEST_CHECK(names->end() != names->find(QualifiedPackageName("cat-one/pkg-both")));
+ TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-one/pkg-two")));
+ TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-one/pkg-neither")));
+ TEST_CHECK_EQUAL(2, std::distance(names->begin(), names->end()));
+
+ names = repo->package_names(CategoryNamePart("cat-two"));
+ TEST_CHECK(! names->empty());
+ TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-two/pkg-one")));
+ TEST_CHECK(names->end() != names->find(QualifiedPackageName("cat-two/pkg-both")));
+ TEST_CHECK(names->end() != names->find(QualifiedPackageName("cat-two/pkg-two")));
+ TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-two/pkg-neither")));
+ TEST_CHECK_EQUAL(2, std::distance(names->begin(), names->end()));
+
+ names = repo->package_names(CategoryNamePart("cat-three"));
+ TEST_CHECK(names->empty());
+ TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-three/pkg-one")));
+ TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-three/pkg-both")));
+ TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-three/pkg-two")));
+ TEST_CHECK(names->end() == names->find(QualifiedPackageName("cat-three/pkg-neither")));
+ TEST_CHECK_EQUAL(0, std::distance(names->begin(), names->end()));
+ }
+ }
+ } test_portage_repository_package_names;
+
+ /**
+ * \test Test PortageRepository bad package names.
+ *
+ */
+ struct PortageRepositoryBadPackageNamesTest : TestCase
+ {
+ PortageRepositoryBadPackageNamesTest() : TestCase("bad package names") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo5");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo5/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ std::tr1::shared_ptr<const QualifiedPackageNameCollection> names;
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+
+ names = repo->package_names(CategoryNamePart("cat-one"));
+ TEST_CHECK(! names->empty());
+ TEST_CHECK(names->end() != names->find(QualifiedPackageName("cat-one/pkg-one")));
+ TEST_CHECK_EQUAL(1, std::distance(names->begin(), names->end()));
+ }
+ }
+ } test_portage_repository_bad_package_names;
+
+ /**
+ * \test Test PortageRepository has_version.
+ *
+ */
+ struct PortageRepositoryHasVersionTest : TestCase
+ {
+ PortageRepositoryHasVersionTest() : TestCase("has version") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo4");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo4/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+
+ TEST_CHECK(repo->has_version(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("1")));
+ TEST_CHECK(repo->has_version(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("1.1-r1")));
+ TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("2")));
+
+ TEST_CHECK(repo->has_version(QualifiedPackageName("cat-one/pkg-both"), VersionSpec("3.45")));
+ TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-one/pkg-both"), VersionSpec("1")));
+ TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-one/pkg-both"), VersionSpec("1.23")));
+
+ TEST_CHECK(repo->has_version(QualifiedPackageName("cat-two/pkg-two"), VersionSpec("2")));
+ TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-two/pkg-two"), VersionSpec("1")));
+
+ TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-two/pkg-both"), VersionSpec("3.45")));
+ TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-two/pkg-both"), VersionSpec("1")));
+ TEST_CHECK(repo->has_version(QualifiedPackageName("cat-two/pkg-both"), VersionSpec("1.23")));
+
+ TEST_CHECK(! repo->has_version(QualifiedPackageName("cat-two/pkg-neither"), VersionSpec("1")));
+ }
+ }
+ } test_portage_repository_has_version;
+
+ /**
+ * \test Test PortageRepository versions.
+ *
+ */
+ struct PortageRepositoryVersionsTest : TestCase
+ {
+ PortageRepositoryVersionsTest() : TestCase("versions") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo4");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo4/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+
+ std::tr1::shared_ptr<const VersionSpecCollection> versions;
+
+ versions = repo->version_specs(QualifiedPackageName("cat-one/pkg-one"));
+ TEST_CHECK(! versions->empty());
+ TEST_CHECK_EQUAL(2, std::distance(versions->begin(), versions->end()));
+ TEST_CHECK(versions->end() != versions->find(VersionSpec("1")));
+ TEST_CHECK(versions->end() != versions->find(VersionSpec("1.1-r1")));
+ TEST_CHECK(versions->end() == versions->find(VersionSpec("2")));
+
+ versions = repo->version_specs(QualifiedPackageName("cat-one/pkg-neither"));
+ TEST_CHECK(versions->empty());
+ TEST_CHECK_EQUAL(0, std::distance(versions->begin(), versions->end()));
+ TEST_CHECK(versions->end() == versions->find(VersionSpec("1")));
+ TEST_CHECK(versions->end() == versions->find(VersionSpec("1.1-r1")));
+ TEST_CHECK(versions->end() == versions->find(VersionSpec("2")));
+ }
+ }
+ } test_portage_repository_versions;
+
+ /**
+ * \test Test PortageRepository duff versions.
+ *
+ */
+ struct PortageRepositoryDuffVersionsTest : TestCase
+ {
+ PortageRepositoryDuffVersionsTest() : TestCase("duff versions") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo8");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo8/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+
+ std::tr1::shared_ptr<const VersionSpecCollection> versions;
+
+ versions = repo->version_specs(QualifiedPackageName("cat-one/pkg-one"));
+ TEST_CHECK(! versions->empty());
+ TEST_CHECK_EQUAL(2, std::distance(versions->begin(), versions->end()));
+ TEST_CHECK(versions->end() != versions->find(VersionSpec("1")));
+ TEST_CHECK(versions->end() != versions->find(VersionSpec("1.1-r1")));
+ TEST_CHECK(versions->end() == versions->find(VersionSpec("2")));
+
+ versions = repo->version_specs(QualifiedPackageName("cat-one/pkg-neither"));
+ TEST_CHECK(versions->empty());
+ TEST_CHECK_EQUAL(0, std::distance(versions->begin(), versions->end()));
+ TEST_CHECK(versions->end() == versions->find(VersionSpec("1")));
+ TEST_CHECK(versions->end() == versions->find(VersionSpec("1.1-r1")));
+ TEST_CHECK(versions->end() == versions->find(VersionSpec("2")));
+ }
+ }
+ } test_portage_repository_duff_versions;
+
+ /**
+ * \test Test PortageRepository cached metadata.
+ *
+ */
+ struct PortageRepositoryMetadataCachedTest : TestCase
+ {
+ PortageRepositoryMetadataCachedTest() : TestCase("metadata cached") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo6");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo6/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+ std::tr1::shared_ptr<const VersionMetadata> m;
+
+ m = repo->version_metadata(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("1"));
+ TEST_CHECK_EQUAL(m->description, "the-description");
+
+ TEST_CHECK_THROWS(repo->version_metadata(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("2")),
+ NoSuchPackageError);
+ TEST_CHECK_THROWS(repo->version_metadata(QualifiedPackageName("cat-two/pkg-one"), VersionSpec("1")),
+ NoSuchPackageError);
+ }
+ }
+ } test_portage_repository_metadata_cached;
+
+ /**
+ * \test Test PortageRepository uncached metadata.
+ *
+ */
+ struct PortageRepositoryMetadataUncachedTest : TestCase
+ {
+ PortageRepositoryMetadataUncachedTest() : TestCase("metadata uncached") { }
+
+ bool skip() const
+ {
+ return ! getenv_with_default("SANDBOX_ON", "").empty();
+ }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo7");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo7/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+ std::tr1::shared_ptr<const VersionMetadata> m;
+
+ m = repo->version_metadata(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("1"));
+ TEST_CHECK_EQUAL(m->description, "The Description");
+ TEST_CHECK_EQUAL(m->eapi, "0");
+ }
+ }
+ } test_portage_repository_metadata_uncached;
+
+ /**
+ * \test Test PortageRepository unparsable metadata.
+ *
+ */
+ struct PortageRepositoryMetadataUnparsableTest : TestCase
+ {
+ PortageRepositoryMetadataUnparsableTest() : TestCase("metadata unparsable") { }
+
+ bool skip() const
+ {
+ return ! getenv_with_default("SANDBOX_ON", "").empty();
+ }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo7");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo7/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+ std::tr1::shared_ptr<const VersionMetadata> m;
+
+ m = repo->version_metadata(QualifiedPackageName("cat-one/pkg-two"), VersionSpec("1"));
+ TEST_CHECK_EQUAL(m->eapi, "UNKNOWN");
+ }
+ }
+ } test_portage_repository_metadata_unparsable;
+
+ /**
+ * \test Test PortageRepository query_use and query_use_mask functions.
+ *
+ */
+ struct PortageRepositoryQueryUseTest : TestCase
+ {
+ PortageRepositoryQueryUseTest() : TestCase("USE query") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo9");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo9/profiles/profile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+
+ PackageDatabaseEntry p1(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("1"),
+ RepositoryName("test-repo-9"));
+ PackageDatabaseEntry p2(QualifiedPackageName("cat-two/pkg-two"), VersionSpec("1"),
+ RepositoryName("test-repo-9"));
+ PackageDatabaseEntry p3(QualifiedPackageName("cat-one/pkg-none"), VersionSpec("1"),
+ RepositoryName("test-repo-9"));
+ PackageDatabaseEntry p4(QualifiedPackageName("cat-one/pkg-one"), VersionSpec("2"),
+ RepositoryName("test-repo-9"));
+
+ TEST_CHECK(repo->query_use(UseFlagName("flag1"), &p1) == use_enabled);
+ TEST_CHECK(repo->query_use(UseFlagName("flag2"), &p1) == use_disabled);
+ TEST_CHECK(repo->query_use_mask(UseFlagName("flag2"), &p1));
+ TEST_CHECK(repo->query_use_mask(UseFlagName("flag2"), &p3));
+ TEST_CHECK(repo->query_use_mask(UseFlagName("flag3"), &p2));
+ TEST_CHECK(! repo->query_use_mask(UseFlagName("flag3"), &p1));
+ TEST_CHECK(repo->query_use_mask(UseFlagName("flag3"), &p4));
+ TEST_CHECK(repo->query_use(UseFlagName("flag3"), &p1) == use_enabled);
+ TEST_CHECK(repo->query_use(UseFlagName("flag4"), &p3) == use_enabled);
+ TEST_CHECK(repo->query_use(UseFlagName("flag5"), &p2) == use_enabled);
+ TEST_CHECK(repo->query_use(UseFlagName("flag5"), &p1) == use_unspecified);
+ }
+ }
+ } test_portage_repository_query_use;
+
+ /**
+ * \test Test PortageRepository query_profile_masks functions.
+ *
+ */
+ struct PortageRepositoryQueryProfileMasksTest : TestCase
+ {
+ PortageRepositoryQueryProfileMasksTest() : TestCase("profiles package.mask") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "ebuild");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("location", "portage_repository_TEST_dir/repo10");
+ keys->insert("profiles", "portage_repository_TEST_dir/repo10/profiles/profile/subprofile");
+ std::tr1::shared_ptr<PortageRepository> repo(make_ebuild_repository(
+ &env, keys));
+
+ for (int pass = 1 ; pass <= 2 ; ++pass)
+ {
+ TestMessageSuffix pass_suffix(stringify(pass), true);
+
+ TEST_CHECK(repo->query_profile_masks(QualifiedPackageName("cat/masked"),
+ VersionSpec("0")));
+ TEST_CHECK(! repo->query_profile_masks(QualifiedPackageName("cat/not_masked"),
+ VersionSpec("0")));
+ TEST_CHECK(! repo->query_profile_masks(QualifiedPackageName("cat/was_masked"),
+ VersionSpec("0")));
+ }
+ }
+ } test_portage_repository_query_profile_masks;
+}
+
diff --git a/paludis/repositories/gentoo/portage_repository_TEST_cleanup.sh b/paludis/repositories/gentoo/portage_repository_TEST_cleanup.sh
new file mode 100755
index 0000000..8c0b290
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_TEST_cleanup.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d portage_repository_TEST_dir ] ; then
+ rm -fr portage_repository_TEST_dir
+else
+ true
+fi
+
+
diff --git a/paludis/repositories/gentoo/portage_repository_TEST_setup.sh b/paludis/repositories/gentoo/portage_repository_TEST_setup.sh
new file mode 100755
index 0000000..5fc9373
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_TEST_setup.sh
@@ -0,0 +1,226 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir portage_repository_TEST_dir || exit 1
+cd portage_repository_TEST_dir || exit 1
+
+mkdir -p repo1/{eclass,distfiles,profiles/profile} || exit 1
+cd repo1 || exit 1
+echo "test-repo-1" > profiles/repo_name || exit 1
+cat <<END > profiles/categories || exit 1
+cat-one
+cat-two
+cat-three
+END
+cat <<END > profiles/profile/make.defaults
+ARCH=test
+END
+cd ..
+
+mkdir -p repo2/{eclass,distfiles,profiles/profile} || exit 1
+cd repo2 || exit 1
+cat <<END > profiles/categories || exit 1
+END
+cat <<END > profiles/profile/make.defaults
+ARCH=test
+END
+cd ..
+
+
+mkdir -p repo3/{eclass,distfiles,profiles/profile} || exit 1
+cd repo3 || exit 1
+echo "# test-repo-3" > profiles/repo_name || exit 1
+cat <<END > profiles/categories || exit 1
+END
+cat <<END > profiles/profile/make.defaults
+ARCH=test
+END
+cd ..
+
+
+mkdir -p repo4/{eclass,distfiles,profiles/profile} || exit 1
+mkdir -p repo4/{cat-one/{pkg-one,pkg-both},cat-two/{pkg-two,pkg-both}} || exit 1
+cd repo4 || exit 1
+echo "test-repo-4" > profiles/repo_name || exit 1
+cat <<END > profiles/categories || exit 1
+cat-one
+cat-two
+END
+cat <<END > profiles/profile/make.defaults
+ARCH=test
+END
+cat <<END > cat-one/pkg-one/pkg-one-1.ebuild || exit 1
+END
+cat <<END > cat-one/pkg-one/pkg-one-1.1-r1.ebuild || exit 1
+END
+cat <<END > cat-one/pkg-both/pkg-both-3.45.ebuild || exit 1
+END
+cat <<END > cat-two/pkg-two/pkg-two-2.ebuild || exit 1
+END
+cat <<END > cat-two/pkg-both/pkg-both-1.23.ebuild || exit 1
+END
+cd ..
+
+
+mkdir -p repo5/{eclass,distfiles,profiles/profile} || exit 1
+mkdir -p repo5/cat-one/{pkg-one,pkg-1,pkg.one} || exit 1
+cd repo5 || exit 1
+echo "test-repo-5" > profiles/repo_name || exit 1
+cat <<END > profiles/categories || exit 1
+cat-one
+END
+cat <<END > profiles/profile/make.defaults
+ARCH=test
+END
+cat <<END > cat-one/pkg-one/pkg-one-1.ebuild || exit 1
+END
+cat <<END > cat-one/pkg-1/pkg-1-1.ebuild || exit 1
+END
+cat <<END > cat-one/pkg.one/pkg.one-1.ebuild || exit 1
+END
+cd ..
+
+
+mkdir -p repo6/{eclass,distfiles,profiles/profile} || exit 1
+mkdir -p repo6/cat-one/pkg-one || exit 1
+mkdir -p repo6/metadata/cache/cat-one
+cd repo6 || exit 1
+echo "test-repo-6" > profiles/repo_name || exit 1
+cat <<END > profiles/categories || exit 1
+cat-one
+END
+cat <<END > profiles/profile/make.defaults
+ARCH=test
+END
+cat <<END > cat-one/pkg-one/pkg-one-1.ebuild || exit 1
+END
+cat <<END > metadata/cache/cat-one/pkg-one-1
+the/depend
+the/rdepend
+the-slot
+the-src-uri
+the-restrict
+the-homepage
+the-license
+the-description
+the-keywords
+
+the-iuse
+unused
+the/pdepend
+the/provide
+0
+END
+cd ..
+
+
+mkdir -p repo7/{eclass,distfiles,profiles/profile} || exit 1
+mkdir -p repo7/cat-one/pkg-{one,two} || exit 1
+mkdir -p repo7/metadata/cache/cat-{one,two}
+cd repo7 || exit 1
+echo "test-repo-7" > profiles/repo_name || exit 1
+cat <<END > profiles/categories || exit 1
+cat-one
+END
+cat <<END > profiles/profile/make.defaults
+ARCH=test
+END
+cat <<END > cat-one/pkg-one/pkg-one-1.ebuild || exit 1
+DESCRIPTION="The Description"
+HOMEPAGE="http://example.com/"
+SRC_URI=""
+SLOT="0"
+IUSE=""
+LICENSE="GPL-2"
+KEYWORDS="test"
+END
+cat <<END > cat-one/pkg-two/pkg-two-1.ebuild || exit 1
+i am a fish
+END
+cd ..
+
+
+mkdir -p repo8/{eclass,distfiles,profiles/profile} || exit 1
+mkdir -p repo8/{cat-one/{pkg-one,pkg-both},cat-two/{pkg-two,pkg-both}} || exit 1
+cd repo8 || exit 1
+echo "test-repo-8" > profiles/repo_name || exit 1
+cat <<END > profiles/categories || exit 1
+cat-one
+cat-two
+END
+cat <<END > profiles/profile/make.defaults
+ARCH=test
+END
+cat <<END > cat-one/pkg-one/pkg-one-1.ebuild || exit 1
+END
+cat <<END > cat-one/pkg-one/pkg-one-1-monkey.ebuild || exit 1
+END
+cat <<END > cat-one/pkg-one/pkg-one-1.1-r1.ebuild || exit 1
+END
+cat <<END > cat-one/pkg-both/pkg-both-3.45.ebuild || exit 1
+END
+cat <<END > cat-one/pkg-both/pkg-both-3.45_r1.ebuild || exit 1
+END
+cat <<END > cat-two/pkg-two/pkg-two-2.ebuild || exit 1
+END
+cat <<END > cat-two/pkg-both/pkg-both-1.23.ebuild || exit 1
+END
+cat <<END > cat-two/pkg-both/pkg-both-.ebuild || exit 1
+END
+cd ..
+
+
+mkdir -p repo9/{eclass,distfiles,profiles/profile} || exit 1
+mkdir -p repo9/{cat-one/pkg-one,cat-two/pkg-two} || exit 1
+cd repo9 || exit 1
+echo "test-repo-9" > profiles/repo_name || exit 1
+cat <<END >profiles/categories || exit 1
+cat-one
+cat-two
+END
+cat <<END >profiles/profile/make.defaults || exit 1
+ARCH=test
+USE="flag1 flag2 flag3 -flag4 -flag5"
+END
+cat <<END >profiles/profile/use.mask || exit 1
+flag2
+END
+cat <<END >profiles/profile/use.force || exit 1
+flag4
+END
+cat <<END >profiles/profile/package.use.mask || exit 1
+cat-two/pkg-two flag3
+>=cat-one/pkg-one-2 flag3
+END
+cat <<END >profiles/profile/package.use.force || exit 1
+cat-two/pkg-two flag5
+END
+cat <<END > cat-one/pkg-one/pkg-one-1.ebuild || exit 1
+END
+cat <<END > cat-one/pkg-one/pkg-one-2.ebuild || exit 1
+cat <<END > cat-two/pkg-two/pkg-two-1.ebuild || exit 1
+END
+cd ..
+
+mkdir -p repo10/{eclass,distfiles,profiles/profile/subprofile} || exit 1
+cd repo10 || exit 1
+echo "test-repo-10" > profiles/repo_name || exit 1
+cat <<END >profiles/profile/make.defaults || exit 1
+ARCH=test
+USE="flag1 flag2 flag3 -flag4 -flag5"
+END
+cat <<END >profiles/categories || exit 1
+cat
+END
+cat <<END >profiles/profile/package.mask
+cat/masked
+cat/was_masked
+END
+cat <<END >profiles/profile/subprofile/package.mask
+-cat/was_masked
+END
+cat <<END >profiles/profile/subprofile/parent
+..
+END
+cd ..
+
diff --git a/paludis/repositories/gentoo/portage_repository_entries.cc b/paludis/repositories/gentoo/portage_repository_entries.cc
new file mode 100644
index 0000000..6abed92
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_entries.cc
@@ -0,0 +1,43 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "portage_repository_entries.hh"
+#include "ebuild_entries.hh"
+
+using namespace paludis;
+
+PortageRepositoryEntries::PortageRepositoryEntries(const std::string & ext) :
+ _ext(ext)
+{
+}
+
+PortageRepositoryEntries::~PortageRepositoryEntries()
+{
+}
+
+NoSuchPortageRepositoryEntriesType::NoSuchPortageRepositoryEntriesType(const std::string & format) throw ():
+ ConfigurationError("No available maker for Portage repository entries type '" + format + "'")
+{
+}
+
+PortageRepositoryEntriesMaker::PortageRepositoryEntriesMaker()
+{
+ register_maker("ebuild", &EbuildEntries::make_ebuild_entries);
+}
+
diff --git a/paludis/repositories/gentoo/portage_repository_entries.hh b/paludis/repositories/gentoo/portage_repository_entries.hh
new file mode 100644
index 0000000..bb85424
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_entries.hh
@@ -0,0 +1,133 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_METADATA_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_METADATA_HH 1
+
+#include <paludis/name.hh>
+#include <paludis/repository.hh>
+#include <paludis/version_spec.hh>
+#include <paludis/version_metadata.hh>
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/virtual_constructor.hh>
+#include <paludis/repositories/gentoo/portage_repository_profile.hh>
+#include <paludis/repositories/gentoo/portage_repository_params.hh>
+#include <string>
+
+/** \file
+ * Declaration for the PortageRepositoryEntries class.
+ *
+ * \ingroup grpportagerepository
+ */
+
+namespace paludis
+{
+ class PortageRepository;
+ class Environment;
+
+ /**
+ * Handle entries (for example, ebuilds) in a PortageRepository.
+ *
+ * \ingroup grpportagerepository
+ * \nosubgrouping
+ */
+ class PALUDIS_VISIBLE PortageRepositoryEntries
+ {
+ private:
+ const std::string _ext;
+
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ /// Constructor, with our file extension
+ PortageRepositoryEntries(const std::string & ext);
+
+ ///\}
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ virtual ~PortageRepositoryEntries();
+
+ ///\}
+
+ /**
+ * Return our file extension, including the dot.
+ */
+ std::string file_extension() const
+ {
+ return _ext;
+ }
+
+ /**
+ * Generate version metadata.
+ */
+ virtual std::tr1::shared_ptr<VersionMetadata> generate_version_metadata(const QualifiedPackageName &,
+ const VersionSpec &) const = 0;
+
+ /**
+ * Fetch an environment variable.
+ */
+ virtual std::string get_environment_variable(const QualifiedPackageName &,
+ const VersionSpec &, const std::string & var,
+ std::tr1::shared_ptr<const PortageRepositoryProfile>) const = 0;
+
+ virtual void install(const QualifiedPackageName &, const VersionSpec &,
+ const InstallOptions &, std::tr1::shared_ptr<const PortageRepositoryProfile>) const = 0;
+ };
+
+ /**
+ * Thrown if a repository of the specified type does not exist.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grprepository
+ * \nosubgrouping
+ */
+ class PALUDIS_VISIBLE NoSuchPortageRepositoryEntriesType : public ConfigurationError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ NoSuchPortageRepositoryEntriesType(const std::string & format) throw ();
+ };
+
+ /**
+ * Virtual constructor for PortageRepositoryEntries.
+ *
+ * \ingroup grprepository
+ */
+ class PortageRepositoryEntriesMaker :
+ public VirtualConstructor<std::string,
+ std::tr1::shared_ptr<PortageRepositoryEntries> (*) (const Environment * const, PortageRepository * const,
+ const PortageRepositoryParams &),
+ virtual_constructor_not_found::ThrowException<NoSuchPortageRepositoryEntriesType> >,
+ public InstantiationPolicy<PortageRepositoryEntriesMaker, instantiation_method::SingletonTag>
+ {
+ friend class InstantiationPolicy<PortageRepositoryEntriesMaker, instantiation_method::SingletonTag>;
+
+ private:
+ PortageRepositoryEntriesMaker();
+ };
+
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/portage_repository_entry.cc b/paludis/repositories/gentoo/portage_repository_entry.cc
new file mode 100644
index 0000000..ea568cd
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_entry.cc
@@ -0,0 +1,32 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "portage_repository_metadata.hh"
+
+using namespace paludis;
+
+PortageRepositoryMetadata::PortageRepositoryMetadata(const std::string & ext) :
+ _ext(ext)
+{
+}
+
+PortageRepositoryMetadata::~PortageRepositoryMetadata()
+{
+}
+
diff --git a/paludis/repositories/gentoo/portage_repository_exceptions.cc b/paludis/repositories/gentoo/portage_repository_exceptions.cc
new file mode 100644
index 0000000..f8e1186
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_exceptions.cc
@@ -0,0 +1,29 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "portage_repository_exceptions.hh"
+
+using namespace paludis;
+
+PortageRepositoryConfigurationError::PortageRepositoryConfigurationError(
+ const std::string & msg) throw () :
+ ConfigurationError("Portage repository configuration error: " + msg)
+{
+}
+
diff --git a/paludis/repositories/gentoo/portage_repository_exceptions.hh b/paludis/repositories/gentoo/portage_repository_exceptions.hh
new file mode 100644
index 0000000..945182e
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_exceptions.hh
@@ -0,0 +1,53 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_EXCEPTIONS_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_EXCEPTIONS_HH 1
+
+#include <paludis/util/exception.hh>
+
+/** \file
+ * Declaration for the PortageRepository exception classes.
+ *
+ * \ingroup grpportagerepository
+ */
+
+namespace paludis
+{
+ /**
+ * Thrown if invalid parameters are provided for
+ * PortageRepository::make_portage_repository.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpportagerepository
+ */
+ class PALUDIS_VISIBLE PortageRepositoryConfigurationError :
+ public ConfigurationError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ PortageRepositoryConfigurationError(const std::string & msg) throw ();
+ };
+
+
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/portage_repository_news.cc b/paludis/repositories/gentoo/portage_repository_news.cc
new file mode 100644
index 0000000..4f89bac
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_news.cc
@@ -0,0 +1,284 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/repositories/gentoo/portage_repository.hh>
+#include <paludis/repositories/gentoo/portage_repository_news.hh>
+
+#include <paludis/config_file.hh>
+#include <paludis/environment.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/query.hh>
+
+#include <set>
+#include <ostream>
+#include <fstream>
+#include <list>
+
+using namespace paludis;
+
+namespace paludis
+{
+ /**
+ * Implementation data for PortageRepositoryNews.
+ *
+ * \ingroup grpportagerepository
+ */
+ template<>
+ struct Implementation<PortageRepositoryNews>
+ {
+ const Environment * const environment;
+ const PortageRepository * const portage_repository;
+ const PortageRepositoryParams params;
+
+ const FSEntry skip_file;
+ const FSEntry unread_file;
+
+ Implementation(const Environment * const e, const PortageRepository * const p,
+ const PortageRepositoryParams & k) :
+ environment(e),
+ portage_repository(p),
+ params(k),
+ skip_file(e->root() / "var" / "lib" / "paludis" / "news" /
+ ("news-" + stringify(portage_repository->name()) + ".skip")),
+ unread_file(e->root() / "var" / "lib" / "paludis" / "news" /
+ ("news-" + stringify(portage_repository->name()) + ".unread"))
+ {
+ }
+ };
+}
+
+PortageRepositoryNews::PortageRepositoryNews(const Environment * const e, const PortageRepository * const p,
+ const PortageRepositoryParams & k) :
+ PrivateImplementationPattern<PortageRepositoryNews>(new Implementation<PortageRepositoryNews>(e, p, k))
+{
+}
+
+PortageRepositoryNews::~PortageRepositoryNews()
+{
+}
+
+void
+PortageRepositoryNews::update_news() const
+{
+ Context context("When updating news at location '" +
+ stringify(_imp->params.newsdir) + "' for repository '" +
+ stringify(_imp->portage_repository->name()) + "':");
+
+ if (! _imp->params.newsdir.is_directory())
+ return;
+
+ std::set<std::string> skip;
+
+ if (_imp->skip_file.is_regular_file())
+ {
+ Context local_context("When handling news skip file '" + stringify(
+ _imp->skip_file) + "':");
+ LineConfigFile s(_imp->skip_file);
+ std::copy(s.begin(), s.end(), std::inserter(skip, skip.end()));
+ }
+
+ for (DirIterator d(_imp->params.newsdir), d_end ; d != d_end ; ++d)
+ {
+ Context local_context("When handling news entry '" + stringify(*d) + "':");
+
+ if (! d->is_directory())
+ continue;
+ if (! (*d / (d->basename() + ".en.txt")).is_regular_file())
+ continue;
+
+ if (skip.end() != skip.find(d->basename()))
+ continue;
+
+ try
+ {
+ NewsFile news(*d / (d->basename() + ".en.txt"));
+ bool show(true);
+
+ if (news.begin_display_if_installed() != news.end_display_if_installed())
+ {
+ bool local_show(false);
+ for (NewsFile::DisplayIfInstalledIterator i(news.begin_display_if_installed()),
+ i_end(news.end_display_if_installed()) ; i != i_end ; ++i)
+ if (! _imp->environment->package_database()->query(
+ query::Package(*i) & query::RepositoryHasInstalledInterface(),
+ qo_whatever)->empty())
+ local_show = true;
+ show &= local_show;
+ }
+
+ if (news.begin_display_if_keyword() != news.end_display_if_keyword())
+ {
+ bool local_show(false);
+ for (NewsFile::DisplayIfKeywordIterator i(news.begin_display_if_keyword()),
+ i_end(news.end_display_if_keyword()) ; i != i_end && ! local_show ; ++i)
+ if (*i == _imp->portage_repository->profile_variable("ARCH"))
+ local_show = true;
+ show &= local_show;
+ }
+
+ if (news.begin_display_if_profile() != news.end_display_if_profile())
+ {
+ bool local_show(false);
+ std::tr1::shared_ptr<const FSEntryCollection> c(_imp->params.profiles);
+ for (FSEntryCollection::Iterator p(c->begin()), p_end(c->end()) ; p != p_end ; ++p)
+ {
+ std::string profile(strip_leading_string(strip_trailing_string(
+ strip_leading_string(stringify(p->realpath()),
+ stringify(p->realpath())), "/"), "/"));
+ Log::get_instance()->message(ll_debug, lc_no_context,
+ "Profile path is '" + profile + "'");
+ for (NewsFile::DisplayIfProfileIterator i(news.begin_display_if_profile()),
+ i_end(news.end_display_if_profile()) ; i != i_end ; ++i)
+ if (profile == *i)
+ local_show = true;
+ }
+ show &= local_show;
+ }
+
+ if (show)
+ {
+ std::ofstream s(stringify(_imp->skip_file).c_str(),
+ std::ios::out | std::ios::app);
+ if (! s)
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "Cannot append to news skip file '"
+ + stringify(_imp->skip_file) +
+ "', skipping news item '" + stringify(*d) + "'");
+
+ std::ofstream t(stringify(_imp->unread_file).c_str(),
+ std::ios::out | std::ios::app);
+ if (! t)
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "Cannot append to unread file '"
+ + stringify(_imp->unread_file) +
+ "', skipping news item '" + stringify(*d) + "'");
+
+ if (s && t)
+ {
+ s << d->basename() << std::endl;
+ t << d->basename() << std::endl;
+ }
+ }
+ }
+ catch (const ConfigFileError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "Skipping news item '"
+ + stringify(*d) + "' because of exception '" + e.message() + "' ("
+ + e.what() + ")");
+ }
+ }
+
+}
+
+namespace paludis
+{
+ /**
+ * Implementation data for NewsFile.
+ *
+ * \ingroup grpnewsconfigfile
+ */
+ template<>
+ struct Implementation<NewsFile>
+ {
+ mutable bool in_header;
+ mutable std::list<std::string> display_if_installed;
+ mutable std::list<std::string> display_if_keyword;
+ mutable std::list<std::string> display_if_profile;
+
+ Implementation() :
+ in_header(true)
+ {
+ }
+ };
+}
+
+NewsFile::NewsFile(const FSEntry & our_filename) :
+ ConfigFile(our_filename),
+ PrivateImplementationPattern<NewsFile>(new Implementation<NewsFile>)
+{
+ need_lines();
+}
+
+NewsFile::~NewsFile()
+{
+}
+
+void
+NewsFile::accept_line(const std::string & line) const
+{
+ if (_imp->in_header)
+ {
+ std::string::size_type p(line.find(':'));
+ if (std::string::npos == p)
+ _imp->in_header = false;
+ else
+ {
+ std::string k(strip_leading(strip_trailing(line.substr(0, p), " \t\n"), " \t\n"));
+ std::string v(strip_leading(strip_trailing(line.substr(p + 1), " \t\n"), " \t\n"));
+ if (k == "Display-If-Installed")
+ _imp->display_if_installed.push_back(v);
+ else if (k == "Display-If-Keyword")
+ _imp->display_if_keyword.push_back(v);
+ if (k == "Display-If-Profile")
+ _imp->display_if_profile.push_back(v);
+ }
+ }
+}
+
+NewsFile::DisplayIfInstalledIterator
+NewsFile::begin_display_if_installed() const
+{
+ return DisplayIfInstalledIterator(_imp->display_if_installed.begin());
+}
+
+NewsFile::DisplayIfInstalledIterator
+NewsFile::end_display_if_installed() const
+{
+ return DisplayIfInstalledIterator(_imp->display_if_installed.end());
+}
+
+NewsFile::DisplayIfKeywordIterator
+NewsFile::begin_display_if_keyword() const
+{
+ return DisplayIfKeywordIterator(_imp->display_if_keyword.begin());
+}
+
+NewsFile::DisplayIfKeywordIterator
+NewsFile::end_display_if_keyword() const
+{
+ return DisplayIfKeywordIterator(_imp->display_if_keyword.end());
+}
+
+NewsFile::DisplayIfProfileIterator
+NewsFile::begin_display_if_profile() const
+{
+ return DisplayIfProfileIterator(_imp->display_if_profile.begin());
+}
+
+NewsFile::DisplayIfProfileIterator
+NewsFile::end_display_if_profile() const
+{
+ return DisplayIfProfileIterator(_imp->display_if_profile.end());
+}
+
+
diff --git a/paludis/repositories/gentoo/portage_repository_news.hh b/paludis/repositories/gentoo/portage_repository_news.hh
new file mode 100644
index 0000000..bd1b67d
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_news.hh
@@ -0,0 +1,135 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_NEWS_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_NEWS_HH 1
+
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/config_file.hh>
+
+/** \file
+ * Declaration for the PortageRepositoryNews class.
+ *
+ * \ingroup grpportagerepository
+ */
+
+namespace paludis
+{
+ class Environment;
+ class FSEntry;
+ class PortageRepository;
+
+ /**
+ * Holds the news/ data for a PortageRepository instance.
+ *
+ * \ingroup grpportagerepository
+ * \nosubgrouping
+ */
+ class PALUDIS_VISIBLE PortageRepositoryNews :
+ private PrivateImplementationPattern<PortageRepositoryNews>,
+ private InstantiationPolicy<PortageRepositoryNews, instantiation_method::NonCopyableTag>
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ PortageRepositoryNews(const Environment * const, const PortageRepository * const,
+ const PortageRepositoryParams &);
+ ~PortageRepositoryNews();
+
+ ///\}
+
+ void update_news() const;
+ };
+
+ /**
+ * A NewsFile represents a GLEP 42 news file.
+ *
+ * \ingroup grpnewsconfigfile
+ * \nosubgrouping
+ */
+ class PALUDIS_VISIBLE NewsFile :
+ protected ConfigFile,
+ private PrivateImplementationPattern<NewsFile>
+ {
+ protected:
+ void accept_line(const std::string &) const;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ /**
+ * Constructor, from a filename.
+ */
+ NewsFile(const FSEntry & filename);
+
+ ~NewsFile();
+
+ ///\}
+
+ ///\name Iterate over our Display-If-Installed headers
+ ///\{
+
+ /// Tag for DisplayIfInstalledIterator.
+ struct DisplayIfInstalledIteratorTag;
+
+ typedef libwrapiter::ForwardIterator<DisplayIfInstalledIteratorTag,
+ const std::string> DisplayIfInstalledIterator;
+
+ DisplayIfInstalledIterator begin_display_if_installed() const;
+
+ DisplayIfInstalledIterator end_display_if_installed() const;
+
+ ///\}
+
+ ///\name Iterate over our Display-If-Keyword headers
+ ///\{
+
+ /// Tag for DisplayIfKeywordIterator.
+ struct DisplayIfKeywordIteratorTag;
+
+ typedef libwrapiter::ForwardIterator<DisplayIfKeywordIteratorTag,
+ const std::string> DisplayIfKeywordIterator;
+
+ DisplayIfKeywordIterator begin_display_if_keyword() const;
+
+ DisplayIfKeywordIterator end_display_if_keyword() const;
+
+ ///\}
+
+ ///\name Iterate over our Display-If-Profile headers
+ ///\{
+
+ /// Tag for DisplayIfProfileIterator.
+ struct DisplayIfProfileIteratorTag;
+
+ typedef libwrapiter::ForwardIterator<DisplayIfProfileIteratorTag,
+ const std::string> DisplayIfProfileIterator;
+
+ DisplayIfProfileIterator begin_display_if_profile() const;
+
+ DisplayIfProfileIterator end_display_if_profile() const;
+
+ ///\}
+ };
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/portage_repository_params.cc b/paludis/repositories/gentoo/portage_repository_params.cc
new file mode 100644
index 0000000..eebc8f6
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_params.cc
@@ -0,0 +1,8 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "portage_repository_params.hh"
+
+using namespace paludis;
+
+#include <paludis/repositories/gentoo/portage_repository_params-sr.cc>
+
diff --git a/paludis/repositories/gentoo/portage_repository_params.hh b/paludis/repositories/gentoo/portage_repository_params.hh
new file mode 100644
index 0000000..cfb9053
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_params.hh
@@ -0,0 +1,43 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_PARAMS_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_PARAMS_HH 1
+
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/collection.hh>
+#include <paludis/util/sr.hh>
+
+/** \file
+ * Declaration for the PortageRepositoryParams class.
+ *
+ * \ingroup grpportagerepository
+ */
+
+namespace paludis
+{
+ class Environment;
+ class PackageDatabase;
+ class PortageRepository;
+
+#include <paludis/repositories/gentoo/portage_repository_params-sr.hh>
+
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/portage_repository_params.sr b/paludis/repositories/gentoo/portage_repository_params.sr
new file mode 100644
index 0000000..e741dc6
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_params.sr
@@ -0,0 +1,36 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+make_class_PortageRepositoryParams()
+{
+ key entry_format std::string
+ key environment "Environment *"
+ key location FSEntry
+ key profiles "std::tr1::shared_ptr<const FSEntryCollection>"
+ key cache FSEntry
+ key write_cache FSEntry
+ key names_cache FSEntry
+ key distdir FSEntry
+ key pkgdir FSEntry
+ key eclassdirs "std::tr1::shared_ptr<const FSEntryCollection>"
+ key setsdir FSEntry
+ key securitydir FSEntry
+ key newsdir FSEntry
+ key sync std::string
+ key sync_options std::string
+ key buildroot FSEntry
+ key master_repository "std::tr1::shared_ptr<const PortageRepository>"
+
+ doxygen_comment << "END"
+ /**
+ * Parameters used to create a PortageRepository
+ *
+ * \see PortageRepository
+ * \ingroup grpportagerepository
+ * \nosubgrouping
+ */
+END
+
+ allow_named_args
+}
+
diff --git a/paludis/repositories/gentoo/portage_repository_profile.cc b/paludis/repositories/gentoo/portage_repository_profile.cc
new file mode 100644
index 0000000..84b976f
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_profile.cc
@@ -0,0 +1,715 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/repositories/gentoo/portage_repository_profile.hh>
+#include <paludis/repositories/gentoo/portage_repository_profile_file.hh>
+#include <paludis/repositories/gentoo/portage_repository_exceptions.hh>
+
+#include <paludis/util/log.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/iterator.hh>
+#include <paludis/util/save.hh>
+
+#include <paludis/config_file.hh>
+#include <paludis/environment.hh>
+#include <paludis/match_package.hh>
+#include <paludis/hashed_containers.hh>
+
+#include <list>
+#include <algorithm>
+#include <set>
+
+#include <strings.h>
+#include <ctype.h>
+
+using namespace paludis;
+
+namespace
+{
+ typedef MakeHashedSet<UseFlagName>::Type UseFlagSet;
+ typedef MakeHashedMap<std::string, std::string>::Type EnvironmentVariablesMap;
+ typedef MakeHashedMap<QualifiedPackageName, std::tr1::shared_ptr<const PackageDepAtom> >::Type VirtualsMap;
+ typedef MakeHashedMap<QualifiedPackageName, std::list<std::tr1::shared_ptr<const PackageDepAtom> > >::Type PackageMaskMap;
+
+ typedef MakeHashedMap<UseFlagName, bool>::Type FlagStatusMap;
+ typedef std::list<std::pair<std::tr1::shared_ptr<const PackageDepAtom>, FlagStatusMap> > PackageFlagStatusMapList;
+
+ struct StackedValues
+ {
+ std::string origin;
+
+ FlagStatusMap use_mask;
+ FlagStatusMap use_force;
+ PackageFlagStatusMapList package_use;
+ PackageFlagStatusMapList package_use_mask;
+ PackageFlagStatusMapList package_use_force;
+
+ StackedValues(const std::string & o) :
+ origin(o)
+ {
+ }
+ };
+
+ typedef std::list<StackedValues> StackedValuesList;
+}
+
+namespace paludis
+{
+ /**
+ * Implementation for PortageRepositoryProfile.
+ *
+ * \ingroup grpportagerepository
+ * \see PortageRepositoryProfile
+ */
+ template<>
+ class Implementation<PortageRepositoryProfile>
+ {
+ private:
+ void load_profile_directory_recursively(const FSEntry & dir);
+ void load_profile_parent(const FSEntry & dir);
+ void load_profile_make_defaults(const FSEntry & dir);
+
+ void load_basic_use_file(const FSEntry & file, FlagStatusMap & m);
+ void load_atom_use_file(const FSEntry & file, PackageFlagStatusMapList & m);
+
+ void add_use_expand_to_use();
+ void make_vars_from_file_vars();
+ void handle_profile_arch_var();
+ void load_special_make_defaults_vars();
+
+ ProfileFile packages_file;
+ ProfileFile virtuals_file;
+ ProfileFile package_mask_file;
+
+ bool is_incremental(const std::string & s) const;
+
+
+ public:
+ ///\name General variables
+ ///\{
+
+ const Environment * const env;
+
+ ///\}
+
+ ///\name Environment variables
+ ///\{
+
+ EnvironmentVariablesMap environment_variables;
+
+ ///\}
+
+ ///\name System package set
+ ///\{
+
+ std::tr1::shared_ptr<AllDepAtom> system_packages;
+ std::tr1::shared_ptr<GeneralSetDepTag> system_tag;
+
+ ///\}
+
+ ///\name Virtuals
+ ///\{
+
+ VirtualsMap virtuals;
+
+ ///\}
+
+ ///\name USE related values
+ ///\{
+
+ UseFlagSet use;
+ UseFlagSet use_expand;
+ UseFlagSet use_expand_hidden;
+ StackedValuesList stacked_values_list;
+
+ ///\}
+
+ ///\name Masks
+ ///\{
+
+ PackageMaskMap package_mask;
+
+ ///\}
+
+ ///\name Basic operations
+ ///\{
+
+ Implementation(const Environment * const e, const RepositoryName & name,
+ const FSEntryCollection & dirs) :
+ env(e),
+ system_packages(new AllDepAtom),
+ system_tag(new GeneralSetDepTag(SetName("system"), stringify(name)))
+ {
+ for (FSEntryCollection::Iterator d(dirs.begin()), d_end(dirs.end()) ;
+ d != d_end ; ++d)
+ load_profile_directory_recursively(*d);
+
+ make_vars_from_file_vars();
+ load_special_make_defaults_vars();
+ add_use_expand_to_use();
+ handle_profile_arch_var();
+ }
+
+ ~Implementation()
+ {
+ }
+
+ ///\}
+ };
+}
+
+void
+Implementation<PortageRepositoryProfile>::load_profile_directory_recursively(const FSEntry & dir)
+{
+ Context context("When adding profile directory '" + stringify(dir) + ":");
+ Log::get_instance()->message(ll_debug, lc_context, "Loading profile directory '" + stringify(dir) + "'");
+
+ if (! dir.is_directory())
+ {
+ Log::get_instance()->message(ll_warning, lc_context,
+ "Profile component '" + stringify(dir) + "' is not a directory");
+ return;
+ }
+
+ stacked_values_list.push_back(StackedValues(stringify(dir)));
+
+ load_profile_parent(dir);
+ load_profile_make_defaults(dir);
+
+ load_basic_use_file(dir / "use.mask", stacked_values_list.back().use_mask);
+ load_basic_use_file(dir / "use.force", stacked_values_list.back().use_force);
+ load_atom_use_file(dir / "package.use", stacked_values_list.back().package_use);
+ load_atom_use_file(dir / "package.use.mask", stacked_values_list.back().package_use_mask);
+ load_atom_use_file(dir / "package.use.force", stacked_values_list.back().package_use_force);
+
+ packages_file.add_file(dir / "packages");
+ virtuals_file.add_file(dir / "virtuals");
+ package_mask_file.add_file(dir / "package.mask");
+}
+
+void
+Implementation<PortageRepositoryProfile>::load_profile_parent(const FSEntry & dir)
+{
+ Context context("When handling parent file for profile directory '" + stringify(dir) + ":");
+
+ if (! (dir / "parent").exists())
+ return;
+
+ LineConfigFile file(dir / "parent");
+
+ LineConfigFile::Iterator i(file.begin()), i_end(file.end());
+ if (i == i_end)
+ Log::get_instance()->message(ll_warning, lc_context, "parent file is empty");
+ else
+ for ( ; i != i_end ; ++i)
+ {
+ FSEntry parent_dir(dir);
+ do
+ {
+ try
+ {
+ parent_dir = (parent_dir / *i).realpath();
+ }
+ catch (const FSError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Skipping parent '"
+ + *i + "' due to exception: " + e.message() + " (" + e.what() + ")");
+ continue;
+ }
+
+ load_profile_directory_recursively(parent_dir);
+
+ } while (false);
+ }
+}
+
+void
+Implementation<PortageRepositoryProfile>::load_profile_make_defaults(const FSEntry & dir)
+{
+ Context context("When handling make.defaults file for profile directory '" + stringify(dir) + ":");
+
+ if (! (dir / "make.defaults").exists())
+ return;
+
+ KeyValueConfigFile file(dir / "make.defaults");
+
+ for (KeyValueConfigFile::Iterator k(file.begin()), k_end(file.end()) ;
+ k != k_end ; ++k)
+ {
+ if (is_incremental(k->first))
+ {
+ std::list<std::string> val, val_add;
+ WhitespaceTokeniser::get_instance()->tokenise(environment_variables[k->first], std::back_inserter(val));
+ WhitespaceTokeniser::get_instance()->tokenise(k->second, std::back_inserter(val_add));
+
+ for (std::list<std::string>::const_iterator v(val_add.begin()), v_end(val_add.end()) ;
+ v != v_end ; ++v)
+ {
+ if (v->empty())
+ continue;
+ if (*v == "-*")
+ val.clear();
+ else if ('-' == v->at(0))
+ val.remove(v->substr(1));
+ else
+ val.push_back(*v);
+ }
+
+ environment_variables[k->first] = join(val.begin(), val.end(), " ");
+ }
+ else
+ environment_variables[k->first] = k->second;
+
+ Log::get_instance()->message(ll_debug, lc_context, "Profile environment variable '" +
+ stringify(k->first) + "' is now '" + stringify(environment_variables[k->first]) + "'");
+ }
+
+ try
+ {
+ use_expand.clear();
+ WhitespaceTokeniser::get_instance()->tokenise(environment_variables["USE_EXPAND"],
+ create_inserter<UseFlagName>(std::inserter(use_expand, use_expand.end())));
+ }
+ catch (const NameError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Loading USE_EXPAND failed due to exception: "
+ + e.message() + " (" + e.what() + ")");
+ }
+}
+
+void
+Implementation<PortageRepositoryProfile>::load_special_make_defaults_vars()
+{
+ try
+ {
+ use.clear();
+ WhitespaceTokeniser::get_instance()->tokenise(environment_variables["USE"],
+ create_inserter<UseFlagName>(std::inserter(use, use.end())));
+ }
+ catch (const NameError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Loading USE failed due to exception: "
+ + e.message() + " (" + e.what() + ")");
+ }
+
+ try
+ {
+ use_expand.clear();
+ WhitespaceTokeniser::get_instance()->tokenise(environment_variables["USE_EXPAND"],
+ create_inserter<UseFlagName>(std::inserter(use_expand, use_expand.end())));
+ }
+ catch (const NameError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Loading USE_EXPAND failed due to exception: "
+ + e.message() + " (" + e.what() + ")");
+ }
+ try
+ {
+ use_expand_hidden.clear();
+ WhitespaceTokeniser::get_instance()->tokenise(environment_variables["USE_EXPAND_HIDDEN"],
+ create_inserter<UseFlagName>(std::inserter(use_expand_hidden, use_expand_hidden.end())));
+ }
+ catch (const NameError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Loading USE_EXPAND_HIDDEN failed due to exception: "
+ + e.message() + " (" + e.what() + ")");
+ }
+}
+
+bool
+Implementation<PortageRepositoryProfile>::is_incremental(const std::string & s) const
+{
+ try
+ {
+ return (s == "USE") || (s == "USE_EXPAND") || (s == "USE_EXPAND_HIDDEN")
+ || (s == "CONFIG_PROTECT") || (s == "CONFIG_PROTECT_MASK")
+ || (use_expand.end() != use_expand.find(UseFlagName(s)));
+ }
+ catch (const NameError &)
+ {
+ return (s == "USE") || (s == "USE_EXPAND") || (s == "USE_EXPAND_HIDDEN")
+ || (s == "CONFIG_PROTECT") || (s == "CONFIG_PROTECT_MASK");
+ }
+}
+
+void
+Implementation<PortageRepositoryProfile>::make_vars_from_file_vars()
+{
+ try
+ {
+ for (ProfileFile::Iterator i(packages_file.begin()), i_end(packages_file.end()) ; i != i_end ; ++i)
+ {
+ if (0 != i->compare(0, 1, "*", 0, 1))
+ continue;
+
+ Context context_atom("When parsing '" + *i + "':");
+ std::tr1::shared_ptr<PackageDepAtom> atom(new PackageDepAtom(i->substr(1)));
+ atom->set_tag(system_tag);
+ system_packages->add_child(atom);
+ }
+ }
+ catch (const NameError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Loading packages "
+ " failed due to exception: " + e.message() + " (" + e.what() + ")");
+ }
+
+ try
+ {
+ for (ProfileFile::Iterator line(virtuals_file.begin()), line_end(virtuals_file.end()) ;
+ line != line_end ; ++line)
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens));
+ if (tokens.size() < 2)
+ continue;
+
+ QualifiedPackageName v(tokens[0]);
+ virtuals.erase(v);
+ virtuals.insert(std::make_pair(v, std::tr1::shared_ptr<PackageDepAtom>(new PackageDepAtom(tokens[1]))));
+ }
+ }
+ catch (const NameError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Loading virtuals "
+ " failed due to exception: " + e.message() + " (" + e.what() + ")");
+ }
+
+ for (ProfileFile::Iterator line(package_mask_file.begin()), line_end(package_mask_file.end()) ;
+ line != line_end ; ++line)
+ {
+ if (line->empty())
+ continue;
+
+ try
+ {
+ std::tr1::shared_ptr<const PackageDepAtom> a(new PackageDepAtom(*line));
+ package_mask[a->package()].push_back(a);
+ }
+ catch (const NameError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Loading package.mask atom '"
+ + stringify(*line) + "' failed due to exception '" + e.message() + "' ("
+ + e.what() + ")");
+ }
+ }
+}
+
+void
+Implementation<PortageRepositoryProfile>::load_basic_use_file(const FSEntry & file, FlagStatusMap & m)
+{
+ if (! file.exists())
+ return;
+
+ Context context("When loading basic use file '" + stringify(file) + ":");
+ LineConfigFile f(file);
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ;
+ line != line_end ; ++line)
+ {
+ std::list<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens));
+
+ for (std::list<std::string>::const_iterator t(tokens.begin()), t_end(tokens.end()) ;
+ t != t_end ; ++t)
+ {
+ try
+ {
+ if (t->empty())
+ continue;
+ if ('-' == t->at(0))
+ m[UseFlagName(t->substr(1))] = false;
+ else
+ m[UseFlagName(*t)] = true;
+ }
+ catch (const NameError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Ignoring token '"
+ + *t + "' due to exception '" + e.message() + "' (" + e.what() + ")");
+ }
+ }
+ }
+}
+
+void
+Implementation<PortageRepositoryProfile>::load_atom_use_file(const FSEntry & file, PackageFlagStatusMapList & m)
+{
+ if (! file.exists())
+ return;
+
+ Context context("When loading atomised use file '" + stringify(file) + ":");
+ LineConfigFile f(file);
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ;
+ line != line_end ; ++line)
+ {
+ std::list<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens));
+
+ if (tokens.empty())
+ continue;
+
+ try
+ {
+ std::tr1::shared_ptr<const PackageDepAtom> atom(new PackageDepAtom(*tokens.begin()));
+ PackageFlagStatusMapList::iterator n(m.insert(m.end(), std::make_pair(atom, FlagStatusMap())));
+
+ for (std::list<std::string>::const_iterator t(next(tokens.begin())), t_end(tokens.end()) ;
+ t != t_end ; ++t)
+ {
+ try
+ {
+ if (t->empty())
+ continue;
+ if ('-' == t->at(0))
+ n->second[UseFlagName(t->substr(1))] = false;
+ else
+ n->second[UseFlagName(*t)] = true;
+ }
+ catch (const NameError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Ignoring token '"
+ + *t + "' due to exception '" + e.message() + "' (" + e.what() + ")");
+ }
+ }
+ }
+ catch (const PackageDepAtomError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Ignoring line '"
+ + *line + "' due to exception '" + e.message() + "' (" + e.what() + ")");
+ }
+ }
+}
+
+void
+Implementation<PortageRepositoryProfile>::add_use_expand_to_use()
+{
+ Context context("When adding USE_EXPAND to USE:");
+
+ stacked_values_list.push_back(StackedValues("use_expand special values"));
+
+ for (UseFlagSet::const_iterator x(use_expand.begin()), x_end(use_expand.end()) ;
+ x != x_end ; ++x)
+ {
+ std::string lower_x;
+ std::transform(x->data().begin(), x->data().end(), std::back_inserter(lower_x),
+ &::tolower);
+
+ std::list<std::string> uses;
+ WhitespaceTokeniser::get_instance()->tokenise(environment_variables[stringify(*x)],
+ std::back_inserter(uses));
+ for (std::list<std::string>::const_iterator u(uses.begin()), u_end(uses.end()) ;
+ u != u_end ; ++u)
+ use.insert(UseFlagName(lower_x + "_" + *u));
+ }
+}
+
+void
+Implementation<PortageRepositoryProfile>::handle_profile_arch_var()
+{
+ Context context("When handling profile ARCH variable:");
+
+ std::string arch_s(environment_variables["ARCH"]);
+ if (arch_s.empty())
+ throw PortageRepositoryConfigurationError("ARCH variable is unset or empty");
+
+ stacked_values_list.push_back(StackedValues("arch special values"));
+ try
+ {
+ UseFlagName arch(arch_s);
+
+ use.insert(arch);
+ stacked_values_list.back().use_force[arch] = true;
+ }
+ catch (const NameError &)
+ {
+ throw PortageRepositoryConfigurationError("ARCH variable has invalid value '" + arch_s + "'");
+ }
+}
+
+PortageRepositoryProfile::PortageRepositoryProfile(
+ const Environment * const env, const RepositoryName & name, const FSEntryCollection & location) :
+ PrivateImplementationPattern<PortageRepositoryProfile>(
+ new Implementation<PortageRepositoryProfile>(env, name, location))
+{
+}
+
+PortageRepositoryProfile::~PortageRepositoryProfile()
+{
+}
+
+bool
+PortageRepositoryProfile::use_masked(const UseFlagName & u,
+ const PackageDatabaseEntry * const e) const
+{
+ bool result(false);
+ for (StackedValuesList::const_iterator i(_imp->stacked_values_list.begin()),
+ i_end(_imp->stacked_values_list.end()) ; i != i_end ; ++i)
+ {
+ FlagStatusMap::const_iterator f(i->use_mask.find(u));
+ if (i->use_mask.end() != f)
+ result = f->second;
+
+ if (e)
+ for (PackageFlagStatusMapList::const_iterator g(i->package_use_mask.begin()),
+ g_end(i->package_use_mask.end()) ; g != g_end ; ++g)
+ {
+ if (! match_package(*_imp->env, *g->first, *e))
+ continue;
+
+ FlagStatusMap::const_iterator h(g->second.find(u));
+ if (g->second.end() != h)
+ result = h->second;
+ }
+ }
+
+ return result;
+}
+
+bool
+PortageRepositoryProfile::use_forced(const UseFlagName & u,
+ const PackageDatabaseEntry * const e) const
+{
+ bool result(false);
+ for (StackedValuesList::const_iterator i(_imp->stacked_values_list.begin()),
+ i_end(_imp->stacked_values_list.end()) ; i != i_end ; ++i)
+ {
+ FlagStatusMap::const_iterator f(i->use_force.find(u));
+ if (i->use_force.end() != f)
+ result = f->second;
+
+ if (e)
+ for (PackageFlagStatusMapList::const_iterator g(i->package_use_force.begin()),
+ g_end(i->package_use_force.end()) ; g != g_end ; ++g)
+ {
+ if (! match_package(*_imp->env, *g->first, *e))
+ continue;
+
+ FlagStatusMap::const_iterator h(g->second.find(u));
+ if (g->second.end() != h)
+ result = h->second;
+ }
+ }
+
+ return result;
+}
+
+UseFlagState
+PortageRepositoryProfile::use_state_ignoring_masks(const UseFlagName & u,
+ const PackageDatabaseEntry * const e) const
+{
+ UseFlagState result(use_unspecified);
+
+ result = _imp->use.end() != _imp->use.find(u) ? use_enabled : use_unspecified;
+
+ for (StackedValuesList::const_iterator i(_imp->stacked_values_list.begin()),
+ i_end(_imp->stacked_values_list.end()) ; i != i_end ; ++i)
+ {
+ if (e)
+ for (PackageFlagStatusMapList::const_iterator g(i->package_use.begin()),
+ g_end(i->package_use.end()) ; g != g_end ; ++g)
+ {
+ if (! match_package(*_imp->env, *g->first, *e))
+ continue;
+
+ FlagStatusMap::const_iterator h(g->second.find(u));
+ if (g->second.end() != h)
+ result = h->second ? use_enabled : use_disabled;
+ }
+ }
+
+ return result;
+}
+
+std::string
+PortageRepositoryProfile::environment_variable(const std::string & s) const
+{
+ EnvironmentVariablesMap::const_iterator i(_imp->environment_variables.find(s));
+ if (_imp->environment_variables.end() == i)
+ {
+ Log::get_instance()->message(ll_debug, lc_no_context, "Environment variable '" + s + "' is unset");
+ return "";
+ }
+ else
+ {
+ Log::get_instance()->message(ll_debug, lc_no_context, "Environment variable '" + s +
+ "' is '" + i->second + "'");
+ return i->second;
+ }
+}
+
+std::tr1::shared_ptr<AllDepAtom>
+PortageRepositoryProfile::system_packages() const
+{
+ return _imp->system_packages;
+}
+
+PortageRepositoryProfile::UseExpandIterator
+PortageRepositoryProfile::begin_use_expand() const
+{
+ return UseExpandIterator(_imp->use_expand.begin());
+}
+
+PortageRepositoryProfile::UseExpandIterator
+PortageRepositoryProfile::end_use_expand() const
+{
+ return UseExpandIterator(_imp->use_expand.end());
+}
+
+PortageRepositoryProfile::UseExpandIterator
+PortageRepositoryProfile::begin_use_expand_hidden() const
+{
+ return UseExpandIterator(_imp->use_expand_hidden.begin());
+}
+
+PortageRepositoryProfile::UseExpandIterator
+PortageRepositoryProfile::end_use_expand_hidden() const
+{
+ return UseExpandIterator(_imp->use_expand_hidden.end());
+}
+
+PortageRepositoryProfile::VirtualsIterator
+PortageRepositoryProfile::begin_virtuals() const
+{
+ return VirtualsIterator(_imp->virtuals.begin());
+}
+
+PortageRepositoryProfile::VirtualsIterator
+PortageRepositoryProfile::end_virtuals() const
+{
+ return VirtualsIterator(_imp->virtuals.end());
+}
+
+bool
+PortageRepositoryProfile::profile_masked(const QualifiedPackageName & n,
+ const VersionSpec & v, const RepositoryName & r) const
+{
+ PackageMaskMap::const_iterator rr(_imp->package_mask.find(n));
+ if (_imp->package_mask.end() == rr)
+ return false;
+ else
+ {
+ PackageDatabaseEntry dbe(n, v, r);
+ for (std::list<std::tr1::shared_ptr<const PackageDepAtom> >::const_iterator k(rr->second.begin()),
+ k_end(rr->second.end()) ; k != k_end ; ++k)
+ if (match_package(*_imp->env, **k, dbe))
+ return true;
+ }
+
+ return false;
+}
+
diff --git a/paludis/repositories/gentoo/portage_repository_profile.hh b/paludis/repositories/gentoo/portage_repository_profile.hh
new file mode 100644
index 0000000..e914b0a
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_profile.hh
@@ -0,0 +1,127 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_PROFILE_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_PROFILE_HH 1
+
+#include <paludis/dep_atom.hh>
+#include <paludis/package_database_entry.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/instantiation_policy.hh>
+
+#include <libwrapiter/libwrapiter_forward_iterator.hh>
+#include <string>
+
+/** \file
+ * Declaration for the PortageRepositoryProfile class.
+ *
+ * \ingroup grpportagerepository
+ */
+
+namespace paludis
+{
+ class Environment;
+
+ /**
+ * Holds the profile data (but <em>not</em> the profiles/ top level data) for
+ * a PortageRepository instance.
+ *
+ * \ingroup grpportagerepository
+ * \nosubgrouping
+ */
+ class PALUDIS_VISIBLE PortageRepositoryProfile :
+ private PrivateImplementationPattern<PortageRepositoryProfile>,
+ private InstantiationPolicy<PortageRepositoryProfile, instantiation_method::NonCopyableTag>
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ PortageRepositoryProfile(const Environment * const env,
+ const RepositoryName & name,
+ const FSEntryCollection & location);
+ ~PortageRepositoryProfile();
+
+ ///\}
+
+ ///\name Use flag queries
+ ///\{
+
+ /// Is a use flag masked?
+ bool use_masked(const UseFlagName &, const PackageDatabaseEntry * const) const;
+
+ /// Is a use flag forced?
+ bool use_forced(const UseFlagName &, const PackageDatabaseEntry * const) const;
+
+ /// Use flag state, ignoring mask and force?
+ UseFlagState use_state_ignoring_masks(const UseFlagName &, const PackageDatabaseEntry * const) const;
+
+ ///\}
+
+ ///\name Iterate over USE_EXPAND, USE_EXPAND_HIDDEN
+ ///\{
+
+ typedef libwrapiter::ForwardIterator<PortageRepositoryProfile, const UseFlagName> UseExpandIterator;
+
+ UseExpandIterator begin_use_expand() const;
+ UseExpandIterator end_use_expand() const;
+ UseExpandIterator begin_use_expand_hidden() const;
+ UseExpandIterator end_use_expand_hidden() const;
+
+ ///\}
+
+ ///\name Environment variable queries
+ ///\{
+
+ /// What is the value of an environment variable?
+ std::string environment_variable(const std::string &) const;
+
+ ///\}
+
+ ///\name Masks
+ ///\{
+
+ bool profile_masked(const QualifiedPackageName &, const VersionSpec &,
+ const RepositoryName &) const;
+
+ ///\}
+
+ ///\name System package set
+ ///\{
+
+ std::tr1::shared_ptr<AllDepAtom> system_packages() const;
+
+ ///\}
+
+ ///\name Virtuals
+ ///\{
+
+ typedef libwrapiter::ForwardIterator<PortageRepositoryProfile,
+ const std::pair<const QualifiedPackageName, std::tr1::shared_ptr<const PackageDepAtom> > > VirtualsIterator;
+
+ VirtualsIterator begin_virtuals() const;
+ VirtualsIterator end_virtuals() const;
+ VirtualsIterator find_virtual() const;
+
+ ///\}
+ };
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/portage_repository_profile_file.cc b/paludis/repositories/gentoo/portage_repository_profile_file.cc
new file mode 100644
index 0000000..04fa13a
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_profile_file.cc
@@ -0,0 +1,85 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "portage_repository_profile_file.hh"
+#include <paludis/util/log.hh>
+#include <paludis/config_file.hh>
+#include <list>
+#include <algorithm>
+
+using namespace paludis;
+
+namespace paludis
+{
+ template <>
+ struct Implementation<ProfileFile>
+ {
+ std::list<std::string> lines;
+ };
+}
+
+void
+ProfileFile::add_file(const FSEntry & f)
+{
+ Context context("When adding profile configuration file '" + stringify(f) + "':");
+
+ if (! f.exists())
+ return;
+
+ LineConfigFile file(f);
+ for (LineConfigFile::Iterator line(file.begin()), line_end(file.end()) ; line != line_end ; ++line)
+ {
+ if (0 == line->compare(0, 1, "-", 0, 1))
+ {
+ std::list<std::string>::iterator i(std::find(_imp->lines.begin(), _imp->lines.end(), line->substr(1)));
+ if (_imp->lines.end() == i)
+ Log::get_instance()->message(ll_qa, lc_context, "No match for '" + *line + "'");
+ else
+ while (_imp->lines.end() != i)
+ {
+ _imp->lines.erase(i++);
+ i = std::find(i, _imp->lines.end(), line->substr(1));
+ }
+ }
+ else
+ _imp->lines.push_back(*line);
+ }
+}
+
+ProfileFile::ProfileFile() :
+ PrivateImplementationPattern<ProfileFile>(new Implementation<ProfileFile>)
+{
+}
+
+ProfileFile::~ProfileFile()
+{
+}
+
+ProfileFile::Iterator
+ProfileFile::begin() const
+{
+ return Iterator(_imp->lines.begin());
+}
+
+ProfileFile::Iterator
+ProfileFile::end() const
+{
+ return Iterator(_imp->lines.end());
+}
+
diff --git a/paludis/repositories/gentoo/portage_repository_profile_file.hh b/paludis/repositories/gentoo/portage_repository_profile_file.hh
new file mode 100644
index 0000000..baa6552
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_profile_file.hh
@@ -0,0 +1,52 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_PROFILE_FILE_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_PROFILE_FILE_HH 1
+
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/attributes.hh>
+#include <paludis/util/fs_entry.hh>
+#include <libwrapiter/libwrapiter_forward_iterator.hh>
+
+namespace paludis
+{
+ /**
+ * A file in a PortageRepository profile.
+ *
+ * Handles -lines, comments, inherits automatically.
+ *
+ * \ingroup grpportagerepository
+ */
+ class PALUDIS_VISIBLE ProfileFile :
+ private PrivateImplementationPattern<ProfileFile>
+ {
+ public:
+ ProfileFile();
+ ~ProfileFile();
+
+ void add_file(const FSEntry &);
+
+ typedef libwrapiter::ForwardIterator<ProfileFile, const std::string> Iterator;
+ Iterator begin() const;
+ Iterator end() const;
+ };
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/portage_repository_sets.cc b/paludis/repositories/gentoo/portage_repository_sets.cc
new file mode 100644
index 0000000..dfa8b5d
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_sets.cc
@@ -0,0 +1,376 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ * Copyright (c) 2006 Danny van Dyk <kugelfang@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/repositories/gentoo/portage_repository.hh>
+#include <paludis/repositories/gentoo/portage_repository_sets.hh>
+#include <paludis/repositories/gentoo/glsa.hh>
+
+#include <paludis/dep_list/dep_list.hh>
+#include <paludis/environment.hh>
+#include <paludis/config_file.hh>
+#include <paludis/query.hh>
+#include <paludis/portage_dep_parser.hh>
+#include <paludis/util/collection_concrete.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/is_file_with_extension.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/tokeniser.hh>
+
+#include <list>
+#include <set>
+
+#include "config.h"
+
+using namespace paludis;
+
+namespace paludis
+{
+ /**
+ * Implementation data for PortageRepositorySets.
+ *
+ * \ingroup grpportagerepository
+ */
+ template<>
+ struct Implementation<PortageRepositorySets>
+ {
+ const Environment * const environment;
+ const PortageRepository * const portage_repository;
+ const PortageRepositoryParams params;
+
+ Implementation(const Environment * const e, const PortageRepository * const p,
+ const PortageRepositoryParams & k) :
+ environment(e),
+ portage_repository(p),
+ params(k)
+ {
+ }
+ };
+}
+
+PortageRepositorySets::PortageRepositorySets(const Environment * const e, const PortageRepository * const p,
+ const PortageRepositoryParams & k) :
+ PrivateImplementationPattern<PortageRepositorySets>(new Implementation<PortageRepositorySets>(e, p, k))
+{
+}
+
+PortageRepositorySets::~PortageRepositorySets()
+{
+}
+
+
+std::tr1::shared_ptr<DepAtom>
+PortageRepositorySets::package_set(const SetName & s) const
+{
+ if ("system" == s.data())
+ throw InternalError(PALUDIS_HERE, "system set should've been handled by PortageRepository");
+ else if ("security" == s.data())
+ return security_set(false);
+ else if ("insecurity" == s.data())
+ return security_set(true);
+ else if ((_imp->params.setsdir / (stringify(s) + ".conf")).exists())
+ {
+ std::tr1::shared_ptr<GeneralSetDepTag> tag(new GeneralSetDepTag(s, stringify(_imp->portage_repository->name())));
+
+ FSEntry ff(_imp->params.setsdir / (stringify(s) + ".conf"));
+ Context context("When loading package set '" + stringify(s) + "' from '" + stringify(ff) + "':");
+
+ std::tr1::shared_ptr<AllDepAtom> result(new AllDepAtom);
+ LineConfigFile f(ff);
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ;
+ line != line_end ; ++line)
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens));
+ if (tokens.empty())
+ continue;
+
+ if (1 == tokens.size())
+ {
+ Log::get_instance()->message(ll_warning, lc_context,
+ "Line '" + *line + "' in set file '"
+ + stringify(ff) + "' does not specify '*' or '?', assuming '*'");
+ std::tr1::shared_ptr<PackageDepAtom> atom(new PackageDepAtom(tokens.at(0)));
+ atom->set_tag(tag);
+ result->add_child(atom);
+ }
+ else if ("*" == tokens.at(0))
+ {
+ std::tr1::shared_ptr<PackageDepAtom> atom(new PackageDepAtom(tokens.at(1)));
+ atom->set_tag(tag);
+ result->add_child(atom);
+ }
+ else if ("?" == tokens.at(0))
+ {
+ std::tr1::shared_ptr<PackageDepAtom> p(new PackageDepAtom(tokens.at(1)));
+ p->set_tag(tag);
+ if (! _imp->environment->package_database()->query(
+ query::Package(p->package()) & query::InstalledAtRoot(
+ _imp->params.environment->root()), qo_whatever)->empty())
+ result->add_child(p);
+ }
+ else
+ Log::get_instance()->message(ll_warning, lc_context,
+ "Line '" + *line + "' in set file '"
+ + stringify(ff) + "' does not start with '*' or '?' token, skipping");
+
+ if (tokens.size() > 2)
+ Log::get_instance()->message(ll_warning, lc_context,
+ "Line '" + *line + "' in set file '"
+ + stringify(ff) + "' has trailing garbage");
+ }
+
+ return result;
+ }
+ else
+ return std::tr1::shared_ptr<DepAtom>();
+}
+
+std::tr1::shared_ptr<const SetsCollection>
+PortageRepositorySets::sets_list() const
+{
+ Context context("While generating the list of sets:");
+
+ std::tr1::shared_ptr<SetsCollection> result(new SetsCollection::Concrete);
+ result->insert(SetName("insecurity"));
+ result->insert(SetName("security"));
+ result->insert(SetName("system"));
+
+ try
+ {
+ std::list<FSEntry> repo_sets;
+ std::copy(DirIterator(_imp->params.setsdir), DirIterator(),
+ filter_inserter(std::back_inserter(repo_sets),
+ IsFileWithExtension(".conf")));
+
+ std::list<FSEntry>::const_iterator f(repo_sets.begin()),
+ f_end(repo_sets.end());
+
+ for ( ; f != f_end ; ++f)
+ try
+ {
+ result->insert(SetName(stringify(*f)));
+ }
+ catch (const NameError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Skipping set '"
+ + stringify(*f) + "' due to exception '" + stringify(e.message()) + "' ("
+ + stringify(e.what()) + ")");
+ }
+ }
+ catch (const paludis::DirOpenError &)
+ {
+ }
+
+ return result;
+}
+
+PackageDatabaseEntryCollection::Iterator
+PortageRepositorySets::find_best(PackageDatabaseEntryCollection & c, const PackageDatabaseEntry & e) const
+{
+ Context local("When finding best update for '" + stringify(e.name) + "-" +
+ stringify(e.version) + "':");
+ // Find an entry in c that matches e best. e is not in c.
+ QualifiedPackageName n(e.name);
+ SlotName s(_imp->environment->package_database()->fetch_repository(
+ e.repository)->version_metadata(e.name, e.version)->slot);
+ PackageDatabaseEntryCollection::Iterator i(c.begin()), i_end(c.end()), i_best(c.end());
+ for ( ; i != i_end; ++i)
+ {
+ if (n != i->name)
+ continue;
+ if (s != _imp->environment->package_database()->fetch_repository(
+ i->repository)->version_metadata(
+ i->name, i->version)->slot)
+ continue;
+
+ i_best = i;
+ }
+
+ return i_best;
+}
+
+namespace
+{
+ bool
+ match_range(const PackageDatabaseEntry & e, const GLSARange & r)
+ {
+ VersionOperatorValue our_op(static_cast<VersionOperatorValue>(-1));
+ std::string ver(r.version);
+ if (r.op == "le")
+ our_op = vo_less_equal;
+ if (r.op == "lt")
+ our_op = vo_less;
+ if (r.op == "eq")
+ {
+ if (! ver.empty() && '*' == ver.at(ver.length() - 1))
+ {
+ ver.erase(ver.length() - 1);
+ our_op = vo_equal_star;
+ }
+ else
+ our_op = vo_equal;
+ }
+ if (r.op == "gt")
+ our_op = vo_greater;
+ if (r.op == "ge")
+ our_op = vo_greater_equal;
+
+ if (-1 != our_op)
+ return (e.version.*(VersionOperator(our_op).as_version_spec_operator()))(VersionSpec(ver));
+
+ if (0 == r.op.compare(0, 1, "r"))
+ {
+ return (e.version.*(VersionOperator(vo_tilde).as_version_spec_operator()))(VersionSpec(ver)) &&
+ match_range(e, GLSARange::create().op(r.op.substr(1)).version(r.version));
+ }
+
+ throw GLSAError("Got bad op '" + r.op + "'");
+ }
+
+ bool
+ is_vulnerable(const GLSAPackage & glsa_pkg, const PackageDatabaseEntry & c)
+ {
+ /* a package is affected if it matches any vulnerable line, except if it matches
+ * any unaffected line. */
+ bool vulnerable(false);
+ for (GLSAPackage::RangesIterator r(glsa_pkg.begin_vulnerable()), r_end(glsa_pkg.end_vulnerable()) ;
+ r != r_end && ! vulnerable ; ++r)
+ if (match_range(c, *r))
+ vulnerable = true;
+
+ if (! vulnerable)
+ return false;
+
+ for (GLSAPackage::RangesIterator r(glsa_pkg.begin_unaffected()), r_end(glsa_pkg.end_unaffected()) ;
+ r != r_end && vulnerable ; ++r)
+ if (match_range(c, *r))
+ vulnerable = false;
+
+ return vulnerable;
+ }
+}
+
+std::tr1::shared_ptr<DepAtom>
+PortageRepositorySets::security_set(bool insecurity) const
+{
+ Context context("When building security or insecurity package set:");
+ std::tr1::shared_ptr<AllDepAtom> security_packages(new AllDepAtom);
+
+ if (!_imp->params.securitydir.is_directory())
+ return security_packages;
+
+ std::map<std::string, std::tr1::shared_ptr<GLSADepTag> > glsa_tags;
+
+ for (DirIterator f(_imp->params.securitydir), f_end ; f != f_end; ++f)
+ {
+ if (! IsFileWithExtension("glsa-", ".xml")(*f))
+ continue;
+
+ Context local_context("When parsing security advisory '" + stringify(*f) + "':");
+
+ try
+ {
+ std::tr1::shared_ptr<const GLSA> glsa(GLSA::create_from_xml_file(stringify(*f)));
+ Context local_local_context("When handling GLSA '" + glsa->id() + "' from '" +
+ stringify(*f) + "':");
+
+ for (GLSA::PackagesIterator glsa_pkg(glsa->begin_packages()),
+ glsa_pkg_end(glsa->end_packages()) ; glsa_pkg != glsa_pkg_end ; ++glsa_pkg)
+ {
+ std::tr1::shared_ptr<const PackageDatabaseEntryCollection> candidates;
+ if (insecurity)
+ candidates = _imp->environment->package_database()->query(query::Package(glsa_pkg->name()), qo_order_by_version);
+ else
+ candidates = _imp->environment->package_database()->query(
+ query::Package(glsa_pkg->name()) & query::RepositoryHasInstalledInterface(), qo_order_by_version);
+
+ for (PackageDatabaseEntryCollection::Iterator c(candidates->begin()), c_end(candidates->end()) ;
+ c != c_end ; ++c)
+ {
+ if (! is_vulnerable(*glsa_pkg, *c))
+ continue;
+
+ if (glsa_tags.end() == glsa_tags.find(glsa->id()))
+ glsa_tags.insert(std::make_pair(glsa->id(), std::tr1::shared_ptr<GLSADepTag>(
+ new GLSADepTag(glsa->id(), glsa->title()))));
+
+ if (insecurity)
+ {
+ std::tr1::shared_ptr<PackageDepAtom> atom(new PackageDepAtom(
+ "=" + stringify(c->name) + "-" + stringify(c->version) +
+ "::" + stringify(c->repository)));
+ atom->set_tag(glsa_tags.find(glsa->id())->second);
+ security_packages->add_child(atom);
+ }
+ else
+ {
+ /* we need to find the best not vulnerable installable package that isn't masked
+ * that's in the same slot as our vulnerable installed package. */
+ bool ok(false);
+ SlotName wanted_slot(_imp->environment->package_database()->fetch_repository(
+ c->repository)->version_metadata(c->name, c->version)->slot);
+
+ std::tr1::shared_ptr<const PackageDatabaseEntryCollection> available(
+ _imp->environment->package_database()->query(PackageDepAtom(glsa_pkg->name()), is_installable_only,
+ qo_order_by_version));
+ for (PackageDatabaseEntryCollection::ReverseIterator r(available->rbegin()),
+ r_end(available->rend()) ; r != r_end ; ++r)
+ {
+ if (_imp->environment->mask_reasons(*r).any())
+ continue;
+ if (_imp->environment->package_database()->fetch_repository(r->repository)->version_metadata(
+ r->name, r->version)->slot != wanted_slot)
+ continue;
+ if (is_vulnerable(*glsa_pkg, *r))
+ continue;
+
+ std::tr1::shared_ptr<PackageDepAtom> atom(new PackageDepAtom(
+ "=" + stringify(r->name) + "-" + stringify(r->version) +
+ "::" + stringify(r->repository)));
+ atom->set_tag(glsa_tags.find(glsa->id())->second);
+ security_packages->add_child(atom);
+ ok = true;
+ break;
+ }
+
+ if (! ok)
+ throw GLSAError("Could not determine upgrade path to resolve '"
+ + glsa->id() + ": " + glsa->title() + "' for package '"
+ + stringify(*c) + "'");
+ }
+ }
+ }
+ }
+ catch (const GLSAError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Cannot use GLSA '" +
+ stringify(*f) + "' due to exception '" + e.message() + "' (" + e.what() + ")");
+ }
+ catch (const NameError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Cannot use GLSA '" +
+ stringify(*f) + "' due to exception '" + e.message() + "' (" + e.what() + ")");
+ }
+ }
+
+ return security_packages;
+}
+
diff --git a/paludis/repositories/gentoo/portage_repository_sets.hh b/paludis/repositories/gentoo/portage_repository_sets.hh
new file mode 100644
index 0000000..12cbabd
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_repository_sets.hh
@@ -0,0 +1,80 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ * Copyright (c) 2006 Danny van Dyk <kugelfang@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_SETS_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_REPOSITORY_SETS_HH 1
+
+#include <paludis/dep_atom.hh>
+#include <paludis/repository.hh>
+
+/** \file
+ * Declaration for the PortageRepositorySets class.
+ *
+ * \ingroup grpportagerepository
+ */
+
+namespace paludis
+{
+ class Environment;
+ class PortageRepository;
+
+ /**
+ * Holds the information about sets, except system, for a PortageRepository.
+ *
+ * \ingroup grpportagerepository
+ * \nosubgrouping
+ */
+ class PALUDIS_VISIBLE PortageRepositorySets :
+ private PrivateImplementationPattern<PortageRepositorySets>,
+ private InstantiationPolicy<PortageRepositorySets, instantiation_method::NonCopyableTag>
+ {
+ private:
+ PackageDatabaseEntryCollection::Iterator
+ find_best(PackageDatabaseEntryCollection & c, const PackageDatabaseEntry & e) const;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ PortageRepositorySets(const Environment * const env, const PortageRepository * const,
+ const PortageRepositoryParams &);
+ ~PortageRepositorySets();
+
+ ///\}
+
+ /**
+ * Fetch a package set other than system.
+ */
+ std::tr1::shared_ptr<DepAtom> package_set(const SetName & s) const;
+
+ /**
+ * Fetch the security or insecurity set.
+ */
+ std::tr1::shared_ptr<DepAtom> security_set(bool insecure) const;
+
+ /**
+ * Give a list of all the sets in this repo.
+ */
+ std::tr1::shared_ptr<const SetsCollection> sets_list() const;
+ };
+}
+
+
+#endif
diff --git a/paludis/repositories/gentoo/portage_virtual_version_metadata.cc b/paludis/repositories/gentoo/portage_virtual_version_metadata.cc
new file mode 100644
index 0000000..a10d4bc
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_virtual_version_metadata.cc
@@ -0,0 +1,45 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "portage_virtual_version_metadata.hh"
+#include <paludis/portage_dep_parser.hh>
+
+using namespace paludis;
+
+PortageVirtualVersionMetadata::PortageVirtualVersionMetadata(const SlotName & s,
+ const PackageDatabaseEntry & e) :
+ VersionMetadata(
+ VersionMetadataBase(s, "", "", "paludis-1"),
+ VersionMetadataCapabilities::create()
+ .virtual_interface(this)
+ .ebuild_interface(0)
+ .deps_interface(this)
+ .license_interface(0)
+ .cran_interface(0)
+ .origins_interface(0)
+ ),
+ VersionMetadataVirtualInterface(e),
+ VersionMetadataDepsInterface(&PortageDepParser::parse_depend)
+{
+}
+
+PortageVirtualVersionMetadata::~PortageVirtualVersionMetadata()
+{
+}
+
diff --git a/paludis/repositories/gentoo/portage_virtual_version_metadata.hh b/paludis/repositories/gentoo/portage_virtual_version_metadata.hh
new file mode 100644
index 0000000..79e6028
--- /dev/null
+++ b/paludis/repositories/gentoo/portage_virtual_version_metadata.hh
@@ -0,0 +1,38 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_VIRTUAL_VERSION_METADATA_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_PORTAGE_VIRTUAL_VERSION_METADATA_HH 1
+
+#include <paludis/version_metadata.hh>
+
+namespace paludis
+{
+ class PortageVirtualVersionMetadata :
+ public VersionMetadata,
+ public VersionMetadataVirtualInterface,
+ public VersionMetadataDepsInterface
+ {
+ public:
+ PortageVirtualVersionMetadata(const SlotName &, const PackageDatabaseEntry &);
+ virtual ~PortageVirtualVersionMetadata();
+ };
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/registration.cc b/paludis/repositories/gentoo/registration.cc
new file mode 100644
index 0000000..9904b2c
--- /dev/null
+++ b/paludis/repositories/gentoo/registration.cc
@@ -0,0 +1,64 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/repositories/repository_maker.hh>
+#include <paludis/repositories/gentoo/make_ebuild_repository.hh>
+#include <paludis/repositories/gentoo/vdb_repository.hh>
+#include <paludis/util/log.hh>
+#include "config.h"
+
+using namespace paludis;
+
+#ifndef MONOLITHIC
+
+extern "C"
+{
+ void register_repositories(RepositoryMaker * maker);
+}
+
+namespace
+{
+ std::tr1::shared_ptr<Repository>
+ make_portage_repository(
+ Environment * const env,
+ std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> > m)
+ {
+ std::string repo_file = "?";
+ if (m->end() != m->find("repo_file"))
+ repo_file = m->find("repo_file")->second;
+
+ Context context("When creating repository using '" + repo_file + "':");
+
+ Log::get_instance()->message(ll_warning, lc_context, "Format 'portage' is "
+ "deprecated, use 'ebuild' instead");
+
+ return make_ebuild_repository_wrapped(env, m);
+ }
+}
+
+void register_repositories(RepositoryMaker * maker)
+{
+ maker->register_maker("ebuild", &make_ebuild_repository_wrapped);
+ maker->register_maker("portage", &make_portage_repository);
+ maker->register_maker("vdb", &VDBRepository::make_vdb_repository);
+}
+
+#endif
+
+
diff --git a/paludis/repositories/gentoo/use_desc.cc b/paludis/repositories/gentoo/use_desc.cc
new file mode 100644
index 0000000..1899d86
--- /dev/null
+++ b/paludis/repositories/gentoo/use_desc.cc
@@ -0,0 +1,95 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "use_desc.hh"
+#include <paludis/hashed_containers.hh>
+#include <paludis/name.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/is_file_with_extension.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/config_file.hh>
+#include <paludis/package_database_entry.hh>
+
+using namespace paludis;
+
+namespace paludis
+{
+ template<>
+ struct Implementation<UseDesc>
+ {
+ MakeHashedMap<std::string, std::string>::Type desc;
+
+ void add(const FSEntry & f, const std::string & prefix)
+ {
+ if (f.is_regular_file())
+ {
+ LineConfigFile ff(f);
+ for (LineConfigFile::Iterator line(ff.begin()), line_end(ff.end()) ;
+ line != line_end ; ++line)
+ {
+ std::string::size_type p(line->find(" - "));
+ if (std::string::npos == p)
+ continue;
+
+ desc.insert(std::make_pair(prefix + line->substr(0, p), line->substr(p + 3)));
+ }
+ }
+ }
+
+ Implementation(const FSEntry & f)
+ {
+ add(f / "use.desc", "");
+ add(f / "use.local.desc", "");
+
+ if ((f / "desc").is_directory())
+ for (DirIterator d(f / "desc"), d_end ; d != d_end ; ++d)
+ if (IsFileWithExtension(".desc")(*d))
+ add(*d, strip_trailing_string(d->basename(), ".desc") + "_");
+ }
+ };
+}
+
+UseDesc::UseDesc(const FSEntry & f) :
+ PrivateImplementationPattern<UseDesc>(new Implementation<UseDesc>(f))
+{
+}
+
+UseDesc::~UseDesc()
+{
+}
+
+std::string
+UseDesc::describe(const UseFlagName & f, const PackageDatabaseEntry * const e) const
+{
+ if (e)
+ {
+ MakeHashedMap<std::string, std::string>::Type::const_iterator i(
+ _imp->desc.find(stringify(e->name) + ":" + stringify(f)));
+ if (_imp->desc.end() != i)
+ return i->second;
+ }
+
+ MakeHashedMap<std::string, std::string>::Type::const_iterator i(_imp->desc.find(stringify(f)));
+ if (_imp->desc.end() != i)
+ return i->second;
+
+ return "";
+}
+
diff --git a/paludis/repositories/gentoo/use_desc.hh b/paludis/repositories/gentoo/use_desc.hh
new file mode 100644
index 0000000..64ffc02
--- /dev/null
+++ b/paludis/repositories/gentoo/use_desc.hh
@@ -0,0 +1,59 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_PALUDIS_REPOSITORIES_PORTAGE_USE_DESC_HH
+#define PALUDIS_GUARD_PALUDIS_PALUDIS_REPOSITORIES_PORTAGE_USE_DESC_HH 1
+
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/name.hh>
+
+namespace paludis
+{
+ class FSEntry;
+ class PackageDatabaseEntry;
+
+ /**
+ * Implements use.desc options for PortageRepository.
+ *
+ * \ingroup grpportagerepository
+ */
+ class UseDesc :
+ private PrivateImplementationPattern<UseDesc>,
+ private InstantiationPolicy<UseDesc, instantiation_method::NonCopyableTag>
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ UseDesc(const FSEntry &);
+ ~UseDesc();
+
+ ///\}
+
+ /**
+ * Describe the given use flag, possibly for the specified package.
+ *
+ * May return an empty string.
+ */
+ std::string describe(const UseFlagName &, const PackageDatabaseEntry * const) const;
+ };
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/vdb_repository.cc b/paludis/repositories/gentoo/vdb_repository.cc
new file mode 100644
index 0000000..838d665
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_repository.cc
@@ -0,0 +1,1542 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/repositories/gentoo/vdb_repository.hh>
+#include <paludis/repositories/gentoo/vdb_version_metadata.hh>
+
+#include <paludis/dep_atom.hh>
+#include <paludis/dep_atom_flattener.hh>
+#include <paludis/ebuild.hh>
+#include <paludis/portage_dep_parser.hh>
+#include <paludis/hashed_containers.hh>
+#include <paludis/config_file.hh>
+#include <paludis/match_package.hh>
+#include <paludis/package_database.hh>
+#include <paludis/repository_name_cache.hh>
+
+#include <paludis/util/collection_concrete.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/fast_unique_copy.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/is_file_with_extension.hh>
+#include <paludis/util/iterator.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/pstream.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/tokeniser.hh>
+
+#include <fstream>
+#include <functional>
+#include <algorithm>
+#include <vector>
+#include <list>
+
+/** \file
+ * Implementation for VDBRepository.
+ *
+ * \ingroup grpvdbrepository
+ */
+
+using namespace paludis;
+
+#include <paludis/repositories/gentoo/vdb_repository-sr.cc>
+
+namespace
+{
+ /**
+ * Holds an entry in a VDB.
+ */
+ struct VDBEntry
+ {
+ /// Our package name.
+ QualifiedPackageName name;
+
+ /// Our package version.
+ VersionSpec version;
+
+ /// Our metadata, may be zero.
+ std::tr1::shared_ptr<VDBVersionMetadata> metadata;
+
+ /// Our built USE flags.
+ std::set<UseFlagName> use;
+
+ /// Our installed date.
+ time_t installed_time;
+
+ /// Constructor
+ VDBEntry(const QualifiedPackageName & n, const VersionSpec & v) :
+ name(n),
+ version(v),
+ installed_time(0)
+ {
+ }
+
+ /// Comparison operator
+ bool operator< (const VDBEntry & other) const
+ {
+ if (name < other.name)
+ return true;
+ if (name > other.name)
+ return false;
+ if (version < other.version)
+ return true;
+ return false;
+ }
+
+ /**
+ * Compare a VDBEntry by category only.
+ *
+ * \ingroup grpvdbrepository
+ */
+ struct CompareCategory
+ {
+ bool operator() (const CategoryNamePart & c, const VDBEntry & e) const
+ {
+ return c < e.name.category;
+ }
+
+ bool operator() (const VDBEntry & e, const CategoryNamePart & c) const
+ {
+ return e.name.category < c;
+ }
+
+ bool operator() (const VDBEntry & e, const VDBEntry & c) const
+ {
+ return e.name.category < c.name.category;
+ }
+ };
+
+ /**
+ * Extract category from a VDBEntry.
+ *
+ * \ingroup grpvdbrepository
+ */
+ struct ExtractCategory
+ {
+ CategoryNamePart operator() (const VDBEntry & e) const
+ {
+ return e.name.category;
+ }
+ };
+
+ /**
+ * Extract package from a VDBEntry.
+ *
+ * \ingroup grpvdbrepository
+ */
+ struct ExtractPackage
+ {
+ QualifiedPackageName operator() (const VDBEntry & e) const
+ {
+ return e.name;
+ }
+ };
+
+ /**
+ * Compare a VDBEntry by name only.
+ *
+ * \ingroup grpvdbrepository
+ */
+ struct ComparePackage
+ {
+ bool operator() (const QualifiedPackageName & c, const VDBEntry & e) const
+ {
+ return c < e.name;
+ }
+
+ bool operator() (const VDBEntry & e, const QualifiedPackageName & c) const
+ {
+ return e.name < c;
+ }
+
+ bool operator() (const VDBEntry & e, const VDBEntry & c) const
+ {
+ return e.name < c.name;
+ }
+ };
+
+ /**
+ * Compare a VDBEntry by name and version.
+ *
+ * \ingroup grpvdbrepository
+ */
+ struct CompareVersion
+ {
+ bool operator() (const std::pair<QualifiedPackageName, VersionSpec> & c,
+ const VDBEntry & e) const
+ {
+ if (c.first < e.name)
+ return true;
+ else if (c.first > e.name)
+ return false;
+ else if (c.second < e.version)
+ return true;
+ else
+ return false;
+ }
+
+ bool operator() (const VDBEntry & e,
+ const std::pair<QualifiedPackageName, VersionSpec> & c) const
+ {
+ if (e.name < c.first)
+ return true;
+ else if (e.name > c.first)
+ return false;
+ else if (e.version < c.second)
+ return true;
+ else
+ return false;
+ }
+ };
+ };
+
+ /**
+ * Figure out the format of environment.bz2. If VDB_FORMAT is "paludis-1",
+ * or if there's no VDB_FORMAT and there're no lines with () and no =, it's
+ * an env dump. Otherwise it's a source file.
+ *
+ * \ingroup grpvdbrepository
+ */
+ bool is_full_env(const FSEntry & vdb_dir)
+ {
+ bool result(false);
+
+ if ((vdb_dir / "VDB_FORMAT").is_regular_file())
+ {
+ std::ifstream f(stringify(vdb_dir / "VDB_FORMAT").c_str());
+ if (! f)
+ throw EnvironmentVariableActionError("Could not read '" +
+ stringify(vdb_dir / "VDB_FORMAT") + "'");
+ result = ("paludis-1" != strip_trailing_string(std::string(
+ (std::istreambuf_iterator<char>(f)),
+ std::istreambuf_iterator<char>()), "\n"));
+ }
+ else if (0 == run_command("bunzip2 < " + stringify(vdb_dir / "environment.bz2") +
+ " | grep -q '^[^=]\\+()'"))
+ result = true;
+
+ return result;
+ }
+
+ /**
+ * Figure out whether there's an ebuild present (won't be the case for
+ * virtual things installed using early paludis versions).
+ *
+ * \ingroup grpvdbrepository
+ */
+ bool is_ebuilded(const FSEntry & vdb_dir)
+ {
+ return ! std::count_if(DirIterator(vdb_dir), DirIterator(),
+ IsFileWithExtension(".ebuild"));
+ }
+
+ /**
+ * Fetch the contents of a VDB file.
+ *
+ * \ingroup grpvdbrepository
+ */
+ std::string
+ file_contents(const FSEntry & location, const QualifiedPackageName & name,
+ const VersionSpec & v, const std::string & key)
+ {
+ Context context("When loading VDBRepository entry for '" + stringify(name)
+ + "-" + stringify(v) + "' key '" + key + "' from '" + stringify(location) + "':");
+
+ FSEntry f(location / stringify(name.category) /
+ (stringify(name.package) + "-" + stringify(v)));
+ if (! (f / key).is_regular_file())
+ return "";
+
+ std::ifstream ff(stringify(f / key).c_str());
+ if (! ff)
+ throw VDBRepositoryKeyReadError("Could not read '" + stringify(f / key) + "'");
+ return strip_leading(strip_trailing(std::string((std::istreambuf_iterator<char>(ff)),
+ std::istreambuf_iterator<char>()), " \t\n"), " \t\n");
+ }
+
+ /**
+ * Filter if a USE flag is a -flag.
+ *
+ * \ingroup grpvdbrepository
+ */
+ struct IsPositiveFlag
+ {
+ bool operator() (const std::string & f) const
+ {
+ return 0 != f.compare(0, 1, "-");
+ }
+ };
+}
+
+
+namespace paludis
+{
+ /**
+ * Implementation data for VDBRepository.
+ *
+ * \ingroup grpvdbrepository
+ */
+ template <>
+ struct Implementation<VDBRepository>
+ {
+ VDBRepositoryParams params;
+
+ /// Our owning env.
+ const Environment * const env;
+
+ /// Our base location.
+ FSEntry location;
+
+ /// Root location
+ FSEntry root;
+
+ /// Build root
+ FSEntry buildroot;
+
+ /// World file
+ FSEntry world_file;
+
+ /// Provides cache
+ FSEntry provides_cache;
+
+ /// Do we have entries loaded?
+ mutable bool entries_valid;
+
+ /// Do we have category entries loaded?
+ mutable MakeHashedSet<CategoryNamePart>::Type category_entries_valid;
+
+ /// Our entries, keep this sorted!
+ mutable std::vector<VDBEntry> entries;
+
+ /// Load entries.
+ void load_entries() const;
+ void load_entries_for(const CategoryNamePart &) const;
+
+ /// Load metadata for one entry.
+ void load_entry(std::vector<VDBEntry>::iterator) const;
+
+ /// Provieds data
+ mutable std::tr1::shared_ptr<RepositoryProvidesInterface::ProvidesCollection> provides;
+
+ const FSEntry names_cache_dir;
+
+ std::tr1::shared_ptr<RepositoryNameCache> names_cache;
+
+ /// Constructor.
+ Implementation(const VDBRepository * const, const VDBRepositoryParams &);
+
+ /// Destructor.
+ ~Implementation();
+
+ /// Invalidate.
+ void invalidate() const;
+ };
+
+ Implementation<VDBRepository>::Implementation(const VDBRepository * const r,
+ const VDBRepositoryParams & p) :
+ params(p),
+ env(p.environment),
+ location(p.location),
+ root(p.root),
+ buildroot(p.buildroot),
+ world_file(p.world),
+ provides_cache(p.provides_cache),
+ entries_valid(false),
+ names_cache_dir(p.names_cache),
+ names_cache(new RepositoryNameCache(names_cache_dir, r))
+ {
+ }
+
+ Implementation<VDBRepository>::~Implementation()
+ {
+ }
+
+ void
+ Implementation<VDBRepository>::load_entries() const
+ {
+ Context context("When loading VDBRepository entries from '" +
+ stringify(location) + "':");
+
+ Log::get_instance()->message(ll_debug, lc_context, "VDB load entries started");
+
+ entries.clear();
+ category_entries_valid.clear();
+ entries_valid = true;
+ try
+ {
+ for (DirIterator cat_i(location), cat_iend ; cat_i != cat_iend ; ++cat_i)
+ load_entries_for(CategoryNamePart(cat_i->basename()));
+
+ std::sort(entries.begin(), entries.end());
+ }
+ catch (...)
+ {
+ entries_valid = false;
+ throw;
+ }
+
+ Log::get_instance()->message(ll_debug, lc_context, "VDB load entries done");
+ }
+
+ void
+ Implementation<VDBRepository>::load_entries_for(const CategoryNamePart & cat) const
+ {
+ MakeHashedSet<CategoryNamePart>::Type::const_iterator i(category_entries_valid.find(cat));
+ if (i != category_entries_valid.end())
+ return;
+
+ Context context("When loading VDBRepository entries for '" + stringify(cat) + "' from '" +
+ stringify(location) + "':");
+
+ Log::get_instance()->message(ll_debug, lc_context, "VDB load entries for '" +
+ stringify(cat) + "' started");
+
+ try
+ {
+ category_entries_valid.insert(cat);
+
+ FSEntry dir(location / stringify(cat));
+ if (! dir.is_directory())
+ return;
+
+ for (DirIterator pkg_i(dir), pkg_iend ; pkg_i != pkg_iend ; ++pkg_i)
+ {
+ PackageDepAtom atom("=" + stringify(cat) + "/" + pkg_i->basename());
+ entries.push_back(VDBEntry(atom.package(),
+ atom.version_requirements_ptr()->begin()->version_spec));
+ }
+
+ std::sort(entries.begin(), entries.end());
+ }
+ catch (...)
+ {
+ category_entries_valid.erase(cat);
+ throw;
+ }
+ }
+
+ void
+ Implementation<VDBRepository>::invalidate() const
+ {
+ entries_valid = false;
+ entries.clear();
+ category_entries_valid.clear();
+ }
+
+ void
+ Implementation<VDBRepository>::load_entry(std::vector<VDBEntry>::iterator p) const
+ {
+ Context context("When loading VDBRepository entry for '" + stringify(p->name)
+ + "-" + stringify(p->version) + "' from '" + stringify(location) + "':");
+
+ p->metadata = std::tr1::shared_ptr<VDBVersionMetadata>(new VDBVersionMetadata);
+ p->metadata->build_depend_string = file_contents(location, p->name, p->version, "DEPEND");
+ p->metadata->run_depend_string = file_contents(location, p->name, p->version, "RDEPEND");
+ p->metadata->license_string = file_contents(location, p->name, p->version, "LICENSE");
+ p->metadata->keywords = "*";
+ p->metadata->inherited = file_contents(location, p->name, p->version, "INHERITED");
+ p->metadata->iuse = file_contents(location, p->name, p->version, "IUSE");
+ p->metadata->post_depend_string = file_contents(location, p->name, p->version, "PDEPEND");
+ p->metadata->provide_string = file_contents(location, p->name, p->version, "PROVIDE");
+ p->metadata->src_uri = file_contents(location, p->name, p->version, "SRC_URI");
+ p->metadata->eapi = file_contents(location, p->name, p->version, "EAPI");
+ p->metadata->homepage = file_contents(location, p->name, p->version, "HOMEPAGE");
+ p->metadata->description = file_contents(location, p->name, p->version, "DESCRIPTION");
+
+ std::string slot(file_contents(location, p->name, p->version, "SLOT"));
+ if (slot.empty())
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "VDBRepository entry '" +
+ stringify(p->name) + "-" + stringify(p->version) + "' in '" +
+ stringify(location) + "' has empty SLOT, setting to \"0\"");
+ slot = "0";
+ }
+ p->metadata->slot = SlotName(slot);
+
+ std::string repo(file_contents(location, p->name, p->version, "REPOSITORY"));
+ if (! repo.empty())
+ p->metadata->source.reset(new PackageDatabaseEntry(p->name, p->version,
+ RepositoryName(repo)));
+
+ std::string raw_use(file_contents(location, p->name, p->version, "USE"));
+ p->use.clear();
+ WhitespaceTokeniser::get_instance()->tokenise(raw_use,
+ filter_inserter(create_inserter<UseFlagName>(
+ std::inserter(p->use, p->use.begin())), IsPositiveFlag()));
+ }
+}
+
+VDBRepository::VDBRepository(const VDBRepositoryParams & p) :
+ Repository(RepositoryName("installed"),
+ RepositoryCapabilities::create()
+ .installable_interface(0)
+ .installed_interface(this)
+ .mask_interface(0)
+ .news_interface(0)
+ .sets_interface(this)
+ .syncable_interface(0)
+ .uninstallable_interface(this)
+ .use_interface(this)
+ .world_interface(this)
+ .environment_variable_interface(this)
+ .mirrors_interface(0)
+ .provides_interface(this)
+ .virtuals_interface(0)
+ .destination_interface(this)
+ .config_interface(this)
+ .contents_interface(this),
+ "vdb"),
+ PrivateImplementationPattern<VDBRepository>(new Implementation<VDBRepository>(this, p))
+{
+ std::tr1::shared_ptr<RepositoryInfoSection> config_info(new RepositoryInfoSection("Configuration information"));
+
+ config_info->add_kv("location", stringify(_imp->location));
+ config_info->add_kv("root", stringify(_imp->root));
+ config_info->add_kv("format", "vdb");
+ config_info->add_kv("world", stringify(_imp->world_file));
+ config_info->add_kv("provides_cache", stringify(_imp->provides_cache));
+ config_info->add_kv("names_cache", stringify(_imp->names_cache_dir));
+ config_info->add_kv("buildroot", stringify(_imp->buildroot));
+
+ _info->add_section(config_info);
+}
+
+VDBRepository::~VDBRepository()
+{
+}
+
+bool
+VDBRepository::do_has_category_named(const CategoryNamePart & c) const
+{
+ Context context("When checking for category '" + stringify(c) +
+ "' in " + stringify(name()) + ":");
+
+ if (! _imp->entries_valid)
+ _imp->load_entries();
+
+ std::pair<std::vector<VDBEntry>::const_iterator, std::vector<VDBEntry>::const_iterator>
+ r(std::equal_range(_imp->entries.begin(), _imp->entries.end(), c,
+ VDBEntry::CompareCategory()));
+ return r.first != r.second;
+}
+
+bool
+VDBRepository::do_has_package_named(const QualifiedPackageName & q) const
+{
+ Context context("When checking for package '" + stringify(q) +
+ "' in " + stringify(name()) + ":");
+
+ if (! _imp->entries_valid)
+ _imp->load_entries_for(q.category);
+
+ std::pair<std::vector<VDBEntry>::const_iterator, std::vector<VDBEntry>::const_iterator>
+ r(std::equal_range(_imp->entries.begin(), _imp->entries.end(), q,
+ VDBEntry::ComparePackage()));
+ return r.first != r.second;
+}
+
+std::tr1::shared_ptr<const CategoryNamePartCollection>
+VDBRepository::do_category_names() const
+{
+ Context context("When fetching category names in " + stringify(name()) + ":");
+
+ if (! _imp->entries_valid)
+ _imp->load_entries();
+
+ std::tr1::shared_ptr<CategoryNamePartCollection> result(new CategoryNamePartCollection::Concrete);
+
+#if 0
+ for (std::vector<VDBEntry>::const_iterator c(_imp->entries.begin()), c_end(_imp->entries.end()) ;
+ c != c_end ; ++c)
+ result->insert(c->name.category);
+#else
+ fast_unique_copy(_imp->entries.begin(), _imp->entries.end(),
+ transform_inserter(result->inserter(), VDBEntry::ExtractCategory()),
+ VDBEntry::CompareCategory());
+#endif
+
+ return result;
+}
+
+std::tr1::shared_ptr<const QualifiedPackageNameCollection>
+VDBRepository::do_package_names(const CategoryNamePart & c) const
+{
+ /* this isn't particularly fast because it isn't called very often. avoid
+ * changing the data structures used to make this faster at the expense of
+ * slowing down single item queries. */
+
+ Context context("When fetching package names in category '" + stringify(c)
+ + "' in " + stringify(name()) + ":");
+
+ std::tr1::shared_ptr<QualifiedPackageNameCollection> result(new QualifiedPackageNameCollection::Concrete);
+
+ std::pair<std::vector<VDBEntry>::const_iterator, std::vector<VDBEntry>::const_iterator>
+ r(std::equal_range(_imp->entries.begin(), _imp->entries.end(), c,
+ VDBEntry::CompareCategory()));
+#if 0
+ for ( ; r.first != r.second ; ++(r.first))
+ result->insert(r.first->name);
+#endif
+ fast_unique_copy(r.first, r.second,
+ transform_inserter(result->inserter(), VDBEntry::ExtractPackage()),
+ VDBEntry::ComparePackage());
+
+ return result;
+}
+
+std::tr1::shared_ptr<const VersionSpecCollection>
+VDBRepository::do_version_specs(const QualifiedPackageName & n) const
+{
+ Context context("When fetching versions of '" + stringify(n) + "' in "
+ + stringify(name()) + ":");
+
+ if (! _imp->entries_valid)
+ _imp->load_entries_for(n.category);
+
+ std::tr1::shared_ptr<VersionSpecCollection> result(new VersionSpecCollection::Concrete);
+
+ std::pair<std::vector<VDBEntry>::const_iterator, std::vector<VDBEntry>::const_iterator>
+ r(std::equal_range(_imp->entries.begin(), _imp->entries.end(), n,
+ VDBEntry::ComparePackage()));
+
+ for ( ; r.first != r.second ; ++(r.first))
+ result->insert(r.first->version);
+
+ return result;
+}
+
+bool
+VDBRepository::do_has_version(const QualifiedPackageName & q,
+ const VersionSpec & v) const
+{
+ Context context("When checking for version '" + stringify(v) + "' in '"
+ + stringify(q) + "' in " + stringify(name()) + ":");
+
+ std::tr1::shared_ptr<const VersionSpecCollection> versions(do_version_specs(q));
+ return versions->end() != versions->find(v);
+}
+
+std::tr1::shared_ptr<const VersionMetadata>
+VDBRepository::do_version_metadata(
+ const QualifiedPackageName & q, const VersionSpec & v) const
+{
+ Context context("When fetching metadata for '" + stringify(q) +
+ "-" + stringify(v) + "':");
+
+ if (! _imp->entries_valid)
+ _imp->load_entries_for(q.category);
+
+ std::pair<std::vector<VDBEntry>::iterator, std::vector<VDBEntry>::iterator>
+ r(std::equal_range(_imp->entries.begin(), _imp->entries.end(), std::make_pair(
+ q, v), VDBEntry::CompareVersion()));
+
+ if (r.first == r.second)
+ throw NoSuchPackageError(stringify(PackageDatabaseEntry(q, v, name())));
+ else
+ {
+ if (! r.first->metadata)
+ _imp->load_entry(r.first);
+ return r.first->metadata;
+ }
+}
+
+std::tr1::shared_ptr<const Contents>
+VDBRepository::do_contents(
+ const QualifiedPackageName & q, const VersionSpec & v) const
+{
+ Context context("When fetching contents for '" + stringify(q) +
+ "-" + stringify(v) + "':");
+
+ if (! _imp->entries_valid)
+ _imp->load_entries();
+
+ std::pair<std::vector<VDBEntry>::iterator, std::vector<VDBEntry>::iterator>
+ r(std::equal_range(_imp->entries.begin(), _imp->entries.end(), std::make_pair(
+ q, v), VDBEntry::CompareVersion()));
+
+ if (r.first == r.second)
+ {
+ Log::get_instance()->message(ll_warning, lc_context,
+ "version lookup failed for request for '" +
+ stringify(q) + "-" + stringify(v) + "' in repository '" +
+ stringify(name()) + "'");
+ return std::tr1::shared_ptr<const Contents>(new Contents);
+ }
+
+ std::tr1::shared_ptr<Contents> result(new Contents);
+
+ FSEntry f(_imp->location / stringify(q.category) /
+ (stringify(q.package) + "-" + stringify(v)));
+ if (! (f / "CONTENTS").is_regular_file())
+ {
+ Log::get_instance()->message(ll_warning, lc_context,
+ "CONTENTS lookup failed for request for '" +
+ stringify(q) + "-" + stringify(v) + "' in vdb '" +
+ stringify(_imp->location) + "'");
+ return result;
+ }
+
+ std::ifstream ff(stringify(f / "CONTENTS").c_str());
+ if (! ff)
+ throw VDBRepositoryKeyReadError("Could not read '" + stringify(f / "CONTENTS") + "'");
+
+ std::string line;
+ unsigned line_number(0);
+ while (std::getline(ff, line))
+ {
+ ++line_number;
+
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(line, std::back_inserter(tokens));
+ if (tokens.empty())
+ continue;
+
+ if (tokens.size() < 2)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "CONTENTS for '" +
+ stringify(q) + "-" + stringify(v) + "' in vdb '" +
+ stringify(_imp->location) + "' has broken line " +
+ stringify(line_number) + ", skipping");
+ continue;
+ }
+
+ if ("obj" == tokens.at(0))
+ result->add(std::tr1::shared_ptr<ContentsEntry>(new ContentsFileEntry(tokens.at(1))));
+ else if ("dir" == tokens.at(0))
+ result->add(std::tr1::shared_ptr<ContentsEntry>(new ContentsDirEntry(tokens.at(1))));
+ else if ("misc" == tokens.at(0))
+ result->add(std::tr1::shared_ptr<ContentsEntry>(new ContentsMiscEntry(tokens.at(1))));
+ else if ("fif" == tokens.at(0))
+ result->add(std::tr1::shared_ptr<ContentsEntry>(new ContentsFifoEntry(tokens.at(1))));
+ else if ("dev" == tokens.at(0))
+ result->add(std::tr1::shared_ptr<ContentsEntry>(new ContentsDevEntry(tokens.at(1))));
+ else if ("sym" == tokens.at(0))
+ {
+ if (tokens.size() < 4)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "CONTENTS for '" +
+ stringify(q) + "-" + stringify(v) + "' in vdb '" +
+ stringify(_imp->location) + "' has broken sym line " +
+ stringify(line_number) + ", skipping");
+ continue;
+ }
+
+ result->add(std::tr1::shared_ptr<ContentsEntry>(new ContentsSymEntry(
+ tokens.at(1), tokens.at(3))));
+ }
+ }
+
+ return result;
+}
+
+time_t
+VDBRepository::do_installed_time(const QualifiedPackageName & q,
+ const VersionSpec & v) const
+{
+ Context context("When finding installed time for '" + stringify(q) +
+ "-" + stringify(v) + "':");
+
+ if (! _imp->entries_valid)
+ _imp->load_entries_for(q.category);
+
+ std::pair<std::vector<VDBEntry>::iterator, std::vector<VDBEntry>::iterator>
+ r(std::equal_range(_imp->entries.begin(), _imp->entries.end(), std::make_pair(
+ q, v), VDBEntry::CompareVersion()));
+
+ if (r.first == r.second)
+ throw NoSuchPackageError(stringify(PackageDatabaseEntry(q, v, name())));
+ else
+ {
+ if (0 == r.first->installed_time)
+ {
+ FSEntry f(_imp->location / stringify(q.category) / (stringify(q.package) + "-"
+ + stringify(v)) / "CONTENTS");
+ try
+ {
+ r.first->installed_time = f.ctime();
+ }
+ catch (const FSError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "Can't get ctime of '"
+ + stringify(f) + "' due to exception '" + e.message() + "' (" + e.what()
+ + ")");
+ r.first->installed_time = 1;
+ }
+ }
+ return r.first->installed_time;
+ }
+}
+
+UseFlagState
+VDBRepository::do_query_use(const UseFlagName & f,
+ const PackageDatabaseEntry * const e) const
+{
+ if (e && e->repository == name())
+ {
+ if (! _imp->entries_valid)
+ _imp->load_entries_for(e->name.category);
+
+ std::pair<std::vector<VDBEntry>::iterator, std::vector<VDBEntry>::iterator>
+ r(std::equal_range(_imp->entries.begin(), _imp->entries.end(), std::make_pair(
+ e->name, e->version), VDBEntry::CompareVersion()));
+
+ if (r.first == r.second)
+ return use_unspecified;
+
+ if (!r.first->metadata)
+ _imp->load_entry(r.first);
+
+ if (r.first->use.end() != r.first->use.find(f))
+ return use_enabled;
+ else
+ return use_disabled;
+ }
+ else
+ return use_unspecified;
+}
+
+bool
+VDBRepository::do_query_use_mask(const UseFlagName & u, const PackageDatabaseEntry * e) const
+{
+ return use_disabled == do_query_use(u, e);
+}
+
+bool
+VDBRepository::do_query_use_force(const UseFlagName & u, const PackageDatabaseEntry * e) const
+{
+ return use_enabled == do_query_use(u, e);
+}
+
+std::tr1::shared_ptr<Repository>
+VDBRepository::make_vdb_repository(
+ Environment * const env,
+ std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> > m)
+{
+ std::string repo_file(m->end() == m->find("repo_file") ? std::string("?") : m->find("repo_file")->second);
+ Context context("When making VDB repository from repo_file '" + repo_file + "':");
+
+ std::string location;
+ if (m->end() == m->find("location") || ((location = m->find("location")->second)).empty())
+ throw VDBRepositoryConfigurationError("Key 'location' not specified or empty");
+
+ std::string root;
+ if (m->end() == m->find("root") || ((root = m->find("root")->second)).empty())
+ root = "/";
+
+ std::string world;
+ if (m->end() == m->find("world") || ((world = m->find("world")->second)).empty())
+ world = location + "/world";
+
+ std::string provides_cache;
+ if (m->end() == m->find("provides_cache") || ((provides_cache = m->find("provides_cache")->second)).empty())
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "The provides_cache key is not set in '"
+ + repo_file + "'. You should read http://paludis.pioto.org/cachefiles.html and select an "
+ "appropriate value.");
+ provides_cache = "/var/empty";
+ }
+
+ std::string names_cache;
+ if (m->end() == m->find("names_cache") || ((names_cache = m->find("names_cache")->second)).empty())
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "The names_cache key is not set in '"
+ + repo_file + "'. You should read http://paludis.pioto.org/cachefiles.html and select an "
+ "appropriate value.");
+ names_cache = "/var/empty";
+ }
+
+ std::string buildroot;
+ if (m->end() == m->find("buildroot") || ((buildroot = m->find("buildroot")->second)).empty())
+ buildroot = "/var/tmp/paludis";
+
+ return std::tr1::shared_ptr<Repository>(new VDBRepository(VDBRepositoryParams::create()
+ .environment(env)
+ .location(location)
+ .root(root)
+ .world(world)
+ .buildroot(buildroot)
+ .provides_cache(provides_cache)
+ .names_cache(names_cache)));
+}
+
+VDBRepositoryConfigurationError::VDBRepositoryConfigurationError(
+ const std::string & msg) throw () :
+ ConfigurationError("VDB repository configuration error: " + msg)
+{
+}
+
+VDBRepositoryKeyReadError::VDBRepositoryKeyReadError(
+ const std::string & msg) throw () :
+ ConfigurationError("VDB repository key read error: " + msg)
+{
+}
+
+bool
+VDBRepository::do_is_licence(const std::string &) const
+{
+ return false;
+}
+
+void
+VDBRepository::do_uninstall(const QualifiedPackageName & q, const VersionSpec & v, const InstallOptions & o) const
+{
+ Context context("When uninstalling '" + stringify(q) + "-" + stringify(v) +
+ "' from '" + stringify(name()) + "':");
+
+ if (! _imp->root.is_directory())
+ throw PackageInstallActionError("Couldn't uninstall '" + stringify(q) + "-" +
+ stringify(v) + "' because root ('" + stringify(_imp->root) + "') is not a directory");
+
+ std::tr1::shared_ptr<const VersionMetadata> metadata;
+ if (! has_version(q, v))
+ throw PackageInstallActionError("Couldn't uninstall '" + stringify(q) + "-" +
+ stringify(v) + "' because has_version failed");
+ else
+ metadata = version_metadata(q, v);
+
+ PackageDatabaseEntry e(q, v, name());
+
+ std::tr1::shared_ptr<FSEntryCollection> eclassdirs(new FSEntryCollection::Concrete);
+ eclassdirs->append(FSEntry(_imp->location / stringify(q.category) /
+ (stringify(q.package) + "-" + stringify(v))));
+
+ FSEntry pkg_dir(_imp->location / stringify(q.category) /
+ (stringify(q.package) + "-" + stringify(v)));
+
+ std::tr1::shared_ptr<FSEntry> load_env;
+ if (is_full_env(pkg_dir))
+ load_env.reset(new FSEntry(pkg_dir / "environment.bz2"));
+
+ EbuildUninstallCommand uninstall_cmd(EbuildCommandParams::create()
+ .environment(_imp->env)
+ .db_entry(&e)
+ .ebuild_dir(pkg_dir)
+ .files_dir(pkg_dir)
+ .eclassdirs(eclassdirs)
+ .portdir(_imp->location)
+ .distdir(pkg_dir)
+ .buildroot(_imp->buildroot),
+
+ EbuildUninstallCommandParams::create()
+ .root(stringify(_imp->root) + "/")
+ .disable_cfgpro(o.no_config_protect)
+ .unmerge_only(is_ebuilded(pkg_dir))
+ .load_environment(load_env.get()));
+
+ uninstall_cmd();
+}
+
+void
+VDBRepository::do_config(const QualifiedPackageName & q, const VersionSpec & v) const
+{
+ Context context("When configuring '" + stringify(q) + "-" + stringify(v) +
+ "' from '" + stringify(name()) + "':");
+
+ if (! _imp->root.is_directory())
+ throw PackageInstallActionError("Couldn't configure '" + stringify(q) + "-" +
+ stringify(v) + "' because root ('" + stringify(_imp->root) + "') is not a directory");
+
+ std::tr1::shared_ptr<const VersionMetadata> metadata;
+ if (! has_version(q, v))
+ throw PackageInstallActionError("Couldn't configure '" + stringify(q) + "-" +
+ stringify(v) + "' because has_version failed");
+ else
+ metadata = version_metadata(q, v);
+
+ PackageDatabaseEntry e(q, v, name());
+
+ std::tr1::shared_ptr<FSEntryCollection> eclassdirs(new FSEntryCollection::Concrete);
+ eclassdirs->append(FSEntry(_imp->location / stringify(q.category) /
+ (stringify(q.package) + "-" + stringify(v))));
+
+ FSEntry pkg_dir(_imp->location / stringify(q.category) /
+ (stringify(q.package) + "-" + stringify(v)));
+
+ std::tr1::shared_ptr<FSEntry> load_env;
+ if (is_full_env(pkg_dir))
+ load_env.reset(new FSEntry(pkg_dir / "environment.bz2"));
+
+ EbuildConfigCommand config_cmd(EbuildCommandParams::create()
+ .environment(_imp->env)
+ .db_entry(&e)
+ .ebuild_dir(pkg_dir)
+ .files_dir(pkg_dir)
+ .eclassdirs(eclassdirs)
+ .portdir(_imp->location)
+ .distdir(pkg_dir)
+ .buildroot(_imp->buildroot),
+
+ EbuildConfigCommandParams::create()
+ .root(stringify(_imp->root) + "/")
+ .load_environment(load_env.get()));
+
+ config_cmd();
+}
+
+std::tr1::shared_ptr<DepAtom>
+VDBRepository::do_package_set(const SetName & s) const
+{
+ Context context("When fetching package set '" + stringify(s) + "' from '" +
+ stringify(name()) + "':");
+
+ if ("everything" == s.data())
+ {
+ std::tr1::shared_ptr<AllDepAtom> result(new AllDepAtom);
+ std::tr1::shared_ptr<GeneralSetDepTag> tag(new GeneralSetDepTag(SetName("everything"), stringify(name())));
+
+ if (! _imp->entries_valid)
+ _imp->load_entries();
+
+ for (std::vector<VDBEntry>::const_iterator p(_imp->entries.begin()),
+ p_end(_imp->entries.end()) ; p != p_end ; ++p)
+ {
+ std::tr1::shared_ptr<PackageDepAtom> atom(new PackageDepAtom(p->name));
+ atom->set_tag(tag);
+ result->add_child(atom);
+ }
+
+ return result;
+ }
+ else if ("world" == s.data())
+ {
+ std::tr1::shared_ptr<AllDepAtom> result(new AllDepAtom);
+ std::tr1::shared_ptr<GeneralSetDepTag> tag(new GeneralSetDepTag(SetName("world"), stringify(name())));
+
+ if (_imp->world_file.exists())
+ {
+ LineConfigFile world(_imp->world_file);
+
+ for (LineConfigFile::Iterator line(world.begin()), line_end(world.end()) ;
+ line != line_end ; ++line)
+ {
+ try
+ {
+ if (std::string::npos == line->find('/'))
+ {
+ std::tr1::shared_ptr<DepAtom> atom(_imp->env->package_set(SetName(*line)));
+ if (atom)
+ result->add_child(atom);
+ else
+ Log::get_instance()->message(ll_warning, lc_no_context, "World file '"
+ + stringify(_imp->world_file) + "' entry '" + *line +
+ " is not a known package set");
+ }
+ else
+ {
+ std::tr1::shared_ptr<PackageDepAtom> atom(new PackageDepAtom(QualifiedPackageName(*line)));
+ atom->set_tag(tag);
+ result->add_child(atom);
+ }
+ }
+ catch (const NameError & n)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "World file '"
+ + stringify(_imp->world_file) + "' entry '" + *line + " is broken: '"
+ + n.message() + "' (" + n.what() + ")");
+ }
+ }
+ }
+ else
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "World file '" + stringify(_imp->world_file) +
+ "' doesn't exist");
+
+ return result;
+ }
+ else
+ return std::tr1::shared_ptr<DepAtom>();
+}
+
+std::tr1::shared_ptr<const SetsCollection>
+VDBRepository::sets_list() const
+{
+ Context context("While generating the list of sets:");
+
+ std::tr1::shared_ptr<SetsCollection> result(new SetsCollection::Concrete);
+ result->insert(SetName("everything"));
+ result->insert(SetName("world"));
+ return result;
+}
+
+void
+VDBRepository::invalidate()
+{
+ _imp.reset(new Implementation<VDBRepository>(this, _imp->params));
+}
+
+void
+VDBRepository::add_string_to_world(const std::string & n) const
+{
+ Context context("When adding '" + n + "' to world file '" +
+ stringify(_imp->world_file) + "':");
+
+ bool found(false);
+
+ if (_imp->world_file.exists())
+ {
+ LineConfigFile world(_imp->world_file);
+
+ for (LineConfigFile::Iterator line(world.begin()), line_end(world.end()) ;
+ line != line_end ; ++line)
+ if (*line == n)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (! found)
+ {
+ /* portage is retarded, and doesn't ensure that the last entry in world has
+ * a newline character after it. */
+ bool world_file_needs_newline(false);
+ {
+ std::ifstream world(stringify(_imp->world_file).c_str(), std::ios::in);
+ if (world)
+ {
+ world.seekg(0, std::ios::end);
+ if (0 != world.tellg())
+ {
+ world.seekg(-1, std::ios::end);
+ if ('\n' != world.get())
+ world_file_needs_newline = true;
+ }
+ }
+ }
+
+ if (world_file_needs_newline)
+ Log::get_instance()->message(ll_warning, lc_no_context, "World file '"
+ + stringify(_imp->world_file) + "' lacks final newline");
+
+ std::ofstream world(stringify(_imp->world_file).c_str(), std::ios::out | std::ios::app);
+ if (! world)
+ Log::get_instance()->message(ll_warning, lc_no_context, "Cannot append to world file '"
+ + stringify(_imp->world_file) + "', skipping world update");
+ else
+ {
+ if (world_file_needs_newline)
+ world << std::endl;
+ world << n << std::endl;
+ }
+ }
+}
+
+void
+VDBRepository::remove_string_from_world(const std::string & n) const
+{
+ std::list<std::string> world_lines;
+
+ if (_imp->world_file.exists())
+ {
+ std::ifstream world_file(stringify(_imp->world_file).c_str());
+
+ if (! world_file)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "Cannot read world file '"
+ + stringify(_imp->world_file) + "', skipping world update");
+ return;
+ }
+
+ std::string line;
+ while (std::getline(world_file, line))
+ {
+ if (strip_leading(strip_trailing(line, " \t"), "\t") != stringify(n))
+ world_lines.push_back(line);
+ else
+ Log::get_instance()->message(ll_debug, lc_no_context, "Removing line '"
+ + line + "' from world file '" + stringify(_imp->world_file));
+ }
+ }
+
+ std::ofstream world_file(stringify(_imp->world_file).c_str());
+
+ if (! world_file)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "Cannot write world file '"
+ + stringify(_imp->world_file) + "', skipping world update");
+ return;
+ }
+
+ std::copy(world_lines.begin(), world_lines.end(),
+ std::ostream_iterator<std::string>(world_file, "\n"));
+}
+
+void
+VDBRepository::add_to_world(const QualifiedPackageName & n) const
+{
+ add_string_to_world(stringify(n));
+}
+
+void
+VDBRepository::add_to_world(const SetName & n) const
+{
+ add_string_to_world(stringify(n));
+}
+
+void
+VDBRepository::remove_from_world(const QualifiedPackageName & n) const
+{
+ remove_string_from_world(stringify(n));
+}
+
+void
+VDBRepository::remove_from_world(const SetName & n) const
+{
+ remove_string_from_world(stringify(n));
+}
+
+std::string
+VDBRepository::get_environment_variable(
+ const PackageDatabaseEntry & for_package,
+ const std::string & var) const
+{
+ Context context("When fetching environment variable '" + var + "' for '" +
+ stringify(for_package) + "':");
+
+ FSEntry vdb_dir(_imp->location / stringify(for_package.name.category)
+ / (stringify(for_package.name.package) + "-" +
+ stringify(for_package.version)));
+
+ if (! vdb_dir.is_directory())
+ throw EnvironmentVariableActionError("Could not find VDB entry for '"
+ + stringify(for_package) + "'");
+
+ if ((vdb_dir / var).is_regular_file())
+ {
+ std::ifstream f(stringify(vdb_dir / var).c_str());
+ if (! f)
+ throw EnvironmentVariableActionError("Could not read '" +
+ stringify(vdb_dir / var) + "'");
+ return strip_trailing_string(
+ std::string((std::istreambuf_iterator<char>(f)),
+ std::istreambuf_iterator<char>()), "\n");
+ }
+ else if ((vdb_dir / "environment.bz2").is_regular_file())
+ {
+ if (is_full_env(vdb_dir))
+ {
+ PStream p("bash -c '( bunzip2 < " + stringify(vdb_dir / "environment.bz2" ) +
+ " ; echo echo \\$" + var + " ) | bash 2>/dev/null'");
+ std::string result(strip_trailing_string(std::string(
+ (std::istreambuf_iterator<char>(p)),
+ std::istreambuf_iterator<char>()), "\n"));
+ if (0 != p.exit_status())
+ throw EnvironmentVariableActionError("Could not load environment.bz2");
+ return result;
+ }
+ else
+ {
+ PStream p("bunzip2 < " + stringify(vdb_dir / "environment.bz2" ));
+ KeyValueConfigFile k(&p);
+
+ if (0 != p.exit_status())
+ throw EnvironmentVariableActionError("Could not get variable '" + var +
+ "' from environment.bz2 for '" + stringify(for_package) + "'");
+
+ return k.get(var);
+ }
+ }
+ else
+ throw EnvironmentVariableActionError("Could not get variable '" + var + "' for '"
+ + stringify(for_package) + "'");
+}
+
+std::tr1::shared_ptr<const RepositoryProvidesInterface::ProvidesCollection>
+VDBRepository::provided_packages() const
+{
+ if (_imp->provides)
+ return _imp->provides;
+
+ if (! load_provided_using_cache())
+ load_provided_the_slow_way();
+
+ return _imp->provides;
+}
+
+std::tr1::shared_ptr<const VersionMetadata>
+VDBRepository::provided_package_version_metadata(const RepositoryProvidesEntry & p) const
+{
+ std::tr1::shared_ptr<const VersionMetadata> m(version_metadata(p.provided_by_name, p.version));
+ std::tr1::shared_ptr<VDBVirtualVersionMetadata> result(new VDBVirtualVersionMetadata(
+ m->slot, PackageDatabaseEntry(p.provided_by_name, p.version, name())));
+
+ result->eapi = m->eapi;
+ result->build_depend_string = stringify(p.provided_by_name);
+ result->run_depend_string = stringify(p.provided_by_name);
+
+ return result;
+}
+
+std::tr1::shared_ptr<const UseFlagNameCollection>
+VDBRepository::do_arch_flags() const
+{
+ return std::tr1::shared_ptr<const UseFlagNameCollection>(new UseFlagNameCollection::Concrete);
+}
+
+std::tr1::shared_ptr<const UseFlagNameCollection>
+VDBRepository::do_use_expand_flags() const
+{
+ return std::tr1::shared_ptr<const UseFlagNameCollection>(new UseFlagNameCollection::Concrete);
+}
+
+std::tr1::shared_ptr<const UseFlagNameCollection>
+VDBRepository::do_use_expand_prefixes() const
+{
+ return std::tr1::shared_ptr<const UseFlagNameCollection>(new UseFlagNameCollection::Concrete);
+}
+
+std::tr1::shared_ptr<const UseFlagNameCollection>
+VDBRepository::do_use_expand_hidden_prefixes() const
+{
+ return std::tr1::shared_ptr<const UseFlagNameCollection>(new UseFlagNameCollection::Concrete);
+}
+
+UseFlagName
+VDBRepository::do_use_expand_name(const UseFlagName & u) const
+{
+ return u;
+}
+
+UseFlagName
+VDBRepository::do_use_expand_value(const UseFlagName & u) const
+{
+ return u;
+}
+
+bool
+VDBRepository::load_provided_using_cache() const
+{
+ if (_imp->provides_cache == FSEntry("/var/empty"))
+ return false;
+
+ Context context("When loading VDB PROVIDEs map using '" + stringify(_imp->provides_cache) + "':");
+
+ std::tr1::shared_ptr<ProvidesCollection> result(new ProvidesCollection::Concrete);
+
+ if (! _imp->provides_cache.is_regular_file())
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "Provides cache at '"
+ + stringify(_imp->provides_cache) + "' is not a regular file.");
+ return false;
+ }
+
+ std::ifstream provides_cache(stringify(_imp->provides_cache).c_str());
+
+ std::string version;
+ std::getline(provides_cache, version);
+
+ if (version != "paludis-2")
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "Can't use provides cache at '"
+ + stringify(_imp->provides_cache) + "' because format '" + version + "' is not 'paludis-2'");
+ return false;
+ }
+
+ std::string for_name;
+ std::getline(provides_cache, for_name);
+ if (for_name != stringify(name()))
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "Can't use provides cache at '"
+ + stringify(_imp->provides_cache) + "' because it was generated for repository '"
+ + for_name + "'. You must not have multiple name caches at the same location.");
+ return false;
+ }
+
+ std::string line;
+ while (std::getline(provides_cache, line))
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(line, std::back_inserter(tokens));
+ if (tokens.size() < 3)
+ continue;
+
+ PackageDatabaseEntry dbe(QualifiedPackageName(tokens.at(0)), VersionSpec(tokens.at(1)), name());
+ DepAtomFlattener f(_imp->env, &dbe, PortageDepParser::parse(
+ join(next(next(tokens.begin())), tokens.end(), " "),
+ PortageDepParserPolicy<PackageDepAtom, false>::get_instance()));
+
+ for (DepAtomFlattener::Iterator p(f.begin()), p_end(f.end()) ; p != p_end ; ++p)
+ result->insert(RepositoryProvidesEntry::create()
+ .virtual_name((*p)->text())
+ .version(dbe.version)
+ .provided_by_name(dbe.name));
+ }
+
+ _imp->provides = result;
+ return true;
+}
+
+void
+VDBRepository::load_provided_the_slow_way() const
+{
+ Context context("When loading VDB PROVIDEs map the slow way:");
+
+ Log::get_instance()->message(ll_debug, lc_no_context, "Starting VDB PROVIDEs map creation");
+
+ std::tr1::shared_ptr<ProvidesCollection> result(new ProvidesCollection::Concrete);
+
+ if (! _imp->entries_valid)
+ _imp->load_entries();
+
+ for (std::vector<VDBEntry>::iterator e(_imp->entries.begin()),
+ e_end(_imp->entries.end()) ; e != e_end ; ++e)
+ {
+ Context loop_context("When loading VDB PROVIDEs entry for '"
+ + stringify(e->name) + "-" + stringify(e->version) + "':");
+
+ try
+ {
+ std::string provide_str;
+ if (e->metadata)
+ provide_str = e->metadata->ebuild_interface->provide_string;
+ else
+ {
+ // _imp->load_entry(e); slow
+ provide_str = file_contents(_imp->location, e->name, e->version, "PROVIDE");
+ }
+ if (provide_str.empty())
+ continue;
+
+ std::tr1::shared_ptr<const DepAtom> provide(PortageDepParser::parse(provide_str,
+ PortageDepParserPolicy<PackageDepAtom, false>::get_instance()));
+ PackageDatabaseEntry dbe(e->name, e->version, name());
+ DepAtomFlattener f(_imp->env, &dbe, provide);
+
+ for (DepAtomFlattener::Iterator p(f.begin()), p_end(f.end()) ; p != p_end ; ++p)
+ {
+ QualifiedPackageName pp((*p)->text());
+
+ if (pp.category != CategoryNamePart("virtual"))
+ Log::get_instance()->message(ll_warning, lc_no_context, "PROVIDE of non-virtual '"
+ + stringify(pp) + "' from '" + stringify(e->name) + "-"
+ + stringify(e->version) + "' in '" + stringify(name())
+ + "' will not work as expected");
+
+ result->insert(RepositoryProvidesEntry::create()
+ .virtual_name(pp)
+ .version(e->version)
+ .provided_by_name(e->name));
+ }
+ }
+ catch (const InternalError &)
+ {
+ throw;
+ }
+ catch (const Exception & ee)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "Skipping VDB PROVIDE entry for '"
+ + stringify(e->name) + "-" + stringify(e->version) + "' due to exception '"
+ + stringify(ee.message()) + "' (" + stringify(ee.what()) + ")");
+ }
+ }
+
+ Log::get_instance()->message(ll_debug, lc_no_context, "Done VDB PROVIDEs map creation");
+
+ _imp->provides = result;
+}
+
+void
+VDBRepository::regenerate_cache() const
+{
+ regenerate_provides_cache();
+ _imp->names_cache->regenerate_cache();
+}
+
+void
+VDBRepository::regenerate_provides_cache() const
+{
+ if (_imp->provides_cache == FSEntry("/var/empty"))
+ return;
+
+ Context context("When generating VDB repository provides cache at '"
+ + stringify(_imp->provides_cache) + "':");
+
+ FSEntry(_imp->provides_cache).unlink();
+ _imp->provides_cache.dirname().mkdir();
+
+ if (! _imp->entries_valid)
+ _imp->load_entries();
+
+ std::ofstream f(stringify(_imp->provides_cache).c_str());
+ if (! f)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Cannot write to '"
+ + stringify(_imp->provides_cache) + "'");
+ return;
+ }
+
+ f << "paludis-2" << std::endl;
+ f << name() << std::endl;
+
+ for (std::vector<VDBEntry>::const_iterator c(_imp->entries.begin()), c_end(_imp->entries.end()) ;
+ c != c_end ; ++c)
+ {
+ std::string provide_str;
+ if (c->metadata)
+ provide_str = c->metadata->ebuild_interface->provide_string;
+ else
+ provide_str = file_contents(_imp->location, c->name, c->version, "PROVIDE");
+
+ provide_str = strip_leading(strip_trailing(provide_str, " \t\r\n"), " \t\r\n");
+ if (provide_str.empty())
+ continue;
+
+ f << c->name << " " << c->version << " " << provide_str << std::endl;
+ }
+}
+
+std::tr1::shared_ptr<const CategoryNamePartCollection>
+VDBRepository::do_category_names_containing_package(const PackageNamePart & p) const
+{
+ if (! _imp->names_cache->usable())
+ return Repository::do_category_names_containing_package(p);
+
+ std::tr1::shared_ptr<const CategoryNamePartCollection> result(
+ _imp->names_cache->category_names_containing_package(p));
+
+ return result ? result : Repository::do_category_names_containing_package(p);
+}
+
+bool
+VDBRepository::is_suitable_destination_for(const PackageDatabaseEntry & e) const
+{
+ return _imp->env->package_database()->fetch_repository(e.repository)->format() == "ebuild";
+}
+
+bool
+VDBRepository::is_default_destination() const
+{
+ return _imp->env->root() == root();
+}
+
+std::string
+VDBRepository::do_describe_use_flag(const UseFlagName &,
+ const PackageDatabaseEntry * const) const
+{
+ return "";
+}
+
+FSEntry
+VDBRepository::root() const
+{
+ return _imp->root;
+}
+
diff --git a/paludis/repositories/gentoo/vdb_repository.hh b/paludis/repositories/gentoo/vdb_repository.hh
new file mode 100644
index 0000000..ddf85d8
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_repository.hh
@@ -0,0 +1,207 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_VDB_REPOSITORY_HH
+#define PALUDIS_GUARD_PALUDIS_VDB_REPOSITORY_HH 1
+
+#include <paludis/repository.hh>
+#include <paludis/util/attributes.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/fs_entry.hh>
+
+/** \file
+ * Declarations for VDBRepository.
+ *
+ * \ingroup grpvdbrepository
+ */
+
+namespace paludis
+{
+
+#include <paludis/repositories/gentoo/vdb_repository-sr.hh>
+
+ /**
+ * A VDBRepository represents the /var/db/pkg database used for
+ * installed packages.
+ *
+ * It has a stupid name because Portage called it that.
+ *
+ * \ingroup grpvdbrepository
+ */
+ class PALUDIS_VISIBLE VDBRepository :
+ public Repository,
+ public RepositoryInstalledInterface,
+ public RepositoryUseInterface,
+ public RepositoryUninstallableInterface,
+ public RepositorySetsInterface,
+ public RepositoryWorldInterface,
+ public RepositoryEnvironmentVariableInterface,
+ public RepositoryProvidesInterface,
+ public RepositoryDestinationInterface,
+ public RepositoryContentsInterface,
+ public RepositoryConfigInterface,
+ public PrivateImplementationPattern<VDBRepository>
+ {
+ private:
+ bool load_provided_using_cache() const;
+ void load_provided_the_slow_way() const;
+
+ void regenerate_provides_cache() const;
+
+ protected:
+ virtual bool do_has_category_named(const CategoryNamePart &) const;
+
+ virtual bool do_has_package_named(const QualifiedPackageName &) const;
+
+ virtual std::tr1::shared_ptr<const CategoryNamePartCollection> do_category_names() const;
+
+ virtual std::tr1::shared_ptr<const QualifiedPackageNameCollection> do_package_names(
+ const CategoryNamePart &) const;
+
+ virtual std::tr1::shared_ptr<const VersionSpecCollection> do_version_specs(
+ const QualifiedPackageName &) const;
+
+ virtual bool do_has_version(const QualifiedPackageName &, const VersionSpec &) const;
+
+ virtual std::tr1::shared_ptr<const VersionMetadata> do_version_metadata(
+ const QualifiedPackageName &,
+ const VersionSpec &) const;
+
+ virtual std::tr1::shared_ptr<const Contents> do_contents(
+ const QualifiedPackageName &,
+ const VersionSpec &) const;
+
+ virtual time_t do_installed_time(
+ const QualifiedPackageName &,
+ const VersionSpec &) const;
+
+ virtual bool do_is_licence(const std::string &) const;
+
+ virtual void do_uninstall(const QualifiedPackageName &, const VersionSpec &,
+ const InstallOptions &) const;
+
+ virtual std::tr1::shared_ptr<DepAtom> do_package_set(const SetName &) const;
+
+ /* RepositoryUseInterface */
+
+ virtual UseFlagState do_query_use(const UseFlagName &, const PackageDatabaseEntry *) const;
+ virtual bool do_query_use_mask(const UseFlagName &, const PackageDatabaseEntry *) const;
+ virtual bool do_query_use_force(const UseFlagName &, const PackageDatabaseEntry *) const;
+ virtual std::tr1::shared_ptr<const UseFlagNameCollection> do_arch_flags() const;
+ virtual std::tr1::shared_ptr<const UseFlagNameCollection> do_use_expand_flags() const;
+ virtual std::tr1::shared_ptr<const UseFlagNameCollection> do_use_expand_hidden_prefixes() const;
+ virtual UseFlagName do_use_expand_name(const UseFlagName & u) const;
+ virtual UseFlagName do_use_expand_value(const UseFlagName & u) const;
+ virtual std::tr1::shared_ptr<const UseFlagNameCollection> do_use_expand_prefixes() const;
+
+ /* end of RepositoryUseInterface */
+
+ virtual std::tr1::shared_ptr<const CategoryNamePartCollection> do_category_names_containing_package(
+ const PackageNamePart &) const;
+
+ virtual void add_string_to_world(const std::string &) const;
+
+ virtual void remove_string_from_world(const std::string &) const;
+
+ virtual void do_config(const QualifiedPackageName &, const VersionSpec &) const;
+
+ public:
+ /**
+ * Constructor.
+ */
+ VDBRepository(const VDBRepositoryParams &);
+
+ /**
+ * Virtual constructor.
+ */
+ static std::tr1::shared_ptr<Repository> make_vdb_repository(
+ Environment * const env,
+ std::tr1::shared_ptr<const AssociativeCollection<std::string, std::string> > m);
+
+ /**
+ * Destructor.
+ */
+ ~VDBRepository();
+
+ virtual void invalidate();
+
+ virtual void regenerate_cache() const;
+
+ virtual void add_to_world(const QualifiedPackageName &) const;
+
+ virtual void remove_from_world(const QualifiedPackageName &) const;
+
+ virtual void add_to_world(const SetName &) const;
+
+ virtual void remove_from_world(const SetName &) const;
+
+ virtual std::string get_environment_variable(
+ const PackageDatabaseEntry & for_package,
+ const std::string & var) const;
+
+ virtual std::tr1::shared_ptr<const ProvidesCollection> provided_packages() const;
+
+ virtual std::tr1::shared_ptr<const VersionMetadata> provided_package_version_metadata(
+ const RepositoryProvidesEntry &) const;
+
+ virtual std::tr1::shared_ptr<const SetsCollection> sets_list() const;
+
+ virtual bool is_suitable_destination_for(const PackageDatabaseEntry &) const;
+
+ virtual bool is_default_destination() const;
+
+ virtual std::string do_describe_use_flag(const UseFlagName &,
+ const PackageDatabaseEntry * const) const;
+
+ virtual FSEntry root() const;
+ };
+
+ /**
+ * Thrown if invalid parameters are provided for
+ * PortageRepository::make_portage_repository.
+ *
+ * \ingroup grpvdbrepository
+ * \ingroup grpexceptions
+ */
+ class PALUDIS_VISIBLE VDBRepositoryConfigurationError : public ConfigurationError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ VDBRepositoryConfigurationError(const std::string & msg) throw ();
+ };
+
+ /**
+ * Thrown if a key read fails.
+ *
+ * \ingroup grpvdbrepository
+ * \ingroup grpexceptions
+ */
+ class PALUDIS_VISIBLE VDBRepositoryKeyReadError : public ConfigurationError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ VDBRepositoryKeyReadError(const std::string & msg) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/vdb_repository.sr b/paludis/repositories/gentoo/vdb_repository.sr
new file mode 100644
index 0000000..48df155
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_repository.sr
@@ -0,0 +1,26 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+make_class_VDBRepositoryParams()
+{
+ key environment "const Environment *"
+ key location FSEntry
+ key root FSEntry
+ key world FSEntry
+ key provides_cache FSEntry
+ key names_cache FSEntry
+ key buildroot FSEntry
+
+ doxygen_comment << "END"
+ /**
+ * Parameters used to create a VDBRepository
+ *
+ * \see VDBRepository
+ * \ingroup grpvdbrepository
+ * \nosubgrouping
+ */
+END
+
+ allow_named_args
+}
+
diff --git a/paludis/repositories/gentoo/vdb_repository_TEST.cc b/paludis/repositories/gentoo/vdb_repository_TEST.cc
new file mode 100644
index 0000000..c684ee0
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_repository_TEST.cc
@@ -0,0 +1,249 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/repositories/vdb/vdb_repository.hh>
+#include <paludis/util/collection_concrete.hh>
+#include <paludis/environment/test/test_environment.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <fstream>
+#include <iterator>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for VDBRepository.
+ *
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test VDBRepository repo names
+ *
+ */
+ struct VDBRepositoryRepoNameTest : TestCase
+ {
+ VDBRepositoryRepoNameTest() : TestCase("repo name") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "vdb");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("provides_cache", "/var/empty");
+ keys->insert("location", "vdb_repository_TEST_dir/repo1");
+ std::tr1::shared_ptr<Repository> repo(VDBRepository::make_vdb_repository(&env, keys));
+ TEST_CHECK_STRINGIFY_EQUAL(repo->name(), "installed");
+ }
+ } test_vdb_repository_repo_name;
+
+ /**
+ * \test Test VDBRepository has_category_named
+ *
+ */
+ struct VDBRepositoryHasCategoryNamedTest : TestCase
+ {
+ VDBRepositoryHasCategoryNamedTest() : TestCase("has category named") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "vdb");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("provides_cache", "/var/empty");
+ keys->insert("location", "vdb_repository_TEST_dir/repo1");
+ std::tr1::shared_ptr<Repository> repo(VDBRepository::make_vdb_repository(
+ &env, keys));
+
+ TEST_CHECK(repo->has_category_named(CategoryNamePart("cat-one")));
+ TEST_CHECK(repo->has_category_named(CategoryNamePart("cat-two")));
+ TEST_CHECK(! repo->has_category_named(CategoryNamePart("cat-three")));
+ }
+ } test_vdb_repository_has_category_named;
+
+ /**
+ * \test Test VDBRepository query_use
+ *
+ */
+ struct VDBRepositoryQueryUseTest : TestCase
+ {
+ VDBRepositoryQueryUseTest() : TestCase("query USE") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "vdb");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("provides_cache", "/var/empty");
+ keys->insert("location", "vdb_repository_TEST_dir/repo1");
+ std::tr1::shared_ptr<Repository> repo(VDBRepository::make_vdb_repository(
+ &env, keys));
+
+ PackageDatabaseEntry e1(CategoryNamePart("cat-one") + PackageNamePart("pkg-one"),
+ VersionSpec("1"), RepositoryName("installed"));
+ PackageDatabaseEntry e2(CategoryNamePart("cat-one") + PackageNamePart("pkg-neither"),
+ VersionSpec("1"), RepositoryName("installed"));
+
+ TEST_CHECK(repo->use_interface->query_use(UseFlagName("flag1"), &e1) == use_enabled);
+ TEST_CHECK(repo->use_interface->query_use(UseFlagName("flag2"), &e1) == use_enabled);
+ TEST_CHECK(repo->use_interface->query_use(UseFlagName("flag3"), &e1) == use_disabled);
+
+ TEST_CHECK(repo->use_interface->query_use(UseFlagName("flag4"), &e2) == use_unspecified);
+ }
+ } test_vdb_repository_query_use;
+
+ /**
+ * \test Test VDBRepository add_to_world.
+ */
+ struct VDBRepositoryAddToWorldNewFileTest : TestCase
+ {
+ VDBRepositoryAddToWorldNewFileTest() : TestCase("add to world (new file)") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "vdb");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("provides_cache", "/var/empty");
+ keys->insert("location", "vdb_repository_TEST_dir/repo1");
+ keys->insert("world", "vdb_repository_TEST_dir/world-new-file");
+ std::tr1::shared_ptr<Repository> repo(VDBRepository::make_vdb_repository(
+ &env, keys));
+ repo->world_interface->add_to_world(QualifiedPackageName("cat-one/foofoo"));
+ std::ifstream world("vdb_repository_TEST_dir/world-new-file");
+ std::string world_content((std::istreambuf_iterator<char>(world)), std::istreambuf_iterator<char>());
+ TEST_CHECK_EQUAL(world_content, "cat-one/foofoo\n");
+ }
+ } test_vdb_repository_add_to_world_new_file;
+
+ /**
+ * \test Test VDBRepository add_to_world.
+ */
+ struct VDBRepositoryAddToWorldEmptyFileTest : TestCase
+ {
+ VDBRepositoryAddToWorldEmptyFileTest() : TestCase("add to world (empty file)") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "vdb");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("provides_cache", "/var/empty");
+ keys->insert("location", "vdb_repository_TEST_dir/repo1");
+ keys->insert("world", "vdb_repository_TEST_dir/world-empty");
+ std::tr1::shared_ptr<Repository> repo(VDBRepository::make_vdb_repository(
+ &env, keys));
+ repo->world_interface->add_to_world(QualifiedPackageName("cat-one/foofoo"));
+ std::ifstream world("vdb_repository_TEST_dir/world-empty");
+ std::string world_content((std::istreambuf_iterator<char>(world)), std::istreambuf_iterator<char>());
+ TEST_CHECK_EQUAL(world_content, "cat-one/foofoo\n");
+ }
+ } test_vdb_repository_add_to_world_empty_file;
+
+ /**
+ * \test Test VDBRepository add_to_world.
+ */
+ struct VDBRepositoryAddToWorldNoMatchTest : TestCase
+ {
+ VDBRepositoryAddToWorldNoMatchTest() : TestCase("add to world (no match)") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "vdb");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("provides_cache", "/var/empty");
+ keys->insert("location", "vdb_repository_TEST_dir/repo1");
+ keys->insert("world", "vdb_repository_TEST_dir/world-no-match");
+ std::tr1::shared_ptr<Repository> repo(VDBRepository::make_vdb_repository(
+ &env, keys));
+ repo->world_interface->add_to_world(QualifiedPackageName("cat-one/foofoo"));
+ std::ifstream world("vdb_repository_TEST_dir/world-no-match");
+ std::string world_content((std::istreambuf_iterator<char>(world)), std::istreambuf_iterator<char>());
+ TEST_CHECK_EQUAL(world_content, "cat-one/foo\ncat-one/bar\ncat-one/oink\ncat-one/foofoo\n");
+ }
+ } test_vdb_repository_add_to_world_no_match;
+
+ /**
+ * \test Test VDBRepository add_to_world.
+ */
+ struct VDBRepositoryAddToWorldMatchTest : TestCase
+ {
+ VDBRepositoryAddToWorldMatchTest() : TestCase("add to world (match)") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "vdb");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("provides_cache", "/var/empty");
+ keys->insert("location", "vdb_repository_TEST_dir/repo1");
+ keys->insert("world", "vdb_repository_TEST_dir/world-match");
+ std::tr1::shared_ptr<Repository> repo(VDBRepository::make_vdb_repository(
+ &env, keys));
+ repo->world_interface->add_to_world(QualifiedPackageName("cat-one/foofoo"));
+ std::ifstream world("vdb_repository_TEST_dir/world-match");
+ std::string world_content((std::istreambuf_iterator<char>(world)), std::istreambuf_iterator<char>());
+ TEST_CHECK_EQUAL(world_content, "cat-one/foo\ncat-one/foofoo\ncat-one/bar\n");
+ }
+ } test_vdb_repository_add_to_world_match;
+
+ /**
+ * \test Test VDBRepository add_to_world.
+ */
+ struct VDBRepositoryAddToWorldNoMatchNoEOLTest : TestCase
+ {
+ VDBRepositoryAddToWorldNoMatchNoEOLTest() : TestCase("add to world (no match, no trailing eol)") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ std::tr1::shared_ptr<AssociativeCollection<std::string, std::string> > keys(
+ new AssociativeCollection<std::string, std::string>::Concrete);
+ keys->insert("format", "vdb");
+ keys->insert("names_cache", "/var/empty");
+ keys->insert("provides_cache", "/var/empty");
+ keys->insert("location", "vdb_repository_TEST_dir/repo1");
+ keys->insert("world", "vdb_repository_TEST_dir/world-no-match-no-eol");
+ std::tr1::shared_ptr<Repository> repo(VDBRepository::make_vdb_repository(
+ &env, keys));
+ repo->world_interface->add_to_world(QualifiedPackageName("cat-one/foofoo"));
+ std::ifstream world("vdb_repository_TEST_dir/world-no-match-no-eol");
+ std::string world_content((std::istreambuf_iterator<char>(world)), std::istreambuf_iterator<char>());
+ TEST_CHECK_EQUAL(world_content, "cat-one/foo\ncat-one/bar\ncat-one/oink\ncat-one/foofoo\n");
+ }
+ } test_vdb_repository_add_to_world_no_match_no_eol;
+}
+
diff --git a/paludis/repositories/gentoo/vdb_repository_TEST_cleanup.sh b/paludis/repositories/gentoo/vdb_repository_TEST_cleanup.sh
new file mode 100755
index 0000000..e9f03a6
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_repository_TEST_cleanup.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d vdb_repository_TEST_dir ] ; then
+ rm -fr vdb_repository_TEST_dir
+else
+ true
+fi
+
+
+
diff --git a/paludis/repositories/gentoo/vdb_repository_TEST_setup.sh b/paludis/repositories/gentoo/vdb_repository_TEST_setup.sh
new file mode 100755
index 0000000..138a6b1
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_repository_TEST_setup.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir -p vdb_repository_TEST_dir || exit 1
+cd vdb_repository_TEST_dir || exit 1
+
+mkdir -p repo1/cat-{one/{pkg-one-1,pkg-both-1},two/{pkg-two-2,pkg-both-2}} || exit 1
+
+for i in SLOT EAPI; do
+ echo "0" >repo1/cat-one/pkg-one-1/${i}
+done
+
+for i in DEPEND RDEPEND LICENSE INHERITED IUSE PDEPEND PROVIDE; do
+ touch repo1/cat-one/pkg-one-1/${i}
+done
+
+echo "flag1 flag2" >>repo1/cat-one/pkg-one-1/USE
+
+touch "world-empty"
+cat <<END > world-no-match
+cat-one/foo
+cat-one/bar
+cat-one/oink
+END
+cat <<END > world-match
+cat-one/foo
+cat-one/foofoo
+cat-one/bar
+END
+cat <<END > world-no-match-no-eol
+cat-one/foo
+cat-one/bar
+END
+echo -n "cat-one/oink" >> world-no-match-no-eol
+
diff --git a/paludis/repositories/gentoo/vdb_version_metadata.cc b/paludis/repositories/gentoo/vdb_version_metadata.cc
new file mode 100644
index 0000000..c5e3171
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_version_metadata.cc
@@ -0,0 +1,65 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "vdb_version_metadata.hh"
+#include <paludis/portage_dep_parser.hh>
+
+using namespace paludis;
+
+VDBVersionMetadata::VDBVersionMetadata() :
+ VersionMetadata(
+ VersionMetadataBase(SlotName("unset"), "", "", "UNKNOWN"),
+ VersionMetadataCapabilities::create()
+ .deps_interface(this)
+ .origins_interface(this)
+ .ebuild_interface(this)
+ .license_interface(this)
+ .virtual_interface(0)
+ .cran_interface(0)
+ ),
+ VersionMetadataDepsInterface(&PortageDepParser::parse_depend),
+ VersionMetadataLicenseInterface(&PortageDepParser::parse_license)
+{
+}
+
+VDBVersionMetadata::~VDBVersionMetadata()
+{
+}
+
+VDBVirtualVersionMetadata::VDBVirtualVersionMetadata(const SlotName & s,
+ const PackageDatabaseEntry & e) :
+ VersionMetadata(
+ VersionMetadataBase(s, "", "", "UNKNOWN"),
+ VersionMetadataCapabilities::create()
+ .deps_interface(this)
+ .origins_interface(0)
+ .ebuild_interface(0)
+ .license_interface(0)
+ .virtual_interface(this)
+ .cran_interface(0)
+ ),
+ VersionMetadataDepsInterface(&PortageDepParser::parse_depend),
+ VersionMetadataVirtualInterface(e)
+{
+}
+
+VDBVirtualVersionMetadata::~VDBVirtualVersionMetadata()
+{
+}
+
diff --git a/paludis/repositories/gentoo/vdb_version_metadata.hh b/paludis/repositories/gentoo/vdb_version_metadata.hh
new file mode 100644
index 0000000..f22721b
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_version_metadata.hh
@@ -0,0 +1,50 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_VDB_VDB_VERSION_METADATA_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_VDB_VDB_VERSION_METADATA_HH 1
+
+#include <paludis/version_metadata.hh>
+
+namespace paludis
+{
+ class VDBVersionMetadata :
+ public VersionMetadata,
+ public VersionMetadataDepsInterface,
+ public VersionMetadataOriginsInterface,
+ public VersionMetadataEbuildInterface,
+ public VersionMetadataLicenseInterface
+ {
+ public:
+ VDBVersionMetadata();
+ virtual ~VDBVersionMetadata();
+ };
+
+ class VDBVirtualVersionMetadata :
+ public VersionMetadata,
+ public VersionMetadataDepsInterface,
+ public VersionMetadataVirtualInterface
+ {
+ public:
+ VDBVirtualVersionMetadata(const SlotName &, const PackageDatabaseEntry &);
+ virtual ~VDBVirtualVersionMetadata();
+ };
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/xml_things.cc b/paludis/repositories/gentoo/xml_things.cc
new file mode 100644
index 0000000..a54ac07
--- /dev/null
+++ b/paludis/repositories/gentoo/xml_things.cc
@@ -0,0 +1,219 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <paludis/repositories/gentoo/glsa.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/join.hh>
+#include <paludis/config_file.hh>
+#include <set>
+#include <list>
+
+using namespace paludis;
+
+extern "C"
+{
+ std::tr1::shared_ptr<GLSA> create_glsa_from_xml_file(const std::string &);
+}
+
+namespace
+{
+ std::string retarded_libxml_string_to_string(const xmlChar * const s)
+ {
+ return s ? stringify(reinterpret_cast<const char *>(s)) : "";
+ }
+
+ std::string normalise(const std::string & s)
+ {
+ std::list<std::string> words;
+ WhitespaceTokeniser::get_instance()->tokenise(s, std::back_inserter(words));
+ return join(words.begin(), words.end(), " ");
+ }
+
+ class Handler
+ {
+ private:
+ std::tr1::shared_ptr<GLSA> _glsa;
+
+ public:
+ Handler() :
+ _glsa(new GLSA)
+ {
+ }
+
+ void handle_glsa_attrs(xmlDocPtr doc, xmlAttr * const attr)
+ {
+ for (xmlAttr * a(attr) ; a ; a = a->next)
+ {
+ if (a->type == XML_ATTRIBUTE_NODE)
+ {
+ std::string name(retarded_libxml_string_to_string(a->name));
+ if (name == "id")
+ _glsa->set_id(normalise(retarded_libxml_string_to_string(xmlNodeListGetString(doc,
+ a->xmlChildrenNode, 1))));
+ }
+ }
+ }
+
+ void handle_package_name(xmlDocPtr doc, xmlAttr * const attr, std::string & str)
+ {
+ for (xmlAttr * a(attr) ; a ; a = a->next)
+ {
+ if (a->type == XML_ATTRIBUTE_NODE)
+ {
+ std::string name(retarded_libxml_string_to_string(a->name));
+ if (name == "name")
+ str = normalise(retarded_libxml_string_to_string(xmlNodeListGetString(doc,
+ a->xmlChildrenNode, 1)));
+ }
+ }
+ }
+
+ void handle_package_archs(xmlDocPtr doc, xmlAttr * const attr, std::tr1::shared_ptr<GLSAPackage> pkg)
+ {
+ for (xmlAttr * a(attr) ; a ; a = a->next)
+ {
+ if (a->type == XML_ATTRIBUTE_NODE)
+ {
+ std::string name(retarded_libxml_string_to_string(a->name));
+ if (name == "arch")
+ {
+ std::set<std::string> archs;
+ WhitespaceTokeniser::get_instance()->tokenise(retarded_libxml_string_to_string(
+ xmlNodeListGetString(doc, a->xmlChildrenNode, 1)),
+ std::inserter(archs, archs.end()));
+ archs.erase("*");
+ for (std::set<std::string>::const_iterator r(archs.begin()), r_end(archs.end()) ;
+ r != r_end ; ++r)
+ pkg->add_arch(UseFlagName(*r));
+ }
+ }
+ }
+ }
+
+ void handle_range_range(xmlDocPtr doc, xmlAttr * const attr, std::string & op)
+ {
+ for (xmlAttr * a(attr) ; a ; a = a->next)
+ {
+ if (a->type == XML_ATTRIBUTE_NODE)
+ {
+ std::string name(retarded_libxml_string_to_string(a->name));
+ if (name == "range")
+ op = normalise(retarded_libxml_string_to_string(xmlNodeListGetString(doc,
+ a->xmlChildrenNode, 1)));
+ }
+ }
+ }
+
+ void handle_package_children(xmlDocPtr doc, xmlNode * const node, std::tr1::shared_ptr<GLSAPackage> pkg)
+ {
+ for (xmlNode * n(node) ; n ; n = n->next)
+ {
+ if (n->type == XML_ELEMENT_NODE)
+ {
+ std::string name(retarded_libxml_string_to_string(n->name));
+ if (name == "unaffected" || name == "vulnerable")
+ {
+ std::string op;
+ handle_range_range(doc, n->properties, op);
+ std::string version(normalise(retarded_libxml_string_to_string(
+ xmlNodeListGetString(doc, n->xmlChildrenNode, 1))));
+ ((*pkg).*(name == "unaffected" ? &GLSAPackage::add_unaffected : &GLSAPackage::add_vulnerable))
+ (GLSARange::create().op(op).version(version));
+ }
+ else
+ handle_node(doc, n->children);
+ }
+ else
+ handle_node(doc, n->children);
+ }
+
+ }
+
+ void handle_node(xmlDocPtr doc, xmlNode * const node)
+ {
+ for (xmlNode * n(node) ; n ; n = n->next)
+ {
+ if (n->type == XML_ELEMENT_NODE)
+ {
+ std::string name(retarded_libxml_string_to_string(n->name));
+ if (name == "glsa")
+ {
+ handle_glsa_attrs(doc, n->properties);
+ handle_node(doc, n->children);
+ }
+ else if (name == "title")
+ _glsa->set_title(normalise(retarded_libxml_string_to_string(xmlNodeListGetString(doc,
+ n->xmlChildrenNode, 1))));
+ else if (name == "package")
+ {
+ std::string m;
+ handle_package_name(doc, n->properties, m);
+ std::tr1::shared_ptr<GLSAPackage> pkg(new GLSAPackage(QualifiedPackageName(m)));
+ handle_package_archs(doc, n->properties, pkg);
+ handle_package_children(doc, n->children, pkg);
+ _glsa->add_package(pkg);
+ }
+ else
+ handle_node(doc, n->children);
+ }
+ else
+ handle_node(doc, n->children);
+ }
+
+ }
+
+ std::tr1::shared_ptr<GLSA> glsa()
+ {
+ return _glsa;
+ }
+ };
+}
+
+std::tr1::shared_ptr<GLSA>
+create_glsa_from_xml_file(const std::string & filename)
+{
+ std::tr1::shared_ptr<xmlDoc> xml_doc(xmlReadFile(filename.c_str(), 0, 0), &xmlFreeDoc);
+ if (! xml_doc)
+ throw GLSAError("Could not parse GLSA", filename);
+
+ Handler h;
+ h.handle_node(xml_doc.get(), xmlDocGetRootElement(xml_doc.get()));
+ return h.glsa();
+}
+
+#ifndef MONOLITHIC
+
+namespace paludis
+{
+ class RepositoryMaker;
+}
+
+extern "C"
+{
+ void register_repositories(RepositoryMaker * maker);
+}
+
+void register_repositories(RepositoryMaker *)
+{
+}
+
+#endif
+
diff --git a/paludis/repositories/gentoo/xml_things.hh b/paludis/repositories/gentoo/xml_things.hh
new file mode 100644
index 0000000..772def3
--- /dev/null
+++ b/paludis/repositories/gentoo/xml_things.hh
@@ -0,0 +1,30 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_XML_THINGS_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_PORTAGE_XML_THINGS_HH 1
+
+#include <paludis/repositories/portage/glsa.hh>
+
+extern "C"
+{
+ GLSA::Pointer create_glsa_from_xml_file(const std::string &);
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/xml_things_TEST.cc b/paludis/repositories/gentoo/xml_things_TEST.cc
new file mode 100644
index 0000000..76d8313
--- /dev/null
+++ b/paludis/repositories/gentoo/xml_things_TEST.cc
@@ -0,0 +1,92 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/repositories/gentoo/glsa.hh>
+#include <paludis/util/join.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+namespace test_cases
+{
+ struct GLSA123456_78Test : TestCase
+ {
+ GLSA123456_78Test() : TestCase("glsa 123456-78") { }
+
+ void run()
+ {
+ std::tr1::shared_ptr<GLSA> glsa(GLSA::create_from_xml_file("xml_things_TEST_dir/glsa-123456-78.xml"));
+ TEST_CHECK(glsa);
+
+ TEST_CHECK_EQUAL("123456-78", glsa->id());
+ TEST_CHECK_EQUAL("Kittens: Too Adorable", glsa->title());
+
+ TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages(), glsa->end_packages()));
+ TEST_CHECK_STRINGIFY_EQUAL("animal-feline/kitten", glsa->begin_packages()->name());
+ TEST_CHECK_STRINGIFY_EQUAL("0", std::distance(glsa->begin_packages()->begin_archs(),
+ glsa->begin_packages()->end_archs()));
+
+ TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages()->begin_unaffected(),
+ glsa->begin_packages()->end_unaffected()));
+ TEST_CHECK_STRINGIFY_EQUAL("ge", glsa->begin_packages()->begin_unaffected()->op);
+ TEST_CHECK_STRINGIFY_EQUAL("1.23", glsa->begin_packages()->begin_unaffected()->version);
+
+ TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages(), glsa->end_packages()));
+ TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages()->begin_vulnerable(),
+ glsa->begin_packages()->end_vulnerable()));
+ TEST_CHECK_STRINGIFY_EQUAL("lt", glsa->begin_packages()->begin_vulnerable()->op);
+ TEST_CHECK_STRINGIFY_EQUAL("1.22", glsa->begin_packages()->begin_vulnerable()->version);
+ }
+ } glsa_test_123456_78;
+
+ struct GLSA987654_32Test : TestCase
+ {
+ GLSA987654_32Test() : TestCase("glsa 987654-32") { }
+
+ void run()
+ {
+ std::tr1::shared_ptr<GLSA> glsa(GLSA::create_from_xml_file("xml_things_TEST_dir/glsa-987654-32.xml"));
+ TEST_CHECK(glsa);
+
+ TEST_CHECK_EQUAL("987654-32", glsa->id());
+ TEST_CHECK_EQUAL("Python: Retarded", glsa->title());
+
+ TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages(), glsa->end_packages()));
+ TEST_CHECK_STRINGIFY_EQUAL("dev-lang/python", glsa->begin_packages()->name());
+ TEST_CHECK_STRINGIFY_EQUAL("3", std::distance(glsa->begin_packages()->begin_archs(),
+ glsa->begin_packages()->end_archs()));
+ TEST_CHECK_STRINGIFY_EQUAL("mips,sparc,x86", join(glsa->begin_packages()->begin_archs(),
+ glsa->begin_packages()->end_archs(), ","));
+
+ TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages()->begin_unaffected(),
+ glsa->begin_packages()->end_unaffected()));
+ TEST_CHECK_STRINGIFY_EQUAL("ge", glsa->begin_packages()->begin_unaffected()->op);
+ TEST_CHECK_STRINGIFY_EQUAL("12.34", glsa->begin_packages()->begin_unaffected()->version);
+
+ TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages(), glsa->end_packages()));
+ TEST_CHECK_STRINGIFY_EQUAL("1", std::distance(glsa->begin_packages()->begin_vulnerable(),
+ glsa->begin_packages()->end_vulnerable()));
+ TEST_CHECK_STRINGIFY_EQUAL("lt", glsa->begin_packages()->begin_vulnerable()->op);
+ TEST_CHECK_STRINGIFY_EQUAL("12.34", glsa->begin_packages()->begin_vulnerable()->version);
+ }
+ } glsa_test_987654_32;
+}
+
diff --git a/paludis/repositories/gentoo/xml_things_TEST_cleanup.sh b/paludis/repositories/