• R/O
  • HTTP
  • SSH
  • HTTPS

コミット

タグ
未設定

よく使われているワード(クリックで追加)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

allura


コミットメタ情報

リビジョンeafda896802b38bc49faf895e72db41aaf562b2b (tree)
日時2012-06-13 01:24:08
作者bolkimen <bolkimen@yaho...>
コミッターDave Brondsema

ログメッセージ

[#4126] ticket:41 add code stats

Conflicts:

Allura/allura/templates/repo/file.html

変更サマリ

差分

--- a/Allura/allura/config/app_cfg.py
+++ b/Allura/allura/config/app_cfg.py
@@ -26,7 +26,7 @@ import ew
2626
2727 import allura
2828 # needed for tg.configuration to work
29-from allura.lib import app_globals
29+from allura.lib import app_globals, helpers
3030
3131 log = logging.getLogger(__name__)
3232
@@ -62,6 +62,7 @@ class ForgeConfig(AppConfig):
6262 autoescape=True,
6363 extensions=['jinja2.ext.do', 'jinja2.ext.i18n'])
6464 jinja2_env.install_gettext_translations(pylons.i18n)
65+ jinja2_env.filters['filesizeformat'] = helpers.do_filesizeformat
6566 config['pylons.app_globals'].jinja2_env = jinja2_env
6667 # Jinja's unable to request c's attributes without strict_c
6768 config['pylons.strict_c'] = True
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -18,6 +18,7 @@ from ming.orm import ThreadLocalORMSession, session
1818
1919 import allura.tasks
2020 from allura.lib import security
21+from allura.lib import utils
2122 from allura.lib import helpers as h
2223 from allura.lib import widgets as w
2324 from allura.lib.decorators import require_post
@@ -487,8 +488,10 @@ class FileBrowser(BaseController):
487488 else:
488489 force_display = 'force' in kw
489490 context = self._blob.context()
491+ stats = utils.generate_code_stats(self._blob)
490492 return dict(
491493 blob=self._blob,
494+ stats=stats,
492495 prev=context.get('prev', None),
493496 next=context.get('next', None),
494497 force_display=force_display
--- a/Allura/allura/lib/utils.py
+++ b/Allura/allura/lib/utils.py
@@ -8,6 +8,7 @@ import os.path
88 import datetime
99 import random
1010 import mimetypes
11+import re
1112 from itertools import groupby
1213
1314 import tg
@@ -410,3 +411,15 @@ class LineAnchorCodeHtmlFormatter(HtmlFormatter):
410411 yield (tup[0], '<div id="l%s" class="code_block">%s</div>' % (num, tup[1]))
411412 num += 1
412413 yield 0, '</pre>'
414+
415+def generate_code_stats(blob):
416+ stats = {'line_count': 0,
417+ 'code_size': 0,
418+ 'data_line_count': 0}
419+ code = blob.text
420+ lines = code.split('\n')
421+ stats['code_size'] = blob.size
422+ stats['line_count'] = len(lines)
423+ spaces = re.compile(r'^\s*$')
424+ stats['data_line_count'] = sum([1 for l in lines if not spaces.match(l)])
425+ return stats
--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -108,6 +108,10 @@ class RepositoryImplementation(object):
108108 '''Return a file-like object that contains the contents of the blob'''
109109 raise NotImplementedError, 'open_blob'
110110
111+ def blob_size(self, blob):
112+ '''Return a blob size in bytes'''
113+ raise NotImplementedError, 'blob_size'
114+
111115 @classmethod
112116 def shorthand_for_commit(cls, oid):
113117 return '[%s]' % oid[:6]
@@ -204,6 +208,8 @@ class Repository(Artifact):
204208 return self._impl.commit_context(commit)
205209 def open_blob(self, blob):
206210 return self._impl.open_blob(blob)
211+ def blob_size(self, blob):
212+ return self._impl.blob_size(blob)
207213 def shorthand_for_commit(self, oid):
208214 return self._impl.shorthand_for_commit(oid)
209215 def symbolics_for_commit(self, commit):
@@ -1108,6 +1114,10 @@ class Blob(RepoObject):
11081114 return iter(self.open())
11091115
11101116 @LazyProperty
1117+ def size(self):
1118+ return self.repo.blob_size(self)
1119+
1120+ @LazyProperty
11111121 def text(self):
11121122 return self.open().read()
11131123
--- a/Allura/allura/templates/repo/file.html
+++ b/Allura/allura/templates/repo/file.html
@@ -68,9 +68,13 @@
6868 {% elif blob.has_html_view or blob.has_pypeline_view or force_display %}
6969 <p><a href="?format=raw">Download this file</a></p>
7070 <div class="clip grid-19">
71- <h3><span class="ico-l"><b data-icon="{{g.icons['table'].char}}" class="ico {{g.icons['table'].css}}"></b> {{h.really_unicode(blob.name)}}</span></h3>
71+ <h3>
72+ <span class="ico-l"><b data-icon="{{g.icons['table'].char}}" class="ico {{g.icons['table'].css}}"></b> {{h.really_unicode(blob.name)}}</span>
73+ &nbsp;&nbsp;
74+ {{ stats.line_count }} lines ({{ stats.data_line_count }} with data), {{ stats.code_size|filesizeformat }}
75+ </h3>
7276 {% if blob.has_pypeline_view %}
73- {{h.render_any_markup(blob.name, blob.text, code_mode=True, linenumbers_style=h.TABLE)}}
77+ {{h.render_any_markup(blob.name, blob.text, code_mode=True)}}
7478 {% else %}
7579 {{g.highlight(blob.text, filename=blob.name)}}
7680 {% endif %}
--- /dev/null
+++ b/Allura/allura/tests/unit/test_utils.py
@@ -0,0 +1,28 @@
1+import unittest
2+from mock import Mock
3+
4+from alluratest.controller import setup_unit_test
5+from allura.lib.utils import generate_code_stats
6+
7+class TestCodeStats(unittest.TestCase):
8+
9+ def setUp(self):
10+ setup_unit_test()
11+
12+ def test_generate_code_stats(self):
13+ blob = Mock()
14+ blob.text = \
15+"""class Person(object):
16+
17+ def __init__(self, name='Alice'):
18+ self.name = name
19+
20+ def greetings(self):
21+ print "Hello, %s" % self.name
22+\t\t"""
23+ blob.size = len(blob.text)
24+
25+ stats = generate_code_stats(blob)
26+ assert stats['line_count'] == 8
27+ assert stats['data_line_count'] == 5
28+ assert stats['code_size'] == len(blob.text)
--- a/ForgeGit/forgegit/model/git_repo.py
+++ b/ForgeGit/forgegit/model/git_repo.py
@@ -272,6 +272,9 @@ class GitImplementation(M.RepositoryImplementation):
272272 return _OpenedGitBlob(
273273 self._object(blob.object_id).data_stream)
274274
275+ def blob_size(self, blob):
276+ return self._object(blob.object_id).data_stream.size
277+
275278 def _setup_hooks(self):
276279 'Set up the git post-commit hook'
277280 text = self.post_receive_template.substitute(
--- a/ForgeHg/forgehg/model/hg.py
+++ b/ForgeHg/forgehg/model/hg.py
@@ -257,6 +257,10 @@ class HgImplementation(M.RepositoryImplementation):
257257 fctx = self._hg[blob.commit.object_id][h.really_unicode(blob.path()).encode('utf-8')[1:]]
258258 return StringIO(fctx.data())
259259
260+ def blob_size(self, blob):
261+ fctx = self._hg[blob.commit.object_id][h.really_unicode(blob.path()).encode('utf-8')[1:]]
262+ return fctx.size()
263+
260264 def _setup_hooks(self):
261265 'Set up the hg changegroup hook'
262266 cp = ConfigParser()
--- a/ForgeSVN/forgesvn/model/svn.py
+++ b/ForgeSVN/forgesvn/model/svn.py
@@ -431,6 +431,24 @@ class SVNImplementation(M.RepositoryImplementation):
431431 revision=self._revision(blob.commit.object_id))
432432 return StringIO(data)
433433
434+ def blob_size(self, blob):
435+ try:
436+ data = self._svn.list(
437+ self._url + blob.path(),
438+ revision=self._revision(blob.commit.object_id),
439+ dirent_fields=pysvn.SVN_DIRENT_SIZE)
440+ except pysvn.ClientError:
441+ log.info('ClientError getting filesize %r %r, returning 0', blob.path(), self._repo, exc_info=True)
442+ return 0
443+
444+ try:
445+ size = data[0][0]['size']
446+ except (IndexError, KeyError):
447+ log.info('Error getting filesize: bad data from svn client %r %r, returning 0', blob.path(), self._repo, exc_info=True)
448+ size = 0
449+
450+ return size
451+
434452 def _setup_hooks(self):
435453 'Set up the post-commit and pre-revprop-change hooks'
436454 text = self.post_receive_template.substitute(