##// END OF EJS Templates
sshrepo: move mkstemp() out of the try block, we don't use the exception...
Benoit Boissinot -
r9742:0c84afa1 default
parent child Browse files
Show More
@@ -1,227 +1,223 b''
1 1 # sshserver.py - ssh protocol server support for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2, incorporated herein by reference.
8 8
9 9 from i18n import _
10 10 from node import bin, hex
11 11 import streamclone, util, hook
12 12 import os, sys, tempfile, urllib, copy
13 13
14 14 class sshserver(object):
15 15
16 16 caps = 'unbundle lookup changegroupsubset branchmap'.split()
17 17
18 18 def __init__(self, ui, repo):
19 19 self.ui = ui
20 20 self.repo = repo
21 21 self.lock = None
22 22 self.fin = sys.stdin
23 23 self.fout = sys.stdout
24 24
25 25 hook.redirect(True)
26 26 sys.stdout = sys.stderr
27 27
28 28 # Prevent insertion/deletion of CRs
29 29 util.set_binary(self.fin)
30 30 util.set_binary(self.fout)
31 31
32 32 def getarg(self):
33 33 argline = self.fin.readline()[:-1]
34 34 arg, l = argline.split()
35 35 val = self.fin.read(int(l))
36 36 return arg, val
37 37
38 38 def respond(self, v):
39 39 self.fout.write("%d\n" % len(v))
40 40 self.fout.write(v)
41 41 self.fout.flush()
42 42
43 43 def serve_forever(self):
44 44 try:
45 45 while self.serve_one(): pass
46 46 finally:
47 47 if self.lock is not None:
48 48 self.lock.release()
49 49 sys.exit(0)
50 50
51 51 def serve_one(self):
52 52 cmd = self.fin.readline()[:-1]
53 53 if cmd:
54 54 impl = getattr(self, 'do_' + cmd, None)
55 55 if impl: impl()
56 56 else: self.respond("")
57 57 return cmd != ''
58 58
59 59 def do_lookup(self):
60 60 arg, key = self.getarg()
61 61 assert arg == 'key'
62 62 try:
63 63 r = hex(self.repo.lookup(key))
64 64 success = 1
65 65 except Exception, inst:
66 66 r = str(inst)
67 67 success = 0
68 68 self.respond("%s %s\n" % (success, r))
69 69
70 70 def do_branchmap(self):
71 71 branchmap = self.repo.branchmap()
72 72 heads = []
73 73 for branch, nodes in branchmap.iteritems():
74 74 branchname = urllib.quote(branch)
75 75 branchnodes = [hex(node) for node in nodes]
76 76 heads.append('%s %s' % (branchname, ' '.join(branchnodes)))
77 77 self.respond('\n'.join(heads))
78 78
79 79 def do_heads(self):
80 80 h = self.repo.heads()
81 81 self.respond(" ".join(map(hex, h)) + "\n")
82 82
83 83 def do_hello(self):
84 84 '''the hello command returns a set of lines describing various
85 85 interesting things about the server, in an RFC822-like format.
86 86 Currently the only one defined is "capabilities", which
87 87 consists of a line in the form:
88 88
89 89 capabilities: space separated list of tokens
90 90 '''
91 91 caps = copy.copy(self.caps)
92 92 if self.ui.configbool('server', 'uncompressed'):
93 93 caps.append('stream=%d' % self.repo.changelog.version)
94 94 self.respond("capabilities: %s\n" % (' '.join(caps),))
95 95
96 96 def do_lock(self):
97 97 '''DEPRECATED - allowing remote client to lock repo is not safe'''
98 98
99 99 self.lock = self.repo.lock()
100 100 self.respond("")
101 101
102 102 def do_unlock(self):
103 103 '''DEPRECATED'''
104 104
105 105 if self.lock:
106 106 self.lock.release()
107 107 self.lock = None
108 108 self.respond("")
109 109
110 110 def do_branches(self):
111 111 arg, nodes = self.getarg()
112 112 nodes = map(bin, nodes.split(" "))
113 113 r = []
114 114 for b in self.repo.branches(nodes):
115 115 r.append(" ".join(map(hex, b)) + "\n")
116 116 self.respond("".join(r))
117 117
118 118 def do_between(self):
119 119 arg, pairs = self.getarg()
120 120 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
121 121 r = []
122 122 for b in self.repo.between(pairs):
123 123 r.append(" ".join(map(hex, b)) + "\n")
124 124 self.respond("".join(r))
125 125
126 126 def do_changegroup(self):
127 127 nodes = []
128 128 arg, roots = self.getarg()
129 129 nodes = map(bin, roots.split(" "))
130 130
131 131 cg = self.repo.changegroup(nodes, 'serve')
132 132 while True:
133 133 d = cg.read(4096)
134 134 if not d:
135 135 break
136 136 self.fout.write(d)
137 137
138 138 self.fout.flush()
139 139
140 140 def do_changegroupsubset(self):
141 141 argmap = dict([self.getarg(), self.getarg()])
142 142 bases = [bin(n) for n in argmap['bases'].split(' ')]
143 143 heads = [bin(n) for n in argmap['heads'].split(' ')]
144 144
145 145 cg = self.repo.changegroupsubset(bases, heads, 'serve')
146 146 while True:
147 147 d = cg.read(4096)
148 148 if not d:
149 149 break
150 150 self.fout.write(d)
151 151
152 152 self.fout.flush()
153 153
154 154 def do_addchangegroup(self):
155 155 '''DEPRECATED'''
156 156
157 157 if not self.lock:
158 158 self.respond("not locked")
159 159 return
160 160
161 161 self.respond("")
162 162 r = self.repo.addchangegroup(self.fin, 'serve', self.client_url())
163 163 self.respond(str(r))
164 164
165 165 def client_url(self):
166 166 client = os.environ.get('SSH_CLIENT', '').split(' ', 1)[0]
167 167 return 'remote:ssh:' + client
168 168
169 169 def do_unbundle(self):
170 170 their_heads = self.getarg()[1].split()
171 171
172 172 def check_heads():
173 173 heads = map(hex, self.repo.heads())
174 174 return their_heads == [hex('force')] or their_heads == heads
175 175
176 176 # fail early if possible
177 177 if not check_heads():
178 178 self.respond(_('unsynced changes'))
179 179 return
180 180
181 181 self.respond('')
182 182
183 183 # write bundle data to temporary file because it can be big
184 tempname = fp = None
184 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
185 fp = os.fdopen(fd, 'wb+')
185 186 try:
186 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
187 fp = os.fdopen(fd, 'wb+')
188
189 187 count = int(self.fin.readline())
190 188 while count:
191 189 fp.write(self.fin.read(count))
192 190 count = int(self.fin.readline())
193 191
194 192 was_locked = self.lock is not None
195 193 if not was_locked:
196 194 self.lock = self.repo.lock()
197 195 try:
198 196 if not check_heads():
199 197 # someone else committed/pushed/unbundled while we
200 198 # were transferring data
201 199 self.respond(_('unsynced changes'))
202 200 return
203 201 self.respond('')
204 202
205 203 # push can proceed
206 204
207 205 fp.seek(0)
208 206 r = self.repo.addchangegroup(fp, 'serve', self.client_url())
209 207 self.respond(str(r))
210 208 finally:
211 209 if not was_locked:
212 210 self.lock.release()
213 211 self.lock = None
214 212 finally:
215 if fp is not None:
216 fp.close()
217 if tempname is not None:
218 os.unlink(tempname)
213 fp.close()
214 os.unlink(tempname)
219 215
220 216 def do_stream_out(self):
221 217 try:
222 218 for chunk in streamclone.stream_out(self.repo):
223 219 self.fout.write(chunk)
224 220 self.fout.flush()
225 221 except streamclone.StreamException, inst:
226 222 self.fout.write(str(inst))
227 223 self.fout.flush()
General Comments 0
You need to be logged in to leave comments. Login now