Changeset - fb7f066126cc
[Not reviewed]
default
0 5 0
Marcin Kuzminski - 15 years ago 2010-06-03 20:28:46
marcin@python-works.com
Added support for repository located in subdirectories.
5 files changed with 57 insertions and 32 deletions:
0 comments (0 inline, 0 general)
pylons_app/config/routing.py
Show inline comments
 
@@ -13,55 +13,79 @@ def make_map(config):
 
    map.minimization = False
 
    map.explicit = False
 

	
 
    # The ErrorController route (handles 404/500 error pages); it should
 
    # likely stay at the top, ensuring it can always be resolved
 
    map.connect('/error/{action}', controller='error')
 
    map.connect('/error/{action}/{id}', controller='error')
 

	
 
    # CUSTOM ROUTES HERE
 
    map.connect('hg_home', '/', controller='hg', action='index')
 
    
 
    
 
    #REST controllers
 
    map.resource('repo', 'repos', path_prefix='/_admin')
 
    #REST routes
 
    with map.submapper(path_prefix='/_admin', controller='repos') as m:
 
        m.connect("repos", "/repos",
 
             action="create", conditions=dict(method=["POST"]))
 
        m.connect("repos", "/repos",
 
             action="index", conditions=dict(method=["GET"]))
 
        m.connect("formatted_repos", "/repos.{format}",
 
             action="index",
 
            conditions=dict(method=["GET"]))
 
        m.connect("new_repo", "/repos/new",
 
             action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_new_repo", "/repos/new.{format}",
 
             action="new", conditions=dict(method=["GET"]))
 
        m.connect("/repos/{id:.*}",
 
             action="update", conditions=dict(method=["PUT"]))
 
        m.connect("/repos/{id:.*}",
 
             action="delete", conditions=dict(method=["DELETE"]))
 
        m.connect("edit_repo", "/repos/{id:.*}/edit",
 
             action="edit", conditions=dict(method=["GET"]))
 
        m.connect("formatted_edit_repo", "/repos/{id:.*}.{format}/edit",
 
             action="edit", conditions=dict(method=["GET"]))
 
        m.connect("repo", "/repos/{id:.*}",
 
             action="show", conditions=dict(method=["GET"]))
 
        m.connect("formatted_repo", "/repos/{id:.*}.{format}",
 
             action="show", conditions=dict(method=["GET"]))
 

	
 
    map.resource('user', 'users', path_prefix='/_admin')
 
    map.resource('permission', 'permissions', path_prefix='/_admin')
 
    
 
    #ADMIN
 
    with map.submapper(path_prefix='/_admin', controller='admin') as m:
 
        m.connect('admin_home', '/', action='index')#main page
 
        m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
 
                  action='add_repo')
 
    
 
    #FEEDS
 
    map.connect('rss_feed_home', '/{repo_name}/feed/rss',
 
    map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
 
                controller='feed', action='rss')
 
    map.connect('atom_feed_home', '/{repo_name}/feed/atom',
 
    map.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
 
                controller='feed', action='atom')
 
    
 
    map.connect('login_home', '/login', controller='login')
 
    map.connect('logout_home', '/logout', controller='login', action='logout')
 
    
 
    map.connect('changeset_home', '/{repo_name}/changeset/{revision}',
 
    map.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
 
                controller='changeset', revision='tip')
 
    map.connect('summary_home', '/{repo_name}/summary',
 
    map.connect('summary_home', '/{repo_name:.*}/summary',
 
                controller='summary')
 
    map.connect('shortlog_home', '/{repo_name}/shortlog',
 
    map.connect('shortlog_home', '/{repo_name:.*}/shortlog',
 
                controller='shortlog')
 
    map.connect('branches_home', '/{repo_name}/branches',
 
    map.connect('branches_home', '/{repo_name:.*}/branches',
 
                controller='branches')
 
    map.connect('tags_home', '/{repo_name}/tags',
 
    map.connect('tags_home', '/{repo_name:.*}/tags',
 
                controller='tags')
 
    map.connect('changelog_home', '/{repo_name}/changelog',
 
    map.connect('changelog_home', '/{repo_name:.*}/changelog',
 
                controller='changelog')    
 
    map.connect('files_home', '/{repo_name}/files/{revision}/{f_path:.*}',
 
    map.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
 
                controller='files', revision='tip', f_path='')
 
    map.connect('files_diff_home', '/{repo_name}/diff/{f_path:.*}',
 
    map.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
 
                controller='files', action='diff', revision='tip', f_path='')
 
    map.connect('files_raw_home', '/{repo_name}/rawfile/{revision}/{f_path:.*}',
 
    map.connect('files_raw_home', '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
 
                controller='files', action='rawfile', revision='tip', f_path='')
 
    map.connect('files_annotate_home', '/{repo_name}/annotate/{revision}/{f_path:.*}',
 
    map.connect('files_annotate_home', '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
 
                controller='files', action='annotate', revision='tip', f_path='')    
 
    map.connect('files_archive_home', '/{repo_name}/archive/{revision}/{fileformat}',
 
    map.connect('files_archive_home', '/{repo_name:.*}/archive/{revision}/{fileformat}',
 
                controller='files', action='archivefile', revision='tip')
 
    return map
pylons_app/controllers/repos.py
Show inline comments
 
from pylons import request, response, session, tmpl_context as c, url, \
 
    app_globals as g
 
from pylons.controllers.util import abort, redirect
 
from pylons_app.lib.auth import LoginRequired
 
from pylons.i18n.translation import _
 
from pylons_app.lib import helpers as h
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.lib.filters import clean_repo
 
from pylons_app.lib.utils import check_repo, invalidate_cache
 
from pylons_app.model.hg_model import HgModel
 
import logging
 
import os
 
import shutil
 
from operator import itemgetter
 
log = logging.getLogger(__name__)
 

	
 
class ReposController(BaseController):
 
    """REST Controller styled on the Atom Publishing Protocol"""
 
@@ -30,24 +32,25 @@ class ReposController(BaseController):
 
        c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
 
        return render('admin/repos/repos.html')
 
    
 
    def create(self):
 
        """POST /repos: Create a new item"""
 
        # url('repos')
 
        name = request.POST.get('name')
 

	
 
        try:
 
            self._create_repo(name)
 
            #clear our cached list for refresh with new repo
 
            invalidate_cache('cached_repo_list')
 
            h.flash(_('created repository %s') % name, category='success')
 
        except Exception as e:
 
            log.error(e)
 
        
 
        return redirect('repos')
 
        
 
    def _create_repo(self, repo_name):        
 
        repo_path = os.path.join(g.base_path, repo_name)
 
        if check_repo(repo_name, g.base_path):
 
            log.info('creating repo %s in %s', repo_name, repo_path)
 
            from vcs.backends.hg import MercurialRepository
 
            MercurialRepository(repo_path, create=True)
 
                        
 
@@ -76,25 +79,25 @@ class ReposController(BaseController):
 
        #    h.form(url('repo', id=ID),
 
        #           method='delete')
 
        # url('repo', id=ID)
 
        from datetime import datetime
 
        path = g.paths[0][1].replace('*', '')
 
        rm_path = os.path.join(path, id)
 
        log.info("Removing %s", rm_path)
 
        shutil.move(os.path.join(rm_path, '.hg'), os.path.join(rm_path, 'rm__.hg'))
 
        shutil.move(rm_path, os.path.join(path, 'rm__%s-%s' % (datetime.today(), id)))
 
        
 
        #clear our cached list for refresh with new repo
 
        invalidate_cache('cached_repo_list')
 
                    
 
        h.flash(_('deleted repository %s') % rm_path, category='success')            
 
        return redirect(url('repos'))
 
        
 

	
 
    def show(self, id, format='html'):
 
        """GET /repos/id: Show a specific item"""
 
        # url('repo', id=ID)
 
        
 
    def edit(self, id, format='html'):
 
        """GET /repos/id/edit: Form to edit an existing item"""
 
        # url('edit_repo', id=ID)
 
        c.new_repo = id
 
        return render('admin/repos/repo_edit.html')
pylons_app/lib/middleware/simplehg.py
Show inline comments
 
@@ -41,37 +41,39 @@ class SimpleHg(object):
 
            # AUTHENTICATE THIS MERCURIAL REQUEST
 
            #===================================================================
 
            username = REMOTE_USER(environ)
 
            if not username:
 
                result = self.authenticate(environ)
 
                if isinstance(result, str):
 
                    AUTH_TYPE.update(environ, 'basic')
 
                    REMOTE_USER.update(environ, result)
 
                else:
 
                    return result.wsgi_application(environ, start_response)
 
            
 
            try:
 
                repo_name = environ['PATH_INFO'].split('/')[1]
 
            except:
 
                repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
 
            except Exception as e:
 
                log.error(e)
 
                return HTTPNotFound()(environ, start_response)
 
            
 
            #since we wrap into hgweb, just reset the path
 
            environ['PATH_INFO'] = '/'
 
            self.baseui = make_ui(self.config['hg_app_repo_conf'])
 
            self.basepath = self.baseui.configitems('paths')[0][1]\
 
                                                            .replace('*', '')
 
            self.repo_path = os.path.join(self.basepath, repo_name)
 
            try:
 
                app = wsgiapplication(self.__make_app)
 
            except Exception as e:
 
                log.error(e)
 
                return HTTPNotFound()(environ, start_response)
 
            action = self.__get_action(environ)            
 
            #invalidate cache on push
 
            if action == 'push':
 
                self.__invalidate_cache(repo_name)
 
            
 
            if action:
 
                username = self.__get_environ_user(environ)
 
                self.__log_user_action(username, action, repo_name)
 
                         
 
            return app(environ, start_response)            
 

	
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
 
    return request.environ['pylons.routes_dict'].get('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):
 
@@ -122,23 +119,16 @@ class EmptyChangeset(BaseChangeset):
 

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

	
 

	
 
def repo2db_mapper():
 
    """
 
    put !
 
    scann all dirs for .hgdbid
 
    if some dir doesn't have one generate one.
 
    """
 
    pass
 
    #scann all dirs for .hgdbid
 
    #if some dir doesn't have one generate one.
 
    #
 
    
 
    
 
    
 
    
 
    
 
    pass
 
\ No newline at end of file
pylons_app/model/hg_model.py
Show inline comments
 
@@ -73,25 +73,31 @@ class HgModel(object):
 
            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:
 
                #name = name.split('/')[-1]
 
                if repos_list.has_key(name):
 
                    raise RepositoryError('Duplicate repository name %s found in'
 
                                    ' %s' % (name, path))
 
                else:
 
                repos_list[name] = MercurialRepository(path, baseui=baseui)
 
                    repos_list[name].name = name
 
            except OSError:
 
                continue
 
        return repos_list
 
        
 
    def get_repos(self):
 
        for name, repo in _get_repos_cached().items():
 
            if repo._get_hidden():
 
                #skip hidden web repository
 
                continue
 
            
 
            last_change = repo.last_change
 
            try:
0 comments (0 inline, 0 general)