Posted by goobsoft on Sun 21 Oct 07:56 (modification of post by view diff)
report abuse | download | new post
- qpush asserts that patches do not affect unknown files
- * * *
- diff --git a/hgext/mq.py b/hgext/mq.py
- --- a/hgext/mq.py
- +++ b/hgext/mq.py
- -599,6 +599,31 @@ class queue:
- else:
- raise util.Abort(_("local changes found"))
- return m, a, r, d
- +
- + def get_unknown(self, repo, affectedfiles):
- + unknownfiles = set([])
- + for f in affectedfiles:
- + if util.lexists(repo.wjoin(f)):
- + if f not in repo.dirstate:
- + unknownfiles.add(f)
- + return unknownfiles
- +
- + 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:
- + if os.stat(patchpath).st_size > 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...
- +
- + unknownfiles = self.get_unknown(repo, affectedfiles)
- + if len(unknownfiles) > 0:
- + raise util.Abort(_('Patch %s can not be applied. Patch effects unknown files %s') % (patchname, unknownfiles))
- +
- def new(self, repo, patch, *pats, **opts):
- msg = opts.get('msg')
- -781,6 +806,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 --git a/mercurial/patch.py b/mercurial/patch.py
- --- a/mercurial/patch.py
- +++ b/mercurial/patch.py
- -496,6 +496,50 @@ 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 = set()
- + difftag = re.compile("^diff( --?[^\\s]*)* a/.* (b/.*)$") # doesn't handle c-style quotes
- + orig_pattern = re.compile("^((\\*{3})|(\\-{3}))\\s") # *** or +++
- + new_pattern = re.compile("^((\\-{3})|(\\+{3}))\\s([^\\t]*)")
- + found_orig=False;
- + for line in file(patchfilepath):
- + diffmatcher = difftag.match(line)
- + if diffmatcher != None:
- + files.add(pathstrip(diffmatcher.group(2), strip))
- +
- + 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.add(pathstrip(matcher.group(4), strip))
- + return files
- class hunk:
- def __init__(self, desc, num, lr, context):
- -774,24 +818,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 --git a/tests/test-mq-qpush-error b/tests/test-mq-qpush-error
- new file mode 100755
- --- /dev/null
- +++ b/tests/test-mq-qpush-error
- -0,0 +1,21 @@
- +#!/bin/bash
- +
- +echo "[extensions]" >> $HGRCPATH
- +echo "mq=" >> $HGRCPATH
- +
- +mkdir tmp1
- +mkdir tmp2
- +
- +echo hi >> tmp1/foo
- +echo h2 >> tmp2/foo
- +
- +diff -uNr tmp1 tmp2 > unified.patch
- +
- +cd tmp1
- +hg init
- +hg qinit
- +hg qimport ../unified.patch
- +hg qpush
- +hg qpop
- +#ls: foo: No such file or directory
- +ls -1 foo
- diff --git a/tests/test-mq-qpush-error.out b/tests/test-mq-qpush-error.out
- new file mode 100644
- --- /dev/null
- +++ b/tests/test-mq-qpush-error.out
- -0,0 +1,4 @@
- +adding unified.patch to series file
- +abort: Patch unified.patch can not be applied. Patch effects unknown files set(['foo'])
- +no patches applied
- +foo
- diff --git a/tests/test-mq-qpush-unknown b/tests/test-mq-qpush-unknown
- new file mode 100755
- --- /dev/null
- +++ b/tests/test-mq-qpush-unknown
- -0,0 +1,229 @@
- +#!/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
- +
- +
- +echo % create bgit.patch
- +
- +cp -rp tmp1 tmp3
- +cd tmp3
- +hg init
- +hg qinit
- +hg qnew binary
- +
- +cat > writebin.py <<EOF
- +import sys
- +open('binaryfile', 'wb').write('BIN\x00ARY')
- +EOF
- +python writebin.py
- +hg add binaryfile
- +hg qref --git
- +cp .hg/patches/binary ../bgit.patch
- +cd ..
- +rm -r tmp3
- +
- +echo % bgit.patch works
- +
- +cp -rp tmp1 tmp3
- +cd tmp3
- +hg init
- +hg qinit
- +hg qimport ../bgit.patch
- +hg qpush
- +cd ..
- +rm -rf tmp3
- +
- +echo % bgit.patch unknown
- +
- +cp -rp tmp1 tmp3
- +cd tmp3
- +hg init
- +hg qinit
- +echo hi > binaryfile
- +hg qimport ../bgit.patch
- +hg qpush
- +cd ..
- +rm -rf tmp3
- diff --git a/tests/test-mq-qpush-unknown.out b/tests/test-mq-qpush-unknown.out
- new file mode 100644
- --- /dev/null
- +++ b/tests/test-mq-qpush-unknown.out
- -0,0 +1,80 @@
- +% 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 correct 4 - qpush from sub directory
- +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. Patch effects unknown files set(['dir/bar', 'foo'])
- +% create bgit.patch
- +% bgit.patch works
- +adding bgit.patch to series file
- +applying bgit.patch
- +Now at: bgit.patch
- +% bgit.patch unknown
- +adding bgit.patch to series file
- +abort: Patch bgit.patch can not be applied. Patch effects unknown files set(['binaryfile'])
- diff --git a/tests/test-mq.out b/tests/test-mq.out
- --- a/tests/test-mq.out
- +++ b/tests/test-mq.out
- -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. Patch effects unknown files set(['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
- diff --git a/tests/test-patch-affected b/tests/test-patch-affected
- new file mode 100755
- --- /dev/null
- +++ b/tests/test-patch-affected
- -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 --git a/tests/test-patch-affected-external b/tests/test-patch-affected-external
- new file mode 100755
- --- /dev/null
- +++ b/tests/test-patch-affected-external
- -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 --git a/tests/test-patch-affected-external.out b/tests/test-patch-affected-external.out
- new file mode 100644
- --- /dev/null
- +++ b/tests/test-patch-affected-external.out
- -0,0 +1,3 @@
- +% testing getaffected: context
- +dir/bar
- +foo
- diff --git a/tests/test-patch-affected.out b/tests/test-patch-affected.out
- new file mode 100644
- --- /dev/null
- +++ b/tests/test-patch-affected.out
- -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
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.