1*9e94795aSAndroid Build Coastguard Worker# python3 2*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2019 The Android Open Source Project 3*9e94795aSAndroid Build Coastguard Worker# 4*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*9e94795aSAndroid Build Coastguard Worker# 8*9e94795aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*9e94795aSAndroid Build Coastguard Worker# 10*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*9e94795aSAndroid Build Coastguard Worker# limitations under the License. 15*9e94795aSAndroid Build Coastguard Worker 16*9e94795aSAndroid Build Coastguard Worker"""Grep warnings messages and output HTML tables or warning counts in CSV. 17*9e94795aSAndroid Build Coastguard Worker 18*9e94795aSAndroid Build Coastguard WorkerDefault is to output warnings in HTML tables grouped by warning severity. 19*9e94795aSAndroid Build Coastguard WorkerUse option --byproject to output tables grouped by source file projects. 20*9e94795aSAndroid Build Coastguard WorkerUse option --gencsv to output warning counts in CSV format. 21*9e94795aSAndroid Build Coastguard Worker 22*9e94795aSAndroid Build Coastguard WorkerDefault input file is build.log, which can be changed with the --log flag. 23*9e94795aSAndroid Build Coastguard Worker""" 24*9e94795aSAndroid Build Coastguard Worker 25*9e94795aSAndroid Build Coastguard Worker# List of important data structures and functions in this script. 26*9e94795aSAndroid Build Coastguard Worker# 27*9e94795aSAndroid Build Coastguard Worker# To parse and keep warning message in the input file: 28*9e94795aSAndroid Build Coastguard Worker# severity: classification of message severity 29*9e94795aSAndroid Build Coastguard Worker# warn_patterns: 30*9e94795aSAndroid Build Coastguard Worker# warn_patterns[w]['category'] tool that issued the warning, not used now 31*9e94795aSAndroid Build Coastguard Worker# warn_patterns[w]['description'] table heading 32*9e94795aSAndroid Build Coastguard Worker# warn_patterns[w]['members'] matched warnings from input 33*9e94795aSAndroid Build Coastguard Worker# warn_patterns[w]['patterns'] regular expressions to match warnings 34*9e94795aSAndroid Build Coastguard Worker# warn_patterns[w]['projects'][p] number of warnings of pattern w in p 35*9e94795aSAndroid Build Coastguard Worker# warn_patterns[w]['severity'] severity tuple 36*9e94795aSAndroid Build Coastguard Worker# project_list[p][0] project name 37*9e94795aSAndroid Build Coastguard Worker# project_list[p][1] regular expression to match a project path 38*9e94795aSAndroid Build Coastguard Worker# project_patterns[p] re.compile(project_list[p][1]) 39*9e94795aSAndroid Build Coastguard Worker# project_names[p] project_list[p][0] 40*9e94795aSAndroid Build Coastguard Worker# warning_messages array of each warning message, without source url 41*9e94795aSAndroid Build Coastguard Worker# warning_links array of each warning code search link; for 'chrome' 42*9e94795aSAndroid Build Coastguard Worker# warning_records array of [idx to warn_patterns, 43*9e94795aSAndroid Build Coastguard Worker# idx to project_names, 44*9e94795aSAndroid Build Coastguard Worker# idx to warning_messages, 45*9e94795aSAndroid Build Coastguard Worker# idx to warning_links] 46*9e94795aSAndroid Build Coastguard Worker# parse_input_file 47*9e94795aSAndroid Build Coastguard Worker# 48*9e94795aSAndroid Build Coastguard Workerimport argparse 49*9e94795aSAndroid Build Coastguard Workerimport io 50*9e94795aSAndroid Build Coastguard Workerimport multiprocessing 51*9e94795aSAndroid Build Coastguard Workerimport os 52*9e94795aSAndroid Build Coastguard Workerimport re 53*9e94795aSAndroid Build Coastguard Workerimport sys 54*9e94795aSAndroid Build Coastguard Worker 55*9e94795aSAndroid Build Coastguard Worker# pylint:disable=relative-beyond-top-level,no-name-in-module 56*9e94795aSAndroid Build Coastguard Worker# suppress false positive of no-name-in-module warnings 57*9e94795aSAndroid Build Coastguard Workerfrom . import android_project_list 58*9e94795aSAndroid Build Coastguard Workerfrom . import chrome_project_list 59*9e94795aSAndroid Build Coastguard Workerfrom . import cpp_warn_patterns as cpp_patterns 60*9e94795aSAndroid Build Coastguard Workerfrom . import html_writer 61*9e94795aSAndroid Build Coastguard Workerfrom . import java_warn_patterns as java_patterns 62*9e94795aSAndroid Build Coastguard Workerfrom . import make_warn_patterns as make_patterns 63*9e94795aSAndroid Build Coastguard Workerfrom . import other_warn_patterns as other_patterns 64*9e94795aSAndroid Build Coastguard Workerfrom . import tidy_warn_patterns as tidy_patterns 65*9e94795aSAndroid Build Coastguard Worker 66*9e94795aSAndroid Build Coastguard Worker 67*9e94795aSAndroid Build Coastguard Worker# Location of this file is used to guess the root of Android source tree. 68*9e94795aSAndroid Build Coastguard WorkerTHIS_FILE_PATH = 'build/make/tools/warn/warn_common.py' 69*9e94795aSAndroid Build Coastguard Worker 70*9e94795aSAndroid Build Coastguard Worker 71*9e94795aSAndroid Build Coastguard Workerdef parse_args(use_google3): 72*9e94795aSAndroid Build Coastguard Worker """Define and parse the args. Return the parse_args() result.""" 73*9e94795aSAndroid Build Coastguard Worker parser = argparse.ArgumentParser( 74*9e94795aSAndroid Build Coastguard Worker description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) 75*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--capacitor_path', default='', 76*9e94795aSAndroid Build Coastguard Worker help='Save capacitor warning file to the passed absolute' 77*9e94795aSAndroid Build Coastguard Worker ' path') 78*9e94795aSAndroid Build Coastguard Worker # csvpath has a different naming than the above path because historically the 79*9e94795aSAndroid Build Coastguard Worker # original Android script used csvpath, so other scripts rely on it 80*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--csvpath', default='', 81*9e94795aSAndroid Build Coastguard Worker help='Save CSV warning file to the passed path') 82*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--gencsv', action='store_true', 83*9e94795aSAndroid Build Coastguard Worker help='Generate CSV file with number of various warnings') 84*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--csvwithdescription', default='', 85*9e94795aSAndroid Build Coastguard Worker help="""Save CSV warning file to the passed path this csv 86*9e94795aSAndroid Build Coastguard Worker will contain all the warning descriptions""") 87*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--byproject', action='store_true', 88*9e94795aSAndroid Build Coastguard Worker help='Separate warnings in HTML output by project names') 89*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--url', default='', 90*9e94795aSAndroid Build Coastguard Worker help='Root URL of an Android source code tree prefixed ' 91*9e94795aSAndroid Build Coastguard Worker 'before files in warnings') 92*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--separator', default='?l=', 93*9e94795aSAndroid Build Coastguard Worker help='Separator between the end of a URL and the line ' 94*9e94795aSAndroid Build Coastguard Worker 'number argument. e.g. #') 95*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--processes', default=multiprocessing.cpu_count(), 96*9e94795aSAndroid Build Coastguard Worker type=int, 97*9e94795aSAndroid Build Coastguard Worker help='Number of parallel processes to process warnings') 98*9e94795aSAndroid Build Coastguard Worker # Old Android build scripts call warn.py without --platform, 99*9e94795aSAndroid Build Coastguard Worker # so the default platform is set to 'android'. 100*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--platform', default='android', 101*9e94795aSAndroid Build Coastguard Worker choices=['chrome', 'android'], 102*9e94795aSAndroid Build Coastguard Worker help='Platform of the build log') 103*9e94795aSAndroid Build Coastguard Worker # Old Android build scripts call warn.py with only a build.log file path. 104*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--log', help='Path to build log file') 105*9e94795aSAndroid Build Coastguard Worker parser.add_argument(dest='buildlog', metavar='build.log', 106*9e94795aSAndroid Build Coastguard Worker default='build.log', nargs='?', 107*9e94795aSAndroid Build Coastguard Worker help='Path to build.log file') 108*9e94795aSAndroid Build Coastguard Worker flags = parser.parse_args() 109*9e94795aSAndroid Build Coastguard Worker if not flags.log: 110*9e94795aSAndroid Build Coastguard Worker flags.log = flags.buildlog 111*9e94795aSAndroid Build Coastguard Worker if not use_google3 and not os.path.exists(flags.log): 112*9e94795aSAndroid Build Coastguard Worker sys.exit('Cannot find log file: ' + flags.log) 113*9e94795aSAndroid Build Coastguard Worker return flags 114*9e94795aSAndroid Build Coastguard Worker 115*9e94795aSAndroid Build Coastguard Worker 116*9e94795aSAndroid Build Coastguard Workerdef get_project_names(project_list): 117*9e94795aSAndroid Build Coastguard Worker """Get project_names from project_list.""" 118*9e94795aSAndroid Build Coastguard Worker return [p[0] for p in project_list] 119*9e94795aSAndroid Build Coastguard Worker 120*9e94795aSAndroid Build Coastguard Worker 121*9e94795aSAndroid Build Coastguard Workerdef find_project_index(line, project_patterns): 122*9e94795aSAndroid Build Coastguard Worker """Return the index to the project pattern array.""" 123*9e94795aSAndroid Build Coastguard Worker for idx, pattern in enumerate(project_patterns): 124*9e94795aSAndroid Build Coastguard Worker if pattern.match(line): 125*9e94795aSAndroid Build Coastguard Worker return idx 126*9e94795aSAndroid Build Coastguard Worker return -1 127*9e94795aSAndroid Build Coastguard Worker 128*9e94795aSAndroid Build Coastguard Worker 129*9e94795aSAndroid Build Coastguard Workerdef classify_one_warning(warning, link, results, project_patterns, 130*9e94795aSAndroid Build Coastguard Worker warn_patterns): 131*9e94795aSAndroid Build Coastguard Worker """Classify one warning line.""" 132*9e94795aSAndroid Build Coastguard Worker for idx, pattern in enumerate(warn_patterns): 133*9e94795aSAndroid Build Coastguard Worker for cpat in pattern['compiled_patterns']: 134*9e94795aSAndroid Build Coastguard Worker if cpat.match(warning): 135*9e94795aSAndroid Build Coastguard Worker project_idx = find_project_index(warning, project_patterns) 136*9e94795aSAndroid Build Coastguard Worker results.append([warning, link, idx, project_idx]) 137*9e94795aSAndroid Build Coastguard Worker return 138*9e94795aSAndroid Build Coastguard Worker # If we end up here, there was a problem parsing the log 139*9e94795aSAndroid Build Coastguard Worker # probably caused by 'make -j' mixing the output from 140*9e94795aSAndroid Build Coastguard Worker # 2 or more concurrent compiles 141*9e94795aSAndroid Build Coastguard Worker 142*9e94795aSAndroid Build Coastguard Worker 143*9e94795aSAndroid Build Coastguard Workerdef remove_prefix(src, sub): 144*9e94795aSAndroid Build Coastguard Worker """Remove everything before last occurrence of substring sub in string src.""" 145*9e94795aSAndroid Build Coastguard Worker if sub in src: 146*9e94795aSAndroid Build Coastguard Worker inc_sub = src.rfind(sub) 147*9e94795aSAndroid Build Coastguard Worker return src[inc_sub:] 148*9e94795aSAndroid Build Coastguard Worker return src 149*9e94795aSAndroid Build Coastguard Worker 150*9e94795aSAndroid Build Coastguard Worker 151*9e94795aSAndroid Build Coastguard Worker# TODO(emmavukelj): Don't have any generate_*_cs_link functions call 152*9e94795aSAndroid Build Coastguard Worker# normalize_path a second time (the first time being in parse_input_file) 153*9e94795aSAndroid Build Coastguard Workerdef generate_cs_link(warning_line, flags, android_root=None): 154*9e94795aSAndroid Build Coastguard Worker """Try to add code search HTTP URL prefix.""" 155*9e94795aSAndroid Build Coastguard Worker if flags.platform == 'chrome': 156*9e94795aSAndroid Build Coastguard Worker return generate_chrome_cs_link(warning_line, flags) 157*9e94795aSAndroid Build Coastguard Worker if flags.platform == 'android': 158*9e94795aSAndroid Build Coastguard Worker return generate_android_cs_link(warning_line, flags, android_root) 159*9e94795aSAndroid Build Coastguard Worker return 'https://cs.corp.google.com/' 160*9e94795aSAndroid Build Coastguard Worker 161*9e94795aSAndroid Build Coastguard Worker 162*9e94795aSAndroid Build Coastguard Workerdef generate_android_cs_link(warning_line, flags, android_root): 163*9e94795aSAndroid Build Coastguard Worker """Generate the code search link for a warning line in Android.""" 164*9e94795aSAndroid Build Coastguard Worker # max_splits=2 -> only 3 items 165*9e94795aSAndroid Build Coastguard Worker raw_path, line_number_str, _ = warning_line.split(':', 2) 166*9e94795aSAndroid Build Coastguard Worker normalized_path = normalize_path(raw_path, flags, android_root) 167*9e94795aSAndroid Build Coastguard Worker if not flags.url: 168*9e94795aSAndroid Build Coastguard Worker return normalized_path 169*9e94795aSAndroid Build Coastguard Worker link_path = flags.url + '/' + normalized_path 170*9e94795aSAndroid Build Coastguard Worker if line_number_str.isdigit(): 171*9e94795aSAndroid Build Coastguard Worker link_path += flags.separator + line_number_str 172*9e94795aSAndroid Build Coastguard Worker return link_path 173*9e94795aSAndroid Build Coastguard Worker 174*9e94795aSAndroid Build Coastguard Worker 175*9e94795aSAndroid Build Coastguard Workerdef generate_chrome_cs_link(warning_line, flags): 176*9e94795aSAndroid Build Coastguard Worker """Generate the code search link for a warning line in Chrome.""" 177*9e94795aSAndroid Build Coastguard Worker split_line = warning_line.split(':') 178*9e94795aSAndroid Build Coastguard Worker raw_path = split_line[0] 179*9e94795aSAndroid Build Coastguard Worker normalized_path = normalize_path(raw_path, flags) 180*9e94795aSAndroid Build Coastguard Worker link_base = 'https://cs.chromium.org/' 181*9e94795aSAndroid Build Coastguard Worker link_add = 'chromium' 182*9e94795aSAndroid Build Coastguard Worker link_path = None 183*9e94795aSAndroid Build Coastguard Worker 184*9e94795aSAndroid Build Coastguard Worker # Basically just going through a few specific directory cases and specifying 185*9e94795aSAndroid Build Coastguard Worker # the proper behavior for that case. This list of cases was accumulated 186*9e94795aSAndroid Build Coastguard Worker # through trial and error manually going through the warnings. 187*9e94795aSAndroid Build Coastguard Worker # 188*9e94795aSAndroid Build Coastguard Worker # This code pattern of using case-specific "if"s instead of "elif"s looks 189*9e94795aSAndroid Build Coastguard Worker # possibly accidental and mistaken but it is intentional because some paths 190*9e94795aSAndroid Build Coastguard Worker # fall under several cases (e.g. third_party/lib/nghttp2_frame.c) and for 191*9e94795aSAndroid Build Coastguard Worker # those we want the most specific case to be applied. If there is reliable 192*9e94795aSAndroid Build Coastguard Worker # knowledge of exactly where these occur, this could be changed to "elif"s 193*9e94795aSAndroid Build Coastguard Worker # but there is no reliable set of paths falling under multiple cases at the 194*9e94795aSAndroid Build Coastguard Worker # moment. 195*9e94795aSAndroid Build Coastguard Worker if '/src/third_party' in raw_path: 196*9e94795aSAndroid Build Coastguard Worker link_path = remove_prefix(raw_path, '/src/third_party/') 197*9e94795aSAndroid Build Coastguard Worker if '/chrome_root/src_internal/' in raw_path: 198*9e94795aSAndroid Build Coastguard Worker link_path = remove_prefix(raw_path, '/chrome_root/src_internal/') 199*9e94795aSAndroid Build Coastguard Worker link_path = link_path[len('/chrome_root'):] # remove chrome_root 200*9e94795aSAndroid Build Coastguard Worker if '/chrome_root/src/' in raw_path: 201*9e94795aSAndroid Build Coastguard Worker link_path = remove_prefix(raw_path, '/chrome_root/src/') 202*9e94795aSAndroid Build Coastguard Worker link_path = link_path[len('/chrome_root'):] # remove chrome_root 203*9e94795aSAndroid Build Coastguard Worker if '/libassistant/' in raw_path: 204*9e94795aSAndroid Build Coastguard Worker link_add = 'eureka_internal/chromium/src' 205*9e94795aSAndroid Build Coastguard Worker link_base = 'https://cs.corp.google.com/' # internal data 206*9e94795aSAndroid Build Coastguard Worker link_path = remove_prefix(normalized_path, '/libassistant/') 207*9e94795aSAndroid Build Coastguard Worker if raw_path.startswith('gen/'): 208*9e94795aSAndroid Build Coastguard Worker link_path = '/src/out/Debug/gen/' + normalized_path 209*9e94795aSAndroid Build Coastguard Worker if '/gen/' in raw_path: 210*9e94795aSAndroid Build Coastguard Worker return '%s?q=file:%s' % (link_base, remove_prefix(normalized_path, '/gen/')) 211*9e94795aSAndroid Build Coastguard Worker 212*9e94795aSAndroid Build Coastguard Worker if not link_path and (raw_path.startswith('src/') or 213*9e94795aSAndroid Build Coastguard Worker raw_path.startswith('src_internal/')): 214*9e94795aSAndroid Build Coastguard Worker link_path = '/%s' % raw_path 215*9e94795aSAndroid Build Coastguard Worker 216*9e94795aSAndroid Build Coastguard Worker if not link_path: # can't find specific link, send a query 217*9e94795aSAndroid Build Coastguard Worker return '%s?q=file:%s' % (link_base, normalized_path) 218*9e94795aSAndroid Build Coastguard Worker 219*9e94795aSAndroid Build Coastguard Worker line_number = int(split_line[1]) 220*9e94795aSAndroid Build Coastguard Worker link = '%s%s%s?l=%d' % (link_base, link_add, link_path, line_number) 221*9e94795aSAndroid Build Coastguard Worker return link 222*9e94795aSAndroid Build Coastguard Worker 223*9e94795aSAndroid Build Coastguard Worker 224*9e94795aSAndroid Build Coastguard Workerdef find_this_file_and_android_root(path): 225*9e94795aSAndroid Build Coastguard Worker """Return android source root path if this file is found.""" 226*9e94795aSAndroid Build Coastguard Worker parts = path.split('/') 227*9e94795aSAndroid Build Coastguard Worker for idx in reversed(range(2, len(parts))): 228*9e94795aSAndroid Build Coastguard Worker root_path = '/'.join(parts[:idx]) 229*9e94795aSAndroid Build Coastguard Worker # Android root directory should contain this script. 230*9e94795aSAndroid Build Coastguard Worker if os.path.exists(root_path + '/' + THIS_FILE_PATH): 231*9e94795aSAndroid Build Coastguard Worker return root_path 232*9e94795aSAndroid Build Coastguard Worker return '' 233*9e94795aSAndroid Build Coastguard Worker 234*9e94795aSAndroid Build Coastguard Worker 235*9e94795aSAndroid Build Coastguard Workerdef find_android_root_top_dirs(root_dir): 236*9e94795aSAndroid Build Coastguard Worker """Return a list of directories under the root_dir, if it exists.""" 237*9e94795aSAndroid Build Coastguard Worker # Root directory should contain at least build/make and build/soong. 238*9e94795aSAndroid Build Coastguard Worker if (not os.path.isdir(root_dir + '/build/make') or 239*9e94795aSAndroid Build Coastguard Worker not os.path.isdir(root_dir + '/build/soong')): 240*9e94795aSAndroid Build Coastguard Worker return None 241*9e94795aSAndroid Build Coastguard Worker return list(filter(lambda d: os.path.isdir(root_dir + '/' + d), 242*9e94795aSAndroid Build Coastguard Worker os.listdir(root_dir))) 243*9e94795aSAndroid Build Coastguard Worker 244*9e94795aSAndroid Build Coastguard Worker 245*9e94795aSAndroid Build Coastguard Workerdef find_android_root(buildlog): 246*9e94795aSAndroid Build Coastguard Worker """Guess android source root from common prefix of file paths.""" 247*9e94795aSAndroid Build Coastguard Worker # Use the longest common prefix of the absolute file paths 248*9e94795aSAndroid Build Coastguard Worker # of the first 10000 warning messages as the android_root. 249*9e94795aSAndroid Build Coastguard Worker warning_lines = [] 250*9e94795aSAndroid Build Coastguard Worker warning_pattern = re.compile('^/[^ ]*/[^ ]*: warning: .*') 251*9e94795aSAndroid Build Coastguard Worker count = 0 252*9e94795aSAndroid Build Coastguard Worker for line in buildlog: 253*9e94795aSAndroid Build Coastguard Worker # We want to find android_root of a local build machine. 254*9e94795aSAndroid Build Coastguard Worker # Do not use RBE warning lines, which has '/b/f/w/' path prefix. 255*9e94795aSAndroid Build Coastguard Worker # Do not use /tmp/ file warnings. 256*9e94795aSAndroid Build Coastguard Worker if ('/b/f/w' not in line and not line.startswith('/tmp/') and 257*9e94795aSAndroid Build Coastguard Worker warning_pattern.match(line)): 258*9e94795aSAndroid Build Coastguard Worker warning_lines.append(line) 259*9e94795aSAndroid Build Coastguard Worker count += 1 260*9e94795aSAndroid Build Coastguard Worker if count > 9999: 261*9e94795aSAndroid Build Coastguard Worker break 262*9e94795aSAndroid Build Coastguard Worker # Try to find warn.py and use its location to find 263*9e94795aSAndroid Build Coastguard Worker # the source tree root. 264*9e94795aSAndroid Build Coastguard Worker if count < 100: 265*9e94795aSAndroid Build Coastguard Worker path = os.path.normpath(re.sub(':.*$', '', line)) 266*9e94795aSAndroid Build Coastguard Worker android_root = find_this_file_and_android_root(path) 267*9e94795aSAndroid Build Coastguard Worker if android_root: 268*9e94795aSAndroid Build Coastguard Worker return android_root, find_android_root_top_dirs(android_root) 269*9e94795aSAndroid Build Coastguard Worker # Do not use common prefix of a small number of paths. 270*9e94795aSAndroid Build Coastguard Worker android_root = '' 271*9e94795aSAndroid Build Coastguard Worker if count > 10: 272*9e94795aSAndroid Build Coastguard Worker # pytype: disable=wrong-arg-types 273*9e94795aSAndroid Build Coastguard Worker root_path = os.path.commonprefix(warning_lines) 274*9e94795aSAndroid Build Coastguard Worker # pytype: enable=wrong-arg-types 275*9e94795aSAndroid Build Coastguard Worker if len(root_path) > 2 and root_path[len(root_path) - 1] == '/': 276*9e94795aSAndroid Build Coastguard Worker android_root = root_path[:-1] 277*9e94795aSAndroid Build Coastguard Worker if android_root and os.path.isdir(android_root): 278*9e94795aSAndroid Build Coastguard Worker return android_root, find_android_root_top_dirs(android_root) 279*9e94795aSAndroid Build Coastguard Worker # When the build.log file is moved to a different machine where 280*9e94795aSAndroid Build Coastguard Worker # android_root is not found, use the location of this script 281*9e94795aSAndroid Build Coastguard Worker # to find the android source tree sub directories. 282*9e94795aSAndroid Build Coastguard Worker if __file__.endswith('/' + THIS_FILE_PATH): 283*9e94795aSAndroid Build Coastguard Worker script_root = __file__.replace('/' + THIS_FILE_PATH, '') 284*9e94795aSAndroid Build Coastguard Worker return android_root, find_android_root_top_dirs(script_root) 285*9e94795aSAndroid Build Coastguard Worker return android_root, None 286*9e94795aSAndroid Build Coastguard Worker 287*9e94795aSAndroid Build Coastguard Worker 288*9e94795aSAndroid Build Coastguard Workerdef remove_android_root_prefix(path, android_root): 289*9e94795aSAndroid Build Coastguard Worker """Remove android_root prefix from path if it is found.""" 290*9e94795aSAndroid Build Coastguard Worker if path.startswith(android_root): 291*9e94795aSAndroid Build Coastguard Worker return path[1 + len(android_root):] 292*9e94795aSAndroid Build Coastguard Worker return path 293*9e94795aSAndroid Build Coastguard Worker 294*9e94795aSAndroid Build Coastguard Worker 295*9e94795aSAndroid Build Coastguard Workerdef normalize_path(path, flags, android_root=None): 296*9e94795aSAndroid Build Coastguard Worker """Normalize file path relative to src/ or src-internal/ directory.""" 297*9e94795aSAndroid Build Coastguard Worker path = os.path.normpath(path) 298*9e94795aSAndroid Build Coastguard Worker 299*9e94795aSAndroid Build Coastguard Worker if flags.platform == 'android': 300*9e94795aSAndroid Build Coastguard Worker if android_root: 301*9e94795aSAndroid Build Coastguard Worker return remove_android_root_prefix(path, android_root) 302*9e94795aSAndroid Build Coastguard Worker return path 303*9e94795aSAndroid Build Coastguard Worker 304*9e94795aSAndroid Build Coastguard Worker # Remove known prefix of root path and normalize the suffix. 305*9e94795aSAndroid Build Coastguard Worker idx = path.find('chrome_root/') 306*9e94795aSAndroid Build Coastguard Worker if idx >= 0: 307*9e94795aSAndroid Build Coastguard Worker # remove chrome_root/, we want path relative to that 308*9e94795aSAndroid Build Coastguard Worker return path[idx + len('chrome_root/'):] 309*9e94795aSAndroid Build Coastguard Worker return path 310*9e94795aSAndroid Build Coastguard Worker 311*9e94795aSAndroid Build Coastguard Worker 312*9e94795aSAndroid Build Coastguard Workerdef normalize_warning_line(line, flags, android_root=None): 313*9e94795aSAndroid Build Coastguard Worker """Normalize file path relative to src directory in a warning line.""" 314*9e94795aSAndroid Build Coastguard Worker line = re.sub(u'[\u2018\u2019]', '\'', line) 315*9e94795aSAndroid Build Coastguard Worker # replace non-ASCII chars to spaces 316*9e94795aSAndroid Build Coastguard Worker line = re.sub(u'[^\x00-\x7f]', ' ', line) 317*9e94795aSAndroid Build Coastguard Worker line = line.strip() 318*9e94795aSAndroid Build Coastguard Worker first_column = line.find(':') 319*9e94795aSAndroid Build Coastguard Worker return normalize_path(line[:first_column], flags, 320*9e94795aSAndroid Build Coastguard Worker android_root) + line[first_column:] 321*9e94795aSAndroid Build Coastguard Worker 322*9e94795aSAndroid Build Coastguard Worker 323*9e94795aSAndroid Build Coastguard Workerdef parse_input_file_chrome(infile, flags): 324*9e94795aSAndroid Build Coastguard Worker """Parse Chrome input file, collect parameters and warning lines.""" 325*9e94795aSAndroid Build Coastguard Worker platform_version = 'unknown' 326*9e94795aSAndroid Build Coastguard Worker board_name = 'unknown' 327*9e94795aSAndroid Build Coastguard Worker architecture = 'unknown' 328*9e94795aSAndroid Build Coastguard Worker 329*9e94795aSAndroid Build Coastguard Worker # only handle warning lines of format 'file_path:line_no:col_no: warning: ...' 330*9e94795aSAndroid Build Coastguard Worker # Bug: http://198657613, This might need change to handle RBE output. 331*9e94795aSAndroid Build Coastguard Worker chrome_warning_pattern = r'^[^ ]*/[^ ]*:[0-9]+:[0-9]+: warning: .*' 332*9e94795aSAndroid Build Coastguard Worker 333*9e94795aSAndroid Build Coastguard Worker warning_pattern = re.compile(chrome_warning_pattern) 334*9e94795aSAndroid Build Coastguard Worker 335*9e94795aSAndroid Build Coastguard Worker # Collect all unique warning lines 336*9e94795aSAndroid Build Coastguard Worker unique_warnings = dict() 337*9e94795aSAndroid Build Coastguard Worker for line in infile: 338*9e94795aSAndroid Build Coastguard Worker if warning_pattern.match(line): 339*9e94795aSAndroid Build Coastguard Worker normalized_line = normalize_warning_line(line, flags) 340*9e94795aSAndroid Build Coastguard Worker if normalized_line not in unique_warnings: 341*9e94795aSAndroid Build Coastguard Worker unique_warnings[normalized_line] = generate_cs_link(line, flags) 342*9e94795aSAndroid Build Coastguard Worker elif (platform_version == 'unknown' or board_name == 'unknown' or 343*9e94795aSAndroid Build Coastguard Worker architecture == 'unknown'): 344*9e94795aSAndroid Build Coastguard Worker result = re.match(r'.+Package:.+chromeos-base/chromeos-chrome-', line) 345*9e94795aSAndroid Build Coastguard Worker if result is not None: 346*9e94795aSAndroid Build Coastguard Worker platform_version = 'R' + line.split('chrome-')[1].split('_')[0] 347*9e94795aSAndroid Build Coastguard Worker continue 348*9e94795aSAndroid Build Coastguard Worker result = re.match(r'.+Source\sunpacked\sin\s(.+)', line) 349*9e94795aSAndroid Build Coastguard Worker if result is not None: 350*9e94795aSAndroid Build Coastguard Worker board_name = result.group(1).split('/')[2] 351*9e94795aSAndroid Build Coastguard Worker continue 352*9e94795aSAndroid Build Coastguard Worker result = re.match(r'.+USE:\s*([^\s]*).*', line) 353*9e94795aSAndroid Build Coastguard Worker if result is not None: 354*9e94795aSAndroid Build Coastguard Worker architecture = result.group(1) 355*9e94795aSAndroid Build Coastguard Worker continue 356*9e94795aSAndroid Build Coastguard Worker 357*9e94795aSAndroid Build Coastguard Worker header_str = '%s - %s - %s' % (platform_version, board_name, architecture) 358*9e94795aSAndroid Build Coastguard Worker return unique_warnings, header_str 359*9e94795aSAndroid Build Coastguard Worker 360*9e94795aSAndroid Build Coastguard Worker 361*9e94795aSAndroid Build Coastguard Workerdef add_normalized_line_to_warnings(line, flags, android_root, unique_warnings): 362*9e94795aSAndroid Build Coastguard Worker """Parse/normalize path, updating warning line and add to warnings dict.""" 363*9e94795aSAndroid Build Coastguard Worker normalized_line = normalize_warning_line(line, flags, android_root) 364*9e94795aSAndroid Build Coastguard Worker if normalized_line not in unique_warnings: 365*9e94795aSAndroid Build Coastguard Worker unique_warnings[normalized_line] = generate_cs_link(line, flags, 366*9e94795aSAndroid Build Coastguard Worker android_root) 367*9e94795aSAndroid Build Coastguard Worker return unique_warnings 368*9e94795aSAndroid Build Coastguard Worker 369*9e94795aSAndroid Build Coastguard Worker 370*9e94795aSAndroid Build Coastguard Workerdef parse_input_file_android(infile, flags): 371*9e94795aSAndroid Build Coastguard Worker """Parse Android input file, collect parameters and warning lines.""" 372*9e94795aSAndroid Build Coastguard Worker # pylint:disable=too-many-locals,too-many-branches 373*9e94795aSAndroid Build Coastguard Worker platform_version = 'unknown' 374*9e94795aSAndroid Build Coastguard Worker target_product = 'unknown' 375*9e94795aSAndroid Build Coastguard Worker target_variant = 'unknown' 376*9e94795aSAndroid Build Coastguard Worker build_id = 'unknown' 377*9e94795aSAndroid Build Coastguard Worker android_root, root_top_dirs = find_android_root(infile) 378*9e94795aSAndroid Build Coastguard Worker infile.seek(0) 379*9e94795aSAndroid Build Coastguard Worker 380*9e94795aSAndroid Build Coastguard Worker # rustc warning messages have two lines that should be combined: 381*9e94795aSAndroid Build Coastguard Worker # warning: description 382*9e94795aSAndroid Build Coastguard Worker # --> file_path:line_number:column_number 383*9e94795aSAndroid Build Coastguard Worker # Some warning messages have no file name: 384*9e94795aSAndroid Build Coastguard Worker # warning: macro replacement list ... [bugprone-macro-parentheses] 385*9e94795aSAndroid Build Coastguard Worker # Some makefile warning messages have no line number: 386*9e94795aSAndroid Build Coastguard Worker # some/path/file.mk: warning: description 387*9e94795aSAndroid Build Coastguard Worker # C/C++ compiler warning messages have line and column numbers: 388*9e94795aSAndroid Build Coastguard Worker # some/path/file.c:line_number:column_number: warning: description 389*9e94795aSAndroid Build Coastguard Worker warning_pattern = re.compile('(^[^ ]*/[^ ]*: warning: .*)|(^warning: .*)') 390*9e94795aSAndroid Build Coastguard Worker rustc_file_position = re.compile('^[ ]+--> [^ ]*/[^ ]*:[0-9]+:[0-9]+') 391*9e94795aSAndroid Build Coastguard Worker 392*9e94795aSAndroid Build Coastguard Worker # If RBE was used, try to reclaim some warning lines (from stdout) 393*9e94795aSAndroid Build Coastguard Worker # that contain leading characters from stderr. 394*9e94795aSAndroid Build Coastguard Worker # The leading characters can be any character, including digits and spaces. 395*9e94795aSAndroid Build Coastguard Worker 396*9e94795aSAndroid Build Coastguard Worker # If a warning line's source file path contains the special RBE prefix 397*9e94795aSAndroid Build Coastguard Worker # /b/f/w/, we can remove all leading chars up to and including the "/b/f/w/". 398*9e94795aSAndroid Build Coastguard Worker bfw_warning_pattern = re.compile('.*/b/f/w/([^ ]*: warning: .*)') 399*9e94795aSAndroid Build Coastguard Worker 400*9e94795aSAndroid Build Coastguard Worker # When android_root is known and available, we find its top directories 401*9e94795aSAndroid Build Coastguard Worker # and remove all leading chars before a top directory name. 402*9e94795aSAndroid Build Coastguard Worker # We assume that the leading chars from stderr do not contain "/". 403*9e94795aSAndroid Build Coastguard Worker # For example, 404*9e94795aSAndroid Build Coastguard Worker # 10external/... 405*9e94795aSAndroid Build Coastguard Worker # 12 warningsexternal/... 406*9e94795aSAndroid Build Coastguard Worker # 413 warningexternal/... 407*9e94795aSAndroid Build Coastguard Worker # 5 warnings generatedexternal/... 408*9e94795aSAndroid Build Coastguard Worker # Suppressed 1000 warnings (packages/modules/... 409*9e94795aSAndroid Build Coastguard Worker if root_top_dirs: 410*9e94795aSAndroid Build Coastguard Worker extra_warning_pattern = re.compile( 411*9e94795aSAndroid Build Coastguard Worker '^.[^/]*((' + '|'.join(root_top_dirs) + 412*9e94795aSAndroid Build Coastguard Worker ')/[^ ]*: warning: .*)') 413*9e94795aSAndroid Build Coastguard Worker else: 414*9e94795aSAndroid Build Coastguard Worker extra_warning_pattern = re.compile('^[^/]* ([^ /]*/[^ ]*: warning: .*)') 415*9e94795aSAndroid Build Coastguard Worker 416*9e94795aSAndroid Build Coastguard Worker # Collect all unique warning lines 417*9e94795aSAndroid Build Coastguard Worker unique_warnings = dict() 418*9e94795aSAndroid Build Coastguard Worker checked_warning_lines = dict() 419*9e94795aSAndroid Build Coastguard Worker line_counter = 0 420*9e94795aSAndroid Build Coastguard Worker prev_warning = '' 421*9e94795aSAndroid Build Coastguard Worker for line in infile: 422*9e94795aSAndroid Build Coastguard Worker line_counter += 1 423*9e94795aSAndroid Build Coastguard Worker if prev_warning: 424*9e94795aSAndroid Build Coastguard Worker if rustc_file_position.match(line): 425*9e94795aSAndroid Build Coastguard Worker # must be a rustc warning, combine 2 lines into one warning 426*9e94795aSAndroid Build Coastguard Worker line = line.strip().replace('--> ', '') + ': ' + prev_warning 427*9e94795aSAndroid Build Coastguard Worker unique_warnings = add_normalized_line_to_warnings( 428*9e94795aSAndroid Build Coastguard Worker line, flags, android_root, unique_warnings) 429*9e94795aSAndroid Build Coastguard Worker prev_warning = '' 430*9e94795aSAndroid Build Coastguard Worker continue 431*9e94795aSAndroid Build Coastguard Worker # add prev_warning, and then process the current line 432*9e94795aSAndroid Build Coastguard Worker prev_warning = 'unknown_source_file: ' + prev_warning 433*9e94795aSAndroid Build Coastguard Worker unique_warnings = add_normalized_line_to_warnings( 434*9e94795aSAndroid Build Coastguard Worker prev_warning, flags, android_root, unique_warnings) 435*9e94795aSAndroid Build Coastguard Worker prev_warning = '' 436*9e94795aSAndroid Build Coastguard Worker 437*9e94795aSAndroid Build Coastguard Worker # re.match is slow, with several warning line patterns and 438*9e94795aSAndroid Build Coastguard Worker # long input lines like "TIMEOUT: ...". 439*9e94795aSAndroid Build Coastguard Worker # We save significant time by skipping non-warning lines. 440*9e94795aSAndroid Build Coastguard Worker # But do not skip the first 100 lines, because we want to 441*9e94795aSAndroid Build Coastguard Worker # catch build variables. 442*9e94795aSAndroid Build Coastguard Worker if line_counter > 100 and line.find('warning: ') < 0: 443*9e94795aSAndroid Build Coastguard Worker continue 444*9e94795aSAndroid Build Coastguard Worker 445*9e94795aSAndroid Build Coastguard Worker # A large clean build output can contain up to 90% of duplicated 446*9e94795aSAndroid Build Coastguard Worker # "warning:" lines. If we can skip them quickly, we can 447*9e94795aSAndroid Build Coastguard Worker # speed up this for-loop 3X to 5X. 448*9e94795aSAndroid Build Coastguard Worker if line in checked_warning_lines: 449*9e94795aSAndroid Build Coastguard Worker continue 450*9e94795aSAndroid Build Coastguard Worker checked_warning_lines[line] = True 451*9e94795aSAndroid Build Coastguard Worker 452*9e94795aSAndroid Build Coastguard Worker # Clean up extra prefix that could be introduced when RBE was used. 453*9e94795aSAndroid Build Coastguard Worker if '/b/f/w/' in line: 454*9e94795aSAndroid Build Coastguard Worker result = bfw_warning_pattern.search(line) 455*9e94795aSAndroid Build Coastguard Worker else: 456*9e94795aSAndroid Build Coastguard Worker result = extra_warning_pattern.search(line) 457*9e94795aSAndroid Build Coastguard Worker if result is not None: 458*9e94795aSAndroid Build Coastguard Worker line = result.group(1) 459*9e94795aSAndroid Build Coastguard Worker 460*9e94795aSAndroid Build Coastguard Worker if warning_pattern.match(line): 461*9e94795aSAndroid Build Coastguard Worker if line.startswith('warning: '): 462*9e94795aSAndroid Build Coastguard Worker # save this line and combine it with the next line 463*9e94795aSAndroid Build Coastguard Worker prev_warning = line 464*9e94795aSAndroid Build Coastguard Worker else: 465*9e94795aSAndroid Build Coastguard Worker unique_warnings = add_normalized_line_to_warnings( 466*9e94795aSAndroid Build Coastguard Worker line, flags, android_root, unique_warnings) 467*9e94795aSAndroid Build Coastguard Worker continue 468*9e94795aSAndroid Build Coastguard Worker 469*9e94795aSAndroid Build Coastguard Worker if line_counter < 100: 470*9e94795aSAndroid Build Coastguard Worker # save a little bit of time by only doing this for the first few lines 471*9e94795aSAndroid Build Coastguard Worker result = re.search('(?<=^PLATFORM_VERSION=).*', line) 472*9e94795aSAndroid Build Coastguard Worker if result is not None: 473*9e94795aSAndroid Build Coastguard Worker platform_version = result.group(0) 474*9e94795aSAndroid Build Coastguard Worker continue 475*9e94795aSAndroid Build Coastguard Worker result = re.search('(?<=^TARGET_PRODUCT=).*', line) 476*9e94795aSAndroid Build Coastguard Worker if result is not None: 477*9e94795aSAndroid Build Coastguard Worker target_product = result.group(0) 478*9e94795aSAndroid Build Coastguard Worker continue 479*9e94795aSAndroid Build Coastguard Worker result = re.search('(?<=^TARGET_BUILD_VARIANT=).*', line) 480*9e94795aSAndroid Build Coastguard Worker if result is not None: 481*9e94795aSAndroid Build Coastguard Worker target_variant = result.group(0) 482*9e94795aSAndroid Build Coastguard Worker continue 483*9e94795aSAndroid Build Coastguard Worker result = re.search('(?<=^BUILD_ID=).*', line) 484*9e94795aSAndroid Build Coastguard Worker if result is not None: 485*9e94795aSAndroid Build Coastguard Worker build_id = result.group(0) 486*9e94795aSAndroid Build Coastguard Worker continue 487*9e94795aSAndroid Build Coastguard Worker 488*9e94795aSAndroid Build Coastguard Worker if android_root: 489*9e94795aSAndroid Build Coastguard Worker new_unique_warnings = dict() 490*9e94795aSAndroid Build Coastguard Worker for warning_line in unique_warnings: 491*9e94795aSAndroid Build Coastguard Worker normalized_line = normalize_warning_line(warning_line, flags, 492*9e94795aSAndroid Build Coastguard Worker android_root) 493*9e94795aSAndroid Build Coastguard Worker new_unique_warnings[normalized_line] = generate_android_cs_link( 494*9e94795aSAndroid Build Coastguard Worker warning_line, flags, android_root) 495*9e94795aSAndroid Build Coastguard Worker unique_warnings = new_unique_warnings 496*9e94795aSAndroid Build Coastguard Worker 497*9e94795aSAndroid Build Coastguard Worker header_str = '%s - %s - %s (%s)' % ( 498*9e94795aSAndroid Build Coastguard Worker platform_version, target_product, target_variant, build_id) 499*9e94795aSAndroid Build Coastguard Worker return unique_warnings, header_str 500*9e94795aSAndroid Build Coastguard Worker 501*9e94795aSAndroid Build Coastguard Worker 502*9e94795aSAndroid Build Coastguard Workerdef parse_input_file(infile, flags): 503*9e94795aSAndroid Build Coastguard Worker """Parse one input file for chrome or android.""" 504*9e94795aSAndroid Build Coastguard Worker if flags.platform == 'chrome': 505*9e94795aSAndroid Build Coastguard Worker return parse_input_file_chrome(infile, flags) 506*9e94795aSAndroid Build Coastguard Worker if flags.platform == 'android': 507*9e94795aSAndroid Build Coastguard Worker return parse_input_file_android(infile, flags) 508*9e94795aSAndroid Build Coastguard Worker raise RuntimeError('parse_input_file not defined for platform %s' % 509*9e94795aSAndroid Build Coastguard Worker flags.platform) 510*9e94795aSAndroid Build Coastguard Worker 511*9e94795aSAndroid Build Coastguard Worker 512*9e94795aSAndroid Build Coastguard Workerdef parse_compiler_output(compiler_output): 513*9e94795aSAndroid Build Coastguard Worker """Parse compiler output for relevant info.""" 514*9e94795aSAndroid Build Coastguard Worker split_output = compiler_output.split(':', 3) # 3 = max splits 515*9e94795aSAndroid Build Coastguard Worker file_path = split_output[0] 516*9e94795aSAndroid Build Coastguard Worker line_number = int(split_output[1]) 517*9e94795aSAndroid Build Coastguard Worker col_number = int(split_output[2].split(' ')[0]) 518*9e94795aSAndroid Build Coastguard Worker warning_message = split_output[3] 519*9e94795aSAndroid Build Coastguard Worker return file_path, line_number, col_number, warning_message 520*9e94795aSAndroid Build Coastguard Worker 521*9e94795aSAndroid Build Coastguard Worker 522*9e94795aSAndroid Build Coastguard Workerdef get_warn_patterns(platform): 523*9e94795aSAndroid Build Coastguard Worker """Get and initialize warn_patterns.""" 524*9e94795aSAndroid Build Coastguard Worker warn_patterns = [] 525*9e94795aSAndroid Build Coastguard Worker if platform == 'chrome': 526*9e94795aSAndroid Build Coastguard Worker warn_patterns = cpp_patterns.warn_patterns 527*9e94795aSAndroid Build Coastguard Worker elif platform == 'android': 528*9e94795aSAndroid Build Coastguard Worker warn_patterns = (make_patterns.warn_patterns + cpp_patterns.warn_patterns + 529*9e94795aSAndroid Build Coastguard Worker java_patterns.warn_patterns + tidy_patterns.warn_patterns + 530*9e94795aSAndroid Build Coastguard Worker other_patterns.warn_patterns) 531*9e94795aSAndroid Build Coastguard Worker else: 532*9e94795aSAndroid Build Coastguard Worker raise Exception('platform name %s is not valid' % platform) 533*9e94795aSAndroid Build Coastguard Worker for pattern in warn_patterns: 534*9e94795aSAndroid Build Coastguard Worker pattern['members'] = [] 535*9e94795aSAndroid Build Coastguard Worker # Each warning pattern has a 'projects' dictionary, that 536*9e94795aSAndroid Build Coastguard Worker # maps a project name to number of warnings in that project. 537*9e94795aSAndroid Build Coastguard Worker pattern['projects'] = {} 538*9e94795aSAndroid Build Coastguard Worker return warn_patterns 539*9e94795aSAndroid Build Coastguard Worker 540*9e94795aSAndroid Build Coastguard Worker 541*9e94795aSAndroid Build Coastguard Workerdef get_project_list(platform): 542*9e94795aSAndroid Build Coastguard Worker """Return project list for appropriate platform.""" 543*9e94795aSAndroid Build Coastguard Worker if platform == 'chrome': 544*9e94795aSAndroid Build Coastguard Worker return chrome_project_list.project_list 545*9e94795aSAndroid Build Coastguard Worker if platform == 'android': 546*9e94795aSAndroid Build Coastguard Worker return android_project_list.project_list 547*9e94795aSAndroid Build Coastguard Worker raise Exception('platform name %s is not valid' % platform) 548*9e94795aSAndroid Build Coastguard Worker 549*9e94795aSAndroid Build Coastguard Worker 550*9e94795aSAndroid Build Coastguard Workerdef parallel_classify_warnings(warning_data, args, project_names, 551*9e94795aSAndroid Build Coastguard Worker project_patterns, warn_patterns, 552*9e94795aSAndroid Build Coastguard Worker use_google3, create_launch_subprocs_fn, 553*9e94795aSAndroid Build Coastguard Worker classify_warnings_fn): 554*9e94795aSAndroid Build Coastguard Worker """Classify all warning lines with num_cpu parallel processes.""" 555*9e94795aSAndroid Build Coastguard Worker # pylint:disable=too-many-arguments,too-many-locals 556*9e94795aSAndroid Build Coastguard Worker num_cpu = args.processes 557*9e94795aSAndroid Build Coastguard Worker group_results = [] 558*9e94795aSAndroid Build Coastguard Worker 559*9e94795aSAndroid Build Coastguard Worker if num_cpu > 1: 560*9e94795aSAndroid Build Coastguard Worker # set up parallel processing for this... 561*9e94795aSAndroid Build Coastguard Worker warning_groups = [[] for _ in range(num_cpu)] 562*9e94795aSAndroid Build Coastguard Worker i = 0 563*9e94795aSAndroid Build Coastguard Worker for warning, link in warning_data.items(): 564*9e94795aSAndroid Build Coastguard Worker warning_groups[i].append((warning, link)) 565*9e94795aSAndroid Build Coastguard Worker i = (i + 1) % num_cpu 566*9e94795aSAndroid Build Coastguard Worker arg_groups = [[] for _ in range(num_cpu)] 567*9e94795aSAndroid Build Coastguard Worker for i, group in enumerate(warning_groups): 568*9e94795aSAndroid Build Coastguard Worker arg_groups[i] = [{ 569*9e94795aSAndroid Build Coastguard Worker 'group': group, 570*9e94795aSAndroid Build Coastguard Worker 'project_patterns': project_patterns, 571*9e94795aSAndroid Build Coastguard Worker 'warn_patterns': warn_patterns, 572*9e94795aSAndroid Build Coastguard Worker 'num_processes': num_cpu 573*9e94795aSAndroid Build Coastguard Worker }] 574*9e94795aSAndroid Build Coastguard Worker 575*9e94795aSAndroid Build Coastguard Worker group_results = create_launch_subprocs_fn(num_cpu, 576*9e94795aSAndroid Build Coastguard Worker classify_warnings_fn, 577*9e94795aSAndroid Build Coastguard Worker arg_groups, 578*9e94795aSAndroid Build Coastguard Worker group_results) 579*9e94795aSAndroid Build Coastguard Worker else: 580*9e94795aSAndroid Build Coastguard Worker group_results = [] 581*9e94795aSAndroid Build Coastguard Worker for warning, link in warning_data.items(): 582*9e94795aSAndroid Build Coastguard Worker classify_one_warning(warning, link, group_results, 583*9e94795aSAndroid Build Coastguard Worker project_patterns, warn_patterns) 584*9e94795aSAndroid Build Coastguard Worker group_results = [group_results] 585*9e94795aSAndroid Build Coastguard Worker 586*9e94795aSAndroid Build Coastguard Worker warning_messages = [] 587*9e94795aSAndroid Build Coastguard Worker warning_links = [] 588*9e94795aSAndroid Build Coastguard Worker warning_records = [] 589*9e94795aSAndroid Build Coastguard Worker if use_google3: 590*9e94795aSAndroid Build Coastguard Worker group_results = [group_results] 591*9e94795aSAndroid Build Coastguard Worker for group_result in group_results: 592*9e94795aSAndroid Build Coastguard Worker for result in group_result: 593*9e94795aSAndroid Build Coastguard Worker for line, link, pattern_idx, project_idx in result: 594*9e94795aSAndroid Build Coastguard Worker pattern = warn_patterns[pattern_idx] 595*9e94795aSAndroid Build Coastguard Worker pattern['members'].append(line) 596*9e94795aSAndroid Build Coastguard Worker message_idx = len(warning_messages) 597*9e94795aSAndroid Build Coastguard Worker warning_messages.append(line) 598*9e94795aSAndroid Build Coastguard Worker link_idx = len(warning_links) 599*9e94795aSAndroid Build Coastguard Worker warning_links.append(link) 600*9e94795aSAndroid Build Coastguard Worker warning_records.append([pattern_idx, project_idx, message_idx, 601*9e94795aSAndroid Build Coastguard Worker link_idx]) 602*9e94795aSAndroid Build Coastguard Worker pname = '???' if project_idx < 0 else project_names[project_idx] 603*9e94795aSAndroid Build Coastguard Worker # Count warnings by project. 604*9e94795aSAndroid Build Coastguard Worker if pname in pattern['projects']: 605*9e94795aSAndroid Build Coastguard Worker pattern['projects'][pname] += 1 606*9e94795aSAndroid Build Coastguard Worker else: 607*9e94795aSAndroid Build Coastguard Worker pattern['projects'][pname] = 1 608*9e94795aSAndroid Build Coastguard Worker return warning_messages, warning_links, warning_records 609*9e94795aSAndroid Build Coastguard Worker 610*9e94795aSAndroid Build Coastguard Worker 611*9e94795aSAndroid Build Coastguard Workerdef process_log(logfile, flags, project_names, project_patterns, warn_patterns, 612*9e94795aSAndroid Build Coastguard Worker html_path, use_google3, create_launch_subprocs_fn, 613*9e94795aSAndroid Build Coastguard Worker classify_warnings_fn, logfile_object): 614*9e94795aSAndroid Build Coastguard Worker # pylint does not recognize g-doc-* 615*9e94795aSAndroid Build Coastguard Worker # pylint: disable=bad-option-value,g-doc-args 616*9e94795aSAndroid Build Coastguard Worker # pylint: disable=bad-option-value,g-doc-return-or-yield 617*9e94795aSAndroid Build Coastguard Worker # pylint: disable=too-many-arguments,too-many-locals 618*9e94795aSAndroid Build Coastguard Worker """Function that handles processing of a log. 619*9e94795aSAndroid Build Coastguard Worker 620*9e94795aSAndroid Build Coastguard Worker This is isolated into its own function (rather than just taking place in main) 621*9e94795aSAndroid Build Coastguard Worker so that it can be used by both warn.py and the borg job process_gs_logs.py, to 622*9e94795aSAndroid Build Coastguard Worker avoid duplication of code. 623*9e94795aSAndroid Build Coastguard Worker Note that if the arguments to this function change, process_gs_logs.py must 624*9e94795aSAndroid Build Coastguard Worker be updated accordingly. 625*9e94795aSAndroid Build Coastguard Worker """ 626*9e94795aSAndroid Build Coastguard Worker if logfile_object is None: 627*9e94795aSAndroid Build Coastguard Worker with io.open(logfile, encoding='utf-8') as log: 628*9e94795aSAndroid Build Coastguard Worker warning_lines_and_links, header_str = parse_input_file(log, flags) 629*9e94795aSAndroid Build Coastguard Worker else: 630*9e94795aSAndroid Build Coastguard Worker warning_lines_and_links, header_str = parse_input_file( 631*9e94795aSAndroid Build Coastguard Worker logfile_object, flags) 632*9e94795aSAndroid Build Coastguard Worker warning_messages, warning_links, warning_records = parallel_classify_warnings( 633*9e94795aSAndroid Build Coastguard Worker warning_lines_and_links, flags, project_names, project_patterns, 634*9e94795aSAndroid Build Coastguard Worker warn_patterns, use_google3, create_launch_subprocs_fn, 635*9e94795aSAndroid Build Coastguard Worker classify_warnings_fn) 636*9e94795aSAndroid Build Coastguard Worker 637*9e94795aSAndroid Build Coastguard Worker html_writer.write_html(flags, project_names, warn_patterns, html_path, 638*9e94795aSAndroid Build Coastguard Worker warning_messages, warning_links, warning_records, 639*9e94795aSAndroid Build Coastguard Worker header_str) 640*9e94795aSAndroid Build Coastguard Worker 641*9e94795aSAndroid Build Coastguard Worker return warning_messages, warning_links, warning_records, header_str 642*9e94795aSAndroid Build Coastguard Worker 643*9e94795aSAndroid Build Coastguard Worker 644*9e94795aSAndroid Build Coastguard Workerdef common_main(use_google3, create_launch_subprocs_fn, classify_warnings_fn, 645*9e94795aSAndroid Build Coastguard Worker logfile_object=None): 646*9e94795aSAndroid Build Coastguard Worker """Shared main function for Google3 and non-Google3 versions of warn.py.""" 647*9e94795aSAndroid Build Coastguard Worker flags = parse_args(use_google3) 648*9e94795aSAndroid Build Coastguard Worker warn_patterns = get_warn_patterns(flags.platform) 649*9e94795aSAndroid Build Coastguard Worker project_list = get_project_list(flags.platform) 650*9e94795aSAndroid Build Coastguard Worker 651*9e94795aSAndroid Build Coastguard Worker project_names = get_project_names(project_list) 652*9e94795aSAndroid Build Coastguard Worker project_patterns = [re.compile(p[1]) for p in project_list] 653*9e94795aSAndroid Build Coastguard Worker 654*9e94795aSAndroid Build Coastguard Worker # html_path=None because we output html below if not outputting CSV 655*9e94795aSAndroid Build Coastguard Worker warning_messages, warning_links, warning_records, header_str = process_log( 656*9e94795aSAndroid Build Coastguard Worker logfile=flags.log, flags=flags, project_names=project_names, 657*9e94795aSAndroid Build Coastguard Worker project_patterns=project_patterns, warn_patterns=warn_patterns, 658*9e94795aSAndroid Build Coastguard Worker html_path=None, use_google3=use_google3, 659*9e94795aSAndroid Build Coastguard Worker create_launch_subprocs_fn=create_launch_subprocs_fn, 660*9e94795aSAndroid Build Coastguard Worker classify_warnings_fn=classify_warnings_fn, 661*9e94795aSAndroid Build Coastguard Worker logfile_object=logfile_object) 662*9e94795aSAndroid Build Coastguard Worker 663*9e94795aSAndroid Build Coastguard Worker html_writer.write_out_csv(flags, warn_patterns, warning_messages, 664*9e94795aSAndroid Build Coastguard Worker warning_links, warning_records, header_str, 665*9e94795aSAndroid Build Coastguard Worker project_names) 666*9e94795aSAndroid Build Coastguard Worker 667*9e94795aSAndroid Build Coastguard Worker # Return these values, so that caller can use them, if desired. 668*9e94795aSAndroid Build Coastguard Worker return flags, warning_messages, warning_records, warn_patterns 669