##// END OF EJS Templates
patch: stop updating changed files set in applydiff()...
patch: stop updating changed files set in applydiff() This information is more correctly returned by backends. The extra updated file removed from test-mq-merge.t output came from changes from git patches being counted before being really applied in some cases.

File last commit:

r14441:39e81b93 default
r14565:3cacc232 default
Show More
record.py
585 lines | 19.6 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
Brodie Rao
record: move copystat() hack out of util.copyfile() and into record...
r13099 import copy, cStringIO, errno, os, re, shutil, tempfile
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
Idan Kamara
record: use cmdutil.command decorator
r14408 cmdtable = {}
command = cmdutil.command(cmdtable)
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
Steve Borho
record: teach parsepatch() about non-git style headers...
r13157 if line.startswith('diff --git a/') or line.startswith('diff -r '):
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 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 """
Steve Borho
record: teach parsepatch() about non-git style headers...
r13157 diffgit_re = re.compile('diff --git a/(.*) b/(.*)$')
diff_re = re.compile('diff -r .* (.*)$')
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 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):
Patrick Mezard
record: simplify header methods with util.any
r13294 return util.any(h.startswith('index ') for h in self.header)
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),
timeless
record: count lines changed as the number of lines added or removed...
r11728 sum([max(h.added, h.removed) for h in self.hunks])))
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 break
fp.write(h)
def write(self, fp):
fp.write(''.join(self.header))
def allhunks(self):
Patrick Mezard
record: simplify header methods with util.any
r13294 return util.any(self.allhunks_re.match(h) for h in self.header)
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
def files(self):
Steve Borho
record: teach parsepatch() about non-git style headers...
r13157 match = self.diffgit_re.match(self.header[0])
if match:
fromfile, tofile = match.groups()
if fromfile == tofile:
return [fromfile]
return [fromfile, tofile]
else:
return self.diff_re.match(self.header[0]).groups()
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
def filename(self):
return self.files()[-1]
def __repr__(self):
return '<header %s>' % (' '.join(map(repr, self.files())))
def special(self):
Patrick Mezard
record: simplify header methods with util.any
r13294 return util.any(self.special_re.match(h) for h in self.header)
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
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):
Patrick Mezard
record: refactor the prompt loop...
r13293 """patch -> [] of headers -> [] 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 = []
Patrick Mezard
record: refactor the prompt loop...
r13293 self.headers = []
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
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.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)
Patrick Mezard
record: refactor the prompt loop...
r13293 self.headers.append(h)
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 self.header = h
def finished(self):
self.addcontext([])
Patrick Mezard
record: refactor the prompt loop...
r13293 return self.headers
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
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()
Patrick Mezard
record: refactor the prompt loop...
r13293 def filterpatch(ui, headers):
Kirill Smelkov
record: some docs...
r5826 """Interactively filter patch chunks into applied-only chunks"""
Patrick Mezard
record: turn prompt() into a pure function
r13291 def prompt(skipfile, skipall, 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)
Patrick Mezard
record: turn prompt() into a pure function
r13291 Return True/False and possibly updated skipfile and skipall.
Kirill Smelkov
record: some docs...
r5826 """
Patrick Mezard
record: turn prompt() into a pure function
r13291 if skipall is not None:
return skipall, skipfile, skipall
if skipfile is not None:
return skipfile, skipfile, skipall
Bryan O'Sullivan
record: improve docs, improve prompts
r5154 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
Patrick Mezard
record: turn prompt() into a pure function
r13291 ret = skipfile = False
Simon Heimberg
ui: extract choice from prompt...
r9048 elif r == 3: # file (Record remaining)
Patrick Mezard
record: turn prompt() into a pure function
r13291 ret = skipfile = True
Simon Heimberg
ui: extract choice from prompt...
r9048 elif r == 4: # done, skip remaining
Patrick Mezard
record: turn prompt() into a pure function
r13291 ret = skipall = False
Simon Heimberg
ui: extract choice from prompt...
r9048 elif r == 5: # all
Patrick Mezard
record: turn prompt() into a pure function
r13291 ret = skipall = 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'))
Patrick Mezard
record: turn prompt() into a pure function
r13291 return ret, skipfile, skipall
seen = set()
applied = {} # 'filename' -> [] of chunks
skipfile, skipall = None, None
Patrick Mezard
record: do not include files into changes count...
r13295 pos, total = 1, sum(len(h.hunks) for h in headers)
Patrick Mezard
record: refactor the prompt loop...
r13293 for h in headers:
Patrick Mezard
record: do not include files into changes count...
r13295 pos += len(h.hunks)
Patrick Mezard
record: refactor the prompt loop...
r13293 skipfile = None
fixoffset = 0
hdr = ''.join(h.header)
if hdr in seen:
continue
seen.add(hdr)
if skipall is None:
h.pretty(ui)
msg = (_('examine changes to %s?') %
_(' and ').join(map(repr, h.files())))
r, skipfile, skipall = prompt(skipfile, skipall, msg)
if not r:
continue
applied[h.filename()] = [h]
if h.allhunks():
applied[h.filename()] += h.hunks
continue
for i, chunk in enumerate(h.hunks):
Patrick Mezard
record: turn prompt() into a pure function
r13291 if skipfile is None and skipall is None:
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 chunk.pretty(ui)
Martin Geisler
record: replace poor man's if-statement with real if-statement
r13773 if total == 1:
msg = _('record this change to %r?') % chunk.filename()
else:
idx = pos - len(h.hunks) + i
msg = _('record change %d/%d to %r?') % (idx, total,
chunk.filename())
Patrick Mezard
record: turn prompt() into a pure function
r13291 r, skipfile, skipall = prompt(skipfile, skipall, msg)
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
Idan Kamara
record: use cmdutil.command decorator
r14408 @command("record",
commands.table['^commit|ci'][1], # same options as commit
_('hg record [OPTION]... [FILE]...'))
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
Idan Kamara
record: add an option to backup all wc modifications...
r14425 dorecord(ui, repo, commands.commit, 'commit', False, *pats, **opts)
Kirill Smelkov
hg qrecord -- like record, but for mq...
r5830
Idan Kamara
record: add qrefresh -i/--interactive...
r14426 def qrefresh(ui, repo, *pats, **opts):
mq = extensions.find('mq')
def committomq(ui, repo, *pats, **opts):
# At this point the working copy contains only changes that
# were accepted. All other changes were reverted.
# We can't pass *pats here since qrefresh will undo all other
# changed files in the patch that aren't in pats.
mq.refresh(ui, repo, **opts)
# backup all changed files
dorecord(ui, repo, committomq, 'qrefresh', True, *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"))
Idan Kamara
record: check patch name is valid before prompting in qrecord
r14424 repo.mq.checkpatchname(patch)
Dan Villiom Podlaski Christiansen
record: function variable naming & signature cleanup....
r10323 def committomq(ui, repo, *pats, **opts):
Idan Kamara
record: check patch name is valid before prompting in qrecord
r14424 opts['checkname'] = False
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
Idan Kamara
record: add an option to backup all wc modifications...
r14425 dorecord(ui, repo, committomq, 'qnew', False, *pats, **opts)
Kirill Smelkov
record: refactor record into generic record driver...
r5827
Idan Kamara
record: add an option to backup all wc modifications...
r14425 def dorecord(ui, repo, commitfunc, cmdsuggest, backupall, *pats, **opts):
Matt Mackall
ui: make interactive a method
r8208 if not ui.interactive():
Idan Kamara
record: suggest the right command when running non interactively
r14407 raise util.Abort(_('running non-interactively, use %s instead') %
cmdsuggest)
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037
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.
Kevin Bullock
record: clean up comments and docstrings...
r13195 Its job is to interactively filter local changes, and
accordingly prepare working directory into a state in which the
job can be delegated to a non-interactive commit command such as
'commit' or 'qrefresh'.
Kirill Smelkov
record: refactor record into generic record driver...
r5827
Kevin Bullock
record: clean up comments and docstrings...
r13195 After the actual job is done by non-interactive command, the
working directory is restored to its original state.
Kirill Smelkov
record: refactor record into generic record driver...
r5827
Kevin Bullock
record: clean up comments and docstrings...
r13195 In the end we'll record interesting changes, and everything else
will be left in place, so the user can continue working.
Kirill Smelkov
record: refactor record into generic record driver...
r5827 """
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 '
timeless
record: quote command in use hg commit message
r13023 '(use "hg commit" instead)'))
Nicolas Dumazet
record: check that we are not committing a merge before patch selection...
r11237
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
Idan Kamara
record: add an option to backup all wc modifications...
r14425 if backupall:
tobackup = changed
else:
tobackup = [f for f in newfiles if f in modified]
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 backups = {}
Idan Kamara
record: add an option to backup all wc modifications...
r14425 if tobackup:
backupdir = repo.join('record-backups')
try:
os.mkdir(backupdir)
except OSError, err:
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
Idan Kamara
record: add an option to backup all wc modifications...
r14425 for f in tobackup:
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 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)
Brodie Rao
record: move copystat() hack out of util.copyfile() and into record...
r13099 shutil.copystat(repo.wjoin(f), tmpname)
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 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:
Matt Mackall
misc: replace .parents()[0] with p1()
r13878 hg.revert(repo, repo.dirstate.p1(),
Renato Cunha
record: removed 'has_key' usage...
r11564 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())
Patrick Mezard
patch: add a workingbackend dirstate layer on top of fsbackend...
r14370 patch.internalpatch(ui, repo, fp, 1, eolmode=None)
Dirkjan Ochtman
record: catch PatchErrors from internalpatch and display error message...
r6950 except patch.PatchError, err:
Patrick Mezard
patch: always raise PatchError with a message, simplify handling
r12674 raise util.Abort(str(err))
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 del fp
Kevin Bullock
record: clean up comments and docstrings...
r13195 # 4. We prepared working directory according to filtered
# patch. Now is the time to delegate the job to
# commit/qrefresh or the like!
Kirill Smelkov
record: refactor record into generic record driver...
r5827
Kevin Bullock
record: clean up comments and docstrings...
r13195 # it is important to first chdir to repo root -- we'll call
# a highlevel command with list of pathnames relative to
# repo root
Kirill Smelkov
record: refactor record into generic record driver...
r5827 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))
Brodie Rao
record: move copystat() hack out of util.copyfile() and into record...
r13099 # Our calls to copystat() here and above are a
# hack to trick any editors that have f open that
# we haven't modified them.
#
# Also note that this racy as an editor could
# notice the file's mtime before we've finished
# writing it.
shutil.copystat(tmpname, repo.wjoin(realname))
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 os.unlink(tmpname)
Idan Kamara
record: add an option to backup all wc modifications...
r14425 if tobackup:
os.rmdir(backupdir)
Bryan O'Sullivan
Add record extension, giving darcs-like interactive hunk picking
r5037 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
Idan Kamara
record: use cmdutil.command decorator
r14408 cmdtable["qrecord"] = \
Idan Kamara
record: fix options placeholder
r14441 (qrecord, [], # placeholder until mq is available
Idan Kamara
record: use cmdutil.command decorator
r14408 _('hg qrecord [OPTION]... PATCH [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
Idan Kamara
record: use cmdutil.command decorator
r14408 cmdtable["qrecord"] = \
Idan Kamara
record: alias qrecord to qnew -i/--interactive
r14427 (qrecord,
# same options as qnew, but copy them so we don't get
# -i/--interactive for qrecord
mq.cmdtable['^qnew'][1][:],
Idan Kamara
record: use cmdutil.command decorator
r14408 _('hg qrecord [OPTION]... PATCH [FILE]...'))
Idan Kamara
record: add qrefresh -i/--interactive...
r14426
Idan Kamara
record: alias qrecord to qnew -i/--interactive
r14427 _wrapcmd('qnew', mq.cmdtable, qrecord, _("interactively record a new patch"))
Idan Kamara
record: add qrefresh -i/--interactive...
r14426 _wrapcmd('qrefresh', mq.cmdtable, qrefresh,
_("interactively select changes to refresh"))
def _wrapcmd(cmd, table, wrapfn, msg):
'''wrap the command'''
def wrapper(orig, *args, **kwargs):
if kwargs['interactive']:
return wrapfn(*args, **kwargs)
return orig(*args, **kwargs)
entry = extensions.wrapcommand(table, cmd, wrapper)
entry[1].append(('i', 'interactive', None, msg))