OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 """Makes sure files have the right permissions. | 6 """Makes sure files have the right permissions. |
7 | 7 |
8 Some developers have broken SCM configurations that flip the svn:executable | 8 Some developers have broken SCM configurations that flip the executable |
9 permission on for no good reason. Unix developers who run ls --color will then | 9 permission on for no good reason. Unix developers who run ls --color will then |
10 see .cc files in green and get confused. | 10 see .cc files in green and get confused. |
11 | 11 |
12 - For file extensions that must be executable, add it to EXECUTABLE_EXTENSIONS. | 12 - For file extensions that must be executable, add it to EXECUTABLE_EXTENSIONS. |
13 - For file extensions that must not be executable, add it to | 13 - For file extensions that must not be executable, add it to |
14 NOT_EXECUTABLE_EXTENSIONS. | 14 NOT_EXECUTABLE_EXTENSIONS. |
15 - To ignore all the files inside a directory, add it to IGNORED_PATHS. | 15 - To ignore all the files inside a directory, add it to IGNORED_PATHS. |
16 - For file base name with ambiguous state and that should not be checked for | 16 - For file base name with ambiguous state and that should not be checked for |
17 shebang, add it to IGNORED_FILENAMES. | 17 shebang, add it to IGNORED_FILENAMES. |
18 | 18 |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 Ignores the error code or stderr. | 223 Ignores the error code or stderr. |
224 """ | 224 """ |
225 logging.debug('%s; cwd=%s' % (' '.join(cmd), cwd)) | 225 logging.debug('%s; cwd=%s' % (' '.join(cmd), cwd)) |
226 env = os.environ.copy() | 226 env = os.environ.copy() |
227 env['LANGUAGE'] = 'en_US.UTF-8' | 227 env['LANGUAGE'] = 'en_US.UTF-8' |
228 p = subprocess.Popen( | 228 p = subprocess.Popen( |
229 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd, env=env) | 229 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd, env=env) |
230 return p.communicate()[0] | 230 return p.communicate()[0] |
231 | 231 |
232 | 232 |
233 def get_svn_info(dir_path): | |
234 """Returns svn meta-data for a svn checkout.""" | |
235 if not os.path.isdir(dir_path): | |
236 return {} | |
237 out = capture(['svn', 'info', '.', '--non-interactive'], dir_path) | |
238 return dict(l.split(': ', 1) for l in out.splitlines() if l) | |
239 | |
240 | |
241 def get_svn_url(dir_path): | |
242 return get_svn_info(dir_path).get('URL') | |
243 | |
244 | |
245 def get_svn_root(dir_path): | |
246 """Returns the svn checkout root or None.""" | |
247 svn_url = get_svn_url(dir_path) | |
248 if not svn_url: | |
249 return None | |
250 logging.info('svn url: %s' % svn_url) | |
251 while True: | |
252 parent = os.path.dirname(dir_path) | |
253 if parent == dir_path: | |
254 return None | |
255 svn_url = svn_url.rsplit('/', 1)[0] | |
256 if svn_url != get_svn_url(parent): | |
257 return dir_path | |
258 dir_path = parent | |
259 | |
260 | |
261 def get_git_root(dir_path): | 233 def get_git_root(dir_path): |
262 """Returns the git checkout root or None.""" | 234 """Returns the git checkout root or None.""" |
263 root = capture(['git', 'rev-parse', '--show-toplevel'], dir_path).strip() | 235 root = capture(['git', 'rev-parse', '--show-toplevel'], dir_path).strip() |
264 if root: | 236 if root: |
265 return root | 237 return root |
266 | 238 |
267 | 239 |
268 def is_ignored(rel_path): | 240 def is_ignored(rel_path): |
269 """Returns True if rel_path is in our whitelist of files to ignore.""" | 241 """Returns True if rel_path is in our whitelist of files to ignore.""" |
270 rel_path = rel_path.lower() | 242 rel_path = rel_path.lower() |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 return errors | 367 return errors |
396 | 368 |
397 def list_dir(self, start_dir): | 369 def list_dir(self, start_dir): |
398 """Lists all the files and directory inside start_dir.""" | 370 """Lists all the files and directory inside start_dir.""" |
399 return sorted( | 371 return sorted( |
400 x for x in os.listdir(os.path.join(self.root_dir, start_dir)) | 372 x for x in os.listdir(os.path.join(self.root_dir, start_dir)) |
401 if not x.startswith('.') | 373 if not x.startswith('.') |
402 ) | 374 ) |
403 | 375 |
404 | 376 |
405 class ApiSvnQuick(ApiBase): | |
406 """Returns all files in svn-versioned directories, independent of the fact if | |
407 they are versionned. | |
408 | |
409 Uses svn info in each directory to determine which directories should be | |
410 crawled. | |
411 """ | |
412 def __init__(self, *args): | |
413 super(ApiSvnQuick, self).__init__(*args) | |
414 self.url = get_svn_url(self.root_dir) | |
415 | |
416 def check_dir(self, rel_path): | |
417 url = self.url + '/' + rel_path | |
418 if get_svn_url(os.path.join(self.root_dir, rel_path)) != url: | |
419 return [] | |
420 return super(ApiSvnQuick, self).check_dir(rel_path) | |
421 | |
422 | |
423 class ApiAllFilesAtOnceBase(ApiBase): | 377 class ApiAllFilesAtOnceBase(ApiBase): |
424 _files = None | 378 _files = None |
425 | 379 |
426 def list_dir(self, start_dir): | 380 def list_dir(self, start_dir): |
427 """Lists all the files and directory inside start_dir.""" | 381 """Lists all the files and directory inside start_dir.""" |
428 if self._files is None: | 382 if self._files is None: |
429 self._files = sorted(self._get_all_files()) | 383 self._files = sorted(self._get_all_files()) |
430 if not self.bare_output: | 384 if not self.bare_output: |
431 print 'Found %s files' % len(self._files) | 385 print 'Found %s files' % len(self._files) |
432 start_dir = start_dir[len(self.root_dir) + 1:] | 386 start_dir = start_dir[len(self.root_dir) + 1:] |
433 return [ | 387 return [ |
434 x[len(start_dir):] for x in self._files if x.startswith(start_dir) | 388 x[len(start_dir):] for x in self._files if x.startswith(start_dir) |
435 ] | 389 ] |
436 | 390 |
437 def _get_all_files(self): | 391 def _get_all_files(self): |
438 """Lists all the files and directory inside self._root_dir.""" | 392 """Lists all the files and directory inside self._root_dir.""" |
439 raise NotImplementedError() | 393 raise NotImplementedError() |
440 | 394 |
441 | 395 |
442 class ApiSvn(ApiAllFilesAtOnceBase): | |
443 """Returns all the subversion controlled files. | |
444 | |
445 Warning: svn ls is abnormally slow. | |
446 """ | |
447 def _get_all_files(self): | |
448 cmd = ['svn', 'ls', '--non-interactive', '--recursive'] | |
449 return ( | |
450 x for x in capture(cmd, self.root_dir).splitlines() | |
451 if not x.endswith(os.path.sep)) | |
452 | |
453 | |
454 class ApiGit(ApiAllFilesAtOnceBase): | 396 class ApiGit(ApiAllFilesAtOnceBase): |
455 def _get_all_files(self): | 397 def _get_all_files(self): |
456 return capture(['git', 'ls-files'], cwd=self.root_dir).splitlines() | 398 return capture(['git', 'ls-files'], cwd=self.root_dir).splitlines() |
457 | 399 |
458 | 400 |
459 def get_scm(dir_path, bare): | 401 def get_scm(dir_path, bare): |
460 """Returns a properly configured ApiBase instance.""" | 402 """Returns a properly configured ApiBase instance.""" |
461 cwd = os.getcwd() | 403 cwd = os.getcwd() |
462 root = get_svn_root(dir_path or cwd) | |
463 if root: | |
464 if not bare: | |
465 print('Found subversion checkout at %s' % root) | |
466 return ApiSvnQuick(dir_path or root, bare) | |
467 root = get_git_root(dir_path or cwd) | 404 root = get_git_root(dir_path or cwd) |
468 if root: | 405 if root: |
469 if not bare: | 406 if not bare: |
470 print('Found git repository at %s' % root) | 407 print('Found git repository at %s' % root) |
471 return ApiGit(dir_path or root, bare) | 408 return ApiGit(dir_path or root, bare) |
472 | 409 |
473 # Returns a non-scm aware checker. | 410 # Returns a non-scm aware checker. |
474 if not bare: | 411 if not bare: |
475 print('Failed to determine the SCM for %s' % dir_path) | 412 print('Failed to determine the SCM for %s' % dir_path) |
476 return ApiBase(dir_path or cwd, bare) | 413 return ApiBase(dir_path or cwd, bare) |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 print '\nFAILED\n' | 475 print '\nFAILED\n' |
539 print '\n'.join('%s: %s' % (e['full_path'], e['error']) for e in errors) | 476 print '\n'.join('%s: %s' % (e['full_path'], e['error']) for e in errors) |
540 return 1 | 477 return 1 |
541 if not options.bare: | 478 if not options.bare: |
542 print '\nSUCCESS\n' | 479 print '\nSUCCESS\n' |
543 return 0 | 480 return 0 |
544 | 481 |
545 | 482 |
546 if '__main__' == __name__: | 483 if '__main__' == __name__: |
547 sys.exit(main()) | 484 sys.exit(main()) |
OLD | NEW |