Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Unified Diff: tools/checkperms/checkperms.py

Issue 10088002: Remove over 100 lines from checkperms.py. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tools/checkperms/pylintrc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/checkperms/checkperms.py
diff --git a/tools/checkperms/checkperms.py b/tools/checkperms/checkperms.py
index c3959f99ce9289fabcfae1a39588947cf89b9797..38bf05e7217dc2d8be4afffe9dc43a2ea87b551c 100755
--- a/tools/checkperms/checkperms.py
+++ b/tools/checkperms/checkperms.py
@@ -11,79 +11,29 @@ see .cc files in green and get confused.
To ignore a particular file, add it to WHITELIST_FILES.
To ignore a particular extension, add it to WHITELIST_EXTENSIONS.
-To ignore whatever regexps your heart desires, add it WHITELIST_REGEX.
+To ignore a particular path, add it WHITELIST_PATHS.
Note that all directory separators must be slashes (Unix-style) and not
backslashes. All directories should be relative to the source root and all
file paths should be only lowercase.
"""
+import logging
import optparse
import os
-import pipes
-import re
import stat
+import subprocess
import sys
#### USER EDITABLE SECTION STARTS HERE ####
# Files with these extensions are allowed to have executable permissions.
-WHITELIST_EXTENSIONS = [
- 'bash',
- 'bat',
- 'dll',
- 'dylib',
- 'exe',
- 'pl',
- 'py',
- 'rb',
- 'sed',
- 'sh',
-]
-
-# Files that end the following paths are whitelisted too.
-WHITELIST_FILES = [
- '/build/gyp_chromium',
- '/build/linux/dump_app_syms',
- '/build/linux/pkg-config-wrapper',
- '/build/mac/strip_from_xcode',
- '/build/mac/strip_save_dsym',
- '/chrome/installer/mac/pkg-dmg',
- '/chrome/tools/build/linux/chrome-wrapper',
- '/chrome/tools/build/mac/build_app_dmg',
- '/chrome/tools/build/mac/clean_up_old_versions',
- '/chrome/tools/build/mac/dump_product_syms',
- '/chrome/tools/build/mac/generate_localizer',
- '/chrome/tools/build/mac/make_sign_sh',
- '/chrome/tools/build/mac/verify_order',
- '/o3d/build/gyp_o3d',
- '/o3d/gypbuild',
- '/o3d/installer/linux/debian.in/rules',
- '/third_party/icu/source/runconfigureicu',
- '/third_party/gold/gold32',
- '/third_party/gold/gold64',
- '/third_party/gold/ld',
- '/third_party/gold/ld.bfd',
- '/third_party/lcov/bin/gendesc',
- '/third_party/lcov/bin/genhtml',
- '/third_party/lcov/bin/geninfo',
- '/third_party/lcov/bin/genpng',
- '/third_party/lcov/bin/lcov',
- '/third_party/lcov/bin/mcov',
- '/third_party/lcov-1.9/bin/gendesc',
- '/third_party/lcov-1.9/bin/genhtml',
- '/third_party/lcov-1.9/bin/geninfo',
- '/third_party/lcov-1.9/bin/genpng',
- '/third_party/lcov-1.9/bin/lcov',
- '/third_party/libxml/linux/xml2-config',
- '/third_party/lzma_sdk/executable/7za.exe',
- '/third_party/swig/linux/swig',
- '/third_party/tcmalloc/chromium/src/pprof',
- '/tools/deep_memory_profiler/dmprof',
- '/tools/git/post-checkout',
- '/tools/git/post-merge',
- '/tools/ld_bfd/ld',
-]
+WHITELIST_EXTENSIONS = (
+ 'bat',
+ 'dll',
+ 'dylib',
+ 'exe',
+)
# File names that are always whitelisted. (These are all autoconf spew.)
WHITELIST_FILENAMES = set((
@@ -94,251 +44,193 @@ WHITELIST_FILENAMES = set((
'install-sh',
'missing',
'mkinstalldirs',
- 'scons',
'naclsdk',
+ 'scons',
))
# File paths that contain these regexps will be whitelisted as well.
-WHITELIST_REGEX = [
- re.compile('/third_party/openssl/'),
- re.compile('/third_party/sqlite/'),
- re.compile('/third_party/xdg-utils/'),
- re.compile('/third_party/yasm/source/patched-yasm/config'),
- re.compile('/third_party/ffmpeg/tools'),
-]
+WHITELIST_PATHS = (
+ '/third_party/openssl/',
+ '/third_party/sqlite/',
+ '/third_party/xdg-utils/',
+ '/third_party/yasm/source/patched-yasm/config',
+ '/third_party/ffmpeg/tools',
+)
#### USER EDITABLE SECTION ENDS HERE ####
-WHITELIST_EXTENSIONS_REGEX = re.compile(r'\.(%s)' %
- '|'.join(WHITELIST_EXTENSIONS))
-
-WHITELIST_FILES_REGEX = re.compile(r'(%s)$' % '|'.join(WHITELIST_FILES))
-
-# Set to true for more output. This is set by the command line options.
-VERBOSE = False
-
-# Using forward slashes as directory separators, ending in a forward slash.
-# Set by the command line options.
-BASE_DIRECTORY = ''
-
-# The default if BASE_DIRECTORY is not set on the command line.
-DEFAULT_BASE_DIRECTORY = '../../..'
-
-# The directories which contain the sources managed by git.
-GIT_SOURCE_DIRECTORY = set()
-
-# The SVN repository url.
-SVN_REPO_URL = ''
-
-# Whether we are using SVN or GIT.
-IS_SVN = True
-
-# Executable permission mask
-EXECUTABLE_PERMISSION = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
+def is_verbose():
+ return logging.getLogger().isEnabledFor(logging.DEBUG)
-def IsWhiteListed(file_path):
- """Returns True if file_path is in our whitelist of files to ignore."""
- if WHITELIST_EXTENSIONS_REGEX.match(os.path.splitext(file_path)[1]):
- return True
- if WHITELIST_FILES_REGEX.search(file_path):
- return True
- if os.path.basename(file_path) in WHITELIST_FILENAMES:
- return True
- for regex in WHITELIST_REGEX:
- if regex.search(file_path):
- return True
- return False
+def capture(cmd, cwd):
+ """Returns the output of a command.
-def CheckFile(file_path):
- """Checks file_path's permissions.
-
- Args:
- file_path: The file path to check.
-
- Returns:
- Either a string describing the error if there was one, or None if the file
- checked out OK.
+ Ignores the error code or stderr.
"""
- if VERBOSE:
- print 'Checking file: ' + file_path
-
- file_path_lower = file_path.lower()
- if IsWhiteListed(file_path_lower):
- return None
-
- # Not whitelisted, stat the file and check permissions.
- try:
- st_mode = os.stat(file_path).st_mode
- except IOError, e:
- return 'Failed to stat file: %s' % e
- except OSError, e:
- return 'Failed to stat file: %s' % e
-
- if EXECUTABLE_PERMISSION & st_mode:
- # Look if the file starts with #!/
+ env = os.environ.copy()
+ env['LANG'] = 'en_us.UTF-8'
+ p = subprocess.Popen(
+ cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd, env=env)
+ return p.communicate()[0]
+
+
+class ApiBase(object):
+ def __init__(self, root_dir):
+ self.root_dir = root_dir
+
+ @staticmethod
+ def is_whitelisted(file_path):
+ """Returns True if file_path is in our whitelist of files to ignore.
+
+ file_path is a relative directory to the checkout root.
+ """
+ file_path = file_path.lower()
+ return (
+ os.path.splitext(file_path)[1][1:] in WHITELIST_EXTENSIONS or
+ os.path.basename(file_path) in WHITELIST_FILENAMES or
+ file_path.startswith(WHITELIST_PATHS))
+
+ @staticmethod
+ def has_executable_bit(file_path):
+ """Returns if any executable bit is set.
+
+ file_path is the absolute path to the file.
+ """
+ permission = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
+ return bool(permission & os.stat(file_path).st_mode)
+
+ @staticmethod
+ def has_shebang(file_path):
+ """Returns if the file starts with #!/.
+
+ file_path is the absolute path to the file.
+ """
with open(file_path, 'rb') as f:
- if f.read(3) == '#!/':
- # That's fine.
+ return f.read(3) == '#!/'
+
+ def check_file(self, file_path):
+ """Checks file_path's permissions and returns an error if it is
+ inconsistent.
+ """
+ if is_verbose():
+ print 'Checking file: %s' % file_path
+
+ if self.is_whitelisted(file_path):
+ return None
+
+ full_path = os.path.join(self.root_dir, file_path)
+ bit = self.has_executable_bit(full_path)
+ shebang = self.has_shebang(full_path)
+ if bit != shebang:
+ if bit:
+ return '%s: Has executable bit but not shebang' % file_path
+ else:
+ return '%s: Has shebang but not executable bit' % file_path
+
+ def check(self, start_dir):
+ """Check the files in start_dir, recursively check its subdirectories."""
+ errors = []
+ for root, dirs, files in os.walk(start_dir):
+ for f in files:
+ error = check_file(root_dir, os.path.join(root, f))
+ if error:
+ errors.append(error)
+ return errors
+
+
+class ApiSvn(ApiBase):
+ @staticmethod
+ def get_info(dir_path):
+ """Returns svn meta-data for a svn checkout."""
+ if not os.path.isdir(dir_path):
+ return {}
+ out = capture(['svn', 'info', '.'], dir_path)
+ return dict(l.split(': ', 1) for l in out.splitlines() if l)
+
+ @staticmethod
+ def get_root(dir_path):
+ """Returns the svn checkout root or None."""
+ svn_url = get_svn_info(dir_path).get('Repository Root:')
+ if not svn_url:
+ return None
+ while True:
+ parent = os.path.dirname(dir_path)
+ if parent == dir_path:
return None
- # TODO(maruel): Check that non-executable file do not start with a shebang.
- error = 'Contains executable permission'
- if VERBOSE:
- return '%s: %06o' % (error, st_mode)
- return error
- return None
-
-
-def ShouldCheckDirectory(dir_path):
- """Determine if we should check the content of dir_path."""
- if not IS_SVN:
- return dir_path in GIT_SOURCE_DIRECTORY
- repo_url = GetSvnRepositoryRoot(dir_path)
- if not repo_url:
- return False
- return repo_url == SVN_REPO_URL
-
-
-def CheckDirectory(dir_path):
- """Check the files in dir_path; recursively check its subdirectories."""
- # Collect a list of all files and directories to check.
- files_to_check = []
- dirs_to_check = []
- success = True
- contents = os.listdir(dir_path)
- for cur in contents:
- full_path = os.path.join(dir_path, cur)
- if os.path.isdir(full_path) and ShouldCheckDirectory(full_path):
- dirs_to_check.append(full_path)
- elif os.path.isfile(full_path):
- files_to_check.append(full_path)
-
- # First check all files in this directory.
- for cur_file in files_to_check:
- file_status = CheckFile(cur_file)
- if file_status is not None:
- print 'ERROR in %s\n%s' % (cur_file, file_status)
- success = False
-
- # Next recurse into the subdirectories.
- for cur_dir in dirs_to_check:
- if not CheckDirectory(cur_dir):
- success = False
- return success
-
-
-def GetGitSourceDirectory(root):
- """Returns a set of the directories to be checked.
-
- Args:
- root: The repository root where a .git directory must exist.
-
- Returns:
- A set of directories which contain sources managed by git.
- """
- git_source_directory = set()
- popen_out = os.popen('cd %s && git ls-files --full-name .' %
- pipes.quote(root))
- for line in popen_out:
- dir_path = os.path.join(root, os.path.dirname(line))
- git_source_directory.add(dir_path)
- git_source_directory.add(root)
- return git_source_directory
+ if svn_url != get_svn_info(parent).get('Repository Root:'):
+ return dir_path
+ dir_path = parent
+ def check(self, start_dir):
+ """Like ApiBase.check() excepts that it skips non-versioned directories."""
+ return super(ApiSvn, self).check(start_dir)
-def GetSvnRepositoryRoot(dir_path):
- """Returns the repository root for a directory.
- Args:
- dir_path: A directory where a .svn subdirectory should exist.
+class ApiGit(ApiBase):
+ @staticmethod
+ def get_root(dir_path):
+ """Returns the git checkout root or None."""
+ root = capture(['git', 'rev-parse', '--show-toplevel'], dir_path).strip()
+ if root:
+ return root
+
+ def check(self, start_dir):
+ """Like ApiBase.check() excepts that it skips non-versioned directories."""
+ return super(ApiSvn, self).check(start_dir)
- Returns:
- The svn repository that contains dir_path or None.
- """
- svn_dir = os.path.join(dir_path, '.svn')
- if not os.path.isdir(svn_dir):
- return None
- popen_out = os.popen('cd %s && svn info' % pipes.quote(dir_path))
- for line in popen_out:
- if line.startswith('Repository Root: '):
- return line[len('Repository Root: '):].rstrip()
- return None
+def get_scm(dir_path):
+ """Returns a properly configured ApiBase instance."""
+ root = ApiSvn.get_root(dir_path)
+ if root:
+ return ApiSvn(root)
+ root = ApiGit.get_root(dir_path)
+ if root:
+ return ApiGit(root)
-def main(argv):
+ # Returns a non-scm aware checker.
+ logging.warn('Failed to determine the SCM for %s' % dir_path)
+ return ApiBase(root)
+
+
+def main():
usage = """Usage: python %prog [--root <root>] [tocheck]
tocheck Specifies the directory, relative to root, to check. This defaults
to "." so it checks everything.
Examples:
- python checkperms.py
- python checkperms.py --root /path/to/source chrome"""
-
- option_parser = optparse.OptionParser(usage=usage)
- option_parser.add_option('--root', dest='base_directory',
- default=DEFAULT_BASE_DIRECTORY,
- help='Specifies the repository root. This defaults '
- 'to %default relative to the script file, which '
- 'will normally be the repository root.')
- option_parser.add_option('-v', '--verbose', action='store_true',
- help='Print debug logging')
- options, args = option_parser.parse_args()
-
- global VERBOSE
- if options.verbose:
- VERBOSE = True
-
- # Optional base directory of the repository.
- global BASE_DIRECTORY
- if (not options.base_directory or
- options.base_directory == DEFAULT_BASE_DIRECTORY):
- BASE_DIRECTORY = os.path.abspath(
- os.path.join(os.path.abspath(argv[0]), DEFAULT_BASE_DIRECTORY))
- else:
- BASE_DIRECTORY = os.path.abspath(argv[2])
-
- # Figure out which directory we have to check.
- if not args:
- # No directory to check specified, use the repository root.
- start_dir = BASE_DIRECTORY
- elif len(args) == 1:
- # Directory specified. Start here. It's supposed to be relative to the
- # base directory.
- start_dir = os.path.abspath(os.path.join(BASE_DIRECTORY, args[0]))
- else:
- # More than one argument, we don't handle this.
- option_parser.print_help()
- return 1
-
- print 'Using base directory:', BASE_DIRECTORY
- print 'Checking directory:', start_dir
-
- BASE_DIRECTORY = BASE_DIRECTORY.replace('\\', '/')
- start_dir = start_dir.replace('\\', '/')
-
- success = True
- if os.path.exists(os.path.join(BASE_DIRECTORY, '.svn')):
- global SVN_REPO_URL
- SVN_REPO_URL = GetSvnRepositoryRoot(BASE_DIRECTORY)
- if not SVN_REPO_URL:
- print 'Cannot determine the SVN repo URL'
- success = False
- elif os.path.exists(os.path.join(BASE_DIRECTORY, '.git')):
- global IS_SVN
- IS_SVN = False
- global GIT_SOURCE_DIRECTORY
- GIT_SOURCE_DIRECTORY = GetGitSourceDirectory(BASE_DIRECTORY)
- if not GIT_SOURCE_DIRECTORY:
- print 'Cannot determine the list of GIT directories'
- success = False
- else:
- print 'Cannot determine the SCM used in %s' % BASE_DIRECTORY
- success = False
-
- if success:
- success = CheckDirectory(start_dir)
- if not success:
+ python %prog
+ python %prog --root /path/to/source chrome"""
+
+ parser = optparse.OptionParser(usage=usage)
+ parser.add_option(
+ '--root',
+ default=get_scm('.')[0],
+ help='Specifies the repository root. This defaults '
+ 'to %default relative to the script file, which '
+ 'will normally be the repository root.')
+ parser.add_option(
+ '-v', '--verbose', action='store_true', help='Print debug logging')
+ options, args = parser.parse_args()
+
+ logging.basicConfig(
+ level=(logging.DEBUG if options.verbose else logging.ERROR))
+
+ if len(args) > 1:
+ parser.error('Too many arguments used')
+ if args:
+ start_dir = args[0]
+
+ if not options.root:
+ parser.error('Must specify --root')
+ options.root = os.path.abspath(options.root)
+
+ # Guess again the SCM used.
+ api = get_scm(options.root)
+
+ if not api.check(start_dir):
print '\nFAILED\n'
return 1
print '\nSUCCESS\n'
@@ -346,4 +238,4 @@ Examples:
if '__main__' == __name__:
- sys.exit(main(sys.argv))
+ sys.exit(main())
« no previous file with comments | « no previous file | tools/checkperms/pylintrc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698