Mercurial > hg
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': |