/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to dulwich/objects.py

  • Committer: Jelmer Vernooij
  • Date: 2009-01-14 18:24:38 UTC
  • mto: (0.222.3 dulwich)
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@samba.org-20090114182438-c0tn5eczyupi4ztn
Fix download url, add version number.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# objects.py -- Acces to base git objects
2
2
# Copyright (C) 2007 James Westby <jw+debian@jameswestby.net>
 
3
# Copyright (C) 2008 Jelmer Vernooij <jelmer@samba.org>
3
4
# The header parsing code is based on that from git itself, which is
4
5
# Copyright (C) 2005 Linus Torvalds
5
6
# and licensed under v2 of the GPL.
36
37
PARENT_ID = "parent"
37
38
AUTHOR_ID = "author"
38
39
COMMITTER_ID = "committer"
 
40
OBJECT_ID = "object"
 
41
TYPE_ID = "type"
 
42
TAGGER_ID = "tagger"
39
43
 
40
44
def _decompress(string):
41
45
    dcomp = zlib.decompressobj()
52
56
         len(hexsha)
53
57
  return hexsha
54
58
 
 
59
def hex_to_sha(hex):
 
60
  """Takes a hex sha and returns a binary sha"""
 
61
  sha = ''
 
62
  for i in range(0, len(hex), 2):
 
63
    sha += chr(int(hex[i:i+2], 16))
 
64
  assert len(sha) == 20, "Incorrent length of sha1: %d" % len(sha)
 
65
  return sha
55
66
 
56
67
class ShaFile(object):
57
68
  """A git SHA file."""
178
189
  """A Git Blob object."""
179
190
 
180
191
  _type = BLOB_ID
 
192
  _num_type = 3
181
193
 
182
194
  @property
183
195
  def data(self):
218
230
    shafile._text = string
219
231
    return shafile
220
232
 
 
233
  def _parse_text(self):
 
234
    """Grab the metadata attached to the tag"""
 
235
    text = self._text
 
236
    count = 0
 
237
    assert text.startswith(OBJECT_ID), "Invalid tag object, " \
 
238
         "must start with %s" % OBJECT_ID
 
239
    count += len(OBJECT_ID)
 
240
    assert text[count] == ' ', "Invalid tag object, " \
 
241
         "%s must be followed by space not %s" % (OBJECT_ID, text[count])
 
242
    count += 1
 
243
    self._object_sha = text[count:count+40]
 
244
    count += 40
 
245
    assert text[count] == '\n', "Invalid tag object, " \
 
246
         "%s sha must be followed by newline" % OBJECT_ID
 
247
    count += 1
 
248
    assert text[count:].startswith(TYPE_ID), "Invalid tag object, " \
 
249
         "%s sha must be followed by %s" % (OBJECT_ID, TYPE_ID)
 
250
    count += len(TYPE_ID)
 
251
    assert text[count] == ' ', "Invalid tag object, " \
 
252
        "%s must be followed by space not %s" % (TAG_ID, text[count])
 
253
    count += 1
 
254
    self._object_type = ""
 
255
    while text[count] != '\n':
 
256
        self._object_type += text[count]
 
257
        count += 1
 
258
    count += 1
 
259
    assert self._object_type in (COMMIT_ID, BLOB_ID, TREE_ID, TAG_ID), "Invalid tag object, " \
 
260
        "unexpected object type %s" % self._object_type
 
261
    self._object_type = type_map[self._object_type]
 
262
 
 
263
    assert text[count:].startswith(TAG_ID), "Invalid tag object, " \
 
264
        "object type must be followed by %s" % (TAG_ID)
 
265
    count += len(TAG_ID)
 
266
    assert text[count] == ' ', "Invalid tag object, " \
 
267
        "%s must be followed by space not %s" % (TAG_ID, text[count])
 
268
    count += 1
 
269
    self._name = ""
 
270
    while text[count] != '\n':
 
271
        self._name += text[count]
 
272
        count += 1
 
273
    count += 1
 
274
 
 
275
    assert text[count:].startswith(TAGGER_ID), "Invalid tag object, " \
 
276
        "%s must be followed by %s" % (TAG_ID, TAGGER_ID)
 
277
    count += len(TAGGER_ID)
 
278
    assert text[count] == ' ', "Invalid tag object, " \
 
279
        "%s must be followed by space not %s" % (TAGGER_ID, text[count])
 
