~vcs-imports/trac/trunk

« back to all changes in this revision

Viewing changes to tracopt/versioncontrol/git/PyGIT.py

  • Committer: jomae
  • Date: 2021-04-14 03:31:17 UTC
  • Revision ID: svn-v4:af82e41b-90c4-0310-8c96-b1721e28e2e2:trunk:17523
1.5.3dev: merge [17522] from 1.4-stable (fix for #13327)

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
import os
19
19
import re
20
20
import subprocess
 
21
import tempfile
21
22
import weakref
22
23
from collections import deque
23
24
from functools import partial
28
29
from trac.util import terminate
29
30
from trac.util.compat import close_fds
30
31
from trac.util.datefmt import time_now
31
 
from trac.util.text import to_unicode
 
32
from trac.util.text import exception_to_unicode, to_unicode
32
33
 
33
34
__all__ = ['GitError', 'GitErrorSha', 'Storage', 'StorageFactory']
34
35
 
705
706
        return self.verifyrev('HEAD')
706
707
 
707
708
    def cat_file(self, kind, sha):
 
709
        return self._cat_file_reader(kind, sha).read()
 
710
 
 
711
    def _cat_file_reader(self, kind, sha):
708
712
        with self.__cat_file_pipe_lock:
709
713
            if self.__cat_file_pipe is None:
710
714
                self.__cat_file_pipe = self.repo.cat_file_batch()
726
730
                                   "kind %r, expected %r)" % (_type, kind))
727
731
 
728
732
                size = int(_size)
729
 
                return self.__cat_file_pipe.stdout.read(size + 1)[:size]
730
 
            except EnvironmentError:
 
733
 
 
734
                # stdout.read() can return fewer bytes than requested,
 
735
                # especially if a pipe buffers because the contents are
 
736
                # larger than 64k.
 
737
                stdout_read = self.__cat_file_pipe.stdout.read
 
738
                if size > 32 * 1024 * 1024:
 
739
                    buf = tempfile.TemporaryFile()
 
740
                else:
 
741
                    buf = io.BytesIO()
 
742
                remaining = size + 1
 
743
                while remaining > 0:
 
744
                    chunk = stdout_read(min(remaining, 65536))
 
745
                    if not chunk:
 
746
                        # No new data, let's abort
 
747
                        raise GitError("internal error (expected to read %d "
 
748
                                       "bytes, but only got %d)" %
 
749
                                       (size + 1, size + 1 - remaining))
 
750
                    remaining -= len(chunk)
 
751
                    buf.write(chunk if remaining > 0 else chunk[:-1])
 
752
 
 
753
                buf.seek(0)
 
754
                return buf
 
755
 
 
756
            except EnvironmentError as e:
731
757
                # There was an error, we should close the pipe to get to a
732
758
                # consistent state (Otherwise it happens that next time we
733
759
                # call cat_file we get payload from previous call)
734
 
                self.logger.debug("closing cat_file pipe")
 
760
                self.logger.warning("closing cat_file pipe: %s",
 
761
                                    exception_to_unicode(e))
735
762
                self._cleanup_proc(self.__cat_file_pipe)
736
763
                self.__cat_file_pipe = None
737
764
 
889
916
 
890
917
    def get_file(self, sha):
891
918
        sha = _rev_b(sha)
892
 
        content = self.cat_file(b'blob', sha)
893
 
        return io.BytesIO(content)
 
919
        return self._cat_file_reader(b'blob', sha)
894
920
 
895
921
    def get_obj_size(self, sha):
896
922
        sha = _rev_b(sha)
897
923
        try:
898
 
            obj_size = int(self.repo.cat_file('-s', sha).strip())
 
924
            obj_size = int(self.repo.cat_file(b'-s', sha).strip())
899
925
        except ValueError:
900
926
            raise GitErrorSha("object '%s' not found" % sha)
901
927
        return obj_size