Changeset - a83a1799480c
[Not reviewed]
default
0 14 0
Marcin Kuzminski - 15 years ago 2010-06-03 00:04:48
marcin@python-works.com
Reimplemented way of caching repos list, hg model now get's repos objects right from cached dict, this way we skipp creating instances of MercurialRepository and gain performance. Some import cleanup
14 files changed with 126 insertions and 91 deletions:
0 comments (0 inline, 0 general)
pylons_app/controllers/branches.py
Show inline comments
 
from pylons import tmpl_context as c, app_globals as g
 
from pylons_app.lib.auth import LoginRequired
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.model.hg_model import HgModel
 
import logging
 

	
 
from pylons import tmpl_context as c, app_globals as g, session, request, config, url
 
from pylons.controllers.util import abort, redirect
 

	
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.lib.utils import get_repo_slug
 
from pylons_app.model.hg_model import HgModel
 
from pylons_app.lib.auth import LoginRequired
 
log = logging.getLogger(__name__)
 

	
 

	
 
class BranchesController(BaseController):
 
    
 
    @LoginRequired()
 
    def __before__(self):
 
        super(BranchesController, self).__before__()
 
    
 
    def index(self):
 
        hg_model = HgModel()
 
        c.repo_info = hg_model.get_repo(c.repo_name)
 
        c.repo_branches = c.repo_info.branches
 
                
 
        return render('branches/branches.html')
pylons_app/controllers/changelog.py
Show inline comments
 
from mercurial.graphmod import revisions as graph_rev, colored, CHANGESET
 
from mercurial.node import short
 
from pylons import request, response, session, tmpl_context as c, url, config, \
 
    app_globals as g
 
from pylons.controllers.util import abort, redirect
 
from pylons import request, session, tmpl_context as c
 
from pylons_app.lib.auth import LoginRequired
 
from pylons_app.lib.base import BaseController, render, _full_changelog_cached
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.lib.filters import age as _age, person
 
from pylons_app.model.hg_model import _full_changelog_cached
 
from simplejson import dumps
 
from webhelpers.paginate import Page
 
import logging
 
log = logging.getLogger(__name__)     
 

	
 
class ChangelogController(BaseController):
 
    
 
    @LoginRequired()
 
    def __before__(self):
 
        super(ChangelogController, self).__before__()
 
                
 
    def index(self):
 
        limit = 100
 
        default = 20
 
        if request.params.get('size'):
 
            try:
 
                int_size = int(request.params.get('size'))
 
            except ValueError:
 
                int_size = default
 
            int_size = int_size if int_size <= limit else limit 
 
            c.size = int_size
 
            session['changelog_size'] = c.size
 
            session.save()
 
        else:
 
            c.size = session.get('changelog_size', default)
 

	
 
        changesets = _full_changelog_cached(c.repo_name)
 
            
 
        p = int(request.params.get('page', 1))
 
        c.pagination = Page(changesets, page=p, item_count=len(changesets),
 
                            items_per_page=c.size)
 
            
 
        #self._graph(c.repo, c.size,p)
 
        
 
        return render('changelog/changelog.html')
 

	
 

	
 
    def _graph(self, repo, size, p):
 
        revcount = size
 
        if not repo.revisions:return dumps([]), 0
 
        
 
        max_rev = repo.revisions[-1]
 
        offset = 1 if p == 1 else  ((p - 1) * revcount)
 
        rev_start = repo.revisions[(-1 * offset)]
 
        c.bg_height = 120
 
        
 
        revcount = min(max_rev, revcount)
 
        rev_end = max(0, rev_start - revcount)
 
        dag = graph_rev(repo.repo, rev_start, rev_end)
 
        
 
        c.dag = tree = list(colored(dag))
 
        canvasheight = (len(tree) + 1) * c.bg_height - 27
 
        data = []
 
        for (id, type, ctx, vtx, edges) in tree:
 
            if type != CHANGESET:
 
                continue
 
            node = short(ctx.node())
 
            age = _age(ctx.date())
 
            desc = ctx.description()
 
            user = person(ctx.user())
 
            branch = ctx.branch()
 
            branch = branch, repo.repo.branchtags().get(branch) == ctx.node()
 
            data.append((node, vtx, edges, desc, user, age, branch, ctx.tags()))
 
    
 
        c.jsdata = dumps(data) 
 
        c.canvasheight = canvasheight 
 

	
pylons_app/controllers/changeset.py
Show inline comments
 
from pylons import request, response, session, tmpl_context as c, url, config, \
 
    app_globals as g
 
from pylons.controllers.util import abort, redirect
 
from pylons import tmpl_context as c
 
from pylons_app.lib.auth import LoginRequired
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.model.hg_model import HgModel
 
from vcs.utils import diffs as differ
 
import logging
 
