Mercurial > bitten > bitten-test
diff bitten/web_ui.py @ 503:a7c795920c4a
Merging trac-0.11 branch to trunk. This revision is equivalent to [571].
author | wbell |
---|---|
date | Mon, 09 Mar 2009 00:46:14 +0000 |
parents | f10da0985227 |
children | e2eef154f1af |
line wrap: on
line diff
--- a/bitten/web_ui.py +++ b/bitten/web_ui.py @@ -16,65 +16,51 @@ from StringIO import StringIO import pkg_resources +from genshi.builder import tag from trac.core import * -try: - from trac.timeline import ITimelineEventProvider - have_trac_011 = True -except ImportError: - from trac.Timeline import ITimelineEventProvider - have_trac_011 = False +from trac.timeline import ITimelineEventProvider from trac.util import escape, pretty_timedelta, format_datetime, shorten_line, \ Markup from trac.util.html import html from trac.web import IRequestHandler from trac.web.chrome import INavigationContributor, ITemplateProvider, \ - add_link, add_stylesheet -from trac.wiki import wiki_to_html -from trac.wiki import wiki_to_oneliner as wiki_to_oneliner_ + add_link, add_stylesheet, add_ctxtnav, \ + prevnext_nav, add_script +from trac.wiki import wiki_to_html, wiki_to_oneliner from bitten.api import ILogFormatter, IReportChartGenerator, IReportSummarizer from bitten.model import BuildConfig, TargetPlatform, Build, BuildStep, \ BuildLog, Report from bitten.queue import collect_changes -def wiki_to_oneliner(wikitext, env, db=None, shorten=False, absurls=False, - req=None): - if have_trac_011: - return wiki_to_oneliner_(wikitext, env, db=db, shorten=shorten, - absurls=absurls, req=req) - else: - return wiki_to_oneliner_(wikitext, env, db=db, shorten=shorten, - absurls=absurls) - - _status_label = {Build.PENDING: 'pending', Build.IN_PROGRESS: 'in progress', Build.SUCCESS: 'completed', Build.FAILURE: 'failed'} -def _build_to_hdf(env, req, build): - hdf = {'id': build.id, 'name': build.slave, 'rev': build.rev, - 'status': _status_label[build.status], - 'cls': _status_label[build.status].replace(' ', '-'), - 'href': req.href.build(build.config, build.id), - 'chgset_href': req.href.changeset(build.rev)} +def _get_build_data(env, req, build): + data = {'id': build.id, 'name': build.slave, 'rev': build.rev, + 'status': _status_label[build.status], + 'cls': _status_label[build.status].replace(' ', '-'), + 'href': req.href.build(build.config, build.id), + 'chgset_href': req.href.changeset(build.rev)} if build.started: - hdf['started'] = format_datetime(build.started) - hdf['started_delta'] = pretty_timedelta(build.started) - hdf['duration'] = pretty_timedelta(build.started) + data['started'] = format_datetime(build.started) + data['started_delta'] = pretty_timedelta(build.started) + data['duration'] = pretty_timedelta(build.started) if build.stopped: - hdf['stopped'] = format_datetime(build.stopped) - hdf['stopped_delta'] = pretty_timedelta(build.stopped) - hdf['duration'] = pretty_timedelta(build.stopped, build.started) - hdf['slave'] = { + data['stopped'] = format_datetime(build.stopped) + data['stopped_delta'] = pretty_timedelta(build.stopped) + data['duration'] = pretty_timedelta(build.stopped, build.started) + data['slave'] = { 'name': build.slave, 'ipnr': build.slave_info.get(Build.IP_ADDRESS), - 'os.name': build.slave_info.get(Build.OS_NAME), - 'os.family': build.slave_info.get(Build.OS_FAMILY), - 'os.version': build.slave_info.get(Build.OS_VERSION), + 'os_name': build.slave_info.get(Build.OS_NAME), + 'os_family': build.slave_info.get(Build.OS_FAMILY), + 'os_version': build.slave_info.get(Build.OS_VERSION), 'machine': build.slave_info.get(Build.MACHINE), 'processor': build.slave_info.get(Build.PROCESSOR) } - return hdf + return data class BittenChrome(Component): @@ -95,11 +81,9 @@ def get_navigation_items(self, req): """Return the navigation item for access the build status overview from the Trac navigation bar.""" - if not req.perm.has_permission('BUILD_VIEW'): - return - yield ('mainnav', 'build', \ - Markup('<a href="%s" accesskey="5">Build Status</a>') % - req.href.build()) + if 'BUILD_VIEW' in req.perm: + yield ('mainnav', 'build', + tag.a('Builds Status', href=req.href.build(), accesskey=5)) # ITemplatesProvider methods @@ -127,43 +111,44 @@ return True def process_request(self, req): - req.perm.assert_permission('BUILD_VIEW') + req.perm.require('BUILD_VIEW') action = req.args.get('action') view = req.args.get('view') config = req.args.get('config') if config: - self._render_config(req, config) + data = self._render_config(req, config) elif view == 'inprogress': - self._render_inprogress(req) + data = self._render_inprogress(req) else: - self._render_overview(req) + data = self._render_overview(req) add_stylesheet(req, 'bitten/bitten.css') - return 'bitten_config.cs', None + return 'bitten_config.html', data, None # Internal methods def _render_overview(self, req): - req.hdf['title'] = 'Build Status' + data = {'title': 'Build Status'} show_all = False if req.args.get('show') == 'all': show_all = True - req.hdf['config.show_all'] = show_all + data['show_all'] = show_all - configs = BuildConfig.select(self.env, include_inactive=show_all) - for idx, config in enumerate(configs): - prefix = 'configs.%d' % idx + configs = [] + for config in BuildConfig.select(self.env, include_inactive=show_all): description = config.description if description: description = wiki_to_html(description, self.env, req) - req.hdf[prefix] = { + config_data = { 'name': config.name, 'label': config.label or config.name, 'active': config.active, 'path': config.path, 'description': description, 'href': req.href.build(config.name), + 'builds': [] } + configs.append(config_data) if not config.active: continue @@ -176,69 +161,74 @@ if rev != prev_rev: if prev_rev is None: chgset = repos.get_changeset(rev) - req.hdf[prefix + '.youngest_rev'] = { + config_data['youngest_rev'] = { 'id': rev, 'href': req.href.changeset(rev), 'author': chgset.author or 'anonymous', 'date': format_datetime(chgset.date), 'message': wiki_to_oneliner( - shorten_line(chgset.message), self.env, req=req - ) + shorten_line(chgset.message), self.env, req=req) } else: break prev_rev = rev if build: - build_hdf = _build_to_hdf(self.env, req, build) - build_hdf['platform'] = platform.name - req.hdf[prefix + '.builds.%d' % platform.id] = build_hdf + build_data = _get_build_data(self.env, req, build) + build_data['platform'] = platform.name + config_data['builds'].append(build_data) else: - req.hdf[prefix + '.builds.%d' % platform.id] = { + config_data['builds'].append({ 'platform': platform.name, 'status': 'pending' - } + }) - req.hdf['page.mode'] = 'overview' + data['configs'] = configs + data['page_mode'] = 'overview' add_link(req, 'views', req.href.build(view='inprogress'), 'In Progress Builds') + add_ctxtnav(req, 'In Progress Builds', + req.href.build(view='inprogress')) + return data def _render_inprogress(self, req): - req.hdf['title'] = 'In Progress Builds' + data = {'title': 'In Progress Builds', + 'page_mode': 'view-inprogress'} db = self.env.get_db_cnx() - configs = BuildConfig.select(self.env, include_inactive=False) - for idx, config in enumerate(configs): + configs = [] + for config in BuildConfig.select(self.env, include_inactive=False): + self.log.debug(config.name) if not config.active: continue in_progress_builds = Build.select(self.env, config=config.name, status=Build.IN_PROGRESS, db=db) - # sort correctly by revision. - builds = list(in_progress_builds) - builds.sort(lambda x, y: int(y.rev) - int(x.rev)) - prefix = 'configs.%d' % idx - current_builds = 0 - for idx2, build in enumerate(builds): - prefix2 = '%s.builds.%d' % (prefix, idx2) + builds = [] + # sort correctly by revision. + for build in sorted(in_progress_builds, + cmp=lambda x, y: int(y.rev) - int(x.rev)): rev = build.rev - req.hdf[prefix2] = _build_to_hdf(self.env, req, build) - req.hdf[prefix2 + '.rev'] = rev - req.hdf[prefix2 + '.rev_href'] = req.href.changeset(rev) + build_data = _get_build_data(self.env, req, build) + build_data['rev'] = rev + build_data['rev_href'] = req.href.changeset(rev) platform = TargetPlatform.fetch(self.env, build.platform) - req.hdf[prefix2 + '.platform'] = platform.name + build_data['platform'] = platform.name + build_data['steps'] = [] for step in BuildStep.select(self.env, build=build.id, db=db): - req.hdf['%s.steps.%s' % (prefix2, step.name)] = { - 'description': step.description, - 'duration': datetime.fromtimestamp(step.stopped) - \ - datetime.fromtimestamp(step.started), - 'failed': not step.successful, - 'errors': step.errors, - 'href': req.hdf[prefix2 + '.href'] + '#step_' + step.name - } + build_data['steps'].append({ + 'name': step.name, + 'description': step.description, + 'duration': datetime.fromtimestamp(step.stopped) - \ + datetime.fromtimestamp(step.started), + 'failed': not step.successful, + 'errors': step.errors, + 'href': build_data['href'] + '#step_' + step.name + }) - current_builds = current_builds + 1 + builds.append(build_data) + current_builds += 1 if current_builds == 0: continue @@ -246,26 +236,29 @@ description = config.description if description: description = wiki_to_html(description, self.env, req) - req.hdf[prefix] = { + configs.append({ 'name': config.name, 'label': config.label or config.name, 'active': config.active, 'path': config.path, 'description': description, 'href': req.href.build(config.name), - } + 'builds': builds + }) - req.hdf['page.mode'] = 'view_inprogress' + data['configs'] = configs + return data def _render_config(self, req, config_name): db = self.env.get_db_cnx() config = BuildConfig.fetch(self.env, config_name, db=db) - req.hdf['title'] = 'Build Configuration "%s"' \ - % config.label or config.name + data = {'title': 'Build Configuration "%s"' \ + % config.label or config.name, + 'page_mode': 'view_config'} add_link(req, 'up', req.href.build(), 'Build Status') description = config.description if description: description = wiki_to_html(description, self.env, req) - req.hdf['config'] = { + data['config'] = { 'name': config.name, 'label': config.label, 'path': config.path, 'min_rev': config.min_rev, 'min_rev_href': req.href.changeset(config.min_rev), @@ -274,12 +267,12 @@ 'active': config.active, 'description': description, 'browser_href': req.href.browser(config.path) } - req.hdf['page.mode'] = 'view_config' platforms = list(TargetPlatform.select(self.env, config=config_name, db=db)) - req.hdf['config.platforms'] = [ - {'name': platform.name, 'id': platform.id} for platform in platforms + data['config']['platforms'] = [ + {'name': platform.name, 'id': platform.id} + for platform in platforms ] has_reports = False @@ -294,14 +287,14 @@ chart_generators.append({ 'href': req.href.build(config.name, 'chart/' + category) }) - req.hdf['config.charts'] = chart_generators + data['config']['charts'] = chart_generators charts_license = self.config.get('bitten', 'charts_license') if charts_license: - req.hdf['config.charts_license'] = charts_license + data['config']['charts_license'] = charts_license page = max(1, int(req.args.get('page', 1))) more = False - req.hdf['page.number'] = page + data['page_number'] = page repos = self.env.get_repository(req.authname) if hasattr(repos, 'sync'): @@ -309,28 +302,31 @@ builds_per_page = 12 * len(platforms) idx = 0 + builds = {} for platform, rev, build in collect_changes(repos, config): if idx >= page * builds_per_page: more = True break elif idx >= (page - 1) * builds_per_page: - prefix = 'config.builds.%s' % rev - req.hdf[prefix + '.href'] = req.href.changeset(rev) + builds.setdefault(rev, {}) + builds[rev].setdefault('href', req.href.changeset(rev)) if build and build.status != Build.PENDING: - build_hdf = _build_to_hdf(self.env, req, build) - req.hdf['%s.%s' % (prefix, platform.id)] = build_hdf + build_data = _get_build_data(self.env, req, build) + build_data['steps'] = [] for step in BuildStep.select(self.env, build=build.id, db=db): - req.hdf['%s.%s.steps.%s' % (prefix, platform.id, - step.name)] = { + build_data['steps'].append({ + 'name': step.name, 'description': step.description, 'duration': datetime.fromtimestamp(step.stopped) - \ datetime.fromtimestamp(step.started), 'failed': not step.successful, 'errors': step.errors, - 'href': build_hdf['href'] + '#step_' + step.name, - } + 'href': build_data['href'] + '#step_' + step.name + }) + builds[rev][platform.id] = build_data idx += 1 + data['config']['builds'] = builds if page > 1: if page == 2: @@ -341,6 +337,8 @@ if more: next_href = req.href.build(config.name, page=page + 1) add_link(req, 'next', next_href, 'Next Page') + prevnext_nav(req, 'Page') + return data class BuildController(Component): @@ -370,7 +368,7 @@ return True def process_request(self, req): - req.perm.assert_permission('BUILD_VIEW') + req.perm.require('BUILD_VIEW') db = self.env.get_db_cnx() build_id = int(req.args.get('id')) @@ -386,11 +384,12 @@ 'Build Configuration') status2title = {Build.SUCCESS: 'Success', Build.FAILURE: 'Failure', Build.IN_PROGRESS: 'In Progress'} - req.hdf['title'] = 'Build %s - %s' % (build_id, - status2title[build.status]) - req.hdf['page.mode'] = 'view_build' + data = {'title': 'Build %s - %s' % (build_id, + status2title[build.status]), + 'page_mode': 'view_build', + 'build': {}} config = BuildConfig.fetch(self.env, build.config, db=db) - req.hdf['build.config'] = { + data['build']['config'] = { 'name': config.label, 'href': req.href.build(config.name) } @@ -404,7 +403,7 @@ categories = summarizer.get_supported_categories() summarizers.update(dict([(cat, summarizer) for cat in categories])) - req.hdf['build'] = _build_to_hdf(self.env, req, build) + data['build'].update(_get_build_data(self.env, req, build)) steps = [] for step in BuildStep.select(self.env, build=build.id, db=db): steps.append({ @@ -416,20 +415,21 @@ 'reports': self._render_reports(req, config, build, summarizers, step) }) - req.hdf['build.steps'] = steps - req.hdf['build.can_delete'] = req.perm.has_permission('BUILD_DELETE') + data['build']['steps'] = steps + data['build']['can_delete'] = ('BUILD_DELETE' in req.perm) repos = self.env.get_repository(req.authname) chgset = repos.get_changeset(build.rev) - req.hdf['build.chgset_author'] = chgset.author + data['build']['chgset_author'] = chgset.author + add_script(req, 'bitten/tabset.js') add_stylesheet(req, 'bitten/bitten.css') - return 'bitten_build.cs', None + return 'bitten_build.html', data, None # ITimelineEventProvider methods def get_timeline_filters(self, req): - if req.perm.has_permission('BUILD_VIEW'): + if 'BUILD_VIEW' in req.perm: yield ('build', 'Builds') def get_timeline_events(self, req, start, stop, filters): @@ -465,9 +465,8 @@ errors += [(step.name, error) for error in step.errors] - title = Markup('Build of <em>%s [%s]</em> on %s %s') % ( - label, rev, platform, _status_label[status] - ) + title = tag('Build of ', tag.em('%s [%s]' % (label, rev)), + ' on %s %s' % (platform, _status_label[status])) message = '' if req.args.get('format') == 'rss': href = req.abs_href.build(config, id) @@ -536,12 +535,12 @@ for report in Report.select(self.env, build=build.id, step=step.name): summarizer = summarizers.get(report.category) if summarizer: - summary = summarizer.render_summary(req, config, build, step, - report.category) + tmpl, data = summarizer.render_summary(req, config, build, + step, report.category) else: - summary = None + tmpl = data = None reports.append({'category': report.category, - 'summary': Markup(summary)}) + 'template': tmpl, 'data': data}) return reports @@ -565,13 +564,13 @@ for generator in self.generators: if category in generator.get_supported_categories(): - template = generator.generate_chart_data(req, config, - category) + tmpl, data = generator.generate_chart_data(req, config, + category) break else: raise TracError('Unknown report category "%s"' % category) - return template, 'text/xml' + return tmpl, data, 'text/xml' class SourceFileLinkFormatter(Component): @@ -609,7 +608,7 @@ link = href(config.path, filepath) if m.group('line'): link += '#L' + m.group('line')[1:] - return Markup(html.A(m.group(0), href=link)) + return Markup(tag.a(m.group(0), href=link)) def _formatter(step, type, level, message): buf = []