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