from vcs.nodes import FileNode
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
class ChangesetController(BaseController):
 
    
 
    @LoginRequired()
 
    def __before__(self):
 
        super(ChangesetController, self).__before__()
 
        
 
    def index(self, revision):
 
        hg_model = HgModel()
 
        c.changeset = hg_model.get_repo(c.repo_name).get_changeset(revision)
 
        c.changeset_old = c.changeset.parents[0]
 
        c.changes = []
 
        
 
                
 
        for node in c.changeset.added:
 
            filenode_old = FileNode(node.path, '')
 
            f_udiff = differ.get_udiff(filenode_old, node)
 
            diff = differ.DiffProcessor(f_udiff).as_html()
 
            c.changes.append(('added', node, diff))
 
            
 
        for node in c.changeset.changed:
 
            filenode_old = c.changeset_old.get_node(node.path)
 
            f_udiff = differ.get_udiff(filenode_old, node)
 
            diff = differ.DiffProcessor(f_udiff).as_html()
 
            c.changes.append(('changed', node, diff))
 
            
 
        for node in c.changeset.removed:
 
            c.changes.append(('removed', node, None))            
 
            
 
        return render('changeset/changeset.html')
pylons_app/controllers/feed.py
Show inline comments
 
#!/usr/bin/python
 
# -*- coding: utf-8 -*-
 
from pylons import tmpl_context as c, url, response
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.model.hg_model import _full_changelog_cached
 
from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
 
import logging
 
from operator import itemgetter
 
from pylons import tmpl_context as c, request, config, url, response
 
from pylons_app.lib.base import BaseController, render, _full_changelog_cached
 
from pylons_app.lib.utils import get_repo_slug
 
from pylons_app.model.hg_model import HgModel
 
from pylons_app.lib.auth import LoginRequired
 
from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
 
log = logging.getLogger(__name__)
 

	
 
class FeedController(BaseController):
 
    
 
    #secure it or not ?
 
    def __before__(self):
 
        super(FeedController, self).__before__()
 
        #common values for feeds
 
        self.description = 'Changes on %s repository'
 
        self.title = "%s feed"
 
        self.language = 'en-us'
 
        self.ttl = "5"
 
        self.feed_nr = 10
 

	
 
    def atom(self, repo_name):
 
        """Produce an atom-1.0 feed via feedgenerator module"""
 
        feed = Atom1Feed(title=self.title % repo_name,
 
                         link=url('summary_home', repo_name=repo_name, qualified=True),
 
                         description=self.description % repo_name,
 
                         language=self.language,
 
                         ttl=self.ttl)
 
        
 
        
 
        for cnt, cs in enumerate(_full_changelog_cached(repo_name)):
 
            if cnt > self.feed_nr:
 
                break
 
            feed.add_item(title=cs.message,
 
                          link=url('changeset_home', repo_name=repo_name, revision=cs.raw_id, qualified=True),
 
                          description=str(cs.date))
 
                          link=url('changeset_home', repo_name=repo_name,
 
                                   revision=cs.raw_id, qualified=True),
 
                                   description=str(cs.date))
 
        
 
        response.content_type = feed.mime_type
 
        return feed.writeString('utf-8')
 

	
 
    
 
    def rss(self, repo_name):
 
        """Produce an rss2 feed via feedgenerator module"""
 
        feed = Rss201rev2Feed(title=self.title % repo_name,
 
                         link=url('summary_home', repo_name=repo_name, qualified=True),
 
                         description=self.description % repo_name,
 
                         language=self.language,
 
                         ttl=self.ttl)
 
        
 
        for cnt, cs in enumerate(_full_changelog_cached(repo_name)):
 
            if cnt > self.feed_nr:
 
                break
 
            feed.add_item(title=cs.message,
 
                          link=url('changeset_home', repo_name=repo_name, revision=cs.raw_id, qualified=True),
 
                          description=str(cs.date))
 
            
 
        response.content_type = feed.mime_type
 
        return feed.writeString('utf-8')
pylons_app/controllers/files.py
Show inline comments
 
import tempfile
 
from pylons import request, response, session, tmpl_context as c, url, config, \
 
    app_globals as g
 
from pylons.controllers.util import abort, redirect
 
from mercurial import archival
 
from pylons import request, response, session, tmpl_context as c, url
 
from pylons_app.lib.auth import LoginRequired
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.lib.utils import get_repo_slug
 
from pylons_app.model.hg_model import HgModel
 
from vcs.exceptions import RepositoryError, ChangesetError
 
from vcs.utils import diffs as differ
 
import logging
 
from mercurial import archival
 
import tempfile
 

	
 
        
 
log = logging.getLogger(__name__)
 

	
 
