| # This Source Code Form is subject to the terms of the Mozilla Public |
| # License, v. 2.0. If a copy of the MPL was not distributed with this |
| # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| |
| # check-sync-dirs.py --- check that one directory is an exact subset of another |
| # |
| # Usage: python check-sync-dirs.py COPY ORIGINAL |
| # |
| # Check that the files present in the directory tree COPY are exact |
| # copies of their counterparts in the directory tree ORIGINAL. COPY |
| # need not have all the files in ORIGINAL, but COPY may not have files |
| # absent from ORIGINAL. |
| # |
| # Each directory in COPY may have a file named |
| # 'check-sync-exceptions', which lists files in COPY that need not be |
| # the same as the corresponding file in ORIGINAL, or exist at all in |
| # ORIGINAL. (The 'check-sync-exceptions' file itself is always |
| # treated as exceptional.) Blank lines and '#' comments in the file |
| # are ignored. |
| |
| import sys |
| import os |
| from os.path import join |
| import filecmp |
| import textwrap |
| import fnmatch |
| |
| if len(sys.argv) != 3: |
| print >> sys.stderr, 'TEST-UNEXPECTED-FAIL | check-sync-dirs.py | Usage: %s COPY ORIGINAL' % sys.argv[0] |
| sys.exit(1) |
| |
| copy = os.path.abspath(sys.argv[1]) |
| original = os.path.abspath(sys.argv[2]) |
| |
| # Return the contents of FILENAME, a 'check-sync-exceptions' file, as |
| # a dictionary whose keys are exactly the list of filenames, along |
| # with the basename of FILENAME itself. If FILENAME does not exist, |
| # return the empty dictionary. |
| def read_exceptions(filename): |
| if (os.path.exists(filename)): |
| f = file(filename) |
| exceptions = {} |
| for line in f: |
| line = line.strip() |
| if line != '' and line[0] != '#': |
| exceptions[line] = None |
| exceptions[os.path.basename (filename)] = None |
| f.close() |
| return exceptions |
| else: |
| return {} |
| |
| # Return true if FILENAME matches any pattern in the list of filename |
| # patterns PATTERNS. |
| def fnmatch_any(filename, patterns): |
| for pattern in patterns: |
| if fnmatch.fnmatch(filename, pattern): |
| return True |
| return False |
| |
| # Check the contents of the directory tree COPY against ORIGINAL. For each |
| # file that differs, apply REPORT to COPY, ORIGINAL, and the file's |
| # relative path. COPY and ORIGINAL should be absolute. Ignore files |
| # that match patterns given in the list IGNORE. |
| def check(copy, original): |
| os.chdir(copy) |
| for (dirpath, dirnames, filenames) in os.walk('.'): |
| exceptions = read_exceptions(join(dirpath, 'check-sync-exceptions')) |
| for dirname in dirnames: |
| if fnmatch_any(dirname, exceptions): |
| dirnames.remove(dirname) |
| break |
| for filename in filenames: |
| if fnmatch_any(filename, exceptions): |
| continue |
| relative_name = join(dirpath, filename) |
| original_name = join(original, relative_name) |
| if (os.path.exists(original_name) |
| and filecmp.cmp(relative_name, original_name, False)): |
| continue |
| report(copy, original, relative_name) |
| |
| differences_found = False |
| |
| # Print an error message for DIFFERING, which was found to differ |
| # between COPY and ORIGINAL. Set the global variable differences_found. |
| def report(copy, original, differing): |
| global differences_found |
| if not differences_found: |
| print >> sys.stderr, 'TEST-UNEXPECTED-FAIL | check-sync-dirs.py | build file copies are not in sync\n' \ |
| 'TEST-INFO | check-sync-dirs.py | file(s) found in: %s\n' \ |
| 'TEST-INFO | check-sync-dirs.py | differ from their originals in: %s' \ |
| % (copy, original) |
| print >> sys.stderr, 'TEST-INFO | check-sync-dirs.py | differing file: %s' % differing |
| differences_found = True |
| |
| check(copy, original) |
| |
| if differences_found: |
| msg = '''In general, the files in '%s' should always be exact copies of |
| originals in '%s'. A change made to one should also be made to the |
| other. See 'check-sync-dirs.py' for more details.''' \ |
| % (copy, original) |
| print >> sys.stderr, textwrap.fill(msg, 75) |
| sys.exit(1) |
| |
| print >> sys.stderr, 'TEST-PASS | check-sync-dirs.py | %s <= %s' % (copy, original) |
| sys.exit(0) |