~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/patches.py

  • Committer: Kit Randel
  • Date: 2014-12-11 23:42:15 UTC
  • mto: This revision was merged to the branch mainline in revision 6602.
  • Revision ID: kit.randel@canonical.com-20141211234215-fk501pdccnat6qlu
change of plan, don't track modified state, just preserve dirty_heads if requested in parse_patches

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
 
32
32
binary_files_re = 'Binary files (.*) and (.*) differ\n'
33
33
 
 
34
 
34
35
def get_patch_names(iter_lines):
35
 
    modified_header = False
36
36
    line = iter_lines.next()
37
 
 
38
 
    if line.startswith("=== "):
39
 
        modified_header = True
40
 
        line = iter_lines.next()
41
 
 
42
37
    try:
43
38
        match = re.match(binary_files_re, line)
44
39
        if match is not None:
57
52
            mod_name = line[4:].rstrip("\n")
58
53
    except StopIteration:
59
54
        raise MalformedPatchHeader("No mod line", "")
60
 
    return (orig_name, mod_name, modified_header)
 
55
    return (orig_name, mod_name)
61
56
 
62
57
 
63
58
def parse_range(textrange):
260
255
 
261
256
 
262
257
class BinaryPatch(object):
263
 
    def __init__(self, oldname, newname, modified=False):
 
258
    def __init__(self, oldname, newname):
264
259
        self.oldname = oldname
265
260
        self.newname = newname
266
 
        self.modified = modified  # patch has file modified header
267
261
 
268
262
    def __str__(self):
269
263
        return 'Binary files %s and %s differ\n' % (self.oldname, self.newname)
271
265
 
272
266
class Patch(BinaryPatch):
273
267
 
274
 
    def __init__(self, oldname, newname, modified):
275
 
        BinaryPatch.__init__(self, oldname, newname, modified)
 
268
    def __init__(self, oldname, newname):
 
269
        BinaryPatch.__init__(self, oldname, newname)
276
270
        self.hunks = []
277
271
 
278
272
    def __str__(self):
280
274
        ret += "".join([str(h) for h in self.hunks])
281
275
        return ret
282
276
 
283
 
    def get_modified_header(self):
284
 
        if self.modified:
285
 
            return "=== modified file '%s'" % self.oldname
286
 
 
287
277
    def get_header(self):
288
278
        return "--- %s\n+++ %s\n" % (self.oldname, self.newname)
289
279
 
328
318
                if isinstance(line, ContextLine):
329
319
                    pos += 1
330
320
 
331
 
 
332
321
def parse_patch(iter_lines, allow_dirty=False):
333
322
    '''
334
323
    :arg iter_lines: iterable of lines to parse
337
326
    '''
338
327
    iter_lines = iter_lines_handle_nl(iter_lines)
339
328
    try:
340
 
        (orig_name, mod_name, modified) = get_patch_names(iter_lines)
 
329
        (orig_name, mod_name) = get_patch_names(iter_lines)
341
330
    except BinaryFiles, e:
342
331
        return BinaryPatch(e.orig_name, e.mod_name)
343
332
    else:
344
 
        patch = Patch(orig_name, mod_name, modified)
 
333
        patch = Patch(orig_name, mod_name)
345
334
        for hunk in iter_hunks(iter_lines, allow_dirty):
346
335
            patch.hunks.append(hunk)
347
336
        return patch
348
337
 
349
338
 
350
 
def iter_file_patch(iter_lines, allow_dirty=False):
 
339
def iter_file_patch(iter_lines, allow_dirty=False, keep_dirty=False):
351
340
    '''
352
341
    :arg iter_lines: iterable of lines to parse for patches
353
342
    :kwarg allow_dirty: If True, allow comments and other non-patch text
363
352
    # (as allow_dirty does).
364
353
    regex = re.compile(binary_files_re)
365
354
    saved_lines = []
 
355
    dirty_head = []
366
356
    orig_range = 0
367
357
    beginning = True
368
 
    modified_header = False
369
358
    for line in iter_lines:
370
359
        if line.startswith('=== '):
371
 
            modified_header = True
 
360
            dirty_head.append(line)
 
361
            continue
372
362
        if line.startswith('*** '):
373
363
            continue
374
364
        if line.startswith('#'):
384
374
                beginning = False
385
375
            elif len(saved_lines) > 0:
386
376
                yield saved_lines
387
 
            if not modified_header:
388
 
                saved_lines = []
 
377
            saved_lines = []
389
378
        elif line.startswith('@@'):
390
379
            hunk = hunk_from_header(line)
391
380
            orig_range = hunk.orig_range
392
381
        saved_lines.append(line)
393
382
    if len(saved_lines) > 0:
394
 
        yield saved_lines
 
383
        if keep_dirty:
 
384
            yield (saved_lines, dirty_head)
 
385
        else:
 
386
            yield saved_lines
395
387
 
396
388
 
397
389
def iter_lines_handle_nl(iter_lines):
415
407
        yield last_line
416
408
 
417
409
 
418
 
def parse_patches(iter_lines, allow_dirty=False):
 
410
def parse_patches(iter_lines, allow_dirty=False, keep_dirty=False):
419
411
    '''
420
412
    :arg iter_lines: iterable of lines to parse for patches
421
413
    :kwarg allow_dirty: If True, allow text that's not part of the patch at
422
414
        selected places.  This includes comments before and after a patch
423
415
        for instance.  Default False.
 
416
    :kwarg keep_dirty: If True, returns a dict of patches with dirty headers.
 
417
        Default False.
424
418
    '''
 
419
    if keep_dirty:
 
420
        patches = []
 
421
        for lines, dirty in iter_file_patch(
 
422
                iter_lines, allow_dirty, keep_dirty):
 
423
            patches.append({'patch': parse_patch(lines, allow_dirty),
 
424
                            'dirty_head': dirty})
 
425
        return patches
425
426
    return [parse_patch(f.__iter__(), allow_dirty) for f in
426
 
                        iter_file_patch(iter_lines, allow_dirty)]
 
427
            iter_file_patch(iter_lines, allow_dirty, keep_dirty)]
427
428
 
428
429
 
429
430
def difference_index(atext, btext):