7 |
7 |
8 import urllib, tempfile, os |
8 import urllib, tempfile, os |
9 from i18n import _ |
9 from i18n import _ |
10 from node import bin, hex |
10 from node import bin, hex |
11 import changegroup as changegroupmod |
11 import changegroup as changegroupmod |
12 import streamclone, repo, error, encoding, util |
12 import repo, error, encoding, util, store |
13 import pushkey as pushkey_ |
13 import pushkey as pushkey_ |
14 |
14 |
15 # list of nodes encoding / decoding |
15 # list of nodes encoding / decoding |
16 |
16 |
17 def decodelist(l, sep=' '): |
17 def decodelist(l, sep=' '): |
169 r.append(encodelist(b) + "\n") |
169 r.append(encodelist(b) + "\n") |
170 return "".join(r) |
170 return "".join(r) |
171 |
171 |
172 def capabilities(repo, proto): |
172 def capabilities(repo, proto): |
173 caps = 'lookup changegroupsubset branchmap pushkey'.split() |
173 caps = 'lookup changegroupsubset branchmap pushkey'.split() |
174 if streamclone.allowed(repo.ui): |
174 if _allowstream(repo.ui): |
175 caps.append('stream=%d' % repo.changelog.version) |
175 caps.append('stream=%d' % repo.changelog.version) |
176 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority)) |
176 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority)) |
177 return ' '.join(caps) |
177 return ' '.join(caps) |
178 |
178 |
179 def changegroup(repo, proto, roots): |
179 def changegroup(repo, proto, roots): |
218 |
218 |
219 def pushkey(repo, proto, namespace, key, old, new): |
219 def pushkey(repo, proto, namespace, key, old, new): |
220 r = pushkey_.push(repo, namespace, key, old, new) |
220 r = pushkey_.push(repo, namespace, key, old, new) |
221 return '%s\n' % int(r) |
221 return '%s\n' % int(r) |
222 |
222 |
|
223 def _allowstream(ui): |
|
224 return ui.configbool('server', 'uncompressed', True, untrusted=True) |
|
225 |
223 def stream(repo, proto): |
226 def stream(repo, proto): |
224 return streamres(streamclone.stream_out(repo)) |
227 '''If the server supports streaming clone, it advertises the "stream" |
|
228 capability with a value representing the version and flags of the repo |
|
229 it is serving. Client checks to see if it understands the format. |
|
230 |
|
231 The format is simple: the server writes out a line with the amount |
|
232 of files, then the total amount of bytes to be transfered (separated |
|
233 by a space). Then, for each file, the server first writes the filename |
|
234 and filesize (separated by the null character), then the file contents. |
|
235 ''' |
|
236 |
|
237 if not _allowstream(repo.ui): |
|
238 return '1\n' |
|
239 |
|
240 entries = [] |
|
241 total_bytes = 0 |
|
242 try: |
|
243 # get consistent snapshot of repo, lock during scan |
|
244 lock = repo.lock() |
|
245 try: |
|
246 repo.ui.debug('scanning\n') |
|
247 for name, ename, size in repo.store.walk(): |
|
248 entries.append((name, size)) |
|
249 total_bytes += size |
|
250 finally: |
|
251 lock.release() |
|
252 except error.LockError: |
|
253 return '2\n' # error: 2 |
|
254 |
|
255 def streamer(repo, entries, total): |
|
256 '''stream out all metadata files in repository.''' |
|
257 yield '0\n' # success |
|
258 repo.ui.debug('%d files, %d bytes to transfer\n' % |
|
259 (len(entries), total_bytes)) |
|
260 yield '%d %d\n' % (len(entries), total_bytes) |
|
261 for name, size in entries: |
|
262 repo.ui.debug('sending %s (%d bytes)\n' % (name, size)) |
|
263 # partially encode name over the wire for backwards compat |
|
264 yield '%s\0%d\n' % (store.encodedir(name), size) |
|
265 for chunk in util.filechunkiter(repo.sopener(name), limit=size): |
|
266 yield chunk |
|
267 |
|
268 return streamres(streamer(repo, entries, total_bytes)) |
225 |
269 |
226 def unbundle(repo, proto, heads): |
270 def unbundle(repo, proto, heads): |
227 their_heads = decodelist(heads) |
271 their_heads = decodelist(heads) |
228 |
272 |
229 def check_heads(): |
273 def check_heads(): |