diff mercurial/commands.py @ 1565:4bcbc126b80b

fix rename --after
author Robin Farine <robin.farine@terminus.org>
date Thu, 01 Dec 2005 10:48:35 -0600
parents 9c6d0abdb94e
children b4956bbbadc9
line wrap: on
line diff
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -821,16 +821,18 @@ def docopy(ui, repo, pats, opts):
             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 @@ def docopy(ui, repo, pats, opts):
                             (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 @@ def docopy(ui, repo, pats, opts):
         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):