sapling/eden/scm/edenscm/hgext/lfs/pointer.py
Mark Thomas 82715fd2ea py3: iter{keys,values,items} -> pycompat.iter{keys,values,items}
Reviewed By: quark-zju

Differential Revision: D19608323

fbshipit-source-id: dd186ef16d6422a56af41fcaa850d9838ae9a240
2020-01-28 16:27:28 -08:00

83 lines
2.7 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.
# pointer.py - Git-LFS pointer serialization
from __future__ import absolute_import
import re
from edenscm.mercurial import error, pycompat
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(pycompat.iteritems(self.validate()), 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 pycompat.iteritems(self):
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 pycompat.iteritems(self):
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