Mercurial > kallithea
comparison rhodecode/model/hg.py @ 665:070f32743632 beta
Moved out reposcan into hg Model.
Rewrote repo scann and caching of repositories, all is in hgModel.
Changed invalidate cache calls.
mergeds main repo list and repo switcher list into one new based on hgModel.
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Sun, 07 Nov 2010 15:02:56 +0100 |
parents | ffd07396d315 |
children | 4685f3eafd35 |
comparison
equal
deleted
inserted
replaced
664:50d9b1afaca7 | 665:070f32743632 |
---|---|
20 """ | 20 """ |
21 Created on April 9, 2010 | 21 Created on April 9, 2010 |
22 Model for RhodeCode | 22 Model for RhodeCode |
23 @author: marcink | 23 @author: marcink |
24 """ | 24 """ |
25 from beaker.cache import cache_region | 25 from beaker.cache import cache_region, region_invalidate |
26 from mercurial import ui | 26 from mercurial import ui |
27 from rhodecode.lib import helpers as h | 27 from rhodecode.lib import helpers as h |
28 from rhodecode.lib.utils import invalidate_cache | |
29 from rhodecode.lib.auth import HasRepoPermissionAny | 28 from rhodecode.lib.auth import HasRepoPermissionAny |
29 from rhodecode.lib.utils import get_repos | |
30 from rhodecode.model import meta | 30 from rhodecode.model import meta |
31 from rhodecode.model.db import Repository, User | 31 from rhodecode.model.caching_query import FromCache |
32 from rhodecode.model.db import Repository, User, RhodeCodeUi | |
32 from sqlalchemy.orm import joinedload | 33 from sqlalchemy.orm import joinedload |
34 from vcs import get_repo as vcs_get_repo, get_backend | |
35 from vcs.backends.hg import MercurialRepository | |
33 from vcs.exceptions import RepositoryError, VCSError | 36 from vcs.exceptions import RepositoryError, VCSError |
37 from vcs.utils.lazy import LazyProperty | |
34 import logging | 38 import logging |
35 import sys | 39 import os |
36 import time | 40 import time |
37 | 41 |
38 log = logging.getLogger(__name__) | 42 log = logging.getLogger(__name__) |
39 | |
40 try: | |
41 from vcs.backends.hg import MercurialRepository | |
42 from vcs.backends.git import GitRepository | |
43 except ImportError: | |
44 sys.stderr.write('You have to import vcs module') | |
45 raise Exception('Unable to import vcs') | |
46 | |
47 def _get_repos_cached_initial(app_globals, initial): | |
48 """return cached dict with repos | |
49 """ | |
50 g = app_globals | |
51 return HgModel().repo_scan(g.paths[0][1], g.baseui, initial) | |
52 | |
53 @cache_region('long_term', 'cached_repo_list') | |
54 def _get_repos_cached(): | |
55 """return cached dict with repos | |
56 """ | |
57 log.info('getting all repositories list') | |
58 from pylons import app_globals as g | |
59 return HgModel().repo_scan(g.paths[0][1], g.baseui) | |
60 | |
61 @cache_region('super_short_term', 'cached_repos_switcher_list') | |
62 def _get_repos_switcher_cached(cached_repo_list): | |
63 repos_lst = [] | |
64 for repo in [x for x in cached_repo_list.values()]: | |
65 if HasRepoPermissionAny('repository.write', 'repository.read', | |
66 'repository.admin')(repo.name, 'main page check'): | |
67 repos_lst.append((repo.name, repo.dbrepo.private,)) | |
68 | |
69 return sorted(repos_lst, key=lambda k:k[0].lower()) | |
70 | |
71 @cache_region('long_term', 'full_changelog') | |
72 def _full_changelog_cached(repo_name): | |
73 log.info('getting full changelog for %s', repo_name) | |
74 return list(reversed(list(HgModel().get_repo(repo_name)))) | |
75 | 43 |
76 class HgModel(object): | 44 class HgModel(object): |
77 """ | 45 """ |
78 Mercurial Model | 46 Mercurial Model |
79 """ | 47 """ |
82 if not sa: | 50 if not sa: |
83 self.sa = meta.Session() | 51 self.sa = meta.Session() |
84 else: | 52 else: |
85 self.sa = sa | 53 self.sa = sa |
86 | 54 |
55 | |
56 @LazyProperty | |
57 def repos_path(self): | |
58 """ | |
59 Get's the repositories root path from database | |
60 """ | |
61 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one() | |
62 | |
63 return q.ui_value | |
64 | |
87 def repo_scan(self, repos_path, baseui, initial=False): | 65 def repo_scan(self, repos_path, baseui, initial=False): |
88 """ | 66 """ |
89 Listing of repositories in given path. This path should not be a | 67 Listing of repositories in given path. This path should not be a |
90 repository itself. Return a dictionary of repository objects | 68 repository itself. Return a dictionary of repository objects |
91 | 69 |
92 :param repos_path: path to directory containing repositories | 70 :param repos_path: path to directory containing repositories |
93 :param baseui | 71 :param baseui |
94 :param initial: initial scann | 72 :param initial: initial scan |
95 """ | 73 """ |
96 log.info('scanning for repositories in %s', repos_path) | 74 log.info('scanning for repositories in %s', repos_path) |
97 | 75 |
98 if not isinstance(baseui, ui.ui): | 76 if not isinstance(baseui, ui.ui): |
99 baseui = ui.ui() | 77 baseui = ui.ui() |
78 repos_list = {} | |
79 for name, path in get_repos(repos_path): | |
80 try: | |
81 if repos_list.has_key(name): | |
82 raise RepositoryError('Duplicate repository name %s ' | |
83 'found in %s' % (name, path)) | |
84 else: | |
100 | 85 |
101 from rhodecode.lib.utils import get_repos | 86 klass = get_backend(path[0]) |
102 repos = get_repos(repos_path) | |
103 | 87 |
104 | |
105 repos_list = {} | |
106 for name, path in repos: | |
107 try: | |
108 #name = name.split('/')[-1] | |
109 if repos_list.has_key(name): | |
110 raise RepositoryError('Duplicate repository name %s found in' | |
111 ' %s' % (name, path)) | |
112 else: | |
113 if path[0] == 'hg': | 88 if path[0] == 'hg': |
114 repos_list[name] = MercurialRepository(path[1], baseui=baseui) | 89 repos_list[name] = klass(path[1], baseui=baseui) |
115 repos_list[name].name = name | |
116 | 90 |
117 if path[0] == 'git': | 91 if path[0] == 'git': |
118 repos_list[name] = GitRepository(path[1]) | 92 repos_list[name] = klass(path[1]) |
119 repos_list[name].name = name | |
120 | |
121 dbrepo = None | |
122 if not initial: | |
123 #for initial scann on application first run we don't | |
124 #have db repos yet. | |
125 dbrepo = self.sa.query(Repository)\ | |
126 .options(joinedload(Repository.fork))\ | |
127 .filter(Repository.repo_name == name)\ | |
128 .scalar() | |
129 | |
130 if dbrepo: | |
131 log.info('Adding db instance to cached list') | |
132 repos_list[name].dbrepo = dbrepo | |
133 repos_list[name].description = dbrepo.description | |
134 if dbrepo.user: | |
135 repos_list[name].contact = dbrepo.user.full_contact | |
136 else: | |
137 repos_list[name].contact = self.sa.query(User)\ | |
138 .filter(User.admin == True).first().full_contact | |
139 except OSError: | 93 except OSError: |
140 continue | 94 continue |
141 | 95 |
142 return repos_list | 96 return repos_list |
143 | 97 |
144 def get_repos(self): | 98 def get_repos(self, all_repos=None): |
145 for name, repo in _get_repos_cached().items(): | 99 """ |
100 Get all repos from db and for each such repo make backend and | |
101 fetch dependent data from db | |
102 """ | |
103 if not all_repos: | |
104 all_repos = self.sa.query(Repository).all() | |
146 | 105 |
147 if isinstance(repo, MercurialRepository) and repo._get_hidden(): | 106 for r in all_repos: |
148 #skip hidden web repository | |
149 continue | |
150 | 107 |
151 last_change = repo.last_change | 108 repo = self.get(r.repo_name) |
152 tip = h.get_changeset_safe(repo, 'tip') | |
153 | 109 |
154 tmp_d = {} | 110 if repo is not None: |
155 tmp_d['name'] = repo.name | 111 last_change = repo.last_change |
156 tmp_d['name_sort'] = tmp_d['name'].lower() | 112 tip = h.get_changeset_safe(repo, 'tip') |
157 tmp_d['description'] = repo.description | 113 |
158 tmp_d['description_sort'] = tmp_d['description'] | 114 tmp_d = {} |
159 tmp_d['last_change'] = last_change | 115 tmp_d['name'] = repo.name |
160 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple()) | 116 tmp_d['name_sort'] = tmp_d['name'].lower() |
161 tmp_d['tip'] = tip.raw_id | 117 tmp_d['description'] = repo.dbrepo.description |
162 tmp_d['tip_sort'] = tip.revision | 118 tmp_d['description_sort'] = tmp_d['description'] |
163 tmp_d['rev'] = tip.revision | 119 tmp_d['last_change'] = last_change |
164 tmp_d['contact'] = repo.contact | 120 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple()) |
165 tmp_d['contact_sort'] = tmp_d['contact'] | 121 tmp_d['tip'] = tip.raw_id |
166 tmp_d['repo_archives'] = list(repo._get_archives()) | 122 tmp_d['tip_sort'] = tip.revision |
167 tmp_d['last_msg'] = tip.message | 123 tmp_d['rev'] = tip.revision |
168 tmp_d['repo'] = repo | 124 tmp_d['contact'] = repo.dbrepo.user.full_contact |
169 yield tmp_d | 125 tmp_d['contact_sort'] = tmp_d['contact'] |
126 tmp_d['repo_archives'] = list(repo._get_archives()) | |
127 tmp_d['last_msg'] = tip.message | |
128 tmp_d['repo'] = repo | |
129 yield tmp_d | |
170 | 130 |
171 def get_repo(self, repo_name): | 131 def get_repo(self, repo_name): |
172 try: | 132 return self.get(repo_name) |
173 repo = _get_repos_cached()[repo_name] | 133 |
174 return repo | 134 def get(self, repo_name): |
175 except KeyError: | 135 """ |
176 #i we're here and we got key errors let's try to invalidate the | 136 Get's repository from given name, creates BackendInstance and |
177 #cahce and try again | 137 propagates it's data from database with all additional information |
178 invalidate_cache('cached_repo_list') | 138 :param repo_name: |
179 repo = _get_repos_cached()[repo_name] | 139 """ |
140 if not HasRepoPermissionAny('repository.read', 'repository.write', | |
141 'repository.admin')(repo_name, 'get repo check'): | |
142 return | |
143 | |
144 @cache_region('long_term', 'get_repo_cached_%s' % repo_name) | |
145 def _get_repo(repo_name): | |
146 | |
147 repo = vcs_get_repo(os.path.join(self.repos_path, repo_name), | |
148 alias=None, create=False) | |
149 | |
150 #skip hidden web repository | |
151 if isinstance(repo, MercurialRepository) and repo._get_hidden(): | |
152 return | |
153 | |
154 dbrepo = self.sa.query(Repository)\ | |
155 .options(joinedload(Repository.fork))\ | |
156 .options(joinedload(Repository.user))\ | |
157 .filter(Repository.repo_name == repo_name)\ | |
158 .scalar() | |
159 repo.dbrepo = dbrepo | |
180 return repo | 160 return repo |
181 | 161 |
162 invalidate = False | |
163 if invalidate: | |
164 log.info('INVALIDATING CACHE FOR %s', repo_name) | |
165 region_invalidate(_get_repo, None, repo_name) | |
182 | 166 |
167 return _get_repo(repo_name) | |
183 | 168 |