1
1
# objects.py -- Access to base git objects
2
2
# Copyright (C) 2007 James Westby <jw+debian@jameswestby.net>
3
# Copyright (C) 2008-2009 Jelmer Vernooij <jelmer@samba.org>
3
# Copyright (C) 2008-2013 Jelmer Vernooij <jelmer@samba.org>
5
5
# This program is free software; you can redistribute it and/or
6
6
# modify it under the terms of the GNU General Public License
291
291
self._deserialize(self._chunked_text)
292
292
self._needs_parsing = False
294
def set_raw_string(self, text):
294
def set_raw_string(self, text, sha=None):
295
295
"""Set the contents of this object from a serialized string."""
296
296
if type(text) != str:
297
297
raise TypeError(text)
298
self.set_raw_chunks([text])
298
self.set_raw_chunks([text], sha)
300
def set_raw_chunks(self, chunks):
300
def set_raw_chunks(self, chunks, sha=None):
301
301
"""Set the contents of this object from a list of chunks."""
302
302
self._chunked_text = chunks
303
303
self._deserialize(chunks)
307
self._sha = FixedSha(sha)
305
308
self._needs_parsing = False
306
309
self._needs_serialization = False
403
406
raise ObjectFormatException("invalid object header")
406
def from_raw_string(type_num, string):
409
def from_raw_string(type_num, string, sha=None):
407
410
"""Creates an object of the indicated type from the raw string given.
409
412
:param type_num: The numeric type of the object.
410
413
:param string: The raw uncompressed contents.
414
:param sha: Optional known sha for the object
412
416
obj = object_class(type_num)()
413
obj.set_raw_string(string)
417
obj.set_raw_string(string, sha)
417
def from_raw_chunks(type_num, chunks):
421
def from_raw_chunks(type_num, chunks, sha=None):
418
422
"""Creates an object of the indicated type from the raw chunks given.
420
424
:param type_num: The numeric type of the object.
421
425
:param chunks: An iterable of the raw uncompressed contents.
426
:param sha: Optional known sha for the object
423
428
obj = object_class(type_num)()
424
obj.set_raw_chunks(chunks)
429
obj.set_raw_chunks(chunks, sha)
579
584
super(Blob, self).check()
582
def _parse_tag_or_commit(text):
583
"""Parse tag or commit text.
587
def _parse_message(chunks):
588
"""Parse a message with a list of fields and a body.
585
:param text: the raw text of the tag or commit object.
590
:param chunks: the raw chunks of the tag or commit object.
586
591
:return: iterator of tuples of (field, value), one per header line, in the
587
592
order read from the text, possibly including duplicates. Includes a
588
593
field named None for the freeform tag/commit text.
595
f = StringIO("".join(chunks))
649
649
check_identity(self._tagger, "invalid tagger")
652
for field, _ in parse_tag("".join(self._chunked_text)):
652
for field, _ in _parse_message(self._chunked_text):
653
653
if field == _OBJECT_HEADER and last is not None:
654
654
raise ObjectFormatException("unexpected object")
655
655
elif field == _TYPE_HEADER and last != _OBJECT_HEADER:
680
680
def _deserialize(self, chunks):
681
681
"""Grab the metadata attached to the tag"""
682
682
self._tagger = None
683
for field, value in parse_tag("".join(chunks)):
683
for field, value in _parse_message(chunks):
684
684
if field == _OBJECT_HEADER:
685
685
self._object_sha = value
686
686
elif field == _TYPE_HEADER:
1035
1035
return '%c%02d%02d' % (sign, offset / 3600, (offset / 60) % 60)
1038
def parse_commit(text):
1039
return _parse_tag_or_commit(text)
1038
def parse_commit(chunks):
1039
"""Parse a commit object from chunks.
1041
:param chunks: Chunks to parse
1042
:return: Tuple of (tree, parents, author_info, commit_info,
1043
encoding, mergetag, message, extra)
1048
author_info = (None, None, (None, None))
1049
commit_info = (None, None, (None, None))
1054
for field, value in _parse_message(chunks):
1055
if field == _TREE_HEADER:
1057
elif field == _PARENT_HEADER:
1058
parents.append(value)
1059
elif field == _AUTHOR_HEADER:
1060
author, timetext, timezonetext = value.rsplit(" ", 2)
1061
author_time = int(timetext)
1062
author_info = (author, author_time, parse_timezone(timezonetext))
1063
elif field == _COMMITTER_HEADER:
1064
committer, timetext, timezonetext = value.rsplit(" ", 2)
1065
commit_time = int(timetext)
1066
commit_info = (committer, commit_time, parse_timezone(timezonetext))
1067
elif field == _ENCODING_HEADER:
1069
elif field == _MERGETAG_HEADER:
1070
mergetag.append(Tag.from_string(value + "\n"))
1074
extra.append((field, value))
1075
return (tree, parents, author_info, commit_info, encoding, mergetag,
1042
1079
class Commit(ShaFile):
1070
1107
def _deserialize(self, chunks):
1074
for field, value in parse_commit(''.join(chunks)):
1075
if field == _TREE_HEADER:
1077
elif field == _PARENT_HEADER:
1078
self._parents.append(value)
1079
elif field == _AUTHOR_HEADER:
1080
self._author, timetext, timezonetext = value.rsplit(" ", 2)
1081
self._author_time = int(timetext)
1082
self._author_timezone, self._author_timezone_neg_utc =\
1083
parse_timezone(timezonetext)
1084
elif field == _COMMITTER_HEADER:
1085
self._committer, timetext, timezonetext = value.rsplit(" ", 2)
1086
self._commit_time = int(timetext)
1087
self._commit_timezone, self._commit_timezone_neg_utc =\
1088
parse_timezone(timezonetext)
1089
elif field == _ENCODING_HEADER:
1090
self._encoding = value
1092
self._message = value
1093
elif field == _MERGETAG_HEADER:
1094
self._mergetag.append(Tag.from_string(value + "\n"))
1096
self._extra.append((field, value))
1108
(self._tree, self._parents, author_info, commit_info, self._encoding,
1109
self._mergetag, self._message, self._extra) = \
1110
parse_commit(chunks)
1111
(self._author, self._author_time, (self._author_timezone,
1112
self._author_timezone_neg_utc)) = author_info
1113
(self._committer, self._commit_time, (self._commit_timezone,
1114
self._commit_timezone_neg_utc)) = commit_info
1098
1116
def check(self):
1099
1117
"""Check this object for internal consistency.
1114
1132
check_identity(self._committer, "invalid committer")
1117
for field, _ in parse_commit("".join(self._chunked_text)):
1135
for field, _ in _parse_message(self._chunked_text):
1118
1136
if field == _TREE_HEADER and last is not None:
1119
1137
raise ObjectFormatException("unexpected tree")
1120
1138
elif field == _PARENT_HEADER and last not in (_PARENT_HEADER,