190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#!/usr/bin/env python
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)# Copyright (c) 2013 The Chromium Authors. All rights reserved.
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)# found in the LICENSE file.
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import optparse
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import os
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import re
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import sys
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)from build_paths import SDK_SRC_DIR
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)# Add SDK make tools scripts to the python path.
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import getos
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)VALID_PLATFORMS = ['linux', 'mac', 'win']
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochPLATFORM_PREFIX_RE = re.compile(r'^\[([^\]]*)\](.*)$')
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class ParseException(Exception):
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  def __init__(self, filename, line, message):
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    Exception.__init__(self)
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    self.filename = filename
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    self.line = line
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    self.message = message
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  def __str__(self):
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return '%s:%d: %s' % (self.filename, self.line, self.message)
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochdef SplitPattern(pattern):
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  match = PLATFORM_PREFIX_RE.match(pattern)
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if not match:
357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return pattern, []
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  # platform-specific line
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  platforms = match.group(1).split(',')
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  # If this platform is included, strip the [...] part.
417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  pattern = match.group(2)
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return pattern, platforms
437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class VerifyException(Exception):
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  pass
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class Rules(object):
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  def __init__(self, filename, platform=None, contents=None):
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    self.glob_prefixes = []
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    self.exact_filenames = set()
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    self.filename = filename
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    self.platform = platform or getos.GetPlatform()
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    self.exe_ext = '.exe' if self.platform == 'win' else ''
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if self.platform not in VALID_PLATFORMS:
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      raise ParseException(self.filename, 1,
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           'Unknown platform %s' % self.platform)
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if not contents:
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      with open(filename) as f:
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        contents = f.read()
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for line_no, rule in enumerate(contents.split('\n')):
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      rule = rule.strip()
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if rule:
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        self.ParsePattern(line_no + 1, rule)
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  def ParsePattern(self, line_no, pattern):
707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    pattern, platforms = SplitPattern(pattern)
717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if platforms:
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      unknown_platforms = set(platforms) - set(VALID_PLATFORMS)
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if unknown_platforms:
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        msg = 'Unknown platform(s) %s.' % (
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            ', '.join('"%s"' % platform for platform in unknown_platforms))
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        raise ParseException(self.filename, line_no, msg)
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if self.platform not in platforms:
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        return
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    pattern = pattern.replace('${PLATFORM}', self.platform)
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    pattern = pattern.replace('${EXE_EXT}', self.exe_ext)
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if '*' in pattern:
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      # glob pattern
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      # We only support * at the end.
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if pattern.find('*') != len(pattern) - 1:
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        msg = '* is only allowed at the end of the line.'
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        raise ParseException(self.filename, line_no, msg)
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      # Remove the *
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      pattern = pattern[:-1]
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      self.glob_prefixes.append(pattern)
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    else:
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      self.exact_filenames.add(pattern)
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  def VerifyDirectoryList(self, directory_list):
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    exact_filenames_used = set()
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    glob_prefixes_used = set()
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    expected_globs = set()
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    expected_filenames = set()
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    unexpected_filenames = set()
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for filename in directory_list:
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if os.path.sep != '/':
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        filename = filename.replace(os.path.sep, '/')
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if filename in self.exact_filenames:
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        exact_filenames_used.add(filename)
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        continue
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      # glob pattern
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      found_prefix = False
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      for prefix in self.glob_prefixes:
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if filename.startswith(prefix):
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          glob_prefixes_used.add(prefix)
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          found_prefix = True
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if not found_prefix:
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        unexpected_filenames.add(filename)
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if len(exact_filenames_used) != len(self.exact_filenames):
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      # We looped through the directory list, so if the lengths are unequal, it
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      # must be that we expected something that isn't there.
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      expected_filenames = self.exact_filenames - exact_filenames_used
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if len(glob_prefixes_used) != self.glob_prefixes:
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      expected_globs = set(self.glob_prefixes) - glob_prefixes_used
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if expected_filenames or unexpected_filenames or expected_globs:
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      msg = ''
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if unexpected_filenames:
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        msg += '>>> Unexpected filenames: <<<\n%s\n' % (
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            '\n'.join(sorted(unexpected_filenames)))
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if expected_filenames:
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        msg += '>>> Expected filenames: <<<\n%s\n' % (
13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            '\n'.join(sorted(expected_filenames)))
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if expected_globs:
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        msg += '>>> Expected 1+ files in these directories: <<< \n%s\n' % (
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            '\n'.join(sorted(expected_globs)))
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      raise VerifyException(msg)
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def GetDirectoryList(directory_path):
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  result = []
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for root, _, files in os.walk(directory_path):
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    rel_root = os.path.relpath(root, directory_path)
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if rel_root == '.':
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      rel_root = ''
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for base_name in files:
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      result.append(os.path.join(rel_root, base_name))
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return result
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochdef Verify(rule_path, directory_path, platform=None):
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  rules = Rules(rule_path, platform=platform)
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  directory_list = GetDirectoryList(directory_path)
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  rules.VerifyDirectoryList(directory_list)
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochdef SortFile(rule_path):
1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  with open(rule_path) as infile:
1627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    lines = infile.readlines()
1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def compare(line1, line2):
1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    line1 = SplitPattern(line1)[0].lower()
1667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    line2 = SplitPattern(line2)[0].lower()
1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return cmp(line1, line2)
1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  lines.sort(compare)
1707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  with open(rule_path, 'w') as output:
1717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for line in lines:
1727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      output.write(line)
1737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def main(args):
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  parser = optparse.OptionParser(usage='%prog <rule file> <directory>')
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  parser.add_option('-p', '--platform',
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      help='Test with this platform, instead of the system\'s platform')
1797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  parser.add_option('-s', '--sort', action='store_true',
1807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      help='Sort the file list in place, rather than verifying the contents.')
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  options, args = parser.parse_args(args)
1827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if options.sort:
1847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if not args:
1857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      parser.error('Expected rule file.')
1867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    SortFile(args[0])
1877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return 0
1887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if len(args) != 2:
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    parser.error('Expected rule file and directory.')
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  rule_path, directory_path = args
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if options.platform:
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if options.platform not in VALID_PLATFORMS:
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      parser.error('Unknown platform: %s' % options.platform)
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    platform = options.platform
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  else:
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    platform = getos.GetPlatform()
19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  try:
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return Verify(rule_path, directory_path, platform)
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  except ParseException, e:
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    print >> sys.stderr, 'Error parsing rules:\n', e
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return 1
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  except VerifyException, e:
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    print >> sys.stderr, 'Error verifying file list:\n', e
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return 1
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return 0
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)if __name__ == '__main__':
21290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  sys.exit(main(sys.argv[1:]))
213