#
# patch "ChangeLog"
# from [1486b1d2adf0958d9f9b7f79e1a6083d49d852da]
# to [55e1dd795c1b8f0884719a7aebd5cf2766b04e53]
#
# patch "change_set.cc"
# from [dca63f6f968128d67da90a44a1c2bb09e0d9c0ed]
# to [d653b309754b89d55c8c8801122d282e363f2d7f]
#
# patch "pcdv.cc"
# from [7bb131b0c0268cae51eadc9d22a11d7ec6d7ad11]
# to [fb89aec9ecf3531efeea6d7f84d8045e24152b59]
#
# patch "pcdv.hh"
# from [42ce2c9da4c7a1e77b1200885b6d3fc579592c69]
# to [7ba58f71a35e6f8e212bc926d0ec2f15d00c2dd6]
#
# patch "sanity.cc"
# from [36ad241e17f12b3d4e08f78ba1f302bb76523a76]
# to [ffb40b74ba38772ebf90bf7bc0f7ac710933a338]
#
# patch "tests/t_merge_add_del.at"
# from [20f850e8ede0f7c4240c1f9cb21855f151f89df2]
# to [7abec2ef42ef3e1ae12434eb8fea72855ae3781e]
#
# patch "tests/t_rename_added_in_rename.at"
# from [986d6f8c484b4cd73df3e6df7c67ad61f3bd1a2d]
# to [c73d2f1b0a4ba14c9165e2775c5e995a656c951d]
#
========================================================================
--- ChangeLog 1486b1d2adf0958d9f9b7f79e1a6083d49d852da
+++ ChangeLog 55e1dd795c1b8f0884719a7aebd5cf2766b04e53
@@ -1,3 +1,18 @@
+2005-08-17 Timothy Brownawell
+
+ Improve testsuite compliance: 1 failure remaining.
+ * tests/t_merge_add_del.at: Remove XFAIL
+ * pcdv.{cc,hh}, change_set.cc: (Ick! Ick! Ick!) allow tree
+ merger to generate sutures. Bugfix suture handling code.
+ Bugfix tree_state::get_changes_for_merge .
+ * sanity.cc (gasp()): When catching an error from dumping a MM'd
+ variable, do not discard output generated prior to the error. This
+ way, at least the header line (function name, file, line no.) is
+ printed.
+ * change_set.cc: write_insane_change_set: new function to write a
+ change set without sanity checking it, now used by dump().
+ * tests/t_rename_added_in_rename.at: Make comment match the code.
+
2005-08-16 Timothy Brownawell
* change_set.{cc,hh}: Replace tree merger with the one in pcdv.{cc,hh}.
========================================================================
--- change_set.cc dca63f6f968128d67da90a44a1c2bb09e0d9c0ed
+++ change_set.cc d653b309754b89d55c8c8801122d282e363f2d7f
@@ -2054,6 +2054,31 @@
{}
};
+void dump(itempaths const & obj, std::string & out)
+{
+ std::string o;
+ dump(obj.anc, o);
+ out = "Ancestor: " + o;
+ dump(obj.left, o);
+ out += "\nLeft: " + o;
+ dump(obj.right, o);
+ out += "\nRight: " + o;
+ dump(obj.merged, o);
+ out += "\nMerged: " + o;
+}
+
+void dump(std::vector const & obj, std::string & out)
+{
+ out.clear();
+ std::string o;
+ for (std::vector::const_iterator i = obj.begin();
+ i != obj.end(); ++i)
+ {
+ dump(*i, o);
+ out += o + "\n";
+ }
+}
+
static void
merge_deltas(itempaths const & paths,
std::map & merge_finalists,
@@ -2122,7 +2147,10 @@
// and we have a delta applied to a file in a2. we want to
// figure out what to call this delta's path in b2.
- itempaths const & paths = pathsmap[delta_entry_path(i)];
+ std::map::const_iterator
+ x = pathsmap.find(delta_entry_path(i));
+ I(x != pathsmap.end());
+ itempaths const & paths = x->second;
// now check to see if there was a delta on the b.second name in b
change_set::delta_map::const_iterator j = b.deltas.find(paths.right);
@@ -2140,7 +2168,8 @@
// if no deltas in b, copy ours over using the merged name
L(F("merge is copying delta '%s' : '%s' -> '%s'\n")
% paths.merged % delta_entry_src(i) % delta_entry_dst(i));
- I(b.deltas.find(paths.merged) == b.deltas.end());
+ I(b.deltas.find(paths.merged) == b.deltas.end()
+ || a.rearrangement.has_deleted_file(paths.merged));
b_merged.apply_delta(paths.merged,
delta_entry_src(i),
delta_entry_dst(i));
@@ -2251,6 +2280,8 @@
{
typedef std::multimap::iterator gi;
typedef std::map > >::iterator ai;
+
+ // process history
std::multimap graph, rgraph;
app.db.get_revision_ancestry(graph);
for (gi i = graph.begin(); i != graph.end(); ++i)
@@ -2334,6 +2365,7 @@
roots.pop_front();
}
+ // find the interesting revisions
std::map::const_iterator
i = trees.find(anc),
j = trees.find(left),
@@ -2348,14 +2380,25 @@
std::vector rr;
rr.push_back(right_extra_changes);
tree_state r = tree_state::merge_with_rearrangement(rp, rr, "xyzzy");
+
+ // do the merge
std::vector conf(l.conflict(r));
std::set res;
- E(conf.size() == 0, F("Cannot handle merge conflicts over filenames yet."));
+ for (std::vector::const_iterator i = conf.begin();
+ i != conf.end(); ++i)
+ {
+ E(i->type != path_conflict::split,
+ F("Cannot handle filename conflicts yet."));
+ if (i->type == path_conflict::collision)
+ W(F("Filename collision, suturing..."));
+ }
std::vector rl;
rl.push_back(l);
rl.push_back(r);
tree_state m = tree_state::merge_with_resolution(rl, res, "abccb");
+ I(m.conflict(m).empty());
+ // calculate outputs
std::map ip;
std::vector > ps;
ps = a.current();
@@ -2410,12 +2453,10 @@
merge_provider & merger,
app_state & app)
{
- MM(a_merged);
- MM(b_merged);
-
L(F("merging revisions\n"));
std::vector paths;
+ MM(paths);
std::map merge_finalists;
@@ -2471,13 +2512,12 @@
}
concatenate_change_sets(anc_b, b_extra_changes, anc_bwithchanges);
+ MM(b_merged);
project_missing_deltas(anc_a, anc_bwithchanges,
paths,
b_merged,
merger, merge_finalists);
- b_merged.check_sane();
-
for (std::vector::iterator i = paths.begin();
i != paths.end(); ++i)
{
@@ -2486,12 +2526,15 @@
(*i).right = t;
}
+ MM(a_merged);
project_missing_deltas(anc_bwithchanges, anc_a,
paths,
a_merged,
merger, merge_finalists);
+ L(F("Checking merge..."));
a_merged.check_sane();
+ b_merged.check_sane();
{
// confirmation step
@@ -3024,11 +3067,10 @@
void
-print_path_rearrangement(basic_io::printer & printer,
- change_set::path_rearrangement const & pr)
+print_insane_path_rearrangement(basic_io::printer & printer,
+ change_set::path_rearrangement const & pr)
{
- pr.check_sane();
for (std::set::const_iterator i = pr.deleted_files.begin();
i != pr.deleted_files.end(); ++i)
{
@@ -3073,6 +3115,14 @@
}
void
+print_path_rearrangement(basic_io::printer & printer,
+ change_set::path_rearrangement const & pr)
+{
+ pr.check_sane();
+ print_insane_path_rearrangement(printer, pr);
+}
+
+void
parse_change_set(basic_io::parser & parser,
change_set & cs)
{
@@ -3097,11 +3147,10 @@
}
void
-print_change_set(basic_io::printer & printer,
- change_set const & cs)
+print_insane_change_set(basic_io::printer & printer,
+ change_set const & cs)
{
- cs.check_sane();
- print_path_rearrangement(printer, cs.rearrangement);
+ print_insane_path_rearrangement(printer, cs.rearrangement);
for (change_set::delta_map::const_iterator i = cs.deltas.begin();
i != cs.deltas.end(); ++i)
@@ -3114,6 +3163,14 @@
}
}
+void
+print_change_set(basic_io::printer & printer,
+ change_set const & cs)
+{
+ cs.check_sane();
+ print_insane_change_set(printer, cs);
+}
+
void
read_path_rearrangement(data const & dat,
change_set::path_rearrangement & re)
@@ -3143,17 +3200,24 @@
}
void
-write_change_set(change_set const & cs,
- data & dat)
+write_insane_change_set(change_set const & cs,
+ data & dat)
{
- cs.check_sane();
std::ostringstream oss;
basic_io::printer pr(oss);
- print_change_set(pr, cs);
+ print_insane_change_set(pr, cs);
dat = data(oss.str());
}
void
+write_change_set(change_set const & cs,
+ data & dat)
+{
+ cs.check_sane();
+ write_insane_change_set(cs, dat);
+}
+
+void
write_path_rearrangement(change_set::path_rearrangement const & re,
data & dat)
{
@@ -3168,7 +3232,8 @@
dump(change_set const & cs, std::string & out)
{
data tmp;
- write_change_set(cs, tmp);
+ write_insane_change_set(cs, tmp);
+// write_change_set(cs, tmp);
out = tmp();
}
========================================================================
--- pcdv.cc 7bb131b0c0268cae51eadc9d22a11d7ec6d7ad11
+++ pcdv.cc fb89aec9ecf3531efeea6d7f84d8045e24152b59
@@ -997,13 +997,22 @@
void
tree_state::add_suture(item_id l, item_id r)
{
+ I(l != r);
+ if (l < r)
+ {
+ item_id t = r;
+ r = l;
+ l = t;
+ }
std::map::const_iterator i = sutures->find(r);
if (i != sutures->end())
add_suture(l, i->second);
+ else
+ sutures->insert(make_pair(l, r));
}
void
-tree_state::apply_sutures()
+tree_state::apply_sutures() const
{
for (std::map::const_iterator i = sutures->begin();
i != sutures->end(); ++i)
@@ -1014,7 +1023,8 @@
{
if (k == states->end())
{
- states->insert(make_pair(i->second, j->second));
+ item_status x(idx(*items, i->second));
+ states->insert(make_pair(i->second, x.suture(j->second)));
states->erase(j);
}
else
@@ -1167,7 +1177,8 @@
i != trees.end() && x != changes.end(); ++i, ++x)
{
premaps.push_back(std::map());
- std::vector > curr = i->current();
+ std::vector >
+ curr = i->current_with_dirs();
for (std::vector >::const_iterator
j = curr.begin(); j != curr.end(); ++j)
{
@@ -1312,6 +1323,7 @@
if (trees.size() == 1)
out.states.reset(new map(*out.states));
I(out.states != idx(trees, 0).states);
+ out.apply_sutures();
return out;
}
@@ -1346,8 +1358,8 @@
std::vector
tree_state::conflict(tree_state const & other) const
{
+ apply_sutures();
tree_state merged(mash(other));
- merged.apply_sutures();
std::vector out;
std::map > m;
@@ -1374,6 +1386,13 @@
I(right.size() == 1);
c.lnames.push_back(get_full_name(*left.begin()));
c.rnames.push_back(other.get_full_name(*right.begin()));
+ P(F("split: '%1%' vs '%2%' ('%3%' vs '%4%' (dirs are %5% vs %6%))")
+ % get_full_name(*left.begin())
+ % other.get_full_name(*right.begin())
+ % merged.get_full_name(*left.begin())
+ % merged.get_full_name(*right.begin())
+ % left.begin()->first
+ % right.begin()->first);
out.push_back(c);
}
for (std::set::const_iterator
@@ -1436,10 +1455,13 @@
std::vector >
tree_state::current() const
{
+ apply_sutures();
std::vector > out;
for (std::map::const_iterator i = states->begin();
i != states->end(); ++i)
{
+ if (i->second.is_dir)
+ continue;
std::set s = i->second.current_names();
I(s.size() == 1);
file_path fp = get_full_name(*s.begin());
@@ -1449,11 +1471,30 @@
return out;
}
+std::vector >
+tree_state::current_with_dirs() const
+{
+ apply_sutures();
+ std::vector > out;
+ for (std::map::const_iterator i = states->begin();
+ i != states->end(); ++i)
+ {
+ std::set s = i->second.current_names();
+ I(s.size() == 1);
+ file_path fp = get_full_name(*s.begin());
+ if (!(fp == file_path()))
+ out.push_back(make_pair(i->first, fp));
+ }
+ return out;
+}
+
void
tree_state::get_changes_for_merge(tree_state const & merged,
change_set::path_rearrangement & changes)
const
{
+ this->apply_sutures();
+ merged.apply_sutures();
changes.deleted_dirs.clear();
changes.deleted_files.clear();
changes.renamed_dirs.clear();
@@ -1464,48 +1505,76 @@
map::const_iterator l, r;
l = states->begin();
r = merged.states->begin();
+ item_status::item_state empty(-1, make_null_component());
while (l != states->end() || r != merged.states->end())
{
file_path from, to;
+ std::set pres, posts;
+ item_status::item_state pre(empty), post(empty);
bool from_is_dir(false), to_is_dir(false);
if (l == states->end())
{
- to = merged.get_full_name(r->second);
+ posts = r->second.current_names();
+ I(posts.size() == 1);
+ post = *posts.begin();
+ if (post != empty)
+ to = merged.get_full_name(post);
to_is_dir = r->second.is_dir;
++r;
}
else if (r == merged.states->end())
{
- from = get_full_name(l->second);
+ pres = l->second.current_names();
+ I(pres.size() == 1);
+ pre = *pres.begin();
+ if (pre != empty)
+ from = get_full_name(pre);
from_is_dir = l->second.is_dir;
++l;
}
else if (l->first > r->first)
{
- to = merged.get_full_name(r->second);
+ posts = r->second.current_names();
+ I(posts.size() == 1);
+ post = *posts.begin();
+ if (post != empty)
+ to = merged.get_full_name(post);
to_is_dir = r->second.is_dir;
++r;
}
else if (r->first > l->first)
{
- from = get_full_name(l->second);
+ pres = l->second.current_names();
+ I(pres.size() == 1);
+ pre = *pres.begin();
+ if (pre != empty)
+ from = get_full_name(pre);
from_is_dir = l->second.is_dir;
++l;
}
else
{
- from = get_full_name(l->second);
+ posts = r->second.current_names();
+ I(posts.size() == 1);
+ post = *posts.begin();
+ if (post != empty)
+ to = merged.get_full_name(post);
+ pres = l->second.current_names();
+ I(pres.size() == 1);
+ pre = *pres.begin();
+ if (pre != empty)
+ from = get_full_name(pre);
from_is_dir = l->second.is_dir;
- to = merged.get_full_name(r->second);
to_is_dir = r->second.is_dir;
++l, ++r;
}
- if (to == from)
+ if (pre == post)
continue;
else if (to == file_path())
{
+ I(!(from == file_path()));
if (from_is_dir)
changes.deleted_dirs.insert(from);
else
@@ -1513,6 +1582,7 @@
}
else if (from == file_path())
{
+ I(!(to == file_path()));
if (to_is_dir)
;
else
@@ -1520,6 +1590,7 @@
}
else
{
+ I(!(from == file_path()));
if (from_is_dir)
changes.renamed_dirs.insert(make_pair(from, to));
else
@@ -1552,7 +1623,8 @@
}
typedef int fpid;
interner cit;
- map names;
+ std::map names;
+ typedef std::pair::iterator, bool> nir;
int lastlevel = 0;
for (std::multimap >::const_iterator
i = sorted.begin(); i != sorted.end(); ++i)
@@ -1576,7 +1648,12 @@
continue;// not reached, or not resolved
resolved.insert(j->first);
fpid f(cit.intern(fp()));
- names.insert(make_pair(f, j->first));
+ nir r = names.insert(make_pair(f, j->first));
+ if (r.first->second != j->first)
+ {
+ W(F("Suturing files %1%") % fp);
+ merged.add_suture(r.first->second, j->first);
+ }
}
}
++lastlevel;
@@ -1620,9 +1697,34 @@
I(j != merged.states->end());
j->second = item_status(j->second.rename(merged.itx->intern(revision),
k->second, name));
- cit.intern(fp());
+ fpid f(cit.intern(fp()));
+ nir r = names.insert(make_pair(f, j->first));
+ if (r.first->second != j->first)
+ {
+ W(F("Suturing files %1%") % fp);
+ merged.add_suture(r.first->second, j->first);
+ }
}
}
+ // nearly a c&p from if (i->first > lastlevel)
+ for (std::map::const_iterator
+ j = merged.states->begin(); j != merged.states->end(); ++j)
+ {
+ if (resolved.find(j->first) == resolved.end())
+ {
+ file_path fp(merged.get_full_name(j->second));
+ resolved.insert(j->first);
+ fpid f(cit.intern(fp()));
+ nir r = names.insert(make_pair(f, j->first));
+ if (r.first->second != j->first)
+ {
+ W(F("Suturing items %1% and %2% over %3%")
+ % r.first->second % j->first % fp);
+ merged.add_suture(r.first->second, j->first);
+ }
+ }
+ }
+ merged.apply_sutures();
return merged;
}
========================================================================
--- pcdv.hh 42ce2c9da4c7a1e77b1200885b6d3fc579592c69
+++ pcdv.hh 7ba58f71a35e6f8e212bc926d0ec2f15d00c2dd6
@@ -254,7 +254,7 @@
tree_state new_skel() const;
void add_suture(item_id l, item_id r);
- void apply_sutures();
+ void apply_sutures() const;
public:
~tree_state();
@@ -276,6 +276,8 @@
std::vector >
current() const;
+ std::vector >
+ current_with_dirs() const;
// get the changes along edge this->merged for merged=merge(revs)
// note that revs should include *this
========================================================================
--- sanity.cc 36ad241e17f12b3d4e08f78ba1f302bb76523a76
+++ sanity.cc ffb40b74ba38772ebf90bf7bc0f7ac710933a338
@@ -253,19 +253,21 @@
for (std::vector::const_iterator
i = musings.begin(); i != musings.end(); ++i)
{
+ std::string tmp;
try
{
- std::string tmp;
(*i)->gasp(tmp);
out << tmp;
}
catch (logic_error)
{
+ out << tmp;
out << "\n";
L(F("ignoring error trigged by saving work set to debug log"));
}
catch (informative_failure)
{
+ out << tmp;
out << "\n";
L(F("ignoring error trigged by saving work set to debug log"));
}
========================================================================
--- tests/t_merge_add_del.at 20f850e8ede0f7c4240c1f9cb21855f151f89df2
+++ tests/t_merge_add_del.at 7abec2ef42ef3e1ae12434eb8fea72855ae3781e
@@ -1,10 +1,7 @@
# -*- Autoconf -*-
AT_SETUP([(imp) merging with ])
-# This test is a bug report.
-AT_XFAIL_IF(true)
-
MONOTONE_SETUP
# We want a graph which looks like:
========================================================================
--- tests/t_rename_added_in_rename.at 986d6f8c484b4cd73df3e6df7c67ad61f3bd1a2d
+++ tests/t_rename_added_in_rename.at c73d2f1b0a4ba14c9165e2775c5e995a656c951d
@@ -14,7 +14,7 @@
# | \ |
# | merge 1
# | |
-# RENAME_FILE_R | - rename_file foo/a bar/a
+# RENAME_FILE_R | - rename_file foo/a foo/b
# \ |
# \ |
# TEST_R