home *** CD-ROM | disk | FTP | other *** search
/ Enter 2003: The Beautiful Scenery / enter-parhaat-2003.iso / files / Python-2.2.1.exe / TREESYNC.PY < prev    next >
Encoding:
Python Source  |  2001-01-17  |  5.9 KB  |  205 lines

  1. #! /usr/bin/env python
  2.  
  3. """Script to synchronize two source trees.
  4.  
  5. Invoke with two arguments:
  6.  
  7. python treesync.py slave master
  8.  
  9. The assumption is that "master" contains CVS administration while
  10. slave doesn't.  All files in the slave tree that have a CVS/Entries
  11. entry in the master tree are synchronized.  This means:
  12.  
  13.     If the files differ:
  14.         if the slave file is newer:
  15.             normalize the slave file
  16.             if the files still differ:
  17.                 copy the slave to the master
  18.         else (the master is newer):
  19.             copy the master to the slave
  20.  
  21.     normalizing the slave means replacing CRLF with LF when the master
  22.     doesn't use CRLF
  23.  
  24. """
  25.  
  26. import os, sys, stat, string, getopt
  27.  
  28. # Interactivity options
  29. default_answer = "ask"
  30. create_files = "yes"
  31. create_directories = "no"
  32. write_slave = "ask"
  33. write_master = "ask"
  34.  
  35. def main():
  36.     global always_no, always_yes
  37.     global create_directories, write_master, write_slave
  38.     opts, args = getopt.getopt(sys.argv[1:], "nym:s:d:f:a:")
  39.     for o, a in opts:
  40.         if o == '-y':
  41.             default_answer = "yes"
  42.         if o == '-n':
  43.             default_answer = "no"
  44.         if o == '-s':
  45.             write_slave = a
  46.         if o == '-m':
  47.             write_master = a
  48.         if o == '-d':
  49.             create_directories = a
  50.         if o == '-f':
  51.             create_files = a
  52.         if o == '-a':
  53.             create_files = create_directories = write_slave = write_master = a
  54.     try:
  55.         [slave, master] = args
  56.     except ValueError:
  57.         print "usage: python", sys.argv[0] or "treesync.py",
  58.         print "[-n] [-y] [-m y|n|a] [-s y|n|a] [-d y|n|a] [-f n|y|a]",
  59.         print "slavedir masterdir"
  60.         return
  61.     process(slave, master)
  62.  
  63. def process(slave, master):
  64.     cvsdir = os.path.join(master, "CVS")
  65.     if not os.path.isdir(cvsdir):
  66.         print "skipping master subdirectory", master
  67.         print "-- not under CVS"
  68.         return
  69.     print "-"*40
  70.     print "slave ", slave
  71.     print "master", master
  72.     if not os.path.isdir(slave):
  73.         if not okay("create slave directory %s?" % slave,
  74.                     answer=create_directories):
  75.             print "skipping master subdirectory", master
  76.             print "-- no corresponding slave", slave
  77.             return
  78.         print "creating slave directory", slave
  79.         try:
  80.             os.mkdir(slave)
  81.         except os.error, msg:
  82.             print "can't make slave directory", slave, ":", msg
  83.             return
  84.         else:
  85.             print "made slave directory", slave
  86.     cvsdir = None
  87.     subdirs = []
  88.     names = os.listdir(master)
  89.     for name in names:
  90.         mastername = os.path.join(master, name)
  91.         slavename = os.path.join(slave, name)
  92.         if name == "CVS":
  93.             cvsdir = mastername
  94.         else:
  95.             if os.path.isdir(mastername) and not os.path.islink(mastername):
  96.                 subdirs.append((slavename, mastername))
  97.     if cvsdir:
  98.         entries = os.path.join(cvsdir, "Entries")
  99.         for e in open(entries).readlines():
  100.             words = string.split(e, '/')
  101.             if words[0] == '' and words[1:]:
  102.                 name = words[1]
  103.                 s = os.path.join(slave, name)
  104.                 m = os.path.join(master, name)
  105.                 compare(s, m)
  106.     for (s, m) in subdirs:
  107.         process(s, m)
  108.  
  109. def compare(slave, master):
  110.     try:
  111.         sf = open(slave, 'r')
  112.     except IOError:
  113.         sf = None
  114.     try:
  115.         mf = open(master, 'rb')
  116.     except IOError:
  117.         mf = None
  118.     if not sf:
  119.         if not mf:
  120.             print "Neither master nor slave exists", master
  121.             return
  122.         print "Creating missing slave", slave
  123.         copy(master, slave, answer=create_files)
  124.         return
  125.     if not mf:
  126.         print "Not updating missing master", master
  127.         return
  128.     if sf and mf:
  129.         if identical(sf, mf):
  130.             return
  131.     sft = mtime(sf)
  132.     mft = mtime(mf)
  133.     if mft > sft:
  134.         # Master is newer -- copy master to slave
  135.         sf.close()
  136.         mf.close()
  137.         print "Master             ", master
  138.         print "is newer than slave", slave
  139.         copy(master, slave, answer=write_slave)
  140.         return
  141.     # Slave is newer -- copy slave to master
  142.     print "Slave is", sft-mft, "seconds newer than master"
  143.     # But first check what to do about CRLF
  144.     mf.seek(0)
  145.     fun = funnychars(mf)
  146.     mf.close()
  147.     sf.close()
  148.     if fun:
  149.         print "***UPDATING MASTER (BINARY COPY)***"
  150.         copy(slave, master, "rb", answer=write_master)
  151.     else:
  152.         print "***UPDATING MASTER***"
  153.         copy(slave, master, "r", answer=write_master)
  154.  
  155. BUFSIZE = 16*1024
  156.  
  157. def identical(sf, mf):
  158.     while 1:
  159.         sd = sf.read(BUFSIZE)
  160.         md = mf.read(BUFSIZE)
  161.         if sd != md: return 0
  162.         if not sd: break
  163.     return 1
  164.  
  165. def mtime(f):
  166.     st = os.fstat(f.fileno())
  167.     return st[stat.ST_MTIME]
  168.  
  169. def funnychars(f):
  170.     while 1:
  171.         buf = f.read(BUFSIZE)
  172.         if not buf: break
  173.         if '\r' in buf or '\0' in buf: return 1
  174.     return 0
  175.  
  176. def copy(src, dst, rmode="rb", wmode="wb", answer='ask'):
  177.     print "copying", src
  178.     print "     to", dst
  179.     if not okay("okay to copy? ", answer):
  180.         return
  181.     f = open(src, rmode)
  182.     g = open(dst, wmode)
  183.     while 1:
  184.         buf = f.read(BUFSIZE)
  185.         if not buf: break
  186.         g.write(buf)
  187.     f.close()
  188.     g.close()
  189.  
  190. def okay(prompt, answer='ask'):
  191.     answer = string.lower(string.strip(answer))
  192.     if not answer or answer[0] not in 'ny':
  193.         answer = raw_input(prompt)
  194.         answer = string.lower(string.strip(answer))
  195.         if not answer:
  196.             answer = default_answer
  197.     if answer[:1] == 'y':
  198.         return 1
  199.     if answer[:1] == 'n':
  200.         return 0
  201.     print "Yes or No please -- try again:"
  202.     return okay(prompt)
  203.  
  204. main()
  205.