changeset 2782:0148869345f7

merge with self.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Fri, 04 Aug 2006 10:38:17 -0700
parents a9fadbef21e9 (current diff) ae726521717c (diff)
children 6b27a7125b67
files
diffstat 4 files changed, 131 insertions(+), 100 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -39,6 +39,16 @@ versionstr = "0.45"
 
 commands.norepo += " qclone qversion"
 
+class StatusEntry:
+    def __init__(self, rev, name=None):
+        if not name:
+            self.rev, self.name = rev.split(':')
+        else:
+            self.rev, self.name = rev, name
+
+    def __str__(self):
+        return self.rev + ':' + self.name
+
 class queue:
     def __init__(self, ui, path, patchdir=None):
         self.basepath = path
@@ -57,10 +67,11 @@ class queue:
 
         if os.path.exists(os.path.join(self.path, self.series_path)):
             self.full_series = self.opener(self.series_path).read().splitlines()
-        self.read_series(self.full_series)
+        self.parse_series()
 
         if os.path.exists(os.path.join(self.path, self.status_path)):
-            self.applied = self.opener(self.status_path).read().splitlines()
+            self.applied = [StatusEntry(l)
+                            for l in self.opener(self.status_path).read().splitlines()]
 
     def find_series(self, patch):
         pre = re.compile("(\s*)([^#]+)")
@@ -75,34 +86,21 @@ class queue:
             index += 1
         return None
 
-    def read_series(self, list):
-        def matcher(list):
-            pre = re.compile("(\s*)([^#]+)")
-            for l in list:
-                m = pre.match(l)
-                if m:
-                    s = m.group(2)
-                    s = s.rstrip()
-                    if len(s) > 0:
-                        yield s
+    def parse_series(self):
         self.series = []
-        self.series = [ x for x in matcher(list) ]
+        for l in self.full_series:
+            s = l.split('#', 1)[0].strip()
+            if s:
+                self.series.append(s)
 
     def save_dirty(self):
-        if self.applied_dirty:
-            if len(self.applied) > 0:
-                nl = "\n"
-            else:
-                nl = ""
-            f = self.opener(self.status_path, "w")
-            f.write("\n".join(self.applied) + nl)
-        if self.series_dirty:
-            if len(self.full_series) > 0:
-                nl = "\n"
-            else:
-                nl = ""
-            f = self.opener(self.series_path, "w")
-            f.write("\n".join(self.full_series) + nl)
+        def write_list(items, path):
+            fp = self.opener(path, 'w')
+            for i in items:
+                print >> fp, i
+            fp.close()
+        if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
+        if self.series_dirty: write_list(self.full_series, self.series_path)
 
     def readheaders(self, patch):
         def eatdiff(lines):
@@ -222,12 +220,10 @@ class queue:
                 return p1
             if len(self.applied) == 0:
                 return None
-            (top, patch) = self.applied[-1].split(':')
-            top = revlog.bin(top)
-            return top
+            return revlog.bin(self.applied[-1].rev)
         pp = repo.changelog.parents(rev)
         if pp[1] != revlog.nullid:
-            arevs = [ x.split(':')[0] for x in self.applied ]
+            arevs = [ x.rev for x in self.applied ]
             p0 = revlog.hex(pp[0])
             p1 = revlog.hex(pp[1])
             if p0 in arevs:
@@ -247,7 +243,7 @@ class queue:
             pname = ".hg.patches.merge.marker"
             n = repo.commit(None, '[mq]: merge marker', user=None, force=1,
                             wlock=wlock)
-            self.applied.append(revlog.hex(n) + ":" + pname)
+            self.applied.append(StatusEntry(revlog.hex(n), pname))
             self.applied_dirty = 1
 
         head = self.qparents(repo)
@@ -265,7 +261,7 @@ class queue:
             rev = revlog.bin(info[1])
             (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock)
             if head:
-                self.applied.append(revlog.hex(head) + ":" + patch)
+                self.applied.append(StatusEntry(revlog.hex(head), patch))
                 self.applied_dirty = 1
             if err:
                 return (err, head)
