xref: /aosp_15_r20/build/make/tools/stub_diff_analyzer.py (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
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