1 """A class to build directory diff tools on."""
11 """Directory comparison class."""
17 # Properties that caller may change before calling self.run():
18 self
.hide
= [os
.curdir
, os
.pardir
] # Names never to be shown
19 self
.ignore
= ['RCS', 'tags'] # Names ignored in comparison
24 """Compare everything except common subdirectories."""
25 self
.a_list
= filter(dircache
.listdir(self
.a
), self
.hide
)
26 self
.b_list
= filter(dircache
.listdir(self
.b
), self
.hide
)
34 """Compute common names."""
45 if x
not in self
.common
:
49 """Distinguish files, directories, funnies."""
51 self
.common_files
= []
52 self
.common_funny
= []
55 a_path
= os
.path
.join(self
.a
, x
)
56 b_path
= os
.path
.join(self
.b
, x
)
60 a_stat
= statcache
.stat(a_path
)
62 # print 'Can\'t stat', a_path, ':', why[1]
65 b_stat
= statcache
.stat(b_path
)
67 # print 'Can\'t stat', b_path, ':', why[1]
71 a_type
= S_IFMT(a_stat
[ST_MODE
])
72 b_type
= S_IFMT(b_stat
[ST_MODE
])
74 self
.common_funny
.append(x
)
76 self
.common_dirs
.append(x
)
78 self
.common_files
.append(x
)
80 self
.common_funny
.append(x
)
82 self
.common_funny
.append(x
)
85 """Find out differences between common files."""
86 xx
= cmpfiles(self
.a
, self
.b
, self
.common_files
)
87 self
.same_files
, self
.diff_files
, self
.funny_files
= xx
90 """Find out differences between common subdirectories.
91 A new dircmp object is created for each common subdirectory,
92 these are stored in a dictionary indexed by filename.
93 The hide and ignore properties are inherited from the parent."""
95 for x
in self
.common_dirs
:
96 a_x
= os
.path
.join(self
.a
, x
)
97 b_x
= os
.path
.join(self
.b
, x
)
98 self
.subdirs
[x
] = newdd
= dircmp().new(a_x
, b_x
)
99 newdd
.hide
= self
.hide
100 newdd
.ignore
= self
.ignore
103 def phase4_closure(self
):
104 """Recursively call phase4() on subdirectories."""
106 for x
in self
.subdirs
.keys():
107 self
.subdirs
[x
].phase4_closure()
110 """Print a report on the differences between a and b."""
111 # Assume that phases 1 to 3 have been executed
112 # Output format is purposely lousy
113 print 'diff', self
.a
, self
.b
115 print 'Only in', self
.a
, ':', self
.a_only
117 print 'Only in', self
.b
, ':', self
.b_only
119 print 'Identical files :', self
.same_files
121 print 'Differing files :', self
.diff_files
123 print 'Trouble with common files :', self
.funny_files
125 print 'Common subdirectories :', self
.common_dirs
126 if self
.common_funny
:
127 print 'Common funny cases :', self
.common_funny
129 def report_closure(self
):
130 """Print reports on self and on subdirs.
131 If phase 4 hasn't been done, no subdir reports are printed."""
135 except AttributeError:
136 return # No subdirectories computed
137 for x
in self
.subdirs
.keys():
139 self
.subdirs
[x
].report_closure()
141 def report_phase4_closure(self
):
142 """Report and do phase 4 recursively."""
145 for x
in self
.subdirs
.keys():
147 self
.subdirs
[x
].report_phase4_closure()
150 def cmpfiles(a
, b
, common
):
151 """Compare common files in two directories.
153 - files that compare equal
154 - files that compare different
155 - funny cases (can't stat etc.)"""
159 res
[cmp(os
.path
.join(a
, x
), os
.path
.join(b
, x
))].append(x
)
164 """Compare two files.
168 2 for funny cases (can't stat, etc.)"""
171 if cmpcache
.cmp(a
, b
): return 0
177 def filter(list, skip
):
178 """Return a copy with items that occur in skip removed."""
182 if item
not in skip
: result
.append(item
)
187 """Demonstration and testing."""
191 options
, args
= getopt
.getopt(sys
.argv
[1:], 'r')
193 raise getopt
.error
, 'need exactly two args'
194 dd
= dircmp().new(args
[0], args
[1])
196 if ('-r', '') in options
:
197 dd
.report_phase4_closure()
201 if __name__
== "__main__":