[PATCH] qpush asserts that patches do not affect unknown files
Matt Mackall
mpm at selenic.com
Thu Oct 25 19:52:21 UTC 2007
Any mq folks have an opinion on this?
On Wed, Sep 26, 2007 at 12:35:45AM -0500, Chad Skeeters wrote:
> # 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
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
--
Mathematics is the supreme nostalgia of our time.
More information about the Mercurial-devel
mailing list