Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Use git cat-file --batch, to avoid repeated fork+exec

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
  • Loading branch information...
commit 0283ffb60178078a2d2d9a83137c83cdd092cc4c 1 parent aa80f45
Anders Kaseorg authored October 20, 2011

Showing 1 changed file with 29 additions and 3 deletions. Show diff stats Hide diff stats

  1. 32  tracext/git/PyGIT.py
32  tracext/git/PyGIT.py
@@ -67,7 +67,12 @@ def __execute(self, git_cmd, *cmd_args):
67 67
 
68 68
         return stdout_data
69 69
 
  70
+    def cat_file_batch(self):
  71
+        return self.__pipe('cat-file', '--batch', stdin=PIPE, stdout=PIPE)
  72
+
70 73
     def __getattr__(self, name):
  74
+        if name[0] == '_' or name in ['cat_file_batch']:
  75
+            raise AttributeError, name
71 76
         return partial(self.__execute, name.replace('_','-'))
72 77
 
73 78
     __is_sha_pat = re.compile(r'[0-9A-Fa-f]*$')
@@ -256,6 +261,13 @@ def __init__(self, git_dir, log, git_bin='git', git_fs_encoding=None):
256 261
         self.__commit_msg_cache = SizedDict(200)
257 262
         self.__commit_msg_lock = Lock()
258 263
 
  264
+        self.__cat_file_pipe = None
  265
+
  266
+    def __del__(self):
  267
+        if self.__cat_file_pipe is not None:
  268
+            self.__cat_file_pipe.stdin.close()
  269
+            self.__cat_file_pipe.wait()
  270
+
259 271
     #
260 272
     # cache handling
261 273
     #
@@ -475,6 +487,20 @@ def head(self):
475 487
         "get current HEAD commit id"
476 488
         return self.verifyrev("HEAD")
477 489
 
  490
+    def cat_file(self, kind, sha):
  491
+        if self.__cat_file_pipe is None:
  492
+            self.__cat_file_pipe = self.repo.cat_file_batch()
  493
+
  494
+        self.__cat_file_pipe.stdin.write(sha + '\n')
  495
+        self.__cat_file_pipe.stdin.flush()
  496
+        _sha, _type, _size = self.__cat_file_pipe.stdout.readline().split()
  497
+
  498
+        if _type != kind:
  499
+            raise TracError("internal error (got unexpected object kind '%s')" % k)
  500
+
  501
+        size = int(_size)
  502
+        return self.__cat_file_pipe.stdout.read(size + 1)[:size]
  503
+
478 504
     def verifyrev(self, rev):
479 505
         "verify/lookup given revision object and return a sha id or None if lookup failed"
480 506
         rev = str(rev)
@@ -496,7 +522,7 @@ def verifyrev(self, rev):
496 522
             return rc
497 523
 
498 524
         if rc in _rev_cache.tag_set:
499  
-            sha = self.repo.cat_file("tag", rc).split(None, 2)[:2]
  525
+            sha = self.cat_file("tag", rc).split(None, 2)[:2]
500 526
             if sha[0] != 'object':
501 527
                 self.logger.debug("unexpected result from 'git-cat-file tag %s'" % rc)
502 528
                 return None
@@ -606,7 +632,7 @@ def read_commit(self, commit_id):
606 632
                 return result[0], dict(result[1])
607 633
 
608 634
             # cache miss
609  
-            raw = self.repo.cat_file("commit", commit_id)
  635
+            raw = self.cat_file("commit", commit_id)
610 636
             raw = unicode(raw, self.get_commit_encoding(), 'replace')
611 637
             lines = raw.splitlines()
612 638
 
@@ -627,7 +653,7 @@ def read_commit(self, commit_id):
627 653
             return result[0], dict(result[1])
628 654
 
629 655
     def get_file(self, sha):
630  
-        return cStringIO.StringIO(self.repo.cat_file("blob", str(sha)))
  656
+        return cStringIO.StringIO(self.cat_file("blob", str(sha)))
631 657
 
632 658
     def get_obj_size(self, sha):
633 659
         sha = str(sha)

0 notes on commit 0283ffb

Please sign in to comment.
Something went wrong with that request. Please try again.