21 class InvalidPointer(error.StorageError): |
21 class InvalidPointer(error.StorageError): |
22 pass |
22 pass |
23 |
23 |
24 |
24 |
25 class gitlfspointer(dict): |
25 class gitlfspointer(dict): |
26 VERSION = 'https://git-lfs.github.com/spec/v1' |
26 VERSION = b'https://git-lfs.github.com/spec/v1' |
27 |
27 |
28 def __init__(self, *args, **kwargs): |
28 def __init__(self, *args, **kwargs): |
29 self['version'] = self.VERSION |
29 self[b'version'] = self.VERSION |
30 super(gitlfspointer, self).__init__(*args) |
30 super(gitlfspointer, self).__init__(*args) |
31 self.update(pycompat.byteskwargs(kwargs)) |
31 self.update(pycompat.byteskwargs(kwargs)) |
32 |
32 |
33 @classmethod |
33 @classmethod |
34 def deserialize(cls, text): |
34 def deserialize(cls, text): |
35 try: |
35 try: |
36 return cls(l.split(' ', 1) for l in text.splitlines()).validate() |
36 return cls(l.split(b' ', 1) for l in text.splitlines()).validate() |
37 except ValueError: # l.split returns 1 item instead of 2 |
37 except ValueError: # l.split returns 1 item instead of 2 |
38 raise InvalidPointer( |
38 raise InvalidPointer( |
39 _('cannot parse git-lfs text: %s') % stringutil.pprint(text) |
39 _(b'cannot parse git-lfs text: %s') % stringutil.pprint(text) |
40 ) |
40 ) |
41 |
41 |
42 def serialize(self): |
42 def serialize(self): |
43 sortkeyfunc = lambda x: (x[0] != 'version', x) |
43 sortkeyfunc = lambda x: (x[0] != b'version', x) |
44 items = sorted(self.validate().iteritems(), key=sortkeyfunc) |
44 items = sorted(self.validate().iteritems(), key=sortkeyfunc) |
45 return ''.join('%s %s\n' % (k, v) for k, v in items) |
45 return b''.join(b'%s %s\n' % (k, v) for k, v in items) |
46 |
46 |
47 def oid(self): |
47 def oid(self): |
48 return self['oid'].split(':')[-1] |
48 return self[b'oid'].split(b':')[-1] |
49 |
49 |
50 def size(self): |
50 def size(self): |
51 return int(self['size']) |
51 return int(self[b'size']) |
52 |
52 |
53 # regular expressions used by _validate |
53 # regular expressions used by _validate |
54 # see https://github.com/git-lfs/git-lfs/blob/master/docs/spec.md |
54 # see https://github.com/git-lfs/git-lfs/blob/master/docs/spec.md |
55 _keyre = re.compile(br'\A[a-z0-9.-]+\Z') |
55 _keyre = re.compile(br'\A[a-z0-9.-]+\Z') |
56 _valuere = re.compile(br'\A[^\n]*\Z') |
56 _valuere = re.compile(br'\A[^\n]*\Z') |
57 _requiredre = { |
57 _requiredre = { |
58 'size': re.compile(br'\A[0-9]+\Z'), |
58 b'size': re.compile(br'\A[0-9]+\Z'), |
59 'oid': re.compile(br'\Asha256:[0-9a-f]{64}\Z'), |
59 b'oid': re.compile(br'\Asha256:[0-9a-f]{64}\Z'), |
60 'version': re.compile(br'\A%s\Z' % stringutil.reescape(VERSION)), |
60 b'version': re.compile(br'\A%s\Z' % stringutil.reescape(VERSION)), |
61 } |
61 } |
62 |
62 |
63 def validate(self): |
63 def validate(self): |
64 """raise InvalidPointer on error. return self if there is no error""" |
64 """raise InvalidPointer on error. return self if there is no error""" |
65 requiredcount = 0 |
65 requiredcount = 0 |
66 for k, v in self.iteritems(): |
66 for k, v in self.iteritems(): |
67 if k in self._requiredre: |
67 if k in self._requiredre: |
68 if not self._requiredre[k].match(v): |
68 if not self._requiredre[k].match(v): |
69 raise InvalidPointer( |
69 raise InvalidPointer( |
70 _('unexpected lfs pointer value: %s=%s') |
70 _(b'unexpected lfs pointer value: %s=%s') |
71 % (k, stringutil.pprint(v)) |
71 % (k, stringutil.pprint(v)) |
72 ) |
72 ) |
73 requiredcount += 1 |
73 requiredcount += 1 |
74 elif not self._keyre.match(k): |
74 elif not self._keyre.match(k): |
75 raise InvalidPointer(_('unexpected lfs pointer key: %s') % k) |
75 raise InvalidPointer(_(b'unexpected lfs pointer key: %s') % k) |
76 if not self._valuere.match(v): |
76 if not self._valuere.match(v): |
77 raise InvalidPointer( |
77 raise InvalidPointer( |
78 _('unexpected lfs pointer value: %s=%s') |
78 _(b'unexpected lfs pointer value: %s=%s') |
79 % (k, stringutil.pprint(v)) |
79 % (k, stringutil.pprint(v)) |
80 ) |
80 ) |
81 if len(self._requiredre) != requiredcount: |
81 if len(self._requiredre) != requiredcount: |
82 miss = sorted(set(self._requiredre.keys()).difference(self.keys())) |
82 miss = sorted(set(self._requiredre.keys()).difference(self.keys())) |
83 raise InvalidPointer( |
83 raise InvalidPointer( |
84 _('missing lfs pointer keys: %s') % ', '.join(miss) |
84 _(b'missing lfs pointer keys: %s') % b', '.join(miss) |
85 ) |
85 ) |
86 return self |
86 return self |
87 |
87 |
88 |
88 |
89 deserialize = gitlfspointer.deserialize |
89 deserialize = gitlfspointer.deserialize |