mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 01:07:15 +03:00
219554305e
Summary: The current `clone --shallow` command has some issues: - It fetches *all* remote bookmarks, since selectivepull does not work with streamclone, then remove most remote bookmarks in a second transaction. - It goes through remotenames, which is racy, and D20703268 does not fix the clone case. Possible cause of T65349853. - Too many wrappers (ex. in remotefilelog, remotenames, fastdiscovery) wtih many configurations (ex. narrow-heads on/off) makes it hard to reason about. Instead of bandaidding the clone function, this diff adds a new clone implementation that aims to solve the issues: - Use streamclone, but do not pull all remote names. - Pull selectivepull names explicitly with a working "discovery" strategy (repo heads should be non-empty with narrow-heads on or off). - Do clone in one transaction. Outside world won't see an incomplete state. - Use `repo.pull` API, which is not subject to race conditions. - Eventually, this might be the only supported "clone" after Mononoke becoming the single source of truth. Note: the code path still goes through bookmarks.py and remotenames.py. They will be cleaned up in upcoming diffs. Reviewed By: DurhamG Differential Revision: D21011401 fbshipit-source-id: d8751ac9bd643e9661e58c87b683be285f0dc925
62 lines
2.1 KiB
Python
62 lines
2.1 KiB
Python
# Copyright (c) Facebook, Inc. and its affiliates.
|
|
#
|
|
# This software may be used and distributed according to the terms of the
|
|
# GNU General Public License version 2.
|
|
|
|
"""clone utilities that aims for Mononoke compatibility"""
|
|
|
|
from . import bookmarks as bookmod, error, streamclone
|
|
from .i18n import _
|
|
|
|
|
|
def shallowclone(source, repo):
|
|
"""clone from source into an empty shallow repo"""
|
|
repo = repo.unfiltered()
|
|
|
|
with repo.wlock(), repo.lock(), repo.transaction("clone"):
|
|
if any(
|
|
repo.svfs.tryread(name)
|
|
for name in ["00changelog.i", "bookmarks", "remotenames"]
|
|
):
|
|
raise error.Abort(_("clone: repo %s is not empty") % repo.root)
|
|
|
|
repo.requirements.add("remotefilelog")
|
|
repo._writerequirements()
|
|
|
|
repo.ui.status(_("fetching changelog\n"))
|
|
with repo.conn(source) as conn:
|
|
# Assume the remote server supports streamclone.
|
|
peer = conn.peer
|
|
fp = peer.stream_out(shallow=True)
|
|
|
|
l = fp.readline()
|
|
if l.strip() != b"0":
|
|
raise error.ResponseError(
|
|
_("unexpected response from remote server:"), l
|
|
)
|
|
|
|
l = fp.readline()
|
|
try:
|
|
filecount, bytecount = list(map(int, l.split(b" ", 1)))
|
|
except (ValueError, TypeError):
|
|
raise error.ResponseError(
|
|
_("unexpected response from remote server:"), l
|
|
)
|
|
|
|
# Get 00changelog.{i,d}. This does not write bookmarks or remotenames.
|
|
streamclone.consumev1(repo, fp, filecount, bytecount)
|
|
# repo.changelog needs to be reloaded.
|
|
repo.invalidate()
|
|
|
|
# Fetch selected remote bookmarks.
|
|
repo.ui.status(_("fetching selected remote bookmarks\n"))
|
|
remote = repo.ui.paths.getname(repo.ui.paths.getpath(source).rawloc)
|
|
assert remote is not None
|
|
repo.pull(
|
|
source, bookmarknames=bookmod.selectivepullbookmarknames(repo, remote)
|
|
)
|
|
|
|
# Data migration.
|
|
if "zstorecommitdata" in repo.storerequirements:
|
|
repo._syncrevlogtozstore()
|