280
    count += 1
 
281
    self._tagger = ""
 
282
    while text[count] != '>':
 
283
        assert text[count] != '\n', "Malformed tagger information"
 
284
        self._tagger += text[count]
 
285
        count += 1
 
286
    self._tagger += text[count]
 
287
    count += 1
 
288
    assert text[count] == ' ', "Invalid tag object, " \
 
289
        "tagger information must be followed by space not %s" % text[count]
 
290
    count += 1
 
291
    self._tag_time = int(text[count:count+10])
 
292
    while text[count] != '\n':
 
293
        count += 1
 
294
    count += 1
 
295
    assert text[count] == '\n', "There must be a new line after the headers"
 
296
    count += 1
 
297
    self._message = text[count:]
 
298
 
 
299
  @property
 
300
  def object(self):
 
301
    """Returns the object pointed by this tag, represented as a tuple(type, sha)"""
 
302
    return (self._object_type, self._object_sha)
 
303
 
 
304
  @property
 
305
  def name(self):
 
306
    """Returns the name of this tag"""
 
307
    return self._name
 
308
 
 
309
  @property
 
310
  def tagger(self):
 
311
    """Returns the name of the person who created this tag"""
 
312
    return self._tagger
 
313
 
 
314
  @property
 
315
  def tag_time(self):
 
316
    """Returns the creation timestamp of the tag.
 
317
 
 
318
    Returns it as the number of seconds since the epoch"""
 
319
    return self._tag_time
 
320
 
 
321
  @property
 
322
  def message(self):
 
323
    """Returns the message attached to this tag"""
 
324
    return self._message
 
325
 
221
326
 
222
327
class Tree(ShaFile):
223
328
  """A Git tree object"""
224
329
 
225
330
  _type = TREE_ID
 
331
  _num_type = 2
 
332
 
 
333
  def __init__(self):
 
334
    self._entries = []
226
335
 
227
336
  @classmethod
228
337
  def from_file(cls, filename):
231
340
      raise NotTreeError(filename)
232
341
    return tree
233
342
 
 
343
  def add(self, mode, name, hexsha):
 
344
    self._entries.append((mode, name, hexsha))
 
345
 
234
346
  def entries(self):
235
347
    """Return a list of tuples describing the tree entries"""
236
348
    return self._entries
237
349
 
238
350
  def _parse_text(self):
239
351
    """Grab the entries in the tree"""
240
 
    self._entries = []
241
352
    count = 0
242
353
    while count < len(self._text):
243
354
      mode = 0
258
369
      chr = self._text[count]
259
370
      sha = self._text[count:count+20]
260
371
      hexsha = sha_to_hex(sha)
261
 
      self._entries.append((mode, name, hexsha))
 
372
      self.add(mode, name, hexsha)
262
373
      count = count + 20
263
374
 
 
375
  def serialize(self):
 
376
    self._text = ""
 
377
    for mode, name, hexsha in self._entries:
 
378
        self._text += "%04o %s\0%s" % (mode, name, hex_to_sha(hexsha))
 
379
 
 
380
 
264
381
class Commit(ShaFile):
265
382
  """A git commit object"""
266
383
 
267
384
  _type = COMMIT_ID
 
385
  _num_type = 1
 
386
 
 
387
  def __init__(self):
 
388
    self._parents = []
268
389
 
269
390
  @classmethod
270
391
  def from_file(cls, filename):
339
460
    # XXX: There can be an encoding field.
340
461
    self._message = text[count:]
341
462
 
 
463
  def serialize(self):
 
464
    self._text = ""
 
465
    self._text += "%s %s\n" % (TREE_ID, self._tree)
 
466
    for p in self._parents:
 
467
      self._text += "%s %s\n" % (PARENT_ID, p)
 
468
    self._text += "%s %s %s +0000\n" % (AUTHOR_ID, self._author, str(self._commit_time))
 
469
    self._text += "%s %s %s +0000\n" % (COMMITTER_ID, self._committer, str(self._commit_time))
 
470
    self._text += "\n" # There must be a new line after the headers
 
471
    self._text += self._message
 
472
 
342
473
  @property
343
474
  def tree(self):
344
475
    """Returns the tree that is the state of this commit"""
372
503
    """
373
504
    return self._commit_time
374
505
 
 
506
 
375
507
type_map = {
376
508
  BLOB_ID : Blob,
377
509
  TREE_ID : Tree,