2022-07-27 05:47:14 +03:00
|
|
|
# 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.
|
|
|
|
|
|
|
|
import bindings
|
|
|
|
|
|
|
|
from . import error, filelog, revlog
|
|
|
|
from .i18n import _
|
|
|
|
from .node import bin, nullid
|
|
|
|
|
|
|
|
EAGEREPO_REQUIREMENT = "eagerepo"
|
|
|
|
|
|
|
|
|
|
|
|
def iseagerepo(repo):
|
|
|
|
return EAGEREPO_REQUIREMENT in repo.storerequirements
|
|
|
|
|
|
|
|
|
|
|
|
def openstore(repo):
|
|
|
|
from .changelog2 import HGCOMMITS_DIR
|
|
|
|
|
|
|
|
path = repo.svfs.join(HGCOMMITS_DIR)
|
|
|
|
return bindings.eagerepo.EagerRepoStore.open(path)
|
|
|
|
|
|
|
|
|
|
|
|
class eagerfilelog(object):
|
|
|
|
"""filelog-like interface for EagerRepoStore"""
|
|
|
|
|
|
|
|
def __init__(self, repo, name):
|
|
|
|
self.store = repo.fileslog.contentstore
|
|
|
|
self.name = name
|
|
|
|
|
|
|
|
def lookup(self, node):
|
|
|
|
assert len(node) == 20
|
|
|
|
return node
|
|
|
|
|
|
|
|
def read(self, node):
|
|
|
|
t = self._get_content(node)
|
|
|
|
# see filelog.read - strip filelog metadata
|
|
|
|
if not t.startswith(b"\1\n"):
|
|
|
|
return t
|
|
|
|
else:
|
|
|
|
s = t.index(b"\1\n", 2)
|
|
|
|
return t[s + 2 :]
|
|
|
|
|
|
|
|
def size(self, node):
|
|
|
|
return len(self.read(node))
|
|
|
|
|
|
|
|
def rev(self, node):
|
|
|
|
# same trick as remotefilelog
|
|
|
|
return node
|
|
|
|
|
|
|
|
def cmp(self, node, text):
|
|
|
|
"""returns True if blob hash is different from text"""
|
|
|
|
# PERF: This does use a fast path avoid read() - a fast path requires
|
|
|
|
# fast path reading p1, p2, which does not exist.
|
|
|
|
return self.read(node) != text
|
|
|
|
|
|
|
|
def renamed(self, node):
|
|
|
|
t = self._get_content(node)
|
|
|
|
if not t.startswith(b"\1\n"):
|
|
|
|
return False
|
|
|
|
m = filelog.parsemeta(t)[0]
|
|
|
|
if m and "copy" in m:
|
|
|
|
return (m["copy"], bin(m["copyrev"]))
|
|
|
|
return False
|
|
|
|
|
|
|
|
def add(self, text, meta, _tr, _linkrev, fparent1, fparent2):
|
|
|
|
# see filelog.add and revlog.addrevision
|
|
|
|
if meta or text.startswith(b"\1\n"):
|
|
|
|
text = filelog.packmeta(meta, text)
|
|
|
|
rawtext = revlog.textwithheader(text, fparent1, fparent2)
|
|
|
|
# SPACE: didn't set the "bases" for candidate delta bases.
|
|
|
|
node = self.store.add_sha1_blob(rawtext)
|
|
|
|
return node
|
|
|
|
|
2022-08-19 20:28:58 +03:00
|
|
|
def flags(self, rev):
|
|
|
|
return 0
|
|
|
|
|
2022-08-08 21:41:01 +03:00
|
|
|
def parents(self, node):
|
|
|
|
if node == nullid:
|
|
|
|
return (nullid, nullid)
|
|
|
|
else:
|
|
|
|
t = self._get_sha1_blob(node)
|
|
|
|
p1 = t[len(nullid) : len(nullid) * 2]
|
|
|
|
p2 = t[: len(nullid)]
|
|
|
|
return (p1, p2)
|
|
|
|
|
debugexportrevlog: command to export a repo to revlog format
Summary:
Now `hg init` can use the "eager repo" format that fully decouples from revlog.
It seems promising to migrate hg's tests off revlog.
However, there is still a revlog dependency in tests: `blobimport` used in
Mononoke tests, and `blobimport` seems having too many features and lacks of
abstraction to be changed confidently.
To continue migrating away from revlog while maintaining Mononoke test
compatibility without O(tests) manual migration, this diff introduces
a `debugexportrevlog` command to export the current repo to the revlog
format that can be read by Mononoke's `blobimport` and upstream hg.
Therefore, the revlog can become just an "export" format (to maintain Mononoke
test compatibility), instead of a "repo" format (to unblock revlog
deprecation).
The code intentionally avoids `revlog.revlog` dependency, by reinventing
revlog in a minimal way - no read, no compression, no delta, no deps on
`revlog.c` or `lz4`, making migrating off revlog easier.
Note the Rust `revlogindex` stays for streaming clone compatibility.
Reviewed By: DurhamG
Differential Revision: D38446492
fbshipit-source-id: 94995bbc0d89e835195e49286e193a8127a314bf
2022-08-16 04:22:28 +03:00
|
|
|
def revision(self, node, raw=True):
|
|
|
|
return self._get_content(node)
|
|
|
|
|
2022-08-08 21:41:01 +03:00
|
|
|
def _get_sha1_blob(self, node):
|
|
|
|
"""get the SHA1 prefixed (sorted([p1, p2])) content"""
|
2022-07-27 05:47:14 +03:00
|
|
|
if node == nullid:
|
|
|
|
return b""
|
|
|
|
t = self.store.get_sha1_blob(node)
|
|
|
|
if t is None:
|
|
|
|
raise error.LookupError(node, self.name, _("no node"))
|
|
|
|
return t
|
2022-08-08 21:41:01 +03:00
|
|
|
|
|
|
|
def _get_content(self, node):
|
|
|
|
"""get the content without hg's parent SHA1 prefix"""
|
|
|
|
if node == nullid:
|
|
|
|
return b""
|
|
|
|
t = self.store.get_content(node)
|
|
|
|
if t is None:
|
|
|
|
raise error.LookupError(node, self.name, _("no node"))
|
|
|
|
return t
|