##// END OF EJS Templates
Added universal cache invalidator for two cached functions....
marcink -
r171:52bbeb1e default
parent child Browse files
Show More
@@ -1,101 +1,101 b''
1 1 import logging
2 2 import os
3 3
4 4 from pylons import request, response, session, tmpl_context as c, url, app_globals as g
5 5 from pylons.controllers.util import abort, redirect
6 6 from pylons_app.lib.base import BaseController, render
7 7 from pylons_app.lib import auth
8 8 from pylons_app.model.forms import LoginForm
9 9 import formencode
10 10 import formencode.htmlfill as htmlfill
11 11 from pylons_app.model import meta
12 12 from pylons_app.model.db import Users, UserLogs
13 13 from webhelpers.paginate import Page
14 14 from pylons_app.lib.utils import check_repo, invalidate_cache
15 15
16 16 log = logging.getLogger(__name__)
17 17
18 18 class AdminController(BaseController):
19 19
20 20 def __before__(self):
21 21 c.admin_user = session.get('admin_user', False)
22 22 c.admin_username = session.get('admin_username')
23 23
24 24 def index(self):
25 25 # Return a rendered template
26 26 if request.POST:
27 27 #import Login Form validator class
28 28 login_form = LoginForm()
29 29
30 30 try:
31 31 c.form_result = login_form.to_python(dict(request.params))
32 32 if auth.admin_auth(c.form_result['username'], c.form_result['password']):
33 33 session['admin_user'] = True
34 34 session['admin_username'] = c.form_result['username']
35 35 session.save()
36 36 return redirect(url('admin_home'))
37 37 else:
38 38 raise formencode.Invalid('Login Error', None, None,
39 39 error_dict={'username':'invalid login',
40 40 'password':'invalid password'})
41 41
42 42 except formencode.Invalid, error:
43 43 c.form_result = error.value
44 44 c.form_errors = error.error_dict or {}
45 45 html = render('admin/admin.html')
46 46
47 47 return htmlfill.render(
48 48 html,
49 49 defaults=c.form_result,
50 50 encoding="UTF-8"
51 51 )
52 52 if c.admin_user:
53 53 sa = meta.Session
54 54
55 55 users_log = sa.query(UserLogs)\
56 56 .order_by(UserLogs.action_date.desc())
57 57 p = int(request.params.get('page', 1))
58 58 c.users_log = Page(users_log, page=p, items_per_page=10)
59 59 c.log_data = render('admin/admin_log.html')
60 60 if request.params.get('partial'):
61 61 return c.log_data
62 62 return render('admin/admin.html')
63 63
64 64 def hgrc(self, dirname):
65 65 filename = os.path.join(dirname, '.hg', 'hgrc')
66 66 return filename
67 67
68 68 def add_repo(self, new_repo):
69 69
70 70
71 71 #extra check it can be add since it's the command
72 72 if new_repo == '_admin':
73 73 c.msg = 'DENIED'
74 74 c.new_repo = ''
75 75 return render('admin/add.html')
76 76
77 77 new_repo = new_repo.replace(" ", "_")
78 78 new_repo = new_repo.replace("-", "_")
79 79
80 80 try:
81 81 self._create_repo(new_repo)
82 82 c.new_repo = new_repo
83 83 c.msg = 'added repo'
84 84 #clear our cached list for refresh with new repo
85 invalidate_cache('repo_list_2')
85 invalidate_cache('cached_repo_list')
86 86 except Exception as e:
87 87 c.new_repo = 'Exception when adding: %s' % new_repo
88 88 c.msg = str(e)
89 89
90 90 return render('admin/add.html')
91 91
92 92
93 93 def _create_repo(self, repo_name):
94 94 if repo_name in [None, '', 'add']:
95 95 raise Exception('undefined repo_name of repo')
96 96 repo_path = os.path.join(g.base_path, repo_name)
97 97 if check_repo(repo_name, g.base_path):
98 98 log.info('creating repo %s in %s', repo_name, repo_path)
99 99 from vcs.backends.hg import MercurialRepository
100 100 MercurialRepository(repo_path, create=True)
101 101
@@ -1,59 +1,64 b''
1 1 import os
2 2 from mercurial.hgweb import hgweb
3 3 from mercurial.hgweb.request import wsgiapplication
4 from pylons_app.lib.utils import make_ui
4 from pylons_app.lib.utils import make_ui, invalidate_cache
5 5 from pylons.controllers.util import abort
6 6 from webob.exc import HTTPNotFound
7 7 class SimpleHg(object):
8 8
9 9 def __init__(self, application, config):
10 10 self.application = application
11 11 self.config = config
12 12
13 13 def __call__(self, environ, start_response):
14 14 if not is_mercurial(environ):
15 15 return self.application(environ, start_response)
16 16 else:
17 17 try:
18 18 repo_name = environ['PATH_INFO'].split('/')[1]
19 19 except:
20 20 return HTTPNotFound()(environ, start_response)
21 21
22 22 #since we wrap into hgweb, just reset the path
23 23 environ['PATH_INFO'] = '/'
24 24 self.baseui = make_ui()
25 self.basepath = self.baseui.configitems('paths')[0][1].replace('*', '')
25 self.basepath = self.baseui.configitems('paths')[0][1]\
26 .replace('*', '')
26 27 self.repo_path = os.path.join(self.basepath, repo_name)
27 28 try:
28 29 app = wsgiapplication(self._make_app)
29 30 except Exception as e:
30 31 return HTTPNotFound()(environ, start_response)
32
33 """we know that some change was made to repositories and we should
34 invalidate the cache to see the changes right away"""
35 invalidate_cache('full_changelog', repo_name)
31 36 return app(environ, start_response)
32 37
33 38 def _make_app(self):
34 39 hgserve = hgweb(self.repo_path)
35 40 return self.load_web_settings(hgserve)
36 41
37 42
38 43 def load_web_settings(self, hgserve):
39 44 repoui = make_ui(os.path.join(self.repo_path, '.hg', 'hgrc'), False)
40 45 #set the global ui for hgserve
41 46 hgserve.repo.ui = self.baseui
42 47
43 48 if repoui:
44 49 #set the repository based config
45 50 hgserve.repo.ui = repoui
46 51
47 52 return hgserve
48 53
49 54 def is_mercurial(environ):
50 55 """
51 56 Returns True if request's target is mercurial server - header
52 57 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
53 58 """
54 59 http_accept = environ.get('HTTP_ACCEPT')
55 60 if http_accept and http_accept.startswith('application/mercurial'):
56 61 return True
57 62 return False
58 63
59 64
@@ -1,114 +1,125 b''
1 1 import os
2 2 import logging
3 3 from mercurial import ui, config, hg
4 4 from mercurial.error import RepoError
5 5 log = logging.getLogger(__name__)
6 6
7 7
8 8 def get_repo_slug(request):
9 9 path_info = request.environ.get('PATH_INFO')
10 10 uri_lst = path_info.split('/')
11 11 repo_name = uri_lst[1]
12 12 return repo_name
13 13
14 14 def is_mercurial(environ):
15 15 """
16 16 Returns True if request's target is mercurial server - header
17 17 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
18 18 """
19 19 http_accept = environ.get('HTTP_ACCEPT')
20 20 if http_accept and http_accept.startswith('application/mercurial'):
21 21 return True
22 22 return False
23 23
24 24 def check_repo_dir(paths):
25 25 repos_path = paths[0][1].split('/')
26 26 if repos_path[-1] in ['*', '**']:
27 27 repos_path = repos_path[:-1]
28 28 if repos_path[0] != '/':
29 29 repos_path[0] = '/'
30 30 if not os.path.isdir(os.path.join(*repos_path)):
31 31 raise Exception('Not a valid repository in %s' % paths[0][1])
32 32
33 33 def check_repo(repo_name, base_path):
34 34
35 35 repo_path = os.path.join(base_path, repo_name)
36 36
37 37 try:
38 38 r = hg.repository(ui.ui(), repo_path)
39 39 hg.verify(r)
40 40 #here we hnow that repo exists it was verified
41 41 log.info('%s repo is already created', repo_name)
42 42 return False
43 43 #raise Exception('Repo exists')
44 44 except RepoError:
45 45 log.info('%s repo is free for creation', repo_name)
46 46 #it means that there is no valid repo there...
47 47 return True
48 48
49 49 def make_ui(path='hgwebdir.config', checkpaths=True):
50 50 """
51 51 A funcion that will read python rc files and make an ui from read options
52 52
53 53 @param path: path to mercurial config file
54 54 """
55 55 if not os.path.isfile(path):
56 56 log.error('Unable to read config file %s' % path)
57 57 return False
58 58 #propagated from mercurial documentation
59 59 sections = [
60 60 'alias',
61 61 'auth',
62 62 'decode/encode',
63 63 'defaults',
64 64 'diff',
65 65 'email',
66 66 'extensions',
67 67 'format',
68 68 'merge-patterns',
69 69 'merge-tools',
70 70 'hooks',
71 71 'http_proxy',
72 72 'smtp',
73 73 'patch',
74 74 'paths',
75 75 'profiling',
76 76 'server',
77 77 'trusted',
78 78 'ui',
79 79 'web',
80 80 ]
81 81
82 82 baseui = ui.ui()
83 83 cfg = config.config()
84 84 cfg.read(path)
85 85 if checkpaths:check_repo_dir(cfg.items('paths'))
86 86
87 87 for section in sections:
88 88 for k, v in cfg.items(section):
89 89 baseui.setconfig(section, k, v)
90 90
91 91 return baseui
92 92
93 def invalidate_cache(name):
93 def invalidate_cache(name, *args):
94 94 from beaker.cache import region_invalidate
95 if name == 'repo_list_2':
96 log.info('INVALIDATING CACHE FOR %s', name)
97 from pylons_app.lib.base import _get_repos
98 #clear our cached list for refresh with new repo
99 region_invalidate(_get_repos, None, 'repo_list_2')
100
95 log.info('INVALIDATING CACHE FOR %s', name)
96
97 """propaget our arguments to make sure invalidation works. First
98 argument has to be the name of cached func name give to cache decorator
99 without that the invalidation would not work"""
100 tmp = [name]
101 tmp.extend(args)
102 args = tuple(tmp)
103
104 if name == 'cached_repo_list':
105 from pylons_app.lib.base import _get_repos_cached
106 region_invalidate(_get_repos_cached, None, *args)
107
108 if name == 'full_changelog':
109 from pylons_app.controllers.changelog import _full_changelog_cached
110 region_invalidate(_full_changelog_cached, None, *args)
111
101 112 from vcs.backends.base import BaseChangeset
102 113 from vcs.utils.lazy import LazyProperty
103 114 class EmptyChangeset(BaseChangeset):
104 115
105 116 revision = -1
106 117
107 118 @LazyProperty
108 119 def raw_id(self):
109 120 """
110 121 Returns raw string identifing this changeset, useful for web
111 122 representation.
112 123 """
113 124 return '0' * 12
114 125
General Comments 0
You need to be logged in to leave comments. Login now