282 return destlock |
282 return destlock |
283 except: # re-raises |
283 except: # re-raises |
284 release(destlock) |
284 release(destlock) |
285 raise |
285 raise |
286 |
286 |
|
287 def clonewithshare(ui, peeropts, sharepath, source, srcpeer, dest, pull=False, |
|
288 rev=None, update=True, stream=False): |
|
289 """Perform a clone using a shared repo. |
|
290 |
|
291 The store for the repository will be located at <sharepath>/.hg. The |
|
292 specified revisions will be cloned or pulled from "source". A shared repo |
|
293 will be created at "dest" and a working copy will be created if "update" is |
|
294 True. |
|
295 """ |
|
296 revs = None |
|
297 if rev: |
|
298 if not srcpeer.capable('lookup'): |
|
299 raise util.Abort(_("src repository does not support " |
|
300 "revision lookup and so doesn't " |
|
301 "support clone by revision")) |
|
302 revs = [srcpeer.lookup(r) for r in rev] |
|
303 |
|
304 basename = os.path.basename(sharepath) |
|
305 |
|
306 if os.path.exists(sharepath): |
|
307 ui.status(_('(sharing from existing pooled repository %s)\n') % |
|
308 basename) |
|
309 else: |
|
310 ui.status(_('(sharing from new pooled repository %s)\n') % basename) |
|
311 # Always use pull mode because hardlinks in share mode don't work well. |
|
312 # Never update because working copies aren't necessary in share mode. |
|
313 clone(ui, peeropts, source, dest=sharepath, pull=True, |
|
314 rev=rev, update=False, stream=stream) |
|
315 |
|
316 sharerepo = repository(ui, path=sharepath) |
|
317 share(ui, sharerepo, dest=dest, update=update, bookmarks=False) |
|
318 |
|
319 # We need to perform a pull against the dest repo to fetch bookmarks |
|
320 # and other non-store data that isn't shared by default. In the case of |
|
321 # non-existing shared repo, this means we pull from the remote twice. This |
|
322 # is a bit weird. But at the time it was implemented, there wasn't an easy |
|
323 # way to pull just non-changegroup data. |
|
324 destrepo = repository(ui, path=dest) |
|
325 exchange.pull(destrepo, srcpeer, heads=revs) |
|
326 |
|
327 return srcpeer, peer(ui, peeropts, dest) |
|
328 |
287 def clone(ui, peeropts, source, dest=None, pull=False, rev=None, |
329 def clone(ui, peeropts, source, dest=None, pull=False, rev=None, |
288 update=True, stream=False, branch=None): |
330 update=True, stream=False, branch=None, shareopts=None): |
289 """Make a copy of an existing repository. |
331 """Make a copy of an existing repository. |
290 |
332 |
291 Create a copy of an existing repository in a new directory. The |
333 Create a copy of an existing repository in a new directory. The |
292 source and destination are URLs, as passed to the repository |
334 source and destination are URLs, as passed to the repository |
293 function. Returns a pair of repository peers, the source and |
335 function. Returns a pair of repository peers, the source and |
318 update: update working directory after clone completes, if |
360 update: update working directory after clone completes, if |
319 destination is local repository (True means update to default rev, |
361 destination is local repository (True means update to default rev, |
320 anything else is treated as a revision) |
362 anything else is treated as a revision) |
321 |
363 |
322 branch: branches to clone |
364 branch: branches to clone |
|
365 |
|
366 shareopts: dict of options to control auto sharing behavior. The "pool" key |
|
367 activates auto sharing mode and defines the directory for stores. The |
|
368 "mode" key determines how to construct the directory name of the shared |
|
369 repository. "identity" means the name is derived from the node of the first |
|
370 changeset in the repository. "remote" means the name is derived from the |
|
371 remote's path/URL. Defaults to "identity." |
323 """ |
372 """ |
324 |
373 |
325 if isinstance(source, str): |
374 if isinstance(source, str): |
326 origsource = ui.expandpath(source) |
375 origsource = ui.expandpath(source) |
327 source, branch = parseurl(origsource, branch) |
376 source, branch = parseurl(origsource, branch) |
349 if destvfs.lexists(): |
398 if destvfs.lexists(): |
350 if not destvfs.isdir(): |
399 if not destvfs.isdir(): |
351 raise util.Abort(_("destination '%s' already exists") % dest) |
400 raise util.Abort(_("destination '%s' already exists") % dest) |
352 elif destvfs.listdir(): |
401 elif destvfs.listdir(): |
353 raise util.Abort(_("destination '%s' is not empty") % dest) |
402 raise util.Abort(_("destination '%s' is not empty") % dest) |
|
403 |
|
404 shareopts = shareopts or {} |
|
405 sharepool = shareopts.get('pool') |
|
406 sharenamemode = shareopts.get('mode') |
|
407 if sharepool: |
|
408 sharepath = None |
|
409 if sharenamemode == 'identity': |
|
410 # Resolve the name from the initial changeset in the remote |
|
411 # repository. This returns nullid when the remote is empty. It |
|
412 # raises RepoLookupError if revision 0 is filtered or otherwise |
|
413 # not available. If we fail to resolve, sharing is not enabled. |
|
414 try: |
|
415 rootnode = srcpeer.lookup('0') |
|
416 if rootnode != node.nullid: |
|
417 sharepath = os.path.join(sharepool, node.hex(rootnode)) |
|
418 else: |
|
419 ui.status(_('(not using pooled storage: ' |
|
420 'remote appears to be empty)\n')) |
|
421 except error.RepoLookupError: |
|
422 ui.status(_('(not using pooled storage: ' |
|
423 'unable to resolve identity of remote)\n')) |
|
424 elif sharenamemode == 'remote': |
|
425 sharepath = os.path.join(sharepool, util.sha1(source).hexdigest()) |
|
426 else: |
|
427 raise util.Abort('unknown share naming mode: %s' % sharenamemode) |
|
428 |
|
429 if sharepath: |
|
430 return clonewithshare(ui, peeropts, sharepath, source, srcpeer, |
|
431 dest, pull=pull, rev=rev, update=update, |
|
432 stream=stream) |
354 |
433 |
355 srclock = destlock = cleandir = None |
434 srclock = destlock = cleandir = None |
356 srcrepo = srcpeer.local() |
435 srcrepo = srcpeer.local() |
357 try: |
436 try: |
358 abspath = origsource |
437 abspath = origsource |