##// END OF EJS Templates
added version generation to pylons_app and showed it into template. Propagated baseController with some data for acces into each controller. Fixed simplehg middleware to get proper name of application
marcink -
r185:3380ca40 default
parent child Browse files
Show More
@@ -0,0 +1,13 b''
1 """
2 Hg app, a web based mercurial repository managment based on pylons
3 """
4
5 VERSION = (0, 6, 0, 'beta')
6
7 __version__ = '.'.join((str(each) for each in VERSION[:4]))
8
9 def get_version():
10 """
11 Returns shorter version (digit parts only) as string.
12 """
13 return '.'.join((str(each) for each in VERSION[:3]))
@@ -1,28 +1,37 b''
1 """The base Controller API
1 """The base Controller API
2
2
3 Provides the BaseController class for subclassing.
3 Provides the BaseController class for subclassing.
4 """
4 """
5 from beaker.cache import cache_region
6 from pylons import config, tmpl_context as c, request, session
5 from pylons.controllers import WSGIController
7 from pylons.controllers import WSGIController
6 from pylons.templating import render_mako as render
8 from pylons.templating import render_mako as render
9 from pylons_app.lib.auth import LoginRequired, AuthUser
10 from pylons_app.lib.utils import get_repo_slug
7 from pylons_app.model import meta
11 from pylons_app.model import meta
8 from beaker.cache import cache_region
9 from pylons import tmpl_context as c
10 from pylons_app.model.hg_model import HgModel
12 from pylons_app.model.hg_model import HgModel
13 from pylons_app import get_version
11
14
12 @cache_region('long_term', 'cached_repo_list')
15 @cache_region('long_term', 'cached_repo_list')
13 def _get_repos_cached():
16 def _get_repos_cached():
14 return [rep for rep in HgModel().get_repos()]
17 return [rep for rep in HgModel().get_repos()]
15
18
16 class BaseController(WSGIController):
19 class BaseController(WSGIController):
17
20
21 def __before__(self):
22 c.hg_app_version = get_version()
23 c.repos_prefix = config['hg_app_name']
24 c.repo_name = get_repo_slug(request)
25 c.hg_app_user = session.get('hg_app_user', AuthUser())
26 c.cached_repo_list = _get_repos_cached()
27 self.sa = meta.Session
28
18 def __call__(self, environ, start_response):
29 def __call__(self, environ, start_response):
19 """Invoke the Controller"""
30 """Invoke the Controller"""
20 # WSGIController.__call__ dispatches to the Controller method
31 # WSGIController.__call__ dispatches to the Controller method
21 # the request is routed to. This routing information is
32 # the request is routed to. This routing information is
22 # available in environ['pylons.routes_dict']
33 # available in environ['pylons.routes_dict']
23 c.cached_repo_list = _get_repos_cached()
24 self.sa = meta.Session
25 try:
34 try:
26 return WSGIController.__call__(self, environ, start_response)
35 return WSGIController.__call__(self, environ, start_response)
27 finally:
36 finally:
28 meta.Session.remove()
37 meta.Session.remove()
@@ -1,86 +1,86 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 #
3 #
4 # Copyright (c) 2010 marcink. All rights reserved.
4 # Copyright (c) 2010 marcink. All rights reserved.
5 #
5 #
6 """
6 """
7 Created on 2010-04-28
7 Created on 2010-04-28
8
8
9 @author: marcink
9 @author: marcink
10 SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
10 SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
11 It's implemented with basic auth function
11 It's implemented with basic auth function
12 """
12 """
13
13
14 from mercurial.hgweb import hgweb
14 from mercurial.hgweb import hgweb
15 from mercurial.hgweb.request import wsgiapplication
15 from mercurial.hgweb.request import wsgiapplication
16 from paste.auth.basic import AuthBasicAuthenticator
16 from paste.auth.basic import AuthBasicAuthenticator
17 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
17 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
18 from pylons_app.lib.utils import is_mercurial
18 from pylons_app.lib.utils import is_mercurial
19 from pylons_app.lib.auth import authfunc
19 from pylons_app.lib.auth import authfunc
20 from pylons_app.lib.utils import make_ui, invalidate_cache
20 from pylons_app.lib.utils import make_ui, invalidate_cache
21 from webob.exc import HTTPNotFound
21 from webob.exc import HTTPNotFound
22 import os
22 import os
23
23
24 class SimpleHg(object):
24 class SimpleHg(object):
25
25
26 def __init__(self, application, config):
26 def __init__(self, application, config):
27 self.application = application
27 self.application = application
28 self.config = config
28 self.config = config
29 #authenticate this mercurial request using
29 #authenticate this mercurial request using
30 realm = '%s %s' % (config['repos_name'], 'mercurial repository')
30 realm = '%s %s' % (config['hg_app_name'], 'mercurial repository')
31 self.authenticate = AuthBasicAuthenticator(realm, authfunc)
31 self.authenticate = AuthBasicAuthenticator(realm, authfunc)
32
32
33 def __call__(self, environ, start_response):
33 def __call__(self, environ, start_response):
34 if not is_mercurial(environ):
34 if not is_mercurial(environ):
35 return self.application(environ, start_response)
35 return self.application(environ, start_response)
36 else:
36 else:
37 #===================================================================
37 #===================================================================
38 # AUTHENTICATE THIS MERCURIAL REQUEST
38 # AUTHENTICATE THIS MERCURIAL REQUEST
39 #===================================================================
39 #===================================================================
40 username = REMOTE_USER(environ)
40 username = REMOTE_USER(environ)
41 if not username:
41 if not username:
42 result = self.authenticate(environ)
42 result = self.authenticate(environ)
43 if isinstance(result, str):
43 if isinstance(result, str):
44 AUTH_TYPE.update(environ, 'basic')
44 AUTH_TYPE.update(environ, 'basic')
45 REMOTE_USER.update(environ, result)
45 REMOTE_USER.update(environ, result)
46 else:
46 else:
47 return result.wsgi_application(environ, start_response)
47 return result.wsgi_application(environ, start_response)
48
48
49 try:
49 try:
50 repo_name = environ['PATH_INFO'].split('/')[1]
50 repo_name = environ['PATH_INFO'].split('/')[1]
51 except:
51 except:
52 return HTTPNotFound()(environ, start_response)
52 return HTTPNotFound()(environ, start_response)
53
53
54 #since we wrap into hgweb, just reset the path
54 #since we wrap into hgweb, just reset the path
55 environ['PATH_INFO'] = '/'
55 environ['PATH_INFO'] = '/'
56 self.baseui = make_ui()
56 self.baseui = make_ui()
57 self.basepath = self.baseui.configitems('paths')[0][1]\
57 self.basepath = self.baseui.configitems('paths')[0][1]\
58 .replace('*', '')
58 .replace('*', '')
59 self.repo_path = os.path.join(self.basepath, repo_name)
59 self.repo_path = os.path.join(self.basepath, repo_name)
60 try:
60 try:
61 app = wsgiapplication(self._make_app)
61 app = wsgiapplication(self._make_app)
62 except Exception as e:
62 except Exception as e:
63 return HTTPNotFound()(environ, start_response)
63 return HTTPNotFound()(environ, start_response)
64
64
65 """we know that some change was made to repositories and we should
65 """we know that some change was made to repositories and we should
66 invalidate the cache to see the changes right away"""
66 invalidate the cache to see the changes right away"""
67 invalidate_cache('full_changelog', repo_name)
67 invalidate_cache('full_changelog', repo_name)
68 return app(environ, start_response)
68 return app(environ, start_response)
69
69
70 def _make_app(self):
70 def _make_app(self):
71 hgserve = hgweb(self.repo_path)
71 hgserve = hgweb(self.repo_path)
72 return self.load_web_settings(hgserve)
72 return self.load_web_settings(hgserve)
73
73
74
74
75 def load_web_settings(self, hgserve):
75 def load_web_settings(self, hgserve):
76 repoui = make_ui(os.path.join(self.repo_path, '.hg', 'hgrc'), False)
76 repoui = make_ui(os.path.join(self.repo_path, '.hg', 'hgrc'), False)
77 #set the global ui for hgserve
77 #set the global ui for hgserve
78 hgserve.repo.ui = self.baseui
78 hgserve.repo.ui = self.baseui
79
79
80 if repoui:
80 if repoui:
81 #set the repository based config
81 #set the repository based config
82 hgserve.repo.ui = repoui
82 hgserve.repo.ui = repoui
83
83
84 return hgserve
84 return hgserve
85
85
86
86
@@ -1,121 +1,121 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 <head>
4 <head>
5 <link rel="icon" href="/images/hgicon.png" type="image/png" />
5 <link rel="icon" href="/images/hgicon.png" type="image/png" />
6 <meta name="robots" content="index, nofollow"/>
6 <meta name="robots" content="index, nofollow"/>
7 <title>${next.title()}</title>
7 <title>${next.title()}</title>
8 ##<link rel="stylesheet" href="/js/yui/reset-fonts-grids/reset-fonts-grids.css" type="text/css" />
8 ##<link rel="stylesheet" href="/js/yui/reset-fonts-grids/reset-fonts-grids.css" type="text/css" />
9 ${self.css()}
9 ${self.css()}
10 ${self.js()}
10 ${self.js()}
11 </head>
11 </head>
12
12
13 <body class="mainbody">
13 <body class="mainbody">
14 <div id="container">
14 <div id="container">
15 <div class="page-header">
15 <div class="page-header">
16 <h1>${next.breadcrumbs()}</h1>
16 <h1>${next.breadcrumbs()}</h1>
17 ${self.page_nav()}
17 ${self.page_nav()}
18 </div>
18 </div>
19 <div id="main">
19 <div id="main">
20 ${next.main()}
20 ${next.main()}
21 </div>
21 </div>
22 <div class="page-footer">
22 <div class="page-footer">
23 Mercurial App &copy; 2010
23 Hg App ${c.hg_app_version} &copy; 2010
24 </div>
24 </div>
25
25
26 <div id="powered-by">
26 <div id="powered-by">
27 <p>
27 <p>
28 <a href="http://mercurial.selenic.com/" title="Mercurial">
28 <a href="http://mercurial.selenic.com/" title="Mercurial">
29 <img src="/images/hglogo.png" width="75" height="90" alt="mercurial"/></a>
29 <img src="/images/hglogo.png" width="75" height="90" alt="mercurial"/></a>
30 </p>
30 </p>
31 </div>
31 </div>
32
32
33 <div id="corner-top-left"></div>
33 <div id="corner-top-left"></div>
34 <div id="corner-top-right"></div>
34 <div id="corner-top-right"></div>
35 <div id="corner-bottom-left"></div>
35 <div id="corner-bottom-left"></div>
36 <div id="corner-bottom-right"></div>
36 <div id="corner-bottom-right"></div>
37
37
38 </div>
38 </div>
39 </body>
39 </body>
40 </html>
40 </html>
41
41
42 ### MAKO DEFS ###
42 ### MAKO DEFS ###
43
43
44 <%def name="page_nav()">
44 <%def name="page_nav()">
45 ${self.menu()}
45 ${self.menu()}
46 </%def>
46 </%def>
47
47
48 <%def name="menu(current)">
48 <%def name="menu(current)">
49 <%
49 <%
50 def is_current(selected):
50 def is_current(selected):
51 if selected == current:
51 if selected == current:
52 return 'class=current'
52 return 'class=current'
53 %>
53 %>
54 %if current not in ['home','admin']:
54 %if current not in ['home','admin']:
55 <script type="text/javascript">
55 <script type="text/javascript">
56 YAHOO.util.Event.onDOMReady(function(){
56 YAHOO.util.Event.onDOMReady(function(){
57 YAHOO.util.Event.addListener('repo_switcher','click',function(){
57 YAHOO.util.Event.addListener('repo_switcher','click',function(){
58 if(YAHOO.util.Dom.hasClass('repo_switcher','selected')){
58 if(YAHOO.util.Dom.hasClass('repo_switcher','selected')){
59 YAHOO.util.Dom.setStyle('switch_repos','display','none');
59 YAHOO.util.Dom.setStyle('switch_repos','display','none');
60 YAHOO.util.Dom.setStyle('repo_switcher','background','');
60 YAHOO.util.Dom.setStyle('repo_switcher','background','');
61 YAHOO.util.Dom.removeClass('repo_switcher','selected');
61 YAHOO.util.Dom.removeClass('repo_switcher','selected');
62 }
62 }
63 else{
63 else{
64 YAHOO.util.Dom.setStyle('switch_repos','display','');
64 YAHOO.util.Dom.setStyle('switch_repos','display','');
65 YAHOO.util.Dom.setStyle('repo_switcher','background','#FFFFFF');
65 YAHOO.util.Dom.setStyle('repo_switcher','background','#FFFFFF');
66 YAHOO.util.Dom.addClass('repo_switcher','selected');
66 YAHOO.util.Dom.addClass('repo_switcher','selected');
67 }
67 }
68 });
68 });
69 YAHOO.util.Event.addListener('repos_list','change',function(e){
69 YAHOO.util.Event.addListener('repos_list','change',function(e){
70 var wa = YAHOO.util.Dom.get('repos_list').value;
70 var wa = YAHOO.util.Dom.get('repos_list').value;
71
71
72 var url = "${h.url('summary_home',repo_name='__REPLACE__')}".replace('__REPLACE__',wa);
72 var url = "${h.url('summary_home',repo_name='__REPLACE__')}".replace('__REPLACE__',wa);
73 window.location = url;
73 window.location = url;
74 })
74 })
75 });
75 });
76 </script>
76 </script>
77 <ul class="page-nav">
77 <ul class="page-nav">
78 <li>
78 <li>
79 <a id="repo_switcher" title="${_('Switch repository')}" href="#">&darr;</a>
79 <a id="repo_switcher" title="${_('Switch repository')}" href="#">&darr;</a>
80 <div id="switch_repos" style="display:none;position: absolute;width: 150px;height: 25px">
80 <div id="switch_repos" style="display:none;position: absolute;width: 150px;height: 25px">
81 <select id="repos_list" size="=10">
81 <select id="repos_list" size="=10">
82 %for repo in c.cached_repo_list:
82 %for repo in c.cached_repo_list:
83 <option value="${repo['name']}">${repo['name']}</option>
83 <option value="${repo['name']}">${repo['name']}</option>
84 %endfor
84 %endfor
85 </select>
85 </select>
86 </div>
86 </div>
87 </li>
87 </li>
88 <li ${is_current('summary')}>${h.link_to(_('summary'),h.url('summary_home',repo_name=c.repo_name))}</li>
88 <li ${is_current('summary')}>${h.link_to(_('summary'),h.url('summary_home',repo_name=c.repo_name))}</li>
89 <li ${is_current('shortlog')}>${h.link_to(_('shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}</li>
89 <li ${is_current('shortlog')}>${h.link_to(_('shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}</li>
90 <li ${is_current('changelog')}>${h.link_to(_('changelog'),h.url('changelog_home',repo_name=c.repo_name))}</li>
90 <li ${is_current('changelog')}>${h.link_to(_('changelog'),h.url('changelog_home',repo_name=c.repo_name))}</li>
91 <li ${is_current('branches')}>${h.link_to(_('branches'),h.url('branches_home',repo_name=c.repo_name))}</li>
91 <li ${is_current('branches')}>${h.link_to(_('branches'),h.url('branches_home',repo_name=c.repo_name))}</li>
92 <li ${is_current('tags')}>${h.link_to(_('tags'),h.url('tags_home',repo_name=c.repo_name))}</li>
92 <li ${is_current('tags')}>${h.link_to(_('tags'),h.url('tags_home',repo_name=c.repo_name))}</li>
93 <li ${is_current('files')}>${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name))}</li>
93 <li ${is_current('files')}>${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name))}</li>
94 </ul>
94 </ul>
95 %else:
95 %else:
96 <ul class="page-nav">
96 <ul class="page-nav">
97 <li ${is_current('home')}>${h.link_to(_('Home'),h.url('/'))}</li>
97 <li ${is_current('home')}>${h.link_to(_('Home'),h.url('/'))}</li>
98 <li ${is_current('admin')}>${h.link_to(_('Admin'),h.url('admin_home'))}</li>
98 <li ${is_current('admin')}>${h.link_to(_('Admin'),h.url('admin_home'))}</li>
99 <li class="logout">${h.link_to(u'Logout',h.url('logout_home'))}</li>
99 <li class="logout">${h.link_to(u'Logout',h.url('logout_home'))}</li>
100 </ul>
100 </ul>
101 %endif
101 %endif
102 </%def>
102 </%def>
103
103
104 <%def name="css()">
104 <%def name="css()">
105 <link rel="stylesheet" href="/css/monoblue_custom.css" type="text/css" />
105 <link rel="stylesheet" href="/css/monoblue_custom.css" type="text/css" />
106 </%def>
106 </%def>
107
107
108 <%def name="js()">
108 <%def name="js()">
109 <script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
109 <script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
110 </%def>
110 </%def>
111
111
112 <!-- DEFINITION OF FORM ERROR FETCHER -->
112 <!-- DEFINITION OF FORM ERROR FETCHER -->
113 <%def name="get_form_error(element)">
113 <%def name="get_form_error(element)">
114 %if hasattr(c,'form_errors') and type(c.form_errors) == dict:
114 %if hasattr(c,'form_errors') and type(c.form_errors) == dict:
115 %if c.form_errors.get(element,False):
115 %if c.form_errors.get(element,False):
116 <span class="error-message">
116 <span class="error-message">
117 ${c.form_errors.get(element,'')}
117 ${c.form_errors.get(element,'')}
118 </span>
118 </span>
119 %endif
119 %endif
120 %endif
120 %endif
121 </%def> No newline at end of file
121 </%def>
@@ -1,40 +1,41 b''
1 from pylons_app import get_version
1 try:
2 try:
2 from setuptools import setup, find_packages
3 from setuptools import setup, find_packages
3 except ImportError:
4 except ImportError:
4 from ez_setup import use_setuptools
5 from ez_setup import use_setuptools
5 use_setuptools()
6 use_setuptools()
6 from setuptools import setup, find_packages
7 from setuptools import setup, find_packages
7
8
8 setup(
9 setup(
9 name='pylons_app',
10 name='pylons_app',
10 version='1.0',
11 version=get_version(),
11 description='',
12 description='',
12 author='marcin kuzminski',
13 author='marcin kuzminski',
13 author_email='marcin@python-blog.com',
14 author_email='marcin@python-blog.com',
14 url='',
15 url='',
15 install_requires=[
16 install_requires=[
16 "Pylons>=1.0.0",
17 "Pylons>=1.0.0",
17 "SQLAlchemy>=0.6",
18 "SQLAlchemy>=0.6",
18 "Mako>=0.3.2",
19 "Mako>=0.3.2",
19 "vcs>=0.1.1",
20 "vcs>=0.1.1",
20 "pygments>=1.3.0"
21 "pygments>=1.3.0"
21 ],
22 ],
22 setup_requires=["PasteScript>=1.6.3"],
23 setup_requires=["PasteScript>=1.6.3"],
23 packages=find_packages(exclude=['ez_setup']),
24 packages=find_packages(exclude=['ez_setup']),
24 include_package_data=True,
25 include_package_data=True,
25 test_suite='nose.collector',
26 test_suite='nose.collector',
26 package_data={'pylons_app': ['i18n/*/LC_MESSAGES/*.mo']},
27 package_data={'pylons_app': ['i18n/*/LC_MESSAGES/*.mo']},
27 message_extractors={'pylons_app': [
28 message_extractors={'pylons_app': [
28 ('**.py', 'python', None),
29 ('**.py', 'python', None),
29 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
30 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
30 ('public/**', 'ignore', None)]},
31 ('public/**', 'ignore', None)]},
31 zip_safe=False,
32 zip_safe=False,
32 paster_plugins=['PasteScript', 'Pylons'],
33 paster_plugins=['PasteScript', 'Pylons'],
33 entry_points="""
34 entry_points="""
34 [paste.app_factory]
35 [paste.app_factory]
35 main = pylons_app.config.middleware:make_app
36 main = pylons_app.config.middleware:make_app
36
37
37 [paste.app_install]
38 [paste.app_install]
38 main = pylons.util:PylonsInstaller
39 main = pylons.util:PylonsInstaller
39 """,
40 """,
40 )
41 )
General Comments 0
You need to be logged in to leave comments. Login now