sapling/eden/scm/edenscm/clone.py
Muir Manders 44343769f8 collapse edenscm.mercurial package into edenscm
Summary:
We want to rename away from "mercurial". Rather than rename the "mercurial" Python package, we opted to just collapse it into the parent "edenscm" package. This is also a step towards further organizing we want to do around the new project name.

To ease the transition wrt hotfixes, we now replace "edenscm.mercurial" with "mercurial" to fix imports within base64-python extensions.

Reviewed By: sggutier

Differential Revision: D38943169

fbshipit-source-id: 03fa18079c51e2f7fac05d65b127095da3ab7c99
2022-08-24 13:45:53 -07:00

153 lines
5.5 KiB
Python

# Copyright (c) Meta Platforms, Inc. and 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"""
import bindings
from . import bookmarks as bookmod, changelog2, error, streamclone
from .i18n import _
from .node import hex
def revlogclone(source, repo):
"""clone from source into an empty remotefilelog repo using revlog changelog"""
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()
# Invalidate the local changelog length metadata.
repo.svfs.tryunlink("00changelog.len")
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()
repo.invalidatechangelog()
# Fetch selected remote bookmarks.
repo.ui.status(_("fetching selected remote bookmarks\n"))
remote = bookmod.remotenameforurl(repo.ui, repo.ui.paths.getpath(source).rawloc)
assert remote is not None
repo.pull(
source, bookmarknames=bookmod.selectivepullbookmarknames(repo, remote)
)
def emergencyclone(source, repo):
"""clone only 1 single commit for emergency commit+push use-cases
The commit graph will be incomplete and there is no way to complete the
history without reclone. Accessing older commits (ex. checking out an
older commit, logging file or directory history) is likely broken!
This can be potentially useful if the server has issues with its commit
graph components.
"""
with repo.wlock(), repo.lock(), repo.transaction("emergencyclone"):
if any(repo.svfs.tryread(name) for name in ["bookmarks", "remotenames", "tip"]):
raise error.Abort(_("clone: repo %s is not empty") % repo.root)
repo.requirements.add("remotefilelog")
repo._writerequirements()
repo.storerequirements.add("lazytextchangelog")
repo.storerequirements.add("emergencychangelog")
repo._writestorerequirements()
mainbookmark = bookmod.mainbookmark(repo)
repo.ui.warn(
_(
"warning: cloning as emergency commit+push use-case only! "
"accessing older commits is broken!\n"
)
)
repo.ui.status(_("resolving %s\n") % mainbookmark)
with repo.conn(source) as conn:
peer = conn.peer
mainnode = peer.lookup(mainbookmark)
# Write a DAG with one commit.
cl = changelog2.changelog.opensegments(repo, repo.ui.uiconfig())
# Pretend the "mainnode" does not have parents.
cl.inner.addgraphnodes([(mainnode, [])])
# Write to the "master" group.
cl.inner.flush([mainnode])
# Update references
remote = bookmod.remotenameforurl(
repo.ui, repo.ui.paths.getpath(source).rawloc
)
fullname = "%s/%s" % (remote, mainbookmark)
repo.svfs.write(
"remotenames", bookmod.encoderemotenames({fullname: mainnode})
)
repo.svfs.write("tip", mainnode)
repo.ui.status(_("added %s: %s\n") % (mainbookmark, hex(mainnode)))
repo.invalidate()
repo.invalidatechangelog()
def segmentsclone(source, repo):
"""clone using segmented changelog's CloneData
This produces a repo with lazy commit hashes.
"""
with repo.wlock(), repo.lock(), repo.transaction("clone"):
changelog2.migrateto(repo, "lazy")
repo.requirements.add("remotefilelog")
repo._writerequirements()
remote = bookmod.remotenameforurl(repo.ui, repo.ui.paths.getpath(source).rawloc)
bookmarks = bookmod.selectivepullbookmarknames(repo, remote)
repo.ui.status(_("populating main commit graph\n"))
if repo.ui.configbool("clone", "nativepull"):
bindings.exchange.clone(
repo.edenapi, repo.metalog(), repo.changelog.inner, bookmarks
)
else:
clonedata = repo.edenapi.clonedata()
repo.changelog.inner.importclonedata(clonedata)
tip = repo.changelog.dag.all().first()
if tip:
repo.ui.status(_("tip commit: %s\n") % hex(tip))
repo.svfs.write("tip", tip)
repo.ui.status(_("fetching selected remote bookmarks\n"))
assert remote is not None
repo.pull(source, bookmarknames=bookmarks)