aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Piotr Jaroszyński <peper@gentoo.org> 2007-05-23 23:56:28 +0000
committerAvatar Piotr Jaroszyński <peper@gentoo.org> 2007-05-23 23:56:28 +0000
commit4af5e94330ce7d8f9e3fbab11eca8971a8f6be60 (patch)
tree8e99d55497ed10aec8aaf5094c81d1b3a0c9fa0d
parent848d36a59b230b040a25991ee0e560dc3518427f (diff)
downloadpaludis-4af5e94330ce7d8f9e3fbab11eca8971a8f6be60.tar.gz
paludis-4af5e94330ce7d8f9e3fbab11eca8971a8f6be60.tar.xz
Redesign Unmerger and add _skip hooks.
-rw-r--r--paludis/merger/Makefile.am17
-rw-r--r--paludis/merger/entry_type.cc22
-rw-r--r--paludis/merger/entry_type.hh32
-rw-r--r--paludis/merger/entry_type.se23
-rw-r--r--paludis/merger/merger.cc144
-rw-r--r--paludis/merger/merger.hh7
-rw-r--r--paludis/merger/merger.se23
-rw-r--r--paludis/merger/merger_TEST.cc123
-rwxr-xr-xpaludis/merger/merger_TEST_setup.sh39
-rw-r--r--paludis/merger/unmerger.cc248
-rw-r--r--paludis/merger/unmerger.hh73
-rw-r--r--paludis/repositories/gentoo/Makefile.am22
-rw-r--r--paludis/repositories/gentoo/vdb_merger.cc6
-rw-r--r--paludis/repositories/gentoo/vdb_merger.hh3
-rw-r--r--paludis/repositories/gentoo/vdb_unmerger.cc276
-rw-r--r--paludis/repositories/gentoo/vdb_unmerger.hh36
-rw-r--r--paludis/repositories/gentoo/vdb_unmerger.sr2
-rw-r--r--paludis/repositories/gentoo/vdb_unmerger_TEST.cc348
-rwxr-xr-xpaludis/repositories/gentoo/vdb_unmerger_TEST_cleanup.sh9
-rwxr-xr-xpaludis/repositories/gentoo/vdb_unmerger_TEST_setup.sh78
20 files changed, 1244 insertions, 287 deletions
diff --git a/paludis/merger/Makefile.am b/paludis/merger/Makefile.am
index 62743a3..1b1e4d9 100644
--- a/paludis/merger/Makefile.am
+++ b/paludis/merger/Makefile.am
@@ -1,7 +1,7 @@
CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda
DISTCLEANFILES = \
- merger-sr.hh merger-sr.cc merger-se.hh merger-se.cc \
+ merger-sr.hh merger-sr.cc entry_type-se.hh entry_type-se.cc \
unmerger-sr.hh unmerger-sr.cc
BUILT_SOURCES = $(DISTCLEANFILES)
@@ -16,13 +16,14 @@ DEFS= \
paludis_merger_includedir = $(includedir)/paludis/merger
paludis_merger_include_HEADERS = \
+ entry_type.hh \
merger.hh \
merger-sr.hh \
- merger-se.hh \
unmerger.hh \
unmerger-sr.hh
libpaludismerger_la_SOURCES = \
+ entry_type.cc entry_type.hh \
merger.cc merger.hh \
unmerger.cc unmerger.hh
@@ -38,7 +39,7 @@ 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 \
+ entry_type-se.hh entry_type-se.cc entry_type.se \
unmerger-sr.hh unmerger-sr.cc unmerger.sr
TESTS = \
@@ -48,6 +49,8 @@ TESTS_ENVIRONMENT = env \
PALUDIS_EBUILD_DIR="$(top_srcdir)/paludis/repositories/gentoo/ebuild/" \
PALUDIS_SKIP_CONFIG="yes" \
PALUDIS_REPOSITORY_SO_DIR="$(top_builddir)/paludis/repositories" \
+ PALUDIS_HOOKER_DIR="$(top_srcdir)/paludis/" \
+ PALUDIS_OUTPUTWRAPPER_DIR="`$(top_srcdir)/paludis/repositories/gentoo/ebuild/utils/canonicalise $(top_builddir)/paludis/util/`" \
TEST_SCRIPT_DIR="$(srcdir)/" \
bash $(top_srcdir)/test/run_test.sh
@@ -78,9 +81,9 @@ unmerger-sr.hh : unmerger.sr $(top_srcdir)/misc/make_sr.bash
unmerger-sr.cc : unmerger.sr $(top_srcdir)/misc/make_sr.bash
if ! $(top_srcdir)/misc/make_sr.bash --source $(srcdir)/unmerger.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
+entry_type-se.hh : entry_type.se $(top_srcdir)/misc/make_se.bash
+ if ! $(top_srcdir)/misc/make_se.bash --header $(srcdir)/entry_type.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
+entry_type-se.cc : entry_type.se $(top_srcdir)/misc/make_se.bash
+ if ! $(top_srcdir)/misc/make_se.bash --source $(srcdir)/entry_type.se > $@ ; then rm -f $@ ; exit 1 ; fi
diff --git a/paludis/merger/entry_type.cc b/paludis/merger/entry_type.cc
new file mode 100644
index 0000000..49179de
--- /dev/null
+++ b/paludis/merger/entry_type.cc
@@ -0,0 +1,22 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Piotr Jaroszyński <peper@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 "entry_type.hh"
+
+#include <paludis/merger/entry_type-se.cc>
diff --git a/paludis/merger/entry_type.hh b/paludis/merger/entry_type.hh
new file mode 100644
index 0000000..12be9aa
--- /dev/null
+++ b/paludis/merger/entry_type.hh
@@ -0,0 +1,32 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Piotr Jaroszyński <peper@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_MERGER_ENTRY_TYPE_HH
+#define PALUDIS_GUARD_PALUDIS_MERGER_ENTRY_TYPE_HH 1
+
+#include <paludis/util/stringify.hh>
+#include <paludis/util/exception.hh>
+
+namespace paludis
+{
+#include <paludis/merger/entry_type-se.hh>
+}
+
+#endif
diff --git a/paludis/merger/entry_type.se b/paludis/merger/entry_type.se
new file mode 100644
index 0000000..15e8108
--- /dev/null
+++ b/paludis/merger/entry_type.se
@@ -0,0 +1,23 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et ft=sh :
+
+make_enum_EntryType()
+{
+ prefix et
+
+ key et_nothing "Does not exist"
+ key et_file "A regular file"
+ key et_dir "A directory"
+ key et_sym "A symlink"
+ key et_misc "Something else"
+
+ doxygen_comment << "END"
+ /**
+ * The type of file.
+ *
+ * \see Merger
+ * \ingroup grpdepresolver
+ */
+END
+}
+
diff --git a/paludis/merger/merger.cc b/paludis/merger/merger.cc
index c66c8cd..728524b 100644
--- a/paludis/merger/merger.cc
+++ b/paludis/merger/merger.cc
@@ -32,7 +32,6 @@
using namespace paludis;
-#include <paludis/merger/merger-se.cc>
#include <paludis/merger/merger-sr.cc>
MergerError::MergerError(const std::string & s) throw () :
@@ -42,7 +41,8 @@ MergerError::MergerError(const std::string & s) throw () :
Merger::Merger(const MergerOptions & o) :
_options(o),
- _result(true)
+ _result(true),
+ _skip_dir(false)
{
}
@@ -117,24 +117,24 @@ Merger::merge()
"Merge of '" + stringify(_options.image) + "' to '" + stringify(_options.root) + "' post hooks returned non-zero");
}
-MergerEntryType
+EntryType
Merger::entry_type(const FSEntry & f)
{
Context context("When checking type of '" + stringify(f) + "':");
if (! f.exists())
- return met_nothing;
+ return et_nothing;
if (f.is_symbolic_link())
- return met_sym;
+ return et_sym;
if (f.is_regular_file())
- return met_file;
+ return et_file;
if (f.is_directory())
- return met_dir;
+ return et_dir;
- return met_misc;
+ return et_misc;
}
void
@@ -152,29 +152,35 @@ Merger::do_dir_recursive(bool is_check, const FSEntry & src, const FSEntry & dst
for (DirIterator d(src, false), d_end ; d != d_end ; ++d)
{
- MergerEntryType m(entry_type(*d));
+ EntryType m(entry_type(*d));
switch (m)
{
- case met_sym:
+ case et_sym:
on_sym(is_check, *d, dst);
continue;
- case met_file:
+ case et_file:
on_file(is_check, *d, dst);
continue;
- case met_dir:
+ case et_dir:
on_dir(is_check, *d, dst);
if (_result)
- do_dir_recursive(is_check, *d, is_check ? (dst / d->basename()) : (dst / d->basename()).realpath());
+ {
+ if (! _skip_dir)
+ do_dir_recursive(is_check, *d,
+ is_check ? (dst / d->basename()) : (dst / d->basename()).realpath());
+ else
+ _skip_dir = false;
+ }
continue;
- case met_misc:
+ case et_misc:
on_misc(is_check, *d, dst);
continue;
- case met_nothing:
- case last_met:
+ case et_nothing:
+ case last_et:
;
}
@@ -189,7 +195,7 @@ Merger::on_file(bool is_check, const FSEntry & src, const FSEntry & dst)
{
Context context("When handling file '" + stringify(src) + "' to '" + stringify(dst) + "':");
- MergerEntryType m(entry_type(dst / src.basename()));
+ EntryType m(entry_type(dst / src.basename()));
if (is_check &&
0 != _options.environment->perform_hook(extend_hook(
@@ -198,31 +204,50 @@ Merger::on_file(bool is_check, const FSEntry & src, const FSEntry & dst)
("INSTALL_DESTINATION", stringify(dst / src.basename())))).max_exit_status)
make_check_fail();
+ if (! is_check)
+ {
+ HookResult hr(_options.environment->perform_hook(extend_hook(
+ Hook("merger_install_file_skip")
+ ("INSTALL_SOURCE", stringify(src))
+ ("INSTALL_DESTINATION", stringify(dst / src.basename()))
+ .grab_output(Hook::AllowedOutputValues()("skip")))));
+
+ if (hr.max_exit_status != 0)
+ Log::get_instance()->message(ll_warning, lc_context) << "Merge of '"
+ << stringify(src) << "' to '" << stringify(dst) << "' skip hooks returned non-zero";
+ else if (hr.output == "skip")
+ {
+ std::string tidy(stringify((dst / src.basename()).strip_leading(_options.root)));
+ display_skip("--- [skp] " + tidy);
+ return;
+ }
+ }
+
do
{
switch (m)
{
- case met_nothing:
+ case et_nothing:
on_file_over_nothing(is_check, src, dst);
continue;
- case met_sym:
+ case et_sym:
on_file_over_sym(is_check, src, dst);
continue;
- case met_dir:
+ case et_dir:
on_file_over_dir(is_check, src, dst);
continue;
- case met_misc:
+ case et_misc:
on_file_over_misc(is_check, src, dst);
continue;
- case met_file:
+ case et_file:
on_file_over_file(is_check, src, dst);
continue;
- case last_met:
+ case last_et:
;
}
@@ -242,7 +267,7 @@ Merger::on_dir(bool is_check, const FSEntry & src, const FSEntry & dst)
{
Context context("When handling dir '" + stringify(src) + "' to '" + stringify(dst) + "':");
- MergerEntryType m(entry_type(dst / src.basename()));
+ EntryType m(entry_type(dst / src.basename()));
if (is_check &&
0 != _options.environment->perform_hook(extend_hook(
@@ -251,31 +276,51 @@ Merger::on_dir(bool is_check, const FSEntry & src, const FSEntry & dst)
("INSTALL_DESTINATION", stringify(dst / src.basename())))).max_exit_status)
make_check_fail();
+ if (! is_check)
+ {
+ HookResult hr(_options.environment->perform_hook(extend_hook(
+ Hook("merger_install_dir_skip")
+ ("INSTALL_SOURCE", stringify(src))
+ ("INSTALL_DESTINATION", stringify(dst / src.basename()))
+ .grab_output(Hook::AllowedOutputValues()("skip")))));
+
+ if (hr.max_exit_status != 0)
+ Log::get_instance()->message(ll_warning, lc_context) << "Merge of '"
+ << stringify(src) << "' to '" << stringify(dst) << "' skip hooks returned non-zero";
+ else if (hr.output == "skip")
+ {
+ std::string tidy(stringify((dst / src.basename()).strip_leading(_options.root)));
+ display_skip("--- [skp] " + tidy);
+ _skip_dir = true;
+ return;
+ }
+ }
+
do
{
switch (m)
{
- case met_nothing:
+ case et_nothing:
on_dir_over_nothing(is_check, src, dst);
continue;
- case met_sym:
+ case et_sym:
on_dir_over_sym(is_check, src, dst);
continue;
- case met_dir:
+ case et_dir:
on_dir_over_dir(is_check, src, dst);
continue;
- case met_misc:
+ case et_misc:
on_dir_over_misc(is_check, src, dst);
continue;
- case met_file:
+ case et_file:
on_dir_over_file(is_check, src, dst);
continue;
- case last_met:
+ case last_et:
;
}
@@ -296,7 +341,7 @@ Merger::on_sym(bool is_check, const FSEntry & src, const FSEntry & dst)
{
Context context("When handling sym '" + stringify(src) + "' to '" + stringify(dst) + "':");
- MergerEntryType m(entry_type(dst / src.basename()));
+ EntryType m(entry_type(dst / src.basename()));
if (is_check &&
0 != _options.environment->perform_hook(extend_hook(
@@ -305,31 +350,50 @@ Merger::on_sym(bool is_check, const FSEntry & src, const FSEntry & dst)
("INSTALL_DESTINATION", stringify(dst / src.basename())))).max_exit_status)
make_check_fail();
+ if (! is_check)
+ {
+ HookResult hr(_options.environment->perform_hook(extend_hook(
+ Hook("merger_install_sym_skip")
+ ("INSTALL_SOURCE", stringify(src))
+ ("INSTALL_DESTINATION", stringify(dst / src.basename()))
+ .grab_output(Hook::AllowedOutputValues()("skip")))));
+
+ if (hr.max_exit_status != 0)
+ Log::get_instance()->message(ll_warning, lc_context) << "Merge of '"
+ << stringify(src) << "' to '" << stringify(dst) << "' skip hooks returned non-zero";
+ else if (hr.output == "skip")
+ {
+ std::string tidy(stringify((dst / src.basename()).strip_leading(_options.root)));
+ display_skip("--- [skp] " + tidy);
+ return;
+ }
+ }
+
do
{
switch (m)
{
- case met_nothing:
+ case et_nothing:
on_sym_over_nothing(is_check, src, dst);
continue;
- case met_sym:
+ case et_sym:
on_sym_over_sym(is_check, src, dst);
continue;
- case met_dir:
+ case et_dir:
on_sym_over_dir(is_check, src, dst);
continue;
- case met_misc:
+ case et_misc:
on_sym_over_misc(is_check, src, dst);
continue;
- case met_file:
+ case et_file:
on_sym_over_file(is_check, src, dst);
continue;
- case last_met:
+ case last_et:
;
}
@@ -451,17 +515,17 @@ Merger::on_dir_over_dir(bool is_check, const FSEntry & src, const FSEntry & dst)
void
Merger::on_dir_over_sym(bool is_check, const FSEntry & src, const FSEntry & dst)
{
- MergerEntryType m;
+ EntryType m;
try
{
m = entry_type((dst / src.basename()).realpath());
}
catch (const FSError &)
{
- m = met_nothing;
+ m = et_nothing;
}
- if (m == met_dir)
+ if (m == et_dir)
{
on_warn(is_check, "Expected '" + stringify(dst / src.basename()) +
"' to be a directory but found a symlink to a directory");
diff --git a/paludis/merger/merger.hh b/paludis/merger/merger.hh
index 7f2ac7d..14c12a7 100644
--- a/paludis/merger/merger.hh
+++ b/paludis/merger/merger.hh
@@ -23,6 +23,7 @@
#include <paludis/util/sr.hh>
#include <paludis/util/fs_entry.hh>
#include <paludis/util/exception.hh>
+#include <paludis/merger/entry_type.hh>
#include <iosfwd>
namespace paludis
@@ -30,7 +31,6 @@ namespace paludis
class Environment;
class Hook;
-#include <paludis/merger/merger-se.hh>
#include <paludis/merger/merger-sr.hh>
/**
@@ -64,6 +64,7 @@ namespace paludis
private:
MergerOptions _options;
bool _result;
+ bool _skip_dir;
protected:
///\name Basic operations
@@ -86,7 +87,7 @@ namespace paludis
/**
* Determine the entry type of a filesystem entry.
*/
- virtual MergerEntryType entry_type(const FSEntry &);
+ virtual EntryType entry_type(const FSEntry &);
/**
* Handle a directory, recursively.
@@ -154,6 +155,8 @@ namespace paludis
*/
virtual void on_warn(bool is_check, const std::string &) = 0;
+ virtual void display_skip(const std::string &) const = 0;
+
///\name Configuration protection
///\{
diff --git a/paludis/merger/merger.se b/paludis/merger/merger.se
deleted file mode 100644
index 3eab4d6..0000000
--- a/paludis/merger/merger.se
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/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_TEST.cc b/paludis/merger/merger_TEST.cc
index 615c742..9b10c0c 100644
--- a/paludis/merger/merger_TEST.cc
+++ b/paludis/merger/merger_TEST.cc
@@ -19,14 +19,60 @@
#include "merger.hh"
#include <paludis/environments/test/test_environment.hh>
+#include <paludis/hooker.hh>
#include <test/test_framework.hh>
#include <test/test_runner.hh>
#include <fstream>
#include <iterator>
+#include <list>
using namespace paludis;
using namespace test;
+namespace paludis
+{
+ class HookTestEnvironment :
+ public TestEnvironment
+ {
+ private:
+ mutable std::tr1::shared_ptr<Hooker> hooker;
+ mutable std::list<std::pair<FSEntry, bool> > hook_dirs;
+
+ public:
+ HookTestEnvironment(const FSEntry & hooks);
+
+ virtual ~HookTestEnvironment();
+
+ virtual HookResult perform_hook(const Hook &) const
+ PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ };
+
+ HookTestEnvironment::HookTestEnvironment(const FSEntry & hooks)
+ {
+ if (hooks.is_directory())
+ hook_dirs.push_back(std::make_pair(hooks, false));
+ }
+
+ HookTestEnvironment::~HookTestEnvironment()
+ {
+ }
+
+ HookResult
+ HookTestEnvironment::perform_hook(const Hook & hook) const
+ {
+ if (! hooker)
+ {
+ hooker.reset(new Hooker(this));
+ for (std::list<std::pair<FSEntry, bool> >::const_iterator h(hook_dirs.begin()),
+ h_end(hook_dirs.end()) ; h != h_end ; ++h)
+ hooker->add_dir(h->first, h->second);
+ }
+ return hooker->perform_hook(hook);
+ }
+}
+
+
namespace
{
struct TestMerger :
@@ -61,6 +107,10 @@ namespace
{
}
+ void display_skip(const std::string &) const
+ {
+ }
+
bool config_protected(const FSEntry &, const FSEntry &)
{
return false;
@@ -78,7 +128,7 @@ namespace
public:
FSEntry image_dir;
FSEntry root_dir;
- TestEnvironment env;
+ HookTestEnvironment env;
TestMerger merger;
bool repeatable() const
@@ -87,13 +137,27 @@ namespace
}
protected:
- MergerTest(MergerEntryType src_type, MergerEntryType dst_type, int n = 0) :
+ MergerTest(EntryType src_type, EntryType dst_type, int n = 0) :
TestCase("merge " + stringify(src_type) + " over " + stringify(dst_type) + (0 == n ? "" : " "
+ stringify(n))),
image_dir("merger_TEST_dir/image_" + stringify(src_type) + "_over_" + stringify(dst_type)
+ (0 == n ? "" : "_" + stringify(n))),
root_dir("merger_TEST_dir/root_" + stringify(src_type) + "_over_" + stringify(dst_type)
+ (0 == n ? "" : "_" + stringify(n))),
+ env(FSEntry("merger_TEST_dir/hooks")),
+ merger(MergerOptions::create()
+ .image(image_dir)
+ .root(root_dir)
+ .environment(&env)
+ .no_chown(true))
+ {
+ }
+
+ MergerTest(const std::string & custom_test) :
+ TestCase("merge " + custom_test + " test"),
+ image_dir("merger_TEST_dir/image_" + custom_test),
+ root_dir("merger_TEST_dir/root_" + custom_test),
+ env(FSEntry("merger_TEST_dir/hooks")),
merger(MergerOptions::create()
.image(image_dir)
.root(root_dir)
@@ -101,6 +165,7 @@ namespace
.no_chown(true))
{
}
+
};
}
@@ -108,7 +173,7 @@ namespace test_cases
{
struct MergerTestSymNothing : MergerTest
{
- MergerTestSymNothing() : MergerTest(met_sym, met_nothing) { }
+ MergerTestSymNothing() : MergerTest(et_sym, et_nothing) { }
void run()
{
@@ -124,7 +189,7 @@ namespace test_cases
struct MergerTestSymSym : MergerTest
{
- MergerTestSymSym() : MergerTest(met_sym, met_sym) { }
+ MergerTestSymSym() : MergerTest(et_sym, et_sym) { }
void run()
{
@@ -141,7 +206,7 @@ namespace test_cases
struct MergerTestSymFile : MergerTest
{
- MergerTestSymFile() : MergerTest(met_sym, met_file) { }
+ MergerTestSymFile() : MergerTest(et_sym, et_file) { }
void run()
{
@@ -157,7 +222,7 @@ namespace test_cases
struct MergerTestSymDir : MergerTest
{
- MergerTestSymDir() : MergerTest(met_sym, met_dir) { }
+ MergerTestSymDir() : MergerTest(et_sym, et_dir) { }
void run()
{
@@ -172,7 +237,7 @@ namespace test_cases
struct MergerTestDirNothing : MergerTest
{
- MergerTestDirNothing() : MergerTest(met_dir, met_nothing) { }
+ MergerTestDirNothing() : MergerTest(et_dir, et_nothing) { }
void run()
{
@@ -187,7 +252,7 @@ namespace test_cases
struct MergerTestDirDir : MergerTest
{
- MergerTestDirDir() : MergerTest(met_dir, met_dir) { }
+ MergerTestDirDir() : MergerTest(et_dir, et_dir) { }
void run()
{
@@ -202,7 +267,7 @@ namespace test_cases
struct MergerTestDirFile : MergerTest
{
- MergerTestDirFile() : MergerTest(met_dir, met_file) { }
+ MergerTestDirFile() : MergerTest(et_dir, et_file) { }
void run()
{
@@ -217,7 +282,7 @@ namespace test_cases
struct MergerTestDirSym1 : MergerTest
{
- MergerTestDirSym1() : MergerTest(met_dir, met_sym, 1) { }
+ MergerTestDirSym1() : MergerTest(et_dir, et_sym, 1) { }
void run()
{
@@ -236,7 +301,7 @@ namespace test_cases
struct MergerTestDirSym2 : MergerTest
{
- MergerTestDirSym2() : MergerTest(met_dir, met_sym, 2) { }
+ MergerTestDirSym2() : MergerTest(et_dir, et_sym, 2) { }
void run()
{
@@ -253,7 +318,7 @@ namespace test_cases
struct MergerTestDirSym3 : MergerTest
{
- MergerTestDirSym3() : MergerTest(met_dir, met_sym, 3) { }
+ MergerTestDirSym3() : MergerTest(et_dir, et_sym, 3) { }
void run()
{
@@ -270,7 +335,7 @@ namespace test_cases
struct MergerTestFileNothing : MergerTest
{
- MergerTestFileNothing() : MergerTest(met_file, met_nothing) { }
+ MergerTestFileNothing() : MergerTest(et_file, et_nothing) { }
void run()
{
@@ -289,7 +354,7 @@ namespace test_cases
struct MergerTestFileFile : MergerTest
{
- MergerTestFileFile() : MergerTest(met_file, met_file) { }
+ MergerTestFileFile() : MergerTest(et_file, et_file) { }
void run()
{
@@ -312,7 +377,7 @@ namespace test_cases
struct MergerTestFileSym : MergerTest
{
- MergerTestFileSym() : MergerTest(met_file, met_sym) { }
+ MergerTestFileSym() : MergerTest(et_file, et_sym) { }
void run()
{
@@ -345,7 +410,7 @@ namespace test_cases
struct MergerTestFileDir : MergerTest
{
- MergerTestFileDir() : MergerTest(met_file, met_dir) { }
+ MergerTestFileDir() : MergerTest(et_file, et_dir) { }
void run()
{
@@ -357,5 +422,31 @@ namespace test_cases
TEST_CHECK((root_dir / "file").is_directory());
}
} test_merger_file_dir;
+
+ struct MergerSkipTest : MergerTest
+ {
+ MergerSkipTest() : MergerTest("skip") { }
+
+ void run()
+ {
+ TEST_CHECK((image_dir / "dir_skip_me").is_directory());
+ TEST_CHECK((image_dir / "dir_noskip_me").is_directory());
+ TEST_CHECK((image_dir / "file_skip_me").is_regular_file());
+ TEST_CHECK((image_dir / "file_noskip_me").is_regular_file());
+ TEST_CHECK((image_dir / "sym_skip_me").is_symbolic_link());
+ TEST_CHECK((image_dir / "sym_noskip_me").is_symbolic_link());
+
+ TEST_CHECK(merger.check());
+ merger.merge();
+
+
+ TEST_CHECK(! (root_dir / "dir_skip_me").exists());
+ TEST_CHECK((root_dir / "dir_noskip_me").is_directory());
+ TEST_CHECK(! (root_dir / "file_skip_me").exists());
+ TEST_CHECK((root_dir / "file_noskip_me").is_regular_file());
+ TEST_CHECK(! (root_dir / "sym_skip_me").exists());
+ TEST_CHECK((root_dir / "sym_noskip_me").is_symbolic_link());
+ }
+ } test_merger_skip;
}
diff --git a/paludis/merger/merger_TEST_setup.sh b/paludis/merger/merger_TEST_setup.sh
index f8eb402..cb41d4e 100755
--- a/paludis/merger/merger_TEST_setup.sh
+++ b/paludis/merger/merger_TEST_setup.sh
@@ -71,3 +71,42 @@ mkdir image_file_over_dir root_file_over_dir
> image_file_over_dir/file
mkdir root_file_over_dir/file
+mkdir image_skip root_skip
+mkdir image_skip/dir_skip_me/
+mkdir image_skip/dir_noskip_me/
+> image_skip/file_skip_me
+> image_skip/file_noskip_me
+ln -s image_skip/file_skip_me image_skip/sym_skip_me
+ln -s image_skip/file_noskip_me image_skip/sym_noskip_me
+
+
+mkdir hooks
+cd hooks
+mkdir \
+merger_install_file_skip \
+merger_install_sym_skip \
+merger_install_dir_skip
+
+cat <<"END" > universal_skip.hook
+hook_run_merger_install_file_skip() {
+ if [[ "${INSTALL_DESTINATION}" == *"/file_skip_me" ]]; then
+ echo "skip"
+ fi
+}
+
+hook_run_merger_install_sym_skip() {
+ if [[ "${INSTALL_DESTINATION}" == *"/sym_skip_me" ]]; then
+ echo "skip"
+ fi
+}
+
+hook_run_merger_install_dir_skip() {
+ if [[ "${INSTALL_DESTINATION}" == *"/dir_skip_me" ]]; then
+ echo "skip"
+ fi
+}
+END
+chmod +x universal_skip.hook
+for dir in merger_install_*_skip; do
+ ln -s ../universal_skip.hook ${dir}
+done
diff --git a/paludis/merger/unmerger.cc b/paludis/merger/unmerger.cc
index 8daf703..761c9ea 100644
--- a/paludis/merger/unmerger.cc
+++ b/paludis/merger/unmerger.cc
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ * Copyright (c) 2007 Piotr Jaroszyński <peper@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
@@ -24,18 +25,37 @@
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
+#include <map>
using namespace paludis;
#include <paludis/merger/unmerger-sr.cc>
+namespace paludis
+{
+ template<>
+ struct Implementation<Unmerger>
+ {
+ UnmergerOptions options;
+
+ std::map<std::string, EntryType> unmerge_set;
+
+ Implementation(const UnmergerOptions & o) :
+ options(o)
+ {
+ }
+ };
+
+ typedef std::map<std::string, EntryType>::reverse_iterator UnmergeListIterator;
+}
+
UnmergerError::UnmergerError(const std::string & s) throw () :
Exception(s)
{
}
Unmerger::Unmerger(const UnmergerOptions & o) :
- _options(o)
+ PrivateImplementationPattern<Unmerger>(new Implementation<Unmerger>(o))
{
}
@@ -44,84 +64,234 @@ Unmerger::~Unmerger()
}
void
-Unmerger::unlink_file(FSEntry d)
+Unmerger::add_unmerge_entry(const std::string & f, EntryType et)
+{
+ if (! _imp->unmerge_set.insert(std::make_pair(f, et)).second)
+ throw UnmergerError("Entry '" + stringify(f) + "' already in the unmerge set");
+}
+
+void
+Unmerger::unmerge()
+{
+ populate_unmerge_set();
+
+ if (0 != _imp->options.environment->perform_hook(extend_hook(
+ Hook("unmerger_unlink_pre")
+ ("UNLINK_TARGET", stringify(_imp->options.root)))).max_exit_status)
+ throw UnmergerError("Unmerge from '" + stringify(_imp->options.root) + "' aborted by hook");
+
+ for (UnmergeListIterator i(_imp->unmerge_set.rbegin()), i_end(_imp->unmerge_set.rend()) ; i != i_end ; ++i)
+ {
+ FSEntry f(i->first);
+ switch (i->second)
+ {
+ case et_dir:
+ unmerge_dir(f);
+ continue;
+
+ case et_file:
+ unmerge_file(f);
+ continue;
+
+ case et_sym:
+ unmerge_sym(f);
+ continue;
+
+ case et_misc:
+ unmerge_misc(f);
+ continue;
+
+ case et_nothing:
+ case last_et:
+ ;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Unexpected entry_type '" + stringify((*i).second) + "'");
+ }
+
+ if (0 != _imp->options.environment->perform_hook(extend_hook(
+ Hook("unmerger_unlink_post")
+ ("UNLINK_TARGET", stringify(_imp->options.root)))).max_exit_status)
+ throw UnmergerError("Unmerge from '" + stringify(_imp->options.root) + "' aborted by hook");
+}
+
+void
+Unmerger::unmerge_file(FSEntry & f) const
+{
+ FSEntry f_real(_imp->options.root / f);
+
+ HookResult hr(_imp->options.environment->perform_hook(extend_hook(
+ Hook("unmerger_unlink_file_skip")
+ ("UNLINK_TARGET", stringify(f_real))
+ .grab_output(Hook::AllowedOutputValues()("skip")("noskip")))));
+
+ if (hr.max_exit_status != 0)
+ throw UnmergerError("Unmerge of '" + stringify(f) + "' aborted by hook");
+ else if (hr.output == "skip")
+ display("--- [skip ] " + stringify(f));
+ else if (hr.output == "noskip")
+ {
+ display("<<< [force] " + stringify(f));
+ unlink_file(f_real);
+ }
+ else if (check_file(f))
+ {
+ display("<<< " + stringify(f));
+ unlink_sym(f_real);
+ }
+}
+
+void
+Unmerger::unmerge_sym(FSEntry & f) const
+{
+ FSEntry f_real(_imp->options.root / f);
+
+ HookResult hr(_imp->options.environment->perform_hook(extend_hook(
+ Hook("unmerger_unlink_sym_skip")
+ ("UNLINK_TARGET", stringify(f_real))
+ .grab_output(Hook::AllowedOutputValues()("skip")("noskip")))));
+
+ if (hr.max_exit_status != 0)
+ throw UnmergerError("Unmerge of '" + stringify(f) + "' aborted by hook");
+ else if (hr.output == "skip")
+ display("--- [skip ] " + stringify(f));
+ else if (hr.output == "noskip")
+ {
+ display("<<< [force] " + stringify(f));
+ unlink_sym(f_real);
+ }
+ else if (check_sym(f))
+ {
+ display("<<< " + stringify(f));
+ unlink_sym(f_real);
+ }
+}
+
+void
+Unmerger::unmerge_dir(FSEntry & f) const
+{
+ FSEntry f_real(_imp->options.root / f);
+
+ HookResult hr(_imp->options.environment->perform_hook(extend_hook(
+ Hook("unmerger_unlink_dir_skip")
+ ("UNLINK_TARGET", stringify(f_real))
+ .grab_output(Hook::AllowedOutputValues()("skip")))));
+
+ if (hr.max_exit_status != 0)
+ throw UnmergerError("Unmerge of '" + stringify(f) + "' aborted by hook");
+ else if (hr.output == "skip")
+ display("--- [skip ] " + stringify(f));
+ else if (check_dir(f))
+ {
+ display("<<< " + stringify(f));
+ unlink_dir(f_real);
+ }
+}
+
+void
+Unmerger::unmerge_misc(FSEntry & f) const
{
- if (0 != _options.environment->perform_hook(extend_hook(
+ FSEntry f_real(_imp->options.root / f);
+
+ HookResult hr(_imp->options.environment->perform_hook(extend_hook(
+ Hook("unmerger_unlink_misc_skip")
+ ("UNLINK_TARGET", stringify(f_real))
+ .grab_output(Hook::AllowedOutputValues()("skip")("noskip")))));
+
+ if (hr.max_exit_status != 0)
+ throw UnmergerError("Unmerge of '" + stringify(f) + "' aborted by hook");
+ else if (hr.output == "skip")
+ display("--- [skip ] " + stringify(f));
+ else if (hr.output == "noskip")
+ {
+ display("<<< [force] " + stringify(f));
+ unlink_misc(f_real);
+ }
+ else if (check_misc(f))
+ {
+ display("<<< " + stringify(f));
+ unlink_misc(f_real);
+ }
+}
+
+void
+Unmerger::unlink_file(FSEntry & f) const
+{
+ if (0 != _imp->options.environment->perform_hook(extend_hook(
Hook("unmerger_unlink_file_pre")
- ("UNLINK_TARGET", stringify(d)))).max_exit_status)
- throw UnmergerError("Unmerge of '" + stringify(d) + "' aborted by hook");
+ ("UNLINK_TARGET", stringify(f)))).max_exit_status)
+ throw UnmergerError("Unmerge of '" + stringify(f) + "' aborted by hook");
- if (d.is_regular_file())
+ if (f.is_regular_file())
{
- mode_t mode(d.permissions());
+ mode_t mode(f.permissions());
if ((mode & S_ISUID) || (mode & S_ISGID))
{
mode &= 0400;
- d.chmod(mode);
+ f.chmod(mode);
}
}
- d.unlink();
+ f.unlink();
- if (0 != _options.environment->perform_hook(extend_hook(
+ if (0 != _imp->options.environment->perform_hook(extend_hook(
Hook("unmerger_unlink_file_post")
- ("UNLINK_TARGET", stringify(d)))).max_exit_status)
- throw UnmergerError("Unmerge of '" + stringify(d) + "' aborted by hook");
+ ("UNLINK_TARGET", stringify(f)))).max_exit_status)
+ throw UnmergerError("Unmerge of '" + stringify(f) + "' aborted by hook");
}
void
-Unmerger::unlink_sym(FSEntry d)
+Unmerger::unlink_sym(FSEntry & f) const
{
- if (0 != _options.environment->perform_hook(extend_hook(
+ if (0 != _imp->options.environment->perform_hook(extend_hook(
Hook("unmerger_unlink_sym_pre")
- ("UNLINK_TARGET", stringify(d)))).max_exit_status)
- throw UnmergerError("Unmerge of '" + stringify(d) + "' aborted by hook");
+ ("UNLINK_TARGET", stringify(f)))).max_exit_status)
+ throw UnmergerError("Unmerge of '" + stringify(f) + "' aborted by hook");
- d.unlink();
+ f.unlink();
- if (0 != _options.environment->perform_hook(extend_hook(
+ if (0 != _imp->options.environment->perform_hook(extend_hook(
Hook("unmerger_unlink_sym_post")
- ("UNLINK_TARGET", stringify(d)))).max_exit_status)
- throw UnmergerError("Unmerge of '" + stringify(d) + "' aborted by hook");
+ ("UNLINK_TARGET", stringify(f)))).max_exit_status)
+ throw UnmergerError("Unmerge of '" + stringify(f) + "' aborted by hook");
}
void
-Unmerger::unlink_dir(FSEntry d)
+Unmerger::unlink_dir(FSEntry & f) const
{
- if (0 != _options.environment->perform_hook(extend_hook(
+ if (0 != _imp->options.environment->perform_hook(extend_hook(
Hook("unmerger_unlink_dir_pre")
- ("UNLINK_TARGET", stringify(d)))).max_exit_status)
- throw UnmergerError("Unmerge of '" + stringify(d) + "' aborted by hook");
+ ("UNLINK_TARGET", stringify(f)))).max_exit_status)
+ throw UnmergerError("Unmerge of '" + stringify(f) + "' aborted by hook");
- d.rmdir();
+ f.rmdir();
- if (0 != _options.environment->perform_hook(extend_hook(
+ if (0 != _imp->options.environment->perform_hook(extend_hook(
Hook("unmerger_unlink_dir_post")
- ("UNLINK_TARGET", stringify(d)))).max_exit_status)
- throw UnmergerError("Unmerge of '" + stringify(d) + "' aborted by hook");
+ ("UNLINK_TARGET", stringify(f)))).max_exit_status)
+ throw UnmergerError("Unmerge of '" + stringify(f) + "' aborted by hook");
}
void
-Unmerger::unlink_misc(FSEntry d)
+Unmerger::unlink_misc(FSEntry & f) const
{
- if (0 != _options.environment->perform_hook(extend_hook(
+ if (0 != _imp->options.environment->perform_hook(extend_hook(
Hook("unmerger_unlink_misc_pre")
- ("UNLINK_TARGET", stringify(d)))).max_exit_status)
- throw UnmergerError("Unmerge of '" + stringify(d) + "' aborted by hook");
+ ("UNLINK_TARGET", stringify(f)))).max_exit_status)
+ throw UnmergerError("Unmerge of '" + stringify(f) + "' aborted by hook");
- d.unlink();
+ f.unlink();
- if (0 != _options.environment->perform_hook(extend_hook(
+ if (0 != _imp->options.environment->perform_hook(extend_hook(
Hook("unmerger_unlink_misc_post")
- ("UNLINK_TARGET", stringify(d)))).max_exit_status)
- throw UnmergerError("Unmerge of '" + stringify(d) + "' aborted by hook");
+ ("UNLINK_TARGET", stringify(f)))).max_exit_status)
+ throw UnmergerError("Unmerge of '" + stringify(f) + "' aborted by hook");
}
Hook
-Unmerger::extend_hook(const Hook & h)
+Unmerger::extend_hook(const Hook & h) const
{
return h
- ("ROOT", stringify(_options.root));
+ ("ROOT", stringify(_imp->options.root));
}
-
diff --git a/paludis/merger/unmerger.hh b/paludis/merger/unmerger.hh
index 6f7560b..1733b43 100644
--- a/paludis/merger/unmerger.hh
+++ b/paludis/merger/unmerger.hh
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ * Copyright (c) 2007 Piotr Jaroszyński <peper@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
@@ -23,6 +24,8 @@
#include <paludis/util/exception.hh>
#include <paludis/util/fs_entry.hh>
#include <paludis/util/sr.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/merger/entry_type.hh>
namespace paludis
{
@@ -56,11 +59,9 @@ namespace paludis
* \ingroup grpunmerger
* \nosubgrouping
*/
- class PALUDIS_VISIBLE Unmerger
+ class PALUDIS_VISIBLE Unmerger :
+ private PrivateImplementationPattern<Unmerger>
{
- private:
- UnmergerOptions _options;
-
protected:
///\name Basic operations
///\{
@@ -70,27 +71,79 @@ namespace paludis
///\}
/**
+ * Add entry to the unmerge set.
+ */
+ void add_unmerge_entry(const std::string &, EntryType);
+
+ /**
+ * Populate the unmerge set.
+ */
+ virtual void populate_unmerge_set() = 0;
+
+ /**
* Extend a hook with extra options.
*/
- virtual Hook extend_hook(const Hook &);
+ virtual Hook extend_hook(const Hook &) const;
+
+ ///\name Unmerge operations
+ ///\{
+
+ virtual void unmerge_file(FSEntry &) const;
+ virtual void unmerge_dir(FSEntry &) const;
+ virtual void unmerge_sym(FSEntry &) const;
+ virtual void unmerge_misc(FSEntry &) const;
+
+ ///\}
+
+ ///\name Check operations
+ ///\{
+
+ virtual bool check_file(const FSEntry &) const
+ {
+ return true;
+ }
+
+ virtual bool check_dir(const FSEntry &) const
+ {
+ return true;
+ }
+
+ virtual bool check_sym(const FSEntry &) const
+ {
+ return true;
+ }
+
+ virtual bool check_misc(const FSEntry &) const
+ {
+ return true;
+ }
+
+ ///\}
///\name Unlink operations
///\{
- virtual void unlink_file(FSEntry);
- virtual void unlink_dir(FSEntry);
- virtual void unlink_sym(FSEntry);
- virtual void unlink_misc(FSEntry);
+ virtual void unlink_file(FSEntry &) const;
+ virtual void unlink_dir(FSEntry &) const;
+ virtual void unlink_sym(FSEntry &) const;
+ virtual void unlink_misc(FSEntry &) const;
///\}
+ virtual void display(const std::string &) const = 0;
+
public:
///\name Basic operations
///\{
- virtual ~Unmerger();
+ virtual ~Unmerger() = 0;
///\}
+
+ /**
+ * Perform the unmerge.
+ */
+ void unmerge();
};
}
diff --git a/paludis/repositories/gentoo/Makefile.am b/paludis/repositories/gentoo/Makefile.am
index 187df38..52d9a4c 100644
--- a/paludis/repositories/gentoo/Makefile.am
+++ b/paludis/repositories/gentoo/Makefile.am
@@ -117,6 +117,19 @@ portage_repository_TEST_LDADD = \
portage_repository_TEST_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir)
+vdb_unmerger_TEST_SOURCES = vdb_unmerger_TEST.cc
+
+vdb_unmerger_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/environments/test/libpaludistestenvironment.la \
+ $(top_builddir)/test/libtest.a \
+ $(DYNAMIC_LD_LIBS)
+
+vdb_unmerger_TEST_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir)
+
EXTRA_DIST = \
ebuild.sr \
ebuild-sr.hh \
@@ -153,7 +166,10 @@ EXTRA_DIST = \
vdb_merger-sr.cc \
vdb_unmerger.sr \
vdb_unmerger-sr.hh \
- vdb_unmerger-sr.cc
+ vdb_unmerger-sr.cc \
+ vdb_unmerger_TEST.cc \
+ vdb_unmerger_TEST_setup.sh \
+ vdb_unmerger_TEST_cleanup.sh
BUILT_SOURCES = \
portage_repository_params-sr.hh \
@@ -181,7 +197,7 @@ check_SCRIPTS = \
vdb_repository_TEST_setup.sh vdb_repository_TEST_cleanup.sh
TESTS_ENVIRONMENT = env \
- PALUDIS_EBUILD_DIR="$(top_srcdir)/paludis/repositories/gentoo/ebuild/" \
+ PALUDIS_EBUILD_DIR="`$(top_srcdir)/paludis/repositories/gentoo/ebuild/utils/canonicalise $(top_srcdir)/paludis/repositories/gentoo/ebuild/`" \
PALUDIS_SKIP_CONFIG="yes" \
TEST_SCRIPT_DIR="$(srcdir)/" \
PALUDIS_REPOSITORY_SO_DIR="$(top_builddir)/paludis/repositories" \
@@ -271,7 +287,7 @@ xml_things_TEST_LDADD = \
endif
-TESTS = portage_repository_TEST $(GLSA_TESTS)
+TESTS = portage_repository_TEST vdb_unmerger_TEST $(GLSA_TESTS)
check_PROGRAMS = $(TESTS)
built-sources : $(BUILT_SOURCES)
diff --git a/paludis/repositories/gentoo/vdb_merger.cc b/paludis/repositories/gentoo/vdb_merger.cc
index ccac35f..161f403 100644
--- a/paludis/repositories/gentoo/vdb_merger.cc
+++ b/paludis/repositories/gentoo/vdb_merger.cc
@@ -240,3 +240,9 @@ VDBMerger::on_enter_dir(bool is_check, const FSEntry)
std::cout << ".";
}
+void
+VDBMerger::display_skip(const std::string & message) const
+{
+ std::cout << message << std::endl;
+}
+
diff --git a/paludis/repositories/gentoo/vdb_merger.hh b/paludis/repositories/gentoo/vdb_merger.hh
index 353fc71..4b6f467 100644
--- a/paludis/repositories/gentoo/vdb_merger.hh
+++ b/paludis/repositories/gentoo/vdb_merger.hh
@@ -40,6 +40,9 @@ namespace paludis
public Merger,
private PrivateImplementationPattern<VDBMerger>
{
+ private:
+ void display_skip(const std::string &) const;
+
public:
///\name Basic operations
///\{
diff --git a/paludis/repositories/gentoo/vdb_unmerger.cc b/paludis/repositories/gentoo/vdb_unmerger.cc
index 8314b4b..4fe7606 100644
--- a/paludis/repositories/gentoo/vdb_unmerger.cc
+++ b/paludis/repositories/gentoo/vdb_unmerger.cc
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ * Copyright (c) 2007 Piotr Jaroszyński <peper@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
@@ -31,6 +32,7 @@ using namespace paludis;
#include <paludis/package_database.hh>
#include <paludis/util/join.hh>
#include <list>
+#include <map>
#include <fstream>
#include <iostream>
#include <vector>
@@ -48,6 +50,8 @@ namespace paludis
std::list<std::string> config_protect;
std::list<std::string> config_protect_mask;
+ std::multimap<std::string, std::string> extra_info;
+
Implementation(const VDBUnmergerOptions & o) :
options(o)
{
@@ -57,13 +61,16 @@ namespace paludis
std::back_inserter(config_protect_mask));
}
};
+
+ typedef std::multimap<std::string, std::string>::iterator ExtraInfoIterator;
}
VDBUnmerger::VDBUnmerger(const VDBUnmergerOptions & o) :
- PrivateImplementationPattern<VDBUnmerger>(new Implementation<VDBUnmerger>(o)),
Unmerger(UnmergerOptions::create()
.environment(o.environment)
- .root(o.root))
+ .root(o.root)),
+ PrivateImplementationPattern<VDBUnmerger>(new Implementation<VDBUnmerger>(o)),
+ _imp(PrivateImplementationPattern<VDBUnmerger>::_imp.operator-> ())
{
}
@@ -72,17 +79,16 @@ VDBUnmerger::~VDBUnmerger()
}
Hook
-VDBUnmerger::extend_hook(const Hook & h)
+VDBUnmerger::extend_hook(const Hook & h) const
{
std::string cat(stringify(_imp->options.package_name.category));
std::string pn(stringify(_imp->options.package_name.package));
std::string pvr(stringify(_imp->options.version));
std::string pv(stringify(_imp->options.version.remove_revision()));
- std::string slot(stringify(_imp->options.repository->version_metadata(_imp->options.package_name, _imp->options.version)->slot));
tr1::shared_ptr<const FSEntryCollection> bashrc_files(_imp->options.environment->bashrc_files());
- return Unmerger::extend_hook(h)
+ Hook result(Unmerger::extend_hook(h)
("P", pn + "-" + pv)
("PN", pn)
("CATEGORY", cat)
@@ -90,40 +96,22 @@ VDBUnmerger::extend_hook(const Hook & h)
("PV", pv)
("PVR", pvr)
("PF", pn + "-" + pvr)
- ("SLOT", slot)
("CONFIG_PROTECT", _imp->options.config_protect)
("CONFIG_PROTECT_MASK", _imp->options.config_protect_mask)
- ("PALUDIS_BASHRC_FILES", join(bashrc_files->begin(), bashrc_files->end(), " "));
-}
-
-void
-VDBUnmerger::unmerge()
-{
- std::ifstream c(stringify(_imp->options.contents_file).c_str());
- if (! c)
- throw VDBUnmergerError("Cannot read '" + stringify(_imp->options.contents_file) + "'");
+ ("PALUDIS_BASHRC_FILES", join(bashrc_files->begin(), bashrc_files->end(), " ")));
- std::list<std::string> lines;
- std::string line;
- while (std::getline(c, line))
- lines.push_back(line);
-
- if (0 != _imp->options.environment->perform_hook(extend_hook(
- Hook("unmerger_unlink_pre")
- ("UNLINK_TARGET", stringify(_imp->options.root)))).max_exit_status)
- throw UnmergerError("Unmerge of '" + stringify(_imp->options.root) + "' aborted by hook");
-
- unmerge_non_directories(lines.begin(), lines.end());
- unmerge_directories(lines.rbegin(), lines.rend());
-
- if (0 != _imp->options.environment->perform_hook(extend_hook(
- Hook("unmerger_unlink_post")
- ("UNLINK_TARGET", stringify(_imp->options.root)))).max_exit_status)
- throw UnmergerError("Unmerge of '" + stringify(_imp->options.root) + "' aborted by hook");
+ if (0 != _imp->options.repository)
+ {
+ std::string slot(stringify(_imp->options.repository->version_metadata(
+ _imp->options.package_name, _imp->options.version)->slot));
+ return result("SLOT", slot);
+ }
+ else
+ return result;
}
bool
-VDBUnmerger::config_protected(const FSEntry & f)
+VDBUnmerger::config_protected(const FSEntry & f) const
{
std::string tidy(make_tidy(f));
@@ -152,14 +140,18 @@ VDBUnmerger::make_tidy(const FSEntry & f) const
return f_str.substr(root_str.length());
}
-template <typename I_>
void
-VDBUnmerger::unmerge_non_directories(I_ cur, const I_ end)
+VDBUnmerger::populate_unmerge_set()
{
- for ( ; cur != end ; ++cur)
+ std::ifstream c(stringify(_imp->options.contents_file).c_str());
+ if (! c)
+ throw VDBUnmergerError("Cannot read '" + stringify(_imp->options.contents_file) + "'");
+
+ std::string line;
+ while (std::getline(c, line))
{
std::vector<std::string> tokens;
- WhitespaceTokeniser::get_instance()->tokenise(*cur, std::back_inserter(tokens));
+ WhitespaceTokeniser::get_instance()->tokenise(line, std::back_inserter(tokens));
if (tokens.empty())
continue;
@@ -171,79 +163,50 @@ VDBUnmerger::unmerge_non_directories(I_ cur, const I_ end)
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();
+ tokens.erase(next(tokens.begin(), 2));
}
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;
+ Log::get_instance()->message(ll_warning, lc_no_context, "Malformed VDB entry '" + line + "'");
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;
- unlink_file(_imp->options.root / tokens.at(1));
- }
+ add_unmerge_entry(tokens.at(1), et_file);
+
+ for (std::vector<std::string>::iterator i(next(tokens.begin(), 2)), i_end(tokens.end()) ;
+ i != i_end ; ++i)
+ _imp->extra_info.insert(std::make_pair(tokens.at(1), *i));
}
+
}
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();
+ tokens.erase(next(tokens.begin(), 2));
}
while (tokens.size() > 5)
{
- if (std::string::npos != tokens.at(2).find('='))
- break;
-
- if (tokens.at(4) == "->")
+ if (std::string::npos != tokens.at(5).find('='))
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();
+ tokens.erase(next(tokens.begin(), 4));
}
- 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;
+ if (tokens.size() != 5 || tokens.at(2) != "->")
+ Log::get_instance()->message(ll_warning, lc_no_context, "Malformed VDB entry '" + line + "'");
else
{
- std::cout << "<<< " << tokens.at(1) << std::endl;
- unlink_sym(_imp->options.root / tokens.at(1));
+ add_unmerge_entry(tokens.at(1), et_sym);
+
+ for (std::vector<std::string>::iterator i(next(tokens.begin(), 3)), i_end(tokens.end()) ;
+ i != i_end ; ++i)
+ _imp->extra_info.insert(std::make_pair(tokens.at(1), *i));
}
}
else if ("misc" == tokens.at(0))
@@ -257,67 +220,126 @@ VDBUnmerger::unmerge_non_directories(I_ cur, const I_ end)
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();
+ tokens.erase(next(tokens.begin(), 2));
}
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;
+ Log::get_instance()->message(ll_warning, lc_no_context, "Malformed VDB entry '" + line + "'");
else
{
- std::cout << "<<< " << tokens.at(1) << std::endl;
- unlink_misc(_imp->options.root / tokens.at(1));
+ add_unmerge_entry(tokens.at(1), et_misc);
+
+ _imp->extra_info.insert(std::make_pair(tokens.at(1), tokens.at(0)));
+ for (std::vector<std::string>::iterator i(next(tokens.begin(), 2)), i_end(tokens.end()) ;
+ i != i_end ; ++i)
+ _imp->extra_info.insert(std::make_pair(tokens.at(1), *i));
}
}
else if ("dir" == tokens.at(0))
- /* nothing */ ;
+ {
+ while (tokens.size() > 2)
+ {
+ if (std::string::npos != tokens.at(2).find('='))
+ break;
+
+ tokens.at(1).append(" " + tokens.at(2));
+ tokens.erase(next(tokens.begin(), 2));
+ }
+
+ if (tokens.size() != 2)
+ Log::get_instance()->message(ll_warning, lc_no_context, "Malformed VDB entry '" + line + "'");
+ else
+ {
+ add_unmerge_entry(tokens.at(1), et_dir);
+
+ for (std::vector<std::string>::iterator i(next(tokens.begin(), 2)), i_end(tokens.end()) ;
+ i != i_end ; ++i)
+ _imp->extra_info.insert(std::make_pair(tokens.at(1), *i));
+ }
+ }
else
- Log::get_instance()->message(ll_warning, lc_no_context, "Malformed VDB entry '" + *cur + "'");
+ Log::get_instance()->message(ll_warning, lc_no_context, "Malformed VDB entry '" + line + "'");
}
}
-template <typename I_>
-void
-VDBUnmerger::unmerge_directories(I_ cur, const I_ end)
+bool
+VDBUnmerger::check_file(const FSEntry & f) const
{
- 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;
+ ExtraInfoIterator i(_imp->extra_info.lower_bound(stringify(f)));
- while (tokens.size() > 2)
+ if (! (_imp->options.root / f).is_regular_file())
+ display("--- [!type] " + stringify(f));
+ else if (stringify((_imp->options.root / f).mtime()) != next(i)->second)
+ display("--- [!time] " + stringify(f));
+ else
+ {
+ std::ifstream md5_file(stringify(_imp->options.root / f).c_str());
+ if (! md5_file)
{
- 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();
+ Log::get_instance()->message(ll_warning, lc_no_context, "Cannot get md5 for '" +
+ stringify(_imp->options.root / f) + "'");
+ display("--- [!md5?] " + stringify(f));
}
-
- 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 if (MD5(md5_file).hexsum() != i->second)
+ display("--- [!md5 ] " + stringify(f));
+ else if (config_protected(_imp->options.root / f))
+ display("--- [cfgpr] " + stringify(f));
else
- {
- std::cout << "<<< " << tokens.at(1) << std::endl;
- unlink_dir(_imp->options.root / tokens.at(1));
- }
+ return true;
}
+
+ return false;
+}
+
+bool
+VDBUnmerger::check_sym(const FSEntry & f) const
+{
+ ExtraInfoIterator i(_imp->extra_info.lower_bound(stringify(f)));
+
+ if (! (_imp->options.root / f).is_symbolic_link())
+ display("--- [!type] " + stringify(f));
+ else if (stringify((_imp->options.root / f).mtime()) != next(i)->second)
+ display("--- [!time] " + stringify(f));
+ else if ((_imp->options.root / f).readlink() != i->second)
+ display("--- [!dest] " + stringify(f));
+ else
+ return true;
+
+ return false;
+}
+
+bool
+VDBUnmerger::check_misc(const FSEntry & f) const
+{
+ ExtraInfoIterator i(_imp->extra_info.lower_bound(stringify(f)));
+
+ if ("fif" == i->second && ! (_imp->options.root / f).is_fifo())
+ display("--- [!type] " + stringify(f));
+ else if ("dev" == i->second && ! (_imp->options.root / f).is_device())
+ display("--- [!type] " + stringify(f));
+ else
+ return true;
+
+ return false;
+}
+
+bool
+VDBUnmerger::check_dir(const FSEntry & f) const
+{
+ if (! (_imp->options.root / f).is_directory())
+ display("--- [!type] " + stringify(f));
+ else if (DirIterator(_imp->options.root / f, false) != DirIterator())
+ display("--- [!empt] " + stringify(f));
+ else
+ return true;
+
+ return false;
+}
+
+void
+VDBUnmerger::display(const std::string & message) const
+{
+ std::cout << message << std::endl;
}
VDBUnmergerError::VDBUnmergerError(const std::string & s) throw () :
diff --git a/paludis/repositories/gentoo/vdb_unmerger.hh b/paludis/repositories/gentoo/vdb_unmerger.hh
index 10ca73c..4c6e967 100644
--- a/paludis/repositories/gentoo/vdb_unmerger.hh
+++ b/paludis/repositories/gentoo/vdb_unmerger.hh
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ * Copyright (c) 2007 Piotr Jaroszyński <peper@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
@@ -57,25 +58,25 @@ namespace paludis
* \ingroup grpvdbrepository
* \nosubgrouping
*/
- class VDBUnmerger :
- private PrivateImplementationPattern<VDBUnmerger>,
- public Unmerger
+ class PALUDIS_VISIBLE VDBUnmerger :
+ public Unmerger,
+ private PrivateImplementationPattern<VDBUnmerger>
{
+ private:
+ Implementation<VDBUnmerger> * _imp;
+
protected:
- bool config_protected(const FSEntry &);
+ bool config_protected(const FSEntry &) const;
std::string make_tidy(const FSEntry &) const;
- /**
- * Unmerge non-directories.
- */
- template <typename I_>
- void unmerge_non_directories(I_ begin, const I_ end);
+ void populate_unmerge_set();
+
+ void display(const std::string &) const;
- /**
- * Unmerge directories.
- */
- template <typename I_>
- void unmerge_directories(I_ begin, const I_ end);
+ bool check_file(const FSEntry &) const;
+ bool check_dir(const FSEntry &) const;
+ bool check_sym(const FSEntry &) const;
+ bool check_misc(const FSEntry &) const;
public:
///\name Basic operations
@@ -86,12 +87,7 @@ namespace paludis
///\}
- virtual Hook extend_hook(const Hook &);
-
- /**
- * Perform the unmerge.
- */
- void unmerge();
+ virtual Hook extend_hook(const Hook &) const;
};
}
diff --git a/paludis/repositories/gentoo/vdb_unmerger.sr b/paludis/repositories/gentoo/vdb_unmerger.sr
index 273d7ad..a77b2a7 100644
--- a/paludis/repositories/gentoo/vdb_unmerger.sr
+++ b/paludis/repositories/gentoo/vdb_unmerger.sr
@@ -3,6 +3,8 @@
make_class_VDBUnmergerOptions()
{
+ visible
+
key environment "Environment *"
key root "FSEntry"
key contents_file "FSEntry"
diff --git a/paludis/repositories/gentoo/vdb_unmerger_TEST.cc b/paludis/repositories/gentoo/vdb_unmerger_TEST.cc
new file mode 100644
index 0000000..b999d1a
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_unmerger_TEST.cc
@@ -0,0 +1,348 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Piotr Jaroszyński <peper@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 "vdb_unmerger.hh"
+#include <paludis/environments/test/test_environment.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace test;
+
+namespace paludis
+{
+ class VDBUnmergerNoDisplay :
+ public VDBUnmerger
+ {
+ protected:
+ void display(const std::string &) const
+ {
+ }
+
+ public:
+ VDBUnmergerNoDisplay(const VDBUnmergerOptions & o) :
+ VDBUnmerger(o)
+ {
+ }
+ };
+
+ class VDBUnmergerTest :
+ public TestCase
+ {
+ public:
+ FSEntry root_dir;
+ std::string target;
+ TestEnvironment env;
+ VDBUnmergerNoDisplay unmerger;
+
+ bool repeatable() const
+ {
+ return false;
+ }
+
+ protected:
+ VDBUnmergerTest(const std::string & what) :
+ TestCase("unmerge '" + what + "' test"),
+ root_dir("vdb_unmerger_TEST_dir/root"),
+ target(what),
+ unmerger(VDBUnmergerOptions::create()
+ .environment(&env)
+ .root(root_dir)
+ .contents_file("vdb_unmerger_TEST_dir/CONTENTS/" + what)
+ .config_protect("")
+ .config_protect_mask("")
+ .package_name(QualifiedPackageName("cat/test"))
+ .version(VersionSpec("0"))
+ .repository(0))
+ {
+ }
+ };
+}
+
+namespace test_cases
+{
+ struct VDBUnmergerTestFileOk : VDBUnmergerTest
+ {
+ VDBUnmergerTestFileOk() : VDBUnmergerTest("file_ok") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_regular_file());
+
+ unmerger.unmerge();
+
+ TEST_CHECK(! (root_dir / target).exists());
+ }
+ } test_vdb_unmerger_file_ok;
+
+ struct VDBUnmergerTestFileWithSpaces : VDBUnmergerTest
+ {
+ VDBUnmergerTestFileWithSpaces() : VDBUnmergerTest("file_ with spaces") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_regular_file());
+
+ unmerger.unmerge();
+
+ TEST_CHECK(! (root_dir / target).exists());
+ }
+ } test_vdb_unmerger_file_with_spaces;
+
+ struct VDBUnmergerTestFileBadType : VDBUnmergerTest
+ {
+ VDBUnmergerTestFileBadType() : VDBUnmergerTest("file_bad_type") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_directory());
+
+ unmerger.unmerge();
+
+ TEST_CHECK((root_dir / target).is_directory());
+ }
+ } test_vdb_unmerger_file_bad_type;
+
+ struct VDBUnmergerTestFileBadMd5sum : VDBUnmergerTest
+ {
+ VDBUnmergerTestFileBadMd5sum() : VDBUnmergerTest("file_bad_md5sum") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_regular_file());
+
+ unmerger.unmerge();
+
+ TEST_CHECK((root_dir / target).is_regular_file());
+ }
+ } test_vdb_unmerger_file_bad_md5sum;
+
+ struct VDBUnmergerTestFileBadMtime : VDBUnmergerTest
+ {
+ VDBUnmergerTestFileBadMtime() : VDBUnmergerTest("file_bad_mtime") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_regular_file());
+
+ unmerger.unmerge();
+
+ TEST_CHECK((root_dir / target).is_regular_file());
+ }
+ } test_vdb_unmerger_file_bad_mtime;
+
+ struct VDBUnmergerTestDirOk : VDBUnmergerTest
+ {
+ VDBUnmergerTestDirOk() : VDBUnmergerTest("dir_ok") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_directory());
+
+ unmerger.unmerge();
+
+ TEST_CHECK(! (root_dir / target).exists());
+ }
+ } test_vdb_unmerger_dir_ok;
+
+ struct VDBUnmergerTestDirWithSpaces : VDBUnmergerTest
+ {
+ VDBUnmergerTestDirWithSpaces() : VDBUnmergerTest("dir_ with spaces") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_directory());
+
+ unmerger.unmerge();
+
+ TEST_CHECK(! (root_dir / target).exists());
+ }
+ } test_vdb_unmerger_dir_with_spaces;
+
+ struct VDBUnmergerTestDirBadType : VDBUnmergerTest
+ {
+ VDBUnmergerTestDirBadType() : VDBUnmergerTest("dir_bad_type") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_regular_file());
+
+ unmerger.unmerge();
+
+ TEST_CHECK((root_dir / target).is_regular_file());
+ }
+ } test_vdb_unmerger_dir_bad_type;
+
+ struct VDBUnmergerTestDirNotEmpty : VDBUnmergerTest
+ {
+ VDBUnmergerTestDirNotEmpty() : VDBUnmergerTest("dir_not_empty") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_directory());
+
+ unmerger.unmerge();
+
+ TEST_CHECK((root_dir / target).is_directory());
+ }
+ } test_vdb_unmerger_dir_not_empty;
+
+ struct VDBUnmergerTestSymOk : VDBUnmergerTest
+ {
+ VDBUnmergerTestSymOk() : VDBUnmergerTest("sym_ok") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_symbolic_link());
+
+ unmerger.unmerge();
+
+ TEST_CHECK(! (root_dir / target).exists());
+ }
+ } test_vdb_unmerger_sym_ok;
+
+ struct VDBUnmergerTestSymWithSpaces : VDBUnmergerTest
+ {
+ VDBUnmergerTestSymWithSpaces() : VDBUnmergerTest("sym_ with spaces") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_symbolic_link());
+
+ unmerger.unmerge();
+
+ TEST_CHECK(! (root_dir / target).exists());
+ }
+ } test_vdb_unmerger_sym_with_spaces;
+
+ struct VDBUnmergerTestSymBadType : VDBUnmergerTest
+ {
+ VDBUnmergerTestSymBadType() : VDBUnmergerTest("sym_bad_type") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_regular_file());
+
+ unmerger.unmerge();
+
+ TEST_CHECK((root_dir / target).is_regular_file());
+ }
+ } test_vdb_unmerger_sym_bad_type;
+
+ struct VDBUnmergerTestSymBadDst : VDBUnmergerTest
+ {
+ VDBUnmergerTestSymBadDst() : VDBUnmergerTest("sym_bad_dst") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_symbolic_link());
+ TEST_CHECK(! (root_dir / "sym_dst_bad").exists());
+
+ unmerger.unmerge();
+
+ TEST_CHECK((root_dir / target).is_symbolic_link());
+ }
+ } test_vdb_unmerger_sym_bad_dst;
+
+ struct VDBUnmergerTestSymBadMtime : VDBUnmergerTest
+ {
+ VDBUnmergerTestSymBadMtime() : VDBUnmergerTest("sym_bad_mtime") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_symbolic_link());
+
+ unmerger.unmerge();
+
+ TEST_CHECK((root_dir / target).is_symbolic_link());
+
+ }
+ } test_vdb_unmerger_sym_bad_mtime;
+
+ struct VDBUnmergerTestSymBadEntry1 : VDBUnmergerTest
+ {
+ VDBUnmergerTestSymBadEntry1() : VDBUnmergerTest("sym_bad_entry_1") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_symbolic_link());
+
+ unmerger.unmerge();
+
+ TEST_CHECK((root_dir / target).is_symbolic_link());
+ }
+ } test_vdb_unmerger_sym_bad_entry_1;
+
+ struct VDBUnmergerTestSymBadEntry2 : VDBUnmergerTest
+ {
+ VDBUnmergerTestSymBadEntry2() : VDBUnmergerTest("sym_bad_entry_2") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_symbolic_link());
+
+ unmerger.unmerge();
+
+ TEST_CHECK((root_dir / target).is_symbolic_link());
+ }
+ } test_vdb_unmerger_sym_bad_entry_2;
+
+ struct VDBUnmergerTestFifoOk : VDBUnmergerTest
+ {
+ VDBUnmergerTestFifoOk() : VDBUnmergerTest("fifo_ok") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_fifo());
+
+ unmerger.unmerge();
+
+ TEST_CHECK(! (root_dir / target).exists());
+ }
+ } test_vdb_unmerger_fifo_ok;
+
+ struct VDBUnmergerTestFifoWithSpaces : VDBUnmergerTest
+ {
+ VDBUnmergerTestFifoWithSpaces() : VDBUnmergerTest("fifo_ with spaces") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_fifo());
+
+ unmerger.unmerge();
+
+ TEST_CHECK(! (root_dir / target).exists());
+ }
+ } test_vdb_unmerger_fifo_with_spaces;
+
+ struct VDBUnmergerTestFifoBadType : VDBUnmergerTest
+ {
+ VDBUnmergerTestFifoBadType() : VDBUnmergerTest("fifo_bad_type") { }
+
+ void run()
+ {
+ TEST_CHECK((root_dir / target).is_regular_file());
+
+ unmerger.unmerge();
+
+ TEST_CHECK((root_dir / target).is_regular_file());
+ }
+ } test_vdb_unmerger_fifo_bad_type;
+}
+
diff --git a/paludis/repositories/gentoo/vdb_unmerger_TEST_cleanup.sh b/paludis/repositories/gentoo/vdb_unmerger_TEST_cleanup.sh
new file mode 100755
index 0000000..16dea18
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_unmerger_TEST_cleanup.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d vdb_unmerger_TEST_dir ] ; then
+ rm -fr vdb_unmerger_TEST_dir
+else
+ true
+fi
+
diff --git a/paludis/repositories/gentoo/vdb_unmerger_TEST_setup.sh b/paludis/repositories/gentoo/vdb_unmerger_TEST_setup.sh
new file mode 100755
index 0000000..34110b3
--- /dev/null
+++ b/paludis/repositories/gentoo/vdb_unmerger_TEST_setup.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir vdb_unmerger_TEST_dir || exit 2
+cd vdb_unmerger_TEST_dir || exit 3
+
+mkdir CONTENTS
+
+mkdir root
+cd root
+
+make_file() {
+ echo "foo" > "file_$1"
+
+ md5=${2:-$(md5sum "file_$1" | cut -f1 -d' ')}
+ mtime=${3:-$(${PALUDIS_EBUILD_DIR}/utils/getmtime "file_$1")}
+ echo "obj /file_$1 ${md5} ${mtime}" > "../CONTENTS/file_$1"
+}
+
+make_sym() {
+ src="sym_$1"
+ dst=${2:-"sym_$1_dst"}
+
+ > "sym_$1_dst"
+ ln -s "${dst}" "${src}"
+
+ mtime=${3:-$(${PALUDIS_EBUILD_DIR}/utils/getmtime "sym_$1")}
+ echo "sym /${src} -> sym_$1_dst ${mtime}" > "../CONTENTS/sym_$1"
+}
+
+make_file "ok"
+
+make_file " with spaces"
+
+make_file "bad_type"
+rm file_bad_type
+mkdir file_bad_type
+
+make_file "bad_md5sum" "bad_md5sum"
+make_file "bad_mtime" "" "bad_mtime"
+echo "obj /file_bad_entry foo" > ../CONTENTS/file_bad_entry
+
+mkdir dir_ok
+echo "dir /dir_ok" > ../CONTENTS/dir_ok
+
+mkdir "dir_ with spaces"
+echo "dir /dir_ with spaces" > "../CONTENTS/dir_ with spaces"
+
+> dir_bad_type
+echo "dir /dir_bad_type" > ../CONTENTS/dir_bad_type
+
+mkdir -p dir_not_empty/foo
+echo "dir /dir_not_empty" > ../CONTENTS/dir_not_empty
+
+make_sym "ok"
+make_sym " with spaces"
+
+make_sym "bad_type"
+rm sym_bad_type
+> sym_bad_type
+
+make_sym "bad_dst" "sym_dst_bad"
+make_sym "bad_mtime" "" "123"
+
+ln -s foo sym_bad_entry_1
+echo "sym /sym_bad_entry_1 -> foo" > "../CONTENTS/sym_bad_entry_1"
+ln -s foo sym_bad_entry_2
+echo "sym /sym_bad_entry_2 >> foo 123" > "../CONTENTS/sym_bad_entry_2"
+
+mkfifo fifo_ok
+echo "fif /fifo_ok" > "../CONTENTS/fifo_ok"
+
+mkfifo "fifo_ with spaces"
+echo "fif /fifo_ with spaces" > "../CONTENTS/fifo_ with spaces"
+
+> fifo_bad_type
+echo "fif /fifo_bad_type" > "../CONTENTS/fifo_bad_type"
+