mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 23:38:50 +03:00
Info command that prints snapshot changes
Summary: This diff makes `hg snapshot info` an equivalent to `hg show`, which shows info about the snapshot and its changes. To do that, it creates a `memctx` for the snapshot, which is kind of a commit in memory, which is useful because we can then reuse base hg stuff to show the diff :) Reviewed By: mitrandir77 Differential Revision: D31802201 fbshipit-source-id: 1bcea87e9a1b3ee665e04822fe78ff03e3ad393e
This commit is contained in:
parent
396e345703
commit
e63377ac51
@ -6,7 +6,7 @@
|
||||
from edenscm.mercurial import error, registrar
|
||||
from edenscm.mercurial.i18n import _
|
||||
|
||||
from . import createremote, restore, info
|
||||
from . import createremote, update, show
|
||||
|
||||
cmdtable = {}
|
||||
command = registrar.command(cmdtable)
|
||||
@ -23,8 +23,8 @@ def snapshot(ui, repo, **opts):
|
||||
|
||||
subcmd = snapshot.subcommand(
|
||||
categories=[
|
||||
("Manage snapshots", ["createremote", "restore"]),
|
||||
("Query snapshots", ["info"]),
|
||||
("Manage snapshots", ["create", "update"]),
|
||||
("Query snapshots", ["show"]),
|
||||
]
|
||||
)
|
||||
|
||||
@ -36,7 +36,7 @@ def createremotecmd(*args, **kwargs):
|
||||
|
||||
|
||||
@subcmd(
|
||||
"restore",
|
||||
"update|restore|checkout|co|up",
|
||||
[
|
||||
(
|
||||
"C",
|
||||
@ -47,12 +47,12 @@ def createremotecmd(*args, **kwargs):
|
||||
],
|
||||
_("ID"),
|
||||
)
|
||||
def restorecmd(*args, **kwargs):
|
||||
def updatecmd(*args, **kwargs):
|
||||
"""download a previously created snapshot and update working copy to its state"""
|
||||
restore.restore(*args, **kwargs)
|
||||
update.update(*args, **kwargs)
|
||||
|
||||
|
||||
@subcmd("info", [], _("ID"))
|
||||
def infocmd(*args, **kwargs):
|
||||
@subcmd("show|info", [], _("ID"))
|
||||
def showcmd(*args, **kwargs):
|
||||
"""gather information about the snapshot"""
|
||||
info.info(*args, **kwargs)
|
||||
show.show(*args, **kwargs)
|
||||
|
@ -1,24 +0,0 @@
|
||||
# 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.
|
||||
|
||||
from edenscm.mercurial import error
|
||||
from edenscm.mercurial.edenapi_upload import (
|
||||
getreponame,
|
||||
)
|
||||
from edenscm.mercurial.i18n import _
|
||||
|
||||
|
||||
def info(ui, repo, csid, **opts):
|
||||
try:
|
||||
repo.edenapi.fetchsnapshot(
|
||||
getreponame(repo),
|
||||
{
|
||||
"cs_id": bytes.fromhex(csid),
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
raise error.Abort(_("snapshot doesn't exist"))
|
||||
else:
|
||||
ui.status(_("snapshot exists\n"))
|
88
eden/scm/edenscm/hgext/snapshot/show.py
Normal file
88
eden/scm/edenscm/hgext/snapshot/show.py
Normal file
@ -0,0 +1,88 @@
|
||||
# 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.
|
||||
|
||||
from edenscm.mercurial import error, scmutil
|
||||
from edenscm.mercurial.cmdutil import changeset_printer
|
||||
from edenscm.mercurial.context import memctx, memfilectx
|
||||
from edenscm.mercurial.edenapi_upload import (
|
||||
getreponame,
|
||||
)
|
||||
from edenscm.mercurial.i18n import _
|
||||
from edenscm.mercurial.node import nullid
|
||||
from edenscm.mercurial.util import pickle
|
||||
|
||||
|
||||
def _snapshot2ctx(repo, snapshot):
|
||||
"""Build a memctx for this snapshot.
|
||||
|
||||
This is not precisely correct as it doesn't differentiate untracked/added
|
||||
but it's good enough for diffing.
|
||||
"""
|
||||
|
||||
parent = snapshot["hg_parents"]
|
||||
# Once merges/conflicted states are supported, we'll need to support more
|
||||
# than one parent
|
||||
assert isinstance(parent, bytes)
|
||||
|
||||
parents = (parent, nullid)
|
||||
path2filechange = {f[0]: f[1] for f in snapshot["file_changes"]}
|
||||
|
||||
def token2cacheable(token):
|
||||
data = token["data"]
|
||||
return pickle.dumps((data["id"], data["bubble_id"]))
|
||||
|
||||
cache = {}
|
||||
|
||||
def getfile(repo, memctx, path):
|
||||
change = path2filechange.get(path)
|
||||
if change is None:
|
||||
return repo[parent][path]
|
||||
if change == "Deletion" or change == "UntrackedDeletion":
|
||||
return None
|
||||
elif "Change" in change or "UntrackedChange" in change:
|
||||
change = change.get("Change") or change["UntrackedChange"]
|
||||
token = change["upload_token"]
|
||||
key = token2cacheable(token)
|
||||
if key not in cache:
|
||||
# Possible future optimisation: Download files in parallel
|
||||
cache[key] = repo.edenapi.downloadfiletomemory(getreponame(repo), token)
|
||||
islink = change["file_type"] == "Symlink"
|
||||
isexec = change["file_type"] == "Executable"
|
||||
return memfilectx(
|
||||
repo, None, path, data=cache[key], islink=islink, isexec=isexec
|
||||
)
|
||||
else:
|
||||
raise error.Abort(_("Unknown file change {}").format(change))
|
||||
|
||||
ctx = memctx(
|
||||
repo,
|
||||
parents,
|
||||
text="",
|
||||
files=list(path2filechange.keys()),
|
||||
filectxfn=getfile,
|
||||
user=None,
|
||||
date=None,
|
||||
)
|
||||
return ctx
|
||||
|
||||
|
||||
def show(ui, repo, csid, **opts):
|
||||
try:
|
||||
snapshot = repo.edenapi.fetchsnapshot(
|
||||
getreponame(repo),
|
||||
{
|
||||
"cs_id": bytes.fromhex(csid),
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
raise error.Abort(_("snapshot doesn't exist"))
|
||||
else:
|
||||
ui.status(_("snapshot: {}\n").format(csid))
|
||||
ctx = _snapshot2ctx(repo, snapshot)
|
||||
displayer = changeset_printer(
|
||||
ui, repo, scmutil.matchall(repo), {"patch": True}, False
|
||||
)
|
||||
displayer.show(ctx)
|
||||
displayer.close()
|
@ -38,7 +38,7 @@ def _fullclean(ui, repo):
|
||||
)
|
||||
|
||||
|
||||
def restore(ui, repo, csid, clean=False):
|
||||
def update(ui, repo, csid, clean=False):
|
||||
ui.status(_("Will restore snapshot {}\n").format(csid), component="snapshot")
|
||||
|
||||
snapshot = repo.edenapi.fetchsnapshot(
|
@ -1954,10 +1954,11 @@ class changeset_printer(object):
|
||||
return
|
||||
|
||||
columns = self._columns
|
||||
self.ui.write(
|
||||
columns["changeset"] % scmutil.formatchangeid(ctx),
|
||||
label=_changesetlabels(ctx),
|
||||
)
|
||||
if changenode:
|
||||
self.ui.write(
|
||||
columns["changeset"] % scmutil.formatchangeid(ctx),
|
||||
label=_changesetlabels(ctx),
|
||||
)
|
||||
|
||||
# branches are shown first before any other names due to backwards
|
||||
# compatibility
|
||||
|
@ -392,6 +392,15 @@ py_class!(pub class client |py| {
|
||||
self.inner(py).clone().downloadfiles_py(py, repo, root, files)
|
||||
}
|
||||
|
||||
/// Download file from given upload token to memory
|
||||
def downloadfiletomemory(
|
||||
&self,
|
||||
repo: String,
|
||||
token: Serde<UploadToken>
|
||||
) -> PyResult<PyBytes> {
|
||||
self.inner(py).clone().downloadfiletomemory_py(py, repo, token)
|
||||
}
|
||||
|
||||
def ephemeralprepare(&self, repo: String)
|
||||
-> PyResult<TStream<anyhow::Result<Serde<EphemeralPrepareResponse>>>>
|
||||
{
|
||||
|
@ -741,6 +741,18 @@ pub trait EdenApiPyExt: EdenApi {
|
||||
.map_pyerr(py)
|
||||
.map(|_| true)
|
||||
}
|
||||
|
||||
fn downloadfiletomemory_py(
|
||||
&self,
|
||||
py: Python,
|
||||
repo: String,
|
||||
token: Serde<UploadToken>,
|
||||
) -> PyResult<PyBytes> {
|
||||
py.allow_threads(|| block_unless_interrupted(self.download_file(repo.clone(), token.0)))
|
||||
.map_pyerr(py)?
|
||||
.map_pyerr(py)
|
||||
.map(|data| PyBytes::new(py, &data))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EdenApi + ?Sized> EdenApiPyExt for T {}
|
||||
|
@ -1627,13 +1627,11 @@ sh % "hg log -r 'null:null'" == r"""
|
||||
# clean:
|
||||
|
||||
sh % "hg log -r 'wdir()' --debug" == r"""
|
||||
commit: ffffffffffffffffffffffffffffffffffffffff
|
||||
phase: draft
|
||||
user: test
|
||||
date: Thu Jan 01 00:00:00 1970 +0000
|
||||
extra: branch=default"""
|
||||
sh % "hg log -r 'wdir()' -p --stat" == r"""
|
||||
commit: ffffffffffff
|
||||
user: test
|
||||
date: Thu Jan 01 00:00:00 1970 +0000"""
|
||||
|
||||
@ -1649,13 +1647,11 @@ sh % "hg status" == r"""
|
||||
R .d6/f1"""
|
||||
|
||||
sh % "hg log -r 'wdir()'" == r"""
|
||||
commit: ffffffffffff
|
||||
user: test
|
||||
date: Thu Jan 01 00:00:00 1970 +0000"""
|
||||
sh % "hg log -r 'wdir()' -q" == "ffffffffffff"
|
||||
|
||||
sh % "hg log -r 'wdir()' --debug" == r"""
|
||||
commit: ffffffffffffffffffffffffffffffffffffffff
|
||||
phase: draft
|
||||
user: test
|
||||
date: Thu Jan 01 00:00:00 1970 +0000
|
||||
@ -1664,7 +1660,6 @@ sh % "hg log -r 'wdir()' --debug" == r"""
|
||||
files-: .d6/f1
|
||||
extra: branch=default"""
|
||||
sh % "hg log -r 'wdir()' -p --stat --git" == r"""
|
||||
commit: ffffffffffff
|
||||
user: test
|
||||
date: Thu Jan 01 00:00:00 1970 +0000
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user