@@ -364,7 +360,7 @@ class queue:
                 raise util.Abort(_("repo commit failed"))
 
             if update_status:
-                self.applied.append(revlog.hex(n) + ":" + patch)
+                self.applied.append(StatusEntry(revlog.hex(n), patch))
 
             if patcherr:
                 if not patchfound:
@@ -397,13 +393,12 @@ class queue:
                 os.unlink(os.path.join(self.path, patch))
         i = self.find_series(patch)
         del self.full_series[i]
-        self.read_series(self.full_series)
+        self.parse_series()
         self.series_dirty = 1
 
     def check_toppatch(self, repo):
         if len(self.applied) > 0:
-            (top, patch) = self.applied[-1].split(':')
-            top = revlog.bin(top)
+            top = revlog.bin(self.applied[-1].rev)
             pp = repo.dirstate.parents()
             if top not in pp:
                 raise util.Abort(_("queue top not at same revision as working directory"))
@@ -434,8 +429,8 @@ class queue:
         if n == None:
             raise util.Abort(_("repo commit failed"))
         self.full_series[insert:insert] = [patch]
-        self.applied.append(revlog.hex(n) + ":" + patch)
-        self.read_series(self.full_series)
+        self.applied.append(StatusEntry(revlog.hex(n), patch))
+        self.parse_series()
         self.series_dirty = 1
         self.applied_dirty = 1
         p = self.opener(patch, "w")
@@ -600,10 +595,9 @@ class queue:
     def isapplied(self, patch):
         """returns (index, rev, patch)"""
         for i in xrange(len(self.applied)):
-            p = self.applied[i]
-            a = p.split(':')
-            if a[1] == patch:
-                return (i, a[0], a[1])
+            a = self.applied[i]
+            if a.name == patch:
+                return (i, a.rev, a.name)
         return None
 
     # if the exact patch name does not exist, we try a few 
@@ -706,7 +700,7 @@ class queue:
             ret = self.mergepatch(repo, mergeq, s, wlock)
         else:
             ret = self.apply(repo, s, list, wlock=wlock)
-        top = self.applied[-1].split(':')[1]
+        top = self.applied[-1].name
         if ret[0]:
             self.ui.write("Errors during apply, please fix and refresh %s\n" %
                           top)
@@ -743,7 +737,7 @@ class queue:
 
         if not update:
             parents = repo.dirstate.parents()
-            rr = [ revlog.bin(x.split(':')[0]) for x in self.applied ]
+            rr = [ revlog.bin(x.rev) for x in self.applied ]
             for p in parents:
                 if p in rr:
                     self.ui.warn("qpop: forcing dirstate update\n")
@@ -764,7 +758,7 @@ class queue:
             if popi >= end:
                 self.ui.warn("qpop: %s is already at the top\n" % patch)
                 return
-        info = [ popi ] + self.applied[popi].split(':')
+        info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
 
         start = info[0]
         rev = revlog.bin(info[1])
@@ -797,7 +791,7 @@ class queue:
         self.strip(repo, rev, update=False, backup='strip', wlock=wlock)
         del self.applied[start:end]
         if len(self.applied):
-            self.ui.write("Now at: %s\n" % self.applied[-1].split(':')[1])
+            self.ui.write("Now at: %s\n" % self.applied[-1].name)
         else:
             self.ui.write("Patch queue now empty\n")
 
@@ -816,7 +810,7 @@ class queue:
         wlock = repo.wlock()
         self.check_toppatch(repo)
         qp = self.qparents(repo)
-        (top, patch) = self.applied[-1].split(':')
+        (top, patch) = (self.applied[-1].rev, self.applied[-1].name)
         top = revlog.bin(top)
         cparents = repo.changelog.parents(top)
         patchparent = self.qparents(repo, top)
@@ -912,7 +906,7 @@ class queue:
 
             self.strip(repo, top, update=False, backup='strip', wlock=wlock)
             n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock)
