changeset 10368:f05e0d54f424

Merge with crew-stable
author Patrick Mezard <pmezard@gmail.com>
date Sun, 07 Feb 2010 14:43:21 +0100
parents d757bc0c7865 (current diff) b8801b58bbd8 (diff)
children 98a0421b9e52
files hgext/mq.py tests/test-mq-qrefresh tests/test-mq.out
diffstat 4 files changed, 181 insertions(+), 169 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/mq.py	Sun Feb 07 14:29:07 2010 +0100
+++ b/hgext/mq.py	Sun Feb 07 14:43:21 2010 +0100
@@ -1208,12 +1208,14 @@
         if newdate:
             newdate = '%d %d' % util.parsedate(newdate)
         wlock = repo.wlock()
+
         try:
             self.check_toppatch(repo)
             (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
             top = bin(top)
             if repo.changelog.heads(top) != [top]:
                 raise util.Abort(_("cannot refresh a revision with children"))
+
             cparents = repo.changelog.parents(top)
             patchparent = self.qparents(repo, top)
             ph = patchheader(self.join(patchfn))
@@ -1232,173 +1234,148 @@
             if comments:
                 patchf.write(comments)
 
-            tip = repo.changelog.tip()
-            if top == tip:
-                # if the top of our patch queue is also the tip, there is an
-                # optimization here.  We update the dirstate in place and strip
-                # off the tip commit.  Then just commit the current directory
-                # tree.  We can also send repo.commit the list of files
-                # changed to speed up the diff
-                #
-                # in short mode, we only diff the files included in the
-                # patch already plus specified files
-                #
-                # this should really read:
-                #   mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4]
-                # but we do it backwards to take advantage of manifest/chlog
-                # caching against the next repo.status call
-                #
-                mm, aa, dd, aa2 = repo.status(patchparent, tip)[:4]
-                changes = repo.changelog.read(tip)
-                man = repo.manifest.read(changes[0])
-                aaa = aa[:]
-                matchfn = cmdutil.match(repo, pats, opts)
-                if opts.get('short'):
-                    # if amending a patch, we start with existing
-                    # files plus specified files - unfiltered
-                    match = cmdutil.matchfiles(repo, mm + aa + dd + matchfn.files())
-                    # filter with inc/exl options
-                    matchfn = cmdutil.match(repo, opts=opts)
-                else:
-                    match = cmdutil.matchall(repo)
-                m, a, r, d = repo.status(match=match)[:4]
+            # update the dirstate in place, strip off the qtip commit
+            # and then commit.
+            #
+            # this should really read:
+            #   mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4]
+            # but we do it backwards to take advantage of manifest/chlog
+            # caching against the next repo.status call
+            mm, aa, dd, aa2 = repo.status(patchparent, top)[:4]
+            changes = repo.changelog.read(top)
+            man = repo.manifest.read(changes[0])
+            aaa = aa[:]
+            matchfn = cmdutil.match(repo, pats, opts)
+            # in short mode, we only diff the files included in the
+            # patch already plus specified files
+            if opts.get('short'):
+                # if amending a patch, we start with existing
+                # files plus specified files - unfiltered
+                match = cmdutil.matchfiles(repo, mm + aa + dd + matchfn.files())
+                # filter with inc/exl options
+                matchfn = cmdutil.match(repo, opts=opts)
+            else:
+                match = cmdutil.matchall(repo)
+            m, a, r, d = repo.status(match=match)[:4]
 
-                # we might end up with files that were added between
-                # tip and the dirstate parent, but then changed in the
-                # local dirstate. in this case, we want them to only
-                # show up in the added section
-                for x in m:
-                    if x not in aa:
-                        mm.append(x)
-                # we might end up with files added by the local dirstate that
-                # were deleted by the patch.  In this case, they should only
-                # show up in the changed section.
-                for x in a:
-                    if x in dd:
-                        del dd[dd.index(x)]
-                        mm.append(x)
-                    else:
-                        aa.append(x)
-                # make sure any files deleted in the local dirstate
-                # are not in the add or change column of the patch
-                forget = []
-                for x in d + r:
-                    if x in aa:
-                        del aa[aa.index(x)]
-                        forget.append(x)
-                        continue
-                    elif x in mm:
-                        del mm[mm.index(x)]
-                    dd.append(x)
+            # we might end up with files that were added between
+            # qtip and the dirstate parent, but then changed in the
+            # local dirstate. in this case, we want them to only
+            # show up in the added section
+            for x in m:
+                if x not in aa:
+                    mm.append(x)
+            # we might end up with files added by the local dirstate that
+            # were deleted by the patch.  In this case, they should only
+            # show up in the changed section.
+            for x in a:
+                if x in dd:
+                    del dd[dd.index(x)]
+                    mm.append(x)
+                else:
+                    aa.append(x)
+            # make sure any files deleted in the local dirstate
+            # are not in the add or change column of the patch
+            forget = []
+            for x in d + r:
+                if x in aa:
+                    del aa[aa.index(x)]
+                    forget.append(x)
+                    continue
+                elif x in mm:
+                    del mm[mm.index(x)]
+                dd.append(x)
 
-                m = list(set(mm))
-                r = list(set(dd))
-                a = list(set(aa))
-                c = [filter(matchfn, l) for l in (m, a, r)]
-                match = cmdutil.matchfiles(repo, set(c[0] + c[1] + c[2]))
-                chunks = patch.diff(repo, patchparent, match=match,
-                                    changes=c, opts=diffopts)
-                for chunk in chunks:
-                    patchf.write(chunk)
+            m = list(set(mm))
+            r = list(set(dd))
+            a = list(set(aa))
+            c = [filter(matchfn, l) for l in (m, a, r)]
+            match = cmdutil.matchfiles(repo, set(c[0] + c[1] + c[2]))
+            chunks = patch.diff(repo, patchparent, match=match,
+                                changes=c, opts=diffopts)
+            for chunk in chunks:
+                patchf.write(chunk)
 
-                try:
-                    if diffopts.git or diffopts.upgrade:
-                        copies = {}
-                        for dst in a:
-                            src = repo.dirstate.copied(dst)
-                            # during qfold, the source file for copies may
-                            # be removed. Treat this as a simple add.
-                            if src is not None and src in repo.dirstate:
-                                copies.setdefault(src, []).append(dst)
-                            repo.dirstate.add(dst)
-                        # remember the copies between patchparent and tip
-                        for dst in aaa:
-                            f = repo.file(dst)
-                            src = f.renamed(man[dst])
-                            if src:
-                                copies.setdefault(src[0], []).extend(
-                                    copies.get(dst, []))
-                                if dst in a:
-                                    copies[src[0]].append(dst)
-                            # we can't copy a file created by the patch itself
-                            if dst in copies:
-                                del copies[dst]
-                        for src, dsts in copies.iteritems():
-                            for dst in dsts:
-                                repo.dirstate.copy(src, dst)
-                    else:
-                        for dst in a:
-                            repo.dirstate.add(dst)
-                        # Drop useless copy information
-                        for f in list(repo.dirstate.copies()):
-                            repo.dirstate.copy(None, f)
-                    for f in r:
-                        repo.dirstate.remove(f)
-                    # if the patch excludes a modified file, mark that
-                    # file with mtime=0 so status can see it.
-                    mm = []
-                    for i in xrange(len(m)-1, -1, -1):
-                        if not matchfn(m[i]):
-                            mm.append(m[i])
-                            del m[i]
-                    for f in m:
-                        repo.dirstate.normal(f)
-                    for f in mm:
-                        repo.dirstate.normallookup(f)
-                    for f in forget:
-                        repo.dirstate.forget(f)
+            try:
+                if diffopts.git or diffopts.upgrade:
+                    copies = {}
+                    for dst in a:
+                        src = repo.dirstate.copied(dst)
+                        # during qfold, the source file for copies may
+                        # be removed. Treat this as a simple add.
+                        if src is not None and src in repo.dirstate:
+                            copies.setdefault(src, []).append(dst)
+                        repo.dirstate.add(dst)
+                    # remember the copies between patchparent and qtip
+                    for dst in aaa:
+                        f = repo.file(dst)
+                        src = f.renamed(man[dst])
+                        if src:
+                            copies.setdefault(src[0], []).extend(
+                                copies.get(dst, []))
+                            if dst in a:
+                                copies[src[0]].append(dst)
+                        # we can't copy a file created by the patch itself
+                        if dst in copies:
+                            del copies[dst]
+                    for src, dsts in copies.iteritems():
+                        for dst in dsts:
+                            repo.dirstate.copy(src, dst)
+                else:
+                    for dst in a:
+                        repo.dirstate.add(dst)
+                    # Drop useless copy information
+                    for f in list(repo.dirstate.copies()):
+                        repo.dirstate.copy(None, f)
+                for f in r:
+                    repo.dirstate.remove(f)
+                # if the patch excludes a modified file, mark that
+                # file with mtime=0 so status can see it.
+                mm = []
+                for i in xrange(len(m)-1, -1, -1):
+                    if not matchfn(m[i]):
+                        mm.append(m[i])
+                        del m[i]
+                for f in m:
+                    repo.dirstate.normal(f)
+                for f in mm:
+                    repo.dirstate.normallookup(f)
+                for f in forget:
+                    repo.dirstate.forget(f)
 
-                    if not msg:
-                        if not ph.message:
-                            message = "[mq]: %s\n" % patchfn
-                        else:
-                            message = "\n".join(ph.message)
+                if not msg:
+                    if not ph.message:
+                        message = "[mq]: %s\n" % patchfn
                     else:
-                        message = msg
-
-                    user = ph.user or changes[1]
+                        message = "\n".join(ph.message)
+                else:
+                    message = msg
 
-                    # assumes strip can roll itself back if interrupted
-                    repo.dirstate.setparents(*cparents)
-                    self.applied.pop()
-                    self.applied_dirty = 1
-                    self.strip(repo, top, update=False,
-                               backup='strip')
-                except:
-                    repo.dirstate.invalidate()
-                    raise
+                user = ph.user or changes[1]
 
-                try:
-                    # might be nice to attempt to roll back strip after this
-                    patchf.rename()
-                    n = repo.commit(message, user, ph.date, match=match,
-                                    force=True)
-                    self.applied.append(statusentry(hex(n), patchfn))
-                except:
-                    ctx = repo[cparents[0]]
-                    repo.dirstate.rebuild(ctx.node(), ctx.manifest())
-                    self.save_dirty()
-                    self.ui.warn(_('refresh interrupted while patch was popped! '
-                                   '(revert --all, qpush to recover)\n'))
-                    raise
-            else:
-                self.printdiff(repo, diffopts, patchparent, fp=patchf)
+                # assumes strip can roll itself back if interrupted
+                repo.dirstate.setparents(*cparents)
+                self.applied.pop()
+                self.applied_dirty = 1
+                self.strip(repo, top, update=False,
+                           backup='strip')
+            except:
+                repo.dirstate.invalidate()
+                raise
+
+            try:
+                # might be nice to attempt to roll back strip after this
                 patchf.rename()
-                added = repo.status()[1]
-                for a in added:
-                    f = repo.wjoin(a)
-                    try:
-                        os.unlink(f)
-                    except OSError, e:
-                        if e.errno != errno.ENOENT:
-                            raise
-                    try: os.removedirs(os.path.dirname(f))
-                    except: pass
-                    # forget the file copies in the dirstate
-                    # push should readd the files later on
-                    repo.dirstate.forget(a)
-                self.pop(repo, force=True)
-                self.push(repo, force=True)
+                n = repo.commit(message, user, ph.date, match=match,
+                                force=True)
+                self.applied.append(statusentry(hex(n), patchfn))
+            except:
+                ctx = repo[cparents[0]]
+                repo.dirstate.rebuild(ctx.node(), ctx.manifest())
+                self.save_dirty()
+                self.ui.warn(_('refresh interrupted while patch was popped! '
+                               '(revert --all, qpush to recover)\n'))
+                raise
         finally:
             wlock.release()
             self.removeundo(repo)
--- a/tests/test-mq-qrefresh	Sun Feb 07 14:29:07 2010 +0100
+++ b/tests/test-mq-qrefresh	Sun Feb 07 14:43:21 2010 +0100
@@ -155,6 +155,31 @@
 hg qdiff --nodates
 cd ..
 
+echo '% issue2025: qrefresh does not honor filtering options when tip != qtip'
+hg init repo-2025
+cd repo-2025
+echo a > a
+echo b > b
+hg ci -qAm addab
+echo a >> a
+echo b >> b
+hg qnew -f patch
+hg up -qC 0
+echo c > c
+hg ci -qAm addc
+hg up -qC 1
+echo '% refresh with tip != qtip'
+hg --config diff.nodates=1 qrefresh -I b 2>&1 \
+    | sed 's/saving bundle.*/saving bundle.../g'
+echo '% status after refresh'
+hg st
+echo '% b after refresh'
+cat b
+echo '% patch file after refresh'
+cat .hg/patches/patch
+cd ..
+
+
 echo % issue1441 with git patches
 hg init repo-1441-git
 cd repo-1441-git
--- a/tests/test-mq-qrefresh.out	Sun Feb 07 14:29:07 2010 +0100
+++ b/tests/test-mq-qrefresh.out	Sun Feb 07 14:43:21 2010 +0100
@@ -259,6 +259,26 @@
 +++ b/b
 @@ -0,0 +1,1 @@
 +a
+% issue2025: qrefresh does not honor filtering options when tip != qtip
+% refresh with tip != qtip
+saving bundle...
+adding branch
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+% status after refresh
+M a
+% b after refresh
+b
+b
+% patch file after refresh
+diff -r 1a60229be7ac b
+--- a/b
++++ b/b
+@@ -1,1 +1,2 @@
+ b
++b
 % issue1441 with git patches
 diff --git a/b b/b
 new file mode 100644
--- a/tests/test-mq.out	Sun Feb 07 14:29:07 2010 +0100
+++ b/tests/test-mq.out	Sun Feb 07 14:43:21 2010 +0100
@@ -392,16 +392,11 @@
 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
 created new head
 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
-popping bar
 adding branch
 adding changesets
 adding manifests
 adding file changes
 added 1 changesets with 1 changes to 1 files
-patch queue now empty
-(working directory not at a head)
-applying bar
-now at: bar
 diff --git a/bar b/bar
 new file mode 100644
 --- /dev/null
@@ -427,16 +422,11 @@
 % test file move chains in the slow path
 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
-popping bar
 adding branch
 adding changesets
 adding manifests
 adding file changes
 added 1 changesets with 1 changes to 1 files
-patch queue now empty
-(working directory not at a head)
-applying bar
-now at: bar
 diff --git a/foo b/bleh
 rename from foo
 rename to bleh