[PATCH] qpush asserts that patches do not affect unknown files

Chad Skeeters goobsoft at yahoo.com
Wed Sep 26 00:35:45 CDT 2007


# HG changeset patch
# User Chad Skeeters <goobsoft at yahoo.com>
# Date 1190784604 18000
# Node ID 4afd6e3c818a6bd9162057a38d40022e767baf62
# Parent  8d00788ca5785e8144e20b7996f0ee3b374f6d45
qpush asserts that patches do not affect unknown files
* * *

diff -r 8d00788ca578 -r 4afd6e3c818a hgext/mq.py
--- a/hgext/mq.py	Mon Sep 24 12:42:25 2007 -0500
+++ b/hgext/mq.py	Wed Sep 26 00:30:04 2007 -0500
@@ -599,6 +599,23 @@ class queue:
                 else:
                     raise util.Abort(_("local changes found"))
         return m, a, r, d
+
+    def check_unknown(self, repo, patchname, patchdir=None):
+        if not patchdir:
+            patchdir = self.path
+
+        patchpath = os.path.join(patchdir, patchname)
+
+        affectedfiles = patch.getaffected(patchpath, self.ui, strip=1)
+        if len(affectedfiles) == 0:
+            self.ui.warn(_('Could not detect files that will be affected by %s.  Can not assure that files are added and committed.\n') % patchname)
+            # or could force check of all files unless Force is true or something like that...
+
+        for f in affectedfiles:
+            if util.lexists(repo.wjoin(f)):
+                if f not in repo.dirstate:
+                      raise util.Abort(_('Patch %s can not be applied on unknown file %s') % (patchname, f))
+
 
     def new(self, repo, patch, *pats, **opts):
         msg = opts.get('msg')
@@ -781,6 +798,11 @@ class queue:
             else:
                 end = self.series.index(patch, start) + 1
             s = self.series[start:end]
+
+            if not force:
+                for patchname in s:
+                    self.check_unknown(repo, patchname);
+
             all_files = {}
             try:
                 if mergeq:
diff -r 8d00788ca578 -r 4afd6e3c818a mercurial/patch.py
--- a/mercurial/patch.py	Mon Sep 24 12:42:25 2007 -0500
+++ b/mercurial/patch.py	Wed Sep 26 00:30:04 2007 -0500
@@ -496,6 +496,45 @@ class patchfile:
         self.ui.warn(_("Hunk #%d FAILED at %d\n") % (h.number, orig_start))
         self.rej.append(h)
         return -1
+
+def getaffected(patchfilepath, ui, strip=1):
+    lsdiff = ui.config('ui', 'lsdiff')
+    if lsdiff:
+        return externalgetaffected(lsdiff, patchfilepath, strip);
+    else:
+        return internalgetaffected(patchfilepath, strip);
+
+
+def externalgetaffected(lsdiff, patchfilepath, strip=1):
+    fp = os.popen('%s %s' % (lsdiff, util.shellquote(patchfilepath)))
+    files = []
+
+    for line in fp:
+        affectedfile = line.strip()
+        files.append(pathstrip(affectedfile, strip))
+    code = fp.close()
+    if code:
+        raise PatchError(_("lsdiff command failed: %s") %
+                         util.explain_exit(code)[0])
+    return files;
+
+
+def internalgetaffected(patchfilepath, strip=1):
+    files = []
+    orig_pattern = re.compile("^((\\*{3})|(\\-{3}))\\s") # *** or +++
+    new_pattern = re.compile("^((\\-{3})|(\\+{3}))\\s([^\\t]*)")
+    found_orig=False;
+    for line in file(patchfilepath):
+        if not found_orig:
+            matcher = orig_pattern.match(line);
+            if matcher != None:
+                found_orig=True;
+        else:
+            found_orig=False;
+            matcher = new_pattern.match(line);
+            if matcher != None:
+                files.append(pathstrip(matcher.group(4), strip));
+    return files
 
 class hunk:
     def __init__(self, desc, num, lr, context):
@@ -774,24 +813,24 @@ def parsefilename(str):
             return s
     return s[:i]
 
+def pathstrip(path, count=1):
+    pathlen = len(path)
+    i = 0
+    if count == 0:
+        return path.rstrip()
+    while count > 0:
+        i = path.find('/', i)
+        if i == -1:
+            raise PatchError(_("unable to strip away %d dirs from %s") %
+                             (count, path))
+        i += 1
+        # consume '//' in the path
+        while i < pathlen - 1 and path[i] == '/':
+            i += 1
+        count -= 1
+    return path[i:].rstrip()
+
 def selectfile(afile_orig, bfile_orig, hunk, strip, reverse):
