| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  | #! /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: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |             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 | 
					
						
							| 
									
										
										
										
											2001-01-17 08:48:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     normalizing the slave means replacing CRLF with LF when the master | 
					
						
							|  |  |  |     doesn't use CRLF | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  | import os, sys, stat, getopt | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # 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: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         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 | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         [slave, master] = args | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     except ValueError: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         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 | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     process(slave, master) | 
					
						
							| 
									
										
										
										
											2001-01-17 08:48:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  | def process(slave, master): | 
					
						
							|  |  |  |     cvsdir = os.path.join(master, "CVS") | 
					
						
							|  |  |  |     if not os.path.isdir(cvsdir): | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         print "skipping master subdirectory", master | 
					
						
							|  |  |  |         print "-- not under CVS" | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     print "-"*40 | 
					
						
							|  |  |  |     print "slave ", slave | 
					
						
							|  |  |  |     print "master", master | 
					
						
							|  |  |  |     if not os.path.isdir(slave): | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         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 | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     cvsdir = None | 
					
						
							|  |  |  |     subdirs = [] | 
					
						
							|  |  |  |     names = os.listdir(master) | 
					
						
							|  |  |  |     for name in names: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         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)) | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     if cvsdir: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         entries = os.path.join(cvsdir, "Entries") | 
					
						
							|  |  |  |         for e in open(entries).readlines(): | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |             words = e.split('/') | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |             if words[0] == '' and words[1:]: | 
					
						
							|  |  |  |                 name = words[1] | 
					
						
							|  |  |  |                 s = os.path.join(slave, name) | 
					
						
							|  |  |  |                 m = os.path.join(master, name) | 
					
						
							|  |  |  |                 compare(s, m) | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     for (s, m) in subdirs: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         process(s, m) | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def compare(slave, master): | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         sf = open(slave, 'r') | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     except IOError: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         sf = None | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         mf = open(master, 'rb') | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     except IOError: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         mf = None | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     if not sf: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         if not mf: | 
					
						
							|  |  |  |             print "Neither master nor slave exists", master | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         print "Creating missing slave", slave | 
					
						
							|  |  |  |         copy(master, slave, answer=create_files) | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											1997-11-04 17:35:43 +00:00
										 |  |  |     if not mf: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         print "Not updating missing master", master | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     if sf and mf: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         if identical(sf, mf): | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     sft = mtime(sf) | 
					
						
							|  |  |  |     mft = mtime(mf) | 
					
						
							|  |  |  |     if mft > sft: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         # 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 | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     # Slave is newer -- copy slave to master | 
					
						
							| 
									
										
										
										
											1997-11-04 17:35:43 +00:00
										 |  |  |     print "Slave is", sft-mft, "seconds newer than master" | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     # But first check what to do about CRLF | 
					
						
							|  |  |  |     mf.seek(0) | 
					
						
							|  |  |  |     fun = funnychars(mf) | 
					
						
							|  |  |  |     mf.close() | 
					
						
							|  |  |  |     sf.close() | 
					
						
							|  |  |  |     if fun: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         print "***UPDATING MASTER (BINARY COPY)***" | 
					
						
							|  |  |  |         copy(slave, master, "rb", answer=write_master) | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         print "***UPDATING MASTER***" | 
					
						
							|  |  |  |         copy(slave, master, "r", answer=write_master) | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | BUFSIZE = 16*1024 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def identical(sf, mf): | 
					
						
							|  |  |  |     while 1: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         sd = sf.read(BUFSIZE) | 
					
						
							|  |  |  |         md = mf.read(BUFSIZE) | 
					
						
							|  |  |  |         if sd != md: return 0 | 
					
						
							|  |  |  |         if not sd: break | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     return 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def mtime(f): | 
					
						
							|  |  |  |     st = os.fstat(f.fileno()) | 
					
						
							|  |  |  |     return st[stat.ST_MTIME] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def funnychars(f): | 
					
						
							|  |  |  |     while 1: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         buf = f.read(BUFSIZE) | 
					
						
							|  |  |  |         if not buf: break | 
					
						
							|  |  |  |         if '\r' in buf or '\0' in buf: return 1 | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     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): | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     f = open(src, rmode) | 
					
						
							|  |  |  |     g = open(dst, wmode) | 
					
						
							|  |  |  |     while 1: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         buf = f.read(BUFSIZE) | 
					
						
							|  |  |  |         if not buf: break | 
					
						
							|  |  |  |         g.write(buf) | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     f.close() | 
					
						
							|  |  |  |     g.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def okay(prompt, answer='ask'): | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |     answer = answer.strip().lower() | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     if not answer or answer[0] not in 'ny': | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         answer = raw_input(prompt) | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |         answer = answer.strip().lower() | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         if not answer: | 
					
						
							|  |  |  |             answer = default_answer | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     if answer[:1] == 'y': | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     if answer[:1] == 'n': | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         return 0 | 
					
						
							| 
									
										
										
										
											1997-08-14 20:15:20 +00:00
										 |  |  |     print "Yes or No please -- try again:" | 
					
						
							|  |  |  |     return okay(prompt) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-08-09 17:27:55 +00:00
										 |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     main() |