Skip to content

Commit

Permalink
Add git_fs_encoding parameter to Storage and StorageFactory
Browse files Browse the repository at this point in the history
This optional parameter allows to enable on-the-fly en/decoding of
bytestrings (as seen by git) from/to unicode objects (as seen by Trac)
  • Loading branch information
hvr committed Oct 17, 2010
1 parent a891c74 commit 67d05ab
Showing 1 changed file with 52 additions and 9 deletions.
61 changes: 52 additions & 9 deletions tracext/git/PyGIT.py
Expand Up @@ -21,6 +21,7 @@
from subprocess import Popen, PIPE
from operator import itemgetter
import cStringIO
import codecs

__all__ = ["git_version", "GitError", "GitErrorSha", "Storage", "StorageFactory"]

Expand Down Expand Up @@ -120,14 +121,14 @@ class StorageFactory(object):
__dict_nonweak = dict()
__dict_lock = Lock()

def __init__(self, repo, log, weak=True, git_bin='git'):
def __init__(self, repo, log, weak=True, git_bin='git', git_fs_encoding=None):
self.logger = log

with StorageFactory.__dict_lock:
try:
i = StorageFactory.__dict[repo]
except KeyError:
i = Storage(repo, log, git_bin)
i = Storage(repo, log, git_bin, git_fs_encoding)
StorageFactory.__dict[repo] = i

# create or remove additional reference depending on 'weak' argument
Expand Down Expand Up @@ -239,9 +240,38 @@ def try_int(s):
" (tried to execute/parse '%s --version' but got %s)"
% (git_bin, repr(e)))

def __init__(self, git_dir, log, git_bin='git'):
def __init__(self, git_dir, log, git_bin='git', git_fs_encoding=None):
"""
Initialize PyGit.Storage instance
`git_dir`: path to .git folder;
this setting is not affected by the `git_fs_encoding` setting
`log`: logger instance
`git_bin`: path to executable
this setting is not affected by the `git_fs_encoding` setting
`git_fs_encoding`: encoding used for paths stored in git repository;
if `None`, no implicit decoding/encoding to/from
unicode objects is performed, and bytestrings are
returned instead
"""

self.logger = log

if git_fs_encoding is not None:
# validate encoding name
codecs.lookup(git_fs_encoding)

# setup conversion functions
self._fs_to_unicode = lambda s: s.decode(git_fs_encoding)
self._fs_from_unicode = lambda s: s.encode(git_fs_encoding)
else:
# pass bytestrings as-is w/o any conversion
self._fs_to_unicode = self._fs_from_unicode = lambda s: s

# simple sanity checking
__git_file_path = partial(os.path.join, git_dir)
if not all(map(os.path.exists,
Expand All @@ -267,8 +297,6 @@ def __init__(self, git_dir, log, git_bin='git'):
self.__commit_msg_cache = SizedDict(200)
self.__commit_msg_lock = Lock()



def __del__(self):
self.logger.debug("PyGIT.Storage instance %d destructed" % id(self))

Expand Down Expand Up @@ -580,6 +608,9 @@ def get_tags(self):

def ls_tree(self, rev, path=""):
rev = rev and str(rev) or 'HEAD' # paranoia

path = self._fs_from_unicode(path)

if path.startswith('/'):
path = path[1:]

Expand All @@ -596,7 +627,7 @@ def split_ls_tree_line(l):
else:
_size = int(_size)

return _mode, _type, _sha, _size, fname
return _mode, _type, _sha, _size, self._fs_to_unicode(fname)

return [ split_ls_tree_line(e) for e in tree if e ]

Expand Down Expand Up @@ -702,13 +733,16 @@ def sync(self):

def last_change(self, sha, path):
return self.repo.rev_list("--max-count=1",
sha, "--", path).strip() or None
sha, "--",
self._fs_from_unicode(path)).strip() or None

def history(self, sha, path, limit=None):
if limit is None:
limit = -1

tmp = self.repo.rev_list("--max-count=%d" % limit, str(sha), "--", path)
tmp = self.repo.rev_list("--max-count=%d" % limit, str(sha), "--",
self._fs_from_unicode(path))

return [ rev.strip() for rev in tmp.splitlines() ]

def history_timerange(self, start, stop):
Expand All @@ -732,6 +766,8 @@ def rev_is_anchestor_of(self, rev1, rev2):
def blame(self, commit_sha, path):
in_metadata = False

path = self._fs_from_unicode(path)

for line in self.repo.blame("-p", "--", path, str(commit_sha)).splitlines():
assert line
if in_metadata:
Expand All @@ -756,7 +792,7 @@ def diff_tree(self, tree1, tree2, path="", find_renames=False):
# diff-tree returns records with the following structure:
# :<old-mode> <new-mode> <old-sha> <new-sha> <change> NUL <old-path> NUL [ <new-path> NUL ]

path = path.strip("/")
path = self._fs_from_unicode(path).strip("/")
diff_tree_args = ["-z", "-r"]
if find_renames:
diff_tree_args.append("-M")
Expand All @@ -775,11 +811,17 @@ def diff_tree(self, tree1, tree2, path="", find_renames=False):
assert not lines[0].startswith(':')
del lines[0]

# FIXME: the following code is ugly, needs rewrite

chg = None

def __chg_tuple():
if len(chg) == 6:
chg.append(None)
else:
chg[6] = self._fs_to_unicode(chg[6])
chg[5] = self._fs_to_unicode(chg[5])

assert len(chg) == 7
return tuple(chg)

Expand All @@ -793,6 +835,7 @@ def __chg_tuple():
else:
chg.append(line)

# handle left-over chg entry
if chg:
yield __chg_tuple()

Expand Down

0 comments on commit 67d05ab

Please sign in to comment.