-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathsvn-sync-repo.py
127 lines (106 loc) · 3.57 KB
/
svn-sync-repo.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/env python
"""
small utility for hot-syncing a svn repository through ssh.
uses execnet.
"""
import os
import sys
import execnet
import py
def usage():
arg0 = sys.argv[0]
print(arg0, "[user@]remote-host:/repo/location localrepo [ssh-config-file]")
def main(args):
remote = args[0]
localrepo = py.path.local(args[1])
if not localrepo.check(dir=1):
raise SystemExit(f"localrepo {localrepo} does not exist")
if len(args) == 3:
configfile = args[2]
else:
configfile = None
remote_host, path = remote.split(":", 1)
print("ssh-connecting to", remote_host)
gw = getgateway(remote_host, configfile)
local_rev = get_svn_youngest(localrepo)
# local protocol
# 1. client sends rev/repo -> server
# 2. server checks for newer revisions and sends dumps
# 3. client receives dumps, updates local repo
# 4. client goes back to step 1
c = gw.remote_exec(
"""
import py
import os
import time
remote_rev, repopath = channel.receive()
while 1:
rev = py.process.cmdexec('svnlook youngest "%s"' % repopath)
rev = int(rev)
if rev > remote_rev:
revrange = (remote_rev+1, rev)
dumpchannel = channel.gateway.newchannel()
channel.send(revrange)
channel.send(dumpchannel)
f = os.popen(
"svnadmin dump -q --incremental -r %s:%s %s"
% (revrange[0], revrange[1], repopath), 'r')
try:
maxcount = dumpchannel.receive()
count = maxcount
while 1:
s = f.read(8192)
if not s:
raise EOFError
dumpchannel.send(s)
count = count - 1
if count <= 0:
ack = dumpchannel.receive()
count = maxcount
except EOFError:
dumpchannel.close()
remote_rev = rev
else:
# using svn-hook instead would be nice here
time.sleep(30)
"""
)
c.send((local_rev, path))
print("checking revisions from %d in %s" % (local_rev, remote))
while 1:
revstart, revend = c.receive()
dumpchannel = c.receive()
print("receiving revisions", revstart, "-", revend, "replaying...")
svn_load(localrepo, dumpchannel)
print("current revision", revend)
def svn_load(repo, dumpchannel, maxcount=100):
# every maxcount we will send an ACK to the other
# side in order to synchronise and avoid our side
# growing buffers (execnet does not control
# RAM usage or receive queue sizes)
dumpchannel.send(maxcount)
f = os.popen(f"svnadmin load -q {repo}", "w")
count = maxcount
for x in dumpchannel:
sys.stdout.write(".")
sys.stdout.flush()
f.write(x)
count = count - 1
if count <= 0:
dumpchannel.send(maxcount)
count = maxcount
print >> sys.stdout
f.close()
def get_svn_youngest(repo):
rev = py.process.cmdexec('svnlook youngest "%s"' % repo)
return int(rev)
def getgateway(host, configfile=None):
xspec = "ssh=%s" % host
if configfile is not None:
xspec += "//ssh_config=%s" % configfile
return execnet.makegateway(xspec)
if __name__ == "__main__":
if len(sys.argv) < 3:
usage()
raise SystemExit(1)
main(sys.argv[1:])