class FilesController(BaseController):
 
    
 
    @LoginRequired()
 
    def __before__(self):
 
        super(FilesController, self).__before__()
 

	
 
    def index(self, repo_name, revision, f_path):
 
        hg_model = HgModel()
 
        c.repo = repo = hg_model.get_repo(c.repo_name)
 
        revision = request.POST.get('at_rev', None) or revision
 
        
 
        def get_next_rev(cur):
 
            max_rev = len(c.repo.revisions) - 1
 
            r = cur + 1
 
            if r > max_rev:
 
                r = max_rev
 
            return r
 
            
 
        def get_prev_rev(cur):
 
            r = cur - 1
 
            return r
 

	
 
        c.f_path = f_path
 
     
 
        
 
        try:
 
            cur_rev = repo.get_changeset(revision).revision
 
            prev_rev = repo.get_changeset(get_prev_rev(cur_rev)).raw_id
 
            next_rev = repo.get_changeset(get_next_rev(cur_rev)).raw_id
 
                    
 
            c.url_prev = url('files_home', repo_name=c.repo_name,
 
                             revision=prev_rev, f_path=f_path) 
 
            c.url_next = url('files_home', repo_name=c.repo_name,
 
                             revision=next_rev, f_path=f_path)   
 
                    
 
            c.changeset = repo.get_changeset(revision)
 
            try:
 
                c.file_msg = c.changeset.get_file_message(f_path)
 
            except:
 
                c.file_msg = None
 
                        
 
            c.cur_rev = c.changeset.raw_id
 
            c.rev_nr = c.changeset.revision
 
            c.files_list = c.changeset.get_node(f_path)
 
            c.file_history = self._get_history(repo, c.files_list, f_path)
 
            
 
        except (RepositoryError, ChangesetError):
 
            c.files_list = None
 
        
 
        return render('files/files.html')
 

	
 
    def rawfile(self, repo_name, revision, f_path):
 
        hg_model = HgModel()
 
        c.repo = hg_model.get_repo(c.repo_name)
 
        file_node = c.repo.get_changeset(revision).get_node(f_path)
 
        response.content_type = file_node.mimetype
 
        response.content_disposition = 'attachment; filename=%s' \
 
                                                    % f_path.split('/')[-1] 
 
        return file_node.content
 
    
 
    def annotate(self, repo_name, revision, f_path):
 
        hg_model = HgModel()
 
        c.repo = hg_model.get_repo(c.repo_name)
 
        cs = c.repo.get_changeset(revision)
 
        c.file = cs.get_node(f_path)
 
        c.file_msg = cs.get_file_message(f_path)
 
        c.cur_rev = cs.raw_id
 
        c.f_path = f_path
 
        c.annotate = cs.get_file_annotate(f_path)
 
        return render('files/files_annotate.html')
 
      
 
    def archivefile(self, repo_name, revision, fileformat):
 
        archive_specs = {
 
          '.tar.bz2': ('application/x-tar', 'tbz2'),
 
          '.tar.gz': ('application/x-tar', 'tgz'),
 
          '.zip': ('application/zip', 'zip'),
 
        }
 
        if not archive_specs.has_key(fileformat):
 
            return 'Unknown archive type %s' % fileformat
 
                        
 
        def read_in_chunks(file_object, chunk_size=1024 * 40):
 
            """Lazy function (generator) to read a file piece by piece.
 
            Default chunk size: 40k."""
 
            while True:
 
                data = file_object.read(chunk_size)
 
                if not data:
 
                    break
 
                yield data        
 
            
 
        archive = tempfile.TemporaryFile()
 
        repo = HgModel().get_repo(repo_name).repo
 
        fname = '%s-%s%s' % (repo_name, revision, fileformat)
 
        archival.archive(repo, archive, revision, archive_specs[fileformat][1],
 
                         prefix='%s-%s' % (repo_name, revision))
 
        response.content_type = archive_specs[fileformat][0]
 
        response.content_disposition = 'attachment; filename=%s' % fname
 
        archive.seek(0)
 
        return read_in_chunks(archive)
 
    
 
    def diff(self, repo_name, f_path):
 
        hg_model = HgModel()
 
        diff1 = request.GET.get('diff1')
 
        diff2 = request.GET.get('diff2')
 
        c.action = action = request.GET.get('diff')
 
        c.no_changes = diff1 == diff2
 
        c.f_path = f_path
 
        c.repo = hg_model.get_repo(c.repo_name)
 
        c.changeset_1 = c.repo.get_changeset(diff1)
 
        c.changeset_2 = c.repo.get_changeset(diff2)
 

	
 
        c.diff1 = 'r%s:%s' % (c.changeset_1.revision, c.changeset_1._short)
 
        c.diff2 = 'r%s:%s' % (c.changeset_2.revision, c.changeset_2._short)
 
        f_udiff = differ.get_udiff(c.changeset_1.get_node(f_path),
 
                            c.changeset_2.get_node(f_path))
 
        
 
        diff = differ.DiffProcessor(f_udiff)
 
                                
 
        if action == 'download':
 
            diff_name = '%s_vs_%s.diff' % (diff1, diff2)
 
            response.content_type = 'text/plain'
 
            response.content_disposition = 'attachment; filename=%s' \
 
                                                    % diff_name             
 
            return diff.raw_diff()
 
        
 
        elif action == 'raw':
 
            c.cur_diff = '<pre class="raw">%s</pre>' % diff.raw_diff()
 
        elif action == 'diff':
 
            c.cur_diff = diff.as_html()
 

	
 
        return render('files/file_diff.html')
 
    
 
    def _get_history(self, repo, node, f_path):
 
        from vcs.nodes import NodeKind
 
        if not node.kind is NodeKind.FILE:
 
            return []
 
        changesets = node.history
 
        hist_l = []
 
        for chs in changesets:
 
            n_desc = 'r%s:%s' % (chs.revision, chs._short)
 
            hist_l.append((chs._short, n_desc,))
 
        return hist_l
pylons_app/controllers/hg.py
Show inline comments
 
#!/usr/bin/python
 
# -*- coding: utf-8 -*-
 
import logging
 
from operator import itemgetter
 
from pylons import tmpl_context as c, request, config
 
from pylons_app.lib.auth import LoginRequired
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.lib.auth import LoginRequired
 
from pylons_app.model.hg_model import HgModel
 
