| #!/usr/bin/env python |
| # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import argparse |
| import os |
| import re |
| import sys |
| |
| import build_version |
| from build_paths import SDK_SRC_DIR, SCRIPT_DIR, OUT_DIR |
| |
| # Add SDK make tools scripts to the python path. |
| sys.path.append(os.path.join(SDK_SRC_DIR, 'tools')) |
| |
| import getos |
| |
| VALID_PLATFORMS = ['linux', 'mac', 'win'] |
| PLATFORM_PREFIX_RE = re.compile(r'^\[([^\]]*)\](.*)$') |
| |
| class ParseException(Exception): |
| def __init__(self, filename, line, message): |
| Exception.__init__(self) |
| self.filename = filename |
| self.line = line |
| self.message = message |
| |
| def __str__(self): |
| return '%s:%d: %s' % (self.filename, self.line, self.message) |
| |
| |
| def SplitPattern(pattern): |
| match = PLATFORM_PREFIX_RE.match(pattern) |
| if not match: |
| return pattern, [] |
| |
| # platform-specific line |
| platforms = match.group(1).split(',') |
| |
| # If this platform is included, strip the [...] part. |
| pattern = match.group(2) |
| return pattern, platforms |
| |
| |
| class VerifyException(Exception): |
| pass |
| |
| class Rules(object): |
| def __init__(self, filename, platform=None, contents=None): |
| self.glob_prefixes = [] |
| self.exact_filenames = set() |
| self.filename = filename |
| self.platform = platform or getos.GetPlatform() |
| self.exe_ext = '.exe' if self.platform == 'win' else '' |
| |
| if self.platform not in VALID_PLATFORMS: |
| raise ParseException(self.filename, 1, |
| 'Unknown platform %s' % self.platform) |
| |
| if not contents: |
| with open(filename) as f: |
| contents = f.read() |
| |
| for line_no, rule in enumerate(contents.split('\n')): |
| rule = rule.strip() |
| if rule: |
| self.ParsePattern(line_no + 1, rule) |
| |
| def ParsePattern(self, line_no, pattern): |
| pattern, platforms = SplitPattern(pattern) |
| if platforms: |
| unknown_platforms = set(platforms) - set(VALID_PLATFORMS) |
| if unknown_platforms: |
| msg = 'Unknown platform(s) %s.' % ( |
| ', '.join('"%s"' % platform for platform in unknown_platforms)) |
| raise ParseException(self.filename, line_no, msg) |
| if self.platform not in platforms: |
| return |
| |
| pattern = pattern.replace('${PLATFORM}', self.platform) |
| pattern = pattern.replace('${EXE_EXT}', self.exe_ext) |
| |
| if '*' in pattern: |
| # glob pattern |
| # We only support * at the end. |
| if pattern.find('*') != len(pattern) - 1: |
| msg = '* is only allowed at the end of the line.' |
| raise ParseException(self.filename, line_no, msg) |
| |
| # Remove the * |
| pattern = pattern[:-1] |
| self.glob_prefixes.append(pattern) |
| # Sort by longest prefix first; otherwise the rules: |
| # |
| # foo/* |
| # foo/bar/* |
| # |
| # Won't work properly. A file "foo/bar/baz" will match the first rule, |
| # not the second. |
| self.glob_prefixes.sort(cmp=lambda x, y: cmp(len(y), len(x))) |
| else: |
| self.exact_filenames.add(pattern) |
| |
| def VerifyDirectoryList(self, directory_list): |
| exact_filenames_used = set() |
| glob_prefixes_used = set() |
| expected_globs = set() |
| expected_filenames = set() |
| unexpected_filenames = set() |
| |
| for filename in directory_list: |
| if os.path.sep != '/': |
| filename = filename.replace(os.path.sep, '/') |
| if filename in self.exact_filenames: |
| exact_filenames_used.add(filename) |
| continue |
| |
| # glob pattern |
| found_prefix = False |
| for prefix in self.glob_prefixes: |
| if filename.startswith(prefix): |
| glob_prefixes_used.add(prefix) |
| found_prefix = True |
| break |
| |
| if not found_prefix: |
| unexpected_filenames.add(filename) |
| |
| if len(exact_filenames_used) != len(self.exact_filenames): |
| # We looped through the directory list, so if the lengths are unequal, it |
| # must be that we expected something that isn't there. |
| expected_filenames = self.exact_filenames - exact_filenames_used |
| |
| if len(glob_prefixes_used) != self.glob_prefixes: |
| expected_globs = set(self.glob_prefixes) - glob_prefixes_used |
| |
| if expected_filenames or unexpected_filenames or expected_globs: |
| msg = '' |
| if unexpected_filenames: |
| msg += '>>> Unexpected filenames: <<<\n%s\n' % ( |
| '\n'.join(sorted(unexpected_filenames))) |
| if expected_filenames: |
| msg += '>>> Expected filenames: <<<\n%s\n' % ( |
| '\n'.join(sorted(expected_filenames))) |
| if expected_globs: |
| msg += '>>> Expected 1+ files in these directories: <<< \n%s\n' % ( |
| '\n'.join(sorted(expected_globs))) |
| raise VerifyException(msg) |
| |
| |
| def GetDirectoryList(directory_path): |
| result = [] |
| for root, _, files in os.walk(directory_path): |
| rel_root = os.path.relpath(root, directory_path) |
| if rel_root == '.': |
| rel_root = '' |
| for base_name in files: |
| result.append(os.path.join(rel_root, base_name)) |
| return result |
| |
| |
| def Verify(rule_path, directory_path, platform=None): |
| rules = Rules(rule_path, platform=platform) |
| directory_list = GetDirectoryList(directory_path) |
| rules.VerifyDirectoryList(directory_list) |
| |
| |
| def SortFile(rule_path): |
| with open(rule_path) as infile: |
| lines = infile.readlines() |
| |
| def compare(line1, line2): |
| line1 = SplitPattern(line1)[0].lower() |
| line2 = SplitPattern(line2)[0].lower() |
| return cmp(line1, line2) |
| |
| lines.sort(compare) |
| with open(rule_path, 'w') as output: |
| for line in lines: |
| output.write(line) |
| |
| |
| def main(args): |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument('-p', '--platform', |
| help='Test with this platform, instead of the system\'s platform') |
| parser.add_argument('-s', '--sort', action='store_true', |
| help='Sort the file list in place, rather than verifying the contents.') |
| parser.add_argument('rule_file', nargs='?', |
| default=os.path.join(SCRIPT_DIR, 'sdk_files.list')) |
| parser.add_argument('directory_path', nargs='?') |
| options = parser.parse_args(args) |
| |
| if options.sort: |
| SortFile(options.rule_file) |
| return 0 |
| |
| if not options.directory_path: |
| version = build_version.ChromeMajorVersion() |
| options.directory_path = os.path.join(OUT_DIR, 'pepper_%s' % version) |
| |
| if options.platform: |
| if options.platform not in VALID_PLATFORMS: |
| parser.error('Unknown platform: %s' % options.platform) |
| platform = options.platform |
| else: |
| platform = getos.GetPlatform() |
| |
| try: |
| return Verify(options.rule_file, options.directory_path, platform) |
| except ParseException, e: |
| sys.stderr.write('Error parsing rules:\n%s\n' % e) |
| return 1 |
| except VerifyException, e: |
| sys.stderr.write('Error verifying file list:\n%s\n' % e) |
| return 1 |
| return 0 |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main(sys.argv[1:])) |