# # # patch "tests/renaming_a_directory/__driver__.lua" # from [9fb630300dcc1992c8bff1e2d64aa803938b13d6] # to [0052b354468484c71e79945a96b4544f74c048f2] # # patch "work.cc" # from [6d2883991ffdb93278fcfa329d42c9981bf13a51] # to [567f5fb4ef040c2b1e83352963108e43c0a53aa7] # ============================================================ --- tests/renaming_a_directory/__driver__.lua 9fb630300dcc1992c8bff1e2d64aa803938b13d6 +++ tests/renaming_a_directory/__driver__.lua 0052b354468484c71e79945a96b4544f74c048f2 @@ -1,6 +1,9 @@ +-- Test various rename directory cases mtn_setup() +include ("common/test_utils_inventory.lua") + mkdir("foo") writefile("foo/foo", "foo file") @@ -36,3 +39,25 @@ check(exists("bar/foo")) check(not qgrep("foo/foo", "manifest")) check(exists("bar/bar")) check(exists("bar/foo")) + +-- Now do directory rename in other order; mtn 0.48 got this wrong +rename("bar", "foo") +check(mtn("rename", "--bookkeep-only", "bar", "foo"), 0, false, false) +check(mtn("automate", "inventory", "--no-unknown"), 0, true, false) +parsed = parse_basic_io(readfile("stdout")) + +check_inventory (parsed, 7, +{path = "bar", + old_type = "directory", + new_path = "foo", + fs_type = "none", + status = {"rename_source"}}) + +check_inventory (parsed, 22, +{path = "foo", + new_type = "directory", + old_path = "bar", + fs_type = "directory", + birth = root_r_sha, + status = {"rename_target", "known"}}) + ============================================================ --- work.cc 6d2883991ffdb93278fcfa329d42c9981bf13a51 +++ work.cc 567f5fb4ef040c2b1e83352963108e43c0a53aa7 @@ -1952,7 +1952,7 @@ workspace::perform_rename(database & db, // source does not exist as a file. if (srcs.size() == 1 && !new_roster.has_node(dst)) { - // "rename SRC DST" case + // "rename SRC DST", DST is a file file_path const & src = *srcs.begin(); file_path dpath = dst; @@ -1975,25 +1975,30 @@ workspace::perform_rename(database & db, //all cases. previously, mtn mv fileA dir/ woudl fail if dir/ wasn't //versioned whereas mtn mv fileA dir/fileA would add dir/ if necessary //and then reparent fileA. - if (get_path_status(dst) == path::directory) - dpath = dst / src.basename(); - else - { - //this handles the case where: - // touch foo - // mtn mv foo bar/foo where bar doesn't exist - file_path parent = dst.dirname(); - E(get_path_status(parent) == path::directory, origin::user, - F("destination path's parent directory %s/ doesn't exist") % parent); - } + // + //Note that we checked above that dst is not a directory + //this handles the case where: + // touch foo + // mtn mv foo bar/foo where bar doesn't exist + file_path parent = dst.dirname(); + E(get_path_status(parent) == path::directory, origin::user, + F("destination path's parent directory %s/ doesn't exist") % parent); + renames.insert(make_pair(src, dpath)); add_parent_dirs(db, nis, *this, dpath, new_roster); } } else { - // "rename SRC1 [SRC2 ...] DSTDIR" case + // Either srcs has more than one element, or dst is an existing + // directory (or both). So we have one of: + // + // 1) rename SRC1 [SRC2 ...] DSTDIR + // + // 2) mv foo bar + // mtn mv --bookkeep-only foo bar + E(get_path_status(dst) == path::directory, origin::user, F("destination %s/ is not a directory") % dst); @@ -2007,9 +2012,23 @@ workspace::perform_rename(database & db, F("source file %s is not versioned") % *i); file_path d = dst / i->basename(); - E(!new_roster.has_node(d), origin::user, - F("destination %s already exists in the workspace manifest") % d); + if (bookkeep_only && + srcs.size() == 1 && + get_path_status(*srcs.begin()) == path::directory && + get_path_status(dst) == path::directory) + { + // case 2) + d = dst; + } + else + { + // case 1) + d = dst / i->basename(); + E(!new_roster.has_node(d), origin::user, + F("destination %s already exists in the workspace manifest") % d); + } + if (*i == dst || dst.is_beneath_of(*i)) { W(F("cannot move `%s' to a subdirectory of itself, `%s/%s'")