Show More
@@ -0,0 +1,87 b'' | |||
|
1 | import logging | |
|
2 | ||
|
3 | from pylons import request, response, session, tmpl_context as c, url, app_globals as g | |
|
4 | from pylons.controllers.util import abort, redirect | |
|
5 | ||
|
6 | from pylons_app.lib.base import BaseController, render | |
|
7 | import os | |
|
8 | from mercurial import ui, hg | |
|
9 | from mercurial.error import RepoError | |
|
10 | from ConfigParser import ConfigParser | |
|
11 | log = logging.getLogger(__name__) | |
|
12 | ||
|
13 | class AdminController(BaseController): | |
|
14 | ||
|
15 | ||
|
16 | def __before__(self): | |
|
17 | c.staticurl = g.statics | |
|
18 | ||
|
19 | def index(self): | |
|
20 | # Return a rendered template | |
|
21 | return render('/admin.html') | |
|
22 | ||
|
23 | ||
|
24 | def manage_hgrc(self): | |
|
25 | pass | |
|
26 | ||
|
27 | def hgrc(self, dirname): | |
|
28 | filename = os.path.join(dirname, '.hg', 'hgrc') | |
|
29 | return filename | |
|
30 | ||
|
31 | def add_repo(self, new_repo): | |
|
32 | ||
|
33 | ||
|
34 | #extra check it can be add since it's the command | |
|
35 | if new_repo == 'add': | |
|
36 | c.msg = 'you basstard ! this repo is a command' | |
|
37 | c.new_repo = '' | |
|
38 | return render('add.html') | |
|
39 | ||
|
40 | new_repo = new_repo.replace(" ", "_") | |
|
41 | new_repo = new_repo.replace("-", "_") | |
|
42 | ||
|
43 | try: | |
|
44 | self._create_repo(new_repo) | |
|
45 | c.new_repo = new_repo | |
|
46 | c.msg = 'added repo' | |
|
47 | except Exception as e: | |
|
48 | c.new_repo = 'Exception when adding: %s' % new_repo | |
|
49 | c.msg = str(e) | |
|
50 | ||
|
51 | return render('add.html') | |
|
52 | ||
|
53 | def _check_repo(self, repo_name): | |
|
54 | p = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) | |
|
55 | config_path = os.path.join(p, 'hgwebdir.config') | |
|
56 | ||
|
57 | cp = ConfigParser() | |
|
58 | ||
|
59 | cp.read(config_path) | |
|
60 | repos_path = cp.get('paths', '/').replace("**", '') | |
|
61 | ||
|
62 | if not repos_path: | |
|
63 | raise Exception('Could not read config !') | |
|
64 | ||
|
65 | self.repo_path = os.path.join(repos_path, repo_name) | |
|
66 | ||
|
67 | try: | |
|
68 | r = hg.repository(ui.ui(), self.repo_path) | |
|
69 | hg.verify(r) | |
|
70 | #here we hnow that repo exists it was verified | |
|
71 | log.info('%s repo is already created', repo_name) | |
|
72 | raise Exception('Repo exists') | |
|
73 | except RepoError: | |
|
74 | log.info('%s repo is free for creation', repo_name) | |
|
75 | #it means that there is no valid repo there... | |
|
76 | return True | |
|
77 | ||
|
78 | ||
|
79 | def _create_repo(self, repo_name): | |
|
80 | if repo_name in [None, '', 'add']: | |
|
81 | raise Exception('undefined repo_name of repo') | |
|
82 | ||
|
83 | if self._check_repo(repo_name): | |
|
84 | log.info('creating repo %s in %s', repo_name, self.repo_path) | |
|
85 | cmd = """mkdir %s && hg init %s""" \ | |
|
86 | % (self.repo_path, self.repo_path) | |
|
87 | os.popen(cmd) |
@@ -0,0 +1,51 b'' | |||
|
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"> | |
|
3 | <html xmlns="http://www.w3.org/1999/xhtml"> | |
|
4 | <head> | |
|
5 | <link rel="icon" href="${c.staticurl}hgicon.png" type="image/png" /> | |
|
6 | <meta name="robots" content="index, nofollow"/> | |
|
7 | <link rel="stylesheet" href="${c.staticurl}style-monoblue.css" type="text/css" /> | |
|
8 | <title>Mercurial repositories Admin</title> | |
|
9 | </head> | |
|
10 | ||
|
11 | <body> | |
|
12 | <div id="container"> | |
|
13 | <div class="page-header"> | |
|
14 | <h1><a href="/">Home</a> / Admin</h1> | |
|
15 | <ul class="page-nav"> | |
|
16 | </ul> | |
|
17 | </div> | |
|
18 | <table cellspacing="0"> | |
|
19 | <tr> | |
|
20 | <td>${h.link_to(u'Create "ccc" repository',h.url('admin_add_repo',new_repo='ccc'))}</td> | |
|
21 | </tr> | |
|
22 | <tr> | |
|
23 | <td>${h.link_to(u'Create "ccc" repository',h.url('admin_add_repo',new_repo='ccc'))}</td> | |
|
24 | </tr> | |
|
25 | <tr> | |
|
26 | <td>${h.link_to(u'Create "ccc" repository',h.url('admin_add_repo',new_repo='ccc'))}</td> | |
|
27 | </tr> | |
|
28 | <tr> | |
|
29 | <td><h2>${c.new_repo}</h2></td> | |
|
30 | </tr> | |
|
31 | </table> | |
|
32 | <div class="page-footer"> | |
|
33 | Mercurial Repository: admin | |
|
34 | </div> | |
|
35 | ||
|
36 | <div id="powered-by"> | |
|
37 | <p> | |
|
38 | <a href="http://mercurial.selenic.com/" title="Mercurial"> | |
|
39 | <img src="${c.staticurl}hglogo.png" width="75" height="90" alt="mercurial"></a> | |
|
40 | </p> | |
|
41 | </div> | |
|
42 | ||
|
43 | <div id="corner-top-left"></div> | |
|
44 | <div id="corner-top-right"></div> | |
|
45 | <div id="corner-bottom-left"></div> | |
|
46 | <div id="corner-bottom-right"></div> | |
|
47 | ||
|
48 | </div> | |
|
49 | </body> | |
|
50 | </html> | |
|
51 | No newline at end of file |
@@ -0,0 +1,7 b'' | |||
|
1 | from pylons_app.tests import * | |
|
2 | ||
|
3 | class TestAdminController(TestController): | |
|
4 | ||
|
5 | def test_index(self): | |
|
6 | response = self.app.get(url(controller='admin', action='index')) | |
|
7 | # Test response... |
@@ -3,12 +3,14 b' import logging' | |||
|
3 | 3 | import os |
|
4 | 4 | |
|
5 | 5 | from mako.lookup import TemplateLookup |
|
6 | from pylons.configuration import PylonsConfig | |
|
6 | 7 | from pylons.error import handle_mako_error |
|
7 |
from |
|
|
8 | from sqlalchemy import engine_from_config | |
|
8 | 9 | |
|
9 | 10 | import pylons_app.lib.app_globals as app_globals |
|
10 | 11 | import pylons_app.lib.helpers |
|
11 | 12 | from pylons_app.config.routing import make_map |
|
13 | from pylons_app.model import init_model | |
|
12 | 14 | |
|
13 | 15 | log = logging.getLogger(__name__) |
|
14 | 16 | |
@@ -16,6 +18,8 b' def load_environment(global_conf, app_co' | |||
|
16 | 18 | """Configure the Pylons environment via the ``pylons.config`` |
|
17 | 19 | object |
|
18 | 20 | """ |
|
21 | config = PylonsConfig() | |
|
22 | ||
|
19 | 23 | # Pylons paths |
|
20 | 24 | root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
|
21 | 25 | paths = dict(root=root, |
@@ -24,13 +28,17 b' def load_environment(global_conf, app_co' | |||
|
24 | 28 | templates=[os.path.join(root, 'templates')]) |
|
25 | 29 | |
|
26 | 30 | # Initialize config with the basic options |
|
27 | config.init_app(global_conf, app_conf, package='pylons_app', | |
|
28 | template_engine='mako', paths=paths) | |
|
31 | config.init_app(global_conf, app_conf, package='pylons_app', paths=paths) | |
|
29 | 32 | |
|
30 | config['routes.map'] = make_map() | |
|
31 | config['pylons.app_globals'] = app_globals.Globals() | |
|
33 | config['routes.map'] = make_map(config) | |
|
34 | config['pylons.app_globals'] = app_globals.Globals(config) | |
|
32 | 35 | config['pylons.h'] = pylons_app.lib.helpers |
|
33 | 36 | |
|
37 | # Setup cache object as early as possible | |
|
38 | import pylons | |
|
39 | pylons.cache._push_object(config['pylons.app_globals'].cache) | |
|
40 | ||
|
41 | ||
|
34 | 42 | # Create the Mako TemplateLookup, with the default auto-escaping |
|
35 | 43 | config['pylons.app_globals'].mako_lookup = TemplateLookup( |
|
36 | 44 | directories=paths['templates'], |
@@ -39,5 +47,22 b' def load_environment(global_conf, app_co' | |||
|
39 | 47 | input_encoding='utf-8', default_filters=['escape'], |
|
40 | 48 | imports=['from webhelpers.html import escape']) |
|
41 | 49 | |
|
50 | #sets the c attribute access when don't existing attribute ar accessed | |
|
51 | config['pylons.strict_tmpl_context'] = False | |
|
52 | ||
|
53 | #MULTIPLE DB configs | |
|
54 | # Setup the SQLAlchemy database engine | |
|
55 | # if config['debug']: | |
|
56 | # #use query time debugging. | |
|
57 | # from pylons_app.lib.timer_proxy import TimerProxy | |
|
58 | # sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.', | |
|
59 | # proxy=TimerProxy()) | |
|
60 | # else: | |
|
61 | # sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.') | |
|
62 | ||
|
63 | #init_model(sa_engine_db1) | |
|
64 | ||
|
42 | 65 | # CONFIGURATION OPTIONS HERE (note: all config options will override |
|
43 | 66 | # any Pylons config options) |
|
67 | ||
|
68 | return config |
@@ -1,10 +1,9 b'' | |||
|
1 | 1 | """Pylons middleware initialization""" |
|
2 |
from beaker.middleware import |
|
|
2 | from beaker.middleware import SessionMiddleware | |
|
3 | 3 | from paste.cascade import Cascade |
|
4 | 4 | from paste.registry import RegistryManager |
|
5 | 5 | from paste.urlparser import StaticURLParser |
|
6 | 6 | from paste.deploy.converters import asbool |
|
7 | from pylons import config | |
|
8 | 7 | from pylons.middleware import ErrorHandler, StatusCodeRedirect |
|
9 | 8 | from pylons.wsgiapp import PylonsApp |
|
10 | 9 | from routes.middleware import RoutesMiddleware |
@@ -12,7 +11,7 b' from paste.auth.basic import AuthBasicHa' | |||
|
12 | 11 | from pylons_app.config.environment import load_environment |
|
13 | 12 | from pylons_app.lib.auth import authfunc |
|
14 | 13 | |
|
15 | def make_app(global_conf, full_stack=True, **app_conf): | |
|
14 | def make_app(global_conf, full_stack=True, static_files=True, **app_conf): | |
|
16 | 15 | """Create a Pylons WSGI application and return it |
|
17 | 16 | |
|
18 | 17 | ``global_conf`` |
@@ -32,17 +31,17 b' def make_app(global_conf, full_stack=Tru' | |||
|
32 | 31 | |
|
33 | 32 | """ |
|
34 | 33 | # Configure the Pylons environment |
|
35 | load_environment(global_conf, app_conf) | |
|
34 | config = load_environment(global_conf, app_conf) | |
|
35 | ||
|
36 | 36 | |
|
37 | 37 | # The Pylons WSGI app |
|
38 | app = PylonsApp() | |
|
38 | app = PylonsApp(config=config) | |
|
39 | 39 | |
|
40 | 40 | # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares) |
|
41 | 41 | |
|
42 | 42 | # Routing/Session/Cache Middleware |
|
43 | 43 | app = RoutesMiddleware(app, config['routes.map']) |
|
44 | 44 | app = SessionMiddleware(app, config) |
|
45 | app = CacheMiddleware(app, config) | |
|
46 | 45 | app = AuthBasicHandler(app, config['repos_name'] + ' mercurial repository', authfunc) |
|
47 | 46 | |
|
48 | 47 | if asbool(full_stack): |
@@ -53,16 +52,19 b' def make_app(global_conf, full_stack=Tru' | |||
|
53 | 52 | # 500 when debug is disabled) |
|
54 | 53 | if asbool(config['debug']): |
|
55 | 54 | #don't handle 404, since mercurial does it for us. |
|
56 |
app = StatusCodeRedirect(app, [400, 401, 403 |
|
|
55 | app = StatusCodeRedirect(app, [400, 401, 403]) | |
|
57 | 56 | else: |
|
58 | 57 | app = StatusCodeRedirect(app, [400, 401, 403, 500]) |
|
59 | 58 | |
|
60 | 59 | # Establish the Registry for this application |
|
61 | 60 | app = RegistryManager(app) |
|
62 | 61 | |
|
63 | # Static files (If running in production, and Apache or another web | |
|
64 | # server is handling this static content, remove the following 3 lines) | |
|
62 | if asbool(static_files): | |
|
63 | # Serve static files | |
|
65 | 64 | static_app = StaticURLParser(config['pylons.paths']['static_files']) |
|
66 | 65 | app = Cascade([static_app, app]) |
|
66 | ||
|
67 | app.config = config | |
|
68 | ||
|
67 | 69 | return app |
|
68 | 70 |
@@ -4,14 +4,14 b' The more specific and detailed routes sh' | |||
|
4 | 4 | may take precedent over the more generic routes. For more information |
|
5 | 5 | refer to the routes manual at http://routes.groovie.org/docs/ |
|
6 | 6 | """ |
|
7 | from pylons import config | |
|
8 | 7 | from routes import Mapper |
|
9 | 8 | |
|
10 | def make_map(): | |
|
9 | def make_map(config): | |
|
11 | 10 | """Create, configure and return the routes Mapper""" |
|
12 | 11 |
map = Mapper(directory |
|
13 | 12 |
always_scan |
|
14 | 13 | map.minimization = False |
|
14 | map.explicit = False | |
|
15 | 15 | |
|
16 | 16 | # The ErrorController route (handles 404/500 error pages); it should |
|
17 | 17 | # likely stay at the top, ensuring it can always be resolved |
@@ -19,10 +19,12 b' def make_map():' | |||
|
19 | 19 |
map.connect('/error/{action}/{id}', controller |
|
20 | 20 | |
|
21 | 21 | # CUSTOM ROUTES HERE |
|
22 | map.connect('hg_add', '/add/{new_repo:[a-z0-9\. _-]*}', | |
|
23 | controller = 'hg', action = 'add_repo') | |
|
24 | map.connect('hg', '/{path_info:.*}', | |
|
25 | controller = 'hg', action = "view", | |
|
26 | path_info = '/') | |
|
22 | with map.submapper(path_prefix='/_admin', controller='admin') as m: | |
|
23 | m.connect('admin_home', '/', action='index')#main page | |
|
24 | m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}', action='add_repo') | |
|
25 | m.connect('admin_manage_users', '/manage_users', action='index') | |
|
26 | ||
|
27 | map.connect('hg', '/{path_info:.*}', controller='hg', | |
|
28 | action="view", path_info='/') | |
|
27 | 29 | |
|
28 | 30 | return map |
@@ -1,14 +1,10 b'' | |||
|
1 | 1 | #!/usr/bin/python |
|
2 | 2 | # -*- coding: utf-8 -*- |
|
3 | 3 | import logging |
|
4 | import os | |
|
5 | from pylons_app.lib.base import BaseController, render | |
|
4 | from pylons_app.lib.base import BaseController | |
|
6 | 5 | from pylons import tmpl_context as c, app_globals as g, session, request, config |
|
7 | 6 | from pylons_app.lib import helpers as h |
|
8 | 7 | from mako.template import Template |
|
9 | from mercurial import ui, hg | |
|
10 | from mercurial.error import RepoError | |
|
11 | from ConfigParser import ConfigParser | |
|
12 | 8 | from pylons.controllers.util import abort |
|
13 | 9 | |
|
14 | 10 | log = logging.getLogger(__name__) |
@@ -43,92 +39,3 b' class HgController(BaseController):' | |||
|
43 | 39 | |
|
44 | 40 | |
|
45 | 41 | return template.render(g=g, c=c, session=session, h=h) |
|
46 | ||
|
47 | ||
|
48 | def manage_hgrc(self): | |
|
49 | pass | |
|
50 | ||
|
51 | def hgrc(self, dirname): | |
|
52 | filename = os.path.join(dirname, '.hg', 'hgrc') | |
|
53 | return filename | |
|
54 | ||
|
55 | def add_repo(self, new_repo): | |
|
56 | c.staticurl = g.statics | |
|
57 | ||
|
58 | #extra check it can be add since it's the command | |
|
59 | if new_repo == 'add': | |
|
60 | c.msg = 'you basstard ! this repo is a command' | |
|
61 | c.new_repo = '' | |
|
62 | return render('add.html') | |
|
63 | ||
|
64 | new_repo = new_repo.replace(" ", "_") | |
|
65 | new_repo = new_repo.replace("-", "_") | |
|
66 | ||
|
67 | try: | |
|
68 | self._create_repo(new_repo) | |
|
69 | c.new_repo = new_repo | |
|
70 | c.msg = 'added repo' | |
|
71 | except Exception as e: | |
|
72 | c.new_repo = 'Exception when adding: %s' % new_repo | |
|
73 | c.msg = str(e) | |
|
74 | ||
|
75 | return render('add.html') | |
|
76 | ||
|
77 | def _check_repo(self, repo_name): | |
|
78 | p = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) | |
|
79 | config_path = os.path.join(p, 'hgwebdir.config') | |
|
80 | ||
|
81 | cp = ConfigParser() | |
|
82 | ||
|
83 | cp.read(config_path) | |
|
84 | repos_path = cp.get('paths', '/').replace("**", '') | |
|
85 | ||
|
86 | if not repos_path: | |
|
87 | raise Exception('Could not read config !') | |
|
88 | ||
|
89 | self.repo_path = os.path.join(repos_path, repo_name) | |
|
90 | ||
|
91 | try: | |
|
92 | r = hg.repository(ui.ui(), self.repo_path) | |
|
93 | hg.verify(r) | |
|
94 | #here we hnow that repo exists it was verified | |
|
95 | log.info('%s repo is already created', repo_name) | |
|
96 | raise Exception('Repo exists') | |
|
97 | except RepoError: | |
|
98 | log.info('%s repo is free for creation', repo_name) | |
|
99 | #it means that there is no valid repo there... | |
|
100 | return True | |
|
101 | ||
|
102 | ||
|
103 | def _create_repo(self, repo_name): | |
|
104 | if repo_name in [None, '', 'add']: | |
|
105 | raise Exception('undefined repo_name of repo') | |
|
106 | ||
|
107 | if self._check_repo(repo_name): | |
|
108 | log.info('creating repo %s in %s', repo_name, self.repo_path) | |
|
109 | cmd = """mkdir %s && hg init %s""" \ | |
|
110 | % (self.repo_path, self.repo_path) | |
|
111 | os.popen(cmd) | |
|
112 | ||
|
113 | #def _make_app(): | |
|
114 | # #for single a repo | |
|
115 | # #return hgweb("/path/to/repo", "Name") | |
|
116 | # repos = "hgwebdir.config" | |
|
117 | # return hgwebdir(repos) | |
|
118 | # | |
|
119 | ||
|
120 | # def view(self, environ, start_response): | |
|
121 | # #the following is only needed when using hgwebdir | |
|
122 | # app = _make_app() | |
|
123 | # #return wsgi_app(environ, start_response) | |
|
124 | # response = app(request.environ, self.start_response) | |
|
125 | # | |
|
126 | # if environ['PATH_INFO'].find("static") != -1: | |
|
127 | # return response | |
|
128 | # else: | |
|
129 | # #wrap the murcurial response in a mako template. | |
|
130 | # template = Template("".join(response), | |
|
131 | # lookup = environ['pylons.pylons']\ | |
|
132 | # .config['pylons.g'].mako_lookup) | |
|
133 | # | |
|
134 | # return template.render(g = g, c = c, session = session, h = h) |
@@ -6,6 +6,9 b' from mercurial import templater' | |||
|
6 | 6 | from mercurial.hgweb.request import wsgiapplication |
|
7 | 7 | from mercurial import ui, config |
|
8 | 8 | import os |
|
9 | from beaker.cache import CacheManager | |
|
10 | from beaker.util import parse_cache_config_options | |
|
11 | ||
|
9 | 12 | class Globals(object): |
|
10 | 13 | |
|
11 | 14 | """Globals acts as a container for objects available throughout the |
@@ -13,7 +16,7 b' class Globals(object):' | |||
|
13 | 16 | |
|
14 | 17 | """ |
|
15 | 18 | |
|
16 | def __init__(self): | |
|
19 | def __init__(self, config): | |
|
17 | 20 | """One instance of Globals is created during application |
|
18 | 21 | initialization and is available during requests via the |
|
19 | 22 | 'app_globals' variable |
@@ -22,6 +25,7 b' class Globals(object):' | |||
|
22 | 25 | #two ways of building the merc app i don't know |
|
23 | 26 | #the fastest one but belive the wsgiapp is better |
|
24 | 27 | #self.hgapp = self.make_web_app() |
|
28 | self.cache = CacheManager(**parse_cache_config_options(config)) | |
|
25 | 29 | self.hgapp = wsgiapplication(self.make_web_app) |
|
26 | 30 | |
|
27 | 31 |
@@ -3,8 +3,7 b'' | |||
|
3 | 3 | Consists of functions to typically be used within templates, but also |
|
4 | 4 | available to Controllers. This module is available to both as 'h'. |
|
5 | 5 | """ |
|
6 | from routes import redirect_to, url_for | |
|
7 | ||
|
6 | from pylons import url | |
|
8 | 7 | from webhelpers.html import (literal, HTML, escape) |
|
9 | 8 | from webhelpers.html.tools import (auto_link, button_to, highlight, js_obfuscate |
|
10 | 9 | , mail_to, strip_links, strip_tags, tag_re) |
@@ -30,10 +29,10 b' class _Link(object):' | |||
|
30 | 29 | @param url: the url for link |
|
31 | 30 | ''' |
|
32 | 31 | |
|
33 |
def __call__(self, label |
|
|
32 | def __call__(self, label='', *url_, **urlargs): | |
|
34 | 33 | if label is None or '': |
|
35 | 34 | label = url |
|
36 |
link_fn = link_to(label, url |
|
|
35 | link_fn = link_to(label, url(*url_, **urlargs)) | |
|
37 | 36 | return link_fn |
|
38 | 37 | |
|
39 | 38 |
@@ -14,7 +14,10 b'' | |||
|
14 | 14 | |
|
15 | 15 | <h2 class="no-link no-border">Not Found</h2> |
|
16 | 16 | <p class="normal">The specified repository "{repo|escape}" is unknown, sorry.</p> |
|
17 | <p class="normal"><a href="/add/{repo|escape}">Create "{repo|escape}" repository </a></p> | |
|
17 | <p class="normal"> | |
|
18 | <a href="/_admin/add_repo/{repo|escape}">Create "{repo|escape}" repository</a> | |
|
19 | ||
|
20 | </p> | |
|
18 | 21 | <p class="normal">Go back to the <a href="{url}">main repository list page</a>.</p> |
|
19 | 22 | <div class="page-footer"> |
|
20 | 23 | <p>Mercurial Repository: {repo|escape}</p> |
General Comments 0
You need to be logged in to leave comments.
Login now