diff options
Diffstat (limited to 'Lib/lib-old/dircmp.py')
-rw-r--r-- | Lib/lib-old/dircmp.py | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/Lib/lib-old/dircmp.py b/Lib/lib-old/dircmp.py new file mode 100644 index 0000000..13a8a04 --- /dev/null +++ b/Lib/lib-old/dircmp.py @@ -0,0 +1,201 @@ +"""A class to build directory diff tools on.""" + +import os + +import dircache +import cmpcache +import statcache +from stat import * + +class dircmp: + """Directory comparison class.""" + + def new(self, a, b): + """Initialize.""" + self.a = a + self.b = b + # Properties that caller may change before calling self.run(): + self.hide = [os.curdir, os.pardir] # Names never to be shown + self.ignore = ['RCS', 'tags'] # Names ignored in comparison + + return self + + def run(self): + """Compare everything except common subdirectories.""" + self.a_list = filter(dircache.listdir(self.a), self.hide) + self.b_list = filter(dircache.listdir(self.b), self.hide) + self.a_list.sort() + self.b_list.sort() + self.phase1() + self.phase2() + self.phase3() + + def phase1(self): + """Compute common names.""" + self.a_only = [] + self.common = [] + for x in self.a_list: + if x in self.b_list: + self.common.append(x) + else: + self.a_only.append(x) + + self.b_only = [] + for x in self.b_list: + if x not in self.common: + self.b_only.append(x) + + def phase2(self): + """Distinguish files, directories, funnies.""" + self.common_dirs = [] + self.common_files = [] + self.common_funny = [] + + for x in self.common: + a_path = os.path.join(self.a, x) + b_path = os.path.join(self.b, x) + + ok = 1 + try: + a_stat = statcache.stat(a_path) + except os.error, why: + # print 'Can\'t stat', a_path, ':', why[1] + ok = 0 + try: + b_stat = statcache.stat(b_path) + except os.error, why: + # print 'Can\'t stat', b_path, ':', why[1] + ok = 0 + + if ok: + a_type = S_IFMT(a_stat[ST_MODE]) + b_type = S_IFMT(b_stat[ST_MODE]) + if a_type <> b_type: + self.common_funny.append(x) + elif S_ISDIR(a_type): + self.common_dirs.append(x) + elif S_ISREG(a_type): + self.common_files.append(x) + else: + self.common_funny.append(x) + else: + self.common_funny.append(x) + + def phase3(self): + """Find out differences between common files.""" + xx = cmpfiles(self.a, self.b, self.common_files) + self.same_files, self.diff_files, self.funny_files = xx + + def phase4(self): + """Find out differences between common subdirectories. + A new dircmp object is created for each common subdirectory, + these are stored in a dictionary indexed by filename. + The hide and ignore properties are inherited from the parent.""" + self.subdirs = {} + for x in self.common_dirs: + a_x = os.path.join(self.a, x) + b_x = os.path.join(self.b, x) + self.subdirs[x] = newdd = dircmp().new(a_x, b_x) + newdd.hide = self.hide + newdd.ignore = self.ignore + newdd.run() + + def phase4_closure(self): + """Recursively call phase4() on subdirectories.""" + self.phase4() + for x in self.subdirs.keys(): + self.subdirs[x].phase4_closure() + + def report(self): + """Print a report on the differences between a and b.""" + # Assume that phases 1 to 3 have been executed + # Output format is purposely lousy + print 'diff', self.a, self.b + if self.a_only: + print 'Only in', self.a, ':', self.a_only + if self.b_only: + print 'Only in', self.b, ':', self.b_only + if self.same_files: + print 'Identical files :', self.same_files + if self.diff_files: + print 'Differing files :', self.diff_files + if self.funny_files: + print 'Trouble with common files :', self.funny_files + if self.common_dirs: + print 'Common subdirectories :', self.common_dirs + if self.common_funny: + print 'Common funny cases :', self.common_funny + + def report_closure(self): + """Print reports on self and on subdirs. + If phase 4 hasn't been done, no subdir reports are printed.""" + self.report() + try: + x = self.subdirs + except AttributeError: + return # No subdirectories computed + for x in self.subdirs.keys(): + print + self.subdirs[x].report_closure() + + def report_phase4_closure(self): + """Report and do phase 4 recursively.""" + self.report() + self.phase4() + for x in self.subdirs.keys(): + print + self.subdirs[x].report_phase4_closure() + + +def cmpfiles(a, b, common): + """Compare common files in two directories. + Return: + - files that compare equal + - files that compare different + - funny cases (can't stat etc.)""" + + res = ([], [], []) + for x in common: + res[cmp(os.path.join(a, x), os.path.join(b, x))].append(x) + return res + + +def cmp(a, b): + """Compare two files. + Return: + 0 for equal + 1 for different + 2 for funny cases (can't stat, etc.)""" + + try: + if cmpcache.cmp(a, b): return 0 + return 1 + except os.error: + return 2 + + +def filter(list, skip): + """Return a copy with items that occur in skip removed.""" + + result = [] + for item in list: + if item not in skip: result.append(item) + return result + + +def demo(): + """Demonstration and testing.""" + + import sys + import getopt + options, args = getopt.getopt(sys.argv[1:], 'r') + if len(args) <> 2: raise getopt.error, 'need exactly two args' + dd = dircmp().new(args[0], args[1]) + dd.run() + if ('-r', '') in options: + dd.report_phase4_closure() + else: + dd.report() + +if __name__ == "__main__": + demo() |