99import git .stats as stats
1010from git .actor import Actor
1111from tree import Tree
12+ from cStringIO import StringIO
1213import base
1314import utils
1415import time
1516import os
1617
17- class Commit (base .Object , Iterable , diff .Diffable , utils .Traversable ):
18+
19+ class Commit (base .Object , Iterable , diff .Diffable , utils .Traversable , utils .Serializable ):
1820 """
1921 Wraps a git Commit object.
2022
@@ -91,7 +93,8 @@ def __init__(self, repo, sha, tree=None, author=None, authored_date=None, author
9193 self ._set_self_from_args_ (locals ())
9294
9395 if parents is not None :
94- self .parents = tuple ( self .__class__ (repo , p ) for p in parents )
96+ cls = type (self )
97+ self .parents = tuple (cls (repo , p ) for p in parents if not isinstance (p , cls ))
9598 # END for each parent to convert
9699
97100 if self .sha and tree is not None :
@@ -109,20 +112,9 @@ def _set_cache_(self, attr):
109112 We set all values at once.
110113 """
111114 if attr in Commit .__slots__ :
112- # prepare our data lines to match rev-list
113- data_lines = self .data .splitlines ()
114- data_lines .insert (0 , "commit %s" % self .sha )
115- temp = self ._iter_from_process_or_stream (self .repo , iter (data_lines ), False ).next ()
116- self .parents = temp .parents
117- self .tree = temp .tree
118- self .author = temp .author
119- self .authored_date = temp .authored_date
120- self .author_tz_offset = temp .author_tz_offset
121- self .committer = temp .committer
122- self .committed_date = temp .committed_date
123- self .committer_tz_offset = temp .committer_tz_offset
124- self .message = temp .message
125- self .encoding = temp .encoding
115+ # read the data in a chunk, its faster - then provide a file wrapper
116+ hexsha , typename , size , data = self .repo .git .get_object_data (self )
117+ self ._deserialize (StringIO (data ))
126118 else :
127119 super (Commit , self )._set_cache_ (attr )
128120
@@ -260,59 +252,18 @@ def _iter_from_process_or_stream(cls, repo, proc_or_stream, from_rev_list):
260252 iterator returning Commit objects
261253 """
262254 stream = proc_or_stream
263- if not hasattr (stream ,'next ' ):
255+ if not hasattr (stream ,'readline ' ):
264256 stream = proc_or_stream .stdout
265257
266- for line in stream :
267- commit_tokens = line .split ()
258+ while True :
259+ line = stream .readline ()
260+ if not line :
261+ break
262+ commit_tokens = line .split ()
268263 id = commit_tokens [1 ]
269264 assert commit_tokens [0 ] == "commit"
270- tree = stream .next ().split ()[1 ]
271-
272- parents = []
273- next_line = None
274- for parent_line in stream :
275- if not parent_line .startswith ('parent' ):
276- next_line = parent_line
277- break
278- # END abort reading parents
279- parents .append (parent_line .split ()[- 1 ])
280- # END for each parent line
281-
282- author , authored_date , author_tz_offset = utils .parse_actor_and_date (next_line )
283- committer , committed_date , committer_tz_offset = utils .parse_actor_and_date (stream .next ())
284-
285265
286- # empty line
287- encoding = stream .next ()
288- encoding .strip ()
289- if encoding :
290- encoding = encoding [encoding .find (' ' )+ 1 :]
291- # END parse encoding
292-
293- message_lines = list ()
294- if from_rev_list :
295- for msg_line in stream :
296- if not msg_line .startswith (' ' ):
297- # and forget about this empty marker
298- break
299- # END abort message reading
300- # strip leading 4 spaces
301- message_lines .append (msg_line [4 :])
302- # END while there are message lines
303- else :
304- # a stream from our data simply gives us the plain message
305- for msg_line in stream :
306- message_lines .append (msg_line )
307- # END message parsing
308- message = '\n ' .join (message_lines )
309-
310-
311- yield Commit (repo , id , tree ,
312- author , authored_date , author_tz_offset ,
313- committer , committed_date , committer_tz_offset ,
314- message , tuple (parents ),
315- encoding or cls .default_encoding )
266+ yield Commit (repo , id )._deserialize (stream , from_rev_list )
316267 # END for each line in stream
317268
318269
@@ -393,7 +344,7 @@ def create_from_tree(cls, repo, tree, message, parent_commits=None, head=False):
393344
394345 # assume utf8 encoding
395346 enc_section , enc_option = cls .conf_encoding .split ('.' )
396- conf_encoding = cr .get_value (enc_section , enc_option , default_encoding )
347+ conf_encoding = cr .get_value (enc_section , enc_option , cls . default_encoding )
397348
398349 author = Actor (author_name , author_email )
399350 committer = Actor (committer_name , committer_email )
@@ -429,3 +380,61 @@ def __str__(self):
429380 def __repr__ (self ):
430381 return '<git.Commit "%s">' % self .sha
431382
383+ #{ Serializable Implementation
384+
385+ def _serialize (self , stream ):
386+ # for now, this is very inefficient and in fact shouldn't be used like this
387+ return super (Commit , self )._serialize (stream )
388+
389+ def _deserialize (self , stream , from_rev_list = False ):
390+ """:param from_rev_list: if true, the stream format is coming from the rev-list command
391+ Otherwise it is assumed to be a plain data stream from our object"""
392+ self .tree = Tree (self .repo , stream .readline ().split ()[1 ], 0 , '' )
393+
394+ self .parents = list ()
395+ next_line = None
396+ while True :
397+ parent_line = stream .readline ()
398+ if not parent_line .startswith ('parent' ):
399+ next_line = parent_line
400+ break
401+ # END abort reading parents
402+ self .parents .append (type (self )(self .repo , parent_line .split ()[- 1 ]))
403+ # END for each parent line
404+ self .parents = tuple (self .parents )
405+
406+ self .author , self .authored_date , self .author_tz_offset = utils .parse_actor_and_date (next_line )
407+ self .committer , self .committed_date , self .committer_tz_offset = utils .parse_actor_and_date (stream .readline ())
408+
409+
410+ # empty line
411+ self .encoding = self .default_encoding
412+ enc = stream .readline ()
413+ enc .strip ()
414+ if enc :
415+ self .encoding = enc [enc .find (' ' )+ 1 :]
416+ # END parse encoding
417+
418+ message_lines = list ()
419+ if from_rev_list :
420+ while True :
421+ msg_line = stream .readline ()
422+ if not msg_line .startswith (' ' ):
423+ # and forget about this empty marker
424+ # cut the last newline to get rid of the artificial newline added
425+ # by rev-list command. Lets hope its just linux style \n
426+ message_lines [- 1 ] = message_lines [- 1 ][:- 1 ]
427+ break
428+ # END abort message reading
429+ # strip leading 4 spaces
430+ message_lines .append (msg_line [4 :])
431+ # END while there are message lines
432+ self .message = '' .join (message_lines )
433+ else :
434+ # a stream from our data simply gives us the plain message
435+ # The end of our message stream is marked with a newline that we strip
436+ self .message = stream .read ()[:- 1 ]
437+ # END message parsing
438+ return self
439+
440+ #} END serializable implementation
0 commit comments