aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-02-12 16:15:43 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-02-12 16:15:43 +0000
commit8f9566eba137edade2b3fc38e5a02d242d7a20e7 (patch)
treeba8780368c67006a2457be1d7fe1652134607d56
parentc06b6fb04b4d402ba95fdf5d3455346fe448cd8b (diff)
downloadpaludis-8f9566eba137edade2b3fc38e5a02d242d7a20e7.tar.gz
paludis-8f9566eba137edade2b3fc38e5a02d242d7a20e7.tar.xz
New destination-driven merger code
-rw-r--r--configure.ac1
-rw-r--r--hooks/Makefile.am.m411
-rwxr-xr-xhooks/rewrite_broken_symlinks.bash48
-rw-r--r--paludis/Makefile.am.m42
-rw-r--r--paludis/merger/Makefile.am74
-rw-r--r--paludis/merger/merger.cc519
-rw-r--r--paludis/merger/merger.hh111
-rw-r--r--paludis/merger/merger.se23
-rw-r--r--paludis/merger/merger.sr23
-rwxr-xr-xpaludis/merger/merger_TEST_cleanup.sh9
-rwxr-xr-xpaludis/merger/merger_TEST_setup.sh73
-rw-r--r--paludis/repositories/cran/cran_installed_repository.cc12
-rw-r--r--paludis/repositories/cran/cran_installed_repository.hh4
-rw-r--r--paludis/repositories/fake/fake_installed_repository.cc11
-rw-r--r--paludis/repositories/fake/fake_installed_repository.hh2
-rw-r--r--paludis/repositories/gentoo/Makefile.am56
-rw-r--r--paludis/repositories/gentoo/ebuild.cc89
-rw-r--r--paludis/repositories/gentoo/ebuild.hh45
-rw-r--r--paludis/repositories/gentoo/ebuild.se39
-rw-r--r--paludis/repositories/gentoo/ebuild.sr23
-rw-r--r--paludis/repositories/gentoo/ebuild/Makefile.am4
-rw-r--r--paludis/repositories/gentoo/ebuild/builtin_loadenv.bash48
-rw-r--r--paludis/repositories/gentoo/ebuild/builtin_merge.bash4
-rw-r--r--paludis/repositories/gentoo/ebuild/builtin_saveenv.bash55
-rw-r--r--paludis/repositories/gentoo/ebuild/die_functions.bash58
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/ebuild.bash75
-rwxr-xr-xpaludis/repositories/gentoo/ebuild/write_vdb_entry.bash100
-rw-r--r--paludis/repositories/gentoo/ebuild_entries.cc66
-rw-r--r--paludis/repositories/gentoo/portage_repository_profile.cc11
-rw-r--r--paludis/repositories/gentoo/vdb_merger.hh57
-rw-r--r--paludis/repositories/gentoo/vdb_merger.sr28
-rw-r--r--paludis/repositories/gentoo/vdb_repository.cc161
-rw-r--r--paludis/repositories/gentoo/vdb_repository.hh7
-rw-r--r--paludis/repositories/gentoo/vdb_repository.sr2
-rw-r--r--paludis/repositories/gentoo/vdb_unmerger.cc291
-rw-r--r--paludis/repositories/gentoo/vdb_unmerger.hh62
-rw-r--r--paludis/repositories/gentoo/vdb_unmerger.sr27
-rw-r--r--paludis/repository.hh24
-rw-r--r--paludis/repository.sr19
-rw-r--r--paludis/util/fs_entry.cc7
-rw-r--r--paludis/util/fs_entry.hh7
41 files changed, 2134 insertions, 154 deletions
diff --git a/configure.ac b/configure.ac
index 9c677b1..2d13f55 100644
--- a/configure.ac
+++ b/configure.ac
@@ -899,6 +899,7 @@ AC_OUTPUT(
paludis/environment/test/Makefile
paludis/fetchers/Makefile
paludis/hashed_containers.hh
+ paludis/merger/Makefile
paludis/qa/Makefile
paludis/repositories/Makefile
paludis/repositories/cran/Makefile
diff --git a/hooks/Makefile.am.m4 b/hooks/Makefile.am.m4
index 298239a..7dcf0bf 100644
--- a/hooks/Makefile.am.m4
+++ b/hooks/Makefile.am.m4
@@ -12,7 +12,6 @@ installvarlibpaludisnewsdir = $(localstatedir)/paludis/news
installhookcommonprogdir = $(libexecdir)/paludis/hooks/common
installhookinstallallpostdir = $(libexecdir)/paludis/hooks/install_all_post
installhookinstallpostdir = $(libexecdir)/paludis/hooks/install_post
-installhookebuildmergepredir = $(libexecdir)/paludis/hooks/ebuild_merge_pre
installhookcommonprog_SCRIPTS = \
gnu_info_index.bash \
@@ -29,9 +28,6 @@ installhookinstallallpost_SCRIPTS = \
installhookinstallpost_SCRIPTS = \
update_config_protect_list.bash
-installhookebuildmergepre_SCRIPTS = \
- rewrite_broken_symlinks.bash
-
installvarlibpaludisnews_DATA = \
.keep
@@ -46,7 +42,6 @@ EXTRA_DIST = \
$(installhookcommonprog_SCRIPTS) \
$(installhookinstallallpost_SCRIPTS) \
$(installhookinstallpost_SCRIPTS) \
- $(installhookebuildmergepre_SCRIPTS) \
$(TESTS)
check_SCRIPTS = $(TESTS)
@@ -90,12 +85,6 @@ userhook(`ebuild_init_post')
userhook(`ebuild_fetch_pre')
userhook(`ebuild_fetch_fail')
userhook(`ebuild_fetch_post')
-userhook(`ebuild_merge_pre')
-userhook(`ebuild_merge_fail')
-userhook(`ebuild_merge_post')
-userhook(`ebuild_unmerge_pre')
-userhook(`ebuild_unmerge_fail')
-userhook(`ebuild_unmerge_post')
userhook(`ebuild_tidyup_pre')
userhook(`ebuild_tidyup_fail')
userhook(`ebuild_tidyup_post')
diff --git a/hooks/rewrite_broken_symlinks.bash b/hooks/rewrite_broken_symlinks.bash
deleted file mode 100755
index 7e83d88..0000000
--- a/hooks/rewrite_broken_symlinks.bash
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/bash
-# vim: set et sw=4 sts=4 :
-
-# 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
-
-shopt -s extglob
-
-export PATH="$(${PALUDIS_EBUILD_DIR}/utils/canonicalise ${PALUDIS_EBUILD_DIR}/utils/ ):${PATH}"
-source ${PALUDIS_EBUILD_DIR}/echo_functions.bash
-
-export count=0
-einfo_unhooked "Checking for broken symlinks..."
-
-while read link ; do
- target=$(readlink "${link}" )
- if [[ "${target#${IMAGE}}" != "${target}" ]] ; then
- ebuild_notice "qa" "Found broken symlink '${link}' -> '${target}'"
- echo rm -f "${link}" 1>&2
- rm -f "${link}"
- newtarget="${target#${IMAGE}}"
- newtarget="/${newtarget##+(/)}"
- echo ln -s "${newtarget}" "${link}" 1>&2
- ln -s "${newtarget}" "${link}"
- export count=$(( ${count} + 1 ))
- fi
-done < <(find "${IMAGE}" -type l )
-
-if [[ "${count}" -eq 0 ]] ; then
- einfo_unhooked "Done checking for broken symlinks"
-else
- ewarn "Fixed ${count} broken symlinks"
-fi
-
-true
-
diff --git a/paludis/Makefile.am.m4 b/paludis/Makefile.am.m4
index 34a1004..b94876c 100644
--- a/paludis/Makefile.am.m4
+++ b/paludis/Makefile.am.m4
@@ -64,7 +64,7 @@ DEFS= \
-DLIBDIR=\"$(libdir)\"
EXTRA_DIST = about.hh.in Makefile.am.m4 paludis.hh.m4 files.m4 \
hashed_containers.hh.in testscriptlist srlist srcleanlist
-SUBDIRS = digests fetchers syncers util selinux . dep_list repositories environment args qa tasks
+SUBDIRS = digests fetchers syncers util selinux . dep_list merger repositories environment args qa tasks
BUILT_SOURCES = srcleanlist
libpaludis_la_SOURCES = filelist
diff --git a/paludis/merger/Makefile.am b/paludis/merger/Makefile.am
new file mode 100644
index 0000000..cf88f66
--- /dev/null
+++ b/paludis/merger/Makefile.am
@@ -0,0 +1,74 @@
+CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda
+
+DISTCLEANFILES = \
+ merger-sr.hh merger-sr.cc merger-se.hh merger-se.cc
+
+BUILT_SOURCES = $(DISTCLEANFILES)
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@ @PALUDIS_CXXFLAGS_VISIBILITY@
+DEFS= \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DDATADIR=\"$(datadir)\" \
+ -DLIBDIR=\"$(libdir)\"
+
+paludis_merger_includedir = $(includedir)/paludis/merger
+paludis_merger_include_HEADERS = \
+ merger.hh \
+ merger-sr.hh \
+ merger-se.cc
+
+libpaludismerger_la_SOURCES = \
+ merger.cc merger.hh
+
+libpaludismerger_la_LDFLAGS = -version-info @VERSION_LIB_CURRENT@:@VERSION_LIB_REVISION@:0
+
+libpaludismerger_la_LIBADD = \
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ $(top_builddir)/paludis/libpaludis.la
+
+lib_LTLIBRARIES = libpaludismerger.la
+
+EXTRA_DIST = \
+ merger_TEST.cc merger_TEST_setup.sh merger_TEST_cleanup.sh \
+ merger-sr.hh merger-sr.cc merger.sr \
+ merger-se.hh merger-se.cc merger.se
+
+TESTS = \
+ merger_TEST
+
+TESTS_ENVIRONMENT = env \
+ PALUDIS_EBUILD_DIR="$(top_srcdir)/paludis/repositories/gentoo/ebuild/" \
+ PALUDIS_SKIP_CONFIG="yes" \
+ PALUDIS_REPOSITORY_SO_DIR="$(top_builddir)/paludis/repositories" \
+ TEST_SCRIPT_DIR="$(srcdir)/" \
+ bash $(top_srcdir)/test/run_test.sh
+
+check_PROGRAMS = $(TESTS)
+check_SCRIPTS = merger_TEST_setup.sh merger_TEST_cleanup.sh
+
+merger_TEST_SOURCES = merger_TEST.cc
+merger_TEST_LDADD = \
+ $(top_builddir)/paludis/environment/test/libpaludistestenvironment.la \
+ $(top_builddir)/paludis/util/test_extras.o \
+ $(top_builddir)/test/libtest.a \
+ libpaludismerger.la \
+ $(top_builddir)/paludis/libpaludis.la \
+ $(top_builddir)/paludis/util/libpaludisutil.la
+
+built-sources : $(BUILT_SOURCES)
+ for s in `echo $(SUBDIRS) | tr -d .` ; do $(MAKE) -C $$s built-sources || exit 1 ; done
+
+merger-sr.hh : merger.sr $(top_srcdir)/misc/make_sr.bash
+ if ! $(top_srcdir)/misc/make_sr.bash --header $(srcdir)/merger.sr > $@ ; then rm -f $@ ; exit 1 ; fi
+
+merger-sr.cc : merger.sr $(top_srcdir)/misc/make_sr.bash
+ if ! $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/merger.sr > $@ ; then rm -f $@ ; exit 1 ; fi
+
+merger-se.hh : merger.se $(top_srcdir)/misc/make_se.bash
+ if ! $(top_srcdir)/misc/make_se.bash --header $(srcdir)/merger.se > $@ ; then rm -f $@ ; exit 1 ; fi
+
+merger-se.cc : merger.se $(top_srcdir)/misc/make_se.bash
+ if ! $(top_srcdir)/misc/make_se.bash --source $(srcdir)/merger.se > $@ ; then rm -f $@ ; exit 1 ; fi
+
diff --git a/paludis/merger/merger.cc b/paludis/merger/merger.cc
new file mode 100644
index 0000000..cb1bf0e
--- /dev/null
+++ b/paludis/merger/merger.cc
@@ -0,0 +1,519 @@
+/* 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 "merger.hh"
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/fd_holder.hh>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+using namespace paludis;
+
+#include <paludis/merger/merger-se.cc>
+#include <paludis/merger/merger-sr.cc>
+
+MergerError::MergerError(const std::string & s) throw () :
+ Exception(s)
+{
+}
+
+Merger::Merger(const MergerOptions & o) :
+ _options(o),
+ _result(true)
+{
+}
+
+Merger::~Merger()
+{
+}
+
+bool
+Merger::check()
+{
+ Context context("When checking merge from '" + stringify(_options.image) + "' to '"
+ + stringify(_options.root) + "':");
+
+ do_dir_recursive(true, _options.image, _options.root);
+ return _result;
+}
+
+void
+Merger::make_check_fail()
+{
+ _result = false;
+}
+
+void
+Merger::merge()
+{
+ Context context("When performing merge from '" + stringify(_options.image) + "' to '"
+ + stringify(_options.root) + "':");
+
+ struct SaveUmask
+ {
+ mode_t m;
+
+ SaveUmask(mode_t mm) :
+ m(mm)
+ {
+ }
+
+ ~SaveUmask()
+ {
+ ::umask(m);
+ }
+ } old_umask(::umask(0000));
+
+ do_dir_recursive(false, _options.image, _options.root);
+}
+
+MergerEntryType
+Merger::entry_type(const FSEntry & f)
+{
+ if (! f.exists())
+ return met_nothing;
+
+ if (f.is_symbolic_link())
+ return met_sym;
+
+ if (f.is_regular_file())
+ return met_file;
+
+ if (f.is_directory())
+ return met_dir;
+
+ return met_misc;
+}
+
+void
+Merger::do_dir_recursive(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ Context context("When " + stringify(is_check ? "checking" : "performing") + " merge from '" +
+ stringify(src) + "' to '" + stringify(dst) + "':");
+
+ if (! src.is_directory())
+ throw MergerError("Source directory '" + stringify(src) + "' is not a directory");
+ if ((! is_check) && (! dst.is_directory()))
+ throw MergerError("Destination directory '" + stringify(src) + "' is not a directory");
+
+ on_enter_dir(is_check, src);
+
+ for (DirIterator d(src), d_end ; d != d_end ; ++d)
+ {
+ MergerEntryType m(entry_type(*d));
+ switch (m)
+ {
+ case met_sym:
+ on_sym(is_check, *d, dst);
+ continue;
+
+ case met_file:
+ on_file(is_check, *d, dst);
+ continue;
+
+ case met_dir:
+ on_dir(is_check, *d, dst);
+ if (_result)
+ do_dir_recursive(is_check, *d, is_check ? (dst / d->basename()) : (dst / d->basename()).realpath());
+ continue;
+
+ case met_misc:
+ on_misc(is_check, *d, dst);
+ continue;
+
+ case met_nothing:
+ case last_met:
+ ;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Unexpected entry_type '" + stringify(m) + "'");
+ }
+
+ on_leave_dir(is_check, src);
+}
+
+void
+Merger::on_file(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ MergerEntryType m(entry_type(dst / src.basename()));
+
+ switch (m)
+ {
+ case met_nothing:
+ on_file_over_nothing(is_check, src, dst);
+ return;
+
+ case met_sym:
+ on_file_over_sym(is_check, src, dst);
+ return;
+
+ case met_dir:
+ on_file_over_dir(is_check, src, dst);
+ return;
+
+ case met_misc:
+ on_file_over_misc(is_check, src, dst);
+ return;
+
+ case met_file:
+ on_file_over_file(is_check, src, dst);
+ return;
+
+ case last_met:
+ ;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Unexpected entry_type '" + stringify(m) + "'");
+}
+
+void
+Merger::on_dir(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ MergerEntryType m(entry_type(dst / src.basename()));
+
+ switch (m)
+ {
+ case met_nothing:
+ on_dir_over_nothing(is_check, src, dst);
+ return;
+
+ case met_sym:
+ on_dir_over_sym(is_check, src, dst);
+ return;
+
+ case met_dir:
+ on_dir_over_dir(is_check, src, dst);
+ return;
+
+ case met_misc:
+ on_dir_over_misc(is_check, src, dst);
+ return;
+
+ case met_file:
+ on_dir_over_file(is_check, src, dst);
+ return;
+
+ case last_met:
+ ;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Unexpected entry_type '" + stringify(m) + "'");
+}
+
+void
+Merger::on_sym(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ MergerEntryType m(entry_type(dst / src.basename()));
+
+ switch (m)
+ {
+ case met_nothing:
+ on_sym_over_nothing(is_check, src, dst);
+ return;
+
+ case met_sym:
+ on_sym_over_sym(is_check, src, dst);
+ return;
+
+ case met_dir:
+ on_sym_over_dir(is_check, src, dst);
+ return;
+
+ case met_misc:
+ on_sym_over_misc(is_check, src, dst);
+ return;
+
+ case met_file:
+ on_sym_over_file(is_check, src, dst);
+ return;
+
+ case last_met:
+ ;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Unexpected entry_type '" + stringify(m) + "'");
+}
+
+void
+Merger::on_misc(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ on_error(is_check, "Cannot write '" + stringify(src) + "' to '" + stringify(dst) +
+ "' because it is not a recognised file type");
+}
+
+void
+Merger::on_enter_dir(bool, const FSEntry)
+{
+}
+
+void
+Merger::on_leave_dir(bool, const FSEntry)
+{
+}
+
+void
+Merger::on_file_over_nothing(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ if (is_check)
+ return;
+
+ install_file(src, dst, src.basename());
+ record_install_file(src, dst, src.basename());
+}
+
+void
+Merger::on_file_over_file(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ if (is_check)
+ return;
+
+ if (config_protected(src, dst))
+ {
+ std::string cfgpro_name(make_config_protect_name(src, dst));
+ install_file(src, dst, cfgpro_name);
+ record_install_file(src, dst, cfgpro_name);
+ }
+ else
+ {
+ unlink_file(dst / src.basename());
+ install_file(src, dst, src.basename());
+ record_install_file(src, dst, src.basename());
+ }
+}
+
+void
+Merger::on_file_over_dir(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ on_error(is_check, "Cannot overwrite directory '" + stringify(dst) + "' with file '"
+ + stringify(src) + "'");
+}
+
+void
+Merger::on_file_over_sym(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ if (is_check)
+ return;
+
+ unlink_sym(dst / src.basename());
+ install_file(src, dst, src.basename());
+ record_install_file(src, dst, src.basename());
+}
+
+void
+Merger::on_file_over_misc(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ if (is_check)
+ return;
+
+ unlink_misc(dst / src.basename());
+ install_file(src, dst, src.basename());
+ record_install_file(src, dst, src.basename());
+}
+
+void
+Merger::on_dir_over_nothing(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ if (is_check)
+ return;
+
+ install_dir(src, dst);
+ record_install_dir(src, dst);
+}
+
+void
+Merger::on_dir_over_file(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ on_error(is_check, "Cannot overwrite file '" + stringify(dst) + "' with directory '"
+ + stringify(src) + "'");
+}
+
+void
+Merger::on_dir_over_dir(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ if (is_check)
+ return;
+
+ record_install_dir(src, dst);
+}
+
+void
+Merger::on_dir_over_sym(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ MergerEntryType m;
+ try
+ {
+ m = entry_type((dst / src.basename()).realpath());
+ }
+ catch (const FSError &)
+ {
+ m = met_nothing;
+ }
+
+ if (m == met_dir)
+ {
+ on_warn(is_check, "Expected '" + stringify(dst / src.basename()) +
+ "' to be a directory but found a symlink to a directory");
+ record_install_dir(src, dst);
+ }
+ else
+ on_error(is_check, "Expected '" + stringify(dst) + "' to be a directory but found a symlink to a non-directory");
+}
+
+void
+Merger::on_dir_over_misc(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ if (is_check)
+ return;
+
+ unlink_misc(dst / src.basename());
+ install_dir(src, dst);
+ record_install_dir(src, dst);
+}
+
+void
+Merger::on_sym_over_nothing(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ if (is_check)
+ return;
+
+ install_sym(src, dst);
+ record_install_sym(src, dst);
+}
+
+void
+Merger::on_sym_over_file(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ if (is_check)
+ return;
+
+ unlink_file(dst / src.basename());
+ install_sym(src, dst);
+ record_install_sym(src, dst);
+}
+
+void
+Merger::on_sym_over_dir(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ on_error(is_check, "Cannot overwrite directory '" + stringify(dst) + "' with symlink '"
+ + stringify(src) + "'");
+}
+
+void
+Merger::on_sym_over_sym(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ if (is_check)
+ return;
+
+ unlink_sym(dst / src.basename());
+ install_sym(src, dst);
+ record_install_sym(src, dst);
+}
+
+void
+Merger::on_sym_over_misc(bool is_check, const FSEntry & src, const FSEntry & dst)
+{
+ if (is_check)
+ return;
+
+ unlink_misc(dst / src.basename());
+ install_sym(src, dst);
+ record_install_sym(src, dst);
+}
+
+void
+Merger::install_file(const FSEntry & src, const FSEntry & dst_dir, const std::string & dst_name)
+{
+ FDHolder input_fd(::open(stringify(src).c_str(), O_RDONLY), false);
+ if (-1 == input_fd)
+ throw MergerError("Cannot read '" + stringify(src) + "'");
+
+ FDHolder output_fd(::open(stringify(dst_dir / dst_name).c_str(), O_WRONLY | O_CREAT,
+ src.permissions()), false);
+ if (-1 == output_fd)
+ throw MergerError("Cannot write '" + stringify(dst_dir / dst_name) + "'");
+
+ if (0 != ::fchown(output_fd, src.owner(), src.group()))
+ throw MergerError("Cannot fchown '" + stringify(dst_dir / dst_name) + "'");
+
+ /* set*id bits */
+ if (0 != ::fchmod(output_fd, src.permissions()))
+ throw MergerError("Cannot fchmod '" + stringify(dst_dir / dst_name) + "'");
+
+ char buf[4096];
+ ssize_t count;
+ while ((count = read(input_fd, buf, 4096)) > 0)
+ write(output_fd, buf, count);
+}
+
+void
+Merger::install_dir(const FSEntry & src, const FSEntry & dst_dir)
+{
+ mode_t mode(src.permissions());
+ FSEntry dst(dst_dir / src.basename());
+ dst.mkdir(mode);
+ dst.chown(src.owner(), src.group());
+ /* pick up set*id bits */
+ dst.chmod(src.permissions());
+}
+
+void
+Merger::install_sym(const FSEntry & src, const FSEntry & dst_dir)
+{
+ if (0 != ::symlink(stringify(src.readlink()).c_str(), stringify(dst_dir / src.basename()).c_str()))
+ throw MergerError("Couldn't create symlink at '" + stringify(dst_dir / src.basename()) + "'");
+}
+
+void
+Merger::unlink_file(FSEntry d)
+{
+ if (d.is_regular_file())
+ {
+ mode_t mode(d.permissions());
+ if ((mode & S_ISUID) || (mode & S_ISGID))
+ {
+ mode &= 0400;
+ d.chmod(mode);
+ }
+ }
+
+ d.unlink();
+}
+
+void
+Merger::unlink_sym(FSEntry d)
+{
+ d.unlink();
+}
+
+void
+Merger::unlink_dir(FSEntry d)
+{
+ d.rmdir();
+}
+
+void
+Merger::unlink_misc(FSEntry d)
+{
+ d.unlink();
+}
+
+
diff --git a/paludis/merger/merger.hh b/paludis/merger/merger.hh
new file mode 100644
index 0000000..527b046
--- /dev/null
+++ b/paludis/merger/merger.hh
@@ -0,0 +1,111 @@
+/* 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_MERGER_MERGER_HH
+#define PALUDIS_GUARD_PALUDIS_MERGER_MERGER_HH 1
+
+#include <paludis/util/sr.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/exception.hh>
+#include <iosfwd>
+
+namespace paludis
+{
+ class Environment;
+
+#include <paludis/merger/merger-se.hh>
+#include <paludis/merger/merger-sr.hh>
+
+ class MergerError :
+ public Exception
+ {
+ public:
+ MergerError(const std::string & msg) throw ();
+ };
+
+ class Merger
+ {
+ private:
+ MergerOptions _options;
+ bool _result;
+
+ protected:
+ Merger(const MergerOptions &);
+
+ void make_check_fail();
+
+ virtual MergerEntryType entry_type(const FSEntry &);
+
+ virtual void do_dir_recursive(bool is_check, const FSEntry &, const FSEntry &);
+
+ virtual void on_enter_dir(bool is_check, const FSEntry);
+ virtual void on_leave_dir(bool is_check, const FSEntry);
+
+ virtual void on_file(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_file_over_nothing(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_file_over_file(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_file_over_dir(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_file_over_sym(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_file_over_misc(bool is_check, const FSEntry &, const FSEntry &);
+
+ virtual void install_file(const FSEntry &, const FSEntry &, const std::string &);
+ virtual void unlink_file(FSEntry);
+ virtual void record_install_file(const FSEntry &, const FSEntry &, const std::string &) = 0;
+
+ virtual void on_dir(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_dir_over_nothing(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_dir_over_file(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_dir_over_dir(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_dir_over_sym(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_dir_over_misc(bool is_check, const FSEntry &, const FSEntry &);
+
+ virtual void install_dir(const FSEntry &, const FSEntry &);
+ virtual void unlink_dir(FSEntry);
+ virtual void record_install_dir(const FSEntry &, const FSEntry &) = 0;
+
+ virtual void on_sym(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_sym_over_nothing(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_sym_over_file(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_sym_over_dir(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_sym_over_sym(bool is_check, const FSEntry &, const FSEntry &);
+ virtual void on_sym_over_misc(bool is_check, const FSEntry &, const FSEntry &);
+
+ virtual void install_sym(const FSEntry &, const FSEntry &);
+ virtual void unlink_sym(FSEntry);
+ virtual void record_install_sym(const FSEntry &, const FSEntry &) = 0;
+
+ virtual void unlink_misc(FSEntry);
+ virtual void on_misc(bool is_check, const FSEntry &, const FSEntry &);
+
+ virtual void on_error(bool is_check, const std::string &) = 0;
+ virtual void on_warn(bool is_check, const std::string &) = 0;
+
+ virtual bool config_protected(const FSEntry &, const FSEntry &) = 0;
+ virtual std::string make_config_protect_name(const FSEntry &, const FSEntry &) = 0;
+
+ public:
+ virtual ~Merger();
+
+ virtual bool check() PALUDIS_ATTRIBUTE((warn_unused_result));
+ virtual void merge();
+ };
+
+}
+
+#endif
diff --git a/paludis/merger/merger.se b/paludis/merger/merger.se
new file mode 100644
index 0000000..3eab4d6
--- /dev/null
+++ b/paludis/merger/merger.se
@@ -0,0 +1,23 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et ft=sh :
+
+make_enum_MergerEntryType()
+{
+ prefix met
+
+ key met_nothing "Does not exist"
+ key met_file "A regular file"
+ key met_dir "A directory"
+ key met_sym "A symlink"
+ key met_misc "Something else"
+
+ doxygen_comment << "END"
+ /**
+ * The type of file being merged.
+ *
+ * \see Merger
+ * \ingroup grpdepresolver
+ */
+END
+}
+
diff --git a/paludis/merger/merger.sr b/paludis/merger/merger.sr
new file mode 100644
index 0000000..d4dc0ac
--- /dev/null
+++ b/paludis/merger/merger.sr
@@ -0,0 +1,23 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+make_class_MergerOptions()
+{
+ key environment "Environment *"
+ key image "FSEntry"
+ key root "FSEntry"
+
+ allow_named_args
+
+ doxygen_comment << "END"
+ /**
+ * Options for a basic Merger.
+ *
+ * \see Merger
+ * \ingroup grpmerger
+ * \nosubgrouping
+ */
+END
+}
+
+
diff --git a/paludis/merger/merger_TEST_cleanup.sh b/paludis/merger/merger_TEST_cleanup.sh
new file mode 100755
index 0000000..44df00e
--- /dev/null
+++ b/paludis/merger/merger_TEST_cleanup.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d merger_TEST_dir ] ; then
+ rm -fr merger_TEST_dir
+else
+ true
+fi
+
diff --git a/paludis/merger/merger_TEST_setup.sh b/paludis/merger/merger_TEST_setup.sh
new file mode 100755
index 0000000..f8eb402
--- /dev/null
+++ b/paludis/merger/merger_TEST_setup.sh
@@ -0,0 +1,73 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir merger_TEST_dir || exit 2
+cd merger_TEST_dir || exit 3
+
+
+mkdir image_sym_over_nothing root_sym_over_nothing
+ln -s image_dst image_sym_over_nothing/sym
+
+mkdir image_sym_over_sym root_sym_over_sym
+ln -s image_dst image_sym_over_sym/sym
+ln -s root_dst root_sym_over_sym/sym
+
+mkdir image_sym_over_file root_sym_over_file
+ln -s image_dst image_sym_over_file/sym
+> root_sym_over_file/sym
+
+mkdir image_sym_over_dir root_sym_over_dir
+ln -s image_dst image_sym_over_dir/sym
+mkdir root_sym_over_dir/sym
+
+
+mkdir image_dir_over_nothing root_dir_over_nothing
+mkdir image_dir_over_nothing/dir
+
+mkdir image_dir_over_dir root_dir_over_dir
+mkdir image_dir_over_dir/dir
+mkdir root_dir_over_dir/dir
+
+mkdir image_dir_over_file root_dir_over_file
+mkdir image_dir_over_file/dir
+> root_dir_over_file/dir
+
+mkdir image_dir_over_sym_1 root_dir_over_sym_1
+mkdir image_dir_over_sym_1/dir
+> image_dir_over_sym_1/dir/file
+mkdir root_dir_over_sym_1/realdir
+ln -s realdir root_dir_over_sym_1/dir
+
+mkdir image_dir_over_sym_2 root_dir_over_sym_2
+mkdir image_dir_over_sym_2/dir
+> image_dir_over_sym_2/dir/file
+> root_dir_over_sym_2/file
+ln -s file root_dir_over_sym_2/dir
+
+mkdir image_dir_over_sym_3 root_dir_over_sym_3
+mkdir image_dir_over_sym_3/dir
+> image_dir_over_sym_3/dir/file
+ln -s nowhere root_dir_over_sym_3/dir
+
+
+mkdir image_file_over_nothing root_file_over_nothing
+echo "image contents" > image_file_over_nothing/file
+
+mkdir image_file_over_file root_file_over_file
+echo "image contents" > image_file_over_file/file
+echo "root contents" > root_file_over_file/file
+
+mkdir image_file_over_sym root_file_over_sym
+echo "image 1 contents" > image_file_over_sym/file1
+echo "image 2 contents" > image_file_over_sym/file2
+echo "image 3 contents" > image_file_over_sym/file3
+ln -s nowhere root_file_over_sym/file1
+ln -s file root_file_over_sym/file2
+ln -s dir root_file_over_sym/file3
+> root_file_over_sym/file
+mkdir root_file_over_sym/dir
+
+mkdir image_file_over_dir root_file_over_dir
+> image_file_over_dir/file
+mkdir root_file_over_dir/file
+
diff --git a/paludis/repositories/cran/cran_installed_repository.cc b/paludis/repositories/cran/cran_installed_repository.cc
index 2455dab..5c7fc76 100644
--- a/paludis/repositories/cran/cran_installed_repository.cc
+++ b/paludis/repositories/cran/cran_installed_repository.cc
@@ -735,3 +735,15 @@ CRANInstalledRepository::is_default_destination() const
return _imp->env->root() == root();
}
+bool
+CRANInstalledRepository::want_pre_post_phases() const
+{
+ return true;
+}
+
+void
+CRANInstalledRepository::merge(const MergeOptions &)
+{
+ throw InternalError(PALUDIS_HERE, "CRANInstalledRepository isn't converted over to do destinations");
+}
+
diff --git a/paludis/repositories/cran/cran_installed_repository.hh b/paludis/repositories/cran/cran_installed_repository.hh
index 39eba39..76f8654 100644
--- a/paludis/repositories/cran/cran_installed_repository.hh
+++ b/paludis/repositories/cran/cran_installed_repository.hh
@@ -125,7 +125,11 @@ namespace paludis
virtual bool is_default_destination() const;
+ virtual bool want_pre_post_phases() const;
+
virtual FSEntry root() const;
+
+ virtual void merge(const MergeOptions &);
};
/**
diff --git a/paludis/repositories/fake/fake_installed_repository.cc b/paludis/repositories/fake/fake_installed_repository.cc
index 73efc90..7eb85a8 100644
--- a/paludis/repositories/fake/fake_installed_repository.cc
+++ b/paludis/repositories/fake/fake_installed_repository.cc
@@ -117,3 +117,14 @@ FakeInstalledRepository::is_default_destination() const
return environment()->root() == root();
}
+bool
+FakeInstalledRepository::want_pre_post_phases() const
+{
+ return false;
+}
+
+void
+FakeInstalledRepository::merge(const MergeOptions &)
+{
+}
+
diff --git a/paludis/repositories/fake/fake_installed_repository.hh b/paludis/repositories/fake/fake_installed_repository.hh
index f067598..da61d59 100644
--- a/paludis/repositories/fake/fake_installed_repository.hh
+++ b/paludis/repositories/fake/fake_installed_repository.hh
@@ -46,6 +46,8 @@ namespace paludis
bool is_suitable_destination_for(const PackageDatabaseEntry &) const;
bool is_default_destination() const;
+ bool want_pre_post_phases() const;
+ void merge(const MergeOptions &);
virtual FSEntry root() const;
};
diff --git a/paludis/repositories/gentoo/Makefile.am b/paludis/repositories/gentoo/Makefile.am
index b771e5c..a9e139a 100644
--- a/paludis/repositories/gentoo/Makefile.am
+++ b/paludis/repositories/gentoo/Makefile.am
@@ -5,7 +5,9 @@ DISTCLEANFILES = \
glsa-sr.hh glsa-sr.cc \
portage_repository_params-sr.hh portage_repository_params-sr.cc \
vdb_repository-sr.hh vdb_repository-sr.cc \
- ebuild-sr.hh ebuild-sr.cc
+ ebuild-sr.hh ebuild-sr.cc ebuild-se.hh ebuild-se.cc \
+ vdb_merger-sr.hh vdb_merger-sr.cc \
+ vdb_unmerger-sr.hh vdb_unmerger-sr.cc
MAINTAINERCLEANFILES = Makefile.in
@@ -51,6 +53,7 @@ libpaludisgentoorepository_la_LDFLAGS = -version-info @VERSION_LIB_CURRENT@:@VER
paludis_repositories_gentoo_include_HEADERS = \
ebuild.hh \
ebuild-sr.hh \
+ ebuild-se.hh \
glsa.hh \
glsa-sr.hh \
portage_repository-sr.hh \
@@ -71,7 +74,11 @@ paludis_repositories_gentoo_include_HEADERS = \
portage_virtual_version_metadata.hh \
vdb_repository.hh \
vdb_version_metadata.hh \
- vdb_repository-sr.hh
+ vdb_repository-sr.hh \
+ vdb_merger-sr.hh \
+ vdb_merger.hh \
+ vdb_unmerger-sr.hh \
+ vdb_unmerger.hh
libpaludisgentoorepository_la_SOURCES = \
ebuild.cc \
@@ -92,18 +99,24 @@ libpaludisgentoorepository_la_SOURCES = \
portage_virtual_version_metadata.cc \
registration.cc \
vdb_repository.cc \
- vdb_version_metadata.cc
+ vdb_version_metadata.cc \
+ vdb_merger.cc \
+ vdb_unmerger.cc \
$(paludis_repositories_gentoo_include_HEADERS)
if MONOLITHIC
libpaludisgentoorepository_la_LIBADD = \
+ $(top_builddir)/paludis/merger/libpaludismerger.la \
+ $(top_builddir)/paludis/digests/libpaludisdigests.la \
libpaludisgentoorepositoryxmlthings.la \
$(DYNAMIC_LD_LIBS)
else
libpaludisgentoorepository_la_LIBADD = \
+ $(top_builddir)/paludis/merger/libpaludismerger.la \
+ $(top_builddir)/paludis/digests/libpaludisdigests.la \
$(top_builddir)/paludis/util/libpaludisutil.la \
$(top_builddir)/paludis/libpaludis.la \
$(DYNAMIC_LD_LIBS)
@@ -142,6 +155,9 @@ EXTRA_DIST = \
ebuild.sr \
ebuild-sr.hh \
ebuild-sr.cc \
+ ebuild.se \
+ ebuild-se.hh \
+ ebuild-se.cc \
glsa.sr \
glsa-sr.hh \
glsa-sr.cc \
@@ -162,7 +178,13 @@ EXTRA_DIST = \
vdb_repository_TEST_cleanup.sh \
vdb_repository-sr.hh \
vdb_repository-sr.cc \
- vdb_repository.sr
+ vdb_repository.sr \
+ vdb_merger.sr \
+ vdb_merger-sr.hh \
+ vdb_merger-sr.cc \
+ vdb_unmerger.sr \
+ vdb_unmerger-sr.hh \
+ vdb_unmerger-sr.cc
BUILT_SOURCES = \
portage_repository_params-sr.hh \
@@ -174,7 +196,13 @@ BUILT_SOURCES = \
vdb_repository-sr.hh \
vdb_repository-sr.cc \
ebuild-sr.hh \
- ebuild-sr.cc
+ ebuild-sr.cc \
+ ebuild-se.hh \
+ ebuild-se.cc \
+ vdb_merger-sr.hh \
+ vdb_merger-sr.cc \
+ vdb_unmerger-sr.hh \
+ vdb_unmerger-sr.cc
check_SCRIPTS = \
portage_repository_TEST_setup.sh portage_repository_TEST_cleanup.sh \
@@ -202,6 +230,18 @@ portage_repository_params-sr.hh : portage_repository_params.sr $(top_srcdir)/mis
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 > $@
+vdb_merger-sr.hh : vdb_merger.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --header $(srcdir)/vdb_merger.sr > $@
+
+vdb_merger-sr.cc : vdb_merger.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/vdb_merger.sr > $@
+
+vdb_unmerger-sr.hh : vdb_unmerger.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --header $(srcdir)/vdb_unmerger.sr > $@
+
+vdb_unmerger-sr.cc : vdb_unmerger.sr $(top_srcdir)/misc/make_sr.bash
+ $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/vdb_unmerger.sr > $@
+
ebuild-sr.hh : ebuild.sr $(top_srcdir)/misc/make_sr.bash
$(top_srcdir)/misc/make_sr.bash --header $(srcdir)/ebuild.sr > $@
@@ -220,6 +260,12 @@ vdb_repository-sr.hh : vdb_repository.sr $(top_srcdir)/misc/make_sr.bash
vdb_repository-sr.cc : vdb_repository.sr $(top_srcdir)/misc/make_sr.bash
$(top_srcdir)/misc/make_sr.bash --source $(srcdir)/vdb_repository.sr > $@
+ebuild-se.hh : ebuild.se $(top_srcdir)/misc/make_se.bash
+ if ! $(top_srcdir)/misc/make_se.bash --header $(srcdir)/ebuild.se > $@ ; then rm -f $@ ; exit 1 ; fi
+
+ebuild-se.cc : ebuild.se $(top_srcdir)/misc/make_se.bash
+ if ! $(top_srcdir)/misc/make_se.bash --source $(srcdir)/ebuild.se > $@ ; then rm -f $@ ; exit 1 ; fi
+
libpaludisgentoorepositoryxmlthings_la_SOURCES = xml_things.cc xml_things.hh
libpaludisgentoorepositoryxmlthings_la_CXXFLAGS = $(AM_CXXFLAGS) @LIBXML2DEPS_CFLAGS@
diff --git a/paludis/repositories/gentoo/ebuild.cc b/paludis/repositories/gentoo/ebuild.cc
index 081eab7..224d3ab 100644
--- a/paludis/repositories/gentoo/ebuild.cc
+++ b/paludis/repositories/gentoo/ebuild.cc
@@ -38,6 +38,7 @@
using namespace paludis;
+#include <paludis/repositories/gentoo/ebuild-se.cc>
#include <paludis/repositories/gentoo/ebuild-sr.cc>
EbuildCommand::EbuildCommand(const EbuildCommandParams & p) :
@@ -302,8 +303,25 @@ EbuildFetchCommand::EbuildFetchCommand(const EbuildCommandParams & p,
std::string
EbuildInstallCommand::commands() const
{
- return "init setup unpack compile test install strip preinst "
- "merge postinst tidyup";
+ switch (install_params.phase)
+ {
+ case ip_build:
+ return "init setup unpack compile test install saveenv";
+
+ case ip_preinstall:
+ return "loadenv strip preinst saveenv";
+
+ case ip_postinstall:
+ return "loadenv postinst saveenv";
+
+ case ip_tidyup:
+ return "tidyup";
+
+ case last_ip:
+ ;
+ };
+
+ throw InternalError(PALUDIS_HERE, "Bad phase");
}
bool
@@ -344,6 +362,9 @@ EbuildInstallCommand::extend_command(const MakeEnvCommand & cmd)
("USE", install_params.use)
("USE_EXPAND", install_params.use_expand)
("ROOT", install_params.root)
+ ("PALUDIS_LOADSAVEENV_DIR", stringify(install_params.loadsaveenv_dir))
+ ("PALUDIS_CONFIG_PROTECT", install_params.config_protect)
+ ("PALUDIS_CONFIG_PROTECT_MASK", install_params.config_protect_mask)
("PALUDIS_EBUILD_OVERRIDE_CONFIG_PROTECT_MASK",
install_params.disable_cfgpro ? "/" : "")
("PALUDIS_DEBUG_BUILD", debug_build)
@@ -370,10 +391,19 @@ EbuildInstallCommand::EbuildInstallCommand(const EbuildCommandParams & p,
std::string
EbuildUninstallCommand::commands() const
{
- if (uninstall_params.unmerge_only)
- return "unmerge";
- else
- return "prerm unmerge postrm";
+ switch (uninstall_params.phase)
+ {
+ case up_preremove:
+ return "prerm saveenv";
+
+ case up_postremove:
+ return "loadenv postrm";
+
+ case last_up:
+ ;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Bad phase value");
}
bool
@@ -388,6 +418,7 @@ EbuildUninstallCommand::extend_command(const MakeEnvCommand & cmd)
{
MakeEnvCommand result(cmd
("ROOT", uninstall_params.root)
+ ("PALUDIS_LOADSAVEENV_DIR", stringify(uninstall_params.loadsaveenv_dir))
("PALUDIS_EBUILD_OVERRIDE_CONFIG_PROTECT_MASK",
uninstall_params.disable_cfgpro ? "/" : ""));
@@ -461,3 +492,49 @@ EbuildConfigCommand::EbuildConfigCommand(const EbuildCommandParams & p,
{
}
+WriteVDBEntryCommand::WriteVDBEntryCommand(const WriteVDBEntryParams & p) :
+ params(p)
+{
+}
+
+void
+WriteVDBEntryCommand::operator() ()
+{
+ std::string ebuild_cmd(getenv_with_default("PALUDIS_EBUILD_DIR", LIBEXECDIR "/paludis") +
+ "/write_vdb_entry.bash '" +
+ stringify(params.output_directory) + "' '" +
+ stringify(params.environment_file) + "'");
+
+ MakeEnvCommand cmd(make_env_command(ebuild_cmd)
+ ("PKGMANAGER", PALUDIS_PACKAGE "-" + stringify(PALUDIS_VERSION_MAJOR) + "." +
+ stringify(PALUDIS_VERSION_MINOR) + "." +
+ stringify(PALUDIS_VERSION_MICRO) +
+ (std::string(PALUDIS_SUBVERSION_REVISION).empty() ?
+ std::string("") : "-r" + std::string(PALUDIS_SUBVERSION_REVISION)))
+ ("PALUDIS_CONFIG_DIR", SYSCONFDIR "/paludis/")
+ ("PALUDIS_BASHRC_FILES", params.environment->bashrc_files())
+ ("PALUDIS_HOOK_DIRS", params.environment->hook_dirs())
+ ("PALUDIS_FETCHERS_DIRS", params.environment->fetchers_dirs())
+ ("PALUDIS_SYNCERS_DIRS", params.environment->syncers_dirs())
+ ("PALUDIS_COMMAND", params.environment->paludis_command())
+ ("PALUDIS_EBUILD_LOG_LEVEL", stringify(Log::get_instance()->log_level()))
+ ("PALUDIS_EBUILD_DIR", getenv_with_default("PALUDIS_EBUILD_DIR", LIBEXECDIR "/paludis")));
+
+ if (0 != (run_command(cmd)))
+ throw PackageInstallActionError("Write VDB Entry command failed");
+}
+
+VDBPostMergeCommand::VDBPostMergeCommand(const VDBPostMergeCommandParams & p) :
+ params(p)
+{
+}
+
+void
+VDBPostMergeCommand::operator() ()
+{
+ std::string ebuild_cmd("ldconfig -r '" + stringify(params.root) + "'");
+
+ if (0 != (run_command(ebuild_cmd)))
+ throw PackageInstallActionError("VDB Entry post merge commands failed");
+}
+
diff --git a/paludis/repositories/gentoo/ebuild.hh b/paludis/repositories/gentoo/ebuild.hh
index 93df68e..e355877 100644
--- a/paludis/repositories/gentoo/ebuild.hh
+++ b/paludis/repositories/gentoo/ebuild.hh
@@ -58,6 +58,7 @@ namespace paludis
class Environment;
class MakeEnvCommand;
+#include <paludis/repositories/gentoo/ebuild-se.hh>
#include <paludis/repositories/gentoo/ebuild-sr.hh>
class EbuildVersionMetadata :
@@ -324,6 +325,50 @@ namespace paludis
*/
EbuildConfigCommand(const EbuildCommandParams &, const EbuildConfigCommandParams &);
};
+
+ /**
+ * Command for generating VDB entries (not a regular EbuildCommand).
+ *
+ * \ingroup grpebuildinterface
+ */
+ class WriteVDBEntryCommand :
+ private InstantiationPolicy<WriteVDBEntryCommand, instantiation_method::NonCopyableTag>
+ {
+ protected:
+ /**
+ * Our parameters.
+ */
+ const WriteVDBEntryParams params;
+
+ public:
+ /**
+ * Constructor.
+ */
+ WriteVDBEntryCommand(const WriteVDBEntryParams &);
+
+ /**
+ * Run the command.
+ */
+ void operator() ();
+ };
+
+ class VDBPostMergeCommand :
+ private InstantiationPolicy<VDBPostMergeCommand, instantiation_method::NonCopyableTag>
+ {
+ private:
+ const VDBPostMergeCommandParams params;
+
+ public:
+ /**
+ * Constructor.
+ */
+ VDBPostMergeCommand(const VDBPostMergeCommandParams &);
+
+ /**
+ * Run the command.
+ */
+ void operator() ();
+ };
}
#endif
diff --git a/paludis/repositories/gentoo/ebuild.se b/paludis/repositories/gentoo/ebuild.se
new file mode 100644
index 0000000..7ef0aa9
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild.se
@@ -0,0 +1,39 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et ft=sh :
+
+make_enum_EbuildInstallCommandPhase()
+{
+ prefix ip
+
+ key ip_build "Build the package."
+ key ip_preinstall "Preinstall to a live system."
+ key ip_postinstall "Postinstall to a live system."
+ key ip_tidyup "Tidy up work."
+
+ doxygen_comment << "END"
+ /**
+ * Which phase of an EbuildInstallCommand to run.
+ *
+ * \see EbuildInstallCommand
+ * \ingroup grpportagerepository
+ */
+END
+}
+
+make_enum_EbuildUninstallCommandPhase()
+{
+ prefix up
+
+ key up_preremove "Preremove from a live system."
+ key up_postremove "Postremove from a live system."
+
+ doxygen_comment << "END"
+ /**
+ * Which phase of an EbuildUninstallCommand to run.
+ *
+ * \see EbuildUninstallCommand
+ * \ingroup grpportagerepository
+ */
+END
+}
+
diff --git a/paludis/repositories/gentoo/ebuild.sr b/paludis/repositories/gentoo/ebuild.sr
index d14d2c1..2f7a88d 100644
--- a/paludis/repositories/gentoo/ebuild.sr
+++ b/paludis/repositories/gentoo/ebuild.sr
@@ -63,6 +63,10 @@ make_class_EbuildInstallCommandParams()
key disable_cfgpro bool
key debug_build InstallDebugOption
key slot SlotName
+ key phase EbuildInstallCommandPhase
+ key config_protect std::string
+ key config_protect_mask std::string
+ key loadsaveenv_dir FSEntry
doxygen_comment << "END"
/**
@@ -83,6 +87,8 @@ make_class_EbuildUninstallCommandParams()
key disable_cfgpro bool
key unmerge_only bool
key load_environment "const FSEntry *"
+ key phase EbuildUninstallCommandPhase
+ key loadsaveenv_dir FSEntry
doxygen_comment << "END"
/**
@@ -115,3 +121,20 @@ END
allow_named_args
}
+make_class_WriteVDBEntryParams()
+{
+ key environment "const Environment *"
+ key db_entry "PackageDatabaseEntry"
+ key output_directory "FSEntry"
+ key environment_file "FSEntry"
+
+ allow_named_args
+}
+
+make_class_VDBPostMergeCommandParams()
+{
+ key root "FSEntry"
+
+ allow_named_args
+}
+
diff --git a/paludis/repositories/gentoo/ebuild/Makefile.am b/paludis/repositories/gentoo/ebuild/Makefile.am
index 431ebc8..4b1842d 100644
--- a/paludis/repositories/gentoo/ebuild/Makefile.am
+++ b/paludis/repositories/gentoo/ebuild/Makefile.am
@@ -10,12 +10,15 @@ libexecprog_SCRIPTS = \
build_functions.bash \
builtin_fetch.bash \
builtin_init.bash \
+ builtin_loadenv.bash \
builtin_merge.bash \
builtin_metadata.bash \
+ builtin_saveenv.bash \
builtin_strip.bash \
builtin_tidyup.bash \
builtin_unmerge.bash \
builtin_variable.bash \
+ die_functions.bash \
ebuild.bash \
echo_functions.bash \
kernel_functions.bash \
@@ -37,6 +40,7 @@ libexecprog_SCRIPTS = \
src_test.bash \
src_unpack.bash \
usage_error.bash \
+ write_vdb_entry.bash \
work_around_broken_utilities.bash
TESTS_ENVIRONMENT = env \
diff --git a/paludis/repositories/gentoo/ebuild/builtin_loadenv.bash b/paludis/repositories/gentoo/ebuild/builtin_loadenv.bash
new file mode 100644
index 0000000..4b057c0
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/builtin_loadenv.bash
@@ -0,0 +1,48 @@
+#!/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
+
+builtin_loadenv()
+{
+ [[ -d "${PALUDIS_LOADSAVEENV_DIR}" ]] \
+ || die "\$PALUDIS_LOADSAVEENV_DIR (\"${PALUDIS_LOADSAVEENV_DIR}\") not a directory"
+ [[ -f "${PALUDIS_LOADSAVEENV_DIR}/loadsaveenv" ]] || \
+ die "${PALUDIS_LOADSAVEENV_DIR}/loadsaveenv not a file"
+ source ${PALUDIS_LOADSAVEENV_DIR}/loadsaveenv
+}
+
+ebuild_f_loadenv()
+{
+ local old_sandbox_write="${SANDBOX_WRITE}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && \
+ SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}${PALUDIS_LOADSAVEENV_DIR%/}/"
+
+ if hasq "loadenv" ${RESTRICT} ; then
+ ebuild_section "Skipping builtin_loadenv (RESTRICT)"
+ elif hasq "loadenv" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping builtin_loadenv (SKIP_FUNCTIONS)"
+ else
+ ebuild_section "Starting builtin_loadenv"
+ builtin_loadenv
+ ebuild_section "Done builtin_loadenv"
+ fi
+
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${old_sandbox_write}"
+ true
+}
+
+
diff --git a/paludis/repositories/gentoo/ebuild/builtin_merge.bash b/paludis/repositories/gentoo/ebuild/builtin_merge.bash
index 452468e..d922e92 100644
--- a/paludis/repositories/gentoo/ebuild/builtin_merge.bash
+++ b/paludis/repositories/gentoo/ebuild/builtin_merge.bash
@@ -16,6 +16,10 @@
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place, Suite 330, Boston, MA 02111-1307 USA
+# !!! This is used for compatibility with older Paludis versions only. When
+# !!! upgrading from versions below 0.20.0, this code will be used until the
+# !!! 'restart paludis' exec kicks in.
+
builtin_merge()
{
ebuild_section "Merging to '${ROOT:-/}'..."
diff --git a/paludis/repositories/gentoo/ebuild/builtin_saveenv.bash b/paludis/repositories/gentoo/ebuild/builtin_saveenv.bash
new file mode 100644
index 0000000..064c9b2
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/builtin_saveenv.bash
@@ -0,0 +1,55 @@
+#!/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
+
+builtin_saveenv()
+{
+ [[ -d "${PALUDIS_LOADSAVEENV_DIR}" ]] || die "\$PALUDIS_LOADSAVEENV_DIR (\"${PALUDIS_LOADSAVEENV_DIR}\") not a directory"
+ [[ -f "${PALUDIS_LOADSAVEENV_DIR}/loadsaveenv" ]] && rm -f "${PALUDIS_LOADSAVEENV_DIR}/loadsaveenv"
+ ( set ; export -p ) | sed \
+ -e '/^\(declare -[rx]\+ \)\?SANDBOX_/d' \
+ -e '/^\(declare -[rx]\+ \)\?.\?[UP]ID/d' \
+ -e '/^\(declare -[rx]\+ \)\?BASH_VERSINFO/d' \
+ -e '/^\(declare -[rx]\+ \)\?PALUDIS_LOADSAVEENV_DIR/d' \
+ -e '/^\(declare -[rx]\+ \)\?SHELLOPTS/d' \
+ -e '/^\(declare -[rx]\+ \)\?EBUILD_KILL_PID/d' \
+ -e 's:^declare -rx:declare -x:' \
+ > ${PALUDIS_LOADSAVEENV_DIR}/loadsaveenv
+}
+
+ebuild_f_saveenv()
+{
+ local old_sandbox_write="${SANDBOX_WRITE}"
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && \
+ SANDBOX_WRITE="${SANDBOX_WRITE+${SANDBOX_WRITE}:}${PALUDIS_LOADSAVEENV_DIR%/}/"
+
+ if hasq "saveenv" ${RESTRICT} ; then
+ ebuild_section "Skipping builtin_saveenv (RESTRICT)"
+ elif hasq "saveenv" ${SKIP_FUNCTIONS} ; then
+ ebuild_section "Skipping builtin_saveenv (SKIP_FUNCTIONS)"
+ else
+ ebuild_section "Starting builtin_saveenv"
+ builtin_saveenv
+ ebuild_section "Done builtin_saveenv"
+ fi
+
+ [[ -z "${PALUDIS_DO_NOTHING_SANDBOXY}" ]] && SANDBOX_WRITE="${old_sandbox_write}"
+ true
+}
+
+
+
diff --git a/paludis/repositories/gentoo/ebuild/die_functions.bash b/paludis/repositories/gentoo/ebuild/die_functions.bash
new file mode 100644
index 0000000..cfff825
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/die_functions.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
+
+EBUILD_KILL_PID=$$
+declare -r 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
+
+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
+}
+
+
diff --git a/paludis/repositories/gentoo/ebuild/ebuild.bash b/paludis/repositories/gentoo/ebuild/ebuild.bash
index e5d53ca..598b868 100755
--- a/paludis/repositories/gentoo/ebuild/ebuild.bash
+++ b/paludis/repositories/gentoo/ebuild/ebuild.bash
@@ -41,54 +41,29 @@ 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"
+if ! [[ -d ${EBUILD_MODULES_DIR} ]] ; then
+ echo "${EBUILD_MODULES_DIR} is not a directory" 1>&2
+ exit 123
+fi
export PALUDIS_EBUILD_MODULES_DIR="${EBUILD_MODULES_DIR}"
ebuild_load_module()
{
- source "${EBUILD_MODULES_DIR}/${1}.bash" || die "Error loading module ${1}"
+ if ! source "${EBUILD_MODULES_DIR}/${1}.bash" ; then
+ type die && die "Error loading module ${1}"
+ echo "Error loading module ${1}" 1>&2
+ exit 123
+ fi
}
+ebuild_load_module die_functions
ebuild_load_module echo_functions
ebuild_load_module kernel_functions
ebuild_load_module sandbox
@@ -122,8 +97,9 @@ ebuild_source_profile()
fi
}
-save_vars="USE USE_EXPAND USE_EXPAND_HIDDEN ${USE_EXPAND}"
-default_save_vars="CONFIG_PROTECT CONFIG_PROTECT_MASK"
+export CONFIG_PROTECT="${PALUDIS_CONFIG_PROTECT}"
+export CONFIG_PROTECT_MASK="${PALUDIS_CONFIG_PROTECT_MASK}"
+save_vars="USE USE_EXPAND USE_EXPAND_HIDDEN ${USE_EXPAND} CONFIG_PROTECT CONFIG_PROTECT_MASK"
for var in ${save_vars} ${default_save_vars} ; do
ebuild_notice "debug" "Saving ${var}=${!var}"
@@ -159,14 +135,6 @@ 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_scrub_environment()
@@ -183,11 +151,12 @@ ebuild_scrub_environment()
(
source "${1}" || exit 1
- unset -f diefunc perform_hook inherit
+ unset -f diefunc perform_hook inherit builtin_loadenv builtin_saveenv
unset -v PATH ROOTPATH T PALUDIS_TMPDIR PALUDIS_EBUILD_LOG_LEVEL
unset -v PORTDIR FILESDIR ECLASSDIR DISTDIR PALUDIS_EBUILD_DIR
unset -v PALUDIS_EXTRA_DIE_MESSAGE PALUDIS_COMMAND PALUDIS_CLIENT
+ unset -v PALUDIS_LOADSAVEENV_DIR
unset -v ${!PALUDIS_CMDLINE_*} PALUDIS_OPTIONS
unset -v ${!CONTRARIUS_CMDLINE_*} CONTRARIUS_OPTIONS
@@ -309,9 +278,15 @@ ebuild_main()
local action ebuild="$1"
shift
+ if [[ ${#@} -ge 2 ]] ; then
+ ebuild_section "Running ebuild phases $@..."
+ else
+ ebuild_section "Running ebuild phase $@..."
+ fi
+
for action in $@ ; do
case ${action} in
- metadata|variable|init|fetch|merge|unmerge|tidyup|strip)
+ metadata|variable|init|fetch|merge|unmerge|tidyup|strip|loadenv|saveenv)
ebuild_load_module builtin_${action}
;;
@@ -360,6 +335,12 @@ ebuild_main()
perform_hook ebuild_${action}_post
done
fi
+
+ if [[ ${#@} -ge 2 ]] ; then
+ ebuild_section "Completed ebuild phases $@"
+ else
+ ebuild_section "Completed ebuild phase $@"
+ fi
}
ebuild_main $@
diff --git a/paludis/repositories/gentoo/ebuild/write_vdb_entry.bash b/paludis/repositories/gentoo/ebuild/write_vdb_entry.bash
new file mode 100755
index 0000000..b7591d0
--- /dev/null
+++ b/paludis/repositories/gentoo/ebuild/write_vdb_entry.bash
@@ -0,0 +1,100 @@
+#!/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
+
+unalias -a
+set +C
+unset GZIP BZIP BZIP2 CDPATH GREP_OPTIONS GREP_COLOR GLOBIGNORE
+eval unset LANG ${!LC_*}
+
+shopt -s expand_aliases
+shopt -s extglob
+
+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 ) )
+if ! [[ -d ${EBUILD_MODULES_DIR} ]] ; then
+ echo "${EBUILD_MODULES_DIR} is not a directory" 1>&2
+ exit 123
+fi
+export PALUDIS_EBUILD_MODULES_DIR="${EBUILD_MODULES_DIR}"
+
+ebuild_load_module()
+{
+ if ! source "${EBUILD_MODULES_DIR}/${1}.bash" ; then
+ type die && die "Error loading module ${1}"
+ echo "Error loading module ${1}" 1>&2
+ exit 123
+ fi
+}
+
+ebuild_load_module die_functions
+ebuild_load_module echo_functions
+ebuild_load_module work_around_broken_utilities
+
+export PALUDIS_HOME="$(canonicalise ${PALUDIS_HOME:-${HOME}} )"
+
+main()
+{
+ local vdbdir="${1}" envfile="${2}"
+
+ if ! [[ -d "${vdbdir}" ]] ; then
+ echo "!!! vdbdir \"${vdbdir}\" is not a directory"
+ exit 1
+ fi
+
+ ebuild_section "Writing VDB entry to '${vdbdir}'..."
+
+ source ${envfile}
+
+ ebuild_section "Writing VDB entry keys ..."
+
+ local v VDB_FORMAT="paludis-2" COUNTER="$(date +%s )"
+ for v in CATEGORY 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
+ if ! echo "${!v}" > "${vdbdir}"/${v} ; then
+ echo "!!! vdb write ${v} failed"
+ exit 1
+ fi
+ 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
+ if ! echo "${!v}" > "${vdbdir}"/${v} ; then
+ echo "!!! vdb write ${v} failed"
+ exit 1
+ fi
+ done
+
+ ebuild_section "Generating saved ebuild and environment..."
+
+ [[ -f "${EBUILD}" ]] && cp "${EBUILD}" ${vdbdir}/
+ sed -e 's:^declare -rx:declare -x:' < ${envfile} | bzip2 > ${vdbdir}/environment.bz2
+
+ ebuild_section "Finished writing VDB entry"
+
+ true
+}
+
+main $@
+
diff --git a/paludis/repositories/gentoo/ebuild_entries.cc b/paludis/repositories/gentoo/ebuild_entries.cc
index e0f5934..0841cfe 100644
--- a/paludis/repositories/gentoo/ebuild_entries.cc
+++ b/paludis/repositories/gentoo/ebuild_entries.cc
@@ -434,7 +434,7 @@ EbuildEntries::install(const QualifiedPackageName & q, const VersionSpec & v,
}
}
- EbuildFetchCommand fetch_cmd(EbuildCommandParams::create()
+ EbuildCommandParams command_params(EbuildCommandParams::create()
.environment(_imp->params.environment)
.db_entry(&e)
.ebuild_dir(_imp->params.location / stringify(q.category) /
@@ -445,8 +445,9 @@ EbuildEntries::install(const QualifiedPackageName & q, const VersionSpec & v,
.portdir(_imp->params.master_repository ? _imp->params.master_repository->params().location :
_imp->params.location)
.distdir(_imp->params.distdir)
- .buildroot(_imp->params.buildroot),
+ .buildroot(_imp->params.buildroot));
+ EbuildFetchCommand fetch_cmd(command_params,
EbuildFetchCommandParams::create()
.a(archives)
.aa(all_archives)
@@ -454,7 +455,7 @@ EbuildEntries::install(const QualifiedPackageName & q, const VersionSpec & v,
.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 ?
+ .root(o.destination && o.destination->installed_interface ?
stringify(o.destination->installed_interface->root()) : "/")
.profiles(_imp->params.profiles)
.no_fetch(fetch_restrict)
@@ -465,33 +466,62 @@ EbuildEntries::install(const QualifiedPackageName & q, const VersionSpec & v,
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),
+ if (! o.destination)
+ throw PackageInstallActionError("Can't install '" + stringify(q) + "-"
+ + stringify(v) + "' because no destination was provided");
+
+ if (! o.destination->destination_interface)
+ throw PackageInstallActionError("Can't install '" + stringify(q) + "-"
+ + stringify(v) + "' to destination '" + stringify(o.destination->name())
+ + "' because destination does not provide destination_interface");
+ EbuildInstallCommandParams install_params(
EbuildInstallCommandParams::create()
+ .phase(ip_build)
.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()) : "/")
+ .root(stringify(o.destination->installed_interface->root()))
.profiles(_imp->params.profiles)
.disable_cfgpro(o.no_config_protect)
.debug_build(o.debug_build)
+ .config_protect(_imp->portage_repository->profile_variable("CONFIG_PROTECT"))
+ .config_protect_mask(_imp->portage_repository->profile_variable("CONFIG_PROTECT_MASK"))
+ .loadsaveenv_dir(_imp->params.buildroot / stringify(q.category) / (
+ stringify(q.package) + "-" + stringify(v)) / "temp")
.slot(SlotName(metadata->slot)));
- install_cmd();
+ EbuildInstallCommand build_cmd(command_params, install_params);
+ build_cmd();
+
+ if (o.destination->destination_interface->want_pre_post_phases())
+ {
+ install_params.phase = ip_preinstall;
+ EbuildInstallCommand preinst_cmd(command_params, install_params);
+ preinst_cmd();
+ }
+
+ o.destination->destination_interface->merge(
+ MergeOptions::create()
+ .package(PackageDatabaseEntry(q, v, _imp->portage_repository->name()))
+ .image_dir(command_params.buildroot / stringify(q.category) / (stringify(q.package) + "-"
+ + stringify(v)) / "image")
+ .environment_file(command_params.buildroot / stringify(q.category) / (stringify(q.package) + "-"
+ + stringify(v)) / "temp" / "loadsaveenv")
+ );
+
+ if (o.destination->destination_interface->want_pre_post_phases())
+ {
+ install_params.phase = ip_postinstall;
+ EbuildInstallCommand postinst_cmd(command_params, install_params);
+ postinst_cmd();
+ }
+
+ install_params.phase = ip_tidyup;
+ EbuildInstallCommand tidyup_cmd(command_params, install_params);
+ tidyup_cmd();
}
std::string
diff --git a/paludis/repositories/gentoo/portage_repository_profile.cc b/paludis/repositories/gentoo/portage_repository_profile.cc
index 84b976f..38d2e75 100644
--- a/paludis/repositories/gentoo/portage_repository_profile.cc
+++ b/paludis/repositories/gentoo/portage_repository_profile.cc
@@ -25,6 +25,7 @@
#include <paludis/util/tokeniser.hh>
#include <paludis/util/iterator.hh>
#include <paludis/util/save.hh>
+#include <paludis/util/system.hh>
#include <paludis/config_file.hh>
#include <paludis/environment.hh>
@@ -81,6 +82,7 @@ namespace paludis
class Implementation<PortageRepositoryProfile>
{
private:
+ void load_environment();
void load_profile_directory_recursively(const FSEntry & dir);
void load_profile_parent(const FSEntry & dir);
void load_profile_make_defaults(const FSEntry & dir);
@@ -156,6 +158,8 @@ namespace paludis
system_packages(new AllDepAtom),
system_tag(new GeneralSetDepTag(SetName("system"), stringify(name)))
{
+ load_environment();
+
for (FSEntryCollection::Iterator d(dirs.begin()), d_end(dirs.end()) ;
d != d_end ; ++d)
load_profile_directory_recursively(*d);
@@ -175,6 +179,13 @@ namespace paludis
}
void
+Implementation<PortageRepositoryProfile>::load_environment()
+{
+ environment_variables["CONFIG_PROTECT"] = getenv_with_default("CONFIG_PROTECT", "/etc");
+ environment_variables["CONFIG_PROTECT_MASK"] = getenv_with_default("CONFIG_PROTECT_MASK", "");
+}
+
+void
Implementation<PortageRepositoryProfile>::load_profile_directory_recursively(const FSEntry & dir)
{
Context context("When adding profile directory '" + stringify(dir) + ":");
diff --git a/paludis/repositories/gentoo/vdb_merger.hh b/paludis/repositories/gentoo/vdb_merger.hh
new file mode 100644
index 0000000..b9269cf
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_merger.hh
@@ -0,0 +1,57 @@
+/* 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_GENTOO_VDB_MERGER_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_GENTOO_VDB_MERGER_HH 1
+
+#include <paludis/merger/merger.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+
+namespace paludis
+{
+
+#include <paludis/repositories/gentoo/vdb_merger-sr.hh>
+
+ class VDBMerger :
+ public Merger,
+ private PrivateImplementationPattern<VDBMerger>
+ {
+ protected:
+ std::string make_tidy(const FSEntry &) const;
+
+ public:
+ VDBMerger(const VDBMergerOptions &);
+ ~VDBMerger();
+
+ virtual void record_install_file(const FSEntry &, const FSEntry &, const std::string &);
+ virtual void record_install_dir(const FSEntry &, const FSEntry &);
+ virtual void record_install_sym(const FSEntry &, const FSEntry &);
+
+ virtual void on_error(bool is_check, const std::string &);
+ virtual void on_warn(bool is_check, const std::string &);
+
+ virtual bool config_protected(const FSEntry &, const FSEntry &);
+ virtual std::string make_config_protect_name(const FSEntry &, const FSEntry &);
+
+ virtual void merge();
+ virtual bool check();
+ };
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/vdb_merger.sr b/paludis/repositories/gentoo/vdb_merger.sr
new file mode 100644
index 0000000..1de74c6
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_merger.sr
@@ -0,0 +1,28 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+make_class_VDBMergerOptions()
+{
+ key environment "Environment *"
+ key image "FSEntry"
+ key root "FSEntry"
+ key contents_file "FSEntry"
+ key config_protect std::string
+ key config_protect_mask std::string
+
+ allow_named_args
+
+ doxygen_comment << "END"
+ /**
+ * Options for a VDBMerger.
+ *
+ * \see VDBMerger
+ * \ingroup grpmerger
+ * \ingroup grpvdbrepository
+ * \nosubgrouping
+ */
+END
+}
+
+
+
diff --git a/paludis/repositories/gentoo/vdb_repository.cc b/paludis/repositories/gentoo/vdb_repository.cc
index 3a1f65b..87061fe 100644
--- a/paludis/repositories/gentoo/vdb_repository.cc
+++ b/paludis/repositories/gentoo/vdb_repository.cc
@@ -19,6 +19,8 @@
#include <paludis/repositories/gentoo/vdb_repository.hh>
#include <paludis/repositories/gentoo/vdb_version_metadata.hh>
+#include <paludis/repositories/gentoo/vdb_merger.hh>
+#include <paludis/repositories/gentoo/vdb_unmerger.hh>
#include <paludis/dep_atom.hh>
#include <paludis/dep_atom_flattener.hh>
@@ -300,7 +302,7 @@ namespace paludis
VDBRepositoryParams params;
/// Our owning env.
- const Environment * const env;
+ Environment * const env;
/// Our base location.
FSEntry location;
@@ -419,9 +421,24 @@ namespace paludis
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));
+ if (! pkg_i->is_directory())
+ continue;
+
+ if ('-' == pkg_i->basename().at(0))
+ continue;
+
+ try
+ {
+ PackageDepAtom atom("=" + stringify(cat) + "/" + pkg_i->basename());
+ entries.push_back(VDBEntry(atom.package(),
+ atom.version_requirements_ptr()->begin()->version_spec));
+ }
+ catch (const Exception & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Ignoring VDB entry '"
+ + stringify(*pkg_i) + "' due to exception '" + stringify(e.message()) + "' ("
+ + e.what() + ")");
+ }
}
std::sort(entries.begin(), entries.end());
@@ -898,34 +915,39 @@ VDBRepository::do_is_licence(const std::string &) const
void
VDBRepository::do_uninstall(const QualifiedPackageName & q, const VersionSpec & v, const UninstallOptions & o) const
{
+ _uninstall(q, v, o, false);
+}
+
+void
+VDBRepository::_uninstall(const QualifiedPackageName & q, const VersionSpec & v, const UninstallOptions & o,
+ bool reinstalling) const
+{
Context context("When uninstalling '" + stringify(q) + "-" + stringify(v) +
- "' from '" + stringify(name()) + "':");
+ "' from '" + stringify(name()) + (reinstalling ? "' for a reinstall:" : "':"));
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))
+ if ((! reinstalling) && (! has_version(q, v)))
throw PackageInstallActionError("Couldn't uninstall '" + stringify(q) + "-" +
stringify(v) + "' because has_version failed");
- else
- metadata = version_metadata(q, v);
+
+ std::string reinstalling_str(reinstalling ? "-reinstalling-" : "");
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))));
+ (reinstalling_str + stringify(q.package) + "-" + stringify(v))));
- FSEntry pkg_dir(_imp->location / stringify(q.category) /
- (stringify(q.package) + "-" + stringify(v)));
+ FSEntry pkg_dir(_imp->location / stringify(q.category) / (reinstalling_str + 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()
+ EbuildCommandParams params(EbuildCommandParams::create()
.environment(_imp->env)
.db_entry(&e)
.ebuild_dir(pkg_dir)
@@ -933,15 +955,50 @@ VDBRepository::do_uninstall(const QualifiedPackageName & q, const VersionSpec &
.eclassdirs(eclassdirs)
.portdir(_imp->location)
.distdir(pkg_dir)
- .buildroot(_imp->buildroot),
+ .buildroot(_imp->buildroot));
- EbuildUninstallCommandParams::create()
+ EbuildUninstallCommandParams uninstall_params(EbuildUninstallCommandParams::create()
+ .phase(up_preremove)
.root(stringify(_imp->root) + "/")
.disable_cfgpro(o.no_config_protect)
.unmerge_only(is_ebuilded(pkg_dir))
+ .loadsaveenv_dir(pkg_dir)
.load_environment(load_env.get()));
- uninstall_cmd();
+ EbuildUninstallCommand uninstall_cmd_pre(params, uninstall_params);
+ uninstall_cmd_pre();
+
+ /* load CONFIG_PROTECT, CONFIG_PROTECT_MASK from vdb, supplement with env */
+ std::string config_protect, config_protect_mask;
+ {
+ std::ifstream c(stringify(pkg_dir / "CONFIG_PROTECT").c_str());
+ config_protect = std::string((std::istreambuf_iterator<char>(c)), std::istreambuf_iterator<char>()) +
+ " " + getenv_with_default("CONFIG_PROTECT", "");
+
+ std::ifstream c_m(stringify(pkg_dir / "CONFIG_PROTECT_MASK").c_str());
+ config_protect_mask = std::string((std::istreambuf_iterator<char>(c_m)), std::istreambuf_iterator<char>()) +
+ " " + getenv_with_default("CONFIG_PROTECT_MASK", "");
+ }
+
+ /* unmerge */
+ VDBUnmerger unmerger(
+ VDBUnmergerOptions::create()
+ .environment(_imp->params.environment)
+ .root(root())
+ .contents_file(pkg_dir / "CONTENTS")
+ .config_protect(config_protect)
+ .config_protect_mask(config_protect_mask));
+
+ unmerger.unmerge();
+
+ uninstall_params.phase = up_postremove;
+ EbuildUninstallCommand uninstall_cmd_post(params, uninstall_params);
+ uninstall_cmd_post();
+
+ /* remove vdb entry */
+ for (DirIterator d(pkg_dir, false), d_end ; d != d_end ; ++d)
+ FSEntry(*d).unlink();
+ pkg_dir.rmdir();
}
void
@@ -1540,3 +1597,75 @@ VDBRepository::root() const
return _imp->root;
}
+bool
+VDBRepository::want_pre_post_phases() const
+{
+ return true;
+}
+
+void
+VDBRepository::merge(const MergeOptions & m)
+{
+ Context context("When merging '" + stringify(m.package) + "' at '" + stringify(m.image_dir)
+ + "' to VDB repository '" + stringify(name()) + "':");
+
+ if (! is_suitable_destination_for(m.package))
+ throw PackageInstallActionError("Not a suitable destination for '" + stringify(m.package) + "'");
+
+ bool is_replace(has_version(m.package.name, m.package.version));
+
+ FSEntry vdb_dir(_imp->params.location);
+ vdb_dir.mkdir();
+ vdb_dir /= stringify(m.package.name.category);
+ vdb_dir.mkdir();
+ vdb_dir /= (stringify(m.package.name.package) + "-" + stringify(m.package.version));
+ if (is_replace)
+ vdb_dir.rename(vdb_dir.dirname() / ("-reinstalling-" + vdb_dir.basename()));
+ vdb_dir.mkdir();
+
+ WriteVDBEntryCommand write_vdb_entry_command(
+ WriteVDBEntryParams::create()
+ .environment(_imp->params.environment)
+ .db_entry(m.package)
+ .output_directory(vdb_dir)
+ .environment_file(m.environment_file));
+
+ write_vdb_entry_command();
+
+ /* load CONFIG_PROTECT, CONFIG_PROTECT_MASK from vdb */
+ std::string config_protect, config_protect_mask;
+ {
+ std::ifstream c(stringify(vdb_dir / "CONFIG_PROTECT").c_str());
+ config_protect = std::string((std::istreambuf_iterator<char>(c)), std::istreambuf_iterator<char>());
+
+ std::ifstream c_m(stringify(vdb_dir / "CONFIG_PROTECT_MASK").c_str());
+ config_protect_mask = std::string((std::istreambuf_iterator<char>(c_m)), std::istreambuf_iterator<char>());
+ }
+
+ VDBMerger merger(
+ VDBMergerOptions::create()
+ .environment(_imp->params.environment)
+ .image(m.image_dir)
+ .root(root())
+ .contents_file(vdb_dir / "CONTENTS")
+ .config_protect(config_protect)
+ .config_protect_mask(config_protect_mask));
+
+ if (! merger.check())
+ throw PackageInstallActionError("Not proceeding with install due to merge sanity check failing");
+
+ merger.merge();
+
+ if (is_replace)
+ {
+ UninstallOptions uninstall_options(false);
+ _uninstall(m.package.name, m.package.version, uninstall_options, true);
+ }
+
+ VDBPostMergeCommand post_merge_command(
+ VDBPostMergeCommandParams::create()
+ .root(root()));
+
+ post_merge_command();
+}
+
diff --git a/paludis/repositories/gentoo/vdb_repository.hh b/paludis/repositories/gentoo/vdb_repository.hh
index f561526..9b5b27c 100644
--- a/paludis/repositories/gentoo/vdb_repository.hh
+++ b/paludis/repositories/gentoo/vdb_repository.hh
@@ -64,6 +64,9 @@ namespace paludis
void regenerate_provides_cache() const;
+ void _uninstall(const QualifiedPackageName &, const VersionSpec &,
+ const UninstallOptions &, bool reinstalling) const;
+
protected:
virtual bool do_has_category_named(const CategoryNamePart &) const;
@@ -166,6 +169,10 @@ namespace paludis
virtual bool is_default_destination() const;
+ virtual bool want_pre_post_phases() const;
+
+ void merge(const MergeOptions &);
+
virtual std::string do_describe_use_flag(const UseFlagName &,
const PackageDatabaseEntry * const) const;
diff --git a/paludis/repositories/gentoo/vdb_repository.sr b/paludis/repositories/gentoo/vdb_repository.sr
index 48df155..6fa2074 100644
--- a/paludis/repositories/gentoo/vdb_repository.sr
+++ b/paludis/repositories/gentoo/vdb_repository.sr
@@ -3,7 +3,7 @@
make_class_VDBRepositoryParams()
{
- key environment "const Environment *"
+ key environment "Environment *"
key location FSEntry
key root FSEntry
key world FSEntry
diff --git a/paludis/repositories/gentoo/vdb_unmerger.cc b/paludis/repositories/gentoo/vdb_unmerger.cc
new file mode 100644
index 0000000..a101311
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_unmerger.cc
@@ -0,0 +1,291 @@
+/* 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_unmerger.hh"
+
+using namespace paludis;
+
+#include <paludis/repositories/gentoo/vdb_unmerger-sr.cc>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/digests/md5.hh>
+#include <list>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace paludis
+{
+ template<>
+ struct Implementation<VDBUnmerger>
+ {
+ VDBUnmergerOptions options;
+
+ std::list<std::string> config_protect;
+ std::list<std::string> config_protect_mask;
+
+ Implementation(const VDBUnmergerOptions & o) :
+ options(o)
+ {
+ WhitespaceTokeniser::get_instance()->tokenise(o.config_protect,
+ std::back_inserter(config_protect));
+ WhitespaceTokeniser::get_instance()->tokenise(o.config_protect_mask,
+ std::back_inserter(config_protect_mask));
+ }
+ };
+}
+
+VDBUnmerger::VDBUnmerger(const VDBUnmergerOptions & o) :
+ PrivateImplementationPattern<VDBUnmerger>(new Implementation<VDBUnmerger>(o))
+{
+}
+
+VDBUnmerger::~VDBUnmerger()
+{
+}
+
+void
+VDBUnmerger::unmerge()
+{
+ std::ifstream c(stringify(_imp->options.contents_file).c_str());
+ if (! c)
+ throw VDBUnmergerError("Cannot read '" + stringify(_imp->options.contents_file) + "'");
+
+ std::list<std::string> lines;
+ std::string line;
+ while (std::getline(c, line))
+ lines.push_back(line);
+
+ unmerge_non_directories(lines.begin(), lines.end());
+ unmerge_directories(lines.rbegin(), lines.rend());
+}
+
+bool
+VDBUnmerger::config_protected(const FSEntry & f)
+{
+ std::string tidy(make_tidy(f));
+
+ bool result(false);
+ for (std::list<std::string>::const_iterator c(_imp->config_protect.begin()),
+ c_end(_imp->config_protect.end()) ; c != c_end && ! result ; ++c)
+ if (0 == tidy.compare(0, c->length(), *c))
+ result = true;
+ if (result)
+ for (std::list<std::string>::const_iterator c(_imp->config_protect_mask.begin()),
+ c_end(_imp->config_protect_mask.end()) ; c != c_end && result ; ++c)
+ if (0 == tidy.compare(0, c->length(), *c))
+ result = false;
+
+ return result;
+}
+
+std::string
+VDBUnmerger::make_tidy(const FSEntry & f) const
+{
+ std::string root_str(stringify(_imp->options.root)), f_str(stringify(f));
+ if (root_str == "/")
+ root_str.clear();
+ if (0 != f_str.compare(0, root_str.length(), root_str))
+ throw VDBUnmergerError("Can't work out tidy name for '" + f_str + "' with root '" + root_str + "'");
+ return f_str.substr(root_str.length());
+}
+
+template <typename I_>
+void
+VDBUnmerger::unmerge_non_directories(I_ cur, const I_ end)
+{
+ for ( ; 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 + "'");
+ else if (! (_imp->options.root / tokens.at(1)).is_regular_file())
+ std::cout << "--- [!type] " << tokens.at(1) << std::endl;
+ else if (stringify((_imp->options.root / tokens.at(1)).mtime()) != tokens.at(3))
+ std::cout << "--- [!time] " << tokens.at(1) << std::endl;
+ else
+ {
+ std::ifstream md5_file(stringify(_imp->options.root / tokens.at(1)).c_str());
+ if (! md5_file)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "Cannot get md5 for '" +
+ stringify(_imp->options.root / tokens.at(1)) + "'");
+ std::cout << "--- [!md5?] " << tokens.at(1) << std::endl;
+ }
+ else if (MD5(md5_file).hexsum() != tokens.at(2))
+ std::cout << "--- [!md5 ] " << tokens.at(1) << std::endl;
+ else if (config_protected(_imp->options.root / tokens.at(1)))
+ std::cout << "--- [cfgpr] " << tokens.at(1) << std::endl;
+ else
+ {
+ std::cout << "<<< " << tokens.at(1) << std::endl;
+ mode_t mode((_imp->options.root / tokens.at(1)).permissions());
+ if ((mode & S_ISUID) || (mode & S_ISGID))
+ {
+ mode &= 0400;
+ (_imp->options.root / tokens.at(1)).chmod(mode);
+ }
+ (_imp->options.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 + "'");
+ else if (! (_imp->options.root / tokens.at(1)).is_symbolic_link())
+ std::cout << "--- [!type] " << tokens.at(1) << std::endl;
+ else if (stringify((_imp->options.root / tokens.at(1)).mtime()) != tokens.at(4))
+ std::cout << "--- [!time] " << tokens.at(1) << std::endl;
+ else if ((_imp->options.root / tokens.at(1)).readlink() != tokens.at(3))
+ std::cout << "--- [!dest] " << tokens.at(1) << std::endl;
+ else
+ {
+ std::cout << "<<< " << tokens.at(1) << std::endl;
+ (_imp->options.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 + "'");
+ else if ("fif" == tokens.at(0) && ! (_imp->options.root / tokens.at(1)).is_fifo())
+ std::cout << "--- [!type] " << tokens.at(1) << std::endl;
+ else if ("dev" == tokens.at(0) && ! (_imp->options.root / tokens.at(1)).is_device())
+ std::cout << "--- [!type] " << tokens.at(1) << std::endl;
+ else
+ {
+ std::cout << "<<< " << tokens.at(1) << std::endl;
+ (_imp->options.root / tokens.at(1)).unlink();
+ }
+ }
+ else if ("dir" == tokens.at(0))
+ /* nothing */ ;
+ else
+ Log::get_instance()->message(ll_warning, lc_no_context, "Malformed VDB entry '" + *cur + "'");
+ }
+}
+
+template <typename I_>
+void
+VDBUnmerger::unmerge_directories(I_ cur, const I_ end)
+{
+ for ( ; 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))
+ continue;
+
+ 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 + "'");
+ else if (! (_imp->options.root / tokens.at(1)).is_directory())
+ std::cout << "--- [!type] " << tokens.at(1) << std::endl;
+ else if (DirIterator(_imp->options.root / tokens.at(1), false) != DirIterator())
+ std::cout << "--- [!empt] " << tokens.at(1) << std::endl;
+ else
+ {
+ std::cout << "<<< " << tokens.at(1) << std::endl;
+ (_imp->options.root / tokens.at(1)).rmdir();
+ }
+ }
+}
+
+VDBUnmergerError::VDBUnmergerError(const std::string & s) throw () :
+ Exception(s)
+{
+}
+
diff --git a/paludis/repositories/gentoo/vdb_unmerger.hh b/paludis/repositories/gentoo/vdb_unmerger.hh
new file mode 100644
index 0000000..0e01b08
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_unmerger.hh
@@ -0,0 +1,62 @@
+/* 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_GENTOO_VDB_UNMERGER_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_GENTOO_VDB_UNMERGER_HH 1
+
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/sr.hh>
+#include <paludis/util/fs_entry.hh>
+
+namespace paludis
+{
+ class Environment;
+
+#include <paludis/repositories/gentoo/vdb_unmerger-sr.hh>
+
+ class VDBUnmergerError :
+ public Exception
+ {
+ public:
+ VDBUnmergerError(const std::string &) throw ();
+ };
+
+ class VDBUnmerger :
+ private PrivateImplementationPattern<VDBUnmerger>
+ {
+ protected:
+ bool config_protected(const FSEntry &);
+ std::string make_tidy(const FSEntry &) const;
+
+ template <typename I_>
+ void unmerge_non_directories(I_ begin, const I_ end);
+
+ template <typename I_>
+ void unmerge_directories(I_ begin, const I_ end);
+
+ public:
+ VDBUnmerger(const VDBUnmergerOptions &);
+ ~VDBUnmerger();
+
+ void unmerge();
+ };
+
+}
+
+#endif
diff --git a/paludis/repositories/gentoo/vdb_unmerger.sr b/paludis/repositories/gentoo/vdb_unmerger.sr
new file mode 100644
index 0000000..0206c40
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_unmerger.sr
@@ -0,0 +1,27 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et :
+
+make_class_VDBUnmergerOptions()
+{
+ key environment "Environment *"
+ key root "FSEntry"
+ key contents_file "FSEntry"
+ key config_protect std::string
+ key config_protect_mask std::string
+
+ allow_named_args
+
+ doxygen_comment << "END"
+ /**
+ * Options for a VDBUnmerger.
+ *
+ * \see VDBUnmerger
+ * \ingroup grpvdbrepository
+ * \nosubgrouping
+ */
+END
+}
+
+
+
+
diff --git a/paludis/repository.hh b/paludis/repository.hh
index 9a0432f..2618254 100644
--- a/paludis/repository.hh
+++ b/paludis/repository.hh
@@ -25,6 +25,7 @@
#include <paludis/util/attributes.hh>
#include <paludis/util/exception.hh>
#include <paludis/util/sr.hh>
+#include <paludis/util/fs_entry.hh>
#include <paludis/util/virtual_constructor.hh>
#include <paludis/version_metadata.hh>
#include <paludis/version_spec.hh>
@@ -46,7 +47,6 @@ namespace paludis
{
class Environment;
class RepositoryNameCache;
- class FSEntry;
class Repository;
class RepositoryInstallableInterface;
@@ -1002,9 +1002,31 @@ namespace paludis
///\name Destination functions
///\{
+ /**
+ * Are we a suitable destination for the specified package?
+ */
virtual bool is_suitable_destination_for(const PackageDatabaseEntry &) const = 0;
+
+ /**
+ * Are we to be included in the Environment::default_destinations list?
+ */
virtual bool is_default_destination() const = 0;
+ /**
+ * If true, pre and post install phases will be used when writing to this
+ * destination.
+ *
+ * This should return true for 'real' filesystem destinations (whether or
+ * not root is /, if root merges are supported), and false for intermediate
+ * destinations such as binary repositories.
+ */
+ virtual bool want_pre_post_phases() const = 0;
+
+ /**
+ * Merge a package.
+ */
+ virtual void merge(const MergeOptions &) = 0;
+
///\}
virtual ~RepositoryDestinationInterface();
diff --git a/paludis/repository.sr b/paludis/repository.sr
index 3583d57..f1efb5f 100644
--- a/paludis/repository.sr
+++ b/paludis/repository.sr
@@ -84,3 +84,22 @@ make_class_RepositoryVirtualsEntry()
comparison_operators all virtual_name
}
+make_class_MergeOptions()
+{
+ key package PackageDatabaseEntry
+ key image_dir FSEntry
+ key environment_file FSEntry
+
+ allow_named_args
+
+ doxygen_comment << "END"
+ /**
+ * Parameters for RepositoryDestinationInterface::merge.
+ *
+ * \see RepositoryDestinationInterface
+ * \ingroup grprepository
+ * \nosubgrouping
+ */
+END
+}
+
diff --git a/paludis/util/fs_entry.cc b/paludis/util/fs_entry.cc
index 3de0337..72647da 100644
--- a/paludis/util/fs_entry.cc
+++ b/paludis/util/fs_entry.cc
@@ -478,3 +478,10 @@ FSEntry::group() const
return _stat_info->st_gid;
}
+void
+FSEntry::rename(const FSEntry & new_name)
+{
+ if (0 != ::rename(_path.c_str(), new_name._path.c_str()))
+ throw FSError("rename('" + stringify(_path) + "', '" + stringify(new_name._path) + "') failed");
+}
+
diff --git a/paludis/util/fs_entry.hh b/paludis/util/fs_entry.hh
index 20e4b38..d83d3b8 100644
--- a/paludis/util/fs_entry.hh
+++ b/paludis/util/fs_entry.hh
@@ -320,6 +320,13 @@ namespace paludis
*/
void chmod(const mode_t mode);
+ /**
+ * Rename ourself (will not work across mount points).
+ *
+ * \exception FSError If the rename failed.
+ */
+ void rename(const FSEntry & new_name);
+
///\}
};