# # old_revision [b78672c7f625a5875db79b4a27567e751e1103bc] # # patch "cmd_ws_commit.cc" # from [b29545c7fd88a94d14d3b6955505e7e179c70d73] # to [2b4ccaed7ccea9d8cb763bae8c7672cd5b5804ac] # # patch "monotone.texi" # from [15d2c02056078f0291a85fbd817f92f0fd540a3a] # to [9fe7b51e75a4f6cd42e0591fbee0952ee322bc1d] # # patch "tests/rename_file_to_dir/__driver__.lua" # from [f6eee8a739b375232f503815fbd3ab0d12c0d5c0] # to [df79dacc55885c68c5cc4b03686c6093181f2d08] # # patch "tests/ws_ops_with_wrong_node_type/__driver__.lua" # from [2a1b24ab18279249e23f2035f69352b950ba4226] # to [03a8a667a4e0da6917d7f00774021fe19e117207] # # patch "work.cc" # from [d602424dc046f080220d23b5dc663b93b573284a] # to [8ccb08cdc7afd8db1c33770ae69ab827c5a96ce4] # ============================================================ --- cmd_ws_commit.cc b29545c7fd88a94d14d3b6955505e7e179c70d73 +++ cmd_ws_commit.cc 2b4ccaed7ccea9d8cb763bae8c7672cd5b5804ac @@ -444,7 +444,8 @@ CMD(rename, "rename", "mv", CMD_REF(work app.require_workspace(); - file_path dst_path = file_path_external(args.back()); + utf8 dstr = args.back(); + file_path dst_path = file_path_external(dstr); set src_paths; for (size_t i = 0; i < args.size()-1; i++) @@ -452,6 +453,15 @@ CMD(rename, "rename", "mv", CMD_REF(work file_path s = file_path_external(idx(args, i)); src_paths.insert(s); } + + //this catches the case where the user specifies a directory 'by convention' + //that doesn't exist. the code in perform_rename already handles the proper + //cases for more than one source item. + if (src_paths.size() == 1 && dstr()[dstr().size() -1] == '/') + if (get_path_status(*src_paths.begin()) != path::directory) + N(get_path_status(dst_path) == path::directory, + F(_("The specified target directory %s/ doesn't exist.")) % dst_path); + app.work.perform_rename(src_paths, dst_path, app.opts.bookkeep_only); } ============================================================ --- monotone.texi 15d2c02056078f0291a85fbd817f92f0fd540a3a +++ monotone.texi 9fe7b51e75a4f6cd42e0591fbee0952ee322bc1d @@ -4360,7 +4360,11 @@ @section Workspace as addition, removal, or renaming of files. This command also moves any attributes on @var{src} to @var{dst}; see @ref{File Attributes} for more details, and, unless the @option{--bookkeep-only} option is supplied, it -will rename the files immediately in the filesystem. +will rename the files immediately in the filesystem. In the case where address@hidden must be a directory (multiple @var{src} items), exists +physically in the filesystem as a directory or is specified as a +directory by convention (a trailing /), it will be automatically added +to the workspace if it is not already versioned. @item mtn commit @item mtn ci ============================================================ --- tests/rename_file_to_dir/__driver__.lua f6eee8a739b375232f503815fbd3ab0d12c0d5c0 +++ tests/rename_file_to_dir/__driver__.lua df79dacc55885c68c5cc4b03686c6093181f2d08 @@ -1,14 +1,16 @@ mtn_setup() mtn_setup() --- this test is a bug report --- the situation where a file is renamed to a dir should be trapped and --- reported with N(...) or something +-- this used to be a bug report, but the semantics have now been changed such +-- that if dest is a dir and exists (doesn't have to be versioned), then +-- the result of mtn mv file dir is dir/file as it would be with a posix mv(1) +-- the side effect is that dir will be added to the roster as if 'by magic' addfile("file", "file") commit() mkdir("dir") +check(mtn("rename", "--bookkeep-only", "file", "dir"), 0, false, false) +-- status and diff will now complain about missing files +check(mtn("status"), 1, false, false) +check(mtn("diff"), 1, false, false) -check(mtn("rename", "--bookkeep-only", "file", "dir"), 1, false, false) -check(mtn("status"), 0, false, false) -check(mtn("diff"), 0, false, false) ============================================================ --- tests/ws_ops_with_wrong_node_type/__driver__.lua 2a1b24ab18279249e23f2035f69352b950ba4226 +++ tests/ws_ops_with_wrong_node_type/__driver__.lua 03a8a667a4e0da6917d7f00774021fe19e117207 @@ -16,6 +16,10 @@ mkdir("dir2") -- running a recursive add what's supposed to be a file, but is actually a -- dir... mkdir("dir2") +check(mtn("rename", "--bookkeep-only", "file", "dir2"), 0, false, false) +-- should now be already added (this is a soft error now. see stderr to +-- ensure proper response +check(mtn("add", "dir2"), 0, false, true) +check(qgrep("skipping dir2, already accounted for in workspace", "stderr")) +-- should have happened already in the --bookkeep-only version above. +check(mtn("rename", "file", "dir2"), 1, false, false) -check(mtn("rename", "--bookkeep-only", "file", "dir2"), 1, false, false) -check(mtn("add", "dir2"), 0, false, false) -check(mtn("rename", "file", "dir2"), 0, false, false) ============================================================ --- work.cc d602424dc046f080220d23b5dc663b93b573284a +++ work.cc 8ccb08cdc7afd8db1c33770ae69ab827c5a96ce4 @@ -1435,31 +1435,39 @@ workspace::perform_rename(set { // "rename SRC DST" case file_path const & src = *srcs.begin(); + file_path dpath = dst; - N(!directory_exists(dst), - F("destination dir %s/ is not versioned (perhaps add it?)") % dst); - N(!src.empty(), F("cannot rename the workspace root (try '%s pivot_root' instead)") % ui.prog_name); N(new_roster.has_node(src), F("source file %s is not versioned") % src); - renames.insert(make_pair(src, dst)); - add_parent_dirs(dst, new_roster, nis, db, lua); + //this allows the 'magic add' of a non-versioned directory to happen in + //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(); + N(get_path_status(parent) == path::directory, + F("destination path's parent directory %s/ doesn't exist") % parent); + } + + renames.insert(make_pair(src, dpath)); + add_parent_dirs(dpath, new_roster, nis, db, lua); } else { // "rename SRC1 [SRC2 ...] DSTDIR" case - N(new_roster.has_node(dst), - F("destination dir %s/ is not versioned (perhaps add it?)") % dst); + N(get_path_status(dst) == path::directory, + F("destination %s/ is not a directory") % dst); - N(is_dir_t(new_roster.get_node(dst)), - (srcs.size() > 1 - ? F("destination %s is a file, not a directory") - : F("destination %s already exists in the workspace manifest")) - % dst); - for (set::const_iterator i = srcs.begin(); i != srcs.end(); i++) { @@ -1474,6 +1482,8 @@ workspace::perform_rename(set F("destination %s already exists in the workspace manifest") % d); renames.insert(make_pair(*i, d)); + + add_parent_dirs(d, new_roster, nis, db, lua); } }