# # # rename "tests/drop_directory_with_unversioned_files_and_merge" # to "tests/drop_directory_with_unversioned_files_and_update" # # patch "ChangeLog" # from [afbfbc85661520b6b22d180f74da2e477c9fb37a] # to [b63e02837a284eb022570e291c3ee7247d2f975d] # # patch "NEWS" # from [baff89704e514e465db0099404e03457e7127f4f] # to [8fd34a19fa8d27585d5508a17d3e2f2d03c39d94] # # patch "tests/(imp)_deleting_directories/__driver__.lua" # from [1647676a62a47c09d1e343614b53860c7d588516] # to [96f9f09f6c4e825dce31110f6a48e0bce057efd4] # # patch "tests/annotate_file_whose_name_changed/__driver__.lua" # from [64074fdcb65f683224fc430dd43d29d8f7d02fcb] # to [4f44e0851966931403a59662e98a2ffd9aad67a6] # # patch "tests/drop_directory_with_unversioned_files_and_update/__driver__.lua" # from [29d996209b3cce4e53c20a53cc2eddd2db28a0cb] # to [ba27d76247f484248766ddd48db30be4b1728d49] # # patch "tests/merge((),_(add_a,_drop_a,_add_a))/__driver__.lua" # from [bb3d0ebcc57f1b0df75f1c58b0a54912c3f11830] # to [9384feb450710524e13b240b368fd869f8ccfdbd] # # patch "tests/merge((),_(add_a,_patch_a,_drop_a,_add_a))/__driver__.lua" # from [098be15f8560f52b9701864d3e391d7d4af1e4ad] # to [d7995b80865ef73c393105bf48f05333b281b108] # # patch "tests/merging_a_rename_twice/__driver__.lua" # from [2601a6a79dcef1a1c85797637eb853d01d707edf] # to [4159fe861a5be46dc91d37530a0f0e944985750a] # # patch "tests/merging_adds/__driver__.lua" # from [3d022afdda9830918a4f448546bdb059f1b4d570] # to [9abce9450dd3cc918401a508f8079d3871ed6d37] # # patch "tests/renaming_a_deleted_file/__driver__.lua" # from [b175facc6c89c70b26e112229221b03bb68212f3] # to [6ba1866a11f40f2101c2265c3d9f1f792cd40bf2] # # patch "tests/repeatedly_exchanging_work_via_netsync/__driver__.lua" # from [a9af63314fe08c9b5e9d8c77de03640f05eb8c0d] # to [30afb928fece485bc82e5afe9beec62e950d9575] # # patch "tests/schema_migration/__driver__.lua" # from [faccb4ba0fb263719495780b5ea830065edda37c] # to [8ddefe1bfa86d47a1d51574afab8199a4a6f5b07] # # patch "tests/schema_migration_with_rosterify/__driver__.lua" # from [5209ad1cb79394949d465cbda8e22a834f929027] # to [7de4d8c9f78f2f3ac4912b508e6aae17c40ade1b] # # patch "tests/test_a_merge_7/__driver__.lua" # from [fa8de24b1aa6f6e132e8dceaa4b28b9163d0f9dc] # to [7811dc728183fe9b01fc68dcef994e87865d72ea] # # patch "tests/update_clobbers_workspace/__driver__.lua" # from [a8570a30a00c76ab80ea93bf55b6594a7e1bb7f6] # to [404175e5caec0f4c1601ba37ff1ebc04ebf070bf] # # patch "tests/update_does_not_stomp_non-monotone_files/__driver__.lua" # from [998d9d0514ec726e00ecaff6659cf276ae098a36] # to [72480446e72630b71f4fea0d2fc58d043e2cab9a] # # patch "work.cc" # from [0db4f196f31d8c2262a68b0985a1487f48cba55a] # to [1db396707aaa747a4f1e3954951bc5e8212b0bbc] # ============================================================ --- ChangeLog afbfbc85661520b6b22d180f74da2e477c9fb37a +++ ChangeLog b63e02837a284eb022570e291c3ee7247d2f975d @@ -1,3 +1,37 @@ +2007-02-07 Derek Scherger + + * NEWS: add notes about changes to update's behaviour + * tests/(imp)_deleting_directories/__driver__.lua: + * tests/annotate_file_whose_name_changed/__driver__.lua: + * tests/merge((),_(add_a,_drop_a,_add_a))/__driver__.lua: + * tests/merge((),_(add_a,_patch_a,_drop_a,_add_a))/__driver__.lua: + * tests/merging_a_rename_twice/__driver__.lua: + * tests/merging_adds/__driver__.lua: + * tests/renaming_a_deleted_file/__driver__.lua: + * tests/repeatedly_exchanging_work_via_netsync/__driver__.lua: + * tests/schema_migration/__driver__.lua: + * tests/schema_migration_with_rosterify/__driver__.lua: + * tests/test_a_merge_7/__driver__.lua: + add a few "remove" calls so that tests no longer require update to + clobber files + * tests/drop_directory_with_unversioned_files_and_merge: rename to ... + * tests/drop_directory_with_unversioned_files_and_update: ... this + and un-xfail + * tests/update_clobbers_workspace/__driver__.lua: + * tests/update_does_not_stomp_non-monotone_files/__driver__.lua: + adjust/un-xfail to account for update no longer clobbering + unversioned files + * work.cc: + (struct workspace_itemizer): new itemizer that builds a roster + which includes every node in the workspace + (struct simulated_working_tree): new working tree implementation + that update runs against to see if it will encounter any workspace + conflicts + (perform_content_update): use workspace_itemizer to create a + workspace roster and then apply the update cset against this with + simulated_working_tree to see if update will fail on something + obvious + 2007-02-04 Ralf S. Engelschall (via Richard Levitte ) ============================================================ --- NEWS baff89704e514e465db0099404e03457e7127f4f +++ NEWS 8fd34a19fa8d27585d5508a17d3e2f2d03c39d94 @@ -1,5 +1,16 @@ Wed Dec 27 09:57:48 UTC 2006 Wed Dec 27 09:57:48 UTC 2006 + 0.33 release. + + Changes + + - update will fail rather than clobbering unversioned files + that exist in the workspace. + - update will detect directories with unversioned files before + attempting to drop them and will refuse to run rather than + corrupting the workspace. such unversioned files must be + removed manually. + 0.32 release. Changes ============================================================ --- tests/(imp)_deleting_directories/__driver__.lua 1647676a62a47c09d1e343614b53860c7d588516 +++ tests/(imp)_deleting_directories/__driver__.lua 96f9f09f6c4e825dce31110f6a48e0bce057efd4 @@ -23,6 +23,8 @@ revert_to(revs.base) revs.other = base_revision() revert_to(revs.base) +remove("bystander2") +remove("rename-out") -- update doesn't remove files... remove("groundzero/rename-in") ============================================================ --- tests/annotate_file_whose_name_changed/__driver__.lua 64074fdcb65f683224fc430dd43d29d8f7d02fcb +++ tests/annotate_file_whose_name_changed/__driver__.lua 4f44e0851966931403a59662e98a2ffd9aad67a6 @@ -15,6 +15,8 @@ revert_to(revs.base) revs.left = base_revision() revert_to(revs.base) +remove("junk") + copy("foo.rightnewname", "foo") check(mtn("rename", "-e", "foo", "foo.new"), 0, false, false) commit() ============================================================ --- tests/drop_directory_with_unversioned_files_and_update/__driver__.lua 29d996209b3cce4e53c20a53cc2eddd2db28a0cb +++ tests/drop_directory_with_unversioned_files_and_update/__driver__.lua ba27d76247f484248766ddd48db30be4b1728d49 @@ -16,4 +16,4 @@ writefile("subdir/unversioned", "") check(mtn("update", "-r", base0), 0, false, false) writefile("subdir/unversioned", "") +check(mtn("update"), 1, false, false) -xfail(mtn("update"), 0, false, false) ============================================================ --- tests/merge((),_(add_a,_drop_a,_add_a))/__driver__.lua bb3d0ebcc57f1b0df75f1c58b0a54912c3f11830 +++ tests/merge((),_(add_a,_drop_a,_add_a))/__driver__.lua 9384feb450710524e13b240b368fd869f8ccfdbd @@ -21,6 +21,7 @@ revert_to(base) commit() revert_to(base) +remove("testfile") addfile("otherfile", "this space for rent") commit() ============================================================ --- tests/merge((),_(add_a,_patch_a,_drop_a,_add_a))/__driver__.lua 098be15f8560f52b9701864d3e391d7d4af1e4ad +++ tests/merge((),_(add_a,_patch_a,_drop_a,_add_a))/__driver__.lua d7995b80865ef73c393105bf48f05333b281b108 @@ -25,6 +25,7 @@ revert_to(base) commit() revert_to(base) +remove("testfile") addfile("otherfile", "this space for rent") commit() ============================================================ --- tests/merging_a_rename_twice/__driver__.lua 2601a6a79dcef1a1c85797637eb853d01d707edf +++ tests/merging_a_rename_twice/__driver__.lua 4159fe861a5be46dc91d37530a0f0e944985750a @@ -66,6 +66,7 @@ revert_to(revs.g) -- produce state H revert_to(revs.g) +remove("bar") check(mtn("add", "baz"), 0, false, false) commit("branch.y") @@ -76,6 +77,10 @@ revert_to(revs.e) -- produce state J revert_to(revs.e) +remove("foo") +remove("bar") +remove("baz") + check(mtn("add", "quux"), 0, false, false) commit("branch.y") ============================================================ --- tests/merging_adds/__driver__.lua 3d022afdda9830918a4f448546bdb059f1b4d570 +++ tests/merging_adds/__driver__.lua 9abce9450dd3cc918401a508f8079d3871ed6d37 @@ -10,6 +10,7 @@ revert_to(anc) left = base_revision() revert_to(anc) +remove("testfile1") addfile("testfile2", "This is test file 2\n") commit() ============================================================ --- tests/renaming_a_deleted_file/__driver__.lua b175facc6c89c70b26e112229221b03bb68212f3 +++ tests/renaming_a_deleted_file/__driver__.lua 6ba1866a11f40f2101c2265c3d9f1f792cd40bf2 @@ -19,6 +19,7 @@ remove("bar") -- revert to root probe_node("foo", root_r_sha, root_f_sha) remove("bar") +remove("baz") -- make a delete edge on the move preimage check(mtn("drop", "foo"), 0, false, false) ============================================================ --- tests/repeatedly_exchanging_work_via_netsync/__driver__.lua a9af63314fe08c9b5e9d8c77de03640f05eb8c0d +++ tests/repeatedly_exchanging_work_via_netsync/__driver__.lua 30afb928fece485bc82e5afe9beec62e950d9575 @@ -15,6 +15,7 @@ revert_to(ver[0]) ver[1] = base_revision() revert_to(ver[0]) +remove("testfile2") writefile("testfile", "version 1 data") commit("testbranch") ============================================================ --- tests/schema_migration/__driver__.lua faccb4ba0fb263719495780b5ea830065edda37c +++ tests/schema_migration/__driver__.lua 8ddefe1bfa86d47a1d51574afab8199a4a6f5b07 @@ -54,6 +54,7 @@ revert_to(rev) check(mtn("commit", "--branch=testbranch2", "--date=2000-01-01T12:00:00", "--message-file=blah_blah.txt"), 0, false, false) revert_to(rev) +remove("testfile3") writefile("testfile2", "f2v2\n") addfile("testfile4", "f4v1\n") ============================================================ --- tests/schema_migration_with_rosterify/__driver__.lua 5209ad1cb79394949d465cbda8e22a834f929027 +++ tests/schema_migration_with_rosterify/__driver__.lua 7de4d8c9f78f2f3ac4912b508e6aae17c40ade1b @@ -40,6 +40,7 @@ revert_to(rev) check(mtn("commit", "--branch=testbranch2", "--message-file=blah_blah.txt"), 0, false, false) revert_to(rev) +remove("testfile3") writefile("testfile2", "f2v2\n") addfile("testfile4", "f4v1\n") ============================================================ --- tests/test_a_merge_7/__driver__.lua fa8de24b1aa6f6e132e8dceaa4b28b9163d0f9dc +++ tests/test_a_merge_7/__driver__.lua 7811dc728183fe9b01fc68dcef994e87865d72ea @@ -27,6 +27,7 @@ revert_to(revs.a) revs.b = base_revision() revert_to(revs.a) +remove("otherfile1") writefile("testfile", "new stuff") commit() ============================================================ --- tests/update_clobbers_workspace/__driver__.lua a8570a30a00c76ab80ea93bf55b6594a7e1bb7f6 +++ tests/update_clobbers_workspace/__driver__.lua 404175e5caec0f4c1601ba37ff1ebc04ebf070bf @@ -15,12 +15,10 @@ check(indir("test1", mtn("update")), 0, check(indir("test1", mtn("update")), 0, false, true) -- update workspace with an unversioned file blocking a versioned file --- clobbers unversioned file mkdir("test2") writefile("test2/file1", "blocker") check(indir("test2", mtn("checkout", "--revision", base, "."))) -check(indir("test2", mtn("update")), 0, false, true) -check(samefile("file1", "test2/file1")) +check(indir("test2", mtn("update")), 1, false, true) -- update workspace with an unversioned directory blocking a versioned directory mkdir("test3") ============================================================ --- tests/update_does_not_stomp_non-monotone_files/__driver__.lua 998d9d0514ec726e00ecaff6659cf276ae098a36 +++ tests/update_does_not_stomp_non-monotone_files/__driver__.lua 72480446e72630b71f4fea0d2fc58d043e2cab9a @@ -31,5 +31,5 @@ rev = indir("bobwd", {base_revision})[1] rev = indir("bobwd", {base_revision})[1]() -- Alice does her update, discovers foo has been stomped! +check(indir("alicewd", mtn("--branch=testbranch", "--root=.", "update", "--revision", rev)), 1, false, false) +check(samefile("foo.alice", "alicewd/foo")) -check(indir("alicewd", mtn("--branch=testbranch", "--root=.", "update", "--revision", rev)), 0, false, false) -xfail_if(true, samefile("foo.alice", "alicewd/foo")) ============================================================ --- work.cc 0db4f196f31d8c2262a68b0985a1487f48cba55a +++ work.cc 1db396707aaa747a4f1e3954951bc5e8212b0bbc @@ -469,6 +469,38 @@ file_itemizer::visit_file(file_path cons } } + +struct workspace_itemizer : public tree_walker +{ + roster_t & roster; + node_id_source & nis; + + workspace_itemizer(roster_t & r, node_id_source & n) + : roster(r), nis(n) {} + virtual void visit_dir(file_path const & path); + virtual void visit_file(file_path const & path); +}; + +void +workspace_itemizer::visit_dir(file_path const & path) +{ + split_path sp; + path.split(sp); + node_id nid = roster.create_dir_node(nis); + roster.attach_node(nid, sp); +} + +void +workspace_itemizer::visit_file(file_path const & path) +{ + split_path sp; + path.split(sp); + file_id fid; + node_id nid = roster.create_file_node(fid, nis); + roster.attach_node(nid, sp); +} + + class addition_builder : public tree_walker @@ -604,6 +636,40 @@ private: }; +struct simulated_working_tree : public editable_tree +{ + roster_t & roster; + node_id_source & nis; + + path_set blocked_paths; + map nid_map; + int conflicts; + + simulated_working_tree(roster_t & r, temp_node_id_source & n) + : roster(r), nis(n), conflicts(0) {} + + virtual node_id detach_node(split_path const & src); + virtual void drop_detached_node(node_id nid); + + virtual node_id create_dir_node(); + virtual node_id create_file_node(file_id const & content); + virtual void attach_node(node_id nid, split_path const & dst); + + virtual void apply_delta(split_path const & pth, + file_id const & old_id, + file_id const & new_id); + virtual void clear_attr(split_path const & pth, + attr_key const & name); + virtual void set_attr(split_path const & pth, + attr_key const & name, + attr_value const & val); + + virtual void commit(); + + virtual ~simulated_working_tree(); +}; + + struct content_merge_empty_adaptor : public content_merge_adaptor { virtual void get_version(file_path const &, @@ -825,6 +891,103 @@ editable_working_tree::~editable_working { } + +node_id +simulated_working_tree::detach_node(split_path const & src) +{ + node_id nid = roster.detach_node(src); + nid_map.insert(make_pair(nid, src)); + return nid; +} + +void +simulated_working_tree::drop_detached_node(node_id nid) +{ + node_t node = roster.get_node(nid); + if (is_dir_t(node)) + { + dir_t dir = downcast_to_dir_t(node); + if (!dir->children.empty()) + { + map::const_iterator i = nid_map.find(nid); + I(i != nid_map.end()); + split_path path = i->second; + W(F("cannot drop non-empty directory '%s'") % path); + conflicts++; + } + } +} + +node_id +simulated_working_tree::create_dir_node() +{ + return roster.create_dir_node(nis); +} + +node_id +simulated_working_tree::create_file_node(file_id const & content) +{ + return roster.create_file_node(content, nis); +} + +void +simulated_working_tree::attach_node(node_id nid, split_path const & dst) +{ + if (roster.has_node(dst)) + { + W(F("attach blocked by unversioned path '%s'") % dst); + blocked_paths.insert(dst); + conflicts++; + } + else + { + split_path dirname; + path_component basename; + dirname_basename(dst, dirname, basename); + + if (blocked_paths.find(dirname) == blocked_paths.end()) + roster.attach_node(nid, dst); + else + { + W(F("attach blocked by unversioned path '%s'") % dst); + blocked_paths.insert(dst); + } + } +} + +void +simulated_working_tree::apply_delta(split_path const & path, + file_id const & old_id, + file_id const & new_id) +{ + // this may fail if path is not a file but that will be caught + // earlier in update_current_roster_from_filesystem +} + +void +simulated_working_tree::clear_attr(split_path const & pth, + attr_key const & name) +{ +} + +void +simulated_working_tree::set_attr(split_path const & pth, + attr_key const & name, + attr_value const & val) +{ +} + +void +simulated_working_tree::commit() +{ + N(conflicts == 0, F("%d workspace conflicts") % conflicts); +} + +simulated_working_tree::~simulated_working_tree() +{ +} + + }; // anonymous namespace static void @@ -1399,6 +1562,20 @@ workspace::perform_content_update(cset c workspace::perform_content_update(cset const & update, content_merge_adaptor const & ca) { + roster_t roster; + temp_node_id_source nis; + split_path root; + file_path().split(root); + + node_id nid = roster.create_dir_node(nis); + roster.attach_node(nid, root); + + workspace_itemizer itemizer(roster, nis); + walk_tree(file_path(), itemizer); + + simulated_working_tree swt(roster, nis); + update.apply_to(swt); + editable_working_tree ewt(lua, ca); update.apply_to(ewt); }