import logging
 
log = logging.getLogger(__name__)
 

	
 
class HgController(BaseController):
 

	
 
    @LoginRequired()
 
    def __before__(self):
 
        super(HgController, self).__before__()
 
        
 
    def index(self):
 
        c.current_sort = request.GET.get('sort', 'name')
 
        cs = c.current_sort
 
        c.cs_slug = cs.replace('-', '')
 
        sortables = ['name', 'description', 'last_change', 'tip', 'contact']
 
        
 
        cached_repo_list = HgModel().get_repos()
 
        if cs and c.cs_slug in sortables:
 
            sort_key = c.cs_slug + '_sort'
 
            if cs.startswith('-'):
 
                c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key), reverse=True)
 
                c.repos_list = sorted(cached_repo_list, key=itemgetter(sort_key), reverse=True)
 
            else:
 
                c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key), reverse=False)
 
                c.repos_list = sorted(cached_repo_list, key=itemgetter(sort_key), reverse=False)
 
            
 
        return render('/index.html')
pylons_app/controllers/shortlog.py
Show inline comments
 
import logging
 

	
 
from pylons import tmpl_context as c, app_globals as g, session, request, config, url
 
from pylons.controllers.util import abort, redirect
 

	
 
from pylons import tmpl_context as c, request
 
from pylons_app.lib.auth import LoginRequired
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.lib.utils import get_repo_slug
 
from pylons_app.model.hg_model import HgModel
 
from webhelpers.paginate import Page
 
from pylons_app.lib.auth import LoginRequired
 
import logging
 

	
 
log = logging.getLogger(__name__)
 

	
 
class ShortlogController(BaseController):
 
    
 
    @LoginRequired()
 
    def __before__(self):
 
        super(ShortlogController, self).__before__()
 
        
 
    def index(self):
 
        hg_model = HgModel()
 
        p = int(request.params.get('page', 1))
 
        repo = hg_model.get_repo(c.repo_name)
 
        c.repo_changesets = Page(repo, page=p, items_per_page=20)
 
        c.shortlog_data = render('shortlog/shortlog_data.html')
 
        if request.params.get('partial'):
 
            return c.shortlog_data
 
        r = render('shortlog/shortlog.html')
 
        return r
pylons_app/controllers/summary.py
Show inline comments
 
from pylons import tmpl_context as c, request
 
from pylons_app.lib.auth import LoginRequired
 
from pylons_app.lib.base import BaseController, render, _full_changelog_cached
 
from pylons_app.model.hg_model import HgModel
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.model.hg_model import HgModel, _full_changelog_cached
 
import logging
 

	
 
log = logging.getLogger(__name__)
 

	
 
class SummaryController(BaseController):
 
    
 
    @LoginRequired()
 
    def __before__(self):
 
        super(SummaryController, self).__before__()
 
        
 
    def index(self):
 
        hg_model = HgModel()
 
        c.repo_info = hg_model.get_repo(c.repo_name)
 
        c.repo_changesets = _full_changelog_cached(c.repo_name)[:10]
 
        
 
        e = request.environ
 
        uri = u'%(protocol)s://%(user)s@%(host)s/%(repo_name)s' % {
 
                                        'protocol': e.get('wsgi.url_scheme'),
 
                                        'user':str(c.hg_app_user.username),
 
                                        'host':e.get('HTTP_HOST'),
 
                                        'repo_name':c.repo_name, }
 
        c.clone_repo_url = uri
 
        c.repo_tags = c.repo_info.tags[:10]
 
        c.repo_branches = c.repo_info.branches[:10]
 
        return render('summary/summary.html')
pylons_app/controllers/tags.py
Show inline comments
 
from pylons import tmpl_context as c
 
from pylons_app.lib.auth import LoginRequired
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.model.hg_model import HgModel
 
import logging
 

	
 
from pylons import tmpl_context as c, app_globals as g, session, request, config, url
 
from pylons.controllers.util import abort, redirect
 

	
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.lib.utils import get_repo_slug
 
from pylons_app.model.hg_model import HgModel
 
from pylons_app.lib.auth import LoginRequired
 
log = logging.getLogger(__name__)
 

	
 

	
 
class TagsController(BaseController):
 
    
 
    @LoginRequired()
 
    def __before__(self):
 
        super(TagsController, self).__before__()
 
        
 
    def index(self):
 
        hg_model = HgModel()
 
        c.repo_info = hg_model.get_repo(c.repo_name)
 
        c.repo_tags = c.repo_info.tags
 
        
 
        return render('tags/tags.html')
pylons_app/controllers/users.py
Show inline comments
 
from formencode import htmlfill
 
from pylons import request, response, session, tmpl_context as c, url, \
 
    app_globals as g
 
from pylons import request, session, tmpl_context as c, url
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 
from pylons_app.lib import helpers as h    
 
from pylons.controllers.util import abort, redirect
 
from pylons_app.lib import helpers as h
 
from pylons_app.lib.auth import LoginRequired, CheckPermissionAll
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.model.db import User, UserLog
 
from pylons_app.model.forms import UserForm
 
from pylons_app.model.user_model import UserModel
 
import formencode
 
