# # patch "cset.cc" # from [f5d04e48a78e2ce897c33801eb55f84c3793da14] # to [8aa6b6df66beb07f9aafed31d8ab01c46b1605bb] # # patch "roster.cc" # from [853c03fd06ccedbfd81897a9350e5b0341ec825c] # to [fb98f2a7eca88938ce25e5ef7b37d4a64341db2b] # # patch "roster_merge.cc" # from [9598a6096285adba63177bcb09b5a27ae6def84d] # to [c79d62667810a48d31eb7c380810621c90731bf6] # # patch "roster_merge.hh" # from [b90caa1f69004ea37e1732462d3284d0bcf15af4] # to [eff5ab8ced6feb7f943b86b425858e4877053ecb] # # patch "vocab.cc" # from [574b8066437cc37ca9cfd7a13763be1a34368900] # to [d465ac7c42bafcb39d03956fc9869b928cae0184] # ======================================================================== --- cset.cc f5d04e48a78e2ce897c33801eb55f84c3793da14 +++ cset.cc 8aa6b6df66beb07f9aafed31d8ab01c46b1605bb @@ -652,6 +652,15 @@ cs.dirs_added.insert(sp); BOOST_CHECK_THROW(cs.apply_to(tree), std::logic_error); } + { + L(F("TEST: can't move a directory underneath itself")); + setup_roster(r, f1, nis); + cset cs; MM(cs); + split_path foo_blah; + file_path_internal("foo/blah").split(foo_blah); + cs.nodes_renamed.insert(std::make_pair(foo, foo_blah)); + BOOST_CHECK_THROW(cs.apply_to(tree), std::logic_error); + } } void ======================================================================== --- roster.cc 853c03fd06ccedbfd81897a9350e5b0341ec825c +++ roster.cc fb98f2a7eca88938ce25e5ef7b37d4a64341db2b @@ -2777,10 +2777,27 @@ } } +static void +check_sane_roster_loop_test() +{ + temp_node_id_source nis; + roster_t r; + split_path root, foo_bar; + file_path().split(root); + file_path_internal("foo/bar").split(foo_bar); + r.attach_node(r.create_dir_node(nis), root); + node_id nid_foo = r.create_dir_node(nis); + node_id nid_bar = r.create_dir_node(nis); + r.attach_node(nid_foo, nid_bar, foo_bar[0]); + r.attach_node(nid_bar, nid_foo, foo_bar[1]); + BOOST_CHECK_THROW(r.check_sane(false), std::logic_error); +} + void add_roster_tests(test_suite * suite) { I(suite); + suite->add(BOOST_TEST_CASE(&check_sane_roster_loop_test)); suite->add(BOOST_TEST_CASE(&check_sane_roster_test)); suite->add(BOOST_TEST_CASE(&automaton_roster_test)); } ======================================================================== --- roster_merge.cc 9598a6096285adba63177bcb09b5a27ae6def84d +++ roster_merge.cc c79d62667810a48d31eb7c380810621c90731bf6 @@ -17,7 +17,8 @@ && file_content_conflicts.empty() && node_attr_conflicts.empty() && orphaned_node_conflicts.empty() - && rename_target_conflicts.empty(); + && rename_target_conflicts.empty() + && directory_loop_conflicts.empty(); } void @@ -28,6 +29,7 @@ node_attr_conflicts.clear(); orphaned_node_conflicts.clear(); rename_target_conflicts.clear(); + directory_loop_conflicts.clear(); roster = roster_t(); } ======================================================================== --- roster_merge.hh b90caa1f69004ea37e1732462d3284d0bcf15af4 +++ roster_merge.hh eff5ab8ced6feb7f943b86b425858e4877053ecb @@ -72,19 +72,30 @@ path_component name; }; -// this is when two (or more, but in fact only two is possible, since we only -// merge two rosters at a time) distinct nodes want to have the same name. -// these nodes always each merged their names cleanly. -// the nodes in the resulting roster are both detached. +// this is when two distinct nodes want to have the same name. these nodes +// always each merged their names cleanly. the nodes in the resulting roster +// are both detached. +// only two nodes are possible, because we +// -- only merge two rosters at a time +// -- merge (parent, basename) as a single scalar. If we merged them +// separately, then it would be possible to have one side of a merge +// rename a bunch of files in different directories to all have the same +// basename, and the other side of the merge to move them all into the +// same directory. +// a clean *-merge of a scalar always takes on the value of one parent or +// another, and the requirement here is that each node have a unique (parent, +// basename) tuple, and since our requirement matches our *-merge scalar, +// we're okay. struct rename_target_conflict { - node_id nid_left, nid_right; + node_id nid1, nid2; std::pair name; }; -// FIXME: +struct directory_loop_conflict +{ +}; - // renaming the root dir (as we currently do _not_) allows: // -- MT in root // -- missing root directory @@ -96,6 +107,7 @@ std::vector node_attr_conflicts; std::vector orphaned_node_conflicts; std::vector rename_target_conflicts; + std::vector directory_loop_conflicts; // this roster is sane if is_clean() returns true roster_t roster; bool is_clean(); ======================================================================== --- vocab.cc 574b8066437cc37ca9cfd7a13763be1a34368900 +++ vocab.cc d465ac7c42bafcb39d03956fc9869b928cae0184 @@ -178,8 +178,8 @@ s((ty ## _tab_active > 0) \ ? (ty ## _tab.unique(str)) \ : str), \ - ok(false) \ -{ verify(*this); } \ + ok(false) \ +{ verify(*this); } \ \ ty::ty(ty const & other) : \ s(other.s), ok(other.ok) \ @@ -196,10 +196,10 @@ void dump(ty const & obj, std::string & out) \ { out = obj(); } \ \ -ty::symtab::symtab() \ -{ ty ## _tab_active++; } \ +ty::symtab::symtab() \ +{ ty ## _tab_active++; } \ \ -ty::symtab::~symtab() \ +ty::symtab::~symtab() \ { \ I(ty ## _tab_active > 0); \ ty ## _tab_active--; \