comparison hgext/record.py @ 5826:cc43d9f36ff2

record: some docs While studing record, I've written some docstrings and comments. Hope they are useful.
author Kirill Smelkov <kirr@mns.spb.ru>
date Thu, 10 Jan 2008 11:43:30 +0300
parents bc475d1f74ca
children 0c29977bd7db
comparison
equal deleted inserted replaced
5825:2b67acc404f6 5826:cc43d9f36ff2
13 import copy, cStringIO, errno, operator, os, re, shutil, tempfile 13 import copy, cStringIO, errno, operator, os, re, shutil, tempfile
14 14
15 lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)') 15 lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)')
16 16
17 def scanpatch(fp): 17 def scanpatch(fp):
18 """like patch.iterhunks, but yield different events
19
20 - ('file', [header_lines + fromfile + tofile])
21 - ('context', [context_lines])
22 - ('hunk', [hunk_lines])
23 - ('range', (-start,len, +start,len, diffp))
24 """
18 lr = patch.linereader(fp) 25 lr = patch.linereader(fp)
19 26
20 def scanwhile(first, p): 27 def scanwhile(first, p):
28 """scan lr while predicate holds"""
21 lines = [first] 29 lines = [first]
22 while True: 30 while True:
23 line = lr.readline() 31 line = lr.readline()
24 if not line: 32 if not line:
25 break 33 break
56 yield 'range', m.groups() 64 yield 'range', m.groups()
57 else: 65 else:
58 raise patch.PatchError('unknown patch content: %r' % line) 66 raise patch.PatchError('unknown patch content: %r' % line)
59 67
60 class header(object): 68 class header(object):
69 """patch header
70
71 XXX shoudn't we move this to mercurial/patch.py ?
72 """
61 diff_re = re.compile('diff --git a/(.*) b/(.*)$') 73 diff_re = re.compile('diff --git a/(.*) b/(.*)$')
62 allhunks_re = re.compile('(?:index|new file|deleted file) ') 74 allhunks_re = re.compile('(?:index|new file|deleted file) ')
63 pretty_re = re.compile('(?:new file|deleted file) ') 75 pretty_re = re.compile('(?:new file|deleted file) ')
64 special_re = re.compile('(?:index|new|deleted|copy|rename) ') 76 special_re = re.compile('(?:index|new|deleted|copy|rename) ')
65 77
113 for h in self.header: 125 for h in self.header:
114 if self.special_re.match(h): 126 if self.special_re.match(h):
115 return True 127 return True
116 128
117 def countchanges(hunk): 129 def countchanges(hunk):
130 """hunk -> (n+,n-)"""
118 add = len([h for h in hunk if h[0] == '+']) 131 add = len([h for h in hunk if h[0] == '+'])
119 rem = len([h for h in hunk if h[0] == '-']) 132 rem = len([h for h in hunk if h[0] == '-'])
120 return add, rem 133 return add, rem
121 134
122 class hunk(object): 135 class hunk(object):
136 """patch hunk
137
138 XXX shouldn't we merge this with patch.hunk ?
139 """
123 maxcontext = 3 140 maxcontext = 3
124 141
125 def __init__(self, header, fromline, toline, proc, before, hunk, after): 142 def __init__(self, header, fromline, toline, proc, before, hunk, after):
126 def trimcontext(number, lines): 143 def trimcontext(number, lines):
127 delta = len(lines) - self.maxcontext 144 delta = len(lines) - self.maxcontext
152 169
153 def __repr__(self): 170 def __repr__(self):
154 return '<hunk %r@%d>' % (self.filename(), self.fromline) 171 return '<hunk %r@%d>' % (self.filename(), self.fromline)
155 172
156 def parsepatch(fp): 173 def parsepatch(fp):
174 """patch -> [] of hunks """
157 class parser(object): 175 class parser(object):
176 """patch parsing state machine"""
158 def __init__(self): 177 def __init__(self):
159 self.fromline = 0 178 self.fromline = 0
160 self.toline = 0 179 self.toline = 0
161 self.proc = '' 180 self.proc = ''
162 self.header = None 181 self.header = None
225 (state, newstate)) 244 (state, newstate))
226 state = newstate 245 state = newstate
227 return p.finished() 246 return p.finished()
228 247
229 def filterpatch(ui, chunks): 248 def filterpatch(ui, chunks):
249 """Interactively filter patch chunks into applied-only chunks"""
230 chunks = list(chunks) 250 chunks = list(chunks)
231 chunks.reverse() 251 chunks.reverse()
232 seen = {} 252 seen = {}
233 def consumefile(): 253 def consumefile():
254 """fetch next portion from chunks until a 'header' is seen
255 NB: header == new-file mark
256 """
234 consumed = [] 257 consumed = []
235 while chunks: 258 while chunks:
236 if isinstance(chunks[-1], header): 259 if isinstance(chunks[-1], header):
237 break 260 break
238 else: 261 else:
239 consumed.append(chunks.pop()) 262 consumed.append(chunks.pop())
240 return consumed 263 return consumed
241 resp_all = [None] 264
242 resp_file = [None] 265 resp_all = [None] # this two are changed from inside prompt,
243 applied = {} 266 resp_file = [None] # so can't be usual variables
267 applied = {} # 'filename' -> [] of chunks
244 def prompt(query): 268 def prompt(query):
269 """prompt query, and process base inputs
270
271 - y/n for the rest of file
272 - y/n for the rest
273 - ? (help)
274 - q (quit)
275
276 else, input is returned to the caller.
277 """
245 if resp_all[0] is not None: 278 if resp_all[0] is not None:
246 return resp_all[0] 279 return resp_all[0]
247 if resp_file[0] is not None: 280 if resp_file[0] is not None:
248 return resp_file[0] 281 return resp_file[0]
249 while True: 282 while True:
266 raise util.Abort(_('user quit')) 299 raise util.Abort(_('user quit'))
267 return r 300 return r
268 while chunks: 301 while chunks:
269 chunk = chunks.pop() 302 chunk = chunks.pop()
270 if isinstance(chunk, header): 303 if isinstance(chunk, header):
304 # new-file mark
271 resp_file = [None] 305 resp_file = [None]
272 fixoffset = 0 306 fixoffset = 0
273 hdr = ''.join(chunk.header) 307 hdr = ''.join(chunk.header)
274 if hdr in seen: 308 if hdr in seen:
275 consumefile() 309 consumefile()
284 if chunk.allhunks(): 318 if chunk.allhunks():
285 applied[chunk.filename()] += consumefile() 319 applied[chunk.filename()] += consumefile()
286 else: 320 else:
287 consumefile() 321 consumefile()
288 else: 322 else:
323 # new hunk
289 if resp_file[0] is None and resp_all[0] is None: 324 if resp_file[0] is None and resp_all[0] is None:
290 chunk.pretty(ui) 325 chunk.pretty(ui)
291 r = prompt(_('record this change to %r?') % 326 r = prompt(_('record this change to %r?') %
292 chunk.filename()) 327 chunk.filename())
293 if r == 'y': 328 if r == 'y':