-            self.applied[-1] = revlog.hex(n) + ':' + patch
+            self.applied[-1] = StatusEntry(revlog.hex(n), patch)
             self.applied_dirty = 1
         else:
             commands.dodiff(patchf, self.ui, repo, patchparent, None)
@@ -934,10 +928,7 @@ class queue:
             start = self.series_end()
         else:
             start = self.series.index(patch) + 1
-        for p in self.series[start:]:
-            if self.ui.verbose:
-                self.ui.write("%d " % self.series.index(p))
-            self.ui.write("%s\n" % p)
+        return [(i, self.series[i]) for i in xrange(start, len(self.series))]
 
     def qseries(self, repo, missing=None, summary=False):
         start = self.series_end()
@@ -1000,11 +991,11 @@ class queue:
                 qpp = [ hg.bin(x) for x in l ]
             elif datastart != None:
                 l = lines[i].rstrip()
-                index = l.index(':')
-                id = l[:index]
-                file = l[index + 1:]
+                se = StatusEntry(l)
+                id = se.rev
+                file = se.name
                 if id:
-                    applied.append(l)
+                    applied.append(se)
                 series.append(file)
         if datastart == None:
             self.ui.warn("No saved patch data found\n")
@@ -1012,7 +1003,7 @@ class queue:
         self.ui.warn("restoring status: %s\n" % lines[0])
         self.full_series = series
         self.applied = applied
-        self.read_series(self.full_series)
+        self.parse_series()
         self.series_dirty = 1
         self.applied_dirty = 1
         heads = repo.changelog.heads()
@@ -1056,18 +1047,18 @@ class queue:
             pp = r.dirstate.parents()
             msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1]))
         msg += "\n\nPatch Data:\n"
-        text = msg + "\n".join(self.applied) + '\n' + (ar and "\n".join(ar)
+        text = msg + "\n".join(str(self.applied)) + '\n' + (ar and "\n".join(ar)
                                                        + '\n' or "")
         n = repo.commit(None, text, user=None, force=1)
         if not n:
             self.ui.warn("repo commit failed\n")
             return 1
-        self.applied.append(revlog.hex(n) + ":" + '.hg.patches.save.line')
+        self.applied.append(StatusEntry(revlog.hex(n),'.hg.patches.save.line'))
         self.applied_dirty = 1
 
     def full_series_end(self):
         if len(self.applied) > 0:
-            (top, p) = self.applied[-1].split(':')
+            p = self.applied[-1].name
             end = self.find_series(p)
             if end == None:
                 return len(self.full_series)
@@ -1077,7 +1068,7 @@ class queue:
     def series_end(self):
         end = 0
         if len(self.applied) > 0:
-            (top, p) = self.applied[-1].split(':')
+            p = self.applied[-1].name
             try:
                 end = self.series.index(p)
             except ValueError:
@@ -1097,8 +1088,7 @@ class queue:
             self.ui.write("%s\n" % p)
 
     def appliedname(self, index):
-        p = self.applied[index]
-        pname = p.split(':')[1]
+        pname = self.applied[index].name
         if not self.ui.verbose:
             p = pname
         else:
@@ -1159,7 +1149,7 @@ class queue:
                                  % patch)
             index = self.full_series_end() + i
             self.full_series[index:index] = [patch]
-            self.read_series(self.full_series)
+            self.parse_series()
             self.ui.warn("adding %s to series file\n" % patch)
             i += 1
             added.append(patch)