import logging
 

	
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
class UsersController(BaseController):
 
    """REST Controller styled on the Atom Publishing Protocol"""
 
    # To properly map this controller, ensure your config/routing.py
 
    # file has a resource setup:
 
    #     map.resource('user', 'users')
 
    @LoginRequired()
 
    def __before__(self):
 
        c.admin_user = session.get('admin_user')
 
        c.admin_username = session.get('admin_username')
 
        super(UsersController, self).__before__()
 
    
 

	
 
    def index(self, format='html'):
 
        """GET /users: All items in the collection"""
 
        # url('users')
 
        
 
        c.users_list = self.sa.query(User).all()     
 
        return render('admin/users/users.html')
 
    
 
    def create(self):
 
        """POST /users: Create a new item"""
 
        # url('users')
 
        
 
        user_model = UserModel()
 
        login_form = UserForm()()
 
        try:
 
            form_result = login_form.to_python(dict(request.POST))
 
            user_model.create(form_result)
 
            h.flash(_('created user %s') % form_result['username'], category='success')
 
            return redirect(url('users'))
 
                           
 
        except formencode.Invalid as errors:
 
            c.form_errors = errors.error_dict
 
            return htmlfill.render(
 
                 render('admin/users/user_add.html'),
 
                defaults=errors.value,
 
                encoding="UTF-8")
 
    
 
    def new(self, format='html'):
 
        """GET /users/new: Form to create a new item"""
 
        # url('new_user')
 
        return render('admin/users/user_add.html')
 

	
 
    def update(self, id):
 
        """PUT /users/id: Update an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="PUT" />
 
        # Or using helpers:
 
        #    h.form(url('user', id=ID),
 
        #           method='put')
 
        # url('user', id=ID)
 
        user_model = UserModel()
 
        login_form = UserForm(edit=True)()
 
        try:
 
            form_result = login_form.to_python(dict(request.POST))
 
            user_model.update(id, form_result)
 
            h.flash(_('User updated succesfully'), category='success')
 
            return redirect(url('users'))
 
                           
 
        except formencode.Invalid as errors:
 
            c.user = user_model.get_user(id)
 
            c.form_errors = errors.error_dict
 
            return htmlfill.render(
 
                 render('admin/users/user_edit.html'),
 
                defaults=errors.value,
 
                encoding="UTF-8")
 
    
 
    def delete(self, id):
 
        """DELETE /users/id: Delete an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="DELETE" />
 
        # Or using helpers:
 
        #    h.form(url('user', id=ID),
 
        #           method='delete')
 
        # url('user', id=ID)
 
        try:
 
            self.sa.delete(self.sa.query(User).get(id))
 
            self.sa.commit()
 
            h.flash(_('sucessfully deleted user'), category='success')
 
        except:
 
            self.sa.rollback()
 
            raise
 
        return redirect(url('users'))
 
        
 
    def show(self, id, format='html'):
 
        """GET /users/id: Show a specific item"""
 
        # url('user', id=ID)
 
    
 
    
 
    def edit(self, id, format='html'):
 
        """GET /users/id/edit: Form to edit an existing item"""
 
        # url('edit_user', id=ID)
 
        c.user = self.sa.query(User).get(id)
 
        defaults = c.user.__dict__
 
        return htmlfill.render(
 
            render('admin/users/user_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )    
pylons_app/lib/base.py
Show inline comments
 
"""The base Controller API
 

	
 
Provides the BaseController class for subclassing.
 
"""
 
from beaker.cache import cache_region
 
from pylons import config, tmpl_context as c, request, session
 
from pylons.controllers import WSGIController
 
from pylons.templating import render_mako as render
 
from pylons_app.lib.auth import LoginRequired, AuthUser
 
from pylons_app.lib.utils import get_repo_slug
 
from pylons_app.model import meta
 
from pylons_app.model.hg_model import HgModel
 
from pylons_app.model.hg_model import _get_repos_cached
 
from pylons_app import __version__
 

	
 
@cache_region('long_term', 'cached_repo_list')
 
def _get_repos_cached():
 
    return [rep for rep in HgModel().get_repos()]
 

	
 
@cache_region('long_term', 'full_changelog')
 
def _full_changelog_cached(repo_name):
 
    return list(reversed(list(HgModel().get_repo(repo_name))))  
 

	
 
class BaseController(WSGIController):
 
    
 
    def __before__(self):
 
        c.hg_app_version = __version__
 
        c.repos_prefix = config['hg_app_name']
 
        c.repo_name = get_repo_slug(request)
 
        c.hg_app_user = session.get('hg_app_user', AuthUser())
 
        c.cached_repo_list = _get_repos_cached()
 
        self.sa = meta.Session
 
    
 
    def __call__(self, environ, start_response):
 
        """Invoke the Controller"""
 
        # WSGIController.__call__ dispatches to the Controller method
 
        # the request is routed to. This routing information is
 
        # available in environ['pylons.routes_dict']
 
        try:
 
            return WSGIController.__call__(self, environ, start_response)
 
        finally:
 
            meta.Session.remove()
pylons_app/lib/utils.py
Show inline comments
 
import os
 
import logging
 
from mercurial import ui, config, hg
 
from mercurial.error import RepoError
 
log = logging.getLogger(__name__)
 

	
 

	
 
def get_repo_slug(request):
 
    path_info = request.environ.get('PATH_INFO')
 
    uri_lst = path_info.split('/')   
 
    repo_name = uri_lst[1]
 
    return repo_name
 

	
 
def is_mercurial(environ):
 
    """
 
    Returns True if request's target is mercurial server - header
 
    ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
 
    """
 
    http_accept = environ.get('HTTP_ACCEPT')
 
    if http_accept and http_accept.startswith('application/mercurial'):
 
        return True
 
    return False
 

	
 
def check_repo_dir(paths):
 
    repos_path = paths[0][1].split('/')
 
    if repos_path[-1] in ['*', '**']:
 
        repos_path = repos_path[:-1]
 
    if repos_path[0] != '/':
 
        repos_path[0] = '/'
 
    if not os.path.isdir(os.path.join(*repos_path)):
 
        raise Exception('Not a valid repository in %s' % paths[0][1])
 

	
 
def check_repo(repo_name, base_path):
 

	
 
    repo_path = os.path.join(base_path, repo_name)
 

	
 
    try:
 
        r = hg.repository(ui.ui(), repo_path)
 
        hg.verify(r)
 
        #here we hnow that repo exists it was verified
 
        log.info('%s repo is already created', repo_name)
 
        return False
 
        #raise Exception('Repo exists')
 
    except RepoError:
 
        log.info('%s repo is free for creation', repo_name)
 
        #it means that there is no valid repo there...
 
        return True
 
                
 
def make_ui(path=None, checkpaths=True):        
 
    """
 
    A funcion that will read python rc files and make an ui from read options
 
    
 
    @param path: path to mercurial config file
 
    """
 
    if not path:
 
        log.error('repos config path is empty !')
 
    
 
    if not os.path.isfile(path):
 
        log.warning('Unable to read config file %s' % path)
 
        return False
 
    #propagated from mercurial documentation
 
    sections = [
 
                'alias',
 
                'auth',
 
                'decode/encode',
 
                'defaults',
 
                'diff',
 
                'email',
 
                'extensions',
 
                'format',
 
                'merge-patterns',
 
                'merge-tools',
 
                'hooks',
 
                'http_proxy',
 
                'smtp',
 
                'patch',
 
                'paths',
 
                'profiling',
 
                'server',
 
                'trusted',
 
                'ui',
 
                'web',
 
                ]
 

	
 
    baseui = ui.ui()
 
    cfg = config.config()
 
    cfg.read(path)
 
    if checkpaths:check_repo_dir(cfg.items('paths'))
 

	
 
    for section in sections:
 
        for k, v in cfg.items(section):
 
            baseui.setconfig(section, k, v)
 
    
 
    return baseui
 

	
 
def invalidate_cache(name, *args):
 
    """Invalidates given name cache"""
 
    
 
    from beaker.cache import region_invalidate
 
    log.info('INVALIDATING CACHE FOR %s', name)
 
    
 
    """propagate our arguments to make sure invalidation works. First
 
    argument has to be the name of cached func name give to cache decorator
 
    without that the invalidation would not work"""
 
    tmp = [name]
 
    tmp.extend(args)
 
    args = tuple(tmp)
 
    
 
    if name == 'cached_repo_list':
 
        from pylons_app.lib.base import _get_repos_cached
 
        from pylons_app.model.hg_model import _get_repos_cached
 
        region_invalidate(_get_repos_cached, None, *args)
 
        
 
    if name == 'full_changelog':
 
        from pylons_app.lib.base import _full_changelog_cached
 
        from pylons_app.model.hg_model import _full_changelog_cached
 
        region_invalidate(_full_changelog_cached, None, *args)
 
        
 
from vcs.backends.base import BaseChangeset
 
from vcs.utils.lazy import LazyProperty
 
class EmptyChangeset(BaseChangeset):
 
    
 
    revision = -1
 

	
 
    @LazyProperty
 
    def raw_id(self):
 
        """
 
        Returns raw string identifing this changeset, useful for web
 
        representation.
 
        """
 
        return '0' * 12
 

	
 

	
 
def repo2db_mapper():
 
    """
 
    put !
 
    """
 
    pass
 
    #scann all dirs for .hgdbid
 
    #if some dir doesn't have one generate one.
 
    #
 
    
 
    
 
    
 
    
 
    
pylons_app/model/hg_model.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
#
 
# Copyright (c) 2010 marcink.  All rights reserved.
 
#
 
from vcs.exceptions import RepositoryError
 
'''
 
Created on Apr 9, 2010
 

	
 
@author: marcink
 
'''
 

	
 
from beaker.cache import cache_region
 
from mercurial import ui
 
from mercurial.hgweb.hgwebdir_mod import findrepos
 
from pylons import app_globals as g
 
from vcs.exceptions import RepositoryError, VCSError
 
import logging
 
import os
 
from pylons import tmpl_context as c, app_globals as g, session, request, config
 
from pylons.controllers.util import abort
 
import sys
 
log = logging.getLogger(__name__)
 

	
 
try:
 
    from vcs.backends.hg import get_repositories, MercurialRepository
 
    from vcs.backends.hg import MercurialRepository
 
except ImportError:
 
    sys.stderr.write('You have to import vcs module')
 
    raise Exception('Unable to import vcs')
 

	
 

	
 
@cache_region('long_term', 'cached_repo_list')
 
def _get_repos_cached():
 
    """
 
    return cached dict with repos
 
    """
 
    return HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
 

	
 
@cache_region('long_term', 'full_changelog')
 
def _full_changelog_cached(repo_name):
 
    log.info('getting full changelog for %s', repo_name)
 
    return list(reversed(list(HgModel().get_repo(repo_name))))
 

	
 
class HgModel(object):
 
    """
 
    Mercurial Model
 
    """
 

	
 

	
 
    def __init__(self):
 
        """
 
        Constructor
 
        """
 
        pass
 

	
 
    
 
    @staticmethod
 
    def repo_scan(repos_prefix, repos_path, baseui):
 
        """
 
        Listing of repositories in given path. This path should not be a 
 
        repository itself. Return a dictionary of repository objects
 
        :param repos_path: path to directory it could take syntax with 
 
        * or ** for deep recursive displaying repositories
 
        """
 
        def check_repo_dir(path):
 
            """
 
            Checks the repository
 
            :param path:
 
            """
 
            repos_path = path.split('/')
 
            if repos_path[-1] in ['*', '**']:
 
                repos_path = repos_path[:-1]
 
            if repos_path[0] != '/':
 
                repos_path[0] = '/'
 
            if not os.path.isdir(os.path.join(*repos_path)):
 
                raise RepositoryError('Not a valid repository in %s' % path[0][1])        
 
        if not repos_path.endswith('*'):
 
            raise VCSError('You need to specify * or ** at the end of path '
 
                            'for recursive scanning')
 
            
 
        check_repo_dir(repos_path)
 
        log.info('scanning for repositories in %s', repos_path)
 
        repos = findrepos([(repos_prefix, repos_path)])
 
        if not isinstance(baseui, ui.ui):
 
            baseui = ui.ui()
 
    
 
        repos_list = {}
 
        for name, path in repos:
 
            try:
 
                repos_list[name] = MercurialRepository(path, baseui=baseui)
 
            except OSError:
 
                continue
 
        return repos_list
 
        
 
    def get_repos(self):
 
        for mercurial_repo in get_repositories(g.paths[0][0], g.paths[0][1], g.baseui):
 
            
 
            if mercurial_repo._get_hidden():
 
        for name, repo in _get_repos_cached().items():
 
            if repo._get_hidden():
 
                #skip hidden web repository
 
                continue
 
            
 
            last_change = mercurial_repo.last_change
 
            last_change = repo.last_change
 
            try:
 
                tip = mercurial_repo.get_changeset('tip')
 
                tip = repo.get_changeset('tip')
 
            except RepositoryError:
 
                from pylons_app.lib.utils import EmptyChangeset
 
                tip = EmptyChangeset()
 
                
 
            tmp_d = {}
 
            tmp_d['name'] = mercurial_repo.name
 
            tmp_d['name'] = repo.name
 
            tmp_d['name_sort'] = tmp_d['name'].lower()
 
            tmp_d['description'] = mercurial_repo.description
 
            tmp_d['description'] = repo.description
 
            tmp_d['description_sort'] = tmp_d['description']
 
            tmp_d['last_change'] = last_change
 
            tmp_d['last_change_sort'] = last_change[1] - last_change[0]
 
            tmp_d['tip'] = tip.raw_id
 
            tmp_d['tip_sort'] = tip.revision 
 
            tmp_d['rev'] = tip.revision
 
            tmp_d['contact'] = mercurial_repo.contact
 
            tmp_d['contact'] = repo.contact
 
            tmp_d['contact_sort'] = tmp_d['contact']
 
            tmp_d['repo_archives'] = list(mercurial_repo._get_archives())
 
            tmp_d['repo_archives'] = list(repo._get_archives())
 
            
 
            yield tmp_d
 

	
 
    def get_repo(self, repo_name):
 
        path = g.paths[0][1].replace('*', '')
 
        repo = MercurialRepository(os.path.join(path, repo_name), baseui=g.baseui)
 
        return repo
 
        return _get_repos_cached()[repo_name]
pylons_app/templates/base/base.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
 
<head>
 
    <link rel="icon" href="/images/hgicon.png" type="image/png" />
 
    <meta name="robots" content="index, nofollow"/>
 
    <title>${next.title()}</title>
 
    ##For future use yui reset for cross browser compatability.
 
    ##<link rel="stylesheet" href="/js/yui/reset-fonts-grids/reset-fonts-grids.css" type="text/css" />
 
    ${self.css()}
 
    ${self.js()}
 
</head>
 

	
 
<body class="mainbody">
 
<div id="container">
 
    <div class="page-header">
 
        <h1>${next.breadcrumbs()}</h1>
 
        ${self.page_nav()}
 
    <div class="flash_msg">
 
    <% messages = h.flash.pop_messages() %>
 
		% if messages:
 
		<ul id="flash-messages">
 
		    % for message in messages:
 
		    <li class="${message.category}_msg">${message}</li>
 
		    % endfor
 
		</ul>
 
		% endif
 
    </div>        
 
    <div id="main"> 
 
    	${next.main()}
 
    </div>
 
    <div class="page-footer">
 
        Hg App ${c.hg_app_version} &copy; 2010 by Marcin Kuzminski
 
    </div>   
 

	
 
    <div id="powered-by">
 
        <p>
 
        <a href="http://mercurial.selenic.com/" title="Mercurial">
 
            <img src="/images/hglogo.png" width="75" height="90" alt="mercurial"/></a>
 
        </p>
 
    </div>
 

	
 
    <div id="corner-top-left"></div>
 
    <div id="corner-top-right"></div>
 
    <div id="corner-bottom-left"></div>
 
    <div id="corner-bottom-right"></div>
 

	
 
</div>
 
</body>
 
</html>
 

	
 
### MAKO DEFS ### 
 

	
 
<%def name="page_nav()">
 
	${self.menu()}
 
	${self.submenu()}
 
</%def>
 

	
 
<%def name="menu(current)">
 
<% 
 
def is_current(selected):
 
	if selected == current:
 
		return "class='current'"
 
%>
 
		%if current not in ['home','admin']:
 
		##regular menu
 
	       <script type="text/javascript">
 
	       	YAHOO.util.Event.onDOMReady(function(){
 
				YAHOO.util.Event.addListener('repo_switcher','click',function(){
 
					if(YAHOO.util.Dom.hasClass('repo_switcher','selected')){
 
						YAHOO.util.Dom.setStyle('switch_repos','display','none');
 
						YAHOO.util.Dom.setStyle('repo_switcher','background','');
 
						YAHOO.util.Dom.removeClass('repo_switcher','selected');
 
					}
 
					else{
 
						YAHOO.util.Dom.setStyle('switch_repos','display','');
 
						YAHOO.util.Dom.setStyle('repo_switcher','background','#FFFFFF');
 
						YAHOO.util.Dom.setStyle('repo_switcher','color','#556CB5');
 
						YAHOO.util.Dom.addClass('repo_switcher','selected');
 
					}
 
					});
 
				YAHOO.util.Event.addListener('repos_list','change',function(e){
 
		            var wa = YAHOO.util.Dom.get('repos_list').value;
 
		        	
 
		            var url = "${h.url('summary_home',repo_name='__REPLACE__')}".replace('__REPLACE__',wa);
 
			        window.location = url;
 
				})
 
	           });
 
	       	</script>       	
 
	        <ul class="page-nav">
 
				<li>
 
					<a id="repo_switcher" title="${_('Switch repository')}" href="#">&darr;</a>
 
					<div id="switch_repos" style="display:none;position: absolute;width: 150px;height: 25px">
 
						<select id="repos_list" size="=10">
 
						%for repo in c.cached_repo_list:
 
							<option value="${repo['name']}">${repo['name']}</option>
 
						%for repo in c.cached_repo_list.values():
 
							<option value="${repo.name}">${repo.name}</option>
 
						%endfor
 
						</select>
 
					</div>			
 
				</li>
 
	            <li ${is_current('summary')}>${h.link_to(_('summary'),h.url('summary_home',repo_name=c.repo_name))}</li>
 
	            <li ${is_current('shortlog')}>${h.link_to(_('shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}</li>
 
				<li ${is_current('changelog')}>${h.link_to(_('changelog'),h.url('changelog_home',repo_name=c.repo_name))}</li>            
 
	            <li ${is_current('branches')}>${h.link_to(_('branches'),h.url('branches_home',repo_name=c.repo_name))}</li>
 
	            <li ${is_current('tags')}>${h.link_to(_('tags'),h.url('tags_home',repo_name=c.repo_name))}</li>
 
	            <li ${is_current('files')}>${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name))}</li>
 
	        </ul>
 
		%else:
 
		##Root menu
 
			<ul class="page-nav">
 
				<li ${is_current('home')}>${h.link_to(_('Home'),h.url('/'))}</li>
 
				<li ${is_current('admin')}>${h.link_to(_('Admin'),h.url('admin_home'))}</li>
 
				<li class="logout">${h.link_to(u'Logout',h.url('logout_home'))}</li>
 
			</ul>
 
		%endif    
 
		</div>
 
</%def>
 
<%def name="submenu(current=None)">
 
	<% 
 
	def is_current(selected):
 
		if selected == current:
 
			return "class='current_submenu'"
 
	%>
 
	%if current != None:
 
	<div>
 
    <ul class="submenu">
 
        <li ${is_current('repos')}>${h.link_to(u'repos',h.url('repos'),class_='repos')}</li>
 
        <li ${is_current('users')}>${h.link_to(u'users',h.url('users'),class_='users')}</li>
 
        <li ${is_current('permissions')}>${h.link_to(u'permissions',h.url('permissions'),class_='permissions')}</li>
 
    </ul>
 
    </div>
 
    %endif
 
</%def>
 

	
 

	
 
<%def name="css()">
 
<link rel="stylesheet" href="/css/monoblue_custom.css" type="text/css" />
 
</%def>
 

	
 
<%def name="js()">
 
<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
 
</%def>
 

	
 
<!-- DEFINITION OF FORM ERROR FETCHER -->
 
<%def name="get_form_error(element)">
 
	%if hasattr(c,'form_errors') and type(c.form_errors) == dict:
 
        %if c.form_errors.get(element,False):
 
            <span class="error-message">
 
                ${c.form_errors.get(element,'')}
 
            </span>
 
        %endif
 
	%endif           
 
</%def>
 
\ No newline at end of file
0 comments (0 inline, 0 general)