1*44844408SAndroid Build Coastguard Worker#!/usr/bin/env python 2*44844408SAndroid Build Coastguard Worker"""A wrapper script around clang-format, suitable for linting multiple files 3*44844408SAndroid Build Coastguard Workerand to use for continuous integration. 4*44844408SAndroid Build Coastguard WorkerThis is an alternative API for the clang-format command line. 5*44844408SAndroid Build Coastguard WorkerIt runs over multiple files and directories in parallel. 6*44844408SAndroid Build Coastguard WorkerA diff output is produced and a sensible exit code is returned. 7*44844408SAndroid Build Coastguard Worker 8*44844408SAndroid Build Coastguard WorkerNOTE: pulled from https://github.com/Sarcasm/run-clang-format, which is 9*44844408SAndroid Build Coastguard Workerlicensed under the MIT license. 10*44844408SAndroid Build Coastguard Worker""" 11*44844408SAndroid Build Coastguard Worker 12*44844408SAndroid Build Coastguard Workerfrom __future__ import print_function, unicode_literals 13*44844408SAndroid Build Coastguard Worker 14*44844408SAndroid Build Coastguard Workerimport argparse 15*44844408SAndroid Build Coastguard Workerimport codecs 16*44844408SAndroid Build Coastguard Workerimport difflib 17*44844408SAndroid Build Coastguard Workerimport fnmatch 18*44844408SAndroid Build Coastguard Workerimport io 19*44844408SAndroid Build Coastguard Workerimport multiprocessing 20*44844408SAndroid Build Coastguard Workerimport os 21*44844408SAndroid Build Coastguard Workerimport signal 22*44844408SAndroid Build Coastguard Workerimport subprocess 23*44844408SAndroid Build Coastguard Workerimport sys 24*44844408SAndroid Build Coastguard Workerimport traceback 25*44844408SAndroid Build Coastguard Worker 26*44844408SAndroid Build Coastguard Workerfrom functools import partial 27*44844408SAndroid Build Coastguard Worker 28*44844408SAndroid Build Coastguard Workertry: 29*44844408SAndroid Build Coastguard Worker from subprocess import DEVNULL # py3k 30*44844408SAndroid Build Coastguard Workerexcept ImportError: 31*44844408SAndroid Build Coastguard Worker DEVNULL = open(os.devnull, "wb") 32*44844408SAndroid Build Coastguard Worker 33*44844408SAndroid Build Coastguard Worker 34*44844408SAndroid Build Coastguard WorkerDEFAULT_EXTENSIONS = 'c,h,C,H,cpp,hpp,cc,hh,c++,h++,cxx,hxx' 35*44844408SAndroid Build Coastguard Worker 36*44844408SAndroid Build Coastguard Worker 37*44844408SAndroid Build Coastguard Workerclass ExitStatus: 38*44844408SAndroid Build Coastguard Worker SUCCESS = 0 39*44844408SAndroid Build Coastguard Worker DIFF = 1 40*44844408SAndroid Build Coastguard Worker TROUBLE = 2 41*44844408SAndroid Build Coastguard Worker 42*44844408SAndroid Build Coastguard Worker 43*44844408SAndroid Build Coastguard Workerdef list_files(files, recursive=False, extensions=None, exclude=None): 44*44844408SAndroid Build Coastguard Worker if extensions is None: 45*44844408SAndroid Build Coastguard Worker extensions = [] 46*44844408SAndroid Build Coastguard Worker if exclude is None: 47*44844408SAndroid Build Coastguard Worker exclude = [] 48*44844408SAndroid Build Coastguard Worker 49*44844408SAndroid Build Coastguard Worker out = [] 50*44844408SAndroid Build Coastguard Worker for file in files: 51*44844408SAndroid Build Coastguard Worker if recursive and os.path.isdir(file): 52*44844408SAndroid Build Coastguard Worker for dirpath, dnames, fnames in os.walk(file): 53*44844408SAndroid Build Coastguard Worker fpaths = [os.path.join(dirpath, fname) for fname in fnames] 54*44844408SAndroid Build Coastguard Worker for pattern in exclude: 55*44844408SAndroid Build Coastguard Worker # os.walk() supports trimming down the dnames list 56*44844408SAndroid Build Coastguard Worker # by modifying it in-place, 57*44844408SAndroid Build Coastguard Worker # to avoid unnecessary directory listings. 58*44844408SAndroid Build Coastguard Worker dnames[:] = [ 59*44844408SAndroid Build Coastguard Worker x for x in dnames 60*44844408SAndroid Build Coastguard Worker if 61*44844408SAndroid Build Coastguard Worker not fnmatch.fnmatch(os.path.join(dirpath, x), pattern) 62*44844408SAndroid Build Coastguard Worker ] 63*44844408SAndroid Build Coastguard Worker fpaths = [ 64*44844408SAndroid Build Coastguard Worker x for x in fpaths if not fnmatch.fnmatch(x, pattern) 65*44844408SAndroid Build Coastguard Worker ] 66*44844408SAndroid Build Coastguard Worker for f in fpaths: 67*44844408SAndroid Build Coastguard Worker ext = os.path.splitext(f)[1][1:] 68*44844408SAndroid Build Coastguard Worker if ext in extensions: 69*44844408SAndroid Build Coastguard Worker out.append(f) 70*44844408SAndroid Build Coastguard Worker else: 71*44844408SAndroid Build Coastguard Worker out.append(file) 72*44844408SAndroid Build Coastguard Worker return out 73*44844408SAndroid Build Coastguard Worker 74*44844408SAndroid Build Coastguard Worker 75*44844408SAndroid Build Coastguard Workerdef make_diff(file, original, reformatted): 76*44844408SAndroid Build Coastguard Worker return list( 77*44844408SAndroid Build Coastguard Worker difflib.unified_diff( 78*44844408SAndroid Build Coastguard Worker original, 79*44844408SAndroid Build Coastguard Worker reformatted, 80*44844408SAndroid Build Coastguard Worker fromfile='{}\t(original)'.format(file), 81*44844408SAndroid Build Coastguard Worker tofile='{}\t(reformatted)'.format(file), 82*44844408SAndroid Build Coastguard Worker n=3)) 83*44844408SAndroid Build Coastguard Worker 84*44844408SAndroid Build Coastguard Worker 85*44844408SAndroid Build Coastguard Workerclass DiffError(Exception): 86*44844408SAndroid Build Coastguard Worker def __init__(self, message, errs=None): 87*44844408SAndroid Build Coastguard Worker super(DiffError, self).__init__(message) 88*44844408SAndroid Build Coastguard Worker self.errs = errs or [] 89*44844408SAndroid Build Coastguard Worker 90*44844408SAndroid Build Coastguard Worker 91*44844408SAndroid Build Coastguard Workerclass UnexpectedError(Exception): 92*44844408SAndroid Build Coastguard Worker def __init__(self, message, exc=None): 93*44844408SAndroid Build Coastguard Worker super(UnexpectedError, self).__init__(message) 94*44844408SAndroid Build Coastguard Worker self.formatted_traceback = traceback.format_exc() 95*44844408SAndroid Build Coastguard Worker self.exc = exc 96*44844408SAndroid Build Coastguard Worker 97*44844408SAndroid Build Coastguard Worker 98*44844408SAndroid Build Coastguard Workerdef run_clang_format_diff_wrapper(args, file): 99*44844408SAndroid Build Coastguard Worker try: 100*44844408SAndroid Build Coastguard Worker ret = run_clang_format_diff(args, file) 101*44844408SAndroid Build Coastguard Worker return ret 102*44844408SAndroid Build Coastguard Worker except DiffError: 103*44844408SAndroid Build Coastguard Worker raise 104*44844408SAndroid Build Coastguard Worker except Exception as e: 105*44844408SAndroid Build Coastguard Worker raise UnexpectedError('{}: {}: {}'.format(file, e.__class__.__name__, 106*44844408SAndroid Build Coastguard Worker e), e) 107*44844408SAndroid Build Coastguard Worker 108*44844408SAndroid Build Coastguard Worker 109*44844408SAndroid Build Coastguard Workerdef run_clang_format_diff(args, file): 110*44844408SAndroid Build Coastguard Worker try: 111*44844408SAndroid Build Coastguard Worker with io.open(file, 'r', encoding='utf-8') as f: 112*44844408SAndroid Build Coastguard Worker original = f.readlines() 113*44844408SAndroid Build Coastguard Worker except IOError as exc: 114*44844408SAndroid Build Coastguard Worker raise DiffError(str(exc)) 115*44844408SAndroid Build Coastguard Worker invocation = [args.clang_format_executable, file] 116*44844408SAndroid Build Coastguard Worker 117*44844408SAndroid Build Coastguard Worker # Use of utf-8 to decode the process output. 118*44844408SAndroid Build Coastguard Worker # 119*44844408SAndroid Build Coastguard Worker # Hopefully, this is the correct thing to do. 120*44844408SAndroid Build Coastguard Worker # 121*44844408SAndroid Build Coastguard Worker # It's done due to the following assumptions (which may be incorrect): 122*44844408SAndroid Build Coastguard Worker # - clang-format will returns the bytes read from the files as-is, 123*44844408SAndroid Build Coastguard Worker # without conversion, and it is already assumed that the files use utf-8. 124*44844408SAndroid Build Coastguard Worker # - if the diagnostics were internationalized, they would use utf-8: 125*44844408SAndroid Build Coastguard Worker # > Adding Translations to Clang 126*44844408SAndroid Build Coastguard Worker # > 127*44844408SAndroid Build Coastguard Worker # > Not possible yet! 128*44844408SAndroid Build Coastguard Worker # > Diagnostic strings should be written in UTF-8, 129*44844408SAndroid Build Coastguard Worker # > the client can translate to the relevant code page if needed. 130*44844408SAndroid Build Coastguard Worker # > Each translation completely replaces the format string 131*44844408SAndroid Build Coastguard Worker # > for the diagnostic. 132*44844408SAndroid Build Coastguard Worker # > -- http://clang.llvm.org/docs/InternalsManual.html#internals-diag-translation 133*44844408SAndroid Build Coastguard Worker # 134*44844408SAndroid Build Coastguard Worker # It's not pretty, due to Python 2 & 3 compatibility. 135*44844408SAndroid Build Coastguard Worker encoding_py3 = {} 136*44844408SAndroid Build Coastguard Worker if sys.version_info[0] >= 3: 137*44844408SAndroid Build Coastguard Worker encoding_py3['encoding'] = 'utf-8' 138*44844408SAndroid Build Coastguard Worker 139*44844408SAndroid Build Coastguard Worker try: 140*44844408SAndroid Build Coastguard Worker proc = subprocess.Popen( 141*44844408SAndroid Build Coastguard Worker invocation, 142*44844408SAndroid Build Coastguard Worker stdout=subprocess.PIPE, 143*44844408SAndroid Build Coastguard Worker stderr=subprocess.PIPE, 144*44844408SAndroid Build Coastguard Worker universal_newlines=True, 145*44844408SAndroid Build Coastguard Worker **encoding_py3) 146*44844408SAndroid Build Coastguard Worker except OSError as exc: 147*44844408SAndroid Build Coastguard Worker raise DiffError( 148*44844408SAndroid Build Coastguard Worker "Command '{}' failed to start: {}".format( 149*44844408SAndroid Build Coastguard Worker subprocess.list2cmdline(invocation), exc 150*44844408SAndroid Build Coastguard Worker ) 151*44844408SAndroid Build Coastguard Worker ) 152*44844408SAndroid Build Coastguard Worker proc_stdout = proc.stdout 153*44844408SAndroid Build Coastguard Worker proc_stderr = proc.stderr 154*44844408SAndroid Build Coastguard Worker if sys.version_info[0] < 3: 155*44844408SAndroid Build Coastguard Worker # make the pipes compatible with Python 3, 156*44844408SAndroid Build Coastguard Worker # reading lines should output unicode 157*44844408SAndroid Build Coastguard Worker encoding = 'utf-8' 158*44844408SAndroid Build Coastguard Worker proc_stdout = codecs.getreader(encoding)(proc_stdout) 159*44844408SAndroid Build Coastguard Worker proc_stderr = codecs.getreader(encoding)(proc_stderr) 160*44844408SAndroid Build Coastguard Worker # hopefully the stderr pipe won't get full and block the process 161*44844408SAndroid Build Coastguard Worker outs = list(proc_stdout.readlines()) 162*44844408SAndroid Build Coastguard Worker errs = list(proc_stderr.readlines()) 163*44844408SAndroid Build Coastguard Worker proc.wait() 164*44844408SAndroid Build Coastguard Worker if proc.returncode: 165*44844408SAndroid Build Coastguard Worker raise DiffError( 166*44844408SAndroid Build Coastguard Worker "Command '{}' returned non-zero exit status {}".format( 167*44844408SAndroid Build Coastguard Worker subprocess.list2cmdline(invocation), proc.returncode 168*44844408SAndroid Build Coastguard Worker ), 169*44844408SAndroid Build Coastguard Worker errs, 170*44844408SAndroid Build Coastguard Worker ) 171*44844408SAndroid Build Coastguard Worker return make_diff(file, original, outs), errs 172*44844408SAndroid Build Coastguard Worker 173*44844408SAndroid Build Coastguard Worker 174*44844408SAndroid Build Coastguard Workerdef bold_red(s): 175*44844408SAndroid Build Coastguard Worker return '\x1b[1m\x1b[31m' + s + '\x1b[0m' 176*44844408SAndroid Build Coastguard Worker 177*44844408SAndroid Build Coastguard Worker 178*44844408SAndroid Build Coastguard Workerdef colorize(diff_lines): 179*44844408SAndroid Build Coastguard Worker def bold(s): 180*44844408SAndroid Build Coastguard Worker return '\x1b[1m' + s + '\x1b[0m' 181*44844408SAndroid Build Coastguard Worker 182*44844408SAndroid Build Coastguard Worker def cyan(s): 183*44844408SAndroid Build Coastguard Worker return '\x1b[36m' + s + '\x1b[0m' 184*44844408SAndroid Build Coastguard Worker 185*44844408SAndroid Build Coastguard Worker def green(s): 186*44844408SAndroid Build Coastguard Worker return '\x1b[32m' + s + '\x1b[0m' 187*44844408SAndroid Build Coastguard Worker 188*44844408SAndroid Build Coastguard Worker def red(s): 189*44844408SAndroid Build Coastguard Worker return '\x1b[31m' + s + '\x1b[0m' 190*44844408SAndroid Build Coastguard Worker 191*44844408SAndroid Build Coastguard Worker for line in diff_lines: 192*44844408SAndroid Build Coastguard Worker if line[:4] in ['--- ', '+++ ']: 193*44844408SAndroid Build Coastguard Worker yield bold(line) 194*44844408SAndroid Build Coastguard Worker elif line.startswith('@@ '): 195*44844408SAndroid Build Coastguard Worker yield cyan(line) 196*44844408SAndroid Build Coastguard Worker elif line.startswith('+'): 197*44844408SAndroid Build Coastguard Worker yield green(line) 198*44844408SAndroid Build Coastguard Worker elif line.startswith('-'): 199*44844408SAndroid Build Coastguard Worker yield red(line) 200*44844408SAndroid Build Coastguard Worker else: 201*44844408SAndroid Build Coastguard Worker yield line 202*44844408SAndroid Build Coastguard Worker 203*44844408SAndroid Build Coastguard Worker 204*44844408SAndroid Build Coastguard Workerdef print_diff(diff_lines, use_color): 205*44844408SAndroid Build Coastguard Worker if use_color: 206*44844408SAndroid Build Coastguard Worker diff_lines = colorize(diff_lines) 207*44844408SAndroid Build Coastguard Worker if sys.version_info[0] < 3: 208*44844408SAndroid Build Coastguard Worker sys.stdout.writelines((l.encode('utf-8') for l in diff_lines)) 209*44844408SAndroid Build Coastguard Worker else: 210*44844408SAndroid Build Coastguard Worker sys.stdout.writelines(diff_lines) 211*44844408SAndroid Build Coastguard Worker 212*44844408SAndroid Build Coastguard Worker 213*44844408SAndroid Build Coastguard Workerdef print_trouble(prog, message, use_colors): 214*44844408SAndroid Build Coastguard Worker error_text = 'error:' 215*44844408SAndroid Build Coastguard Worker if use_colors: 216*44844408SAndroid Build Coastguard Worker error_text = bold_red(error_text) 217*44844408SAndroid Build Coastguard Worker print("{}: {} {}".format(prog, error_text, message), file=sys.stderr) 218*44844408SAndroid Build Coastguard Worker 219*44844408SAndroid Build Coastguard Worker 220*44844408SAndroid Build Coastguard Workerdef main(): 221*44844408SAndroid Build Coastguard Worker parser = argparse.ArgumentParser(description=__doc__) 222*44844408SAndroid Build Coastguard Worker parser.add_argument( 223*44844408SAndroid Build Coastguard Worker '--clang-format-executable', 224*44844408SAndroid Build Coastguard Worker metavar='EXECUTABLE', 225*44844408SAndroid Build Coastguard Worker help='path to the clang-format executable', 226*44844408SAndroid Build Coastguard Worker default='clang-format') 227*44844408SAndroid Build Coastguard Worker parser.add_argument( 228*44844408SAndroid Build Coastguard Worker '--extensions', 229*44844408SAndroid Build Coastguard Worker help='comma separated list of file extensions (default: {})'.format( 230*44844408SAndroid Build Coastguard Worker DEFAULT_EXTENSIONS), 231*44844408SAndroid Build Coastguard Worker default=DEFAULT_EXTENSIONS) 232*44844408SAndroid Build Coastguard Worker parser.add_argument( 233*44844408SAndroid Build Coastguard Worker '-r', 234*44844408SAndroid Build Coastguard Worker '--recursive', 235*44844408SAndroid Build Coastguard Worker action='store_true', 236*44844408SAndroid Build Coastguard Worker help='run recursively over directories') 237*44844408SAndroid Build Coastguard Worker parser.add_argument('files', metavar='file', nargs='+') 238*44844408SAndroid Build Coastguard Worker parser.add_argument( 239*44844408SAndroid Build Coastguard Worker '-q', 240*44844408SAndroid Build Coastguard Worker '--quiet', 241*44844408SAndroid Build Coastguard Worker action='store_true') 242*44844408SAndroid Build Coastguard Worker parser.add_argument( 243*44844408SAndroid Build Coastguard Worker '-j', 244*44844408SAndroid Build Coastguard Worker metavar='N', 245*44844408SAndroid Build Coastguard Worker type=int, 246*44844408SAndroid Build Coastguard Worker default=0, 247*44844408SAndroid Build Coastguard Worker help='run N clang-format jobs in parallel' 248*44844408SAndroid Build Coastguard Worker ' (default number of cpus + 1)') 249*44844408SAndroid Build Coastguard Worker parser.add_argument( 250*44844408SAndroid Build Coastguard Worker '--color', 251*44844408SAndroid Build Coastguard Worker default='auto', 252*44844408SAndroid Build Coastguard Worker choices=['auto', 'always', 'never'], 253*44844408SAndroid Build Coastguard Worker help='show colored diff (default: auto)') 254*44844408SAndroid Build Coastguard Worker parser.add_argument( 255*44844408SAndroid Build Coastguard Worker '-e', 256*44844408SAndroid Build Coastguard Worker '--exclude', 257*44844408SAndroid Build Coastguard Worker metavar='PATTERN', 258*44844408SAndroid Build Coastguard Worker action='append', 259*44844408SAndroid Build Coastguard Worker default=[], 260*44844408SAndroid Build Coastguard Worker help='exclude paths matching the given glob-like pattern(s)' 261*44844408SAndroid Build Coastguard Worker ' from recursive search') 262*44844408SAndroid Build Coastguard Worker 263*44844408SAndroid Build Coastguard Worker args = parser.parse_args() 264*44844408SAndroid Build Coastguard Worker 265*44844408SAndroid Build Coastguard Worker # use default signal handling, like diff return SIGINT value on ^C 266*44844408SAndroid Build Coastguard Worker # https://bugs.python.org/issue14229#msg156446 267*44844408SAndroid Build Coastguard Worker signal.signal(signal.SIGINT, signal.SIG_DFL) 268*44844408SAndroid Build Coastguard Worker try: 269*44844408SAndroid Build Coastguard Worker signal.SIGPIPE 270*44844408SAndroid Build Coastguard Worker except AttributeError: 271*44844408SAndroid Build Coastguard Worker # compatibility, SIGPIPE does not exist on Windows 272*44844408SAndroid Build Coastguard Worker pass 273*44844408SAndroid Build Coastguard Worker else: 274*44844408SAndroid Build Coastguard Worker signal.signal(signal.SIGPIPE, signal.SIG_DFL) 275*44844408SAndroid Build Coastguard Worker 276*44844408SAndroid Build Coastguard Worker colored_stdout = False 277*44844408SAndroid Build Coastguard Worker colored_stderr = False 278*44844408SAndroid Build Coastguard Worker if args.color == 'always': 279*44844408SAndroid Build Coastguard Worker colored_stdout = True 280*44844408SAndroid Build Coastguard Worker colored_stderr = True 281*44844408SAndroid Build Coastguard Worker elif args.color == 'auto': 282*44844408SAndroid Build Coastguard Worker colored_stdout = sys.stdout.isatty() 283*44844408SAndroid Build Coastguard Worker colored_stderr = sys.stderr.isatty() 284*44844408SAndroid Build Coastguard Worker 285*44844408SAndroid Build Coastguard Worker version_invocation = [args.clang_format_executable, str("--version")] 286*44844408SAndroid Build Coastguard Worker try: 287*44844408SAndroid Build Coastguard Worker subprocess.check_call(version_invocation, stdout=DEVNULL) 288*44844408SAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 289*44844408SAndroid Build Coastguard Worker print_trouble(parser.prog, str(e), use_colors=colored_stderr) 290*44844408SAndroid Build Coastguard Worker return ExitStatus.TROUBLE 291*44844408SAndroid Build Coastguard Worker except OSError as e: 292*44844408SAndroid Build Coastguard Worker print_trouble( 293*44844408SAndroid Build Coastguard Worker parser.prog, 294*44844408SAndroid Build Coastguard Worker "Command '{}' failed to start: {}".format( 295*44844408SAndroid Build Coastguard Worker subprocess.list2cmdline(version_invocation), e 296*44844408SAndroid Build Coastguard Worker ), 297*44844408SAndroid Build Coastguard Worker use_colors=colored_stderr, 298*44844408SAndroid Build Coastguard Worker ) 299*44844408SAndroid Build Coastguard Worker return ExitStatus.TROUBLE 300*44844408SAndroid Build Coastguard Worker 301*44844408SAndroid Build Coastguard Worker retcode = ExitStatus.SUCCESS 302*44844408SAndroid Build Coastguard Worker files = list_files( 303*44844408SAndroid Build Coastguard Worker args.files, 304*44844408SAndroid Build Coastguard Worker recursive=args.recursive, 305*44844408SAndroid Build Coastguard Worker exclude=args.exclude, 306*44844408SAndroid Build Coastguard Worker extensions=args.extensions.split(',')) 307*44844408SAndroid Build Coastguard Worker 308*44844408SAndroid Build Coastguard Worker if not files: 309*44844408SAndroid Build Coastguard Worker return 310*44844408SAndroid Build Coastguard Worker 311*44844408SAndroid Build Coastguard Worker njobs = args.j 312*44844408SAndroid Build Coastguard Worker if njobs == 0: 313*44844408SAndroid Build Coastguard Worker njobs = multiprocessing.cpu_count() + 1 314*44844408SAndroid Build Coastguard Worker njobs = min(len(files), njobs) 315*44844408SAndroid Build Coastguard Worker 316*44844408SAndroid Build Coastguard Worker if njobs == 1: 317*44844408SAndroid Build Coastguard Worker # execute directly instead of in a pool, 318*44844408SAndroid Build Coastguard Worker # less overhead, simpler stacktraces 319*44844408SAndroid Build Coastguard Worker it = (run_clang_format_diff_wrapper(args, file) for file in files) 320*44844408SAndroid Build Coastguard Worker pool = None 321*44844408SAndroid Build Coastguard Worker else: 322*44844408SAndroid Build Coastguard Worker pool = multiprocessing.Pool(njobs) 323*44844408SAndroid Build Coastguard Worker it = pool.imap_unordered( 324*44844408SAndroid Build Coastguard Worker partial(run_clang_format_diff_wrapper, args), files) 325*44844408SAndroid Build Coastguard Worker while True: 326*44844408SAndroid Build Coastguard Worker try: 327*44844408SAndroid Build Coastguard Worker outs, errs = next(it) 328*44844408SAndroid Build Coastguard Worker except StopIteration: 329*44844408SAndroid Build Coastguard Worker break 330*44844408SAndroid Build Coastguard Worker except DiffError as e: 331*44844408SAndroid Build Coastguard Worker print_trouble(parser.prog, str(e), use_colors=colored_stderr) 332*44844408SAndroid Build Coastguard Worker retcode = ExitStatus.TROUBLE 333*44844408SAndroid Build Coastguard Worker sys.stderr.writelines(e.errs) 334*44844408SAndroid Build Coastguard Worker except UnexpectedError as e: 335*44844408SAndroid Build Coastguard Worker print_trouble(parser.prog, str(e), use_colors=colored_stderr) 336*44844408SAndroid Build Coastguard Worker sys.stderr.write(e.formatted_traceback) 337*44844408SAndroid Build Coastguard Worker retcode = ExitStatus.TROUBLE 338*44844408SAndroid Build Coastguard Worker # stop at the first unexpected error, 339*44844408SAndroid Build Coastguard Worker # something could be very wrong, 340*44844408SAndroid Build Coastguard Worker # don't process all files unnecessarily 341*44844408SAndroid Build Coastguard Worker if pool: 342*44844408SAndroid Build Coastguard Worker pool.terminate() 343*44844408SAndroid Build Coastguard Worker break 344*44844408SAndroid Build Coastguard Worker else: 345*44844408SAndroid Build Coastguard Worker sys.stderr.writelines(errs) 346*44844408SAndroid Build Coastguard Worker if outs == []: 347*44844408SAndroid Build Coastguard Worker continue 348*44844408SAndroid Build Coastguard Worker if not args.quiet: 349*44844408SAndroid Build Coastguard Worker print_diff(outs, use_color=colored_stdout) 350*44844408SAndroid Build Coastguard Worker if retcode == ExitStatus.SUCCESS: 351*44844408SAndroid Build Coastguard Worker retcode = ExitStatus.DIFF 352*44844408SAndroid Build Coastguard Worker return retcode 353*44844408SAndroid Build Coastguard Worker 354*44844408SAndroid Build Coastguard Worker 355*44844408SAndroid Build Coastguard Workerif __name__ == '__main__': 356*44844408SAndroid Build Coastguard Worker sys.exit(main()) 357