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