1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python 2*9e94795aSAndroid Build Coastguard Worker# 3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2022 The Android Open Source Project 4*9e94795aSAndroid Build Coastguard Worker# 5*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*9e94795aSAndroid Build Coastguard Worker# 9*9e94795aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*9e94795aSAndroid Build Coastguard Worker# 11*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*9e94795aSAndroid Build Coastguard Worker# limitations under the License. 16*9e94795aSAndroid Build Coastguard Worker 17*9e94795aSAndroid Build Coastguard Workerfrom sys import exit 18*9e94795aSAndroid Build Coastguard Workerfrom typing import List 19*9e94795aSAndroid Build Coastguard Workerfrom glob import glob 20*9e94795aSAndroid Build Coastguard Workerfrom pathlib import Path 21*9e94795aSAndroid Build Coastguard Workerfrom collections import defaultdict 22*9e94795aSAndroid Build Coastguard Workerfrom difflib import Differ 23*9e94795aSAndroid Build Coastguard Workerfrom re import split 24*9e94795aSAndroid Build Coastguard Workerfrom tqdm import tqdm 25*9e94795aSAndroid Build Coastguard Workerimport argparse 26*9e94795aSAndroid Build Coastguard Worker 27*9e94795aSAndroid Build Coastguard Worker 28*9e94795aSAndroid Build Coastguard WorkerDIFFER_CODE_LEN = 2 29*9e94795aSAndroid Build Coastguard Worker 30*9e94795aSAndroid Build Coastguard Workerclass DifferCodes: 31*9e94795aSAndroid Build Coastguard Worker COMMON = ' ' 32*9e94795aSAndroid Build Coastguard Worker UNIQUE_FIRST = '- ' 33*9e94795aSAndroid Build Coastguard Worker UNIQUE_SECOND = '+ ' 34*9e94795aSAndroid Build Coastguard Worker DIFF_IDENT = '? ' 35*9e94795aSAndroid Build Coastguard Worker 36*9e94795aSAndroid Build Coastguard Workerclass FilesDiffAnalyzer: 37*9e94795aSAndroid Build Coastguard Worker def __init__(self, args) -> None: 38*9e94795aSAndroid Build Coastguard Worker self.out_dir = args.out_dir 39*9e94795aSAndroid Build Coastguard Worker self.show_diff = args.show_diff 40*9e94795aSAndroid Build Coastguard Worker self.skip_words = args.skip_words 41*9e94795aSAndroid Build Coastguard Worker self.first_dir = args.first_dir 42*9e94795aSAndroid Build Coastguard Worker self.second_dir = args.second_dir 43*9e94795aSAndroid Build Coastguard Worker self.include_common = args.include_common 44*9e94795aSAndroid Build Coastguard Worker 45*9e94795aSAndroid Build Coastguard Worker self.first_dir_files = self.get_files(self.first_dir) 46*9e94795aSAndroid Build Coastguard Worker self.second_dir_files = self.get_files(self.second_dir) 47*9e94795aSAndroid Build Coastguard Worker self.common_file_map = defaultdict(set) 48*9e94795aSAndroid Build Coastguard Worker 49*9e94795aSAndroid Build Coastguard Worker self.map_common_files(self.first_dir_files, self.first_dir) 50*9e94795aSAndroid Build Coastguard Worker self.map_common_files(self.second_dir_files, self.second_dir) 51*9e94795aSAndroid Build Coastguard Worker 52*9e94795aSAndroid Build Coastguard Worker def get_files(self, dir: str) -> List[str]: 53*9e94795aSAndroid Build Coastguard Worker """Get all files directory in the input directory including the files in the subdirectories 54*9e94795aSAndroid Build Coastguard Worker 55*9e94795aSAndroid Build Coastguard Worker Recursively finds all files in the input directory. 56*9e94795aSAndroid Build Coastguard Worker Returns a list of file directory strings, which do not include directories but only files. 57*9e94795aSAndroid Build Coastguard Worker List is sorted in alphabetical order of the file directories. 58*9e94795aSAndroid Build Coastguard Worker 59*9e94795aSAndroid Build Coastguard Worker Args: 60*9e94795aSAndroid Build Coastguard Worker dir: Directory to get the files. String. 61*9e94795aSAndroid Build Coastguard Worker 62*9e94795aSAndroid Build Coastguard Worker Returns: 63*9e94795aSAndroid Build Coastguard Worker A list of file directory strings within the input directory. 64*9e94795aSAndroid Build Coastguard Worker Sorted in Alphabetical order. 65*9e94795aSAndroid Build Coastguard Worker 66*9e94795aSAndroid Build Coastguard Worker Raises: 67*9e94795aSAndroid Build Coastguard Worker FileNotFoundError: An error occurred accessing the non-existing directory 68*9e94795aSAndroid Build Coastguard Worker """ 69*9e94795aSAndroid Build Coastguard Worker 70*9e94795aSAndroid Build Coastguard Worker if not dir_exists(dir): 71*9e94795aSAndroid Build Coastguard Worker raise FileNotFoundError("Directory does not exist") 72*9e94795aSAndroid Build Coastguard Worker 73*9e94795aSAndroid Build Coastguard Worker if dir[:-2] != "**": 74*9e94795aSAndroid Build Coastguard Worker if dir[:-1] != "/": 75*9e94795aSAndroid Build Coastguard Worker dir += "/" 76*9e94795aSAndroid Build Coastguard Worker dir += "**" 77*9e94795aSAndroid Build Coastguard Worker 78*9e94795aSAndroid Build Coastguard Worker return [file for file in sorted(glob(dir, recursive=True)) if Path(file).is_file()] 79*9e94795aSAndroid Build Coastguard Worker 80*9e94795aSAndroid Build Coastguard Worker def map_common_files(self, files: List[str], dir: str) -> None: 81*9e94795aSAndroid Build Coastguard Worker for file in files: 82*9e94795aSAndroid Build Coastguard Worker file_name = file.split(dir, 1)[-1] 83*9e94795aSAndroid Build Coastguard Worker self.common_file_map[file_name].add(dir) 84*9e94795aSAndroid Build Coastguard Worker return 85*9e94795aSAndroid Build Coastguard Worker 86*9e94795aSAndroid Build Coastguard Worker def compare_file_contents(self, first_file: str, second_file: str) -> List[str]: 87*9e94795aSAndroid Build Coastguard Worker """Compare the contents of the files and return different lines 88*9e94795aSAndroid Build Coastguard Worker 89*9e94795aSAndroid Build Coastguard Worker Given two file directory strings, compare the contents of the two files 90*9e94795aSAndroid Build Coastguard Worker and return the list of file contents string prepended with unique identifier codes. 91*9e94795aSAndroid Build Coastguard Worker The identifier codes include: 92*9e94795aSAndroid Build Coastguard Worker - ' '(two empty space characters): Line common to two files 93*9e94795aSAndroid Build Coastguard Worker - '- '(minus followed by a space) : Line unique to first file 94*9e94795aSAndroid Build Coastguard Worker - '+ '(plus followed by a space) : Line unique to second file 95*9e94795aSAndroid Build Coastguard Worker 96*9e94795aSAndroid Build Coastguard Worker Args: 97*9e94795aSAndroid Build Coastguard Worker first_file: First file directory string to compare the content 98*9e94795aSAndroid Build Coastguard Worker second_file: Second file directory string to compare the content 99*9e94795aSAndroid Build Coastguard Worker 100*9e94795aSAndroid Build Coastguard Worker Returns: 101*9e94795aSAndroid Build Coastguard Worker A list of the file content strings. For example: 102*9e94795aSAndroid Build Coastguard Worker 103*9e94795aSAndroid Build Coastguard Worker [ 104*9e94795aSAndroid Build Coastguard Worker " Foo", 105*9e94795aSAndroid Build Coastguard Worker "- Bar", 106*9e94795aSAndroid Build Coastguard Worker "+ Baz" 107*9e94795aSAndroid Build Coastguard Worker ] 108*9e94795aSAndroid Build Coastguard Worker """ 109*9e94795aSAndroid Build Coastguard Worker 110*9e94795aSAndroid Build Coastguard Worker d = Differ() 111*9e94795aSAndroid Build Coastguard Worker first_file_contents = sort_methods(get_file_contents(first_file)) 112*9e94795aSAndroid Build Coastguard Worker second_file_contents = sort_methods(get_file_contents(second_file)) 113*9e94795aSAndroid Build Coastguard Worker diff = list(d.compare(first_file_contents, second_file_contents)) 114*9e94795aSAndroid Build Coastguard Worker ret = [f"diff {first_file} {second_file}"] 115*9e94795aSAndroid Build Coastguard Worker 116*9e94795aSAndroid Build Coastguard Worker idx = 0 117*9e94795aSAndroid Build Coastguard Worker while idx < len(diff): 118*9e94795aSAndroid Build Coastguard Worker line = diff[idx] 119*9e94795aSAndroid Build Coastguard Worker line_code = line[:DIFFER_CODE_LEN] 120*9e94795aSAndroid Build Coastguard Worker 121*9e94795aSAndroid Build Coastguard Worker match line_code: 122*9e94795aSAndroid Build Coastguard Worker case DifferCodes.COMMON: 123*9e94795aSAndroid Build Coastguard Worker if self.include_common: 124*9e94795aSAndroid Build Coastguard Worker ret.append(line) 125*9e94795aSAndroid Build Coastguard Worker 126*9e94795aSAndroid Build Coastguard Worker case DifferCodes.UNIQUE_FIRST: 127*9e94795aSAndroid Build Coastguard Worker # Should compare line 128*9e94795aSAndroid Build Coastguard Worker if (idx < len(diff) - 1 and 129*9e94795aSAndroid Build Coastguard Worker (next_line_code := diff[idx + 1][:DIFFER_CODE_LEN]) 130*9e94795aSAndroid Build Coastguard Worker not in (DifferCodes.UNIQUE_FIRST, DifferCodes.COMMON)): 131*9e94795aSAndroid Build Coastguard Worker delta = 1 if next_line_code == DifferCodes.UNIQUE_SECOND else 2 132*9e94795aSAndroid Build Coastguard Worker line_to_compare = diff[idx + delta] 133*9e94795aSAndroid Build Coastguard Worker if self.lines_differ(line, line_to_compare): 134*9e94795aSAndroid Build Coastguard Worker ret.extend([line, line_to_compare]) 135*9e94795aSAndroid Build Coastguard Worker else: 136*9e94795aSAndroid Build Coastguard Worker if self.include_common: 137*9e94795aSAndroid Build Coastguard Worker ret.append(DifferCodes.COMMON + 138*9e94795aSAndroid Build Coastguard Worker line[DIFFER_CODE_LEN:]) 139*9e94795aSAndroid Build Coastguard Worker idx += delta 140*9e94795aSAndroid Build Coastguard Worker else: 141*9e94795aSAndroid Build Coastguard Worker ret.append(line) 142*9e94795aSAndroid Build Coastguard Worker 143*9e94795aSAndroid Build Coastguard Worker case DifferCodes.UNIQUE_SECOND: 144*9e94795aSAndroid Build Coastguard Worker ret.append(line) 145*9e94795aSAndroid Build Coastguard Worker 146*9e94795aSAndroid Build Coastguard Worker case DifferCodes.DIFF_IDENT: 147*9e94795aSAndroid Build Coastguard Worker pass 148*9e94795aSAndroid Build Coastguard Worker idx += 1 149*9e94795aSAndroid Build Coastguard Worker return ret 150*9e94795aSAndroid Build Coastguard Worker 151*9e94795aSAndroid Build Coastguard Worker def lines_differ(self, line1: str, line2: str) -> bool: 152*9e94795aSAndroid Build Coastguard Worker """Check if the input lines are different or not 153*9e94795aSAndroid Build Coastguard Worker 154*9e94795aSAndroid Build Coastguard Worker Compare the two lines word by word and check if the two lines are different or not. 155*9e94795aSAndroid Build Coastguard Worker If the different words in the comparing lines are included in skip_words, 156*9e94795aSAndroid Build Coastguard Worker the lines are not considered different. 157*9e94795aSAndroid Build Coastguard Worker 158*9e94795aSAndroid Build Coastguard Worker Args: 159*9e94795aSAndroid Build Coastguard Worker line1: first line to compare 160*9e94795aSAndroid Build Coastguard Worker line2: second line to compare 161*9e94795aSAndroid Build Coastguard Worker 162*9e94795aSAndroid Build Coastguard Worker Returns: 163*9e94795aSAndroid Build Coastguard Worker Boolean value indicating if the two lines are different or not 164*9e94795aSAndroid Build Coastguard Worker 165*9e94795aSAndroid Build Coastguard Worker """ 166*9e94795aSAndroid Build Coastguard Worker # Split by '.' or ' '(whitespace) 167*9e94795aSAndroid Build Coastguard Worker def split_words(line: str) -> List[str]: 168*9e94795aSAndroid Build Coastguard Worker return split('\\s|\\.', line[DIFFER_CODE_LEN:]) 169*9e94795aSAndroid Build Coastguard Worker 170*9e94795aSAndroid Build Coastguard Worker line1_words, line2_words = split_words(line1), split_words(line2) 171*9e94795aSAndroid Build Coastguard Worker if len(line1_words) != len(line2_words): 172*9e94795aSAndroid Build Coastguard Worker return True 173*9e94795aSAndroid Build Coastguard Worker 174*9e94795aSAndroid Build Coastguard Worker for word1, word2 in zip(line1_words, line2_words): 175*9e94795aSAndroid Build Coastguard Worker if word1 != word2: 176*9e94795aSAndroid Build Coastguard Worker # not check if words are equal to skip word, but 177*9e94795aSAndroid Build Coastguard Worker # check if words contain skip word as substring 178*9e94795aSAndroid Build Coastguard Worker if all(sw not in word1 and sw not in word2 for sw in self.skip_words): 179*9e94795aSAndroid Build Coastguard Worker return True 180*9e94795aSAndroid Build Coastguard Worker 181*9e94795aSAndroid Build Coastguard Worker return False 182*9e94795aSAndroid Build Coastguard Worker 183*9e94795aSAndroid Build Coastguard Worker def analyze(self) -> None: 184*9e94795aSAndroid Build Coastguard Worker """Analyze file contents in both directories and write to output or console. 185*9e94795aSAndroid Build Coastguard Worker """ 186*9e94795aSAndroid Build Coastguard Worker for file in tqdm(sorted(self.common_file_map.keys())): 187*9e94795aSAndroid Build Coastguard Worker val = self.common_file_map[file] 188*9e94795aSAndroid Build Coastguard Worker 189*9e94795aSAndroid Build Coastguard Worker # When file exists in both directories 190*9e94795aSAndroid Build Coastguard Worker lines = list() 191*9e94795aSAndroid Build Coastguard Worker if val == set([self.first_dir, self.second_dir]): 192*9e94795aSAndroid Build Coastguard Worker lines = self.compare_file_contents( 193*9e94795aSAndroid Build Coastguard Worker self.first_dir + file, self.second_dir + file) 194*9e94795aSAndroid Build Coastguard Worker else: 195*9e94795aSAndroid Build Coastguard Worker existing_dir, not_existing_dir = ( 196*9e94795aSAndroid Build Coastguard Worker (self.first_dir, self.second_dir) if self.first_dir in val 197*9e94795aSAndroid Build Coastguard Worker else (self.second_dir, self.first_dir)) 198*9e94795aSAndroid Build Coastguard Worker 199*9e94795aSAndroid Build Coastguard Worker lines = [f"{not_existing_dir}{file} does not exist."] 200*9e94795aSAndroid Build Coastguard Worker 201*9e94795aSAndroid Build Coastguard Worker if self.show_diff: 202*9e94795aSAndroid Build Coastguard Worker lines.append(f"Content of {existing_dir}{file}: \n") 203*9e94795aSAndroid Build Coastguard Worker lines.extend(get_file_contents(existing_dir + file)) 204*9e94795aSAndroid Build Coastguard Worker 205*9e94795aSAndroid Build Coastguard Worker self.write(lines) 206*9e94795aSAndroid Build Coastguard Worker 207*9e94795aSAndroid Build Coastguard Worker def write(self, lines: List[str]) -> None: 208*9e94795aSAndroid Build Coastguard Worker if self.out_dir == "": 209*9e94795aSAndroid Build Coastguard Worker pprint(lines) 210*9e94795aSAndroid Build Coastguard Worker else: 211*9e94795aSAndroid Build Coastguard Worker write_lines(self.out_dir, lines) 212*9e94795aSAndroid Build Coastguard Worker 213*9e94795aSAndroid Build Coastguard Worker### 214*9e94795aSAndroid Build Coastguard Worker# Helper functions 215*9e94795aSAndroid Build Coastguard Worker### 216*9e94795aSAndroid Build Coastguard Worker 217*9e94795aSAndroid Build Coastguard Workerdef sort_methods(lines: List[str]) -> List[str]: 218*9e94795aSAndroid Build Coastguard Worker """Sort class methods in the file contents by alphabetical order 219*9e94795aSAndroid Build Coastguard Worker 220*9e94795aSAndroid Build Coastguard Worker Given lines of Java file contents, return lines with class methods sorted in alphabetical order. 221*9e94795aSAndroid Build Coastguard Worker Also omit empty lines or lines with spaces. 222*9e94795aSAndroid Build Coastguard Worker For example: 223*9e94795aSAndroid Build Coastguard Worker l = [ 224*9e94795aSAndroid Build Coastguard Worker "package android.test;", 225*9e94795aSAndroid Build Coastguard Worker "", 226*9e94795aSAndroid Build Coastguard Worker "public static final int ORANGE = 1;", 227*9e94795aSAndroid Build Coastguard Worker "", 228*9e94795aSAndroid Build Coastguard Worker "public class TestClass {", 229*9e94795aSAndroid Build Coastguard Worker "public TestClass() { throw new RuntimeException("Stub!"); }", 230*9e94795aSAndroid Build Coastguard Worker "public void foo() { throw new RuntimeException("Stub!"); }", 231*9e94795aSAndroid Build Coastguard Worker "public void bar() { throw new RuntimeException("Stub!"); }", 232*9e94795aSAndroid Build Coastguard Worker "}" 233*9e94795aSAndroid Build Coastguard Worker ] 234*9e94795aSAndroid Build Coastguard Worker sort_methods(l) returns 235*9e94795aSAndroid Build Coastguard Worker [ 236*9e94795aSAndroid Build Coastguard Worker "package android.test;", 237*9e94795aSAndroid Build Coastguard Worker "public static final int ORANGE = 1;", 238*9e94795aSAndroid Build Coastguard Worker "public class TestClass {", 239*9e94795aSAndroid Build Coastguard Worker "public TestClass() { throw new RuntimeException("Stub!"); }", 240*9e94795aSAndroid Build Coastguard Worker "public void bar() { throw new RuntimeException("Stub!"); }", 241*9e94795aSAndroid Build Coastguard Worker "public void foo() { throw new RuntimeException("Stub!"); }", 242*9e94795aSAndroid Build Coastguard Worker "}" 243*9e94795aSAndroid Build Coastguard Worker ] 244*9e94795aSAndroid Build Coastguard Worker 245*9e94795aSAndroid Build Coastguard Worker Args: 246*9e94795aSAndroid Build Coastguard Worker lines: List of strings consisted of Java file contents. 247*9e94795aSAndroid Build Coastguard Worker 248*9e94795aSAndroid Build Coastguard Worker Returns: 249*9e94795aSAndroid Build Coastguard Worker A list of string with sorted class methods. 250*9e94795aSAndroid Build Coastguard Worker 251*9e94795aSAndroid Build Coastguard Worker """ 252*9e94795aSAndroid Build Coastguard Worker def is_not_blank(l: str) -> bool: 253*9e94795aSAndroid Build Coastguard Worker return bool(l) and not l.isspace() 254*9e94795aSAndroid Build Coastguard Worker 255*9e94795aSAndroid Build Coastguard Worker ret = list() 256*9e94795aSAndroid Build Coastguard Worker 257*9e94795aSAndroid Build Coastguard Worker in_class = False 258*9e94795aSAndroid Build Coastguard Worker buffer = list() 259*9e94795aSAndroid Build Coastguard Worker for line in lines: 260*9e94795aSAndroid Build Coastguard Worker if not in_class: 261*9e94795aSAndroid Build Coastguard Worker if "class" in line: 262*9e94795aSAndroid Build Coastguard Worker in_class = True 263*9e94795aSAndroid Build Coastguard Worker ret.append(line) 264*9e94795aSAndroid Build Coastguard Worker else: 265*9e94795aSAndroid Build Coastguard Worker # Adding static variables, package info, etc. 266*9e94795aSAndroid Build Coastguard Worker # Skipping empty or space lines. 267*9e94795aSAndroid Build Coastguard Worker if is_not_blank(line): 268*9e94795aSAndroid Build Coastguard Worker ret.append(line) 269*9e94795aSAndroid Build Coastguard Worker else: 270*9e94795aSAndroid Build Coastguard Worker # End of class 271*9e94795aSAndroid Build Coastguard Worker if line and line[0] == "}": 272*9e94795aSAndroid Build Coastguard Worker in_class = False 273*9e94795aSAndroid Build Coastguard Worker ret.extend(sorted(buffer)) 274*9e94795aSAndroid Build Coastguard Worker buffer = list() 275*9e94795aSAndroid Build Coastguard Worker ret.append(line) 276*9e94795aSAndroid Build Coastguard Worker else: 277*9e94795aSAndroid Build Coastguard Worker if is_not_blank(line): 278*9e94795aSAndroid Build Coastguard Worker buffer.append(line) 279*9e94795aSAndroid Build Coastguard Worker 280*9e94795aSAndroid Build Coastguard Worker return ret 281*9e94795aSAndroid Build Coastguard Worker 282*9e94795aSAndroid Build Coastguard Workerdef get_file_contents(file_path: str) -> List[str]: 283*9e94795aSAndroid Build Coastguard Worker lines = list() 284*9e94795aSAndroid Build Coastguard Worker with open(file_path) as f: 285*9e94795aSAndroid Build Coastguard Worker lines = [line.rstrip('\n') for line in f] 286*9e94795aSAndroid Build Coastguard Worker f.close() 287*9e94795aSAndroid Build Coastguard Worker return lines 288*9e94795aSAndroid Build Coastguard Worker 289*9e94795aSAndroid Build Coastguard Workerdef pprint(l: List[str]) -> None: 290*9e94795aSAndroid Build Coastguard Worker for line in l: 291*9e94795aSAndroid Build Coastguard Worker print(line) 292*9e94795aSAndroid Build Coastguard Worker 293*9e94795aSAndroid Build Coastguard Workerdef write_lines(out_dir: str, lines: List[str]) -> None: 294*9e94795aSAndroid Build Coastguard Worker with open(out_dir, "a") as f: 295*9e94795aSAndroid Build Coastguard Worker f.writelines(line + '\n' for line in lines) 296*9e94795aSAndroid Build Coastguard Worker f.write("\n") 297*9e94795aSAndroid Build Coastguard Worker f.close() 298*9e94795aSAndroid Build Coastguard Worker 299*9e94795aSAndroid Build Coastguard Workerdef dir_exists(dir: str) -> bool: 300*9e94795aSAndroid Build Coastguard Worker return Path(dir).exists() 301*9e94795aSAndroid Build Coastguard Worker 302*9e94795aSAndroid Build Coastguard Workerif __name__ == '__main__': 303*9e94795aSAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 304*9e94795aSAndroid Build Coastguard Worker parser.add_argument('first_dir', action='store', type=str, 305*9e94795aSAndroid Build Coastguard Worker help="first path to compare file directory and contents") 306*9e94795aSAndroid Build Coastguard Worker parser.add_argument('second_dir', action='store', type=str, 307*9e94795aSAndroid Build Coastguard Worker help="second path to compare file directory and contents") 308*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--out', dest='out_dir', 309*9e94795aSAndroid Build Coastguard Worker action='store', default="", type=str, 310*9e94795aSAndroid Build Coastguard Worker help="optional directory to write log. If not set, will print to console") 311*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--show-diff-file', dest='show_diff', 312*9e94795aSAndroid Build Coastguard Worker action=argparse.BooleanOptionalAction, 313*9e94795aSAndroid Build Coastguard Worker help="optional flag. If passed, will print out the content of the file unique to each directories") 314*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--include-common', dest='include_common', 315*9e94795aSAndroid Build Coastguard Worker action=argparse.BooleanOptionalAction, 316*9e94795aSAndroid Build Coastguard Worker help="optional flag. If passed, will print out the contents common to both files as well,\ 317*9e94795aSAndroid Build Coastguard Worker instead of printing only diff lines.") 318*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--skip-words', nargs='+', 319*9e94795aSAndroid Build Coastguard Worker dest='skip_words', default=[], help="optional words to skip in comparison") 320*9e94795aSAndroid Build Coastguard Worker 321*9e94795aSAndroid Build Coastguard Worker args = parser.parse_args() 322*9e94795aSAndroid Build Coastguard Worker 323*9e94795aSAndroid Build Coastguard Worker if not args.first_dir or not args.second_dir: 324*9e94795aSAndroid Build Coastguard Worker parser.print_usage() 325*9e94795aSAndroid Build Coastguard Worker exit(0) 326*9e94795aSAndroid Build Coastguard Worker 327*9e94795aSAndroid Build Coastguard Worker analyzer = FilesDiffAnalyzer(args) 328*9e94795aSAndroid Build Coastguard Worker analyzer.analyze() 329