3 """Script to synchronize two source trees.
5 Invoke with two arguments:
7 python treesync.py slave master
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:
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
21 normalizing the slave means replacing CRLF with LF when the master
26 import os, sys, stat, getopt
28 # Interactivity options
29 default_answer = "ask"
31 create_directories = "no"
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:")
41 default_answer = "yes"
49 create_directories = a
53 create_files = create_directories = write_slave = write_master = a
55 [slave, master] = args
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"
61 process(slave, master)
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"
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
78 print "creating slave directory", slave
82 print "can't make slave directory", slave, ":", msg
85 print "made slave directory", slave
88 names = os.listdir(master)
90 mastername = os.path.join(master, name)
91 slavename = os.path.join(slave, name)
95 if os.path.isdir(mastername) and not os.path.islink(mastername):
96 subdirs.append((slavename, mastername))
98 entries = os.path.join(cvsdir, "Entries")
99 for e in open(entries).readlines():
101 if words[0] == '' and words[1:]:
103 s = os.path.join(slave, name)
104 m = os.path.join(master, name)
106 for (s, m) in subdirs:
109 def compare(slave, master):
111 sf = open(slave, 'r')
115 mf = open(master, 'rb')
120 print "Neither master nor slave exists", master
122 print "Creating missing slave", slave
123 copy(master, slave, answer=create_files)
126 print "Not updating missing master", master
129 if identical(sf, mf):
134 # Master is newer -- copy master to slave
137 print "Master ", master
138 print "is newer than slave", slave
139 copy(master, slave, answer=write_slave)
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
149 print "***UPDATING MASTER (BINARY COPY)***"
150 copy(slave, master, "rb", answer=write_master)
152 print "***UPDATING MASTER***"
153 copy(slave, master, "r", answer=write_master)
157 def identical(sf, mf):
159 sd = sf.read(BUFSIZE)
160 md = mf.read(BUFSIZE)
161 if sd != md: return 0
166 st = os.fstat(f.fileno())
167 return st[stat.ST_MTIME]
171 buf = f.read(BUFSIZE)
173 if '\r' in buf or '\0' in buf: return 1
176 def copy(src, dst, rmode="rb", wmode="wb", answer='ask'):
179 if not okay("okay to copy? ", answer):
184 buf = f.read(BUFSIZE)
190 def okay(prompt, answer='ask'):
191 answer = answer.strip().lower()
192 if not answer or answer[0] not in 'ny':
193 answer = raw_input(prompt)
194 answer = answer.strip().lower()
196 answer = default_answer
197 if answer[:1] == 'y':
199 if answer[:1] == 'n':
201 print "Yes or No please -- try again:"
204 if __name__ == '__main__':