summaryrefslogtreecommitdiffstats
path: root/Tools/scripts/treesync.py
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1997-08-14 20:15:20 (GMT)
committerGuido van Rossum <guido@python.org>1997-08-14 20:15:20 (GMT)
commita554107802c751dff3a542e7b43c374860985b64 (patch)
tree0d4088b2f784b072ce918137cff4732bf0e2d424 /Tools/scripts/treesync.py
parent30e53c0c399c6cd0d8529bc24d17ba1d1e64b44e (diff)
downloadcpython-a554107802c751dff3a542e7b43c374860985b64.zip
cpython-a554107802c751dff3a542e7b43c374860985b64.tar.gz
cpython-a554107802c751dff3a542e7b43c374860985b64.tar.bz2
Source tree synchronization tool (for Windowes, mostly)
Diffstat (limited to 'Tools/scripts/treesync.py')
-rwxr-xr-xTools/scripts/treesync.py200
1 files changed, 200 insertions, 0 deletions
diff --git a/Tools/scripts/treesync.py b/Tools/scripts/treesync.py
new file mode 100755
index 0000000..1cad0e5
--- /dev/null
+++ b/Tools/scripts/treesync.py
@@ -0,0 +1,200 @@
+#! /usr/bin/env python
+
+"""Script to synchronize two source trees.
+
+Invoke with two arguments:
+
+python treesync.py slave master
+
+The assumption is that "master" contains CVS administration while
+slave doesn't. All files in the slave tree that have a CVS/Entries
+entry in the master tree are synchronized. This means:
+
+ If the files differ:
+ if the slave file is newer:
+ normalize the slave file
+ if the files still differ:
+ copy the slave to the master
+ else (the master is newer):
+ copy the master to the slave
+
+ normalizing the slave means replacing CRLF with LF when the master
+ doesn't use CRLF
+
+"""
+
+import os, sys, stat, string, getopt
+
+# Interactivity options
+default_answer = "ask"
+create_files = "yes"
+create_directories = "no"
+write_slave = "ask"
+write_master = "ask"
+
+def main():
+ global always_no, always_yes
+ global create_directories, write_master, write_slave
+ opts, args = getopt.getopt(sys.argv[1:], "nym:s:d:f:a:")
+ for o, a in opts:
+ if o == '-y':
+ default_answer = "yes"
+ if o == '-n':
+ default_answer = "no"
+ if o == '-s':
+ write_slave = a
+ if o == '-m':
+ write_master = a
+ if o == '-d':
+ create_directories = a
+ if o == '-f':
+ create_files = a
+ if o == '-a':
+ create_files = create_directories = write_slave = write_master = a
+ try:
+ [slave, master] = args
+ except ValueError:
+ print "usage: python", sys.argv[0] or "treesync.py",
+ print "[-n] [-y] [-m y|n|a] [-s y|n|a] [-d y|n|a] [-f n|y|a]",
+ print "slavedir masterdir"
+ return
+ process(slave, master)
+
+def process(slave, master):
+ cvsdir = os.path.join(master, "CVS")
+ if not os.path.isdir(cvsdir):
+ print "skipping master subdirectory", master
+ print "-- not under CVS"
+ return
+ print "-"*40
+ print "slave ", slave
+ print "master", master
+ if not os.path.isdir(slave):
+ if not okay("create slave directory %s?" % slave,
+ answer=create_directories):
+ print "skipping master subdirectory", master
+ print "-- no corresponding slave", slave
+ return
+ print "creating slave directory", slave
+ try:
+ os.mkdir(slave)
+ except os.error, msg:
+ print "can't make slave directory", slave, ":", msg
+ return
+ else:
+ print "made slave directory", slave
+ cvsdir = None
+ subdirs = []
+ names = os.listdir(master)
+ for name in names:
+ mastername = os.path.join(master, name)
+ slavename = os.path.join(slave, name)
+ if name == "CVS":
+ cvsdir = mastername
+ else:
+ if os.path.isdir(mastername) and not os.path.islink(mastername):
+ subdirs.append((slavename, mastername))
+ if cvsdir:
+ entries = os.path.join(cvsdir, "Entries")
+ for e in open(entries).readlines():
+ words = string.split(e, '/')
+ if words[0] == '' and words[1:]:
+ name = words[1]
+ s = os.path.join(slave, name)
+ m = os.path.join(master, name)
+ compare(s, m)
+ for (s, m) in subdirs:
+ process(s, m)
+
+def compare(slave, master):
+ try:
+ sf = open(slave, 'rb')
+ except IOError:
+ sf = None
+ try:
+ mf = open(master, 'rb')
+ except IOError:
+ mf = None
+ if not sf:
+ if not mf:
+ print "Not updating missing master", master
+ return
+ print "Creating missing slave", slave
+ copy(master, slave, answer=create_files)
+ return
+ if sf and mf:
+ if identical(sf, mf):
+ return
+ sft = mtime(sf)
+ mft = mtime(mf)
+ if mft > sft:
+ # Master is newer -- copy master to slave
+ sf.close()
+ mf.close()
+ print "Master ", master
+ print "is newer than slave", slave
+ copy(master, slave, answer=write_slave)
+ return
+ # Slave is newer -- copy slave to master
+ # But first check what to do about CRLF
+ mf.seek(0)
+ fun = funnychars(mf)
+ mf.close()
+ sf.close()
+ if fun:
+ print "***UPDATING MASTER (BINARY COPY)***"
+ copy(slave, master, "rb", write_master)
+ else:
+ print "***UPDATING MASTER***"
+ copy(slave, master, "r", write_master)
+
+BUFSIZE = 16*1024
+
+def identical(sf, mf):
+ while 1:
+ sd = sf.read(BUFSIZE)
+ md = mf.read(BUFSIZE)
+ if sd != md: return 0
+ if not sd: break
+ return 1
+
+def mtime(f):
+ st = os.fstat(f.fileno())
+ return st[stat.ST_MTIME]
+
+def funnychars(f):
+ while 1:
+ buf = f.read(BUFSIZE)
+ if not buf: break
+ if '\r' in buf or '\0' in buf: return 1
+ return 0
+
+def copy(src, dst, rmode="rb", wmode="wb", answer='ask'):
+ print "copying", src
+ print " to", dst
+ if not okay("okay to copy? ", answer):
+ return
+ f = open(src, rmode)
+ g = open(dst, wmode)
+ while 1:
+ buf = f.read(BUFSIZE)
+ if not buf: break
+ g.write(buf)
+ f.close()
+ g.close()
+
+def okay(prompt, answer='ask'):
+ answer = string.lower(string.strip(answer))
+ if not answer or answer[0] not in 'ny':
+ answer = raw_input(prompt)
+ answer = string.lower(string.strip(answer))
+ if not answer:
+ answer = default_answer
+ if answer[:1] == 'y':
+ return 1
+ if answer[:1] == 'n':
+ return 0
+ print "Yes or No please -- try again:"
+ return okay(prompt)
+
+main()