-    def pathstrip(path, count=1):
-        pathlen = len(path)
-        i = 0
-        if count == 0:
-            return path.rstrip()
-        while count > 0:
-            i = path.find('/', i)
-            if i == -1:
-                raise PatchError(_("unable to strip away %d dirs from %s") %
-                                 (count, path))
-            i += 1
-            # consume '//' in the path
-            while i < pathlen - 1 and path[i] == '/':
-                i += 1
-            count -= 1
-        return path[i:].rstrip()
-
     nulla = afile_orig == "/dev/null"
     nullb = bfile_orig == "/dev/null"
     afile = pathstrip(afile_orig, strip)
diff -r 8d00788ca578 -r 4afd6e3c818a tests/test-mq-guards.out
--- a/tests/test-mq-guards.out	Mon Sep 24 12:42:25 2007 -0500
+++ b/tests/test-mq-guards.out	Wed Sep 26 00:30:04 2007 -0500
@@ -133,6 +133,7 @@ 1 G b.patch
 1 G b.patch
 2 U c.patch
 3 G d.patch
+Could not detect files that will be affected by d.patch.  Can not assure that files are added and committed.
 applying new.patch
 skipping b.patch - guarded by ['+2']
 applying c.patch
diff -r 8d00788ca578 -r 4afd6e3c818a tests/test-mq-qpush-unknown
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qpush-unknown	Wed Sep 26 00:30:04 2007 -0500
@@ -0,0 +1,187 @@
+#!/bin/bash
+
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
+
+mkdir tmp1
+mkdir tmp1/dir
+mkdir tmp2
+mkdir tmp2/dir
+
+echo hi >> tmp1/foo
+echo hi >> tmp1/foo
+echo hi >> tmp1/foo
+echo hi >> tmp1/foo
+
+echo hi >> tmp1/dir/bar
+echo hi >> tmp1/dir/bar
+echo hi >> tmp1/dir/bar
+echo hi >> tmp1/dir/bar
+
+echo hi >> tmp2/foo
+echo h2 >> tmp2/foo
+echo hi >> tmp2/foo
+echo h4 >> tmp2/foo
+
+echo hi >> tmp2/dir/bar
+echo hi >> tmp2/dir/bar
+echo h3 >> tmp2/dir/bar
+echo hi >> tmp2/dir/bar
+
+diff -uNr tmp1 tmp2 > unified.patch
+diff -eNr tmp1 tmp2 > ed.patch
+diff -nNr tmp1 tmp2 > normal.patch
+diff -cNr tmp1 tmp2 > context.patch
+
+# don't want to require git just to support.  Pregenerated.
+cat > git.patch <<EOF
+diff --git a/dir/bar b/dir/bar
+index af8b2b3..49a5f2f 100644
+--- a/dir/bar
++++ b/dir/bar
+@@ -1,4 +1,4 @@
+ hi
+ hi
+-hi
++h3
+ hi
+diff --git a/foo b/foo
+index af8b2b3..8953a92 100644
+--- a/foo
++++ b/foo
+@@ -1,4 +1,4 @@
+ hi
++h2
+ hi
+-hi
+-hi
++h4
+EOF
+
+echo % qpush unknown correct
+cp -r tmp1 tmp3
+cd tmp3
+hg init
+hg add
+hg commit -m "test"
+hg qinit
+hg qimport ../unified.patch
+hg qpush
+cat foo | grep h2
+cat dir/bar | grep h3
+hg qpop
+cat foo | grep hi | wc -l
+cat dir/bar | grep hi | wc -l
+cd ..
+rm -rf tmp3
+
+echo % qpush unknown correct 2
+cp -r tmp1 tmp3
+cd tmp3
+hg init
+hg add
+hg commit -m "test"
+hg qinit
+hg qimport ../context.patch
+hg qpush
+cat foo | grep h2
+cat dir/bar | grep h3
+hg qpop
+cat foo | grep hi | wc -l
+cat dir/bar | grep hi | wc -l
+cd ..
+rm -rf tmp3
+
+echo % qpush unknown correct 3
+cp -r tmp1 tmp3
+cd tmp3
+hg init
+hg add
+hg commit -m "test"
+hg qinit
+hg qimport ../git.patch
+hg qpush
+cat foo | grep h2
+cat dir/bar | grep h3
+hg qpop
+cat foo | grep hi | wc -l
+cat dir/bar | grep hi | wc -l
+cd ..
+rm -rf tmp3
+
+echo % qpush unknown correct 4 - qpush from sub directory
+cp -r tmp1 tmp3
+cd tmp3
+hg init
+hg add
+hg commit -m "test"
+hg qinit
+hg qimport ../git.patch
+cd dir
+hg qpush
+cd ..
+cat foo | grep h2
+cat dir/bar | grep h3
+hg qpop
+cat foo | grep hi | wc -l
+cat dir/bar | grep hi | wc -l
+cd ..
+rm -rf tmp3
+
+echo % qpush unknown warn
+cp -r tmp1 tmp3
+cd tmp3
+hg init
+hg add
+hg commit -m "test"
+hg qinit
+hg qimport ../ed.patch
+hg qpush
+cd ..
+rm -rf tmp3
+
+echo % qpush unknown warn 2
+cp -r tmp1 tmp3
+cd tmp3
+hg init
+hg add
+hg commit -m "test"
+hg qinit
+hg qimport ../normal.patch
+hg qpush
+cd ..
+rm -rf tmp3
+
+echo % qpush unknown error
+cp -r tmp1 tmp3
+cd tmp3
+hg init
+hg add foo # but not bar
+hg qinit
+hg qimport ../unified.patch
+hg qpush
+cd ..
+rm -rf tmp3
+
+echo % qpush unknown error 2
+cp -r tmp1 tmp3
+cd tmp3
+hg init
+hg add dir/bar # but not foo
+hg qinit
+hg qimport ../context.patch
+hg qpush
+cd ..
+rm -rf tmp3
+
+echo % qpush unknown error 3
+cp -r tmp1 tmp3
+cd tmp3
+hg init
+# add nothing
+hg qinit
+hg qimport ../git.patch
+hg qpush
+cd ..
+rm -rf tmp3
+
diff -r 8d00788ca578 -r 4afd6e3c818a tests/test-mq-qpush-unknown.out
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qpush-unknown.out	Wed Sep 26 00:30:04 2007 -0500
@@ -0,0 +1,61 @@
+% qpush unknown correct
+adding dir/bar
+adding foo
+adding unified.patch to series file
+applying unified.patch
+Now at: unified.patch
+h2
+h3
+Patch queue now empty
+4
+4
+% qpush unknown correct 2
+adding dir/bar
+adding foo
+adding context.patch to series file
+applying context.patch
+Now at: context.patch
+h2
+h3
+Patch queue now empty
+4
+4
+% qpush unknown correct 3
+adding dir/bar
+adding foo
+adding git.patch to series file
+applying git.patch
+Now at: git.patch
+h2
+h3
+Patch queue now empty
+4
+4
+% qpush unknown warn
+adding dir/bar
+adding foo
+adding ed.patch to series file
+Could not detect files that will be affected by ed.patch.  Can not assure that files are added and committed.
+applying ed.patch
+patch failed, unable to continue (try -v)
+patch ed.patch is empty
+Now at: ed.patch
+% qpush unknown warn 2
+adding dir/bar
+adding foo
+adding normal.patch to series file
+Could not detect files that will be affected by normal.patch.  Can not assure that files are added and committed.
+applying normal.patch
+/usr/bin/patch: **** Only garbage was found in the patch input.
+patch failed, unable to continue (try -v)
+patch normal.patch is empty
+Now at: normal.patch
+% qpush unknown error
+adding unified.patch to series file
+abort: local changes found, refresh first
+% qpush unknown error 2
+adding context.patch to series file
+abort: local changes found, refresh first
+% qpush unknown error 3
+adding git.patch to series file
+abort: Patch git.patch can not be applied on unknown file dir/bar
diff -r 8d00788ca578 -r 4afd6e3c818a tests/test-mq.out
--- a/tests/test-mq.out	Mon Sep 24 12:42:25 2007 -0500
+++ b/tests/test-mq.out	Wed Sep 26 00:30:04 2007 -0500
@@ -260,19 +260,10 @@ M a
 M a
 % qpush failure
 Patch queue now empty
