review/web_ui.py @ ddea94e8e138 webpy-sucks

Refactor the diff-annotating functionality into the API.
author Steve Losh <steve@stevelosh.com>
date Wed, 03 Mar 2010 18:55:40 -0500
parents f936bf37db17
children 12301b2a5461
"""The review extension's web UI."""
from __future__ import with_statement

import sys, os
from hashlib import md5

from mercurial import cmdutil, hg, templatefilters
from mercurial.node import short, hex
from mercurial.util import email

import api

package_path = os.path.split(os.path.realpath(__file__))[0]
template_path = os.path.join(package_path, 'web_templates')
media_path = os.path.join(package_path, 'web_media')
top_path = os.path.split(package_path)[0]
bundled_path = os.path.join(top_path, 'bundled')
cherrypy_path = os.path.join(bundled_path, 'cherrypy')
jinja2_path = os.path.join(bundled_path, 'jinja2')

sys.path.insert(0, cherrypy_path)
sys.path.insert(0, jinja2_path)

import cherrypy
from jinja2 import Environment, FileSystemLoader


TEMPLATE_DIR = os.path.join(package_path, 'web_templates')
jinja_env = Environment(loader=FileSystemLoader(TEMPLATE_DIR))

LOG_PAGE_LEN = 1000000

def _comment_gravatar(comment):
    return 'http://www.gravatar.com/avatar/%s/' % md5(email(comment.author)).hexdigest()

def _skipped_comments(n, previous_n, line_level_comments):
    return filter(lambda c: max(c.lines) in range(previous_n + 1, n), line_level_comments)

def _skipped_comments_end(previous_n, max_line, line_level_comments):
    return filter(lambda c: max(c.lines) in range(previous_n + 1, max_line), line_level_comments)

def _line_type(line):
    return 'rem' if line[0] == '-' else 'add' if line[0] == '+' else 'con'

def _line_comments(n, line_level_comments):
    return filter(lambda c: max(c.lines) == n, line_level_comments)

utils = {
    'node_short': short,
    'basename': os.path.basename,
    'md5': md5,
    'email': email,
    'templatefilters': templatefilters,
    'len': len,
    'comment_gravatar': _comment_gravatar,
    'skipped_comments': _skipped_comments,
    'skipped_comments_end': _skipped_comments_end,
    'line_type': _line_type,
    'line_comments': _line_comments,
}

class ReviewWebUI(object):
    def __init__(self, datastore):
        self.datastore = datastore
    
    
    @cherrypy.expose
    def index(self):
        rev_max = self.datastore.target['tip'].rev()
        rev_min = rev_max - LOG_PAGE_LEN if rev_max >= LOG_PAGE_LEN else 0
        rcsets = [self.datastore[r] for r in xrange(rev_max, rev_min, -1)]
        
        return jinja_env.get_template('index.html').render(
            utils=utils, datastore=self.datastore, title='',
            rcsets=rcsets,
        )
    
    
    @cherrypy.expose
    def changeset(self, *args):
        if len(args) != 1:
            return 'OH GOD HOW DID THIS GET HERE I AM NOT GOOD WITH LINKS'
        rev_id = args[0]
        rcset = self.datastore[rev_id]
        rev = rcset.target[rev_id]
        
        return jinja_env.get_template('changeset.html').render(
            utils=utils, datastore=self.datastore,
            title='%s:%s' % (rev.rev(), short(rev.node())),
            rcset=rcset, rev=rev,
        )


def load_interface(ui, repo, open=False, port=8080):
    if open:
        import webbrowser
        webbrowser.open('http://localhost:%d/' % port)
        
    conf = {
        '/media': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': media_path,
        }
    }
    
    cherrypy.quickstart(ReviewWebUI(api.ReviewDatastore(ui, repo)), config=conf)



# _rd = None
# urls = (
#     '/', 'index',
#     '/media/([^/]*)', 'media',
#     '/review/([\da-f]{12})/?', 'review',
#     '/push/', 'push',
#     '/pull/', 'pull',
# )
# 
# render = web.template.render(template_path, globals=g)
# 
# LOG_PAGE_LEN = 25
# 
# def render_in_base(fn):
#     def _fn(*args, **kwargs):
#         title, content = fn(*args, **kwargs)
#         return render.base(_rd, content, title)
#     return _fn
# 
# class index:
#     @render_in_base
#     def GET(self):
#         rev_max = _rd.target['tip'].rev()
#         rev_min = rev_max - LOG_PAGE_LEN if rev_max >= LOG_PAGE_LEN else 0
#         revs = (_rd.target[r] for r in xrange(rev_max, rev_min, -1))
#         return ('', render.index(_rd, revs))
#     
# 
# class review:
#     @render_in_base
#     def GET(self, node_short):
#         title = '/ %s:%s &ndash; %s' % (
#             _rd[node_short].target[node_short].rev(),
#             node_short,
#             _rd[node_short].target[node_short].description().splitlines()[0])
#         return (title, render.review(_rd, _rd[node_short]))
#     
#     def POST(self, node_short):
#         i = web.input()
#         body = i['body']
#         filename = i['filename'] if 'filename' in i else ''
#         lines = i['lines'].split(',') if 'lines' in i else ''
#         print filename, lines
#         
#         if body:
#             rcset = _rd[node_short]
#             rcset.add_comment(body, filename, lines)
#         
#         raise web.seeother('/review/%s/' % node_short)
#     
# 
# class push:
#     def GET(self):
#         path = web.input()['path']
#         dest, revs, checkout = hg.parseurl(_rd.repo.ui.expandpath(path, path), None)
#         other = hg.repository(cmdutil.remoteui(_rd.repo, {}), dest)
#         
#         _rd.repo.push(other, True, revs=revs)
#         
#         raise web.seeother('/')
#     
# 
# class pull:
#     def GET(self):
#         path = web.input()['path']
#         source, revs, checkout = hg.parseurl(_rd.repo.ui.expandpath(path, path), None)
#         other = hg.repository(cmdutil.remoteui(_rd.repo, {}), source)
#         
#         modheads = _rd.repo.pull(other, heads=revs, force=True)
#         
#         if modheads:
#             hg.update(_rd.repo, 'tip')
#         
#         raise web.seeother('/')
#     
# 
# class media:
#     def GET(self, fname):
#         if '..' in fname:
#             return ''
#         else:
#             with open(os.path.join(media_path, fname)) as f:
#                 content = f.read()
#             return content
#     
#