git.py: introduce Blob abstraction

Some blob representations (such as embedded images) require raw blob
content, however, the 'blob' view is unconditionally handed cooked
(utf8-encoded) content, thus representations which need raw content are
forced to reload the blob in raw form, which is ugly and expensive (due
to shelling out to git-cat-file a second time).

The ultimate goal is to eliminate the wasteful blob reloading when raw
content is needed. As a first step, introduce a Blob abstraction to be
returned by Repo.blob() rather than the cooked content. A subsequent
change will flesh out Blob, allowing it to return raw or cooked content
on demand without the client having to specify one or the other when
invoking Repo.blob().

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Alberto Bertogli <albertito@blitiri.com.ar>
This commit is contained in:
Eric Sunshine 2015-01-13 04:57:09 -05:00 committed by Alberto Bertogli
parent 6b83e32bc1
commit 0ba89d75e6
3 changed files with 16 additions and 7 deletions

13
git.py

@ -340,7 +340,7 @@ class Repo:
return Tree(self, ref) return Tree(self, ref)
def blob(self, path, ref = None, raw = False): def blob(self, path, ref = None, raw = False):
"""Returns the contents of the given path.""" """Returns a Blob instance for the given path."""
if not ref: if not ref:
ref = self.branch ref = self.branch
cmd = self.cmd('cat-file') cmd = self.cmd('cat-file')
@ -356,7 +356,7 @@ class Repo:
if not head or head.strip().endswith('missing'): if not head or head.strip().endswith('missing'):
return None return None
return out.read() return Blob(out.read(), raw)
def last_commit_timestamp(self): def last_commit_timestamp(self):
"""Return the timestamp of the last commit.""" """Return the timestamp of the last commit."""
@ -555,3 +555,12 @@ class Tree:
# manipulate otherwise. # manipulate otherwise.
yield otype, smstr(name), size yield otype, smstr(name), size
class Blob:
"""A git blob."""
def __init__(self, content, raw):
if raw:
self.raw_content = content
else:
self.utf8_content = content

@ -107,5 +107,5 @@ def embed_image_blob(repo, dirname, fname):
raw_blob = repo.blob(dirname + fname, raw = True) raw_blob = repo.blob(dirname + fname, raw = True)
return '<img style="max-width:100%;" src="data:{0};base64,{1}" />'.format( \ return '<img style="max-width:100%;" src="data:{0};base64,{1}" />'.format( \
mimetype, base64.b64encode(raw_blob)) mimetype, base64.b64encode(raw_blob.raw_content))

@ -42,12 +42,12 @@
% if can_embed_image(repo, fname.unicode): % if can_embed_image(repo, fname.unicode):
{{!embed_image_blob(repo, dirname.raw, fname.raw)}} {{!embed_image_blob(repo, dirname.raw, fname.raw)}}
% elif can_markdown(repo, fname.unicode): % elif can_markdown(repo, fname.unicode):
{{!markdown_blob(blob)}} {{!markdown_blob(blob.utf8_content)}}
% elif can_colorize(blob): % elif can_colorize(blob.utf8_content):
{{!colorize_blob(fname.unicode, blob)}} {{!colorize_blob(fname.unicode, blob.utf8_content)}}
% else: % else:
<pre class="blob-body"> <pre class="blob-body">
{{blob}} {{blob.utf8_content}}
</pre> </pre>
% end % end