-applying foo
-applying bar
-file foo already exists
-1 out of 1 hunk FAILED -- saving rejects to file foo.rej
-patch failed, unable to continue (try -v)
-patch failed, rejects left in working dir
-Errors during apply, please fix and refresh bar
+abort: Patch bar can not be applied on unknown file foo
 ? foo
-? foo.rej
 % mq tags
-0 qparent
-1 qbase foo
-2 qtip bar tip
+abort: unknown revision 'qparent'!
 new file
 
 diff --git a/new b/new
@@ -287,6 +278,7 @@ copy from new
 copy from new
 copy to copy
 Now at: new
+Could not detect files that will be affected by copy.  Can not assure that files are added and committed.
 applying copy
 Now at: copy
 diff --git a/new b/copy
@@ -371,6 +363,7 @@ diff --git a/bucephalus b/bucephalus
 diff --git a/bucephalus b/bucephalus
 % check binary patches can be popped and pushed
 Now at: addalexander
+Could not detect files that will be affected by addbucephalus.  Can not assure that files are added and committed.
 applying addbucephalus
 Now at: addbucephalus
 8ba2a2f3e77b55d03051ff9c24ad65e7  bucephalus
diff -r 8d00788ca578 -r 4afd6e3c818a tests/test-patch-affected
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-patch-affected	Wed Sep 26 00:30:04 2007 -0500
@@ -0,0 +1,81 @@
+#!/bin/bash
+
+mkdir tmp1
+mkdir tmp1/dir
+mkdir tmp2
+mkdir tmp2/dir
+
+echo hi >> tmp1/foo
+echo hi >> tmp1/foo
+echo hi >> tmp1/foo
+echo hi >> tmp1/foo
+
+echo hi >> tmp1/dir/bar
+echo hi >> tmp1/dir/bar
+echo hi >> tmp1/dir/bar
+echo hi >> tmp1/dir/bar
+
+echo hi >> tmp2/foo
+echo h2 >> tmp2/foo
+echo hi >> tmp2/foo
+echo h4 >> tmp2/foo
+
+echo hi >> tmp2/dir/bar
+echo hi >> tmp2/dir/bar
+echo h3 >> tmp2/dir/bar
+echo hi >> tmp2/dir/bar
+
+diff -uNr tmp1 tmp2 > unified.patch
+diff -eNr tmp1 tmp2 > ed.patch
+diff -nNr tmp1 tmp2 > normal.patch
+diff -cNr tmp1 tmp2 > context.patch
+
+# don't want to require git just to support.  Pregenerated.
+cat > git.patch <<EOF
+diff --git a/dir/bar b/dir/bar
+index af8b2b3..49a5f2f 100644
+--- a/dir/bar
++++ b/dir/bar
+@@ -1,4 +1,4 @@
+ hi
+ hi
+-hi
++h3
+ hi
+diff --git a/foo b/foo
+index af8b2b3..8953a92 100644
+--- a/foo
++++ b/foo
+@@ -1,4 +1,4 @@
+ hi
++h2
+ hi
+-hi
+-hi
++h4
+EOF
+
+cat > patch.py <<EOF
+from mercurial import commands, cmdutil, hg, patch, revlog, util
+def printaffected(patchfilepath):
+    files = patch.internalgetaffected(patchfilepath);
+    for f in files:
+        print f;
+
+print("% testing getaffected: unified");
+printaffected("unified.patch");
+
+print("% testing getaffected: ed");
+printaffected("ed.patch");
+
+print("% testing getaffected: normal");
+printaffected("normal.patch");
+
+print("% testing getaffected: context");
+printaffected("context.patch");
+
+print("% testing getaffected: git");
+printaffected("git.patch");
+EOF
+
+python patch.py
diff -r 8d00788ca578 -r 4afd6e3c818a tests/test-patch-affected-external
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-patch-affected-external	Wed Sep 26 00:30:04 2007 -0500
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+echo "[ui]" >> $HGRCPATH
+echo "lsdiff=lsdiff" >> $HGRCPATH
+
+mkdir tmp1
+mkdir tmp1/dir
+mkdir tmp2
+mkdir tmp2/dir
+
+echo hi >> tmp1/foo
+echo hi >> tmp1/foo
+echo hi >> tmp1/foo
+echo hi >> tmp1/foo
+
+echo hi >> tmp1/dir/bar
+echo hi >> tmp1/dir/bar
+echo hi >> tmp1/dir/bar
+echo hi >> tmp1/dir/bar
+
+echo hi >> tmp2/foo
+echo h2 >> tmp2/foo
+echo hi >> tmp2/foo
+echo h4 >> tmp2/foo
+
+echo hi >> tmp2/dir/bar
+echo hi >> tmp2/dir/bar
+echo h3 >> tmp2/dir/bar
+echo hi >> tmp2/dir/bar
+
+diff -cNr tmp1 tmp2 > context.patch
+
+cat > patch.py <<EOF
+from mercurial import commands, cmdutil, hg, patch, revlog, util
+from mercurial import ui as _ui
+
+def printaffected(patchfilepath):
+    u = _ui.ui()
+    files = patch.getaffected(patchfilepath, u)
+    for f in files:
+        print f;
+
+print("% testing getaffected: context");
+printaffected("context.patch");
+EOF
+
+python patch.py
diff -r 8d00788ca578 -r 4afd6e3c818a tests/test-patch-affected-external.out
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-patch-affected-external.out	Wed Sep 26 00:30:04 2007 -0500
@@ -0,0 +1,3 @@
+% testing getaffected: context
+dir/bar
+foo
diff -r 8d00788ca578 -r 4afd6e3c818a tests/test-patch-affected.out
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-patch-affected.out	Wed Sep 26 00:30:04 2007 -0500
@@ -0,0 +1,11 @@
+% testing getaffected: unified
+dir/bar
+foo
+% testing getaffected: ed
+% testing getaffected: normal
+% testing getaffected: context
+dir/bar
+foo
+% testing getaffected: git
+dir/bar
+foo


More information about the Mercurial-devel mailing list