aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Saleem Abdulrasool <compnerd@compnerd.org> 2013-05-27 01:00:49 -0700
committerAvatar Saleem Abdulrasool <compnerd@compnerd.org> 2013-06-01 22:12:32 -0700
commitb04e6805a25ef61c29fe88bcc4cea73ebb23f57a (patch)
tree81e4560f701e6e76e7ebcc62ca8be141f5ee2ce1
parentd34636a1dc4f422aeb868e49447a0503c303f0a2 (diff)
downloadpaludis-b04e6805a25ef61c29fe88bcc4cea73ebb23f57a.tar.gz
paludis-b04e6805a25ef61c29fe88bcc4cea73ebb23f57a.tar.xz
merger: add support for selective parts
This adds the ability to take the associated classification information via expart and then use that along with options to selectively install parts. Signed-off-by: Saleem Abdulrasool <compnerd@compnerd.org>
-rw-r--r--paludis/fs_merger.cc93
-rw-r--r--paludis/fs_merger.hh7
-rw-r--r--paludis/fs_merger.se1
-rw-r--r--paludis/fs_merger_TEST.cc6
-rw-r--r--paludis/ndbam_merger.cc11
-rw-r--r--paludis/ndbam_merger.hh2
-rw-r--r--paludis/partitioning.cc10
-rw-r--r--paludis/partitioning.hh11
-rw-r--r--paludis/repositories/e/exndbam_repository.cc39
-rw-r--r--paludis/repositories/e/exndbam_repository_TEST.cc127
-rwxr-xr-xpaludis/repositories/e/exndbam_repository_TEST_setup.sh19
-rw-r--r--paludis/repositories/e/vdb_merger.cc3
-rw-r--r--paludis/repositories/unpackaged/installed_repository.cc3
13 files changed, 309 insertions, 23 deletions
diff --git a/paludis/fs_merger.cc b/paludis/fs_merger.cc
index e08a05a..908ce12 100644
--- a/paludis/fs_merger.cc
+++ b/paludis/fs_merger.cc
@@ -35,6 +35,7 @@
#include <paludis/selinux/security_context.hh>
#include <paludis/environment.hh>
#include <paludis/hook.hh>
+#include <paludis/partitioning.hh>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -69,11 +70,31 @@ namespace paludis
{
MergedMap merged_ids;
FSMergerParams params;
+ std::set<FSPath, FSPathComparator> elided_paths;
Imp(const FSMergerParams & p) :
params(p)
{
}
+
+ bool is_elided_directory(const FSPath & dir) const
+ {
+ for (FSIterator dentry(dir, { fsio_include_dotfiles }), invalid;
+ dentry != invalid; ++dentry)
+ {
+ const auto path = dentry->strip_leading(params.image());
+ const auto part = params.parts()->classify(path);
+
+ if (path.stat().is_directory())
+ if (! is_elided_directory(*dentry))
+ return false;
+
+ if (params.should_merge()(path))
+ return false;
+ }
+
+ return true;
+ }
};
}
@@ -216,7 +237,7 @@ FSMerger::on_dir_over_dir(bool is_check, const FSPath & src, const FSPath & dst)
if (is_check)
return;
- track_install_dir(src, dst, FSMergerStatusFlags() + msi_used_existing);
+ track_install_dir(src, dst, { msi_used_existing });
}
void
@@ -242,7 +263,7 @@ FSMerger::on_dir_over_sym(bool is_check, const FSPath & src, const FSPath & dst)
"' to be a directory but found a symlink to a directory");
if (! is_check)
- track_install_dir(src, dst, FSMergerStatusFlags() + msi_used_existing);
+ track_install_dir(src, dst, { msi_used_existing });
}
else
on_error(is_check, "Expected '" + stringify(dst / src.basename()) +
@@ -310,13 +331,17 @@ FSMerger::install_file(const FSPath & src, const FSPath & dst_dir, const std::st
{
Context context("When installing file '" + stringify(src) + "' to '" + stringify(dst_dir) + "' with protection '"
+ stringify(dst_name) + "':");
- FSMergerStatusFlags result;
-
- FSStat src_stat(src);
- FSPath dst(dst_dir / (stringify(dst_name) + "|paludis-midmerge"));
FSPath dst_real(dst_dir / dst_name);
+
+ if (_imp->params.should_merge() &&
+ ! _imp->params.should_merge()(dst_real.strip_leading(_imp->params.root().realpath())))
+ return { msi_unselected_part };
+
+ FSMergerStatusFlags result;
+ FSStat src_stat(src);
FSStat dst_real_stat(dst_real);
+ FSPath dst(dst_dir / (stringify(dst_name) + "|paludis-midmerge"));
if (dst_real_stat.is_regular_file())
dst_real.chmod(0);
@@ -528,9 +553,20 @@ FSMerger::install_dir(const FSPath & src, const FSPath & dst_dir)
{
Context context("When installing dir '" + stringify(src) + "' to '" + stringify(dst_dir) + "':");
+ const FSPath dst(dst_dir / src.basename());
FSMergerStatusFlags result;
FSStat src_stat(src);
+ if (! _imp->elided_paths.empty())
+ {
+ const auto path = dst.strip_leading(_imp->params.root());
+ if (_imp->elided_paths.find(path) != _imp->elided_paths.end())
+ {
+ set_skipped_dir(true);
+ return { msi_unselected_part };
+ }
+ }
+
if (0 != _imp->params.environment()->perform_hook(extend_hook(
Hook("merger_install_dir_pre")
("INSTALL_SOURCE", stringify(src))
@@ -543,7 +579,6 @@ FSMerger::install_dir(const FSPath & src, const FSPath & dst_dir)
if (0 != (mode & (S_ISVTX | S_ISUID | S_ISGID)))
result += msi_setid_bits;
- FSPath dst(dst_dir / src.basename());
std::shared_ptr<const SecurityContext> secctx(MatchPathCon::get_instance()->match(stringify(dst), mode));
FSCreateCon createcon(secctx);
if (0 != paludis::setfilecon(src, secctx))
@@ -553,7 +588,10 @@ FSMerger::install_dir(const FSPath & src, const FSPath & dst_dir)
if (is_selinux_enabled())
relabel_dir_recursive(src, dst);
- if ((! _imp->params.options()[mo_nondestructive]) &&
+ const bool partitioned = _imp->params.parts() &&
+ _imp->params.parts()->is_partitioned(dst.strip_leading(_imp->params.root()));
+
+ if (! partitioned && ! _imp->params.options()[mo_nondestructive] &&
0 == std::rename(stringify(src).c_str(), stringify(dst).c_str()))
{
result += msi_rename;
@@ -562,8 +600,9 @@ FSMerger::install_dir(const FSPath & src, const FSPath & dst_dir)
}
else
{
- Log::get_instance()->message("merger.dir.rename_failed", ll_debug, lc_context) <<
- "rename failed. Falling back to recursive copy.";
+ if (! partitioned && ! _imp->params.options()[mo_nondestructive])
+ Log::get_instance()->message("merger.dir.rename_failed", ll_debug, lc_context)
+ << "rename failed. Falling back to recursive copy.";
dst.mkdir(mode, { fspmkdo_ok_if_exists });
FDHolder dst_fd(::open(stringify(dst).c_str(), O_RDONLY));
@@ -604,9 +643,13 @@ FSMerger::install_sym(const FSPath & src, const FSPath & dst_dir)
{
Context context("When installing sym '" + stringify(src) + "' to '" + stringify(dst_dir) + "':");
- FSMergerStatusFlags result;
-
FSPath dst(dst_dir / src.basename());
+
+ if (_imp->params.should_merge() &&
+ ! _imp->params.should_merge()(dst.strip_leading(_imp->params.root().realpath())))
+ return { msi_unselected_part };
+
+ FSMergerStatusFlags result;
FSStat src_stat(src);
if (0 != _imp->params.environment()->perform_hook(extend_hook(
@@ -851,6 +894,10 @@ FSMerger::try_to_copy_xattrs(const FSPath &, int, FSMergerStatusFlags &)
void
FSMerger::track_install_file(const FSPath & src, const FSPath & dst_dir, const std::string & dst_name, const FSMergerStatusFlags & flags)
{
+ if (flags[msi_unselected_part])
+ return display_merge(et_file, dst_dir / src.basename(), flags,
+ src.basename() == dst_name ? "" : dst_name);
+
_imp->params.merged_entries()->insert(dst_dir / dst_name);
record_install_file(src, dst_dir, dst_name, flags);
}
@@ -858,6 +905,9 @@ FSMerger::track_install_file(const FSPath & src, const FSPath & dst_dir, const s
void
FSMerger::track_install_dir(const FSPath & src, const FSPath & dst_dir, const FSMergerStatusFlags & flags)
{
+ if (flags[msi_unselected_part])
+ return display_merge(et_dir, dst_dir / src.basename(), flags);
+
_imp->params.merged_entries()->insert(dst_dir / src.basename());
record_install_dir(src, dst_dir, flags);
}
@@ -872,6 +922,9 @@ FSMerger::track_install_under_dir(const FSPath & dst, const FSMergerStatusFlags
void
FSMerger::track_install_sym(const FSPath & src, const FSPath & dst_dir, const FSMergerStatusFlags & flags)
{
+ if (flags[msi_unselected_part])
+ return display_merge(et_sym, dst_dir / src.basename(), flags);
+
_imp->params.merged_entries()->insert(dst_dir / src.basename());
record_install_sym(src, dst_dir, flags);
}
@@ -952,6 +1005,18 @@ FSMerger::on_dir_main(bool is_check, const FSPath & src, const FSPath & dst)
}
void
+FSMerger::on_enter_dir(bool is_check, const FSPath src)
+{
+ if (is_check || ! _imp->params.parts() || ! _imp->params.should_merge())
+ return;
+
+ for (FSIterator dentry(src, { fsio_want_directories }), invalid;
+ dentry != invalid; ++dentry)
+ if (_imp->is_elided_directory(*dentry))
+ _imp->elided_paths.insert(dentry->strip_leading(_imp->params.image()));
+}
+
+void
FSMerger::on_sym_main(bool is_check, const FSPath & src, const FSPath & dst)
{
EntryType m(entry_type(dst / src.basename()));
@@ -1025,6 +1090,10 @@ FSMerger::make_arrows(const FSMergerStatusFlags & flags) const
result[0] = '=';
continue;
+ case msi_unselected_part:
+ result[0] = '%';
+ continue;
+
case msi_parent_rename:
result[1] = '^';
continue;
diff --git a/paludis/fs_merger.hh b/paludis/fs_merger.hh
index e0f2848..c0f67a8 100644
--- a/paludis/fs_merger.hh
+++ b/paludis/fs_merger.hh
@@ -62,6 +62,7 @@ namespace paludis
typedef Name<struct name_parts> parts;
typedef Name<struct name_permit_destination> permit_destination;
typedef Name<struct name_root> root;
+ typedef Name<struct name_should_merge> should_merge;
}
/**
@@ -108,12 +109,16 @@ namespace paludis
NamedValue<n::no_chown, bool> no_chown;
NamedValue<n::options, MergerOptions> options;
+ ///\since 1.1.0
NamedValue<n::parts, std::shared_ptr<const Partitioning> > parts;
///\since 0.66
NamedValue<n::permit_destination, PermitDestinationFn> permit_destination;
NamedValue<n::root, FSPath> root;
+
+ ///\since 1.99.0
+ NamedValue<n::should_merge, std::function<bool(const FSPath &)>> should_merge;
};
/**
@@ -187,6 +192,8 @@ namespace paludis
virtual void unlink_file(FSPath);
virtual void record_install_file(const FSPath &, const FSPath &, const std::string &, const FSMergerStatusFlags &) = 0;
+ virtual void on_enter_dir(bool is_check, const FSPath);
+
virtual void on_dir_main(bool is_check, const FSPath & src, const FSPath & dst);
virtual void on_dir_over_nothing(bool is_check, const FSPath &, const FSPath &);
virtual void on_dir_over_file(bool is_check, const FSPath &, const FSPath &);
diff --git a/paludis/fs_merger.se b/paludis/fs_merger.se
index a05cec3..5681f13 100644
--- a/paludis/fs_merger.se
+++ b/paludis/fs_merger.se
@@ -13,6 +13,7 @@ make_enum_FSMergerStatusFlag()
key msi_setid_bits "The source file had set*id bits"
key msi_xattr "The source file had xattr bits"
key msi_as_hardlink "We detected a hardlink and merged it as such"
+ key msi_unselected_part "The content belongs to an unselected part"
doxygen_comment << "END"
/**
diff --git a/paludis/fs_merger_TEST.cc b/paludis/fs_merger_TEST.cc
index 5b63ca3..3b1fc06 100644
--- a/paludis/fs_merger_TEST.cc
+++ b/paludis/fs_merger_TEST.cc
@@ -176,7 +176,8 @@ namespace
n::options() = MergerOptions() + mo_rewrite_symlinks + mo_allow_empty_dirs,
n::parts() = nullptr,
n::permit_destination() = std::bind(return_literal_function(true)),
- n::root() = root_dir.realpath()
+ n::root() = root_dir.realpath(),
+ n::should_merge() = nullptr
))
{
}
@@ -200,7 +201,8 @@ namespace
n::options() = o,
n::parts() = nullptr,
n::permit_destination() = std::bind(return_literal_function(true)),
- n::root() = root_dir.realpath()
+ n::root() = root_dir.realpath(),
+ n::should_merge() = nullptr
))
{
}
diff --git a/paludis/ndbam_merger.cc b/paludis/ndbam_merger.cc
index 24ce4e2..282b4c8 100644
--- a/paludis/ndbam_merger.cc
+++ b/paludis/ndbam_merger.cc
@@ -86,7 +86,8 @@ NDBAMMerger::NDBAMMerger(const NDBAMMergerParams & p) :
n::options() = p.options(),
n::parts() = p.parts(),
n::permit_destination() = p.permit_destination(),
- n::root() = p.root()
+ n::root() = p.root(),
+ n::should_merge() = p.should_merge()
)),
_imp(p)
{
@@ -326,12 +327,12 @@ NDBAMMerger::check()
}
void
-NDBAMMerger::on_enter_dir(bool is_check, const FSPath)
+NDBAMMerger::on_enter_dir(bool is_check, const FSPath src)
{
- if (! is_check)
- return;
+ if (is_check)
+ _imp->params.output_manager()->stdout_stream() << "." << std::flush;
- _imp->params.output_manager()->stdout_stream() << "." << std::flush;
+ FSMerger::on_enter_dir(is_check, src);
}
void
diff --git a/paludis/ndbam_merger.hh b/paludis/ndbam_merger.hh
index ddc5077..8508b79 100644
--- a/paludis/ndbam_merger.hh
+++ b/paludis/ndbam_merger.hh
@@ -47,6 +47,7 @@ namespace paludis
typedef Name<struct name_parts> parts;
typedef Name<struct name_permit_destination> permit_destination;
typedef Name<struct name_root> root;
+ typedef Name<struct name_should_merge> should_merge;
}
struct NDBAMMergerParams
@@ -67,6 +68,7 @@ namespace paludis
NamedValue<n::parts, std::shared_ptr<const Partitioning> > parts;
NamedValue<n::permit_destination, PermitDestinationFn> permit_destination;
NamedValue<n::root, FSPath> root;
+ NamedValue<n::should_merge, std::function<bool(const FSPath &)>> should_merge;
};
/**
diff --git a/paludis/partitioning.cc b/paludis/partitioning.cc
index 791c655..afb3a0d 100644
--- a/paludis/partitioning.cc
+++ b/paludis/partitioning.cc
@@ -62,3 +62,13 @@ Partitioning::classify(const FSPath & path) const
return PartName("");
}
+bool
+Partitioning::is_partitioned(const FSPath & path) const
+{
+ for (auto part = _imp->parts.rbegin(), end = _imp->parts.rend();
+ part != end; ++part)
+ if (part->first.starts_with(path) && ! part->second.value().empty())
+ return true;
+ return false;
+}
+
diff --git a/paludis/partitioning.hh b/paludis/partitioning.hh
index 26bf8d0..31aafb4 100644
--- a/paludis/partitioning.hh
+++ b/paludis/partitioning.hh
@@ -77,6 +77,17 @@ namespace paludis
* \since 1.1.0
*/
PartName classify(const FSPath &) const;
+
+ /**
+ * Check if a path is partitioned.
+ *
+ * \arg [in] path the path to check
+ *
+ * \return %true if the path contains a partioned image
+ *
+ * \since 1.99.0
+ */
+ bool is_partitioned(const FSPath &) const;
};
}
diff --git a/paludis/repositories/e/exndbam_repository.cc b/paludis/repositories/e/exndbam_repository.cc
index ca14dae..81116a4 100644
--- a/paludis/repositories/e/exndbam_repository.cc
+++ b/paludis/repositories/e/exndbam_repository.cc
@@ -49,7 +49,9 @@
#include <paludis/metadata_key.hh>
#include <paludis/package_id.hh>
#include <paludis/action.hh>
+#include <paludis/choice.hh>
#include <paludis/literal_metadata_key.hh>
+#include <paludis/partitioning.hh>
#include <paludis/slot.hh>
#include <functional>
@@ -330,6 +332,27 @@ namespace
{
return s->end() != s->find(f);
}
+
+ bool
+ should_merge(const std::shared_ptr<Partitioning> & partitioning,
+ const std::shared_ptr<const Choice> & parts,
+ const FSPath & path)
+ {
+ if (! partitioning)
+ return true;
+
+ const auto classification(partitioning->classify(path).value());
+
+ // NOTE(compnerd) the empty name signifies the core partition
+ if (classification.empty())
+ return true;
+
+ for (const auto & part : *parts)
+ if (part->unprefixed_name().value() == classification)
+ return part->enabled();
+
+ throw InternalError(PALUDIS_HERE, classification + " choice not found");
+ }
}
void
@@ -429,9 +452,20 @@ ExndbamRepository::merge(const MergeParams & m)
}
}
- auto eapi(std::static_pointer_cast<const ERepositoryID>(m.package_id())->eapi()->supported());
+ auto package(std::static_pointer_cast<const ERepositoryID>(m.package_id()));
+ auto eapi(package->eapi()->supported());
auto fix_mtimes(eapi->ebuild_options()->fix_mtimes());
+ std::function<bool(const FSPath &)> should_merge_callback;
+ if (auto prefix = eapi->parts_prefix())
+ {
+ const auto choices(package->choices_key()->parse_value());
+ const auto parts(choices->find(ChoicePrefixName(prefix->value())));
+
+ should_merge_callback =
+ std::bind(should_merge, m.parts(), *parts, std::placeholders::_1);
+ }
+
NDBAMMerger merger(
make_named_values<NDBAMMergerParams>(
n::config_protect() = config_protect,
@@ -449,7 +483,8 @@ ExndbamRepository::merge(const MergeParams & m)
n::package_id() = m.package_id(),
n::parts() = m.parts(),
n::permit_destination() = m.permit_destination(),
- n::root() = installed_root_key()->parse_value()
+ n::root() = installed_root_key()->parse_value(),
+ n::should_merge() = should_merge_callback
));
(m.used_this_for_config_protect())(config_protect);
diff --git a/paludis/repositories/e/exndbam_repository_TEST.cc b/paludis/repositories/e/exndbam_repository_TEST.cc
index 5189787..025dd31 100644
--- a/paludis/repositories/e/exndbam_repository_TEST.cc
+++ b/paludis/repositories/e/exndbam_repository_TEST.cc
@@ -27,10 +27,13 @@
#include <paludis/util/join.hh>
#include <paludis/util/make_named_values.hh>
#include <paludis/util/sequence.hh>
+#include <paludis/util/fs_iterator.hh>
#include <paludis/util/fs_path.hh>
+#include <paludis/util/fs_stat.hh>
#include <paludis/standard_output_manager.hh>
#include <paludis/action.hh>
+#include <paludis/choice.hh>
#include <paludis/filtered_generator.hh>
#include <paludis/generator.hh>
#include <paludis/selection.hh>
@@ -38,6 +41,8 @@
#include <gtest/gtest.h>
+#include <algorithm>
+
using namespace paludis;
namespace
@@ -95,6 +100,26 @@ namespace
&env, { })), nullptr, { }))]->begin())->perform_action(install_action);
}
+ void
+ uninstall(const Environment & env, const std::string & package)
+ {
+ UninstallAction action(make_named_values<UninstallActionOptions>(
+ n::config_protect() = "",
+ n::if_for_install_id() = nullptr,
+ n::ignore_for_unmerge() = [](const FSPath &) { return false; },
+ n::is_overwrite() = false,
+ n::make_output_manager() = &make_standard_output_manager,
+ n::override_contents() = nullptr,
+ n::want_phase() = &want_all_phases
+ ));
+
+ auto spec(parse_user_package_dep_spec(package, &env, { }));
+ auto matches(generator::Matches(spec, nullptr, { }));
+ auto id(*env[selection::RequireExactlyOne(matches)]->begin());
+
+ id->perform_action(action);
+ }
+
std::shared_ptr<Repository>
make_exndbam_repository(Environment & env, const FSPath & root,
const std::string & name)
@@ -138,6 +163,39 @@ namespace
return ERepository::repository_factory_create(&env, std::bind(from_keys,
keys, _1));
}
+
+ bool
+ recursive_image_matches(const FSPath & root, const FSPath & directory,
+ std::vector<FSPath> & contents)
+ {
+ for (FSIterator dentry(directory, { fsio_include_dotfiles }), invalid;
+ dentry != invalid; ++dentry)
+ {
+ const FSStat fstat(*dentry);
+ const auto entry(dentry->strip_leading(root));
+
+ auto expected = std::find(std::begin(contents), std::end(contents),
+ entry);
+
+ if (expected == std::end(contents))
+ return false;
+
+ contents.erase(expected);
+
+ if (fstat.is_directory())
+ if (! recursive_image_matches(root, *dentry, contents))
+ return false;
+ }
+
+ return true;
+ }
+
+ bool
+ image_matches(const FSPath & root, const std::vector<FSPath> & contents)
+ {
+ std::vector<FSPath> unseen(contents);
+ return recursive_image_matches(root, root, unseen) && !unseen.size();
+ }
}
TEST(ExndbamRepository, RepoName)
@@ -262,3 +320,72 @@ TEST(ExndbamRepository, UnlistedPartsFails)
EXPECT_TRUE(installed->package_ids(partitioned, { })->empty());
}
+TEST(ExndbamRepository, SelectivePartsCoreOnly)
+{
+ const auto partitioned(QualifiedPackageName("category/partitioned"));
+
+ TestEnvironment env(exndbam_repository_TEST_root);
+
+ auto parts(make_exheres_0_repository(env, exndbam_repository_TEST_dir,
+ "parts"));
+ auto installed(make_exndbam_repository(env, exndbam_repository_TEST_dir,
+ "installed"));
+ env.add_repository(0, installed);
+ env.add_repository(1, parts);
+
+ EXPECT_TRUE(installed->package_ids(partitioned, { })->empty());
+ EXPECT_TRUE(!parts->package_ids(partitioned, { })->empty());
+
+ install(env, installed, "=category/partitioned-1::parts", "");
+ installed->invalidate();
+
+ EXPECT_TRUE(!installed->package_ids(partitioned, { })->empty());
+ EXPECT_TRUE(image_matches(exndbam_repository_TEST_root, {
+ FSPath("/etc"),
+ FSPath("/usr"),
+ FSPath("/usr/share"),
+ FSPath("/usr/share/man"),
+ FSPath("/usr/share/man/man1"),
+ FSPath("/usr/share/man/man1/expart.1")
+ }));
+
+ uninstall(env, "=category/partitioned-1::installed");
+}
+
+TEST(ExndbamRepository, SelectivePartsCoreAndSelectedParts)
+{
+ const auto partitioned(QualifiedPackageName("category/partitioned"));
+
+ TestEnvironment env(exndbam_repository_TEST_root);
+ env.set_want_choice_enabled(ChoicePrefixName("parts"),
+ UnprefixedChoiceName("binaries"),
+ Tribool("true"));
+
+ auto parts(make_exheres_0_repository(env, exndbam_repository_TEST_dir,
+ "parts"));
+ auto installed(make_exndbam_repository(env, exndbam_repository_TEST_dir,
+ "installed"));
+ env.add_repository(0, installed);
+ env.add_repository(1, parts);
+
+ EXPECT_TRUE(installed->package_ids(partitioned, { })->empty());
+ EXPECT_TRUE(!parts->package_ids(partitioned, { })->empty());
+
+ install(env, installed, "=category/partitioned-1::parts", "");
+ installed->invalidate();
+
+ EXPECT_TRUE(!installed->package_ids(partitioned, { })->empty());
+ EXPECT_TRUE(image_matches(exndbam_repository_TEST_root, {
+ FSPath("/etc"),
+ FSPath("/usr"),
+ FSPath("/usr/bin"),
+ FSPath("/usr/bin/binary"),
+ FSPath("/usr/share"),
+ FSPath("/usr/share/man"),
+ FSPath("/usr/share/man/man1"),
+ FSPath("/usr/share/man/man1/expart.1")
+ }));
+
+ uninstall(env, "=category/partitioned-1::installed");
+}
+
diff --git a/paludis/repositories/e/exndbam_repository_TEST_setup.sh b/paludis/repositories/e/exndbam_repository_TEST_setup.sh
index 4d2311f..1636f26 100755
--- a/paludis/repositories/e/exndbam_repository_TEST_setup.sh
+++ b/paludis/repositories/e/exndbam_repository_TEST_setup.sh
@@ -86,3 +86,22 @@ src_install() {
}
EOF
+cat <<- EOF > parts/packages/category/partitioned/partitioned-1.exheres-0
+PLATFORMS="test"
+MYOPTIONS="parts: binaries libraries"
+
+SLOT="0"
+
+src_unpack() {
+ edo mkdir -p "\${WORK}"
+}
+
+src_install() {
+ edo mkdir -p "\${IMAGE}"/usr/{bin,lib,share/man/man1}
+ edo touch "\${IMAGE}"/usr/{bin/binary,lib/library.{so,a},share/man/man1/expart.1}
+
+ expart binaries /usr/bin
+ expart libraries /usr/lib
+}
+EOF
+
diff --git a/paludis/repositories/e/vdb_merger.cc b/paludis/repositories/e/vdb_merger.cc
index 9312f22..395a119 100644
--- a/paludis/repositories/e/vdb_merger.cc
+++ b/paludis/repositories/e/vdb_merger.cc
@@ -100,7 +100,8 @@ VDBMerger::VDBMerger(const VDBMergerParams & p) :
n::options() = p.options(),
n::parts() = nullptr,
n::permit_destination() = p.permit_destination(),
- n::root() = p.root()
+ n::root() = p.root(),
+ n::should_merge() = nullptr
)),
_imp(p)
{
diff --git a/paludis/repositories/unpackaged/installed_repository.cc b/paludis/repositories/unpackaged/installed_repository.cc
index 2159e93..80bc449 100644
--- a/paludis/repositories/unpackaged/installed_repository.cc
+++ b/paludis/repositories/unpackaged/installed_repository.cc
@@ -347,7 +347,8 @@ InstalledUnpackagedRepository::merge(const MergeParams & m)
n::package_id() = m.package_id(),
n::parts() = m.parts(),
n::permit_destination() = m.permit_destination(),
- n::root() = installed_root_key()->parse_value().realpath()
+ n::root() = installed_root_key()->parse_value().realpath(),
+ n::should_merge() = nullptr
));
if (m.check())