1#!/usr/bin/env python 2# 3# Copyright 2008 The Closure Linter Authors. All Rights Reserved. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS-IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Determines the list of files to be checked from command line arguments.""" 18 19__author__ = ('robbyw@google.com (Robert Walker)', 20 'ajp@google.com (Andy Perelson)') 21 22import glob 23import os 24import re 25 26import gflags as flags 27 28 29FLAGS = flags.FLAGS 30 31flags.DEFINE_multistring( 32 'recurse', 33 None, 34 'Recurse in to the subdirectories of the given path', 35 short_name='r') 36flags.DEFINE_list( 37 'exclude_directories', 38 ('_demos'), 39 'Exclude the specified directories (only applicable along with -r or ' 40 '--presubmit)', 41 short_name='e') 42flags.DEFINE_list( 43 'exclude_files', 44 ('deps.js'), 45 'Exclude the specified files', 46 short_name='x') 47 48 49def MatchesSuffixes(filename, suffixes): 50 """Returns whether the given filename matches one of the given suffixes. 51 52 Args: 53 filename: Filename to check. 54 suffixes: Sequence of suffixes to check. 55 56 Returns: 57 Whether the given filename matches one of the given suffixes. 58 """ 59 suffix = filename[filename.rfind('.'):] 60 return suffix in suffixes 61 62 63def _GetUserSpecifiedFiles(argv, suffixes): 64 """Returns files to be linted, specified directly on the command line. 65 66 Can handle the '*' wildcard in filenames, but no other wildcards. 67 68 Args: 69 argv: Sequence of command line arguments. The second and following arguments 70 are assumed to be files that should be linted. 71 suffixes: Expected suffixes for the file type being checked. 72 73 Returns: 74 A sequence of files to be linted. 75 """ 76 files = argv[1:] or [] 77 all_files = [] 78 lint_files = [] 79 80 # Perform any necessary globs. 81 for f in files: 82 if f.find('*') != -1: 83 for result in glob.glob(f): 84 all_files.append(result) 85 else: 86 all_files.append(f) 87 88 for f in all_files: 89 if MatchesSuffixes(f, suffixes): 90 lint_files.append(f) 91 return lint_files 92 93 94def _GetRecursiveFiles(suffixes): 95 """Returns files to be checked specified by the --recurse flag. 96 97 Args: 98 suffixes: Expected suffixes for the file type being checked. 99 100 Returns: 101 A list of files to be checked. 102 """ 103 lint_files = [] 104 # Perform any request recursion 105 if FLAGS.recurse: 106 for start in FLAGS.recurse: 107 for root, subdirs, files in os.walk(start): 108 for f in files: 109 if MatchesSuffixes(f, suffixes): 110 lint_files.append(os.path.join(root, f)) 111 return lint_files 112 113 114def GetAllSpecifiedFiles(argv, suffixes): 115 """Returns all files specified by the user on the commandline. 116 117 Args: 118 argv: Sequence of command line arguments. The second and following arguments 119 are assumed to be files that should be linted. 120 suffixes: Expected suffixes for the file type 121 122 Returns: 123 A list of all files specified directly or indirectly (via flags) on the 124 command line by the user. 125 """ 126 files = _GetUserSpecifiedFiles(argv, suffixes) 127 128 if FLAGS.recurse: 129 files += _GetRecursiveFiles(suffixes) 130 131 return FilterFiles(files) 132 133 134def FilterFiles(files): 135 """Filters the list of files to be linted be removing any excluded files. 136 137 Filters out files excluded using --exclude_files and --exclude_directories. 138 139 Args: 140 files: Sequence of files that needs filtering. 141 142 Returns: 143 Filtered list of files to be linted. 144 """ 145 num_files = len(files) 146 147 ignore_dirs_regexs = [] 148 for ignore in FLAGS.exclude_directories: 149 ignore_dirs_regexs.append(re.compile(r'(^|[\\/])%s[\\/]' % ignore)) 150 151 result_files = [] 152 for f in files: 153 add_file = True 154 for exclude in FLAGS.exclude_files: 155 if f.endswith('/' + exclude) or f == exclude: 156 add_file = False 157 break 158 for ignore in ignore_dirs_regexs: 159 if ignore.search(f): 160 # Break out of ignore loop so we don't add to 161 # filtered files. 162 add_file = False 163 break 164 if add_file: 165 # Convert everything to absolute paths so we can easily remove duplicates 166 # using a set. 167 result_files.append(os.path.abspath(f)) 168 169 skipped = num_files - len(result_files) 170 if skipped: 171 print 'Skipping %d file(s).' % skipped 172 173 return set(result_files) 174 175 176def GetFileList(argv, file_type, suffixes): 177 """Parse the flags and return the list of files to check. 178 179 Args: 180 argv: Sequence of command line arguments. 181 suffixes: Sequence of acceptable suffixes for the file type. 182 183 Returns: 184 The list of files to check. 185 """ 186 return sorted(GetAllSpecifiedFiles(argv, suffixes)) 187 188 189def IsEmptyArgumentList(argv): 190 return not (len(argv[1:]) or FLAGS.recurse) 191