##// END OF EJS Templates
convert: some tidyups, doc improvements, and test fixes...
convert: some tidyups, doc improvements, and test fixes The various back end options are now documented. The hg source can now be configured not to hand out a revision ID.

File last commit:

r5534:61c230f8 default
r5556:61fdf255 default
Show More
mq.py
2258 lines | 82.1 KiB | text/x-python | PythonLexer
mason@suse.com
Add mq extension
r1808 # queue.py - patch queues for mercurial
#
Vadim Gelfer
update copyrights.
r2859 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
mason@suse.com
Add mq extension
r1808 #
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
Vadim Gelfer
help: add help to mq extension
r2554 '''patch management and development
This extension lets you work with a stack of patches in a Mercurial
repository. It manages two stacks of patches - all known patches, and
applied patches (subset of known patches).
Known patches are represented as patch files in the .hg/patches
directory. Applied patches are both patch files and changesets.
Common tasks (use "hg help command" for more details):
prepare repository to work with patches qinit
create new patch qnew
import existing patch qimport
print patch series qseries
print applied patches qapplied
print name of top applied patch qtop
add known patch to applied stack qpush
remove patch from applied stack qpop
refresh contents of top applied patch qrefresh
'''
Matt Mackall
Simplify i18n imports
r3891 from mercurial.i18n import _
Matt Mackall
strip: move strip code to a new repair module
r4702 from mercurial import commands, cmdutil, hg, patch, revlog, util
from mercurial import repair
Benoit Boissinot
remove various unused import
r3963 import os, sys, re, errno
mason@suse.com
Add mq extension
r1808
Vadim Gelfer
mq: add qclone command
r2720 commands.norepo += " qclone qversion"
Patrick Mezard
Enforce unixish style for all generated patch names....
r4037 # Patch names looks like unix-file names.
# They must be joinable with queue directory and result in the patch path.
normname = util.normpath
Brendan Cully
Make mq camelcase consistent with the rest of hg.
r2818 class statusentry:
Brendan Cully
Use StatusEntry class instead of repeated status line parsing....
r2780 def __init__(self, rev, name=None):
if not name:
Brendan Cully
mq: handle patch names containing ":"
r3091 fields = rev.split(':', 1)
Brendan Cully
Update qsave to use StatusEntry; don't throw exception on bad status lines.
r2816 if len(fields) == 2:
self.rev, self.name = fields
else:
self.rev, self.name = None, None
Brendan Cully
Use StatusEntry class instead of repeated status line parsing....
r2780 else:
self.rev, self.name = rev, name
def __str__(self):
return self.rev + ':' + self.name
mason@suse.com
Add mq extension
r1808 class queue:
def __init__(self, ui, path, patchdir=None):
self.basepath = path
Vadim Gelfer
mq: add join method
r2819 self.path = patchdir or os.path.join(path, "patches")
Thomas Arendsen Hein
Fix mq's usage of opener, which don't allow absolute paths now.
r1852 self.opener = util.opener(self.path)
mason@suse.com
Add mq extension
r1808 self.ui = ui
self.applied = []
self.full_series = []
self.applied_dirty = 0
self.series_dirty = 0
Thomas Arendsen Hein
Fix mq's usage of opener, which don't allow absolute paths now.
r1852 self.series_path = "series"
self.status_path = "status"
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 self.guards_path = "guards"
self.active_guards = None
self.guards_dirty = False
Vadim Gelfer
refactor text diff/patch code....
r2874 self._diffopts = None
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810
Vadim Gelfer
mq: add join method
r2819 if os.path.exists(self.join(self.series_path)):
Thomas Arendsen Hein
Fix mq's usage of opener, which don't allow absolute paths now.
r1852 self.full_series = self.opener(self.series_path).read().splitlines()
Vadim Gelfer
mq: rename read_series as parse_series, make simpler and faster
r2767 self.parse_series()
mason@suse.com
Add mq extension
r1808
Vadim Gelfer
mq: add join method
r2819 if os.path.exists(self.join(self.status_path)):
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 lines = self.opener(self.status_path).read().splitlines()
self.applied = [statusentry(l) for l in lines]
mason@suse.com
Add mq extension
r1808
Vadim Gelfer
refactor text diff/patch code....
r2874 def diffopts(self):
if self._diffopts is None:
Matt Mackall
Move ui.diffopts to patch.diffopts where it belongs
r2888 self._diffopts = patch.diffopts(self.ui)
Vadim Gelfer
refactor text diff/patch code....
r2874 return self._diffopts
Vadim Gelfer
mq: add join method
r2819 def join(self, *p):
return os.path.join(self.path, *p)
mason@suse.com
Add mq extension
r1808 def find_series(self, patch):
pre = re.compile("(\s*)([^#]+)")
index = 0
for l in self.full_series:
m = pre.match(l)
if m:
s = m.group(2)
s = s.rstrip()
if s == patch:
return index
index += 1
return None
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
Vadim Gelfer
mq: rename read_series as parse_series, make simpler and faster
r2767 def parse_series(self):
mason@suse.com
Add mq extension
r1808 self.series = []
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 self.series_guards = []
Vadim Gelfer
mq: rename read_series as parse_series, make simpler and faster
r2767 for l in self.full_series:
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 h = l.find('#')
if h == -1:
patch = l
comment = ''
elif h == 0:
continue
else:
patch = l[:h]
comment = l[h:]
patch = patch.strip()
if patch:
Brendan Cully
mq: bail out if a patch appears more than once in the series file....
r3184 if patch in self.series:
raise util.Abort(_('%s appears more than once in %s') %
(patch, self.join(self.series_path)))
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 self.series.append(patch)
self.series_guards.append(self.guard_re.findall(comment))
def check_guard(self, guard):
bad_chars = '# \t\r\n\f'
first = guard[0]
for c in '-+':
if first == c:
return (_('guard %r starts with invalid character: %r') %
(guard, c))
for c in bad_chars:
if c in guard:
return _('invalid character in guard %r: %r') % (guard, c)
Thomas Arendsen Hein
Whitespace/Tab cleanup
r3223
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 def set_active(self, guards):
for guard in guards:
bad = self.check_guard(guard)
if bad:
raise util.Abort(bad)
guards = dict.fromkeys(guards).keys()
guards.sort()
self.ui.debug('active guards: %s\n' % ' '.join(guards))
self.active_guards = guards
self.guards_dirty = True
def active(self):
if self.active_guards is None:
self.active_guards = []
try:
guards = self.opener(self.guards_path).read().split()
except IOError, err:
if err.errno != errno.ENOENT: raise
guards = []
for i, guard in enumerate(guards):
bad = self.check_guard(guard)
if bad:
self.ui.warn('%s:%d: %s\n' %
(self.join(self.guards_path), i + 1, bad))
else:
self.active_guards.append(guard)
return self.active_guards
def set_guards(self, idx, guards):
for g in guards:
if len(g) < 2:
raise util.Abort(_('guard %r too short') % g)
if g[0] not in '-+':
raise util.Abort(_('guard %r starts with invalid char') % g)
bad = self.check_guard(g[1:])
if bad:
raise util.Abort(bad)
drop = self.guard_re.sub('', self.full_series[idx])
self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
self.parse_series()
self.series_dirty = True
Thomas Arendsen Hein
Whitespace/Tab cleanup
r3223
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 def pushable(self, idx):
if isinstance(idx, str):
idx = self.series.index(idx)
patchguards = self.series_guards[idx]
if not patchguards:
return True, None
default = False
guards = self.active()
exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
if exactneg:
return False, exactneg[0]
pos = [g for g in patchguards if g[0] == '+']
Vadim Gelfer
mq: apply patch is any posative guard matches...
r2850 exactpos = [g for g in pos if g[1:] in guards]
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 if pos:
Vadim Gelfer
mq: apply patch is any posative guard matches...
r2850 if exactpos:
return True, exactpos[0]
return False, pos
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 return True, ''
def explain_pushable(self, idx, all_patches=False):
write = all_patches and self.ui.write or self.ui.warn
if all_patches or self.ui.verbose:
if isinstance(idx, str):
idx = self.series.index(idx)
pushable, why = self.pushable(idx)
if all_patches and pushable:
if why is None:
write(_('allowing %s - no guards in effect\n') %
self.series[idx])
else:
if not why:
write(_('allowing %s - no matching negative guards\n') %
self.series[idx])
else:
write(_('allowing %s - guarded by %r\n') %
(self.series[idx], why))
if not pushable:
Vadim Gelfer
mq: make guards more strict, add tests
r2829 if why:
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 write(_('skipping %s - guarded by %r\n') %
Brendan Cully
mq: fix explain_pushable for negative guards
r3870 (self.series[idx], why))
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 else:
write(_('skipping %s - no matching guards\n') %
self.series[idx])
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810
mason@suse.com
Add mq extension
r1808 def save_dirty(self):
Vadim Gelfer
mq: simplify save_dirty
r2772 def write_list(items, path):
fp = self.opener(path, 'w')
for i in items:
print >> fp, i
fp.close()
Vadim Gelfer
merge with brendan.
r2781 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
Vadim Gelfer
mq: simplify save_dirty
r2772 if self.series_dirty: write_list(self.full_series, self.series_path)
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
mason@suse.com
Add mq extension
r1808
def readheaders(self, patch):
def eatdiff(lines):
while lines:
l = lines[-1]
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 if (l.startswith("diff -") or
l.startswith("Index:") or
l.startswith("===========")):
mason@suse.com
Add mq extension
r1808 del lines[-1]
else:
break
def eatempty(lines):
while lines:
l = lines[-1]
if re.match('\s*$', l):
del lines[-1]
else:
break
Vadim Gelfer
mq: add join method
r2819 pf = self.join(patch)
mason@suse.com
Add mq extension
r1808 message = []
comments = []
user = None
Danek Duvall
Add timestamp field to export format. Make import and mq use it.
r2299 date = None
mason@suse.com
Add mq extension
r1808 format = None
subject = None
diffstart = 0
for line in file(pf):
line = line.rstrip()
Brendan Cully
Teach mq about git patches
r2934 if line.startswith('diff --git'):
diffstart = 2
break
mason@suse.com
Add mq extension
r1808 if diffstart:
if line.startswith('+++ '):
diffstart = 2
break
if line.startswith("--- "):
diffstart = 1
continue
elif format == "hgpatch":
# parse values when importing the result of an hg export
if line.startswith("# User "):
user = line[7:]
Thomas Arendsen Hein
Use "# Date" instead of "# Timestamp" for dated export/import of patches....
r2300 elif line.startswith("# Date "):
date = line[7:]
mason@suse.com
Add mq extension
r1808 elif not line.startswith("# ") and line:
message.append(line)
format = None
elif line == '# HG changeset patch':
format = "hgpatch"
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 elif (format != "tagdone" and (line.startswith("Subject: ") or
line.startswith("subject: "))):
mason@suse.com
Add mq extension
r1808 subject = line[9:]
format = "tag"
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 elif (format != "tagdone" and (line.startswith("From: ") or
line.startswith("from: "))):
mason@suse.com
Add mq extension
r1808 user = line[6:]
format = "tag"
elif format == "tag" and line == "":
# when looking for tags (subject: from: etc) they
# end once you find a blank line in the source
format = "tagdone"
Thomas Arendsen Hein
Strip empty lines and trailing spaces around commit messages....
r2301 elif message or line:
mason@suse.com
Add mq extension
r1808 message.append(line)
comments.append(line)
eatdiff(message)
eatdiff(comments)
eatempty(message)
eatempty(comments)
# make sure message isn't empty
if format and format.startswith("tag") and subject:
message.insert(0, "")
message.insert(0, subject)
Danek Duvall
Add timestamp field to export format. Make import and mq use it.
r2299 return (message, comments, user, date, diffstart > 1)
mason@suse.com
Add mq extension
r1808
Brendan Cully
Remove undo log after mq operations that rollback would break
r4207 def removeundo(self, repo):
undo = repo.sjoin('undo')
if not os.path.exists(undo):
return
try:
os.unlink(undo)
except OSError, inst:
self.ui.warn('error removing undo: %s\n' % str(inst))
Vadim Gelfer
refactor text diff/patch code....
r2874 def printdiff(self, repo, node1, node2=None, files=None,
Brendan Cully
Fix test-mq-qdiff; add -I and -X options to qdiff
r2937 fp=None, changes=None, opts={}):
fns, matchfn, anypats = cmdutil.matchpats(repo, files, opts)
patch.diff(repo, node1, node2, fns, match=matchfn,
Vadim Gelfer
refactor text diff/patch code....
r2874 fp=fp, changes=changes, opts=self.diffopts())
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 def mergeone(self, repo, mergeq, head, patch, rev):
mason@suse.com
Add mq extension
r1808 # first try just applying the patch
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 (err, n) = self.apply(repo, [ patch ], update_status=False,
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 strict=True, merge=rev)
mason@suse.com
Add mq extension
r1808
if err == 0:
return (err, n)
if n is None:
Vadim Gelfer
mq: move many error messages to util.Abort
r2712 raise util.Abort(_("apply failed for patch %s") % patch)
mason@suse.com
Add mq extension
r1808
self.ui.warn("patch didn't work out, merging %s\n" % patch)
# apply failed, strip away that rev and merge.
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 hg.clean(repo, head)
self.strip(repo, n, update=False, backup='strip')
mason@suse.com
Add mq extension
r1808
Benoit Boissinot
mq: use contexts
r3980 ctx = repo.changectx(rev)
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 ret = hg.merge(repo, rev)
mason@suse.com
Add mq extension
r1808 if ret:
Vadim Gelfer
mq: move many error messages to util.Abort
r2712 raise util.Abort(_("update returned %d") % ret)
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 n = repo.commit(None, ctx.description(), ctx.user(), force=1)
mason@suse.com
Add mq extension
r1808 if n == None:
Vadim Gelfer
mq: move many error messages to util.Abort
r2712 raise util.Abort(_("repo commit failed"))
mason@suse.com
Add mq extension
r1808 try:
Danek Duvall
Add timestamp field to export format. Make import and mq use it.
r2299 message, comments, user, date, patchfound = mergeq.readheaders(patch)
mason@suse.com
Add mq extension
r1808 except:
Vadim Gelfer
mq: move many error messages to util.Abort
r2712 raise util.Abort(_("unable to read %s") % patch)
mason@suse.com
Add mq extension
r1808
Thomas Arendsen Hein
Fix mq's usage of opener, which don't allow absolute paths now.
r1852 patchf = self.opener(patch, "w")
mason@suse.com
Add mq extension
r1808 if comments:
comments = "\n".join(comments) + '\n\n'
patchf.write(comments)
Vadim Gelfer
refactor text diff/patch code....
r2874 self.printdiff(repo, head, n, fp=patchf)
mason@suse.com
Add mq extension
r1808 patchf.close()
Brendan Cully
Remove undo log after mq operations that rollback would break
r4207 self.removeundo(repo)
mason@suse.com
Add mq extension
r1808 return (0, n)
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810
mason@suse.com
Add mq extension
r1808 def qparents(self, repo, rev=None):
if rev is None:
(p1, p2) = repo.dirstate.parents()
if p2 == revlog.nullid:
return p1
if len(self.applied) == 0:
return None
Brendan Cully
Use StatusEntry class instead of repeated status line parsing....
r2780 return revlog.bin(self.applied[-1].rev)
mason@suse.com
Add mq extension
r1808 pp = repo.changelog.parents(rev)
if pp[1] != revlog.nullid:
Brendan Cully
Use StatusEntry class instead of repeated status line parsing....
r2780 arevs = [ x.rev for x in self.applied ]
mason@suse.com
Add mq extension
r1808 p0 = revlog.hex(pp[0])
p1 = revlog.hex(pp[1])
if p0 in arevs:
return pp[0]
if p1 in arevs:
return pp[1]
return pp[0]
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 def mergepatch(self, repo, mergeq, series):
mason@suse.com
Add mq extension
r1808 if len(self.applied) == 0:
# each of the patches merged in will have two parents. This
# can confuse the qrefresh, qdiff, and strip code because it
# needs to know which parent is actually in the patch queue.
# so, we insert a merge marker with only one parent. This way
# the first patch in the queue is never a merge patch
#
pname = ".hg.patches.merge.marker"
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 n = repo.commit(None, '[mq]: merge marker', user=None, force=1)
Brendan Cully
Remove undo log after mq operations that rollback would break
r4207 self.removeundo(repo)
Brendan Cully
Make mq camelcase consistent with the rest of hg.
r2818 self.applied.append(statusentry(revlog.hex(n), pname))
mason@suse.com
Add mq extension
r1808 self.applied_dirty = 1
head = self.qparents(repo)
for patch in series:
Chris Mason
mq: patch naming shortcuts...
r2696 patch = mergeq.lookup(patch, strict=True)
mason@suse.com
Add mq extension
r1808 if not patch:
self.ui.warn("patch %s does not exist\n" % patch)
return (1, None)
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 pushable, reason = self.pushable(patch)
if not pushable:
self.explain_pushable(patch, all_patches=True)
continue
mason@suse.com
Add mq extension
r1808 info = mergeq.isapplied(patch)
if not info:
self.ui.warn("patch %s is not applied\n" % patch)
return (1, None)
rev = revlog.bin(info[1])
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 (err, head) = self.mergeone(repo, mergeq, head, patch, rev)
mason@suse.com
Add mq extension
r1808 if head:
Brendan Cully
Make mq camelcase consistent with the rest of hg.
r2818 self.applied.append(statusentry(revlog.hex(head), patch))
mason@suse.com
Add mq extension
r1808 self.applied_dirty = 1
if err:
return (err, head)
Brendan Cully
Make mergepatch save queue now that qpush isn't.
r4437 self.save_dirty()
mason@suse.com
Add mq extension
r1808 return (0, head)
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748 def patch(self, repo, patchfile):
'''Apply patchfile to the working directory.
patchfile: file name of patch'''
Brendan Cully
patch: return list of modified files even when an exception is raised...
r3465 files = {}
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748 try:
Brendan Cully
patch: return list of modified files even when an exception is raised...
r3465 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
files=files)
Brendan Cully
Unify mq and hg patch invocation....
r2919 except Exception, inst:
self.ui.note(str(inst) + '\n')
if not self.ui.verbose:
self.ui.warn("patch failed, unable to continue (try -v)\n")
Brendan Cully
patch: return list of modified files even when an exception is raised...
r3465 return (False, files, False)
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748
Brendan Cully
Teach mq about git patches
r2934 return (True, files, fuzz)
Benoit Boissinot
mq: codingstyle
r2796
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 def apply(self, repo, series, list=False, update_status=True,
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 strict=False, patchdir=None, merge=None, all_files={}):
wlock = lock = tr = None
Bryan O'Sullivan
MQ: tidy up if a qpush is interrupted....
r4418 try:
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 wlock = repo.wlock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 lock = repo.lock()
tr = repo.transaction()
Bryan O'Sullivan
MQ: tidy up if a qpush is interrupted....
r4418 try:
Matt Mackall
transactions: avoid late tear-down (issue641)...
r4970 ret = self._apply(repo, series, list, update_status,
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 strict, patchdir, merge, all_files=all_files)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 tr.close()
self.save_dirty()
return ret
except:
try:
tr.abort()
finally:
repo.invalidate()
repo.dirstate.invalidate()
raise
finally:
Alexis S. L. Carvalho
del transaction before lock before wlock...
r5053 del tr, lock, wlock
Alexis S. L. Carvalho
mq: really remove undo after a qpush (and after a strip)...
r5527 self.removeundo(repo)
Bryan O'Sullivan
MQ: tidy up if a qpush is interrupted....
r4418
Matt Mackall
transactions: avoid late tear-down (issue641)...
r4970 def _apply(self, repo, series, list=False, update_status=True,
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 strict=False, patchdir=None, merge=None, all_files={}):
mason@suse.com
Add mq extension
r1808 # TODO unify with commands.py
if not patchdir:
patchdir = self.path
err = 0
n = None
Brendan Cully
Teach mq about git patches
r2934 for patchname in series:
pushable, reason = self.pushable(patchname)
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 if not pushable:
Brendan Cully
Teach mq about git patches
r2934 self.explain_pushable(patchname, all_patches=True)
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 continue
Brendan Cully
Teach mq about git patches
r2934 self.ui.warn("applying %s\n" % patchname)
pf = os.path.join(patchdir, patchname)
mason@suse.com
Add mq extension
r1808
try:
Brendan Cully
Teach mq about git patches
r2934 message, comments, user, date, patchfound = self.readheaders(patchname)
mason@suse.com
Add mq extension
r1808 except:
Brendan Cully
Teach mq about git patches
r2934 self.ui.warn("Unable to read %s\n" % patchname)
mason@suse.com
Add mq extension
r1808 err = 1
break
if not message:
Brendan Cully
Teach mq about git patches
r2934 message = "imported patch %s\n" % patchname
mason@suse.com
Add mq extension
r1808 else:
if list:
Brendan Cully
Teach mq about git patches
r2934 message.append("\nimported patch %s" % patchname)
mason@suse.com
Add mq extension
r1808 message = '\n'.join(message)
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748 (patcherr, files, fuzz) = self.patch(repo, pf)
Bryan O'Sullivan
MQ: tidy up if a qpush is interrupted....
r4418 all_files.update(files)
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748 patcherr = not patcherr
mason@suse.com
Add mq extension
r1808
Brendan Cully
Teach mq about git patches
r2934 if merge and files:
Alexis S. L. Carvalho
mq: don't abort when merging a patch that removes files
r4332 # Mark as removed/merged and update dirstate parent info
removed = []
merged = []
for f in files:
Matt Mackall
dirstate: make wjoin function private
r4905 if os.path.exists(repo.wjoin(f)):
Alexis S. L. Carvalho
mq: don't abort when merging a patch that removes files
r4332 merged.append(f)
else:
removed.append(f)
Matt Mackall
dirstate: break update into separate functions
r4904 for f in removed:
repo.dirstate.remove(f)
for f in merged:
repo.dirstate.merge(f)
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 p1, p2 = repo.dirstate.parents()
repo.dirstate.setparents(p1, merge)
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 files = patch.updatedir(self.ui, repo, files)
n = repo.commit(files, message, user, date, force=1)
mason@suse.com
Add mq extension
r1808
if n == None:
Vadim Gelfer
mq: move many error messages to util.Abort
r2712 raise util.Abort(_("repo commit failed"))
mason@suse.com
Add mq extension
r1808
if update_status:
Brendan Cully
Teach mq about git patches
r2934 self.applied.append(statusentry(revlog.hex(n), patchname))
mason@suse.com
Add mq extension
r1808
if patcherr:
if not patchfound:
Brendan Cully
Teach mq about git patches
r2934 self.ui.warn("patch %s is empty\n" % patchname)
mason@suse.com
Add mq extension
r1808 err = 0
else:
self.ui.warn("patch failed, rejects left in working dir\n")
err = 1
break
if fuzz and strict:
self.ui.warn("fuzz found when applying patch, stopping\n")
err = 1
break
return (err, n)
Brendan Cully
mq: add qdelete --forget option...
r3088 def delete(self, repo, patches, opts):
Brendan Cully
mq: require patch argument or revision for qdelete
r4736 if not patches and not opts.get('rev'):
Brendan Cully
mq: more qdelete help text tweaks
r4737 raise util.Abort(_('qdelete requires at least one revision or '
'patch name'))
Brendan Cully
mq: require patch argument or revision for qdelete
r4736
Brendan Cully
Allow qdel to delete multiple patches.
r2905 realpatches = []
for patch in patches:
patch = self.lookup(patch, strict=True)
info = self.isapplied(patch)
Brendan Cully
mq: change qdel --forget to --rev; accept any revision symbol
r3373 if info:
Brendan Cully
Allow qdel to delete multiple patches.
r2905 raise util.Abort(_("cannot delete applied patch %s") % patch)
if patch not in self.series:
raise util.Abort(_("patch %s not in series file") % patch)
Brendan Cully
mq: change qdel --forget to --rev; accept any revision symbol
r3373 realpatches.append(patch)
appliedbase = 0
if opts.get('rev'):
if not self.applied:
raise util.Abort(_('no patches applied'))
Thomas Arendsen Hein
Removed unused ui parameter from revpair/revrange and fix its users.
r3707 revs = cmdutil.revrange(repo, opts['rev'])
Brendan Cully
mq: change qdel --forget to --rev; accept any revision symbol
r3373 if len(revs) > 1 and revs[0] > revs[1]:
revs.reverse()
for rev in revs:
if appliedbase >= len(self.applied):
raise util.Abort(_("revision %d is not managed") % rev)
base = revlog.bin(self.applied[appliedbase].rev)
node = repo.changelog.node(rev)
if node != base:
raise util.Abort(_("cannot delete revision %d above "
"applied patches") % rev)
realpatches.append(self.applied[appliedbase].name)
Brendan Cully
mq: add qdelete --forget option...
r3088 appliedbase += 1
Brendan Cully
Allow qdel to delete multiple patches.
r2905
Brendan Cully
mq: add qdelete --forget option...
r3088 if not opts.get('keep'):
Brendan Cully
Add -f option to qdelete, to remove patch file.
r2752 r = self.qrepo()
if r:
Brendan Cully
Allow qdel to delete multiple patches.
r2905 r.remove(realpatches, True)
Brendan Cully
Add -f option to qdelete, to remove patch file.
r2752 else:
Brendan Cully
mq: make qdelete without -k or a subrepository delete all patches
r3375 for p in realpatches:
os.unlink(self.join(p))
Brendan Cully
Allow qdel to delete multiple patches.
r2905
Brendan Cully
mq: change qdel --forget to --rev; accept any revision symbol
r3373 if appliedbase:
Brendan Cully
mq: add qdelete --forget option...
r3088 del self.applied[:appliedbase]
self.applied_dirty = 1
Brendan Cully
Allow qdel to delete multiple patches.
r2905 indices = [self.find_series(p) for p in realpatches]
indices.sort()
for i in indices[-1::-1]:
del self.full_series[i]
Vadim Gelfer
mq: rename read_series as parse_series, make simpler and faster
r2767 self.parse_series()
mason@suse.com
Add mq extension
r1808 self.series_dirty = 1
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810
mason@suse.com
Add mq extension
r1808 def check_toppatch(self, repo):
if len(self.applied) > 0:
Brendan Cully
Use StatusEntry class instead of repeated status line parsing....
r2780 top = revlog.bin(self.applied[-1].rev)
mason@suse.com
Add mq extension
r1808 pp = repo.dirstate.parents()
if top not in pp:
Matt Mackall
mq: clarify queue top message
r5432 raise util.Abort(_("working directory revision is not qtip"))
mason@suse.com
Add mq extension
r1808 return top
return None
Vadim Gelfer
remove localrepository.changes....
r2875 def check_localchanges(self, repo, force=False, refresh=True):
m, a, r, d = repo.status()[:4]
if m or a or r or d:
if not force:
if refresh:
raise util.Abort(_("local changes found, refresh first"))
else:
raise util.Abort(_("local changes found"))
return m, a, r, d
Brendan Cully
mq: support qnew -I/-X and file name lists
r4713
def new(self, repo, patch, *pats, **opts):
msg = opts.get('msg')
force = opts.get('force')
Vadim Gelfer
mq: add join method
r2819 if os.path.exists(self.join(patch)):
Vadim Gelfer
mq: do not allow to qnew a patch twice
r2711 raise util.Abort(_('patch "%s" already exists') % patch)
Brendan Cully
mq: support qnew -I/-X and file name lists
r4713 if opts.get('include') or opts.get('exclude') or pats:
fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
m, a, r, d = repo.status(files=fns, match=match)[:4]
else:
m, a, r, d = self.check_localchanges(repo, force)
Patrick Mezard
mq: avoid qnew committing everything on invalid paths (issue 803)...
r5534 fns, match, anypats = cmdutil.matchpats(repo, m + a + r)
Vadim Gelfer
remove localrepository.changes....
r2875 commitfiles = m + a + r
mason@suse.com
Add mq extension
r1808 self.check_toppatch(repo)
wlock = repo.wlock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
insert = self.full_series_end()
Patrick Mezard
mq: avoid qnew committing everything on invalid paths (issue 803)...
r5534 commitmsg = msg and msg or ("[mq]: %s" % patch)
n = repo.commit(commitfiles, commitmsg, match=match, force=True)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if n == None:
raise util.Abort(_("repo commit failed"))
self.full_series[insert:insert] = [patch]
self.applied.append(statusentry(revlog.hex(n), patch))
self.parse_series()
self.series_dirty = 1
self.applied_dirty = 1
p = self.opener(patch, "w")
if msg:
msg = msg + "\n"
p.write(msg)
p.close()
wlock = None
r = self.qrepo()
if r: r.add([patch])
if commitfiles:
Patrick Mezard
mq: add qnew --git option
r5025 self.refresh(repo, short=True, git=opts.get('git'))
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 self.removeundo(repo)
finally:
del wlock
mason@suse.com
Add mq extension
r1808
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 def strip(self, repo, rev, update=True, backup="all"):
wlock = lock = None
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
mason@suse.com
Add mq extension
r1808 wlock = repo.wlock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 lock = repo.lock()
mason@suse.com
Add mq extension
r1808
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if update:
self.check_localchanges(repo, refresh=False)
urev = self.qparents(repo, rev)
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 hg.clean(repo, urev)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 repo.dirstate.write()
mason@suse.com
Add mq extension
r1808
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 self.removeundo(repo)
repair.strip(self.ui, repo, rev, backup)
Alexis S. L. Carvalho
mq: really remove undo after a qpush (and after a strip)...
r5527 # strip may have unbundled a set of backed up revisions after
# the actual strip
self.removeundo(repo)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 finally:
del lock, wlock
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810
mason@suse.com
Add mq extension
r1808 def isapplied(self, patch):
"""returns (index, rev, patch)"""
for i in xrange(len(self.applied)):
Brendan Cully
Use StatusEntry class instead of repeated status line parsing....
r2780 a = self.applied[i]
if a.name == patch:
return (i, a.rev, a.name)
mason@suse.com
Add mq extension
r1808 return None
Thomas Arendsen Hein
Whitespace/Tab cleanup
r3223 # if the exact patch name does not exist, we try a few
Chris Mason
mq: patch naming shortcuts...
r2696 # variations. If strict is passed, we try only #1
#
# 1) a number to indicate an offset in the series file
# 2) a unique substring of the patch name was given
# 3) patchname[-+]num to indicate an offset in the series file
def lookup(self, patch, strict=False):
Vadim Gelfer
qselect: add --pop, --reapply options
r2844 patch = patch and str(patch)
Chris Mason
mq: patch naming shortcuts...
r2696 def partial_name(s):
if s in self.series:
return s
Vadim Gelfer
mq: print matches if patch name not unique
r2765 matches = [x for x in self.series if s in x]
if len(matches) > 1:
self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
for m in matches:
self.ui.warn(' %s\n' % m)
return None
if matches:
return matches[0]
Chris Mason
mq: patch naming shortcuts...
r2696 if len(self.series) > 0 and len(self.applied) > 0:
if s == 'qtip':
Brendan Cully
mq: fix qheader without args when guards are applied after qtop
r3874 return self.series[self.series_end(True)-1]
Chris Mason
mq: patch naming shortcuts...
r2696 if s == 'qbase':
return self.series[0]
return None
mason@suse.com
Add mq extension
r1808 if patch == None:
return None
Chris Mason
mq: patch naming shortcuts...
r2696
# we don't want to return a partial match until we make
# sure the file name passed in does not exist (checked below)
res = partial_name(patch)
if res and res == patch:
return res
Vadim Gelfer
mq: add join method
r2819 if not os.path.isfile(self.join(patch)):
mason@suse.com
Add mq extension
r1808 try:
sno = int(patch)
except(ValueError, OverflowError):
Chris Mason
mq: patch naming shortcuts...
r2696 pass
else:
if sno < len(self.series):
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 return self.series[sno]
Chris Mason
mq: patch naming shortcuts...
r2696 if not strict:
# return any partial match made above
if res:
return res
Thomas Arendsen Hein
Fixed python2.3 incompatibility (rsplit) in qpush/qpop with index.
r3082 minus = patch.rfind('-')
if minus >= 0:
res = partial_name(patch[:minus])
Chris Mason
mq: patch naming shortcuts...
r2696 if res:
i = self.series.index(res)
try:
Thomas Arendsen Hein
Fixed python2.3 incompatibility (rsplit) in qpush/qpop with index.
r3082 off = int(patch[minus+1:] or 1)
Chris Mason
mq: patch naming shortcuts...
r2696 except(ValueError, OverflowError):
pass
else:
if i - off >= 0:
return self.series[i - off]
Thomas Arendsen Hein
Fixed python2.3 incompatibility (rsplit) in qpush/qpop with index.
r3082 plus = patch.rfind('+')
if plus >= 0:
res = partial_name(patch[:plus])
Chris Mason
mq: patch naming shortcuts...
r2696 if res:
i = self.series.index(res)
try:
Thomas Arendsen Hein
Fixed python2.3 incompatibility (rsplit) in qpush/qpop with index.
r3082 off = int(patch[plus+1:] or 1)
Chris Mason
mq: patch naming shortcuts...
r2696 except(ValueError, OverflowError):
pass
else:
if i + off < len(self.series):
return self.series[i + off]
Vadim Gelfer
mq: move many error messages to util.Abort
r2712 raise util.Abort(_("patch %s not in series") % patch)
mason@suse.com
Add mq extension
r1808
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 def push(self, repo, patch=None, force=False, list=False,
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 mergeq=None):
wlock = repo.wlock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
patch = self.lookup(patch)
# Suppose our series file is: A B C and the current 'top'
# patch is B. qpush C should be performed (moving forward)
# qpush B is a NOP (no change) qpush A is an error (can't
# go backwards with qpush)
if patch:
info = self.isapplied(patch)
if info:
if info[0] < len(self.applied) - 1:
raise util.Abort(
_("cannot push to a previous patch: %s") % patch)
if info[0] < len(self.series) - 1:
self.ui.warn(
_('qpush: %s is already at the top\n') % patch)
else:
self.ui.warn(_('all patches are currently applied\n'))
return
Ben Thomas
Modify qpush/qpop idempotent operations to return success...
r4100
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 # Following the above example, starting at 'top' of B:
# qpush should be performed (pushes C), but a subsequent
# qpush without an argument is an error (nothing to
# apply). This allows a loop of "...while hg qpush..." to
# work as it detects an error when done
if self.series_end() == len(self.series):
self.ui.warn(_('patch series already fully applied\n'))
return 1
if not force:
self.check_localchanges(repo)
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 self.applied_dirty = 1;
start = self.series_end()
if start > 0:
self.check_toppatch(repo)
if not patch:
patch = self.series[start]
end = start + 1
Bryan O'Sullivan
MQ: tidy up if a qpush is interrupted....
r4418 else:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 end = self.series.index(patch, start) + 1
s = self.series[start:end]
all_files = {}
try:
if mergeq:
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 ret = self.mergepatch(repo, mergeq, s)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 else:
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 ret = self.apply(repo, s, list, all_files=all_files)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 except:
self.ui.warn(_('cleaning up working directory...'))
node = repo.dirstate.parents()[0]
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 hg.revert(repo, node, None)
unknown = repo.status()[4]
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 # only remove unknown files that we know we touched or
# created while patching
for f in unknown:
if f in all_files:
util.unlink(repo.wjoin(f))
self.ui.warn(_('done\n'))
raise
top = self.applied[-1].name
if ret[0]:
self.ui.write(
"Errors during apply, please fix and refresh %s\n" % top)
else:
self.ui.write("Now at: %s\n" % top)
return ret[0]
finally:
del wlock
mason@suse.com
Add mq extension
r1808
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 def pop(self, repo, patch=None, force=False, update=True, all=False):
Bryan O'Sullivan
mq: teach qpop about symlinks
r5157 def getfile(f, rev, flags):
mason@suse.com
Add mq extension
r1808 t = repo.file(f).read(rev)
Bryan O'Sullivan
mq: teach qpop about symlinks
r5157 repo.wwrite(f, t, flags)
mason@suse.com
Add mq extension
r1808
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 wlock = repo.wlock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
if patch:
# index, rev, patch
info = self.isapplied(patch)
if not info:
patch = self.lookup(patch)
info = self.isapplied(patch)
if not info:
raise util.Abort(_("patch %s is not applied") % patch)
Ben Thomas
Modify qpush/qpop idempotent operations to return success...
r4100
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if len(self.applied) == 0:
# Allow qpop -a to work repeatedly,
# but not qpop without an argument
self.ui.warn(_("no patches applied\n"))
return not all
mason@suse.com
Add mq extension
r1808
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if not update:
parents = repo.dirstate.parents()
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")
update = True
mason@suse.com
Add mq extension
r1808
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if not force and update:
self.check_localchanges(repo)
mason@suse.com
Add mq extension
r1808
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 self.applied_dirty = 1;
end = len(self.applied)
if not patch:
if all:
popi = 0
else:
popi = len(self.applied) - 1
Chris Mason
mq: qpop should act like quilt pop...
r2697 else:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 popi = info[0] + 1
if popi >= end:
self.ui.warn("qpop: %s is already at the top\n" % patch)
return
info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
Chris Mason
mq: qpop should act like quilt pop...
r2697
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 start = info[0]
rev = revlog.bin(info[1])
mason@suse.com
Add mq extension
r1808
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 # we know there are no local changes, so we can make a simplified
# form of hg.update.
if update:
top = self.check_toppatch(repo)
qp = self.qparents(repo, rev)
changes = repo.changelog.read(qp)
mmap = repo.manifest.read(changes[0])
m, a, r, d, u = repo.status(qp, top)[:5]
if d:
raise util.Abort("deletions found between repo revs")
for f in m:
Bryan O'Sullivan
mq: teach qpop about symlinks
r5157 getfile(f, mmap[f], mmap.flags(f))
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 for f in r:
Bryan O'Sullivan
mq: teach qpop about symlinks
r5157 getfile(f, mmap[f], mmap.flags(f))
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 for f in m + r:
repo.dirstate.normal(f)
for f in a:
try:
os.unlink(repo.wjoin(f))
except OSError, e:
if e.errno != errno.ENOENT:
raise
try: os.removedirs(os.path.dirname(repo.wjoin(f)))
except: pass
repo.dirstate.forget(f)
repo.dirstate.setparents(qp, revlog.nullid)
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 self.strip(repo, rev, update=False, backup='strip')
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 del self.applied[start:end]
if len(self.applied):
self.ui.write("Now at: %s\n" % self.applied[-1].name)
else:
self.ui.write("Patch queue now empty\n")
finally:
del wlock
mason@suse.com
Add mq extension
r1808
Brendan Cully
Fix test-mq-qdiff; add -I and -X options to qdiff
r2937 def diff(self, repo, pats, opts):
mason@suse.com
Add mq extension
r1808 top = self.check_toppatch(repo)
if not top:
self.ui.write("No patches applied\n")
return
qp = self.qparents(repo, top)
Alexis S. L. Carvalho
add --git option to qdiff
r3697 if opts.get('git'):
self.diffopts().git = True
Brendan Cully
Fix test-mq-qdiff; add -I and -X options to qdiff
r2937 self.printdiff(repo, qp, files=pats, opts=opts)
mason@suse.com
Add mq extension
r1808
Brendan Cully
allow qrefresh to take a list of files; closes #96.
r2938 def refresh(self, repo, pats=None, **opts):
mason@suse.com
Add mq extension
r1808 if len(self.applied) == 0:
self.ui.write("No patches applied\n")
Bryan O'Sullivan
qrefresh: exit with status 1 if no patches applied.
r3004 return 1
mason@suse.com
Add mq extension
r1808 wlock = repo.wlock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
self.check_toppatch(repo)
(top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
top = revlog.bin(top)
cparents = repo.changelog.parents(top)
patchparent = self.qparents(repo, top)
message, comments, user, date, patchfound = self.readheaders(patchfn)
mason@suse.com
Add mq extension
r1808
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 patchf = self.opener(patchfn, 'r+')
Bryan O'Sullivan
mq: autodetect an existing git patch during qrefresh (issue 491)
r4930
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 # if the patch was a git patch, refresh it as a git patch
for line in patchf:
if line.startswith('diff --git'):
self.diffopts().git = True
break
Bryan O'Sullivan
mq: autodetect an existing git patch during qrefresh (issue 491)
r4930
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 msg = opts.get('msg', '').rstrip()
Brendan Cully
mq: some improvements to header rewriting (closes #690)...
r5235 if msg and comments:
# Remove existing message, keeping the rest of the comments
# fields.
# If comments contains 'subject: ', message will prepend
# the field and a blank line.
if message:
subj = 'subject: ' + message[0].lower()
for i in xrange(len(comments)):
if subj == comments[i].lower():
del comments[i]
message = message[2:]
break
Brendan Cully
Change patch header as well as commit message with qrefresh -m or -l.
r2745 ci = 0
Benoit Boissinot
use xrange instead of range
r3473 for mi in xrange(len(message)):
Brendan Cully
mq: some improvements to header rewriting (closes #690)...
r5235 while message[mi] != comments[ci]:
Brendan Cully
Change patch header as well as commit message with qrefresh -m or -l.
r2745 ci += 1
del comments[ci]
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if msg:
comments.append(msg)
Brendan Cully
mq: truncate patch just before rewriting header
r5180
Brendan Cully
Merge with crew-stable
r5183 patchf.seek(0)
patchf.truncate()
Brendan Cully
mq: truncate patch just before rewriting header
r5180
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if comments:
comments = "\n".join(comments) + '\n\n'
patchf.write(comments)
mason@suse.com
Add mq extension
r1808
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if opts.get('git'):
self.diffopts().git = True
fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
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
#
# this should really read:
# mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
# but we do it backwards to take advantage of manifest/chlog
# caching against the next repo.status call
#
mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
changes = repo.changelog.read(tip)
man = repo.manifest.read(changes[0])
aaa = aa[:]
if opts.get('short'):
filelist = mm + aa + dd
match = dict.fromkeys(filelist).__contains__
mason@suse.com
Add mq extension
r1808 else:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 filelist = None
match = util.always
m, a, r, d, u = repo.status(files=filelist, match=match)[:5]
mason@suse.com
Add mq extension
r1808
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 # 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)
mason@suse.com
Add mq extension
r1808
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 m = util.unique(mm)
r = util.unique(dd)
a = util.unique(aa)
c = [filter(matchfn, l) for l in (m, a, r, [], u)]
filelist = util.unique(c[0] + c[1] + c[2])
patch.diff(repo, patchparent, files=filelist, match=matchfn,
fp=patchf, changes=c, opts=self.diffopts())
patchf.close()
mason@suse.com
Add mq extension
r1808
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 repo.dirstate.setparents(*cparents)
copies = {}
for dst in a:
src = repo.dirstate.copied(dst)
Brendan Cully
mq: fix regression in 6fd953d5faea...
r5294 if src is not None:
copies.setdefault(src, []).append(dst)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 repo.dirstate.add(dst)
# remember the copies between patchparent and tip
# this may be slow, so don't do it if we're not tracking copies
if self.diffopts().git:
for dst in aaa:
f = repo.file(dst)
src = f.renamed(man[dst])
if src:
copies[src[0]] = 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)
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:
Alexis S. L. Carvalho
merge: forcefully mark files that we get from the second parent as dirty...
r5210 repo.dirstate.normallookup(f)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 for f in forget:
repo.dirstate.forget(f)
mason@suse.com
Add mq extension
r1808
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if not msg:
if not message:
message = "[mq]: %s\n" % patchfn
else:
message = "\n".join(message)
"Mathieu Clabaut "
MQ: uniformise message and logfile option....
r2694 else:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 message = msg
"Mathieu Clabaut "
MQ: uniformise message and logfile option....
r2694
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 self.strip(repo, top, update=False,
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 backup='strip')
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 n = repo.commit(filelist, message, changes[1], match=matchfn,
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 force=1)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
self.applied_dirty = 1
self.removeundo(repo)
else:
self.printdiff(repo, patchparent, fp=patchf)
patchf.close()
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)
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 self.pop(repo, force=True)
self.push(repo, force=True)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 finally:
del wlock
mason@suse.com
Add mq extension
r1808
def init(self, repo, create=False):
Alexis S. L. Carvalho
mq: qinit -c creates a repo even after a regular qinit
r4071 if not create and os.path.isdir(self.path):
Vadim Gelfer
mq: move many error messages to util.Abort
r2712 raise util.Abort(_("patch queue directory already exists"))
Alexis S. L. Carvalho
mq: qinit -c creates a repo even after a regular qinit
r4071 try:
os.mkdir(self.path)
except OSError, inst:
if inst.errno != errno.EEXIST or not create:
raise
mason@suse.com
Add mq extension
r1808 if create:
return self.qrepo(create=True)
def unapplied(self, repo, patch=None):
if patch and patch not in self.series:
Vadim Gelfer
mq: move many error messages to util.Abort
r2712 raise util.Abort(_("patch %s is not in series file") % patch)
mason@suse.com
Add mq extension
r1808 if not patch:
start = self.series_end()
else:
start = self.series.index(patch) + 1
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 unapplied = []
for i in xrange(start, len(self.series)):
pushable, reason = self.pushable(i)
if pushable:
unapplied.append((i, self.series[i]))
self.explain_pushable(i)
return unapplied
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810
Thomas Arendsen Hein
Simplified qseries and hg qapplied to fix some bugs caused by optimization:...
r4239 def qseries(self, repo, missing=None, start=0, length=None, status=None,
Brendan Cully
mq: add --summary to qapplied, qunapplied, qtop, qnext and qprev...
r3183 summary=False):
def displayname(patchname):
if summary:
msg = self.readheaders(patchname)[0]
msg = msg and ': ' + msg[0] or ': '
else:
msg = ''
return '%s%s' % (patchname, msg)
Alexis S. L. Carvalho
fix qseries -v and guards interaction...
r3763 applied = dict.fromkeys([p.name for p in self.applied])
Thomas Arendsen Hein
Simplified qseries and hg qapplied to fix some bugs caused by optimization:...
r4239 if length is None:
Brendan Cully
mq: add --summary to qapplied, qunapplied, qtop, qnext and qprev...
r3183 length = len(self.series) - start
mason@suse.com
Add mq extension
r1808 if not missing:
Benoit Boissinot
use xrange instead of range
r3473 for i in xrange(start, start+length):
Thomas Arendsen Hein
Simplified qseries and hg qapplied to fix some bugs caused by optimization:...
r4239 patch = self.series[i]
if patch in applied:
stat = 'A'
elif self.pushable(i)[0]:
stat = 'U'
else:
stat = 'G'
Brendan Cully
mq: add --summary to qapplied, qunapplied, qtop, qnext and qprev...
r3183 pfx = ''
mason@suse.com
Add mq extension
r1808 if self.ui.verbose:
Alexis S. L. Carvalho
fix qseries -v and guards interaction...
r3763 pfx = '%d %s ' % (i, stat)
Thomas Arendsen Hein
Simplified qseries and hg qapplied to fix some bugs caused by optimization:...
r4239 elif status and status != stat:
Thomas Arendsen Hein
Fix issue443: inconsistent output of "hg qunapplied -v"...
r4238 continue
Brendan Cully
mq: add --summary to qapplied, qunapplied, qtop, qnext and qprev...
r3183 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
mason@suse.com
Add mq extension
r1808 else:
Benoit Boissinot
mq: fix variables shadowing builtin
r2794 msng_list = []
mason@suse.com
Add mq extension
r1808 for root, dirs, files in os.walk(self.path):
d = root[len(self.path) + 1:]
for f in files:
fl = os.path.join(d, f)
Thomas Arendsen Hein
Fix mq's usage of opener, which don't allow absolute paths now.
r1852 if (fl not in self.series and
Thomas Arendsen Hein
hg qseries -m: guards file was not ignored
r4241 fl not in (self.status_path, self.series_path,
self.guards_path)
Thomas Arendsen Hein
Fix mq's usage of opener, which don't allow absolute paths now.
r1852 and not fl.startswith('.')):
Benoit Boissinot
mq: fix variables shadowing builtin
r2794 msng_list.append(fl)
msng_list.sort()
Benoit Boissinot
mq: remove unecessary test
r2795 for x in msng_list:
Brendan Cully
mq: add --summary to qapplied, qunapplied, qtop, qnext and qprev...
r3183 pfx = self.ui.verbose and ('D ') or ''
self.ui.write("%s%s\n" % (pfx, displayname(x)))
mason@suse.com
Add mq extension
r1808
def issaveline(self, l):
Brendan Cully
Update qsave to use StatusEntry; don't throw exception on bad status lines.
r2816 if l.name == '.hg.patches.save.line':
mason@suse.com
Add mq extension
r1808 return True
def qrepo(self, create=False):
Vadim Gelfer
mq: add join method
r2819 if create or os.path.isdir(self.join(".hg")):
Thomas Arendsen Hein
Create local ui object per repository, so .hg/hgrc don't get mixed....
r1839 return hg.repository(self.ui, path=self.path, create=create)
mason@suse.com
Add mq extension
r1808
def restore(self, repo, rev, delete=None, qupdate=None):
c = repo.changelog.read(rev)
desc = c[4].strip()
lines = desc.splitlines()
i = 0
datastart = None
series = []
applied = []
qpp = None
for i in xrange(0, len(lines)):
if lines[i] == 'Patch Data:':
datastart = i + 1
elif lines[i].startswith('Dirstate:'):
l = lines[i].rstrip()
l = l[10:].split(' ')
qpp = [ hg.bin(x) for x in l ]
elif datastart != None:
l = lines[i].rstrip()
Brendan Cully
Make mq camelcase consistent with the rest of hg.
r2818 se = statusentry(l)
Benoit Boissinot
mq: fix variables shadowing builtin
r2794 file_ = se.name
if se.rev:
Brendan Cully
Use StatusEntry class instead of repeated status line parsing....
r2780 applied.append(se)
Brendan Cully
mq: don't write applied patches into series twice in restore
r3185 else:
series.append(file_)
mason@suse.com
Add mq extension
r1808 if datastart == None:
self.ui.warn("No saved patch data found\n")
return 1
self.ui.warn("restoring status: %s\n" % lines[0])
self.full_series = series
self.applied = applied
Vadim Gelfer
mq: rename read_series as parse_series, make simpler and faster
r2767 self.parse_series()
mason@suse.com
Add mq extension
r1808 self.series_dirty = 1
self.applied_dirty = 1
heads = repo.changelog.heads()
if delete:
if rev not in heads:
self.ui.warn("save entry has children, leaving it alone\n")
else:
self.ui.warn("removing save entry %s\n" % hg.short(rev))
pp = repo.dirstate.parents()
if rev in pp:
update = True
else:
update = False
self.strip(repo, rev, update=update, backup='strip')
if qpp:
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 self.ui.warn("saved queue repository parents: %s %s\n" %
mason@suse.com
Add mq extension
r1808 (hg.short(qpp[0]), hg.short(qpp[1])))
if qupdate:
print "queue directory updating"
r = self.qrepo()
if not r:
self.ui.warn("Unable to load queue repository\n")
return 1
Matt Mackall
Introduce update helper functions: update, merge, clean, and revert
r2808 hg.clean(r, qpp[0])
mason@suse.com
Add mq extension
r1808
def save(self, repo, msg=None):
if len(self.applied) == 0:
self.ui.warn("save: no patches applied, exiting\n")
return 1
if self.issaveline(self.applied[-1]):
self.ui.warn("status is already saved\n")
return 1
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810
mason@suse.com
Add mq extension
r1808 ar = [ ':' + x for x in self.full_series ]
if not msg:
msg = "hg patches saved state"
else:
msg = "hg patches: " + msg.rstrip('\r\n')
r = self.qrepo()
if r:
pp = r.dirstate.parents()
msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1]))
msg += "\n\nPatch Data:\n"
Brendan Cully
Update qsave to use StatusEntry; don't throw exception on bad status lines.
r2816 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
"\n".join(ar) + '\n' or "")
mason@suse.com
Add mq extension
r1808 n = repo.commit(None, text, user=None, force=1)
if not n:
self.ui.warn("repo commit failed\n")
return 1
Brendan Cully
Make mq camelcase consistent with the rest of hg.
r2818 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
mason@suse.com
Add mq extension
r1808 self.applied_dirty = 1
Matt Mackall
Merge with -stable, fix small test failure
r4209 self.removeundo(repo)
mason@suse.com
Add mq extension
r1808
Chris Mason
mq: fix qnew and qimport to deal with series file comments...
r2698 def full_series_end(self):
if len(self.applied) > 0:
Brendan Cully
Use StatusEntry class instead of repeated status line parsing....
r2780 p = self.applied[-1].name
Chris Mason
mq: fix qnew and qimport to deal with series file comments...
r2698 end = self.find_series(p)
if end == None:
return len(self.full_series)
return end + 1
return 0
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 def series_end(self, all_patches=False):
Patrick Mezard
mq: fix qtop failure when the series ends with guarded patches.
r4406 """If all_patches is False, return the index of the next pushable patch
in the series, or the series length. If all_patches is True, return the
index of the first patch past the last applied one.
"""
mason@suse.com
Add mq extension
r1808 end = 0
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 def next(start):
if all_patches:
return start
i = start
while i < len(self.series):
p, reason = self.pushable(i)
if p:
break
self.explain_pushable(i)
i += 1
return i
mason@suse.com
Add mq extension
r1808 if len(self.applied) > 0:
Brendan Cully
Use StatusEntry class instead of repeated status line parsing....
r2780 p = self.applied[-1].name
mason@suse.com
Add mq extension
r1808 try:
end = self.series.index(p)
except ValueError:
return 0
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 return next(end + 1)
return next(end)
mason@suse.com
Add mq extension
r1808
def appliedname(self, index):
Brendan Cully
Use StatusEntry class instead of repeated status line parsing....
r2780 pname = self.applied[index].name
mason@suse.com
Add mq extension
r1808 if not self.ui.verbose:
"Mathieu Clabaut "
mq: uniform verbose display of patche[s]....
r2677 p = pname
else:
Brendan Cully
mq: fix appliedname
r2941 p = str(self.series.index(pname)) + " " + pname
mason@suse.com
Add mq extension
r1808 return p
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810
Brendan Cully
mq: Add --rev argument to qimport, to adopt existing changesets.
r3141 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
Brendan Cully
mq: add --git option to qimport -r
r3691 force=None, git=False):
Brendan Cully
mq: Add --rev argument to qimport, to adopt existing changesets.
r3141 def checkseries(patchname):
if patchname in self.series:
raise util.Abort(_('patch %s is already in the series file')
% patchname)
def checkfile(patchname):
if not force and os.path.exists(self.join(patchname)):
raise util.Abort(_('patch "%s" already exists')
% patchname)
if rev:
if files:
raise util.Abort(_('option "-r" not valid when importing '
'files'))
Thomas Arendsen Hein
Removed unused ui parameter from revpair/revrange and fix its users.
r3707 rev = cmdutil.revrange(repo, rev)
Brendan Cully
mq: Add --rev argument to qimport, to adopt existing changesets.
r3141 rev.sort(lambda x, y: cmp(y, x))
if (len(files) > 1 or len(rev) > 1) and patchname:
Vadim Gelfer
mq: move many error messages to util.Abort
r2712 raise util.Abort(_('option "-n" not valid when importing multiple '
Brendan Cully
mq: Add --rev argument to qimport, to adopt existing changesets.
r3141 'patches'))
mason@suse.com
Add mq extension
r1808 i = 0
Vadim Gelfer
mq: add qimported patches if patch dir is a repo
r2488 added = []
Brendan Cully
mq: Add --rev argument to qimport, to adopt existing changesets.
r3141 if rev:
# If mq patches are applied, we can only import revisions
# that form a linear path to qbase.
# Otherwise, they should form a linear path to a head.
heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
if len(heads) > 1:
raise util.Abort(_('revision %d is the root of more than one '
'branch') % rev[-1])
if self.applied:
base = revlog.hex(repo.changelog.node(rev[0]))
if base in [n.rev for n in self.applied]:
raise util.Abort(_('revision %d is already managed')
% rev[0])
if heads != [revlog.bin(self.applied[-1].rev)]:
raise util.Abort(_('revision %d is not the parent of '
'the queue') % rev[0])
base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
lastparent = repo.changelog.parentrevs(base)[0]
else:
if heads != [repo.changelog.node(rev[0])]:
raise util.Abort(_('revision %d has unmanaged children')
% rev[0])
lastparent = None
Brendan Cully
mq: add --git option to qimport -r
r3691 if git:
self.diffopts().git = True
Brendan Cully
mq: Add --rev argument to qimport, to adopt existing changesets.
r3141 for r in rev:
p1, p2 = repo.changelog.parentrevs(r)
n = repo.changelog.node(r)
Thomas Arendsen Hein
Define and use nullrev (revision of nullid) instead of -1.
r3578 if p2 != revlog.nullrev:
Brendan Cully
mq: Add --rev argument to qimport, to adopt existing changesets.
r3141 raise util.Abort(_('cannot import merge revision %d') % r)
if lastparent and lastparent != r:
raise util.Abort(_('revision %d is not the parent of %d')
% (r, lastparent))
lastparent = p1
if not patchname:
Patrick Mezard
Enforce unixish style for all generated patch names....
r4037 patchname = normname('%d.diff' % r)
Brendan Cully
mq: Add --rev argument to qimport, to adopt existing changesets.
r3141 checkseries(patchname)
checkfile(patchname)
self.full_series.insert(0, patchname)
patchf = self.opener(patchname, "w")
patch.export(repo, [n], fp=patchf, opts=self.diffopts())
patchf.close()
se = statusentry(revlog.hex(n), patchname)
self.applied.insert(0, se)
added.append(patchname)
patchname = None
self.parse_series()
self.applied_dirty = 1
mason@suse.com
Add mq extension
r1808 for filename in files:
if existing:
Brendan Cully
mq: support qimport -
r3547 if filename == '-':
raise util.Abort(_('-e is incompatible with import from -'))
Brendan Cully
qimport: rename patch to patchname to avoid shadowing module
r3133 if not patchname:
Patrick Mezard
Enforce unixish style for all generated patch names....
r4037 patchname = normname(filename)
Brendan Cully
qimport: rename patch to patchname to avoid shadowing module
r3133 if not os.path.isfile(self.join(patchname)):
raise util.Abort(_("patch %s does not exist") % patchname)
mason@suse.com
Add mq extension
r1808 else:
try:
Brendan Cully
mq: support qimport -
r3547 if filename == '-':
if not patchname:
raise util.Abort(_('need --name to import a patch from -'))
text = sys.stdin.read()
else:
text = file(filename).read()
mason@suse.com
Add mq extension
r1808 except IOError:
Brendan Cully
qimport: rename patch to patchname to avoid shadowing module
r3133 raise util.Abort(_("unable to read %s") % patchname)
if not patchname:
Patrick Mezard
Enforce unixish style for all generated patch names....
r4037 patchname = normname(os.path.basename(filename))
Brendan Cully
mq: Add --rev argument to qimport, to adopt existing changesets.
r3141 checkfile(patchname)
Brendan Cully
qimport: rename patch to patchname to avoid shadowing module
r3133 patchf = self.opener(patchname, "w")
mason@suse.com
Add mq extension
r1808 patchf.write(text)
Brendan Cully
mq: Add --rev argument to qimport, to adopt existing changesets.
r3141 checkseries(patchname)
Chris Mason
mq: fix qnew and qimport to deal with series file comments...
r2698 index = self.full_series_end() + i
Brendan Cully
qimport: rename patch to patchname to avoid shadowing module
r3133 self.full_series[index:index] = [patchname]
Vadim Gelfer
mq: rename read_series as parse_series, make simpler and faster
r2767 self.parse_series()
Brendan Cully
qimport: rename patch to patchname to avoid shadowing module
r3133 self.ui.warn("adding %s to series file\n" % patchname)
mason@suse.com
Add mq extension
r1808 i += 1
Brendan Cully
qimport: rename patch to patchname to avoid shadowing module
r3133 added.append(patchname)
patchname = None
mason@suse.com
Add mq extension
r1808 self.series_dirty = 1
Vadim Gelfer
mq: add qimported patches if patch dir is a repo
r2488 qrepo = self.qrepo()
if qrepo:
qrepo.add(added)
mason@suse.com
Add mq extension
r1808
Brendan Cully
mq: change qdel --forget to --rev; accept any revision symbol
r3373 def delete(ui, repo, *patches, **opts):
Brendan Cully
Allow qdel to delete multiple patches.
r2905 """remove patches from queue
Brendan Cully
Add -f option to qdelete, to remove patch file.
r2752
Brendan Cully
mq: more qdelete help text tweaks
r4737 The patches must not be applied, unless they are arguments to
the --rev parameter. At least one patch or revision is required.
Brendan Cully
mq: add qdelete --forget option...
r3088
Brendan Cully
mq: more qdelete help text tweaks
r4737 With --rev, mq will stop managing the named revisions (converting
them to regular mercurial changesets). The patches must be applied
and at the base of the stack. This option is useful when the patches
have been applied upstream.
Brendan Cully
mq: add qdelete --forget option...
r3088
With --keep, the patch files are preserved in the patch directory."""
Brendan Cully
mq: replace module-wide repo hash with a repo attribute
r2724 q = repo.mq
Brendan Cully
mq: change qdel --forget to --rev; accept any revision symbol
r3373 q.delete(repo, patches, opts)
mason@suse.com
Add mq extension
r1808 q.save_dirty()
return 0
def applied(ui, repo, patch=None, **opts):
"""print the patches already applied"""
Brendan Cully
mq: add --summary to qapplied, qunapplied, qtop, qnext and qprev...
r3183 q = repo.mq
if patch:
if patch not in q.series:
raise util.Abort(_("patch %s is not in series file") % patch)
end = q.series.index(patch) + 1
else:
Thomas Arendsen Hein
Simplified qseries and hg qapplied to fix some bugs caused by optimization:...
r4239 end = q.series_end(True)
Brendan Cully
mq: add --summary to qapplied, qunapplied, qtop, qnext and qprev...
r3183 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
mason@suse.com
Add mq extension
r1808
def unapplied(ui, repo, patch=None, **opts):
"""print the patches not yet applied"""
Brendan Cully
mq: add --summary to qapplied, qunapplied, qtop, qnext and qprev...
r3183 q = repo.mq
if patch:
if patch not in q.series:
raise util.Abort(_("patch %s is not in series file") % patch)
start = q.series.index(patch) + 1
else:
Thomas Arendsen Hein
Fix issue443: inconsistent output of "hg qunapplied -v"...
r4238 start = q.series_end(True)
q.qseries(repo, start=start, status='U', summary=opts.get('summary'))
mason@suse.com
Add mq extension
r1808
def qimport(ui, repo, *filename, **opts):
Brendan Cully
mq: Add --rev argument to qimport, to adopt existing changesets.
r3141 """import a patch
The patch will have the same name as its source file unless you
give it a new one with --name.
You can register an existing patch inside the patch directory
with the --existing flag.
With --force, an existing patch of the same name will be overwritten.
An existing changeset may be placed under mq control with --rev
(e.g. qimport --rev tip -n patch will place tip under mq control).
Brendan Cully
mq: add --git option to qimport -r
r3691 With --git, patches imported with --rev will use the git diff
format.
Brendan Cully
mq: Add --rev argument to qimport, to adopt existing changesets.
r3141 """
Brendan Cully
mq: replace module-wide repo hash with a repo attribute
r2724 q = repo.mq
Brendan Cully
qimport: rename patch to patchname to avoid shadowing module
r3133 q.qimport(repo, filename, patchname=opts['name'],
Brendan Cully
mq: add --git option to qimport -r
r3691 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
git=opts['git'])
mason@suse.com
Add mq extension
r1808 q.save_dirty()
return 0
def init(ui, repo, **opts):
Brendan Cully
Add more verbose help text to mq commands.
r2754 """init a new queue repository
The queue repository is unversioned by default. If -c is
specified, qinit will create a separate nested repository
Brendan Cully
mq: document that qinit -c may be run later
r4711 for patches (qinit -c may also be run later to convert
an unversioned patch repository into a versioned one).
You can use qcommit to commit changes to this queue repository."""
Brendan Cully
mq: replace module-wide repo hash with a repo attribute
r2724 q = repo.mq
mason@suse.com
Add mq extension
r1808 r = q.init(repo, create=opts['create_repo'])
q.save_dirty()
if r:
Alexis S. L. Carvalho
mq: qinit -c creates a repo even after a regular qinit
r4071 if not os.path.exists(r.wjoin('.hgignore')):
fp = r.wopener('.hgignore', 'w')
fp.write('syntax: glob\n')
fp.write('status\n')
fp.write('guards\n')
fp.close()
if not os.path.exists(r.wjoin('series')):
r.wopener('series', 'w').close()
mason@suse.com
Add mq extension
r1808 r.add(['.hgignore', 'series'])
Alexis S. L. Carvalho
mq: qinit -c creates a repo even after a regular qinit
r4071 commands.add(ui, r)
mason@suse.com
Add mq extension
r1808 return 0
Vadim Gelfer
mq: add qclone command
r2720 def clone(ui, source, dest=None, **opts):
'''clone main and patch repository at same time
If source is local, destination will have no patches applied. If
source is remote, this command can not check if patches are
applied in source, so cannot guarantee that patches are not
applied in destination. If you clone remote repository, be sure
before that it has no patches applied.
Source patch repository is looked for in <src>/.hg/patches by
default. Use -p <url> to change.
Brendan Cully
mq: improve qclone error handling when patch directory is not a repository.
r4862
The patch directory must be a nested mercurial repository, as
would be created by qinit -c.
Vadim Gelfer
mq: add qclone command
r2720 '''
Alexis S. L. Carvalho
avoid double slash problem mentioned in issue695
r5226 def patchdir(repo):
url = repo.url()
if url.endswith('/'):
url = url[:-1]
return url + '/.hg/patches'
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 cmdutil.setremoteconfig(ui, opts)
Vadim Gelfer
mq: add qclone command
r2720 if dest is None:
dest = hg.defaultdest(source)
sr = hg.repository(ui, ui.expandpath(source))
Alexis S. L. Carvalho
Merge with crew-stable
r5248 patchespath = opts['patches'] or patchdir(sr)
Brendan Cully
mq: improve qclone error handling when patch directory is not a repository.
r4862 try:
Alexis S. L. Carvalho
Merge with crew-stable
r5248 pr = hg.repository(ui, patchespath)
Brendan Cully
mq: improve qclone error handling when patch directory is not a repository.
r4862 except hg.RepoError:
raise util.Abort(_('versioned patch repository not found'
' (see qinit -c)'))
Vadim Gelfer
mq: add qclone command
r2720 qbase, destrev = None, None
if sr.local():
Vadim Gelfer
mq: update to handle repomap not longer used
r2725 if sr.mq.applied:
Brendan Cully
Use StatusEntry class instead of repeated status line parsing....
r2780 qbase = revlog.bin(sr.mq.applied[0].rev)
Vadim Gelfer
mq: add qclone command
r2720 if not hg.islocal(dest):
Alexis S. L. Carvalho
fix qclone to a remote repo...
r4171 heads = dict.fromkeys(sr.heads())
for h in sr.heads(qbase):
del heads[h]
destrev = heads.keys()
destrev.append(sr.changelog.parents(qbase)[0])
Vadim Gelfer
mq: add qclone command
r2720 ui.note(_('cloning main repo\n'))
Matt Mackall
mq: pass a URL to clone
r4476 sr, dr = hg.clone(ui, sr.url(), dest,
Vadim Gelfer
mq: add qclone command
r2720 pull=opts['pull'],
rev=destrev,
update=False,
stream=opts['uncompressed'])
ui.note(_('cloning patch repo\n'))
Alexis S. L. Carvalho
avoid double slash problem mentioned in issue695
r5226 spr, dpr = hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
pull=opts['pull'], update=not opts['noupdate'],
Vadim Gelfer
mq: add qclone command
r2720 stream=opts['uncompressed'])
if dr.local():
if qbase:
ui.note(_('stripping applied patches from destination repo\n'))
Vadim Gelfer
mq: update to handle repomap not longer used
r2725 dr.mq.strip(dr, qbase, update=False, backup=None)
Vadim Gelfer
mq: add qclone command
r2720 if not opts['noupdate']:
ui.note(_('updating destination repo\n'))
Matt Mackall
Move merge code to its own module...
r2775 hg.update(dr, dr.changelog.tip())
Vadim Gelfer
mq: add qclone command
r2720
mason@suse.com
Add mq extension
r1808 def commit(ui, repo, *pats, **opts):
Thomas Arendsen Hein
mq: Added help for qcommit, consistently talk about queue repository.
r2526 """commit changes in the queue repository"""
Brendan Cully
mq: replace module-wide repo hash with a repo attribute
r2724 q = repo.mq
mason@suse.com
Add mq extension
r1808 r = q.qrepo()
if not r: raise util.Abort('no queue repository')
commands.commit(r.ui, r, *pats, **opts)
def series(ui, repo, **opts):
"""print the entire series file"""
Brendan Cully
Add -s option to qseries: display first line of patch header.
r2756 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
mason@suse.com
Add mq extension
r1808 return 0
def top(ui, repo, **opts):
"""print the name of the current patch"""
Brendan Cully
mq: add --summary to qapplied, qunapplied, qtop, qnext and qprev...
r3183 q = repo.mq
Patrick Mezard
mq: fix qtop failure when the series ends with guarded patches.
r4406 t = q.applied and q.series_end(True) or 0
Brendan Cully
mq: add --summary to qapplied, qunapplied, qtop, qnext and qprev...
r3183 if t:
return q.qseries(repo, start=t-1, length=1, status='A',
summary=opts.get('summary'))
else:
ui.write("No patches applied\n")
return 1
mason@suse.com
Add mq extension
r1808
def next(ui, repo, **opts):
"""print the name of the next patch"""
Brendan Cully
mq: add --summary to qapplied, qunapplied, qtop, qnext and qprev...
r3183 q = repo.mq
end = q.series_end()
if end == len(q.series):
ui.write("All patches applied\n")
return 1
return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
mason@suse.com
Add mq extension
r1808
def prev(ui, repo, **opts):
"""print the name of the previous patch"""
Brendan Cully
mq: add --summary to qapplied, qunapplied, qtop, qnext and qprev...
r3183 q = repo.mq
l = len(q.applied)
if l == 1:
ui.write("Only one patch applied\n")
return 1
if not l:
ui.write("No patches applied\n")
return 1
return q.qseries(repo, start=l-2, length=1, status='A',
summary=opts.get('summary'))
mason@suse.com
Add mq extension
r1808
Brendan Cully
mq: support qnew -I/-X and file name lists
r4713 def new(ui, repo, patch, *args, **opts):
Brendan Cully
Add more verbose help text to mq commands.
r2754 """create a new patch
qnew creates a new patch on top of the currently-applied patch
(if any). It will refuse to run if there are any outstanding
changes unless -f is specified, in which case the patch will
Brendan Cully
mq: support qnew -I/-X and file name lists
r4713 be initialised with them. You may also use -I, -X, and/or a list of
files after the patch name to add only changes to matching files
to the new patch, leaving the rest as uncommitted modifications.
Brendan Cully
Add more verbose help text to mq commands.
r2754
Brendan Cully
Add qnew -e option.
r2939 -e, -m or -l set the patch header as well as the commit message.
If none is specified, the patch header is empty and the
Brendan Cully
mq: regularize patch header creation....
r4722 commit message is '[mq]: PATCH'"""
Brendan Cully
mq: replace module-wide repo hash with a repo attribute
r2724 q = repo.mq
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 message = cmdutil.logmessage(opts)
Brendan Cully
Add qnew -e option.
r2939 if opts['edit']:
message = ui.edit(message, ui.username())
Brendan Cully
mq: support qnew -I/-X and file name lists
r4713 opts['msg'] = message
q.new(repo, patch, *args, **opts)
mason@suse.com
Add mq extension
r1808 q.save_dirty()
return 0
Brendan Cully
allow qrefresh to take a list of files; closes #96.
r2938 def refresh(ui, repo, *pats, **opts):
Brendan Cully
mq help text updates and speling fixes
r2940 """update the current patch
If any file patterns are provided, the refreshed patch will contain only
the modifications that match those patterns; the remaining modifications
will remain in the working directory.
Thomas Arendsen Hein
mq: Mention usage of hg add/remove/copy/rename in qrefresh help text.
r4048
hg add/remove/copy/rename work as usual, though you might want to use
git-style patches (--git or [diff] git=1) to track copies and renames.
Brendan Cully
mq help text updates and speling fixes
r2940 """
Brendan Cully
mq: replace module-wide repo hash with a repo attribute
r2724 q = repo.mq
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 message = cmdutil.logmessage(opts)
Brendan Cully
Add option -e/--edit to qrefresh, to edit the existing header.
r2746 if opts['edit']:
Alexis S. L. Carvalho
mq: fix qrefresh -e with no patches applied
r5334 if not q.applied:
ui.write(_("No patches applied\n"))
return 1
Brendan Cully
Add option -e/--edit to qrefresh, to edit the existing header.
r2746 if message:
raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
Brendan Cully
Use StatusEntry class instead of repeated status line parsing....
r2780 patch = q.applied[-1].name
Brendan Cully
Add option -e/--edit to qrefresh, to edit the existing header.
r2746 (message, comment, user, date, hasdiff) = q.readheaders(patch)
message = ui.edit('\n'.join(message), user or ui.username())
Bryan O'Sullivan
qrefresh: exit with status 1 if no patches applied.
r3004 ret = q.refresh(repo, pats, msg=message, **opts)
mason@suse.com
Add mq extension
r1808 q.save_dirty()
Bryan O'Sullivan
qrefresh: exit with status 1 if no patches applied.
r3004 return ret
mason@suse.com
Add mq extension
r1808
Brendan Cully
Fix test-mq-qdiff; add -I and -X options to qdiff
r2937 def diff(ui, repo, *pats, **opts):
mason@suse.com
Add mq extension
r1808 """diff of the current patch"""
Brendan Cully
Fix test-mq-qdiff; add -I and -X options to qdiff
r2937 repo.mq.diff(repo, pats, opts)
mason@suse.com
Add mq extension
r1808 return 0
Brendan Cully
Add -m, -l, -e options to qfold.
r2753 def fold(ui, repo, *files, **opts):
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748 """fold the named patches into the current patch
Brendan Cully
Add -m, -l, -e options to qfold.
r2753
Brendan Cully
Add -f option to qfold; improve qfold documentation.
r2771 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
Brendan Cully
Replace qdel/qfold -f option with -k/--keep.
r2904 be deleted. With -k/--keep, the folded patch files will not
Brendan Cully
Add -f option to qfold; improve qfold documentation.
r2771 be removed afterwards.
Brendan Cully
Add -m, -l, -e options to qfold.
r2753 The header for each folded patch will be concatenated with
the current patch header, separated by a line of '* * *'."""
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748 q = repo.mq
if not files:
raise util.Abort(_('qfold requires at least one patch name'))
if not q.check_toppatch(repo):
Thomas Arendsen Hein
Never apply string formatting to generated errors with util.Abort....
r3072 raise util.Abort(_('No patches applied'))
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 message = cmdutil.logmessage(opts)
Brendan Cully
Add -m, -l, -e options to qfold.
r2753 if opts['edit']:
if message:
raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748 parent = q.lookup('qtip')
patches = []
messages = []
for f in files:
Brendan Cully
Fix qfold after recent changes
r2936 p = q.lookup(f)
if p in patches or p == parent:
ui.warn(_('Skipping already folded patch %s') % p)
if q.isapplied(p):
raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
patches.append(p)
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748
Brendan Cully
Fix qfold after recent changes
r2936 for p in patches:
Brendan Cully
Add -m, -l, -e options to qfold.
r2753 if not message:
Brendan Cully
Fix qfold after recent changes
r2936 messages.append(q.readheaders(p)[0])
pf = q.join(p)
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748 (patchsuccess, files, fuzz) = q.patch(repo, pf)
if not patchsuccess:
Brendan Cully
Fix qfold after recent changes
r2936 raise util.Abort(_('Error folding patch %s') % p)
patch.updatedir(ui, repo, files)
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748
Brendan Cully
Add -m, -l, -e options to qfold.
r2753 if not message:
message, comments, user = q.readheaders(parent)[0:3]
for msg in messages:
message.append('* * *')
message.extend(msg)
message = '\n'.join(message)
if opts['edit']:
message = ui.edit(message, user or ui.username())
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748
q.refresh(repo, msg=message)
Brendan Cully
mq: update qfold to call delete correctly
r3243 q.delete(repo, patches, opts)
Brendan Cully
New mq command qfold: Merge patches into the current patch....
r2748 q.save_dirty()
Bryan O'Sullivan
mq: add qgoto command.
r4432 def goto(ui, repo, patch, **opts):
'''push or pop patches until named patch is at top of stack'''
q = repo.mq
patch = q.lookup(patch)
if q.isapplied(patch):
ret = q.pop(repo, patch, force=opts['force'])
else:
ret = q.push(repo, patch, force=opts['force'])
q.save_dirty()
return ret
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 def guard(ui, repo, *args, **opts):
'''set or print guards for a patch
Brendan Cully
mq help text updates and speling fixes
r2940 Guards control whether a patch can be pushed. A patch with no
guards is always pushed. A patch with a positive guard ("+foo") is
pushed only if the qselect command has activated it. A patch with
a negative guard ("-foo") is never pushed if the qselect command
has activated it.
Vadim Gelfer
mq: new commands qselect, qguard...
r2821
Brendan Cully
mq help text updates and speling fixes
r2940 With no arguments, print the currently active guards.
With arguments, set guards for the named patch.
Vadim Gelfer
mq: new commands qselect, qguard...
r2821
Brendan Cully
mq help text updates and speling fixes
r2940 To set a negative guard "-foo" on topmost patch ("--" is needed so
hg will not interpret "-foo" as an option):
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 hg qguard -- -foo
Brendan Cully
mq help text updates and speling fixes
r2940 To set guards on another patch:
Thomas Arendsen Hein
Whitespace/Tab cleanup
r3223 hg qguard other.patch +2.6.17 -stable
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 '''
def status(idx):
guards = q.series_guards[idx] or ['unguarded']
ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
q = repo.mq
patch = None
args = list(args)
if opts['list']:
if args or opts['none']:
raise util.Abort(_('cannot mix -l/--list with options or arguments'))
for i in xrange(len(q.series)):
status(i)
return
if not args or args[0][0:1] in '-+':
if not q.applied:
raise util.Abort(_('no patches applied'))
patch = q.applied[-1].name
if patch is None and args[0][0:1] not in '-+':
patch = args.pop(0)
if patch is None:
raise util.Abort(_('no patch to work with'))
if args or opts['none']:
Christian Ebert
mq: abort cleanly when invalid patch name is given to qguard
r4133 idx = q.find_series(patch)
if idx is None:
raise util.Abort(_('no patch named %s') % patch)
q.set_guards(idx, args)
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 q.save_dirty()
else:
status(q.series.index(q.lookup(patch)))
Brendan Cully
Add command qheader to display the header of a given patch.
r2747 def header(ui, repo, patch=None):
"""Print the header of the topmost or specified patch"""
q = repo.mq
if patch:
patch = q.lookup(patch)
else:
if not q.applied:
ui.write('No patches applied\n')
Bryan O'Sullivan
qheader: exit withh meaningful error code.
r3008 return 1
Brendan Cully
Add command qheader to display the header of a given patch.
r2747 patch = q.lookup('qtip')
message = repo.mq.readheaders(patch)[0]
ui.write('\n'.join(message) + '\n')
mason@suse.com
Add mq extension
r1808 def lastsavename(path):
Benoit Boissinot
mq: fix variables shadowing builtin
r2794 (directory, base) = os.path.split(path)
names = os.listdir(directory)
mason@suse.com
Add mq extension
r1808 namere = re.compile("%s.([0-9]+)" % base)
Benoit Boissinot
mq: fix variables shadowing builtin
r2794 maxindex = None
mason@suse.com
Add mq extension
r1808 maxname = None
for f in names:
m = namere.match(f)
if m:
index = int(m.group(1))
Benoit Boissinot
mq: fix variables shadowing builtin
r2794 if maxindex == None or index > maxindex:
maxindex = index
mason@suse.com
Add mq extension
r1808 maxname = f
if maxname:
Benoit Boissinot
mq: fix variables shadowing builtin
r2794 return (os.path.join(directory, maxname), maxindex)
mason@suse.com
Add mq extension
r1808 return (None, None)
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810
mason@suse.com
Add mq extension
r1808 def savename(path):
(last, index) = lastsavename(path)
if last is None:
index = 0
newpath = path + ".%d" % (index + 1)
return newpath
def push(ui, repo, patch=None, **opts):
"""push the next patch onto the stack"""
Brendan Cully
mq: replace module-wide repo hash with a repo attribute
r2724 q = repo.mq
mason@suse.com
Add mq extension
r1808 mergeq = None
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810
mason@suse.com
Add mq extension
r1808 if opts['all']:
Brendan Cully
mq: handle qpush -a with empty series
r3604 if not q.series:
Ben Thomas
Modify qpush/qpop idempotent operations to return success...
r4100 ui.warn(_('no patches in series\n'))
return 0
mason@suse.com
Add mq extension
r1808 patch = q.series[-1]
if opts['merge']:
if opts['name']:
newpath = opts['name']
else:
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 newpath, i = lastsavename(q.path)
mason@suse.com
Add mq extension
r1808 if not newpath:
ui.warn("no saved queues found, please use -n\n")
return 1
mergeq = queue(ui, repo.join(""), newpath)
ui.warn("merging with queue at: %s\n" % mergeq.path)
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
mason@suse.com
Add mq extension
r1808 mergeq=mergeq)
return ret
def pop(ui, repo, patch=None, **opts):
"""pop the current patch off the stack"""
localupdate = True
if opts['name']:
q = queue(ui, repo.join(""), repo.join(opts['name']))
ui.warn('using patch queue: %s\n' % q.path)
localupdate = False
else:
Brendan Cully
mq: replace module-wide repo hash with a repo attribute
r2724 q = repo.mq
Alexis S. L. Carvalho
mq: propagate the return error of pop
r4099 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
all=opts['all'])
mason@suse.com
Add mq extension
r1808 q.save_dirty()
Alexis S. L. Carvalho
mq: propagate the return error of pop
r4099 return ret
mason@suse.com
Add mq extension
r1808
Brendan Cully
New self-explanatory command qrename.
r2750 def rename(ui, repo, patch, name=None, **opts):
"""rename a patch
With one argument, renames the current patch to PATCH1.
With two arguments, renames PATCH1 to PATCH2."""
q = repo.mq
if not name:
name = patch
patch = None
if patch:
patch = q.lookup(patch)
else:
if not q.applied:
ui.write(_('No patches applied\n'))
return
patch = q.lookup('qtip')
Brendan Cully
Make qrename handle directory targets; closes #333.
r3083 absdest = q.join(name)
if os.path.isdir(absdest):
Patrick Mezard
Enforce unixish style for all generated patch names....
r4037 name = normname(os.path.join(name, os.path.basename(patch)))
Brendan Cully
Make qrename handle directory targets; closes #333.
r3083 absdest = q.join(name)
if os.path.exists(absdest):
raise util.Abort(_('%s already exists') % absdest)
Thomas Arendsen Hein
Whitespace/Tab cleanup
r3223
Brendan Cully
Make qrename handle directory targets; closes #333.
r3083 if name in q.series:
raise util.Abort(_('A patch named %s already exists in the series file') % name)
Brendan Cully
New self-explanatory command qrename.
r2750
if ui.verbose:
ui.write('Renaming %s to %s\n' % (patch, name))
i = q.find_series(patch)
Mathieu Clabaut
Issue424: mq patch loses guard when qrenamed
r3685 guards = q.guard_re.findall(q.full_series[i])
q.full_series[i] = name + ''.join([' #' + g for g in guards])
Vadim Gelfer
mq: rename read_series as parse_series, make simpler and faster
r2767 q.parse_series()
Brendan Cully
New self-explanatory command qrename.
r2750 q.series_dirty = 1
info = q.isapplied(patch)
if info:
Brendan Cully
Make mq camelcase consistent with the rest of hg.
r2818 q.applied[info[0]] = statusentry(info[1], name)
Brendan Cully
New self-explanatory command qrename.
r2750 q.applied_dirty = 1
Vadim Gelfer
mq: add join method
r2819 util.rename(q.join(patch), absdest)
Brendan Cully
New self-explanatory command qrename.
r2750 r = q.qrepo()
if r:
wlock = r.wlock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
if r.dirstate[name] == 'r':
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 r.undelete([name])
r.copy(patch, name)
r.remove([patch], False)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 finally:
del wlock
Brendan Cully
New self-explanatory command qrename.
r2750
q.save_dirty()
mason@suse.com
Add mq extension
r1808 def restore(ui, repo, rev, **opts):
"""restore the queue state saved by a rev"""
rev = repo.lookup(rev)
Brendan Cully
mq: replace module-wide repo hash with a repo attribute
r2724 q = repo.mq
mason@suse.com
Add mq extension
r1808 q.restore(repo, rev, delete=opts['delete'],
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 qupdate=opts['update'])
mason@suse.com
Add mq extension
r1808 q.save_dirty()
return 0
def save(ui, repo, **opts):
"""save current queue state"""
Brendan Cully
mq: replace module-wide repo hash with a repo attribute
r2724 q = repo.mq
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 message = cmdutil.logmessage(opts)
"Mathieu Clabaut "
MQ: uniformise message and logfile option....
r2694 ret = q.save(repo, msg=message)
mason@suse.com
Add mq extension
r1808 if ret:
return ret
q.save_dirty()
if opts['copy']:
path = q.path
if opts['name']:
newpath = os.path.join(q.basepath, opts['name'])
if os.path.exists(newpath):
if not os.path.isdir(newpath):
Vadim Gelfer
mq: move many error messages to util.Abort
r2712 raise util.Abort(_('destination %s exists and is not '
'a directory') % newpath)
mason@suse.com
Add mq extension
r1808 if not opts['force']:
Vadim Gelfer
mq: move many error messages to util.Abort
r2712 raise util.Abort(_('destination %s exists, '
'use -f to force') % newpath)
mason@suse.com
Add mq extension
r1808 else:
newpath = savename(path)
ui.warn("copy %s to %s\n" % (path, newpath))
util.copyfiles(path, newpath)
if opts['empty']:
try:
Vadim Gelfer
mq: add join method
r2819 os.unlink(q.join(q.status_path))
mason@suse.com
Add mq extension
r1808 except:
pass
return 0
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810
mason@suse.com
Add mq extension
r1808 def strip(ui, repo, rev, **opts):
"""strip a revision and all later revs on the same branch"""
rev = repo.lookup(rev)
backup = 'all'
if opts['backup']:
backup = 'strip'
elif opts['nobackup']:
backup = 'none'
Brendan Cully
mq: do not update an empty working directory after strip....
r3087 update = repo.dirstate.parents()[0] != revlog.nullid
repo.mq.strip(repo, rev, backup=backup, update=update)
mason@suse.com
Add mq extension
r1808 return 0
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 def select(ui, repo, *args, **opts):
'''set or print guarded patches to push
Brendan Cully
mq help text updates and speling fixes
r2940 Use the qguard command to set or print guards on patch, then use
qselect to tell mq which guards to use. A patch will be pushed if it
has no guards or any positive guards match the currently selected guard,
but will not be pushed if any negative guards match the current guard.
For example:
Vadim Gelfer
mq: new commands qselect, qguard...
r2821
Brendan Cully
mq help text updates and speling fixes
r2940 qguard foo.patch -stable (negative guard)
qguard bar.patch +stable (positive guard)
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 qselect stable
Brendan Cully
mq help text updates and speling fixes
r2940 This activates the "stable" guard. mq will skip foo.patch (because
it has a negative match) but push bar.patch (because it
has a positive match).
Vadim Gelfer
mq: new commands qselect, qguard...
r2821
Brendan Cully
mq help text updates and speling fixes
r2940 With no arguments, prints the currently active guards.
With one argument, sets the active guard.
Thomas Arendsen Hein
Whitespace/Tab cleanup
r3223
Brendan Cully
mq help text updates and speling fixes
r2940 Use -n/--none to deactivate guards (no other arguments needed).
When no guards are active, patches with positive guards are skipped
and patches with negative guards are pushed.
Vadim Gelfer
mq: new commands qselect, qguard...
r2821
Brendan Cully
mq help text updates and speling fixes
r2940 qselect can change the guards on applied patches. It does not pop
guarded patches by default. Use --pop to pop back to the last applied
patch that is not guarded. Use --reapply (which implies --pop) to push
back to the current patch afterwards, but skip guarded patches.
Vadim Gelfer
qselect: add --pop, --reapply options
r2844
Brendan Cully
mq help text updates and speling fixes
r2940 Use -s/--series to print a list of all guards in the series file (no
other arguments needed). Use -v for more information.'''
Vadim Gelfer
mq: new commands qselect, qguard...
r2821
q = repo.mq
guards = q.active()
if args or opts['none']:
Vadim Gelfer
qselect: add --pop, --reapply options
r2844 old_unapplied = q.unapplied(repo)
old_guarded = [i for i in xrange(len(q.applied)) if
not q.pushable(i)[0]]
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 q.set_active(args)
q.save_dirty()
if not args:
ui.status(_('guards deactivated\n'))
Vadim Gelfer
qselect: add --pop, --reapply options
r2844 if not opts['pop'] and not opts['reapply']:
unapplied = q.unapplied(repo)
guarded = [i for i in xrange(len(q.applied))
if not q.pushable(i)[0]]
if len(unapplied) != len(old_unapplied):
ui.status(_('number of unguarded, unapplied patches has '
'changed from %d to %d\n') %
(len(old_unapplied), len(unapplied)))
if len(guarded) != len(old_guarded):
ui.status(_('number of guarded, applied patches has changed '
'from %d to %d\n') %
(len(old_guarded), len(guarded)))
Vadim Gelfer
mq: new commands qselect, qguard...
r2821 elif opts['series']:
guards = {}
noguards = 0
for gs in q.series_guards:
if not gs:
noguards += 1
for g in gs:
guards.setdefault(g, 0)
guards[g] += 1
if ui.verbose:
guards['NONE'] = noguards
guards = guards.items()
guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
if guards:
ui.note(_('guards in series file:\n'))
for guard, count in guards:
ui.note('%2d ' % count)
ui.write(guard, '\n')
else:
ui.note(_('no guards in series file\n'))
else:
if guards:
ui.note(_('active guards:\n'))
for g in guards:
ui.write(g, '\n')
else:
ui.write(_('no active guards\n'))
Vadim Gelfer
qselect: add --pop, --reapply options
r2844 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
popped = False
if opts['pop'] or opts['reapply']:
for i in xrange(len(q.applied)):
pushable, reason = q.pushable(i)
if not pushable:
ui.status(_('popping guarded patches\n'))
popped = True
if i == 0:
q.pop(repo, all=True)
else:
q.pop(repo, i-1)
break
if popped:
try:
if reapply:
ui.status(_('reapplying unguarded patches\n'))
q.push(repo, reapply)
finally:
q.save_dirty()
Vadim Gelfer
mq: new commands qselect, qguard...
r2821
mason@suse.com
Add mq extension
r1808 def reposetup(ui, repo):
Brendan Cully
Make mq camelcase consistent with the rest of hg.
r2818 class mqrepo(repo.__class__):
Vadim Gelfer
mq: do not allow to push from repo with patches applied
r2848 def abort_if_wdir_patched(self, errmsg, force=False):
if self.mq.applied and not force:
parent = revlog.hex(self.dirstate.parents()[0])
if parent in [s.rev for s in self.mq.applied]:
raise util.Abort(errmsg)
Thomas Arendsen Hein
Whitespace/Tab cleanup
r3223
Brendan Cully
Disallow commit over an applied mq patch.
r2845 def commit(self, *args, **opts):
if len(args) >= 6:
force = args[5]
else:
force = opts.get('force')
Vadim Gelfer
mq: do not allow to push from repo with patches applied
r2848 self.abort_if_wdir_patched(
_('cannot commit over an applied mq patch'),
force)
Brendan Cully
Disallow commit over an applied mq patch.
r2845
return super(mqrepo, self).commit(*args, **opts)
Vadim Gelfer
mq: do not allow to push from repo with patches applied
r2848 def push(self, remote, force=False, revs=None):
Brendan Cully
mq: allow push if -r is given explicitly
r4040 if self.mq.applied and not force and not revs:
Vadim Gelfer
mq: do not allow to push from repo with patches applied
r2848 raise util.Abort(_('source has mq patches applied'))
return super(mqrepo, self).push(remote, force, revs)
Thomas Arendsen Hein
Whitespace/Tab cleanup
r3223
Brendan Cully
mq: do not hold a reference to repo in tags override...
r2723 def tags(self):
if self.tagscache:
return self.tagscache
Brendan Cully
Make mq camelcase consistent with the rest of hg.
r2818 tagscache = super(mqrepo, self).tags()
Brendan Cully
Add mq patch names to tagscache instead of overriding lookup....
r2682
Brendan Cully
mq: replace module-wide repo hash with a repo attribute
r2724 q = self.mq
Brendan Cully
mq: do not hold a reference to repo in tags override...
r2723 if not q.applied:
return tagscache
Brendan Cully
Mq: modify repo.lookup to resolve applied patches too.
r2663
Brendan Cully
mq: add qparent tag (first parent of qbase)
r4219 mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied]
Brendan Cully
mq: do not hold a reference to repo in tags override...
r2723 mqtags.append((mqtags[-1][0], 'qtip'))
mqtags.append((mqtags[0][0], 'qbase'))
Brendan Cully
mq: add qparent tag (first parent of qbase)
r4219 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
Brendan Cully
mq: do not hold a reference to repo in tags override...
r2723 for patch in mqtags:
if patch[1] in tagscache:
self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
else:
Brendan Cully
mq: add qparent tag (first parent of qbase)
r4219 tagscache[patch[1]] = patch[0]
Brendan Cully
Add mq patch names to tagscache instead of overriding lookup....
r2682
return tagscache
Brendan Cully
Add qtip and qbase to mq qlookup.
r2664
Alexis S. L. Carvalho
fix encoding conversion of branch names when mq is loaded
r3826 def _branchtags(self):
Alexis S. L. Carvalho
make mq play nicely with the branch cache...
r3492 q = self.mq
if not q.applied:
Alexis S. L. Carvalho
fix encoding conversion of branch names when mq is loaded
r3826 return super(mqrepo, self)._branchtags()
Alexis S. L. Carvalho
make mq play nicely with the branch cache...
r3492
self.branchcache = {} # avoid recursion in changectx
cl = self.changelog
partial, last, lrev = self._readbranchcache()
qbase = cl.rev(revlog.bin(q.applied[0].rev))
start = lrev + 1
if start < qbase:
# update the cache (excluding the patches) and save it
self._updatebranchcache(partial, lrev+1, qbase)
self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
start = qbase
# if start = qbase, the cache is as updated as it should be.
# if start > qbase, the cache includes (part of) the patches.
# we might as well use it, but we won't save it.
# update the cache up to the tip
self._updatebranchcache(partial, start, cl.count())
Alexis S. L. Carvalho
fix encoding conversion of branch names when mq is loaded
r3826 return partial
Alexis S. L. Carvalho
make mq play nicely with the branch cache...
r3492
Vadim Gelfer
mq: only add mq attribute to local repo
r2851 if repo.local():
repo.__class__ = mqrepo
repo.mq = queue(ui, repo.join(""))
mason@suse.com
Add mq extension
r1808
Brendan Cully
mq: add --summary to qapplied, qunapplied, qtop, qnext and qprev...
r3183 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
mason@suse.com
Add mq extension
r1808 cmdtable = {
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
"qclone":
(clone,
[('', 'pull', None, _('use pull protocol to copy metadata')),
('U', 'noupdate', None, _('do not update the new working directories')),
('', 'uncompressed', None,
_('use uncompressed transfer (fast over LAN)')),
('p', 'patches', '', _('location of source patch repo')),
Benoit Boissinot
refactor options from cmdtable...
r5147 ] + commands.remoteopts,
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 _('hg qclone [OPTION]... SOURCE [DEST]')),
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 "qcommit|qci":
(commit,
Thomas Arendsen Hein
Better help for mq: Corrected synopses, get qcommit options from commands.py.
r2185 commands.table["^commit|ci"][1],
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 _('hg qcommit [OPTION]... [FILE]...')),
"^qdiff":
(diff,
[('g', 'git', None, _('use git extended diff format')),
Benoit Boissinot
refactor options from cmdtable...
r5147 ] + commands.walkopts,
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 _('hg qdiff [-I] [-X] [-g] [FILE]...')),
Brendan Cully
Replace qdel/qfold -f option with -k/--keep.
r2904 "qdelete|qremove|qrm":
Brendan Cully
Add -f option to qdelete, to remove patch file.
r2752 (delete,
Brendan Cully
mq: change qdel --forget to --rev; accept any revision symbol
r3373 [('k', 'keep', None, _('keep patch file')),
('r', 'rev', [], _('stop managing a revision'))],
Brendan Cully
mq: more qdelete help text tweaks
r4737 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
Brendan Cully
Add -m, -l, -e options to qfold.
r2753 'qfold':
(fold,
[('e', 'edit', None, _('edit patch header')),
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 ('k', 'keep', None, _('keep folded patch files')),
] + commands.commitopts,
_('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
'qgoto':
(goto,
[('f', 'force', None, _('overwrite any local changes'))],
_('hg qgoto [OPTION]... PATCH')),
'qguard':
(guard,
[('l', 'list', None, _('list all patches and guards')),
('n', 'none', None, _('drop all guards'))],
_('hg qguard [-l] [-n] [PATCH] [+GUARD]... [-GUARD]...')),
'qheader': (header, [], _('hg qheader [PATCH]')),
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 "^qimport":
(qimport,
[('e', 'existing', None, 'import file in patch dir'),
('n', 'name', '', 'patch file name'),
Brendan Cully
mq: Add --rev argument to qimport, to adopt existing changesets.
r3141 ('f', 'force', None, 'overwrite existing files'),
Brendan Cully
mq: add --git option to qimport -r
r3691 ('r', 'rev', [], 'place existing revisions under mq control'),
('g', 'git', None, _('use git extended diff format'))],
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 _('hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...')),
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 "^qinit":
(init,
Thomas Arendsen Hein
mq: Added help for qcommit, consistently talk about queue repository.
r2526 [('c', 'create-repo', None, 'create queue repository')],
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 _('hg qinit [-c]')),
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 "qnew":
(new,
Brendan Cully
Add qnew -e option.
r2939 [('e', 'edit', None, _('edit commit message')),
Brendan Cully
mq: support qnew -I/-X and file name lists
r4713 ('f', 'force', None, _('import uncommitted changes into patch')),
Patrick Mezard
mq: add qnew --git option
r5025 ('g', 'git', None, _('use git extended diff format')),
Benoit Boissinot
refactor options from cmdtable...
r5147 ] + commands.walkopts + commands.commitopts,
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
"qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
"qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 "^qpop":
(pop,
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 [('a', 'all', None, _('pop all patches')),
('n', 'name', '', _('queue name to pop')),
('f', 'force', None, _('forget any local changes'))],
_('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 "^qpush":
(push,
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 [('f', 'force', None, _('apply if the patch has rejects')),
('l', 'list', None, _('list patch name in commit text')),
('a', 'all', None, _('apply all patches')),
('m', 'merge', None, _('merge from another queue')),
('n', 'name', '', _('merge queue name'))],
_('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 "^qrefresh":
(refresh,
Brendan Cully
Add option -e/--edit to qrefresh, to edit the existing header.
r2746 [('e', 'edit', None, _('edit commit message')),
Brendan Cully
mq: Add --git option to qrefresh
r3086 ('g', 'git', None, _('use git extended diff format')),
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 ('s', 'short', None, _('refresh only files already in the patch')),
Benoit Boissinot
refactor options from cmdtable...
r5147 ] + commands.walkopts + commands.commitopts,
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
Vadim Gelfer
mq: add qmv as alias for qrename
r2751 'qrename|qmv':
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 "qrestore":
(restore,
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 [('d', 'delete', None, _('delete save entry')),
('u', 'update', None, _('update queue working dir'))],
_('hg qrestore [-d] [-u] REV')),
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 "qsave":
(save,
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 [('c', 'copy', None, _('copy patch directory')),
('n', 'name', '', _('copy directory name')),
('e', 'empty', None, _('clear queue status file')),
('f', 'force', None, _('force copy'))] + commands.commitopts,
_('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
"qselect":
(select,
[('n', 'none', None, _('disable all guards')),
('s', 'series', None, _('list all guards in series file')),
('', 'pop', None, _('pop to before first guarded applied patch')),
('', 'reapply', None, _('pop, then reapply patches'))],
_('hg qselect [OPTION]... [GUARD]...')),
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 "qseries":
(series,
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 [('m', 'missing', None, _('print patches not in series')),
] + seriesopts,
_('hg qseries [-ms]')),
Thomas Arendsen Hein
Whitespace, tab and formatting cleanups, mainly in mq.py
r1810 "^strip":
(strip,
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 [('f', 'force', None, _('force multi-head removal')),
('b', 'backup', None, _('bundle unrelated changesets')),
('n', 'nobackup', None, _('no backups'))],
_('hg strip [-f] [-b] [-n] REV')),
"qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
"qunapplied": (unapplied, [] + seriesopts, _('hg qunapplied [-s] [PATCH]')),
mason@suse.com
Add mq extension
r1808 }