| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Traverses the source tree, parses all found DEPS files, and constructs | 6 """Traverses the source tree, parses all found DEPS files, and constructs |
| 7 a dependency rule table to be used by subclasses. | 7 a dependency rule table to be used by subclasses. |
| 8 | 8 |
| 9 The format of the deps file: | 9 The format of the deps file: |
| 10 | 10 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 so you can modify or remove it using the normal include rules. | 68 so you can modify or remove it using the normal include rules. |
| 69 | 69 |
| 70 The rules are processed in order. This means you can explicitly allow a higher | 70 The rules are processed in order. This means you can explicitly allow a higher |
| 71 directory and then take away permissions from sub-parts, or the reverse. | 71 directory and then take away permissions from sub-parts, or the reverse. |
| 72 | 72 |
| 73 Note that all directory separators must be slashes (Unix-style) and not | 73 Note that all directory separators must be slashes (Unix-style) and not |
| 74 backslashes. All directories should be relative to the source root and use | 74 backslashes. All directories should be relative to the source root and use |
| 75 only lowercase. | 75 only lowercase. |
| 76 """ | 76 """ |
| 77 | 77 |
| 78 import copy |
| 78 import os | 79 import os |
| 80 import posixpath |
| 79 import subprocess | 81 import subprocess |
| 80 import copy | |
| 81 | 82 |
| 82 from rules import Rule, Rules | 83 from rules import Rule, Rules |
| 83 | 84 |
| 84 | 85 |
| 85 # Variable name used in the DEPS file to add or subtract include files from | 86 # Variable name used in the DEPS file to add or subtract include files from |
| 86 # the module-level deps. | 87 # the module-level deps. |
| 87 INCLUDE_RULES_VAR_NAME = 'include_rules' | 88 INCLUDE_RULES_VAR_NAME = 'include_rules' |
| 88 | 89 |
| 89 # Variable name used in the DEPS file to add or subtract include files | 90 # Variable name used in the DEPS file to add or subtract include files |
| 90 # from module-level deps specific to files whose basename (last | 91 # from module-level deps specific to files whose basename (last |
| 91 # component of path) matches a given regular expression. | 92 # component of path) matches a given regular expression. |
| 92 SPECIFIC_INCLUDE_RULES_VAR_NAME = 'specific_include_rules' | 93 SPECIFIC_INCLUDE_RULES_VAR_NAME = 'specific_include_rules' |
| 93 | 94 |
| 94 # Optionally present in the DEPS file to list subdirectories which should not | 95 # Optionally present in the DEPS file to list subdirectories which should not |
| 95 # be checked. This allows us to skip third party code, for example. | 96 # be checked. This allows us to skip third party code, for example. |
| 96 SKIP_SUBDIRS_VAR_NAME = 'skip_child_includes' | 97 SKIP_SUBDIRS_VAR_NAME = 'skip_child_includes' |
| 97 | 98 |
| 98 | 99 |
| 99 def NormalizePath(path): | 100 def NormalizePath(path): |
| 100 """Returns a path normalized to how we write DEPS rules and compare paths. | 101 """Returns a path normalized to how we write DEPS rules and compare paths.""" |
| 101 """ | 102 return os.path.normcase(path).replace(os.path.sep, posixpath.sep) |
| 102 return path.lower().replace('\\', '/') | |
| 103 | 103 |
| 104 | 104 |
| 105 class DepsBuilder(object): | 105 class DepsBuilder(object): |
| 106 """Parses include_rules from DEPS files. | 106 """Parses include_rules from DEPS files.""" |
| 107 """ | |
| 108 | 107 |
| 109 def __init__(self, | 108 def __init__(self, |
| 110 base_directory=None, | 109 base_directory=None, |
| 111 verbose=False, | 110 verbose=False, |
| 112 being_tested=False, | 111 being_tested=False, |
| 113 ignore_temp_rules=False, | 112 ignore_temp_rules=False, |
| 114 ignore_specific_rules=False): | 113 ignore_specific_rules=False): |
| 115 """Creates a new DepsBuilder. | 114 """Creates a new DepsBuilder. |
| 116 | 115 |
| 117 Args: | 116 Args: |
| 118 base_directory: OS-compatible path to root of checkout, e.g. C:\chr\src. | 117 base_directory: local path to root of checkout, e.g. C:\chr\src. |
| 119 verbose: Set to true for debug output. | 118 verbose: Set to True for debug output. |
| 120 being_tested: Set to true to ignore the DEPS file at tools/checkdeps/DEPS. | 119 being_tested: Set to True to ignore the DEPS file at tools/checkdeps/DEPS. |
| 121 ignore_temp_rules: Ignore rules that start with Rule.TEMP_ALLOW ("!"). | 120 ignore_temp_rules: Ignore rules that start with Rule.TEMP_ALLOW ("!"). |
| 122 """ | 121 """ |
| 123 base_directory = (base_directory or | 122 base_directory = (base_directory or |
| 124 os.path.join(os.path.dirname(__file__), '..', '..')) | 123 os.path.join(os.path.dirname(__file__), |
| 125 self.base_directory = os.path.abspath(base_directory) | 124 os.pardir, os.pardir)) |
| 125 self.base_directory = os.path.abspath(base_directory) # Local absolute path |
| 126 self.verbose = verbose | 126 self.verbose = verbose |
| 127 self._under_test = being_tested | 127 self._under_test = being_tested |
| 128 self._ignore_temp_rules = ignore_temp_rules | 128 self._ignore_temp_rules = ignore_temp_rules |
| 129 self._ignore_specific_rules = ignore_specific_rules | 129 self._ignore_specific_rules = ignore_specific_rules |
| 130 | 130 |
| 131 self.git_source_directories = set() | 131 self.git_source_directories = set() # Normalized paths |
| 132 self._AddGitSourceDirectories() | 132 self._AddGitSourceDirectories() |
| 133 | 133 |
| 134 # Map of normalized directory paths to rules to use for those | 134 # Map of normalized directory paths to rules to use for those |
| 135 # directories, or None for directories that should be skipped. | 135 # directories, or None for directories that should be skipped. |
| 136 # Normalized is: absolute, lowercase, / for separator. |
| 136 self.directory_rules = {} | 137 self.directory_rules = {} |
| 137 self._ApplyDirectoryRulesAndSkipSubdirs(Rules(), self.base_directory) | 138 self._ApplyDirectoryRulesAndSkipSubdirs(Rules(), self.base_directory) |
| 138 | 139 |
| 139 def _ApplyRules(self, existing_rules, includes, specific_includes, cur_dir): | 140 def _ApplyRules(self, existing_rules, includes, specific_includes, |
| 141 cur_dir_norm): |
| 140 """Applies the given include rules, returning the new rules. | 142 """Applies the given include rules, returning the new rules. |
| 141 | 143 |
| 142 Args: | 144 Args: |
| 143 existing_rules: A set of existing rules that will be combined. | 145 existing_rules: A set of existing rules that will be combined. |
| 144 include: The list of rules from the "include_rules" section of DEPS. | 146 include: The list of rules from the "include_rules" section of DEPS. |
| 145 specific_includes: E.g. {'.*_unittest\.cc': ['+foo', '-blat']} rules | 147 specific_includes: E.g. {'.*_unittest\.cc': ['+foo', '-blat']} rules |
| 146 from the "specific_include_rules" section of DEPS. | 148 from the "specific_include_rules" section of DEPS. |
| 147 cur_dir: The current directory, normalized path. We will create an | 149 cur_dir_norm: The current directory, normalized path. We will create an |
| 148 implicit rule that allows inclusion from this directory. | 150 implicit rule that allows inclusion from this directory. |
| 149 | 151 |
| 150 Returns: A new set of rules combining the existing_rules with the other | 152 Returns: A new set of rules combining the existing_rules with the other |
| 151 arguments. | 153 arguments. |
| 152 """ | 154 """ |
| 153 rules = copy.deepcopy(existing_rules) | 155 rules = copy.deepcopy(existing_rules) |
| 154 | 156 |
| 155 # First apply the implicit "allow" rule for the current directory. | 157 # First apply the implicit "allow" rule for the current directory. |
| 156 if cur_dir.startswith( | 158 base_dir_norm = NormalizePath(self.base_directory) |
| 157 NormalizePath(os.path.normpath(self.base_directory))): | 159 if not cur_dir_norm.startswith(base_dir_norm): |
| 158 relative_dir = cur_dir[len(self.base_directory) + 1:] | 160 raise Exception( |
| 161 'Internal error: base directory is not at the beginning for\n' |
| 162 ' %s and base dir\n' |
| 163 ' %s' % (cur_dir_norm, base_dir_norm)) |
| 164 relative_dir = posixpath.relpath(cur_dir_norm, base_dir_norm) |
| 159 | 165 |
| 160 source = relative_dir | 166 # Make the help string a little more meaningful. |
| 161 if len(source) == 0: | 167 source = relative_dir or 'top level' |
| 162 source = 'top level' # Make the help string a little more meaningful. | 168 rules.AddRule('+' + relative_dir, |
| 163 rules.AddRule('+' + relative_dir, | 169 relative_dir, |
| 164 relative_dir, | 170 'Default rule for ' + source) |
| 165 'Default rule for ' + source) | |
| 166 else: | |
| 167 raise Exception('Internal error: base directory is not at the beginning' + | |
| 168 ' for\n %s and base dir\n %s' % | |
| 169 (cur_dir, self.base_directory)) | |
| 170 | 171 |
| 171 def ApplyOneRule(rule_str, cur_dir, dependee_regexp=None): | 172 def ApplyOneRule(rule_str, dependee_regexp=None): |
| 172 """Deduces a sensible description for the rule being added, and | 173 """Deduces a sensible description for the rule being added, and |
| 173 adds the rule with its description to |rules|. | 174 adds the rule with its description to |rules|. |
| 174 | 175 |
| 175 If we are ignoring temporary rules, this function does nothing | 176 If we are ignoring temporary rules, this function does nothing |
| 176 for rules beginning with the Rule.TEMP_ALLOW character. | 177 for rules beginning with the Rule.TEMP_ALLOW character. |
| 177 """ | 178 """ |
| 178 if self._ignore_temp_rules and rule_str.startswith(Rule.TEMP_ALLOW): | 179 if self._ignore_temp_rules and rule_str.startswith(Rule.TEMP_ALLOW): |
| 179 return | 180 return |
| 180 | 181 |
| 181 rule_block_name = 'include_rules' | 182 rule_block_name = 'include_rules' |
| 182 if dependee_regexp: | 183 if dependee_regexp: |
| 183 rule_block_name = 'specific_include_rules' | 184 rule_block_name = 'specific_include_rules' |
| 184 if not relative_dir: | 185 if relative_dir: |
| 186 rule_description = relative_dir + "'s %s" % rule_block_name |
| 187 else: |
| 185 rule_description = 'the top level %s' % rule_block_name | 188 rule_description = 'the top level %s' % rule_block_name |
| 186 else: | |
| 187 rule_description = relative_dir + "'s %s" % rule_block_name | |
| 188 rules.AddRule(rule_str, relative_dir, rule_description, dependee_regexp) | 189 rules.AddRule(rule_str, relative_dir, rule_description, dependee_regexp) |
| 189 | 190 |
| 190 # Apply the additional explicit rules. | 191 # Apply the additional explicit rules. |
| 191 for (_, rule_str) in enumerate(includes): | 192 for rule_str in includes: |
| 192 ApplyOneRule(rule_str, cur_dir) | 193 ApplyOneRule(rule_str) |
| 193 | 194 |
| 194 # Finally, apply the specific rules. | 195 # Finally, apply the specific rules. |
| 195 if not self._ignore_specific_rules: | 196 if self._ignore_specific_rules: |
| 196 for regexp, specific_rules in specific_includes.iteritems(): | 197 return rules |
| 197 for rule_str in specific_rules: | 198 |
| 198 ApplyOneRule(rule_str, cur_dir, regexp) | 199 for regexp, specific_rules in specific_includes.iteritems(): |
| 200 for rule_str in specific_rules: |
| 201 ApplyOneRule(rule_str, regexp) |
| 199 | 202 |
| 200 return rules | 203 return rules |
| 201 | 204 |
| 202 def _ApplyDirectoryRules(self, existing_rules, dir_name): | 205 def _ApplyDirectoryRules(self, existing_rules, dir_path_local_abs): |
| 203 """Combines rules from the existing rules and the new directory. | 206 """Combines rules from the existing rules and the new directory. |
| 204 | 207 |
| 205 Any directory can contain a DEPS file. Toplevel DEPS files can contain | 208 Any directory can contain a DEPS file. Toplevel DEPS files can contain |
| 206 module dependencies which are used by gclient. We use these, along with | 209 module dependencies which are used by gclient. We use these, along with |
| 207 additional include rules and implicit rules for the given directory, to | 210 additional include rules and implicit rules for the given directory, to |
| 208 come up with a combined set of rules to apply for the directory. | 211 come up with a combined set of rules to apply for the directory. |
| 209 | 212 |
| 210 Args: | 213 Args: |
| 211 existing_rules: The rules for the parent directory. We'll add-on to these. | 214 existing_rules: The rules for the parent directory. We'll add-on to these. |
| 212 dir_name: The directory name that the deps file may live in (if | 215 dir_path_local_abs: The directory path that the DEPS file may live in (if |
| 213 it exists). This will also be used to generate the | 216 it exists). This will also be used to generate the |
| 214 implicit rules. This is a non-normalized path. | 217 implicit rules. This is a local, non-normalized path. |
| 215 | 218 |
| 216 Returns: A tuple containing: (1) the combined set of rules to apply to the | 219 Returns: A tuple containing: (1) the combined set of rules to apply to the |
| 217 sub-tree, and (2) a list of all subdirectories that should NOT be | 220 sub-tree, and (2) a list of all subdirectories that should NOT be |
| 218 checked, as specified in the DEPS file (if any). | 221 checked, as specified in the DEPS file (if any). Subdirectories |
| 222 are single words, hence no OS-dependence. |
| 219 """ | 223 """ |
| 220 norm_dir_name = NormalizePath(dir_name) | 224 dir_path_norm = NormalizePath(dir_path_local_abs) |
| 221 | 225 |
| 222 # Check for a .svn directory in this directory or check this directory is | 226 # Check for a .svn directory in this directory or check this directory is |
| 223 # contained in git source direcotries. This will tell us if it's a source | 227 # contained in git source direcotries. This will tell us if it's a source |
| 224 # directory and should be checked. | 228 # directory and should be checked. |
| 225 if not (os.path.exists(os.path.join(dir_name, ".svn")) or | 229 if not (os.path.exists(os.path.join(dir_path_local_abs, '.svn')) or |
| 226 (norm_dir_name in self.git_source_directories)): | 230 dir_path_norm in self.git_source_directories): |
| 227 return (None, []) | 231 return None, [] |
| 228 | 232 |
| 229 # Check the DEPS file in this directory. | 233 # Check the DEPS file in this directory. |
| 230 if self.verbose: | 234 if self.verbose: |
| 231 print 'Applying rules from', dir_name | 235 print 'Applying rules from', dir_path_local_abs |
| 232 def FromImpl(_unused, _unused2): | 236 def FromImpl(*_): |
| 233 pass # NOP function so "From" doesn't fail. | 237 pass # NOP function so "From" doesn't fail. |
| 234 | 238 |
| 235 def FileImpl(_unused): | 239 def FileImpl(_): |
| 236 pass # NOP function so "File" doesn't fail. | 240 pass # NOP function so "File" doesn't fail. |
| 237 | 241 |
| 238 class _VarImpl: | 242 class _VarImpl: |
| 239 def __init__(self, local_scope): | 243 def __init__(self, local_scope): |
| 240 self._local_scope = local_scope | 244 self._local_scope = local_scope |
| 241 | 245 |
| 242 def Lookup(self, var_name): | 246 def Lookup(self, var_name): |
| 243 """Implements the Var syntax.""" | 247 """Implements the Var syntax.""" |
| 244 if var_name in self._local_scope.get('vars', {}): | 248 try: |
| 245 return self._local_scope['vars'][var_name] | 249 return self._local_scope['vars'][var_name] |
| 246 raise Exception('Var is not defined: %s' % var_name) | 250 except KeyError: |
| 251 raise Exception('Var is not defined: %s' % var_name) |
| 247 | 252 |
| 248 local_scope = {} | 253 local_scope = {} |
| 249 global_scope = { | 254 global_scope = { |
| 250 'File': FileImpl, | 255 'File': FileImpl, |
| 251 'From': FromImpl, | 256 'From': FromImpl, |
| 252 'Var': _VarImpl(local_scope).Lookup, | 257 'Var': _VarImpl(local_scope).Lookup, |
| 253 } | 258 } |
| 254 deps_file = os.path.join(dir_name, 'DEPS') | 259 deps_file_path = os.path.join(dir_path_local_abs, 'DEPS') |
| 255 | 260 |
| 256 # The second conditional here is to disregard the | 261 # The second conditional here is to disregard the |
| 257 # tools/checkdeps/DEPS file while running tests. This DEPS file | 262 # tools/checkdeps/DEPS file while running tests. This DEPS file |
| 258 # has a skip_child_includes for 'testdata' which is necessary for | 263 # has a skip_child_includes for 'testdata' which is necessary for |
| 259 # running production tests, since there are intentional DEPS | 264 # running production tests, since there are intentional DEPS |
| 260 # violations under the testdata directory. On the other hand when | 265 # violations under the testdata directory. On the other hand when |
| 261 # running tests, we absolutely need to verify the contents of that | 266 # running tests, we absolutely need to verify the contents of that |
| 262 # directory to trigger those intended violations and see that they | 267 # directory to trigger those intended violations and see that they |
| 263 # are handled correctly. | 268 # are handled correctly. |
| 264 if os.path.isfile(deps_file) and ( | 269 if os.path.isfile(deps_file_path) and not ( |
| 265 not self._under_test or not os.path.split(dir_name)[1] == 'checkdeps'): | 270 self._under_test and |
| 266 execfile(deps_file, global_scope, local_scope) | 271 os.path.basename(dir_path_local_abs) == 'checkdeps'): |
| 272 execfile(deps_file_path, global_scope, local_scope) |
| 267 elif self.verbose: | 273 elif self.verbose: |
| 268 print ' No deps file found in', dir_name | 274 print ' No deps file found in', dir_path_local_abs |
| 269 | 275 |
| 270 # Even if a DEPS file does not exist we still invoke ApplyRules | 276 # Even if a DEPS file does not exist we still invoke ApplyRules |
| 271 # to apply the implicit "allow" rule for the current directory | 277 # to apply the implicit "allow" rule for the current directory |
| 272 include_rules = local_scope.get(INCLUDE_RULES_VAR_NAME, []) | 278 include_rules = local_scope.get(INCLUDE_RULES_VAR_NAME, []) |
| 273 specific_include_rules = local_scope.get(SPECIFIC_INCLUDE_RULES_VAR_NAME, | 279 specific_include_rules = local_scope.get(SPECIFIC_INCLUDE_RULES_VAR_NAME, |
| 274 {}) | 280 {}) |
| 275 skip_subdirs = local_scope.get(SKIP_SUBDIRS_VAR_NAME, []) | 281 skip_subdirs = local_scope.get(SKIP_SUBDIRS_VAR_NAME, []) |
| 276 | 282 |
| 277 return (self._ApplyRules(existing_rules, include_rules, | 283 return (self._ApplyRules(existing_rules, include_rules, |
| 278 specific_include_rules, norm_dir_name), | 284 specific_include_rules, dir_path_norm), |
| 279 skip_subdirs) | 285 skip_subdirs) |
| 280 | 286 |
| 281 def _ApplyDirectoryRulesAndSkipSubdirs(self, parent_rules, dir_path): | 287 def _ApplyDirectoryRulesAndSkipSubdirs(self, parent_rules, |
| 282 """Given |parent_rules| and a subdirectory |dir_path| from the | 288 dir_path_local_abs): |
| 283 directory that owns the |parent_rules|, add |dir_path|'s rules to | 289 """Given |parent_rules| and a subdirectory |dir_path_local_abs| of the |
| 290 directory that owns the |parent_rules|, add |dir_path_local_abs|'s rules to |
| 284 |self.directory_rules|, and add None entries for any of its | 291 |self.directory_rules|, and add None entries for any of its |
| 285 subdirectories that should be skipped. | 292 subdirectories that should be skipped. |
| 286 """ | 293 """ |
| 287 directory_rules, excluded_subdirs = self._ApplyDirectoryRules(parent_rules, | 294 directory_rules, excluded_subdirs = self._ApplyDirectoryRules( |
| 288 dir_path) | 295 parent_rules, dir_path_local_abs) |
| 289 self.directory_rules[NormalizePath(dir_path)] = directory_rules | 296 dir_path_norm = NormalizePath(dir_path_local_abs) |
| 297 self.directory_rules[dir_path_norm] = directory_rules |
| 290 for subdir in excluded_subdirs: | 298 for subdir in excluded_subdirs: |
| 291 self.directory_rules[NormalizePath( | 299 subdir_path_norm = posixpath.join(dir_path_norm, subdir) |
| 292 os.path.normpath(os.path.join(dir_path, subdir)))] = None | 300 self.directory_rules[subdir_path_norm] = None |
| 293 | 301 |
| 294 def GetDirectoryRules(self, dir_path): | 302 def GetDirectoryRules(self, dir_path_local): |
| 295 """Returns a Rules object to use for the given directory, or None | 303 """Returns a Rules object to use for the given directory, or None |
| 296 if the given directory should be skipped. This takes care of | 304 if the given directory should be skipped. |
| 297 first building rules for parent directories (up to | 305 |
| 298 self.base_directory) if needed. | 306 Also modifies |self.directory_rules| to store the Rules. |
| 307 This takes care of first building rules for parent directories (up to |
| 308 |self.base_directory|) if needed, which may add rules for skipped |
| 309 subdirectories. |
| 299 | 310 |
| 300 Args: | 311 Args: |
| 301 dir_path: A real (non-normalized) path to the directory you want | 312 dir_path_local: A local path to the directory you want rules for. |
| 302 rules for. | 313 Can be relative and unnormalized. |
| 303 """ | 314 """ |
| 304 norm_dir_path = NormalizePath(dir_path) | 315 if os.path.isabs(dir_path_local): |
| 316 dir_path_local_abs = dir_path_local |
| 317 else: |
| 318 dir_path_local_abs = os.path.join(self.base_directory, dir_path_local) |
| 319 dir_path_norm = NormalizePath(dir_path_local_abs) |
| 305 | 320 |
| 306 if not norm_dir_path.startswith( | 321 if dir_path_norm in self.directory_rules: |
| 307 NormalizePath(os.path.normpath(self.base_directory))): | 322 return self.directory_rules[dir_path_norm] |
| 308 dir_path = os.path.join(self.base_directory, dir_path) | |
| 309 norm_dir_path = NormalizePath(dir_path) | |
| 310 | 323 |
| 311 parent_dir = os.path.dirname(dir_path) | 324 parent_dir_local_abs = os.path.dirname(dir_path_local_abs) |
| 312 parent_rules = None | 325 parent_rules = self.GetDirectoryRules(parent_dir_local_abs) |
| 313 if not norm_dir_path in self.directory_rules: | 326 # We need to check for an entry for our dir_path again, since |
| 314 parent_rules = self.GetDirectoryRules(parent_dir) | 327 # GetDirectoryRules can modify entries for subdirectories, namely setting |
| 328 # to None if they should be skipped, via _ApplyDirectoryRulesAndSkipSubdirs. |
| 329 # For example, if dir_path == 'A/B/C' and A/B/DEPS specifies that the C |
| 330 # subdirectory be skipped, GetDirectoryRules('A/B') will fill in the entry |
| 331 # for 'A/B/C' as None. |
| 332 if dir_path_norm in self.directory_rules: |
| 333 return self.directory_rules[dir_path_norm] |
| 315 | 334 |
| 316 # We need to check for an entry for our dir_path again, in case we | 335 if parent_rules: |
| 317 # are at a path e.g. A/B/C where A/B/DEPS specifies the C | 336 self._ApplyDirectoryRulesAndSkipSubdirs(parent_rules, dir_path_local_abs) |
| 318 # subdirectory to be skipped; in this case, the invocation to | 337 else: |
| 319 # GetDirectoryRules(parent_dir) has already filled in an entry for | 338 # If the parent directory should be skipped, then the current |
| 320 # A/B/C. | 339 # directory should also be skipped. |
| 321 if not norm_dir_path in self.directory_rules: | 340 self.directory_rules[dir_path_norm] = None |
| 322 if not parent_rules: | 341 return self.directory_rules[dir_path_norm] |
| 323 # If the parent directory should be skipped, then the current | |
| 324 # directory should also be skipped. | |
| 325 self.directory_rules[norm_dir_path] = None | |
| 326 else: | |
| 327 self._ApplyDirectoryRulesAndSkipSubdirs(parent_rules, dir_path) | |
| 328 return self.directory_rules[norm_dir_path] | |
| 329 | 342 |
| 330 def _AddGitSourceDirectories(self): | 343 def _AddGitSourceDirectories(self): |
| 331 """Adds any directories containing sources managed by git to | 344 """Adds any directories containing sources managed by git to |
| 332 self.git_source_directories. | 345 self.git_source_directories. |
| 333 """ | 346 """ |
| 334 if not os.path.exists(os.path.join(self.base_directory, '.git')): | 347 if not os.path.exists(os.path.join(self.base_directory, '.git')): |
| 335 return | 348 return |
| 336 | 349 |
| 337 popen_out = os.popen('cd %s && git ls-files --full-name .' % | 350 popen_out = os.popen('cd %s && git ls-files --full-name .' % |
| 338 subprocess.list2cmdline([self.base_directory])) | 351 subprocess.list2cmdline([self.base_directory])) |
| 339 for line in popen_out.readlines(): | 352 for line in popen_out.readlines(): |
| 340 dir_name = os.path.join(self.base_directory, os.path.dirname(line)) | 353 dir_path = os.path.join(self.base_directory, os.path.dirname(line)) |
| 341 # Add the directory as well as all the parent directories. Use | 354 # Add the directory as well as all the parent directories. Use |
| 342 # forward slashes and lower case to normalize paths. | 355 # forward slashes and lower case to normalize paths. |
| 343 while dir_name != self.base_directory: | 356 while dir_path != self.base_directory: |
| 344 self.git_source_directories.add(NormalizePath(dir_name)) | 357 self.git_source_directories.add(NormalizePath(dir_path)) |
| 345 dir_name = os.path.dirname(dir_name) | 358 dir_path = os.path.dirname(dir_path) |
| 346 self.git_source_directories.add(NormalizePath(self.base_directory)) | 359 self.git_source_directories.add(NormalizePath(self.base_directory)) |
| OLD | NEW |