--- a/hgext/mq.py Fri Aug 04 10:37:40 2006 -0700
+++ b/hgext/mq.py Fri Aug 04 10:38:17 2006 -0700
@@ -39,6 +39,16 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
% 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 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 @@
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 @@
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 @@
-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 @@
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 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 @@
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 @@
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 @@
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 @@
'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/tests/test-import.out Fri Aug 04 10:37:40 2006 -0700
+++ b/tests/test-import.out Fri Aug 04 10:38:17 2006 -0700
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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