home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyth_os2.zip / python-1.0.2 / Lib / dircmp.py < prev    next >
Text File  |  1993-12-29  |  5KB  |  204 lines

  1. # Module 'dirmp'
  2. #
  3. # Defines a class to build directory diff tools on.
  4.  
  5. import os
  6.  
  7. import dircache
  8. import cmpcache
  9. import statcache
  10. from stat import *
  11.  
  12. # Directory comparison class.
  13. #
  14. class dircmp:
  15.     #
  16.     def new(self, a, b): # Initialize
  17.         self.a = a
  18.         self.b = b
  19.         # Properties that caller may change before calling self.run():
  20.         self.hide = [os.curdir, os.pardir] # Names never to be shown
  21.         self.ignore = ['RCS', 'tags'] # Names ignored in comparison
  22.         #
  23.         return self
  24.     #
  25.     def run(self): # Compare everything except common subdirectories
  26.         self.a_list = filter(dircache.listdir(self.a), self.hide)
  27.         self.b_list = filter(dircache.listdir(self.b), self.hide)
  28.         self.a_list.sort()
  29.         self.b_list.sort()
  30.         self.phase1()
  31.         self.phase2()
  32.         self.phase3()
  33.     #
  34.     def phase1(self): # Compute common names
  35.         self.a_only = []
  36.         self.common = []
  37.         for x in self.a_list:
  38.             if x in self.b_list:
  39.                 self.common.append(x)
  40.             else:
  41.                 self.a_only.append(x)
  42.         #
  43.         self.b_only = []
  44.         for x in self.b_list:
  45.             if x not in self.common:
  46.                 self.b_only.append(x)
  47.     #
  48.     def phase2(self): # Distinguish files, directories, funnies
  49.         self.common_dirs = []
  50.         self.common_files = []
  51.         self.common_funny = []
  52.         #
  53.         for x in self.common:
  54.             a_path = os.path.join(self.a, x)
  55.             b_path = os.path.join(self.b, x)
  56.             #
  57.             ok = 1
  58.             try:
  59.                 a_stat = statcache.stat(a_path)
  60.             except os.error, why:
  61.                 # print 'Can\'t stat', a_path, ':', why[1]
  62.                 ok = 0
  63.             try:
  64.                 b_stat = statcache.stat(b_path)
  65.             except os.error, why:
  66.                 # print 'Can\'t stat', b_path, ':', why[1]
  67.                 ok = 0
  68.             #
  69.             if ok:
  70.                 a_type = S_IFMT(a_stat[ST_MODE])
  71.                 b_type = S_IFMT(b_stat[ST_MODE])
  72.                 if a_type <> b_type:
  73.                     self.common_funny.append(x)
  74.                 elif S_ISDIR(a_type):
  75.                     self.common_dirs.append(x)
  76.                 elif S_ISREG(a_type):
  77.                     self.common_files.append(x)
  78.                 else:
  79.                     self.common_funny.append(x)
  80.             else:
  81.                 self.common_funny.append(x)
  82.     #
  83.     def phase3(self): # Find out differences between common files
  84.         xx = cmpfiles(self.a, self.b, self.common_files)
  85.         self.same_files, self.diff_files, self.funny_files = xx
  86.     #
  87.     def phase4(self): # Find out differences between common subdirectories
  88.         # A new dircmp object is created for each common subdirectory,
  89.         # these are stored in a dictionary indexed by filename.
  90.         # The hide and ignore properties are inherited from the parent
  91.         self.subdirs = {}
  92.         for x in self.common_dirs:
  93.             a_x = os.path.join(self.a, x)
  94.             b_x = os.path.join(self.b, x)
  95.             self.subdirs[x] = newdd = dircmp().new(a_x, b_x)
  96.             newdd.hide = self.hide
  97.             newdd.ignore = self.ignore
  98.             newdd.run()
  99.     #
  100.     def phase4_closure(self): # Recursively call phase4() on subdirectories
  101.         self.phase4()
  102.         for x in self.subdirs.keys():
  103.             self.subdirs[x].phase4_closure()
  104.     #
  105.     def report(self): # Print a report on the differences between a and b
  106.         # Assume that phases 1 to 3 have been executed
  107.         # Output format is purposely lousy
  108.         print 'diff', self.a, self.b
  109.         if self.a_only:
  110.             print 'Only in', self.a, ':', self.a_only
  111.         if self.b_only:
  112.             print 'Only in', self.b, ':', self.b_only
  113.         if self.same_files:
  114.             print 'Identical files :', self.same_files
  115.         if self.diff_files:
  116.             print 'Differing files :', self.diff_files
  117.         if self.funny_files:
  118.             print 'Trouble with common files :', self.funny_files
  119.         if self.common_dirs:
  120.             print 'Common subdirectories :', self.common_dirs
  121.         if self.common_funny:
  122.             print 'Common funny cases :', self.common_funny
  123.     #
  124.     def report_closure(self): # Print reports on self and on subdirs
  125.         # If phase 4 hasn't been done, no subdir reports are printed
  126.         self.report()
  127.         try:
  128.             x = self.subdirs
  129.         except AttributeError:
  130.             return # No subdirectories computed
  131.         for x in self.subdirs.keys():
  132.             print
  133.             self.subdirs[x].report_closure()
  134.     #
  135.     def report_phase4_closure(self): # Report and do phase 4 recursively
  136.         self.report()
  137.         self.phase4()
  138.         for x in self.subdirs.keys():
  139.             print
  140.             self.subdirs[x].report_phase4_closure()
  141.  
  142.  
  143. # Compare common files in two directories.
  144. # Return:
  145. #    - files that compare equal
  146. #    - files that compare different
  147. #    - funny cases (can't stat etc.)
  148. #
  149. def cmpfiles(a, b, common):
  150.     res = ([], [], [])
  151.     for x in common:
  152.         res[cmp(os.path.join(a, x), os.path.join(b, x))].append(x)
  153.     return res
  154.  
  155.  
  156. # Compare two files.
  157. # Return:
  158. #    0 for equal
  159. #    1 for different
  160. #    2 for funny cases (can't stat, etc.)
  161. #
  162. def cmp(a, b):
  163.     try:
  164.         if cmpcache.cmp(a, b): return 0
  165.         return 1
  166.     except os.error:
  167.         return 2
  168.  
  169.  
  170. # Remove a list item.
  171. # NB: This modifies the list argument.
  172. #
  173. def remove(list, item):
  174.     for i in range(len(list)):
  175.         if list[i] == item:
  176.             del list[i]
  177.             break
  178.  
  179.  
  180. # Return a copy with items that occur in skip removed.
  181. #
  182. def filter(list, skip):
  183.     result = []
  184.     for item in list:
  185.         if item not in skip: result.append(item)
  186.     return result
  187.  
  188.  
  189. # Demonstration and testing.
  190. #
  191. def demo():
  192.     import sys
  193.     import getopt
  194.     options, args = getopt.getopt(sys.argv[1:], 'r')
  195.     if len(args) <> 2: raise getopt.error, 'need exactly two args'
  196.     dd = dircmp().new(args[0], args[1])
  197.     dd.run()
  198.     if ('-r', '') in options:
  199.         dd.report_phase4_closure()
  200.     else:
  201.         dd.report()
  202.  
  203. # demo()
  204.