1*387726c4SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*387726c4SAndroid Build Coastguard Worker 3*387726c4SAndroid Build Coastguard Worker# 4*387726c4SAndroid Build Coastguard Worker# Copyright 2015, The Android Open Source Project 5*387726c4SAndroid Build Coastguard Worker# 6*387726c4SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 7*387726c4SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 8*387726c4SAndroid Build Coastguard Worker# You may obtain a copy of the License at 9*387726c4SAndroid Build Coastguard Worker# 10*387726c4SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 11*387726c4SAndroid Build Coastguard Worker# 12*387726c4SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 13*387726c4SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 14*387726c4SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15*387726c4SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 16*387726c4SAndroid Build Coastguard Worker# limitations under the License. 17*387726c4SAndroid Build Coastguard Worker# 18*387726c4SAndroid Build Coastguard Worker 19*387726c4SAndroid Build Coastguard Worker"""Script that is used by developers to run style checks on Java files.""" 20*387726c4SAndroid Build Coastguard Worker 21*387726c4SAndroid Build Coastguard Workerfrom __future__ import print_function 22*387726c4SAndroid Build Coastguard Worker 23*387726c4SAndroid Build Coastguard Workerimport argparse 24*387726c4SAndroid Build Coastguard Workerimport errno 25*387726c4SAndroid Build Coastguard Workerimport os 26*387726c4SAndroid Build Coastguard Workerimport shutil 27*387726c4SAndroid Build Coastguard Workerimport subprocess 28*387726c4SAndroid Build Coastguard Workerimport sys 29*387726c4SAndroid Build Coastguard Workerimport tempfile 30*387726c4SAndroid Build Coastguard Workerimport xml.dom.minidom 31*387726c4SAndroid Build Coastguard Workerimport gitlint.git as git 32*387726c4SAndroid Build Coastguard Worker 33*387726c4SAndroid Build Coastguard Worker 34*387726c4SAndroid Build Coastguard Workerdef _FindFoldersContaining(root, wanted): 35*387726c4SAndroid Build Coastguard Worker """Recursively finds directories that have a file with the given name. 36*387726c4SAndroid Build Coastguard Worker 37*387726c4SAndroid Build Coastguard Worker Args: 38*387726c4SAndroid Build Coastguard Worker root: Root folder to start the search from. 39*387726c4SAndroid Build Coastguard Worker wanted: The filename that we are looking for. 40*387726c4SAndroid Build Coastguard Worker 41*387726c4SAndroid Build Coastguard Worker Returns: 42*387726c4SAndroid Build Coastguard Worker List of folders that has a file with the given name 43*387726c4SAndroid Build Coastguard Worker """ 44*387726c4SAndroid Build Coastguard Worker 45*387726c4SAndroid Build Coastguard Worker if not root: 46*387726c4SAndroid Build Coastguard Worker return [] 47*387726c4SAndroid Build Coastguard Worker if os.path.islink(root): 48*387726c4SAndroid Build Coastguard Worker return [] 49*387726c4SAndroid Build Coastguard Worker result = [] 50*387726c4SAndroid Build Coastguard Worker for file_name in os.listdir(root): 51*387726c4SAndroid Build Coastguard Worker file_path = os.path.join(root, file_name) 52*387726c4SAndroid Build Coastguard Worker if os.path.isdir(file_path): 53*387726c4SAndroid Build Coastguard Worker sub_result = _FindFoldersContaining(file_path, wanted) 54*387726c4SAndroid Build Coastguard Worker result.extend(sub_result) 55*387726c4SAndroid Build Coastguard Worker else: 56*387726c4SAndroid Build Coastguard Worker if file_name == wanted: 57*387726c4SAndroid Build Coastguard Worker result.append(root) 58*387726c4SAndroid Build Coastguard Worker return result 59*387726c4SAndroid Build Coastguard Worker 60*387726c4SAndroid Build Coastguard WorkerMAIN_DIRECTORY = os.path.normpath(os.path.dirname(__file__)) 61*387726c4SAndroid Build Coastguard WorkerCHECKSTYLE_JAR = os.path.join(MAIN_DIRECTORY, 'checkstyle.jar') 62*387726c4SAndroid Build Coastguard WorkerCHECKSTYLE_STYLE = os.path.join(MAIN_DIRECTORY, 'android-style.xml') 63*387726c4SAndroid Build Coastguard WorkerFORCED_RULES = ['com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck', 64*387726c4SAndroid Build Coastguard Worker 'com.puppycrawl.tools.checkstyle.checks.imports.UnusedImportsCheck'] 65*387726c4SAndroid Build Coastguard WorkerSKIPPED_RULES_FOR_TEST_FILES = ['com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTypeCheck', 66*387726c4SAndroid Build Coastguard Worker 'com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck'] 67*387726c4SAndroid Build Coastguard WorkerSUBPATH_FOR_TEST_FILES = ['/tests/', '/test/', '/androidTest/', '/perftests/', '/gts-tests/', 68*387726c4SAndroid Build Coastguard Worker '/hostsidetests/', '/jvmTest/', '/robotests/', '/robolectric/'] 69*387726c4SAndroid Build Coastguard WorkerSUBPATH_FOR_TEST_DATA_FILES = _FindFoldersContaining(git.repository_root(), 70*387726c4SAndroid Build Coastguard Worker 'IGNORE_CHECKSTYLE') 71*387726c4SAndroid Build Coastguard WorkerERROR_UNCOMMITTED = 'You need to commit all modified files before running Checkstyle\n' 72*387726c4SAndroid Build Coastguard WorkerERROR_UNTRACKED = 'You have untracked java files that are not being checked:\n' 73*387726c4SAndroid Build Coastguard Worker 74*387726c4SAndroid Build Coastguard Worker 75*387726c4SAndroid Build Coastguard Workerdef RunCheckstyleOnFiles(java_files, classpath=CHECKSTYLE_JAR, config_xml=CHECKSTYLE_STYLE): 76*387726c4SAndroid Build Coastguard Worker """Runs Checkstyle checks on a given set of java_files. 77*387726c4SAndroid Build Coastguard Worker 78*387726c4SAndroid Build Coastguard Worker Args: 79*387726c4SAndroid Build Coastguard Worker java_files: A list of files to check. 80*387726c4SAndroid Build Coastguard Worker classpath: The colon-delimited list of JARs in the classpath. 81*387726c4SAndroid Build Coastguard Worker config_xml: Path of the checkstyle XML configuration file. 82*387726c4SAndroid Build Coastguard Worker 83*387726c4SAndroid Build Coastguard Worker Returns: 84*387726c4SAndroid Build Coastguard Worker A tuple of errors and warnings. 85*387726c4SAndroid Build Coastguard Worker """ 86*387726c4SAndroid Build Coastguard Worker print('Running Checkstyle on inputted files') 87*387726c4SAndroid Build Coastguard Worker java_files = list(map(os.path.abspath, java_files)) 88*387726c4SAndroid Build Coastguard Worker stdout = _ExecuteCheckstyle(java_files, classpath, config_xml) 89*387726c4SAndroid Build Coastguard Worker (errors, warnings) = _ParseAndFilterOutput(stdout) 90*387726c4SAndroid Build Coastguard Worker _PrintErrorsAndWarnings(errors, warnings) 91*387726c4SAndroid Build Coastguard Worker return errors, warnings 92*387726c4SAndroid Build Coastguard Worker 93*387726c4SAndroid Build Coastguard Worker 94*387726c4SAndroid Build Coastguard Workerdef RunCheckstyleOnACommit(commit, 95*387726c4SAndroid Build Coastguard Worker classpath=CHECKSTYLE_JAR, 96*387726c4SAndroid Build Coastguard Worker config_xml=CHECKSTYLE_STYLE, 97*387726c4SAndroid Build Coastguard Worker file_whitelist=None): 98*387726c4SAndroid Build Coastguard Worker """Runs Checkstyle checks on a given commit. 99*387726c4SAndroid Build Coastguard Worker 100*387726c4SAndroid Build Coastguard Worker It will run Checkstyle on the changed Java files in a specified commit SHA-1 101*387726c4SAndroid Build Coastguard Worker and if that is None it will fallback to check the latest commit of the 102*387726c4SAndroid Build Coastguard Worker currently checked out branch. 103*387726c4SAndroid Build Coastguard Worker 104*387726c4SAndroid Build Coastguard Worker Args: 105*387726c4SAndroid Build Coastguard Worker commit: A full 40 character SHA-1 of a commit to check. 106*387726c4SAndroid Build Coastguard Worker classpath: The colon-delimited list of JARs in the classpath. 107*387726c4SAndroid Build Coastguard Worker config_xml: Path of the checkstyle XML configuration file. 108*387726c4SAndroid Build Coastguard Worker file_whitelist: A list of whitelisted file paths that should be checked. 109*387726c4SAndroid Build Coastguard Worker 110*387726c4SAndroid Build Coastguard Worker Returns: 111*387726c4SAndroid Build Coastguard Worker A tuple of errors and warnings. 112*387726c4SAndroid Build Coastguard Worker """ 113*387726c4SAndroid Build Coastguard Worker if not git.repository_root(): 114*387726c4SAndroid Build Coastguard Worker print('FAILURE: not inside a git repository') 115*387726c4SAndroid Build Coastguard Worker sys.exit(1) 116*387726c4SAndroid Build Coastguard Worker explicit_commit = commit is not None 117*387726c4SAndroid Build Coastguard Worker if not explicit_commit: 118*387726c4SAndroid Build Coastguard Worker _WarnIfUntrackedFiles() 119*387726c4SAndroid Build Coastguard Worker commit = git.last_commit() 120*387726c4SAndroid Build Coastguard Worker print('Running Checkstyle on %s commit' % commit) 121*387726c4SAndroid Build Coastguard Worker commit_modified_files = _GetModifiedFiles(commit, explicit_commit) 122*387726c4SAndroid Build Coastguard Worker commit_modified_files = _FilterFiles(commit_modified_files, file_whitelist) 123*387726c4SAndroid Build Coastguard Worker if not list(commit_modified_files.keys()): 124*387726c4SAndroid Build Coastguard Worker print('No Java files to check') 125*387726c4SAndroid Build Coastguard Worker return [], [] 126*387726c4SAndroid Build Coastguard Worker 127*387726c4SAndroid Build Coastguard Worker (tmp_dir, tmp_file_map) = _GetTempFilesForCommit( 128*387726c4SAndroid Build Coastguard Worker list(commit_modified_files.keys()), commit) 129*387726c4SAndroid Build Coastguard Worker 130*387726c4SAndroid Build Coastguard Worker java_files = list(tmp_file_map.keys()) 131*387726c4SAndroid Build Coastguard Worker stdout = _ExecuteCheckstyle(java_files, classpath, config_xml) 132*387726c4SAndroid Build Coastguard Worker 133*387726c4SAndroid Build Coastguard Worker # Remove all the temporary files. 134*387726c4SAndroid Build Coastguard Worker shutil.rmtree(tmp_dir) 135*387726c4SAndroid Build Coastguard Worker 136*387726c4SAndroid Build Coastguard Worker (errors, warnings) = _ParseAndFilterOutput(stdout, 137*387726c4SAndroid Build Coastguard Worker commit, 138*387726c4SAndroid Build Coastguard Worker commit_modified_files, 139*387726c4SAndroid Build Coastguard Worker tmp_file_map) 140*387726c4SAndroid Build Coastguard Worker _PrintErrorsAndWarnings(errors, warnings) 141*387726c4SAndroid Build Coastguard Worker return errors, warnings 142*387726c4SAndroid Build Coastguard Worker 143*387726c4SAndroid Build Coastguard Worker 144*387726c4SAndroid Build Coastguard Workerdef _WarnIfUntrackedFiles(out=sys.stdout): 145*387726c4SAndroid Build Coastguard Worker """Prints a warning and a list of untracked files if needed.""" 146*387726c4SAndroid Build Coastguard Worker root = git.repository_root() 147*387726c4SAndroid Build Coastguard Worker untracked_files = git.modified_files(root, False) 148*387726c4SAndroid Build Coastguard Worker untracked_files = {f for f in untracked_files if f.endswith('.java')} 149*387726c4SAndroid Build Coastguard Worker if untracked_files: 150*387726c4SAndroid Build Coastguard Worker out.write(ERROR_UNTRACKED) 151*387726c4SAndroid Build Coastguard Worker for untracked_file in untracked_files: 152*387726c4SAndroid Build Coastguard Worker out.write(untracked_file + '\n') 153*387726c4SAndroid Build Coastguard Worker out.write('\n') 154*387726c4SAndroid Build Coastguard Worker 155*387726c4SAndroid Build Coastguard Worker 156*387726c4SAndroid Build Coastguard Workerdef _PrintErrorsAndWarnings(errors, warnings): 157*387726c4SAndroid Build Coastguard Worker """Prints given errors and warnings.""" 158*387726c4SAndroid Build Coastguard Worker if errors: 159*387726c4SAndroid Build Coastguard Worker print('ERRORS:\n' + '\n'.join(errors)) 160*387726c4SAndroid Build Coastguard Worker if warnings: 161*387726c4SAndroid Build Coastguard Worker print('WARNINGS:\n' + '\n'.join(warnings)) 162*387726c4SAndroid Build Coastguard Worker 163*387726c4SAndroid Build Coastguard Workerdef _CheckForJava(): 164*387726c4SAndroid Build Coastguard Worker try: 165*387726c4SAndroid Build Coastguard Worker java_env = os.environ.copy() 166*387726c4SAndroid Build Coastguard Worker java_env['JAVA_CMD'] = 'java' 167*387726c4SAndroid Build Coastguard Worker check = subprocess.Popen(['java', '--help'], 168*387726c4SAndroid Build Coastguard Worker stdout=subprocess.PIPE, env=java_env, 169*387726c4SAndroid Build Coastguard Worker universal_newlines=True) 170*387726c4SAndroid Build Coastguard Worker stdout, _ = check.communicate() 171*387726c4SAndroid Build Coastguard Worker stdout_lines = stdout.splitlines() 172*387726c4SAndroid Build Coastguard Worker except OSError as e: 173*387726c4SAndroid Build Coastguard Worker if e.errno == errno.ENOENT: 174*387726c4SAndroid Build Coastguard Worker print('Error: Could not find `java` on path!') 175*387726c4SAndroid Build Coastguard Worker sys.exit(1) 176*387726c4SAndroid Build Coastguard Worker 177*387726c4SAndroid Build Coastguard Workerdef _ExecuteCheckstyle(java_files, classpath, config_xml): 178*387726c4SAndroid Build Coastguard Worker """Runs Checkstyle to check give Java files for style errors. 179*387726c4SAndroid Build Coastguard Worker 180*387726c4SAndroid Build Coastguard Worker Args: 181*387726c4SAndroid Build Coastguard Worker java_files: A list of Java files that needs to be checked. 182*387726c4SAndroid Build Coastguard Worker classpath: The colon-delimited list of JARs in the classpath. 183*387726c4SAndroid Build Coastguard Worker config_xml: Path of the checkstyle XML configuration file. 184*387726c4SAndroid Build Coastguard Worker 185*387726c4SAndroid Build Coastguard Worker Returns: 186*387726c4SAndroid Build Coastguard Worker Checkstyle output in XML format. 187*387726c4SAndroid Build Coastguard Worker """ 188*387726c4SAndroid Build Coastguard Worker # Run checkstyle 189*387726c4SAndroid Build Coastguard Worker checkstyle_env = os.environ.copy() 190*387726c4SAndroid Build Coastguard Worker checkstyle_env['JAVA_CMD'] = 'java' 191*387726c4SAndroid Build Coastguard Worker 192*387726c4SAndroid Build Coastguard Worker try: 193*387726c4SAndroid Build Coastguard Worker check = subprocess.Popen(['java', 194*387726c4SAndroid Build Coastguard Worker '-Dcheckstyle.enableExternalDtdLoad=true', 195*387726c4SAndroid Build Coastguard Worker '-cp', classpath, 196*387726c4SAndroid Build Coastguard Worker 'com.puppycrawl.tools.checkstyle.Main', '-c', 197*387726c4SAndroid Build Coastguard Worker config_xml, '-f', 'xml'] + java_files, 198*387726c4SAndroid Build Coastguard Worker stdout=subprocess.PIPE, env=checkstyle_env, 199*387726c4SAndroid Build Coastguard Worker universal_newlines=True) 200*387726c4SAndroid Build Coastguard Worker stdout, _ = check.communicate() 201*387726c4SAndroid Build Coastguard Worker stdout_lines = stdout.splitlines() 202*387726c4SAndroid Build Coastguard Worker # A work-around for Checkstyle printing error count to stdio. 203*387726c4SAndroid Build Coastguard Worker if len(stdout_lines) < 2: 204*387726c4SAndroid Build Coastguard Worker stdout = stdout_lines[0] 205*387726c4SAndroid Build Coastguard Worker elif len(stdout_lines) >= 2 and '</checkstyle>' in stdout_lines[-2]: 206*387726c4SAndroid Build Coastguard Worker stdout = '\n'.join(stdout_lines[:-1]) 207*387726c4SAndroid Build Coastguard Worker return stdout 208*387726c4SAndroid Build Coastguard Worker except OSError as e: 209*387726c4SAndroid Build Coastguard Worker if e.errno == errno.ENOENT: 210*387726c4SAndroid Build Coastguard Worker _CheckForJava() 211*387726c4SAndroid Build Coastguard Worker print('Error running Checkstyle!') 212*387726c4SAndroid Build Coastguard Worker sys.exit(1) 213*387726c4SAndroid Build Coastguard Worker 214*387726c4SAndroid Build Coastguard Worker 215*387726c4SAndroid Build Coastguard Workerdef _ParseAndFilterOutput(stdout, 216*387726c4SAndroid Build Coastguard Worker sha=None, 217*387726c4SAndroid Build Coastguard Worker commit_modified_files=None, 218*387726c4SAndroid Build Coastguard Worker tmp_file_map=None): 219*387726c4SAndroid Build Coastguard Worker result_errors = [] 220*387726c4SAndroid Build Coastguard Worker result_warnings = [] 221*387726c4SAndroid Build Coastguard Worker root = xml.dom.minidom.parseString(stdout) 222*387726c4SAndroid Build Coastguard Worker for file_element in root.getElementsByTagName('file'): 223*387726c4SAndroid Build Coastguard Worker file_name = file_element.attributes['name'].value 224*387726c4SAndroid Build Coastguard Worker if tmp_file_map: 225*387726c4SAndroid Build Coastguard Worker file_name = tmp_file_map[file_name] 226*387726c4SAndroid Build Coastguard Worker modified_lines = None 227*387726c4SAndroid Build Coastguard Worker if commit_modified_files: 228*387726c4SAndroid Build Coastguard Worker modified_lines = git.modified_lines(file_name, 229*387726c4SAndroid Build Coastguard Worker commit_modified_files[file_name], 230*387726c4SAndroid Build Coastguard Worker sha) 231*387726c4SAndroid Build Coastguard Worker test_class = any(substring in file_name for substring 232*387726c4SAndroid Build Coastguard Worker in SUBPATH_FOR_TEST_FILES) 233*387726c4SAndroid Build Coastguard Worker test_data_class = any(substring in file_name for substring 234*387726c4SAndroid Build Coastguard Worker in SUBPATH_FOR_TEST_DATA_FILES) 235*387726c4SAndroid Build Coastguard Worker file_name = os.path.relpath(file_name) 236*387726c4SAndroid Build Coastguard Worker errors = file_element.getElementsByTagName('error') 237*387726c4SAndroid Build Coastguard Worker for error in errors: 238*387726c4SAndroid Build Coastguard Worker line = int(error.attributes['line'].value) 239*387726c4SAndroid Build Coastguard Worker rule = error.attributes['source'].value 240*387726c4SAndroid Build Coastguard Worker if _ShouldSkip(commit_modified_files, modified_lines, line, rule, 241*387726c4SAndroid Build Coastguard Worker test_class, test_data_class): 242*387726c4SAndroid Build Coastguard Worker continue 243*387726c4SAndroid Build Coastguard Worker 244*387726c4SAndroid Build Coastguard Worker column = '' 245*387726c4SAndroid Build Coastguard Worker if error.hasAttribute('column'): 246*387726c4SAndroid Build Coastguard Worker column = '%s:' % error.attributes['column'].value 247*387726c4SAndroid Build Coastguard Worker message = error.attributes['message'].value 248*387726c4SAndroid Build Coastguard Worker project = '' 249*387726c4SAndroid Build Coastguard Worker if os.environ.get('REPO_PROJECT'): 250*387726c4SAndroid Build Coastguard Worker project = '[' + os.environ.get('REPO_PROJECT') + '] ' 251*387726c4SAndroid Build Coastguard Worker 252*387726c4SAndroid Build Coastguard Worker result = ' %s%s:%s:%s %s' % (project, file_name, line, column, message) 253*387726c4SAndroid Build Coastguard Worker 254*387726c4SAndroid Build Coastguard Worker severity = error.attributes['severity'].value 255*387726c4SAndroid Build Coastguard Worker if severity == 'error': 256*387726c4SAndroid Build Coastguard Worker result_errors.append(result) 257*387726c4SAndroid Build Coastguard Worker elif severity == 'warning': 258*387726c4SAndroid Build Coastguard Worker result_warnings.append(result) 259*387726c4SAndroid Build Coastguard Worker return result_errors, result_warnings 260*387726c4SAndroid Build Coastguard Worker 261*387726c4SAndroid Build Coastguard Worker 262*387726c4SAndroid Build Coastguard Workerdef _ShouldSkip(commit_check, modified_lines, line, rule, test_class=False, 263*387726c4SAndroid Build Coastguard Worker test_data_class=False): 264*387726c4SAndroid Build Coastguard Worker """Returns whether an error on a given line should be skipped. 265*387726c4SAndroid Build Coastguard Worker 266*387726c4SAndroid Build Coastguard Worker Args: 267*387726c4SAndroid Build Coastguard Worker commit_check: Whether Checkstyle is being run on a specific commit. 268*387726c4SAndroid Build Coastguard Worker modified_lines: A list of lines that has been modified. 269*387726c4SAndroid Build Coastguard Worker line: The line that has a rule violation. 270*387726c4SAndroid Build Coastguard Worker rule: The type of rule that a given line is violating. 271*387726c4SAndroid Build Coastguard Worker test_class: Whether the file being checked is a test class. 272*387726c4SAndroid Build Coastguard Worker test_data_class: Whether the file being check is a class used as test data. 273*387726c4SAndroid Build Coastguard Worker 274*387726c4SAndroid Build Coastguard Worker Returns: 275*387726c4SAndroid Build Coastguard Worker A boolean whether a given line should be skipped in the reporting. 276*387726c4SAndroid Build Coastguard Worker """ 277*387726c4SAndroid Build Coastguard Worker # None modified_lines means checked file is new and nothing should be skipped. 278*387726c4SAndroid Build Coastguard Worker if test_data_class: 279*387726c4SAndroid Build Coastguard Worker return True 280*387726c4SAndroid Build Coastguard Worker if test_class and rule in SKIPPED_RULES_FOR_TEST_FILES: 281*387726c4SAndroid Build Coastguard Worker return True 282*387726c4SAndroid Build Coastguard Worker if not commit_check: 283*387726c4SAndroid Build Coastguard Worker return False 284*387726c4SAndroid Build Coastguard Worker if modified_lines is None: 285*387726c4SAndroid Build Coastguard Worker return False 286*387726c4SAndroid Build Coastguard Worker return line not in modified_lines and rule not in FORCED_RULES 287*387726c4SAndroid Build Coastguard Worker 288*387726c4SAndroid Build Coastguard Worker 289*387726c4SAndroid Build Coastguard Workerdef _GetModifiedFiles(commit, explicit_commit=False, out=sys.stdout): 290*387726c4SAndroid Build Coastguard Worker root = git.repository_root() 291*387726c4SAndroid Build Coastguard Worker pending_files = git.modified_files(root, True) 292*387726c4SAndroid Build Coastguard Worker if pending_files and not explicit_commit: 293*387726c4SAndroid Build Coastguard Worker out.write(ERROR_UNCOMMITTED) 294*387726c4SAndroid Build Coastguard Worker sys.exit(1) 295*387726c4SAndroid Build Coastguard Worker 296*387726c4SAndroid Build Coastguard Worker modified_files = git.modified_files(root, True, commit) 297*387726c4SAndroid Build Coastguard Worker modified_files = {f: modified_files[f] for f 298*387726c4SAndroid Build Coastguard Worker in modified_files if f.endswith('.java')} 299*387726c4SAndroid Build Coastguard Worker return modified_files 300*387726c4SAndroid Build Coastguard Worker 301*387726c4SAndroid Build Coastguard Worker 302*387726c4SAndroid Build Coastguard Workerdef _FilterFiles(files, file_whitelist): 303*387726c4SAndroid Build Coastguard Worker if not file_whitelist: 304*387726c4SAndroid Build Coastguard Worker return files 305*387726c4SAndroid Build Coastguard Worker return {f: files[f] for f in files 306*387726c4SAndroid Build Coastguard Worker for whitelist in file_whitelist if whitelist in f} 307*387726c4SAndroid Build Coastguard Worker 308*387726c4SAndroid Build Coastguard Worker 309*387726c4SAndroid Build Coastguard Workerdef _GetTempFilesForCommit(file_names, commit): 310*387726c4SAndroid Build Coastguard Worker """Creates a temporary snapshot of the files in at a commit. 311*387726c4SAndroid Build Coastguard Worker 312*387726c4SAndroid Build Coastguard Worker Retrieves the state of every file in file_names at a given commit and writes 313*387726c4SAndroid Build Coastguard Worker them all out to a temporary directory. 314*387726c4SAndroid Build Coastguard Worker 315*387726c4SAndroid Build Coastguard Worker Args: 316*387726c4SAndroid Build Coastguard Worker file_names: A list of files that need to be retrieved. 317*387726c4SAndroid Build Coastguard Worker commit: A full 40 character SHA-1 of a commit. 318*387726c4SAndroid Build Coastguard Worker 319*387726c4SAndroid Build Coastguard Worker Returns: 320*387726c4SAndroid Build Coastguard Worker A tuple of temprorary directory name and a directionary of 321*387726c4SAndroid Build Coastguard Worker temp_file_name: filename. For example: 322*387726c4SAndroid Build Coastguard Worker 323*387726c4SAndroid Build Coastguard Worker ('/tmp/random/', {'/tmp/random/blarg.java': 'real/path/to/file.java' } 324*387726c4SAndroid Build Coastguard Worker """ 325*387726c4SAndroid Build Coastguard Worker tmp_dir_name = tempfile.mkdtemp() 326*387726c4SAndroid Build Coastguard Worker tmp_file_names = {} 327*387726c4SAndroid Build Coastguard Worker for file_name in file_names: 328*387726c4SAndroid Build Coastguard Worker rel_path = os.path.relpath(file_name) 329*387726c4SAndroid Build Coastguard Worker content = subprocess.check_output( 330*387726c4SAndroid Build Coastguard Worker ['git', 'show', commit + ':' + rel_path]) 331*387726c4SAndroid Build Coastguard Worker 332*387726c4SAndroid Build Coastguard Worker tmp_file_name = os.path.join(tmp_dir_name, rel_path) 333*387726c4SAndroid Build Coastguard Worker # create directory for the file if it doesn't exist 334*387726c4SAndroid Build Coastguard Worker if not os.path.exists(os.path.dirname(tmp_file_name)): 335*387726c4SAndroid Build Coastguard Worker os.makedirs(os.path.dirname(tmp_file_name)) 336*387726c4SAndroid Build Coastguard Worker 337*387726c4SAndroid Build Coastguard Worker tmp_file = open(tmp_file_name, 'wb') 338*387726c4SAndroid Build Coastguard Worker tmp_file.write(content) 339*387726c4SAndroid Build Coastguard Worker tmp_file.close() 340*387726c4SAndroid Build Coastguard Worker tmp_file_names[tmp_file_name] = file_name 341*387726c4SAndroid Build Coastguard Worker return tmp_dir_name, tmp_file_names 342*387726c4SAndroid Build Coastguard Worker 343*387726c4SAndroid Build Coastguard Worker 344*387726c4SAndroid Build Coastguard Workerdef main(args=None): 345*387726c4SAndroid Build Coastguard Worker """Runs Checkstyle checks on a given set of java files or a commit. 346*387726c4SAndroid Build Coastguard Worker 347*387726c4SAndroid Build Coastguard Worker It will run Checkstyle on the list of java files first, if unspecified, 348*387726c4SAndroid Build Coastguard Worker then the check will be run on a specified commit SHA-1 and if that 349*387726c4SAndroid Build Coastguard Worker is None it will fallback to check the latest commit of the currently checked 350*387726c4SAndroid Build Coastguard Worker out branch. 351*387726c4SAndroid Build Coastguard Worker """ 352*387726c4SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 353*387726c4SAndroid Build Coastguard Worker parser.add_argument('--file', '-f', nargs='+') 354*387726c4SAndroid Build Coastguard Worker parser.add_argument('--sha', '-s') 355*387726c4SAndroid Build Coastguard Worker parser.add_argument('--config_xml', '-c') 356*387726c4SAndroid Build Coastguard Worker parser.add_argument('--file_whitelist', '-fw', nargs='+') 357*387726c4SAndroid Build Coastguard Worker parser.add_argument('--add_classpath', '-p') 358*387726c4SAndroid Build Coastguard Worker args = parser.parse_args() 359*387726c4SAndroid Build Coastguard Worker 360*387726c4SAndroid Build Coastguard Worker config_xml = args.config_xml or CHECKSTYLE_STYLE 361*387726c4SAndroid Build Coastguard Worker 362*387726c4SAndroid Build Coastguard Worker if not os.path.exists(config_xml): 363*387726c4SAndroid Build Coastguard Worker print('Java checkstyle configuration file is missing') 364*387726c4SAndroid Build Coastguard Worker sys.exit(1) 365*387726c4SAndroid Build Coastguard Worker 366*387726c4SAndroid Build Coastguard Worker classpath = CHECKSTYLE_JAR 367*387726c4SAndroid Build Coastguard Worker 368*387726c4SAndroid Build Coastguard Worker if args.add_classpath: 369*387726c4SAndroid Build Coastguard Worker classpath = args.add_classpath + ':' + classpath 370*387726c4SAndroid Build Coastguard Worker 371*387726c4SAndroid Build Coastguard Worker if args.file: 372*387726c4SAndroid Build Coastguard Worker # Files to check were specified via command line. 373*387726c4SAndroid Build Coastguard Worker (errors, warnings) = RunCheckstyleOnFiles(args.file, classpath, config_xml) 374*387726c4SAndroid Build Coastguard Worker else: 375*387726c4SAndroid Build Coastguard Worker (errors, warnings) = RunCheckstyleOnACommit(args.sha, classpath, config_xml, 376*387726c4SAndroid Build Coastguard Worker args.file_whitelist) 377*387726c4SAndroid Build Coastguard Worker 378*387726c4SAndroid Build Coastguard Worker if errors or warnings: 379*387726c4SAndroid Build Coastguard Worker sys.exit(1) 380*387726c4SAndroid Build Coastguard Worker 381*387726c4SAndroid Build Coastguard Worker print('SUCCESS! NO ISSUES FOUND') 382*387726c4SAndroid Build Coastguard Worker sys.exit(0) 383*387726c4SAndroid Build Coastguard Worker 384*387726c4SAndroid Build Coastguard Worker 385*387726c4SAndroid Build Coastguard Workerif __name__ == '__main__': 386*387726c4SAndroid Build Coastguard Worker main() 387