PageRenderTime 296ms CodeModel.GetById 160ms app.highlight 20ms RepoModel.GetById 51ms app.codeStats 18ms

/Tools/scripts/treesync.py

http://unladen-swallow.googlecode.com/
Python | 205 lines | 197 code | 1 blank | 7 comment | 1 complexity | 80da9c526ee690ac8407b70befa048b4 MD5 | raw file
  1#! /usr/bin/env python
  2
  3"""Script to synchronize two source trees.
  4
  5Invoke with two arguments:
  6
  7python treesync.py slave master
  8
  9The assumption is that "master" contains CVS administration while
 10slave doesn't.  All files in the slave tree that have a CVS/Entries
 11entry 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
 26import os, sys, stat, getopt
 27
 28# Interactivity options
 29default_answer = "ask"
 30create_files = "yes"
 31create_directories = "no"
 32write_slave = "ask"
 33write_master = "ask"
 34
 35def 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
 63def 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
109def 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
155BUFSIZE = 16*1024
156
157def 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
165def mtime(f):
166    st = os.fstat(f.fileno())
167    return st[stat.ST_MTIME]
168
169def 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
176def 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
190def 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
204if __name__ == '__main__':
205    main()