262 r.append(wireprototypes.encodelist(b) + b"\n") |
263 r.append(wireprototypes.encodelist(b) + b"\n") |
263 |
264 |
264 return wireprototypes.bytesresponse(b''.join(r)) |
265 return wireprototypes.bytesresponse(b''.join(r)) |
265 |
266 |
266 |
267 |
|
268 @wireprotocommand(b'get_inline_clone_bundle', b'path', permission=b'pull') |
|
269 def get_inline_clone_bundle(repo, proto, path): |
|
270 """ |
|
271 Server command to send a clonebundle to the client |
|
272 """ |
|
273 if hook.hashook(repo.ui, b'pretransmit-inline-clone-bundle'): |
|
274 hook.hook( |
|
275 repo.ui, |
|
276 repo, |
|
277 b'pretransmit-inline-clone-bundle', |
|
278 throw=True, |
|
279 clonebundlepath=path, |
|
280 ) |
|
281 |
|
282 bundle_dir = repo.vfs.join(bundlecaches.BUNDLE_CACHE_DIR) |
|
283 clonebundlepath = repo.vfs.join(bundle_dir, path) |
|
284 if not repo.vfs.exists(clonebundlepath): |
|
285 raise error.Abort(b'clonebundle %s does not exist' % path) |
|
286 |
|
287 clonebundles_dir = os.path.realpath(bundle_dir) |
|
288 if not os.path.realpath(clonebundlepath).startswith(clonebundles_dir): |
|
289 raise error.Abort(b'clonebundle %s is using an illegal path' % path) |
|
290 |
|
291 def generator(vfs, bundle_path): |
|
292 with vfs(bundle_path) as f: |
|
293 length = os.fstat(f.fileno())[6] |
|
294 yield util.uvarintencode(length) |
|
295 for chunk in util.filechunkiter(f): |
|
296 yield chunk |
|
297 |
|
298 stream = generator(repo.vfs, clonebundlepath) |
|
299 return wireprototypes.streamres(gen=stream, prefer_uncompressed=True) |
|
300 |
|
301 |
267 @wireprotocommand(b'clonebundles', b'', permission=b'pull') |
302 @wireprotocommand(b'clonebundles', b'', permission=b'pull') |
268 def clonebundles(repo, proto): |
303 def clonebundles(repo, proto): |
269 """Server command for returning info for available bundles to seed clones. |
304 """Server command for returning info for available bundles to seed clones. |
270 |
305 |
271 Clients will parse this response and determine what bundle to fetch. |
306 Clients will parse this response and determine what bundle to fetch. |
272 |
307 |
273 Extensions may wrap this command to filter or dynamically emit data |
308 Extensions may wrap this command to filter or dynamically emit data |
274 depending on the request. e.g. you could advertise URLs for the closest |
309 depending on the request. e.g. you could advertise URLs for the closest |
275 data center given the client's IP address. |
310 data center given the client's IP address. |
276 """ |
311 |
277 manifest = bundlecaches.get_manifest(repo) |
312 The only filter on the server side is filtering out inline clonebundles |
278 return wireprototypes.bytesresponse(manifest) |
313 in case a client does not support them. |
|
314 Otherwise, older clients would retrieve and error out on those. |
|
315 """ |
|
316 manifest_contents = bundlecaches.get_manifest(repo) |
|
317 clientcapabilities = proto.getprotocaps() |
|
318 if b'inlineclonebundles' in clientcapabilities: |
|
319 return wireprototypes.bytesresponse(manifest_contents) |
|
320 modified_manifest = [] |
|
321 for line in manifest_contents.splitlines(): |
|
322 if line.startswith(bundlecaches.CLONEBUNDLESCHEME): |
|
323 continue |
|
324 modified_manifest.append(line) |
|
325 return wireprototypes.bytesresponse(b'\n'.join(modified_manifest)) |
279 |
326 |
280 |
327 |
281 wireprotocaps = [ |
328 wireprotocaps = [ |
282 b'lookup', |
329 b'lookup', |
283 b'branchmap', |
330 b'branchmap', |