hgext/record.py
author Bryan O'Sullivan <bos@serpentine.com>
Tue, 31 Jul 2007 16:28:05 -0700
changeset 5037 b2607267236d
child 5040 4f34d9b2568e
permissions -rw-r--r--
Add record extension, giving darcs-like interactive hunk picking
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
5037
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     1
# record.py
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     2
#
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     3
# Copyright 2007 Bryan O'Sullivan <bos@serpentine.com>
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     4
#
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms of
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     6
# the GNU General Public License, incorporated herein by reference.
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     7
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     8
'''interactive change selection during commit'''
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
     9
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    10
from mercurial.i18n import _
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    11
from mercurial import cmdutil, commands, cmdutil, hg, mdiff, patch, revlog
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    12
from mercurial import util
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    13
import copy, cStringIO, errno, operator, os, re, shutil, tempfile
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    14
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    15
lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)')
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    16
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    17
def scanpatch(fp):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    18
    lr = patch.linereader(fp)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    19
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    20
    def scanwhile(first, p):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    21
        lines = [first]
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    22
        while True:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    23
            line = lr.readline()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    24
            if not line:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    25
                break
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    26
            if p(line):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    27
                lines.append(line)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    28
            else:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    29
                lr.push(line)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    30
                break
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    31
        return lines
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    32
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    33
    while True:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    34
        line = lr.readline()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    35
        if not line:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    36
            break
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    37
        if line.startswith('diff --git a/'):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    38
            def notheader(line):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    39
                s = line.split(None, 1)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    40
                return not s or s[0] not in ('---', 'diff')
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    41
            header = scanwhile(line, notheader)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    42
            fromfile = lr.readline()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    43
            if fromfile.startswith('---'):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    44
                tofile = lr.readline()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    45
                header += [fromfile, tofile]
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    46
            else:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    47
                lr.push(fromfile)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    48
            yield 'file', header
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    49
        elif line[0] == ' ':
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    50
            yield 'context', scanwhile(line, lambda l: l[0] in ' \\')
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    51
        elif line[0] in '-+':
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    52
            yield 'hunk', scanwhile(line, lambda l: l[0] in '-+\\')
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    53
        else:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    54
            m = lines_re.match(line)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    55
            if m:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    56
                yield 'range', m.groups()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    57
            else:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    58
                raise patch.PatchError('unknown patch content: %r' % line)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    59
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    60
class header(object):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    61
    diff_re = re.compile('diff --git a/(.*) b/(.*)$')
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    62
    allhunks_re = re.compile('(?:index|new file|deleted file) ')
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    63
    pretty_re = re.compile('(?:new file|deleted file) ')
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    64
    special_re = re.compile('(?:index|new|deleted|copy|rename) ')
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    65
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    66
    def __init__(self, header):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    67
        self.header = header
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    68
        self.hunks = []
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    69
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    70
    def binary(self):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    71
        for h in self.header:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    72
            if h.startswith('index '):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    73
                return True
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    74
        
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    75
    def pretty(self, fp):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    76
        for h in self.header:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    77
            if h.startswith('index '):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    78
                fp.write(_('this modifies a binary file (all or nothing)\n'))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    79
                break
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    80
            if self.pretty_re.match(h):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    81
                fp.write(h)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    82
                if self.binary():
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    83
                    fp.write(_('this is a binary file\n'))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    84
                break
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    85
            if h.startswith('---'):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    86
                fp.write(_('%d hunks, %d lines changed\n') %
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    87
                         (len(self.hunks),
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    88
                          sum([h.added + h.removed for h in self.hunks])))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    89
                break
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    90
            fp.write(h)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    91
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    92
    def write(self, fp):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    93
        fp.write(''.join(self.header))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    94
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    95
    def allhunks(self):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    96
        for h in self.header:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    97
            if self.allhunks_re.match(h):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    98
                return True
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
    99
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   100
    def files(self):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   101
        fromfile, tofile = self.diff_re.match(self.header[0]).groups()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   102
        if fromfile == tofile:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   103
            return [fromfile]
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   104
        return [fromfile, tofile]
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   105
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   106
    def filename(self):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   107
        return self.files()[-1]
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   108
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   109
    def __repr__(self):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   110
        return '<header %s>' % (' '.join(map(repr, self.files())))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   111
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   112
    def special(self):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   113
        for h in self.header:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   114
            if self.special_re.match(h):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   115
                return True
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   116
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   117
def countchanges(hunk):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   118
    add = len([h for h in hunk if h[0] == '+'])
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   119
    rem = len([h for h in hunk if h[0] == '-'])
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   120
    return add, rem
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   121
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   122
class hunk(object):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   123
    maxcontext = 3
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   124
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   125
    def __init__(self, header, fromline, toline, proc, before, hunk, after):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   126
        def trimcontext(number, lines):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   127
            delta = len(lines) - self.maxcontext
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   128
            if False and delta > 0:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   129
                return number + delta, lines[:self.maxcontext]
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   130
            return number, lines
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   131
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   132
        self.header = header
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   133
        self.fromline, self.before = trimcontext(fromline, before)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   134
        self.toline, self.after = trimcontext(toline, after)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   135
        self.proc = proc
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   136
        self.hunk = hunk
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   137
        self.added, self.removed = countchanges(self.hunk)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   138
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   139
    def write(self, fp):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   140
        delta = len(self.before) + len(self.after)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   141
        fromlen = delta + self.removed
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   142
        tolen = delta + self.added
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   143
        fp.write('@@ -%d,%d +%d,%d @@%s\n' %
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   144
                 (self.fromline, fromlen, self.toline, tolen,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   145
                  self.proc and (' ' + self.proc)))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   146
        fp.write(''.join(self.before + self.hunk + self.after))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   147
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   148
    pretty = write
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   149
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   150
    def filename(self):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   151
        return self.header.filename()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   152
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   153
    def __repr__(self):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   154
        return '<hunk %r@%d>' % (self.filename(), self.fromline)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   155
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   156
def parsepatch(fp):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   157
    class parser(object):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   158
        def __init__(self):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   159
            self.fromline = 0
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   160
            self.toline = 0
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   161
            self.proc = ''
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   162
            self.header = None
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   163
            self.context = []
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   164
            self.before = []
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   165
            self.hunk = []
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   166
            self.stream = []
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   167
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   168
        def addrange(self, (fromstart, fromend, tostart, toend, proc)):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   169
            self.fromline = int(fromstart)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   170
            self.toline = int(tostart)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   171
            self.proc = proc
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   172
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   173
        def addcontext(self, context):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   174
            if self.hunk:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   175
                h = hunk(self.header, self.fromline, self.toline, self.proc,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   176
                         self.before, self.hunk, context)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   177
                self.header.hunks.append(h)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   178
                self.stream.append(h)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   179
                self.fromline += len(self.before) + h.removed
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   180
                self.toline += len(self.before) + h.added
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   181
                self.before = []
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   182
                self.hunk = []
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   183
                self.proc = ''
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   184
            self.context = context
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   185
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   186
        def addhunk(self, hunk):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   187
            if self.context:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   188
                self.before = self.context
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   189
                self.context = []
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   190
            self.hunk = data
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   191
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   192
        def newfile(self, hdr):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   193
            self.addcontext([])
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   194
            h = header(hdr)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   195
            self.stream.append(h)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   196
            self.header = h
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   197
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   198
        def finished(self):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   199
            self.addcontext([])
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   200
            return self.stream
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   201
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   202
        transitions = {
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   203
            'file': {'context': addcontext,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   204
                     'file': newfile,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   205
                     'hunk': addhunk,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   206
                     'range': addrange},
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   207
            'context': {'file': newfile,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   208
                        'hunk': addhunk,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   209
                        'range': addrange},
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   210
            'hunk': {'context': addcontext,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   211
                     'file': newfile,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   212
                     'range': addrange},
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   213
            'range': {'context': addcontext,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   214
                      'hunk': addhunk},
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   215
            }
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   216
             
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   217
    p = parser()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   218
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   219
    state = 'context'
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   220
    for newstate, data in scanpatch(fp):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   221
        try:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   222
            p.transitions[state][newstate](p, data)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   223
        except KeyError:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   224
            raise patch.PatchError('unhandled transition: %s -> %s' %
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   225
                                   (state, newstate))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   226
        state = newstate
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   227
    return p.finished()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   228
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   229
def filterpatch(ui, chunks):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   230
    chunks = list(chunks)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   231
    chunks.reverse()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   232
    seen = {}
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   233
    def consumefile():
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   234
        consumed = []
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   235
        while chunks:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   236
            if isinstance(chunks[-1], header):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   237
                break
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   238
            else:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   239
                consumed.append(chunks.pop())
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   240
        return consumed
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   241
    resp = None
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   242
    applied = {}
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   243
    while chunks:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   244
        chunk = chunks.pop()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   245
        if isinstance(chunk, header):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   246
            fixoffset = 0
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   247
            hdr = ''.join(chunk.header)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   248
            if hdr in seen:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   249
                consumefile()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   250
                continue
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   251
            seen[hdr] = True
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   252
            if not resp:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   253
                chunk.pretty(ui)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   254
            r = resp or ui.prompt(_('record changes to %s? [y]es [n]o') %
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   255
                                  _(' and ').join(map(repr, chunk.files())),
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   256
                                  '(?:|[yYnNqQaA])$') or 'y'
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   257
            if r in 'aA':
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   258
                r = 'y'
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   259
                resp = 'y'
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   260
            if r in 'qQ':
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   261
                raise util.Abort(_('user quit'))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   262
            if r in 'yY':
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   263
                applied[chunk.filename()] = [chunk]
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   264
                if chunk.allhunks():
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   265
                    applied[chunk.filename()] += consumefile()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   266
            else:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   267
                consumefile()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   268
        else:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   269
            if not resp:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   270
                chunk.pretty(ui)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   271
            r = resp or ui.prompt(_('record this change to %r? [y]es [n]o') %
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   272
                                  chunk.filename(), '(?:|[yYnNqQaA])$') or 'y'
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   273
            if r in 'aA':
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   274
                r = 'y'
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   275
                resp = 'y'
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   276
            if r in 'qQ':
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   277
                raise util.Abort(_('user quit'))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   278
            if r in 'yY':
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   279
                if fixoffset:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   280
                    chunk = copy.copy(chunk)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   281
                    chunk.toline += fixoffset
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   282
                applied[chunk.filename()].append(chunk)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   283
            else:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   284
                fixoffset += chunk.removed - chunk.added
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   285
    return reduce(operator.add, [h for h in applied.itervalues()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   286
                                 if h[0].special() or len(h) > 1], [])
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   287
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   288
def record(ui, repo, *pats, **opts):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   289
    '''interactively select changes to commit'''
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   290
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   291
    if not ui.interactive:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   292
        raise util.Abort(_('running non-interactively, use commit instead'))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   293
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   294
    def recordfunc(ui, repo, files, message, match, opts):
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   295
        if files:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   296
            changes = None
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   297
        else:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   298
            changes = repo.status(files=files, match=match)[:5]
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   299
            modified, added, removed = changes[:3]
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   300
            files = modified + added + removed
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   301
        diffopts = mdiff.diffopts(git=True, nodates=True)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   302
        fp = cStringIO.StringIO()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   303
        patch.diff(repo, repo.dirstate.parents()[0], files=files,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   304
                   match=match, changes=changes, opts=diffopts, fp=fp)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   305
        fp.seek(0)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   306
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   307
        chunks = filterpatch(ui, parsepatch(fp))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   308
        del fp
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   309
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   310
        contenders = {}
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   311
        for h in chunks:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   312
            try: contenders.update(dict.fromkeys(h.files()))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   313
            except AttributeError: pass
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   314
            
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   315
        newfiles = [f for f in files if f in contenders]
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   316
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   317
        if not newfiles:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   318
            ui.status(_('no changes to record\n'))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   319
            return 0
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   320
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   321
        if changes is None:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   322
            changes = repo.status(files=newfiles, match=match)[:5]
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   323
        modified = dict.fromkeys(changes[0])
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   324
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   325
        backups = {}
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   326
        backupdir = repo.join('record-backups')
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   327
        try:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   328
            os.mkdir(backupdir)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   329
        except OSError, err:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   330
            if err.errno == errno.EEXIST:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   331
                pass
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   332
        try:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   333
            for f in newfiles:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   334
                if f not in modified:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   335
                    continue
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   336
                fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.',
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   337
                                               dir=backupdir)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   338
                os.close(fd)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   339
                ui.debug('backup %r as %r\n' % (f, tmpname))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   340
                util.copyfile(repo.wjoin(f), tmpname)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   341
                backups[f] = tmpname
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   342
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   343
            fp = cStringIO.StringIO()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   344
            for c in chunks:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   345
                if c.filename() in backups:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   346
                    c.write(fp)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   347
            dopatch = fp.tell()
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   348
            fp.seek(0)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   349
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   350
            if backups:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   351
                hg.revert(repo, repo.dirstate.parents()[0], backups.has_key)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   352
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   353
            if dopatch:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   354
                ui.debug('applying patch\n')
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   355
                ui.debug(fp.getvalue())
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   356
                patch.internalpatch(fp, ui, 1, repo.root)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   357
            del fp
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   358
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   359
            repo.commit(newfiles, message, opts['user'], opts['date'], match,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   360
                        force_editor=opts.get('force_editor'))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   361
            return 0
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   362
        finally:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   363
            try:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   364
                for realname, tmpname in backups.iteritems():
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   365
                    ui.debug('restoring %r to %r\n' % (tmpname, realname))
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   366
                    util.copyfile(tmpname, realname)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   367
                    os.unlink(tmpname)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   368
                os.rmdir(backupdir)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   369
            except OSError:
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   370
                pass
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   371
    return cmdutil.commit(ui, repo, recordfunc, pats, opts)
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   372
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   373
cmdtable = {
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   374
    'record':
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   375
    (record, [('A', 'addremove', None,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   376
               _('mark new/missing files as added/removed before committing')),
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   377
              ('d', 'date', '', _('record datecode as commit date')),
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   378
              ('u', 'user', '', _('record user as commiter')),
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   379
              ] + commands.walkopts + commands.commitopts,
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   380
     _('hg record [FILE]...')),
b2607267236d Add record extension, giving darcs-like interactive hunk picking
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
   381
    }