##// END OF EJS Templates
convert: warn on superfluous / in paths...
convert: warn on superfluous / in paths shlex is really a bad parser for this line-based format ...

File last commit:

r11564:9bbfeba3 default
r11680:7fefef3c default
Show More
record.py
573 lines | 18.4 KiB | text/x-python | PythonLexer
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 # record.py
#
# Copyright 2007 Bryan O'Sullivan <bos@serpentine.com>
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
Dirkjan Ochtman
extensions: change descriptions for extensions providing a few commands
r8934 '''commands to interactively select changes for commit/qrefresh'''
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
Martin Geisler
i18n, record: improve use of translated docstring in prompts...
r7015 from mercurial.i18n import gettext, _
Joel Rosdahl
Remove unused imports
r6212 from mercurial import cmdutil, commands, extensions, hg, mdiff, patch
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 from mercurial import util
Renato Cunha
record: removed 'reduce' calls (unsupported by py3k)...
r11500 import copy, cStringIO, errno, os, re, tempfile
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)')
def scanpatch(fp):
Kirill Smelkov
record: some docs...
r5826 """like patch.iterhunks, but yield different events
- ('file', [header_lines + fromfile + tofile])
- ('context', [context_lines])
- ('hunk', [hunk_lines])
- ('range', (-start,len, +start,len, diffp))
"""
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 lr = patch.linereader(fp)
def scanwhile(first, p):
Kirill Smelkov
record: some docs...
r5826 """scan lr while predicate holds"""
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 lines = [first]
while True:
line = lr.readline()
if not line:
break
if p(line):
lines.append(line)
else:
lr.push(line)
break
return lines
while True:
line = lr.readline()
if not line:
break
if line.startswith('diff --git a/'):
def notheader(line):
s = line.split(None, 1)
return not s or s[0] not in ('---', 'diff')
header = scanwhile(line, notheader)
fromfile = lr.readline()
if fromfile.startswith('---'):
tofile = lr.readline()
header += [fromfile, tofile]
else:
lr.push(fromfile)
yield 'file', header
elif line[0] == ' ':
yield 'context', scanwhile(line, lambda l: l[0] in ' \\')
elif line[0] in '-+':
yield 'hunk', scanwhile(line, lambda l: l[0] in '-+\\')
else:
m = lines_re.match(line)
if m:
yield 'range', m.groups()
else:
raise patch.PatchError('unknown patch content: %r' % line)
class header(object):
Kirill Smelkov
record: some docs...
r5826 """patch header
Thomas Arendsen Hein
Removed trailing spaces from everything except test output
r6210
XXX shoudn't we move this to mercurial/patch.py ?
Kirill Smelkov
record: some docs...
r5826 """
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 diff_re = re.compile('diff --git a/(.*) b/(.*)$')
allhunks_re = re.compile('(?:index|new file|deleted file) ')
pretty_re = re.compile('(?:new file|deleted file) ')
special_re = re.compile('(?:index|new|deleted|copy|rename) ')
def __init__(self, header):
self.header = header
self.hunks = []
def binary(self):
for h in self.header:
if h.startswith('index '):
return True
Thomas Arendsen Hein
Remove trailing spaces, fix indentation
r5143
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 def pretty(self, fp):
for h in self.header:
if h.startswith('index '):
fp.write(_('this modifies a binary file (all or nothing)\n'))
break
if self.pretty_re.match(h):
fp.write(h)
if self.binary():
fp.write(_('this is a binary file\n'))
break
if h.startswith('---'):
fp.write(_('%d hunks, %d lines changed\n') %
(len(self.hunks),
sum([h.added + h.removed for h in self.hunks])))
break
fp.write(h)
def write(self, fp):
fp.write(''.join(self.header))
def allhunks(self):
for h in self.header:
if self.allhunks_re.match(h):
return True
def files(self):
fromfile, tofile = self.diff_re.match(self.header[0]).groups()
if fromfile == tofile:
return [fromfile]
return [fromfile, tofile]
def filename(self):
return self.files()[-1]
def __repr__(self):
return '<header %s>' % (' '.join(map(repr, self.files())))
def special(self):
for h in self.header:
if self.special_re.match(h):
return True
def countchanges(hunk):
Kirill Smelkov
record: some docs...
r5826 """hunk -> (n+,n-)"""
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 add = len([h for h in hunk if h[0] == '+'])
rem = len([h for h in hunk if h[0] == '-'])
return add, rem
class hunk(object):
Kirill Smelkov
record: some docs...
r5826 """patch hunk
Thomas Arendsen Hein
Removed trailing spaces from everything except test output
r6210
Kirill Smelkov
record: some docs...
r5826 XXX shouldn't we merge this with patch.hunk ?
"""
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 maxcontext = 3
def __init__(self, header, fromline, toline, proc, before, hunk, after):
def trimcontext(number, lines):
delta = len(lines) - self.maxcontext
if False and delta > 0:
return number + delta, lines[:self.maxcontext]
return number, lines
self.header = header
self.fromline, self.before = trimcontext(fromline, before)
self.toline, self.after = trimcontext(toline, after)
self.proc = proc
self.hunk = hunk
self.added, self.removed = countchanges(self.hunk)
def write(self, fp):
delta = len(self.before) + len(self.after)
Dirkjan Ochtman
record: take diff lines for lack of trailing newlines into account (issue1282)...
r6949 if self.after and self.after[-1] == '\\ No newline at end of file\n':
delta -= 1
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 fromlen = delta + self.removed
tolen = delta + self.added
fp.write('@@ -%d,%d +%d,%d @@%s\n' %
(self.fromline, fromlen, self.toline, tolen,
self.proc and (' ' + self.proc)))
fp.write(''.join(self.before + self.hunk + self.after))
pretty = write
def filename(self):
return self.header.filename()
def __repr__(self):
return '<hunk %r@%d>' % (self.filename(), self.fromline)
def parsepatch(fp):
Kirill Smelkov
record: some docs...
r5826 """patch -> [] of hunks """
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 class parser(object):
Kirill Smelkov
record: some docs...
r5826 """patch parsing state machine"""
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 def __init__(self):
self.fromline = 0
self.toline = 0
self.proc = ''
self.header = None
self.context = []
self.before = []
self.hunk = []
self.stream = []
Renato Cunha
record: tuple parameter unpacking is deprecated in py3k
r11499 def addrange(self, limits):
fromstart, fromend, tostart, toend, proc = limits
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 self.fromline = int(fromstart)
self.toline = int(tostart)
self.proc = proc
def addcontext(self, context):
if self.hunk:
h = hunk(self.header, self.fromline, self.toline, self.proc,
self.before, self.hunk, context)
self.header.hunks.append(h)
self.stream.append(h)
self.fromline += len(self.before) + h.removed
self.toline += len(self.before) + h.added
self.before = []
self.hunk = []
self.proc = ''
self.context = context
def addhunk(self, hunk):
if self.context:
self.before = self.context
self.context = []
Dirkjan Ochtman
record: take diff lines for lack of trailing newlines into account (issue1282)...
r6949 self.hunk = hunk
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
def newfile(self, hdr):
self.addcontext([])
h = header(hdr)
self.stream.append(h)
self.header = h
def finished(self):
self.addcontext([])
return self.stream
transitions = {
'file': {'context': addcontext,
'file': newfile,
'hunk': addhunk,
'range': addrange},
'context': {'file': newfile,
'hunk': addhunk,
'range': addrange},
'hunk': {'context': addcontext,
'file': newfile,
'range': addrange},
'range': {'context': addcontext,
'hunk': addhunk},
}
Thomas Arendsen Hein
Remove trailing spaces, fix indentation
r5143
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 p = parser()
state = 'context'
for newstate, data in scanpatch(fp):
try:
p.transitions[state][newstate](p, data)
except KeyError:
raise patch.PatchError('unhandled transition: %s -> %s' %
(state, newstate))
state = newstate
return p.finished()
def filterpatch(ui, chunks):
Kirill Smelkov
record: some docs...
r5826 """Interactively filter patch chunks into applied-only chunks"""
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 chunks = list(chunks)
chunks.reverse()
Benoit Boissinot
record: use set instead of dict
r8460 seen = set()
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 def consumefile():
Kirill Smelkov
record: some docs...
r5826 """fetch next portion from chunks until a 'header' is seen
NB: header == new-file mark
"""
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 consumed = []
while chunks:
if isinstance(chunks[-1], header):
break
else:
consumed.append(chunks.pop())
return consumed
Kirill Smelkov
record: some docs...
r5826
resp_all = [None] # this two are changed from inside prompt,
resp_file = [None] # so can't be usual variables
applied = {} # 'filename' -> [] of chunks
Bryan O'Sullivan
record: improve docs, improve prompts
r5154 def prompt(query):
Kirill Smelkov
record: some docs...
r5826 """prompt query, and process base inputs
Thomas Arendsen Hein
Removed trailing spaces from everything except test output
r6210
Kirill Smelkov
record: some docs...
r5826 - y/n for the rest of file
- y/n for the rest
- ? (help)
- q (quit)
Martin Geisler
record: handle translated prompt correctly...
r9837 Returns True/False and sets reps_all and resp_file as
appropriate.
Kirill Smelkov
record: some docs...
r5826 """
Bryan O'Sullivan
record: improve docs, improve prompts
r5154 if resp_all[0] is not None:
return resp_all[0]
if resp_file[0] is not None:
return resp_file[0]
while True:
Steve Borho
ui: replace regexp pattern with sequence of choices...
r8259 resps = _('[Ynsfdaq?]')
choices = (_('&Yes, record this change'),
_('&No, skip this change'),
_('&Skip remaining changes to this file'),
_('Record remaining changes to this &file'),
_('&Done, skip remaining changes and files'),
_('Record &all changes to all remaining files'),
_('&Quit, recording no changes'),
_('&?'))
timeless@mozdev.org
record: remove superfluous space
r9461 r = ui.promptchoice("%s %s" % (query, resps), choices)
Martin Geisler
record: separate each hunk with a blank line...
r10694 ui.write("\n")
Simon Heimberg
ui: extract choice from prompt...
r9048 if r == 7: # ?
Martin Geisler
i18n, record: improve use of translated docstring in prompts...
r7015 doc = gettext(record.__doc__)
Martin Geisler
record: better way to find help in docstring...
r11236 c = doc.find('::') + 2
Martin Geisler
i18n, record: improve use of translated docstring in prompts...
r7015 for l in doc[c:].splitlines():
Martin Geisler
record: better way to find help in docstring...
r11236 if l.startswith(' '):
Matt Mackall
many, many trivial check-code fixups
r10282 ui.write(l.strip(), '\n')
Bryan O'Sullivan
record: improve docs, improve prompts
r5154 continue
Simon Heimberg
ui: extract choice from prompt...
r9048 elif r == 0: # yes
Martin Geisler
record: handle translated prompt correctly...
r9837 ret = True
Simon Heimberg
ui: extract choice from prompt...
r9048 elif r == 1: # no
Martin Geisler
record: handle translated prompt correctly...
r9837 ret = False
Simon Heimberg
ui: extract choice from prompt...
r9048 elif r == 2: # Skip
Martin Geisler
record: handle translated prompt correctly...
r9837 ret = resp_file[0] = False
Simon Heimberg
ui: extract choice from prompt...
r9048 elif r == 3: # file (Record remaining)
Martin Geisler
record: handle translated prompt correctly...
r9837 ret = resp_file[0] = True
Simon Heimberg
ui: extract choice from prompt...
r9048 elif r == 4: # done, skip remaining
Martin Geisler
record: handle translated prompt correctly...
r9837 ret = resp_all[0] = False
Simon Heimberg
ui: extract choice from prompt...
r9048 elif r == 5: # all
Martin Geisler
record: handle translated prompt correctly...
r9837 ret = resp_all[0] = True
Simon Heimberg
ui: extract choice from prompt...
r9048 elif r == 6: # quit
Bryan O'Sullivan
record: improve docs, improve prompts
r5154 raise util.Abort(_('user quit'))
Simon Heimberg
ui: extract choice from prompt...
r9048 return ret
Rocco Rutte
record: Give user a hint about chunk selection progress...
r7910 pos, total = 0, len(chunks) - 1
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 while chunks:
Benoit Boissinot
record: get the right position (account for skipped files)
r9688 pos = total - len(chunks) + 1
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 chunk = chunks.pop()
if isinstance(chunk, header):
Kirill Smelkov
record: some docs...
r5826 # new-file mark
Bryan O'Sullivan
record: improve docs, improve prompts
r5154 resp_file = [None]
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 fixoffset = 0
hdr = ''.join(chunk.header)
if hdr in seen:
consumefile()
continue
Benoit Boissinot
record: use set instead of dict
r8460 seen.add(hdr)
Bryan O'Sullivan
record: improve docs, improve prompts
r5154 if resp_all[0] is None:
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 chunk.pretty(ui)
Bryan O'Sullivan
record: change wording of initial per-file prompt
r5285 r = prompt(_('examine changes to %s?') %
Bryan O'Sullivan
record: improve docs, improve prompts
r5154 _(' and ').join(map(repr, chunk.files())))
Martin Geisler
record: handle translated prompt correctly...
r9837 if r:
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 applied[chunk.filename()] = [chunk]
if chunk.allhunks():
applied[chunk.filename()] += consumefile()
else:
consumefile()
else:
Kirill Smelkov
record: some docs...
r5826 # new hunk
Bryan O'Sullivan
record: improve docs, improve prompts
r5154 if resp_file[0] is None and resp_all[0] is None:
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 chunk.pretty(ui)
Rocco Rutte
record: Give user a hint about chunk selection progress...
r7910 r = total == 1 and prompt(_('record this change to %r?') %
Benoit Boissinot
record: fix indentation
r7911 chunk.filename()) \
or prompt(_('record change %d/%d to %r?') %
(pos, total, chunk.filename()))
Martin Geisler
record: handle translated prompt correctly...
r9837 if r:
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 if fixoffset:
chunk = copy.copy(chunk)
chunk.toline += fixoffset
applied[chunk.filename()].append(chunk)
else:
fixoffset += chunk.removed - chunk.added
Renato Cunha
record: removed 'reduce' calls (unsupported by py3k)...
r11500 return sum([h for h in applied.itervalues()
if h[0].special() or len(h) > 1], [])
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
def record(ui, repo, *pats, **opts):
Bryan O'Sullivan
record: improve docs, improve prompts
r5154 '''interactively select changes to commit
Martin Geisler
Use hg role in help strings
r10973 If a list of files is omitted, all changes reported by :hg:`status`
Martin Geisler
record: wrap docstrings at 70 characters
r9272 will be candidates for recording.
Bryan O'Sullivan
record: improve docs, improve prompts
r5154
Martin Geisler
Use hg role in help strings
r10973 See :hg:`help dates` for a list of formats valid for -d/--date.
Thomas Arendsen Hein
Document log date ranges and mention 'hg help dates' for all commands (issue998)
r6163
Martin Geisler
record: wrap docstrings at 70 characters
r9272 You will be prompted for whether to record changes to each
modified file, and for files with multiple changes, for each
change to use. For each query, the following responses are
possible::
Bryan O'Sullivan
record: improve docs, improve prompts
r5154
Martin Geisler
commands: use minirst parser when displaying help
r9157 y - record this change
n - skip this change
Bryan O'Sullivan
record: improve docs, improve prompts
r5154
Martin Geisler
commands: use minirst parser when displaying help
r9157 s - skip remaining changes to this file
f - record remaining changes to this file
Bryan O'Sullivan
record: improve docs, improve prompts
r5154
Martin Geisler
commands: use minirst parser when displaying help
r9157 d - done, skip remaining changes and files
a - record all changes to all remaining files
q - quit, recording no changes
Bryan O'Sullivan
record: improve docs, improve prompts
r5154
Nicolas Dumazet
record: check that we are not committing a merge before patch selection...
r11237 ? - display help
This command is not available when committing a merge.'''
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
Dan Villiom Podlaski Christiansen
record: function variable naming & signature cleanup....
r10323 dorecord(ui, repo, commands.commit, *pats, **opts)
Kirill Smelkov
hg qrecord -- like record, but for mq...
r5830
Kirill Smelkov
qrecord: record complements commit, so qrecord should complement qnew...
r5932 def qrecord(ui, repo, patch, *pats, **opts):
'''interactively record a new patch
Kirill Smelkov
hg qrecord -- like record, but for mq...
r5830
Martin Geisler
Use hg role in help strings
r10973 See :hg:`help qnew` & :hg:`help record` for more information and
Martin Geisler
record: wrap docstrings at 70 characters
r9272 usage.
Kirill Smelkov
hg qrecord -- like record, but for mq...
r5830 '''
try:
mq = extensions.find('mq')
except KeyError:
raise util.Abort(_("'mq' extension not loaded"))
Dan Villiom Podlaski Christiansen
record: function variable naming & signature cleanup....
r10323 def committomq(ui, repo, *pats, **opts):
Kirill Smelkov
qrecord: record complements commit, so qrecord should complement qnew...
r5932 mq.new(ui, repo, patch, *pats, **opts)
Kirill Smelkov
hg qrecord -- like record, but for mq...
r5830
Kirill Smelkov
qrecord: record complements commit, so qrecord should complement qnew...
r5932 opts = opts.copy()
opts['force'] = True # always 'qnew -f'
Dan Villiom Podlaski Christiansen
record: function variable naming & signature cleanup....
r10323 dorecord(ui, repo, committomq, *pats, **opts)
Kirill Smelkov
record: refactor record into generic record driver...
r5827
Dan Villiom Podlaski Christiansen
record: function variable naming & signature cleanup....
r10323 def dorecord(ui, repo, commitfunc, *pats, **opts):
Matt Mackall
ui: make interactive a method
r8208 if not ui.interactive():
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 raise util.Abort(_('running non-interactively, use commit instead'))
Matt Mackall
match: stop passing files through commitfunc
r6600 def recordfunc(ui, repo, message, match, opts):
Kirill Smelkov
record: refactor record into generic record driver...
r5827 """This is generic record driver.
Martin Geisler
typos: "it's" -> "its"
r9087 Its job is to interactively filter local changes, and accordingly
Kirill Smelkov
record: refactor record into generic record driver...
r5827 prepare working dir into a state, where the job can be delegated to
non-interactive commit command such as 'commit' or 'qrefresh'.
After the actual job is done by non-interactive command, working dir
state is restored to original.
Nicolas Dumazet
record: docstring typo
r11235 In the end we'll record interesting changes, and everything else will be
Kirill Smelkov
record: refactor record into generic record driver...
r5827 left in place, so the user can continue his work.
"""
Dirkjan Ochtman
record: minimize number of status calls
r7754
Nicolas Dumazet
record: check that we are not committing a merge before patch selection...
r11237 merge = len(repo[None].parents()) > 1
if merge:
raise util.Abort(_('cannot partially commit a merge '
'(use hg commit instead)'))
Dirkjan Ochtman
record: minimize number of status calls
r7754 changes = repo.status(match=match)[:3]
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 diffopts = mdiff.diffopts(git=True, nodates=True)
Dirkjan Ochtman
record: minimize number of status calls
r7754 chunks = patch.diff(repo, changes=changes, opts=diffopts)
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 fp = cStringIO.StringIO()
Dirkjan Ochtman
patch: turn patch.diff() into a generator...
r7308 fp.write(''.join(chunks))
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 fp.seek(0)
Kirill Smelkov
record: refactor record into generic record driver...
r5827 # 1. filter patch, so we have intending-to apply subset of it
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 chunks = filterpatch(ui, parsepatch(fp))
del fp
Martin Geisler
replace set-like dictionaries with real sets...
r8152 contenders = set()
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 for h in chunks:
Matt Mackall
many, many trivial check-code fixups
r10282 try:
contenders.update(set(h.files()))
except AttributeError:
pass
Thomas Arendsen Hein
Remove trailing spaces, fix indentation
r5143
Dirkjan Ochtman
record: minimize number of status calls
r7754 changed = changes[0] + changes[1] + changes[2]
newfiles = [f for f in changed if f in contenders]
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 if not newfiles:
ui.status(_('no changes to record\n'))
return 0
Martin Geisler
replace set-like dictionaries with real sets...
r8152 modified = set(changes[0])
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
Kirill Smelkov
record: refactor record into generic record driver...
r5827 # 2. backup changed files, so we can restore them in the end
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 backups = {}
backupdir = repo.join('record-backups')
try:
os.mkdir(backupdir)
except OSError, err:
Bryan O'Sullivan
record: raise an exception correctly if we can't create a backup directory
r5129 if err.errno != errno.EEXIST:
raise
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 try:
Kirill Smelkov
record: refactor record into generic record driver...
r5827 # backup continues
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 for f in newfiles:
if f not in modified:
continue
fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.',
dir=backupdir)
os.close(fd)
Martin Geisler
do not attempt to translate ui.debug output
r9467 ui.debug('backup %r as %r\n' % (f, tmpname))
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 util.copyfile(repo.wjoin(f), tmpname)
backups[f] = tmpname
fp = cStringIO.StringIO()
for c in chunks:
if c.filename() in backups:
c.write(fp)
dopatch = fp.tell()
fp.seek(0)
Kirill Smelkov
record: refactor record into generic record driver...
r5827 # 3a. apply filtered patch to clean repo (clean)
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 if backups:
Renato Cunha
record: removed 'has_key' usage...
r11564 hg.revert(repo, repo.dirstate.parents()[0],
lambda key: key in backups)
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
Kirill Smelkov
record: refactor record into generic record driver...
r5827 # 3b. (apply)
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 if dopatch:
Dirkjan Ochtman
record: catch PatchErrors from internalpatch and display error message...
r6950 try:
Martin Geisler
do not attempt to translate ui.debug output
r9467 ui.debug('applying patch\n')
Dirkjan Ochtman
record: catch PatchErrors from internalpatch and display error message...
r6950 ui.debug(fp.getvalue())
Steve Borho
record: do not lose permission changes on commit
r7718 pfiles = {}
Patrick Mezard
Make mq, record and transplant honor patch.eol
r8811 patch.internalpatch(fp, ui, 1, repo.root, files=pfiles,
eolmode=None)
Steve Borho
record: do not lose permission changes on commit
r7718 patch.updatedir(ui, repo, pfiles)
Dirkjan Ochtman
record: catch PatchErrors from internalpatch and display error message...
r6950 except patch.PatchError, err:
s = str(err)
if s:
raise util.Abort(s)
else:
raise util.Abort(_('patch failed to apply'))
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 del fp
Kirill Smelkov
record: refactor record into generic record driver...
r5827 # 4. We prepared working directory according to filtered patch.
# Now is the time to delegate the job to commit/qrefresh or the like!
# it is important to first chdir to repo root -- we'll call a
# highlevel command with list of pathnames relative to repo root
cwd = os.getcwd()
os.chdir(repo.root)
try:
Dan Villiom Podlaski Christiansen
record: function variable naming & signature cleanup....
r10323 commitfunc(ui, repo, *newfiles, **opts)
Kirill Smelkov
record: refactor record into generic record driver...
r5827 finally:
os.chdir(cwd)
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 return 0
finally:
Kirill Smelkov
record: refactor record into generic record driver...
r5827 # 5. finally restore backed-up files
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 try:
for realname, tmpname in backups.iteritems():
Martin Geisler
do not attempt to translate ui.debug output
r9467 ui.debug('restoring %r to %r\n' % (tmpname, realname))
Bryan O'Sullivan
record: work properly if invoked in a subdirectory
r5128 util.copyfile(tmpname, repo.wjoin(realname))
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 os.unlink(tmpname)
os.rmdir(backupdir)
except OSError:
pass
Brodie Rao
record: make use of output labeling
r10825
# wrap ui.write so diff output can be labeled/colorized
def wrapwrite(orig, *args, **kw):
label = kw.pop('label', '')
for chunk, l in patch.difflabel(lambda: args):
orig(chunk, label=label + l)
oldwrite = ui.write
extensions.wrapfunction(ui, 'write', wrapwrite)
try:
return cmdutil.commit(ui, repo, recordfunc, pats, opts)
finally:
ui.write = oldwrite
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
cmdtable = {
Thomas Arendsen Hein
Update style of record's cmdtable to match mercurial/commands.py
r5040 "record":
(record,
Kirill Smelkov
hg qrecord -- like record, but for mq...
r5830
# add commit options
commands.table['^commit|ci'][1],
Thomas Arendsen Hein
Update style of record's cmdtable to match mercurial/commands.py
r5040 _('hg record [OPTION]... [FILE]...')),
}
Kirill Smelkov
hg qrecord -- like record, but for mq...
r5830
Martin Geisler
record: use uisetup instead of extsetup to register qrecord...
r9710 def uisetup(ui):
Kirill Smelkov
hg qrecord -- like record, but for mq...
r5830 try:
mq = extensions.find('mq')
except KeyError:
return
qcmdtable = {
"qrecord":
(qrecord,
Kirill Smelkov
qrecord: record complements commit, so qrecord should complement qnew...
r5932 # add qnew options, except '--force'
Matt Mackall
mq: promote qnew, demote qinit in short help
r10890 [opt for opt in mq.cmdtable['^qnew'][1] if opt[1] != 'force'],
Kirill Smelkov
hg qrecord -- like record, but for mq...
r5830
Kirill Smelkov
qrecord: record complements commit, so qrecord should complement qnew...
r5932 _('hg qrecord [OPTION]... PATCH [FILE]...')),
Kirill Smelkov
hg qrecord -- like record, but for mq...
r5830 }
cmdtable.update(qcmdtable)