# HG changeset patch # User Robin Farine # Date 1133455715 21600 # Node ID 4bcbc126b80b2a0532751270fc04a01091aa01f3 # Parent 34579a67fa71813c9d58330bc873f51e04dca9da fix rename --after diff -r 34579a67fa71 -r 4bcbc126b80b mercurial/commands.py --- a/mercurial/commands.py Thu Dec 01 10:48:29 2005 -0600 +++ b/mercurial/commands.py Thu Dec 01 10:48:35 2005 -0600 @@ -821,16 +821,18 @@ ui.warn(_('%s: not overwriting - %s collides with %s\n') % (reltarget, abssrc, prevsrc)) return - elif os.path.exists(reltarget): - if opts['force']: - os.unlink(reltarget) - else: + if (not opts['after'] and os.path.exists(reltarget) or + opts['after'] and repo.dirstate.state(abstarget) not in '?r'): + if not opts['force']: ui.warn(_('%s: not overwriting - file exists\n') % reltarget) return - if ui.verbose or not exact: - ui.status(_('copying %s to %s\n') % (relsrc, reltarget)) - if not opts['after']: + if not opts['after']: + os.unlink(reltarget) + if opts['after']: + if not os.path.exists(reltarget): + return + else: targetdir = os.path.dirname(reltarget) or '.' if not os.path.isdir(targetdir): os.makedirs(targetdir) @@ -847,10 +849,64 @@ (relsrc, inst.strerror)) errors += 1 return + if ui.verbose or not exact: + ui.status(_('copying %s to %s\n') % (relsrc, reltarget)) targets[abstarget] = abssrc repo.copy(abssrc, abstarget) copied.append((abssrc, relsrc, exact)) + def targetpathfn(pat, dest, srcs): + if os.path.isdir(pat): + if pat.endswith(os.sep): + pat = pat[:-len(os.sep)] + if destdirexists: + striplen = len(os.path.split(pat)[0]) + else: + striplen = len(pat) + if striplen: + striplen += len(os.sep) + res = lambda p: os.path.join(dest, p[striplen:]) + elif destdirexists: + res = lambda p: os.path.join(dest, os.path.basename(p)) + else: + res = lambda p: dest + return res + + def targetpathafterfn(pat, dest, srcs): + if util.patkind(pat, None)[0]: + # a mercurial pattern + res = lambda p: os.path.join(dest, os.path.basename(p)) + elif len(util.canonpath(repo.root, cwd, pat)) < len(srcs[0][0]): + # A directory. Either the target path contains the last + # component of the source path or it does not. + def evalpath(striplen): + score = 0 + for s in srcs: + t = os.path.join(dest, s[1][striplen:]) + if os.path.exists(t): + score += 1 + return score + + if pat.endswith(os.sep): + pat = pat[:-len(os.sep)] + striplen = len(pat) + len(os.sep) + if os.path.isdir(os.path.join(dest, os.path.split(pat)[1])): + score = evalpath(striplen) + striplen1 = len(os.path.split(pat)[0]) + if striplen1: + striplen1 += len(os.sep) + if evalpath(striplen1) > score: + striplen = striplen1 + res = lambda p: os.path.join(dest, p[striplen:]) + else: + # a file + if destdirexists: + res = lambda p: os.path.join(dest, os.path.basename(p)) + else: + res = lambda p: dest + return res + + pats = list(pats) if not pats: raise util.Abort(_('no source or destination specified')) @@ -858,31 +914,31 @@ raise util.Abort(_('no destination specified')) dest = pats.pop() destdirexists = os.path.isdir(dest) - if (len(pats) > 1 or not os.path.exists(pats[0])) and not destdirexists: + if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists: raise util.Abort(_('with multiple sources, destination must be an ' 'existing directory')) - + if opts['after']: + tfn = targetpathafterfn + else: + tfn = targetpathfn + copylist = [] for pat in pats: - if os.path.isdir(pat): - if destdirexists: - striplen = len(os.path.split(pat)[0]) - else: - striplen = len(pat) - if striplen: - striplen += len(os.sep) - targetpath = lambda p: os.path.join(dest, p[striplen:]) - elif destdirexists: - targetpath = lambda p: os.path.join(dest, os.path.basename(p)) - else: - targetpath = lambda p: dest + srcs = [] for tag, abssrc, relsrc, exact in walk(repo, [pat], opts): if okaytocopy(abssrc, relsrc, exact): - copy(abssrc, relsrc, targetpath(abssrc), exact) + srcs.append((abssrc, relsrc, exact)) + if not srcs: + continue + copylist.append((tfn(pat, dest, srcs), srcs)) + if not copylist: + raise util.Abort(_('no files to copy')) + + for targetpath, srcs in copylist: + for abssrc, relsrc, exact in srcs: + copy(abssrc, relsrc, targetpath(relsrc), exact) if errors: ui.warn(_('(consider using --after)\n')) - if len(copied) == 0: - raise util.Abort(_('no files to copy')) return errors, copied def copy(ui, repo, *pats, **opts): diff -r 34579a67fa71 -r 4bcbc126b80b tests/test-rename --- a/tests/test-rename Thu Dec 01 10:48:29 2005 -0600 +++ b/tests/test-rename Thu Dec 01 10:48:35 2005 -0600 @@ -15,18 +15,56 @@ hg status hg update -C +echo "# rename --after a single file" +mv d1/d11/a1 d2/c +hg rename --after d1/d11/a1 d2/c +hg status +hg update -C + echo "# move a single file to an existing directory" hg rename d1/d11/a1 d2 hg status hg update -C +echo "# move --after a single file to an existing directory" +mv d1/d11/a1 d2 +hg rename --after d1/d11/a1 d2 +hg status +hg update -C + +echo "# rename a file using a relative path" +(cd d1/d11; hg rename ../../d2/b e) +hg status +hg update -C + +echo "# rename --after a file using a relative path" +(cd d1/d11; mv ../../d2/b e; hg rename --after ../../d2/b e) +hg status +hg update -C + echo "# rename directory d1 as d3" -hg rename d1 d3 +hg rename d1/ d3 +hg status +hg update -C + +echo "# rename --after directory d1 as d3" +mv d1 d3 +hg rename --after d1 d3 +hg status +hg update -C + +echo "# move a directory using a relative path" +(cd d2; mkdir d3; hg rename ../d1/d11 d3) +hg status +hg update -C + +echo "# move --after a directory using a relative path" +(cd d2; mkdir d3; mv ../d1/d11 d3; hg rename --after ../d1/d11 d3) hg status hg update -C echo "# move directory d1/d11 to an existing directory d2 (removes empty d1)" -hg rename d1/d11 d2 +hg rename d1/d11/ d2 hg status hg update -C @@ -36,6 +74,13 @@ hg status hg update -C +echo "# move --after directories d1 and d2 to a new directory d3" +mkdir d3 +mv d1 d2 d3 +hg rename --after d1 d2 d3 +hg status +hg update -C + echo "# move everything under directory d1 to existing directory d2, do not" echo "# overwrite existing files (d2/b)" hg rename d1/* d2 @@ -53,6 +98,13 @@ hg status hg update -C +echo "# move --after some files under d1 to d2/d21 (glob)" +mkdir d2/d21 +mv d1/a d1/d11/a1 d2/d21 +hg rename --after 'glob:d1/**' d2/d21 +hg status +hg update -C + echo "# move every file under d1 starting with an 'a' to d2/d21 (regexp)" mkdir d2/d21 hg rename 're:d1/([^a][^/]*/)*a.*' d2/d21 diff -r 34579a67fa71 -r 4bcbc126b80b tests/test-rename.out --- a/tests/test-rename.out Thu Dec 01 10:48:29 2005 -0600 +++ b/tests/test-rename.out Thu Dec 01 10:48:35 2005 -0600 @@ -1,9 +1,21 @@ # rename a single file A d2/c R d1/d11/a1 +# rename --after a single file +A d2/c +R d1/d11/a1 # move a single file to an existing directory A d2/a1 R d1/d11/a1 +# move --after a single file to an existing directory +A d2/a1 +R d1/d11/a1 +# rename a file using a relative path +A d1/d11/e +R d2/b +# rename --after a file using a relative path +A d1/d11/e +R d2/b # rename directory d1 as d3 copying d1/a to d3/a copying d1/b to d3/b @@ -21,6 +33,33 @@ R d1/b R d1/ba R d1/d11/a1 +# rename --after directory d1 as d3 +copying d1/a to d3/a +copying d1/b to d3/b +copying d1/ba to d3/ba +copying d1/d11/a1 to d3/d11/a1 +removing d1/a +removing d1/b +removing d1/ba +removing d1/d11/a1 +A d3/a +A d3/b +A d3/ba +A d3/d11/a1 +R d1/a +R d1/b +R d1/ba +R d1/d11/a1 +# move a directory using a relative path +copying ../d1/d11/a1 to d3/d11/a1 +removing ../d1/d11/a1 +A d2/d3/d11/a1 +R d1/d11/a1 +# move --after a directory using a relative path +copying ../d1/d11/a1 to d3/d11/a1 +removing ../d1/d11/a1 +A d2/d3/d11/a1 +R d1/d11/a1 # move directory d1/d11 to an existing directory d2 (removes empty d1) copying d1/d11/a1 to d2/d11/a1 removing d1/d11/a1 @@ -47,6 +86,27 @@ R d1/ba R d1/d11/a1 R d2/b +# move --after directories d1 and d2 to a new directory d3 +copying d1/a to d3/d1/a +copying d1/b to d3/d1/b +copying d1/ba to d3/d1/ba +copying d1/d11/a1 to d3/d1/d11/a1 +copying d2/b to d3/d2/b +removing d1/a +removing d1/b +removing d1/ba +removing d1/d11/a1 +removing d2/b +A d3/d1/a +A d3/d1/b +A d3/d1/ba +A d3/d1/d11/a1 +A d3/d2/b +R d1/a +R d1/b +R d1/ba +R d1/d11/a1 +R d2/b # move everything under directory d1 to existing directory d2, do not # overwrite existing files (d2/b) d2/b: not overwriting - file exists @@ -82,6 +142,15 @@ R d1/b R d1/ba R d1/d11/a1 +# move --after some files under d1 to d2/d21 (glob) +copying d1/a to d2/d21/a +copying d1/d11/a1 to d2/d21/a1 +removing d1/a +removing d1/d11/a1 +A d2/d21/a +A d2/d21/a1 +R d1/a +R d1/d11/a1 # move every file under d1 starting with an 'a' to d2/d21 (regexp) copying d1/a to d2/d21/a copying d1/d11/a1 to d2/d21/a1 @@ -93,7 +162,6 @@ R d1/d11/a1 # attempt to overwrite an existing file d1/ca: not overwriting - file exists -abort: no files to copy ? d1/ca # forced overwrite of an existing file A d1/ca