1*fb1b10abSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*fb1b10abSAndroid Build Coastguard Worker## Copyright (c) 2012 The WebM project authors. All Rights Reserved. 3*fb1b10abSAndroid Build Coastguard Worker## 4*fb1b10abSAndroid Build Coastguard Worker## Use of this source code is governed by a BSD-style license 5*fb1b10abSAndroid Build Coastguard Worker## that can be found in the LICENSE file in the root of the source 6*fb1b10abSAndroid Build Coastguard Worker## tree. An additional intellectual property rights grant can be found 7*fb1b10abSAndroid Build Coastguard Worker## in the file PATENTS. All contributing project authors may 8*fb1b10abSAndroid Build Coastguard Worker## be found in the AUTHORS file in the root of the source tree. 9*fb1b10abSAndroid Build Coastguard Worker## 10*fb1b10abSAndroid Build Coastguard Worker"""Classes for representing diff pieces.""" 11*fb1b10abSAndroid Build Coastguard Worker 12*fb1b10abSAndroid Build Coastguard Worker__author__ = "[email protected]" 13*fb1b10abSAndroid Build Coastguard Worker 14*fb1b10abSAndroid Build Coastguard Workerimport re 15*fb1b10abSAndroid Build Coastguard Worker 16*fb1b10abSAndroid Build Coastguard Worker 17*fb1b10abSAndroid Build Coastguard Workerclass DiffLines(object): 18*fb1b10abSAndroid Build Coastguard Worker """A container for one half of a diff.""" 19*fb1b10abSAndroid Build Coastguard Worker 20*fb1b10abSAndroid Build Coastguard Worker def __init__(self, filename, offset, length): 21*fb1b10abSAndroid Build Coastguard Worker self.filename = filename 22*fb1b10abSAndroid Build Coastguard Worker self.offset = offset 23*fb1b10abSAndroid Build Coastguard Worker self.length = length 24*fb1b10abSAndroid Build Coastguard Worker self.lines = [] 25*fb1b10abSAndroid Build Coastguard Worker self.delta_line_nums = [] 26*fb1b10abSAndroid Build Coastguard Worker 27*fb1b10abSAndroid Build Coastguard Worker def Append(self, line): 28*fb1b10abSAndroid Build Coastguard Worker l = len(self.lines) 29*fb1b10abSAndroid Build Coastguard Worker if line[0] != " ": 30*fb1b10abSAndroid Build Coastguard Worker self.delta_line_nums.append(self.offset + l) 31*fb1b10abSAndroid Build Coastguard Worker self.lines.append(line[1:]) 32*fb1b10abSAndroid Build Coastguard Worker assert l+1 <= self.length 33*fb1b10abSAndroid Build Coastguard Worker 34*fb1b10abSAndroid Build Coastguard Worker def Complete(self): 35*fb1b10abSAndroid Build Coastguard Worker return len(self.lines) == self.length 36*fb1b10abSAndroid Build Coastguard Worker 37*fb1b10abSAndroid Build Coastguard Worker def __contains__(self, item): 38*fb1b10abSAndroid Build Coastguard Worker return item >= self.offset and item <= self.offset + self.length - 1 39*fb1b10abSAndroid Build Coastguard Worker 40*fb1b10abSAndroid Build Coastguard Worker 41*fb1b10abSAndroid Build Coastguard Workerclass DiffHunk(object): 42*fb1b10abSAndroid Build Coastguard Worker """A container for one diff hunk, consisting of two DiffLines.""" 43*fb1b10abSAndroid Build Coastguard Worker 44*fb1b10abSAndroid Build Coastguard Worker def __init__(self, header, file_a, file_b, start_a, len_a, start_b, len_b): 45*fb1b10abSAndroid Build Coastguard Worker self.header = header 46*fb1b10abSAndroid Build Coastguard Worker self.left = DiffLines(file_a, start_a, len_a) 47*fb1b10abSAndroid Build Coastguard Worker self.right = DiffLines(file_b, start_b, len_b) 48*fb1b10abSAndroid Build Coastguard Worker self.lines = [] 49*fb1b10abSAndroid Build Coastguard Worker 50*fb1b10abSAndroid Build Coastguard Worker def Append(self, line): 51*fb1b10abSAndroid Build Coastguard Worker """Adds a line to the DiffHunk and its DiffLines children.""" 52*fb1b10abSAndroid Build Coastguard Worker if line[0] == "-": 53*fb1b10abSAndroid Build Coastguard Worker self.left.Append(line) 54*fb1b10abSAndroid Build Coastguard Worker elif line[0] == "+": 55*fb1b10abSAndroid Build Coastguard Worker self.right.Append(line) 56*fb1b10abSAndroid Build Coastguard Worker elif line[0] == " ": 57*fb1b10abSAndroid Build Coastguard Worker self.left.Append(line) 58*fb1b10abSAndroid Build Coastguard Worker self.right.Append(line) 59*fb1b10abSAndroid Build Coastguard Worker elif line[0] == "\\": 60*fb1b10abSAndroid Build Coastguard Worker # Ignore newline messages from git diff. 61*fb1b10abSAndroid Build Coastguard Worker pass 62*fb1b10abSAndroid Build Coastguard Worker else: 63*fb1b10abSAndroid Build Coastguard Worker assert False, ("Unrecognized character at start of diff line " 64*fb1b10abSAndroid Build Coastguard Worker "%r" % line[0]) 65*fb1b10abSAndroid Build Coastguard Worker self.lines.append(line) 66*fb1b10abSAndroid Build Coastguard Worker 67*fb1b10abSAndroid Build Coastguard Worker def Complete(self): 68*fb1b10abSAndroid Build Coastguard Worker return self.left.Complete() and self.right.Complete() 69*fb1b10abSAndroid Build Coastguard Worker 70*fb1b10abSAndroid Build Coastguard Worker def __repr__(self): 71*fb1b10abSAndroid Build Coastguard Worker return "DiffHunk(%s, %s, len %d)" % ( 72*fb1b10abSAndroid Build Coastguard Worker self.left.filename, self.right.filename, 73*fb1b10abSAndroid Build Coastguard Worker max(self.left.length, self.right.length)) 74*fb1b10abSAndroid Build Coastguard Worker 75*fb1b10abSAndroid Build Coastguard Worker 76*fb1b10abSAndroid Build Coastguard Workerdef ParseDiffHunks(stream): 77*fb1b10abSAndroid Build Coastguard Worker """Walk a file-like object, yielding DiffHunks as they're parsed.""" 78*fb1b10abSAndroid Build Coastguard Worker 79*fb1b10abSAndroid Build Coastguard Worker file_regex = re.compile(r"(\+\+\+|---) (\S+)") 80*fb1b10abSAndroid Build Coastguard Worker range_regex = re.compile(r"@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))?") 81*fb1b10abSAndroid Build Coastguard Worker hunk = None 82*fb1b10abSAndroid Build Coastguard Worker while True: 83*fb1b10abSAndroid Build Coastguard Worker line = stream.readline() 84*fb1b10abSAndroid Build Coastguard Worker if not line: 85*fb1b10abSAndroid Build Coastguard Worker break 86*fb1b10abSAndroid Build Coastguard Worker 87*fb1b10abSAndroid Build Coastguard Worker if hunk is None: 88*fb1b10abSAndroid Build Coastguard Worker # Parse file names 89*fb1b10abSAndroid Build Coastguard Worker diff_file = file_regex.match(line) 90*fb1b10abSAndroid Build Coastguard Worker if diff_file: 91*fb1b10abSAndroid Build Coastguard Worker if line.startswith("---"): 92*fb1b10abSAndroid Build Coastguard Worker a_line = line 93*fb1b10abSAndroid Build Coastguard Worker a = diff_file.group(2) 94*fb1b10abSAndroid Build Coastguard Worker continue 95*fb1b10abSAndroid Build Coastguard Worker if line.startswith("+++"): 96*fb1b10abSAndroid Build Coastguard Worker b_line = line 97*fb1b10abSAndroid Build Coastguard Worker b = diff_file.group(2) 98*fb1b10abSAndroid Build Coastguard Worker continue 99*fb1b10abSAndroid Build Coastguard Worker 100*fb1b10abSAndroid Build Coastguard Worker # Parse offset/lengths 101*fb1b10abSAndroid Build Coastguard Worker diffrange = range_regex.match(line) 102*fb1b10abSAndroid Build Coastguard Worker if diffrange: 103*fb1b10abSAndroid Build Coastguard Worker if diffrange.group(2): 104*fb1b10abSAndroid Build Coastguard Worker start_a = int(diffrange.group(1)) 105*fb1b10abSAndroid Build Coastguard Worker len_a = int(diffrange.group(3)) 106*fb1b10abSAndroid Build Coastguard Worker else: 107*fb1b10abSAndroid Build Coastguard Worker start_a = 1 108*fb1b10abSAndroid Build Coastguard Worker len_a = int(diffrange.group(1)) 109*fb1b10abSAndroid Build Coastguard Worker 110*fb1b10abSAndroid Build Coastguard Worker if diffrange.group(5): 111*fb1b10abSAndroid Build Coastguard Worker start_b = int(diffrange.group(4)) 112*fb1b10abSAndroid Build Coastguard Worker len_b = int(diffrange.group(6)) 113*fb1b10abSAndroid Build Coastguard Worker else: 114*fb1b10abSAndroid Build Coastguard Worker start_b = 1 115*fb1b10abSAndroid Build Coastguard Worker len_b = int(diffrange.group(4)) 116*fb1b10abSAndroid Build Coastguard Worker 117*fb1b10abSAndroid Build Coastguard Worker header = [a_line, b_line, line] 118*fb1b10abSAndroid Build Coastguard Worker hunk = DiffHunk(header, a, b, start_a, len_a, start_b, len_b) 119*fb1b10abSAndroid Build Coastguard Worker else: 120*fb1b10abSAndroid Build Coastguard Worker # Add the current line to the hunk 121*fb1b10abSAndroid Build Coastguard Worker hunk.Append(line) 122*fb1b10abSAndroid Build Coastguard Worker 123*fb1b10abSAndroid Build Coastguard Worker # See if the whole hunk has been parsed. If so, yield it and prepare 124*fb1b10abSAndroid Build Coastguard Worker # for the next hunk. 125*fb1b10abSAndroid Build Coastguard Worker if hunk.Complete(): 126*fb1b10abSAndroid Build Coastguard Worker yield hunk 127*fb1b10abSAndroid Build Coastguard Worker hunk = None 128*fb1b10abSAndroid Build Coastguard Worker 129*fb1b10abSAndroid Build Coastguard Worker # Partial hunks are a parse error 130*fb1b10abSAndroid Build Coastguard Worker assert hunk is None 131