]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/python/contrib/Tools/scripts/treesync.py
Inital import
[l4.git] / l4 / pkg / python / contrib / Tools / scripts / treesync.py
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, 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 = e.split('/')
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 = answer.strip().lower()
192     if not answer or answer[0] not in 'ny':
193         answer = raw_input(prompt)
194         answer = answer.strip().lower()
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 if __name__ == '__main__':
205     main()