mirror of
https://github.com/facebook/sapling.git
synced 2024-10-12 09:48:05 +03:00
9dc21f8d0b
Summary: D13853115 adds `edenscm/` to `sys.path` and code still uses `import mercurial`. That has nasty problems if both `import mercurial` and `import edenscm.mercurial` are used, because Python would think `mercurial.foo` and `edenscm.mercurial.foo` are different modules so code like `try: ... except mercurial.error.Foo: ...`, or `isinstance(x, mercurial.foo.Bar)` would fail to handle the `edenscm.mercurial` version. There are also some module-level states (ex. `extensions._extensions`) that would cause trouble if they have multiple versions in a single process. Change imports to use the `edenscm` so ideally the `mercurial` is no longer imported at all. Add checks in extensions.py to catch unexpected extensions importing modules from the old (wrong) locations when running tests. Reviewed By: phillco Differential Revision: D13868981 fbshipit-source-id: f4e2513766957fd81d85407994f7521a08e4de48
83 lines
2.7 KiB
Python
83 lines
2.7 KiB
Python
# pointer.py - Git-LFS pointer serialization
|
|
#
|
|
# Copyright 2017 Facebook, Inc.
|
|
#
|
|
# This software may be used and distributed according to the terms of the
|
|
# GNU General Public License version 2 or any later version.
|
|
|
|
from __future__ import absolute_import
|
|
|
|
import re
|
|
|
|
from edenscm.mercurial import error
|
|
from edenscm.mercurial.i18n import _
|
|
|
|
|
|
class InvalidPointer(error.RevlogError):
|
|
pass
|
|
|
|
|
|
class gitlfspointer(dict):
|
|
VERSION = "https://git-lfs.github.com/spec/v1"
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self["version"] = self.VERSION
|
|
super(gitlfspointer, self).__init__(*args, **kwargs)
|
|
|
|
@classmethod
|
|
def deserialize(cls, text):
|
|
try:
|
|
return cls(l.split(" ", 1) for l in text.splitlines()).validate()
|
|
except ValueError: # l.split returns 1 item instead of 2
|
|
raise InvalidPointer(_("cannot parse git-lfs text: %r") % text)
|
|
|
|
def serialize(self):
|
|
sortkeyfunc = lambda x: (x[0] != "version", x)
|
|
items = sorted(self.validate().iteritems(), key=sortkeyfunc)
|
|
return "".join("%s %s\n" % (k, v) for k, v in items)
|
|
|
|
def oid(self):
|
|
return self["oid"].split(":")[-1]
|
|
|
|
def size(self):
|
|
return int(self["size"])
|
|
|
|
def hgmeta(self):
|
|
"""Translate LFS metadata to hg filelog metadata dictionary"""
|
|
hgmeta = {}
|
|
for k, v in self.iteritems():
|
|
if k.startswith("x-hg-"):
|
|
name = k[len("x-hg-") :]
|
|
hgmeta[name] = v
|
|
return hgmeta
|
|
|
|
# regular expressions used by _validate
|
|
# see https://github.com/git-lfs/git-lfs/blob/master/docs/spec.md
|
|
_keyre = re.compile(r"\A[a-z0-9.-]+\Z")
|
|
_valuere = re.compile(r"\A[^\n]*\Z")
|
|
_requiredre = {
|
|
"size": re.compile(r"\A[0-9]+\Z"),
|
|
"oid": re.compile(r"\Asha256:[0-9a-f]{64}\Z"),
|
|
"version": re.compile(r"\A%s\Z" % re.escape(VERSION)),
|
|
}
|
|
|
|
def validate(self):
|
|
"""raise InvalidPointer on error. return self if there is no error"""
|
|
requiredcount = 0
|
|
for k, v in self.iteritems():
|
|
if k in self._requiredre:
|
|
if not self._requiredre[k].match(v):
|
|
raise InvalidPointer(_("unexpected value: %s=%r") % (k, v))
|
|
requiredcount += 1
|
|
elif not self._keyre.match(k):
|
|
raise InvalidPointer(_("unexpected key: %s") % k)
|
|
if not self._valuere.match(v):
|
|
raise InvalidPointer(_("unexpected value: %s=%r") % (k, v))
|
|
if len(self._requiredre) != requiredcount:
|
|
miss = sorted(set(self._requiredre.keys()).difference(self.keys()))
|
|
raise InvalidPointer(_("missed keys: %s") % ", ".join(miss))
|
|
return self
|
|
|
|
|
|
deserialize = gitlfspointer.deserialize
|