1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
# 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])
# Ignore detritus left lying around by editing tools.
ignored_patterns = ['*~', '.#*', '#*#', '*.orig', '*.rej']
# 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, ignore):
os.chdir(copy)
for (dirpath, dirnames, filenames) in os.walk('.'):
exceptions = read_exceptions(join(dirpath, 'check-sync-exceptions'))
for dirname in dirnames:
if (dirname in exceptions):
dirnames.remove(dirname)
break
for filename in filenames:
if (filename in exceptions) or fnmatch_any(filename, ignore):
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, ignored_patterns)
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)
|