@@ -34,7 +34,6 @@ class Git(object):
3434 of the command to stdout.
3535 Set its value to 'full' to see details about the returned values.
3636 """
37-
3837 class AutoInterrupt (object ):
3938 """
4039 Kill/Interrupt the stored process instance once this instance goes out of scope. It is
@@ -50,7 +49,7 @@ def __del__(self):
5049 # did the process finish already so we have a return code ?
5150 if self .proc .poll () is not None :
5251 return
53-
52+
5453 # try to kill it
5554 try :
5655 os .kill (self .proc .pid , 2 ) # interrupt signal
@@ -73,6 +72,10 @@ def __init__(self, git_dir=None):
7372 """
7473 super (Git , self ).__init__ ()
7574 self .git_dir = git_dir
75+
76+ # cached command slots
77+ self .cat_file_header = None
78+ self .cat_file_all = None
7679
7780 def __getattr__ (self , name ):
7881 """
@@ -262,3 +265,74 @@ def _call_process(self, method, *args, **kwargs):
262265 call .extend (args )
263266
264267 return self .execute (call , ** _kwargs )
268+
269+ def _parse_object_header (self , header_line ):
270+ """
271+ ``header_line``
272+ <hex_sha> type_string size_as_int
273+
274+ Returns
275+ (type_string, size_as_int)
276+
277+ Raises
278+ ValueError if the header contains indication for an error due to incorrect
279+ input sha
280+ """
281+ tokens = header_line .split ()
282+ if len (tokens ) != 3 :
283+ raise ValueError ( "SHA named %s could not be resolved" % tokens [0 ] )
284+
285+ return (tokens [1 ], int (tokens [2 ]))
286+
287+ def __prepare_ref (self , ref ):
288+ # required for command to separate refs on stdin
289+ refstr = str (ref ) # could be ref-object
290+ if refstr .endswith ("\n " ):
291+ return refstr
292+ return refstr + "\n "
293+
294+ def __get_persistent_cmd (self , attr_name , cmd_name , * args ,** kwargs ):
295+ cur_val = getattr (self , attr_name )
296+ if cur_val is not None :
297+ return cur_val
298+
299+ options = { "istream" : subprocess .PIPE , "as_process" : True }
300+ options .update ( kwargs )
301+
302+ cmd = self ._call_process ( cmd_name , * args , ** options )
303+ setattr (self , attr_name , cmd )
304+ return cmd
305+
306+ def __get_object_header (self , cmd , ref ):
307+ cmd .stdin .write (self .__prepare_ref (ref ))
308+ cmd .stdin .flush ()
309+ return self ._parse_object_header (cmd .stdout .readline ())
310+
311+ def get_object_header (self , ref ):
312+ """
313+ Use this method to quickly examine the type and size of the object behind
314+ the given ref.
315+
316+ NOTE
317+ The method will only suffer from the costs of command invocation
318+ once and reuses the command in subsequent calls.
319+
320+ Return:
321+ (type_string, size_as_int)
322+ """
323+ cmd = self .__get_persistent_cmd ("cat_file_header" , "cat_file" , batch_check = True )
324+ return self .__get_object_header (cmd , ref )
325+
326+ def get_object_data (self , ref ):
327+ """
328+ As get_object_header, but returns object data as well
329+
330+ Return:
331+ (type_string, size_as_int,data_string)
332+ """
333+ cmd = self .__get_persistent_cmd ("cat_file_all" , "cat_file" , batch = True )
334+ typename , size = self .__get_object_header (cmd , ref )
335+ data = cmd .stdout .read (size )
336+ cmd .stdout .read (1 ) # finishing newlines
337+
338+ return (typename , size , data )
0 commit comments