@@ -1186,8 +1176,10 @@ def applied(ui, repo, patch=None, **opts
 
 def unapplied(ui, repo, patch=None, **opts):
     """print the patches not yet applied"""
-    repo.mq.unapplied(repo, patch)
-    return 0
+    for i, p in repo.mq.unapplied(repo, patch):
+        if ui.verbose:
+            ui.write("%d " % i)
+        ui.write("%s\n" % p)
 
 def qimport(ui, repo, *filename, **opts):
     """import a patch"""
@@ -1228,7 +1220,7 @@ def clone(ui, source, dest=None, **opts)
     Source patch repository is looked for in <src>/.hg/patches by
     default.  Use -p <url> to change.
     '''
-    commands.setremoteconfig(**opts)
+    commands.setremoteconfig(ui, opts)
     if dest is None:
         dest = hg.defaultdest(source)
     sr = hg.repository(ui, ui.expandpath(source))
@@ -1236,7 +1228,7 @@ def clone(ui, source, dest=None, **opts)
     if sr.local():
         reposetup(ui, sr)
         if sr.mq.applied:
-            qbase = revlog.bin(sr.mq.applied[0].split(':')[0])
+            qbase = revlog.bin(sr.mq.applied[0].rev)
             if not hg.islocal(dest):
                 destrev = sr.parents(qbase)[0]
     ui.note(_('cloning main repo\n'))
@@ -1297,10 +1289,7 @@ def new(ui, repo, patch, **opts):
 
     -m or -l set the patch header as well as the commit message.
     If neither is specified, the patch header is empty and the
-    commit message is 'New patch: PATCH'
-
-    If -f is specified, the patch will be initialized with any
-    uncommitted changes. Otherwise, if there outsta"""
+    commit message is 'New patch: PATCH'"""
     q = repo.mq
     message=commands.logmessage(**opts)
     q.new(repo, patch, msg=message, force=opts['force'])
@@ -1314,7 +1303,7 @@ def refresh(ui, repo, **opts):
     if opts['edit']:
         if message:
             raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
-        patch = q.applied[-1].split(':')[1]
+        patch = q.applied[-1].name
         (message, comment, user, date, hasdiff) = q.readheaders(patch)
         message = ui.edit('\n'.join(message), user or ui.username())
     q.refresh(repo, msg=message, short=opts['short'])
@@ -1330,7 +1319,13 @@ def diff(ui, repo, *files, **opts):
 def fold(ui, repo, *files, **opts):
     """fold the named patches into the current patch
 
-    Patches must not yet be applied.
+    Patches must not yet be applied. Each patch will be successively
+    applied to the current patch in the order given. If all the
+    patches apply successfully, the current patch will be refreshed
+    with the new cumulative patch, and the folded patches will
+    be deleted. With -f/--force, the folded patch files will
+    be removed afterwards.
+
     The header for each folded patch will be concatenated with
     the current patch header, separated by a line of '* * *'."""
 
@@ -1378,7 +1373,7 @@ def fold(ui, repo, *files, **opts):
     q.refresh(repo, msg=message)
 
     for patch in patches:
-        q.delete(repo, patch)
+        q.delete(repo, patch, force=opts['force'])
 
     q.save_dirty()
 
@@ -1487,12 +1482,12 @@ def rename(ui, repo, patch, name=None, *
         ui.write('Renaming %s to %s\n' % (patch, name))
     i = q.find_series(patch)
     q.full_series[i] = name
-    q.read_series(q.full_series)
+    q.parse_series()
     q.series_dirty = 1
 
     info = q.isapplied(patch)
     if info:
-        q.applied[info[0]] = info[1] + ':' + name
+        q.applied[info[0]] = StatusEntry(info[1], name)
     q.applied_dirty = 1
 
     util.rename(os.path.join(q.path, patch), absdest)
@@ -1573,7 +1568,7 @@ def reposetup(ui, repo):
             if not q.applied:
                 return tagscache
 
-            mqtags = [patch.split(':') for patch in q.applied]
+            mqtags = [(patch.rev, patch.name) for patch in q.applied]
             mqtags.append((mqtags[-1][0], 'qtip'))
             mqtags.append((mqtags[0][0], 'qbase'))
             for patch in mqtags:
@@ -1611,6 +1606,7 @@ cmdtable = {
     'qfold':
         (fold,
          [('e', 'edit', None, _('edit patch header')),
+          ('f', 'force', None, _('delete folded patch files')),
           ('m', 'message', '', _('set patch header to <text>')),
           ('l', 'logfile', '', _('set patch header to contents of <file>'))],
          'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -13,7 +13,8 @@ demandload(globals(), "localrepo bundler
 demandload(globals(), "errno lock os shutil util")
 
 def _local(path):
-    return os.path.isfile(util.drop_scheme('file', path)) and bundlerepo or localrepo
+    return (os.path.isfile(path and util.drop_scheme('file', path)) and
+            bundlerepo or localrepo)
 
 schemes = {
     'bundle': bundlerepo,
--- a/tests/test-import
+++ b/tests/test-import
@@ -1,7 +1,10 @@
 #!/bin/sh
 
 hg init a
+mkdir a/d1
+mkdir a/d1/d2
 echo line 1 > a/a
+echo line 1 > a/d1/d2/a
 hg --cwd a ci -d '0 0' -Ama
 
 echo line 2 >> a/a
@@ -79,3 +82,19 @@ python mkmsg.py | hg --cwd b import -
 hg --cwd b tip | grep second
 rm -rf b
 
+# bug non regression test
+# importing a patch in a subdirectory failed at the commit stage
+echo line 2 >> a/d1/d2/a
+hg --cwd a ci -u someoneelse -d '1 0' -m'subdir change'
+echo % hg import in a subdirectory
+hg clone -r0 a b
+hg --cwd a export tip | sed -e 's/d1\/d2\///' > tip.patch
+pushd b/d1/d2 2>&1 > /dev/null
+hg import  ../../../tip.patch
+popd  2>&1 > /dev/null
+echo "% message should be 'subdir change'"
+hg --cwd b tip | grep 'subdir change'
+echo "% committer should be 'someoneelse'"
+hg --cwd b tip | grep someoneelse
+echo "% should be empty"
+hg --cwd b status
--- a/tests/test-import.out
+++ b/tests/test-import.out
@@ -1,11 +1,12 @@
 adding a
+adding d1/d2/a
 % import exported patch
 requesting all changes
 adding changesets
 adding manifests
 adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+added 1 changesets with 2 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying ../tip.patch
 patching file a
 % message should be same
@@ -17,8 +18,8 @@ requesting all changes
 adding changesets
 adding manifests
 adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+added 1 changesets with 2 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying ../tip.patch
 patching file a
 transaction abort!
@@ -28,8 +29,8 @@ requesting all changes
 adding changesets
 adding manifests
 adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+added 1 changesets with 2 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying ../tip.patch
 patching file a
 % import from stdin
@@ -37,8 +38,8 @@ requesting all changes
 adding changesets
 adding manifests
 adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+added 1 changesets with 2 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying patch from stdin
 patching file a
 % override commit message
@@ -46,8 +47,8 @@ requesting all changes
 adding changesets
 adding manifests
 adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+added 1 changesets with 2 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying patch from stdin
 patching file a
 summary:     override
@@ -56,8 +57,8 @@ requesting all changes
 adding changesets
 adding manifests
 adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+added 1 changesets with 2 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying ../msg.patch
 patching file a
 user:        email patcher
@@ -67,8 +68,8 @@ requesting all changes
 adding changesets
 adding manifests
 adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+added 1 changesets with 2 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying patch from stdin
 patching file a
 % plain diff in email, subject, no message body
@@ -76,8 +77,8 @@ requesting all changes
 adding changesets
 adding manifests
 adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+added 1 changesets with 2 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying patch from stdin
 patching file a
 % plain diff in email, no subject, no message body, should fail
@@ -85,8 +86,8 @@ requesting all changes
 adding changesets
 adding manifests
 adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+added 1 changesets with 2 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying patch from stdin
 patching file a
 transaction abort!
@@ -96,8 +97,22 @@ requesting all changes
 adding changesets
 adding manifests
 adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+added 1 changesets with 2 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying patch from stdin
 patching file a
 summary:     second change
+% hg import in a subdirectory
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 2 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+applying ../../../tip.patch
+patching file a
+% message should be 'subdir change'
+summary:     subdir change
+% committer should be 'someoneelse'
+user:        someoneelse
+% should be empty