9
9
import git .stats as stats
10
10
from git .actor import Actor
11
11
from tree import Tree
12
+ from cStringIO import StringIO
12
13
import base
13
14
import utils
14
15
import time
15
16
import os
16
17
17
- class Commit (base .Object , Iterable , diff .Diffable , utils .Traversable ):
18
+
19
+ class Commit (base .Object , Iterable , diff .Diffable , utils .Traversable , utils .Serializable ):
18
20
"""
19
21
Wraps a git Commit object.
20
22
@@ -91,7 +93,8 @@ def __init__(self, repo, sha, tree=None, author=None, authored_date=None, author
91
93
self ._set_self_from_args_ (locals ())
92
94
93
95
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 ))
95
98
# END for each parent to convert
96
99
97
100
if self .sha and tree is not None :
@@ -109,20 +112,9 @@ def _set_cache_(self, attr):
109
112
We set all values at once.
110
113
"""
111
114
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 ))
126
118
else :
127
119
super (Commit , self )._set_cache_ (attr )
128
120
@@ -260,59 +252,18 @@ def _iter_from_process_or_stream(cls, repo, proc_or_stream, from_rev_list):
260
252
iterator returning Commit objects
261
253
"""
262
254
stream = proc_or_stream
263
- if not hasattr (stream ,'next ' ):
255
+ if not hasattr (stream ,'readline ' ):
264
256
stream = proc_or_stream .stdout
265
257
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 ()
268
263
id = commit_tokens [1 ]
269
264
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
-
285
265
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 )
316
267
# END for each line in stream
317
268
318
269
@@ -393,7 +344,7 @@ def create_from_tree(cls, repo, tree, message, parent_commits=None, head=False):
393
344
394
345
# assume utf8 encoding
395
346
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 )
397
348
398
349
author = Actor (author_name , author_email )
399
350
committer = Actor (committer_name , committer_email )
@@ -429,3 +380,61 @@ def __str__(self):
429
380
def __repr__ (self ):
430
381
return '<git.Commit "%s">' % self .sha
431
382
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