Mercurial > kallithea
changeset 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 | 50d9b1afaca7 |
children | 6ed37675e78b |
files | rhodecode/config/environment.py rhodecode/controllers/admin/repos.py rhodecode/controllers/admin/settings.py rhodecode/controllers/settings.py rhodecode/lib/base.py rhodecode/lib/middleware/simplegit.py rhodecode/lib/middleware/simplehg.py rhodecode/lib/utils.py rhodecode/model/hg.py rhodecode/templates/admin/users/user_edit_my_account.html rhodecode/templates/base/base.html |
diffstat | 11 files changed, 151 insertions(+), 180 deletions(-) [+] |
line wrap: on
line diff
--- a/rhodecode/config/environment.py Sat Nov 06 16:19:01 2010 +0100 +++ b/rhodecode/config/environment.py Sun Nov 07 15:02:56 2010 +0100 @@ -6,7 +6,7 @@ from rhodecode.lib.auth import set_available_permissions, set_base_path from rhodecode.lib.utils import repo2db_mapper, make_ui, set_rhodecode_config from rhodecode.model import init_model -from rhodecode.model.hg import _get_repos_cached_initial +from rhodecode.model.hg import HgModel from sqlalchemy import engine_from_config import logging import os @@ -69,7 +69,8 @@ #init baseui config['pylons.app_globals'].baseui = make_ui('db') - repo2db_mapper(_get_repos_cached_initial(config['pylons.app_globals'], initial)) + g = config['pylons.app_globals'] + repo2db_mapper(HgModel().repo_scan(g.paths[0][1], g.baseui, initial)) set_available_permissions(config) set_base_path(config) set_rhodecode_config(config)
--- a/rhodecode/controllers/admin/repos.py Sat Nov 06 16:19:01 2010 +0100 +++ b/rhodecode/controllers/admin/repos.py Sun Nov 07 15:02:56 2010 +0100 @@ -74,7 +74,6 @@ try: form_result = _form.to_python(dict(request.POST)) repo_model.create(form_result, c.rhodecode_user) - invalidate_cache('cached_repo_list') h.flash(_('created repository %s') % form_result['repo_name'], category='success') @@ -133,7 +132,7 @@ try: form_result = _form.to_python(dict(request.POST)) repo_model.update(repo_name, form_result) - invalidate_cache('cached_repo_list') + invalidate_cache('get_repo_cached_%s' % repo_name) h.flash(_('Repository %s updated succesfully' % repo_name), category='success') changed_name = form_result['repo_name'] @@ -182,7 +181,7 @@ action_logger(self.rhodecode_user, 'admin_deleted_repo', repo_name, '', self.sa) repo_model.delete(repo) - invalidate_cache('cached_repo_list') + invalidate_cache('get_repo_cached_%s' % repo_name) h.flash(_('deleted repository %s') % repo_name, category='success') except Exception, e:
--- a/rhodecode/controllers/admin/settings.py Sat Nov 06 16:19:01 2010 +0100 +++ b/rhodecode/controllers/admin/settings.py Sun Nov 07 15:02:56 2010 +0100 @@ -33,12 +33,13 @@ from rhodecode.lib.base import BaseController, render from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \ set_rhodecode_config, get_hg_settings, get_hg_ui_settings -from rhodecode.model.db import RhodeCodeSettings, RhodeCodeUi +from rhodecode.model.db import RhodeCodeSettings, RhodeCodeUi, Repository from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \ ApplicationUiSettingsForm from rhodecode.model.hg import HgModel from rhodecode.model.user import UserModel from rhodecode.lib.celerylib import tasks, run_task +from sqlalchemy import func import formencode import logging import traceback @@ -98,9 +99,12 @@ rm_obsolete = request.POST.get('destroy', False) log.debug('Rescanning directories with destroy=%s', rm_obsolete) - initial = HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui) + initial = HgModel().repo_scan(g.paths[0][1], g.baseui) + for repo_name in initial.keys(): + invalidate_cache('get_repo_cached_%s' % repo_name) + repo2db_mapper(initial, rm_obsolete) - invalidate_cache('cached_repo_list') + h.flash(_('Repositories successfully rescanned'), category='success') if setting_id == 'whoosh': @@ -238,12 +242,14 @@ """ GET /_admin/my_account Displays info about my account """ + # url('admin_settings_my_account') c.user = UserModel(self.sa).get(c.rhodecode_user.user_id, cache=False) - c.user_repos = [] - for repo in c.cached_repo_list.values(): - if repo.dbrepo.user.username == c.user.username: - c.user_repos.append(repo) + all_repos = self.sa.query(Repository)\ + .filter(Repository.user_id == c.user.user_id)\ + .order_by(func.lower(Repository.repo_name))\ + .all() + c.user_repos = HgModel().get_repos(all_repos) if c.user.username == 'default': h.flash(_("You can't edit this user since it's"
--- a/rhodecode/controllers/settings.py Sat Nov 06 16:19:01 2010 +0100 +++ b/rhodecode/controllers/settings.py Sun Nov 07 15:02:56 2010 +0100 @@ -78,7 +78,7 @@ try: form_result = _form.to_python(dict(request.POST)) repo_model.update(repo_name, form_result) - invalidate_cache('cached_repo_list') + invalidate_cache('get_repo_cached_%s' % repo_name) h.flash(_('Repository %s updated successfully' % repo_name), category='success') changed_name = form_result['repo_name'] @@ -96,7 +96,7 @@ encoding="UTF-8") except Exception: log.error(traceback.format_exc()) - h.flash(_('error occured during update of repository %s') \ + h.flash(_('error occurred during update of repository %s') \ % repo_name, category='error') return redirect(url('repo_settings_home', repo_name=changed_name)) @@ -126,7 +126,7 @@ action_logger(self.rhodecode_user, 'user_deleted_repo', repo_name, '', self.sa) repo_model.delete(repo) - invalidate_cache('cached_repo_list') + invalidate_cache('get_repo_cached_%s' % repo_name) h.flash(_('deleted repository %s') % repo_name, category='success') except Exception: h.flash(_('An error occurred during deletion of %s') % repo_name,
--- a/rhodecode/lib/base.py Sat Nov 06 16:19:01 2010 +0100 +++ b/rhodecode/lib/base.py Sun Nov 07 15:02:56 2010 +0100 @@ -9,20 +9,20 @@ from rhodecode.lib import auth from rhodecode.lib.utils import get_repo_slug from rhodecode.model import meta -from rhodecode.model.hg import _get_repos_cached, \ - _get_repos_switcher_cached +from rhodecode.model.hg import HgModel from vcs import BACKENDS + class BaseController(WSGIController): def __before__(self): c.rhodecode_version = __version__ c.rhodecode_name = config['rhodecode_title'] c.repo_name = get_repo_slug(request) - c.cached_repo_list = _get_repos_cached() - c.repo_switcher_list = _get_repos_switcher_cached(c.cached_repo_list) + c.cached_repo_list = HgModel().get_repos() c.backends = BACKENDS.keys() + if c.repo_name: - cached_repo = c.cached_repo_list.get(c.repo_name) + cached_repo = HgModel().get(c.repo_name) if cached_repo: c.repository_tags = cached_repo.tags
--- a/rhodecode/lib/middleware/simplegit.py Sat Nov 06 16:19:01 2010 +0100 +++ b/rhodecode/lib/middleware/simplegit.py Sun Nov 07 15:02:56 2010 +0100 @@ -83,15 +83,15 @@ self.repository = None self.username = None self.action = None - + def __call__(self, environ, start_response): if not is_git(environ): return self.application(environ, start_response) - + proxy_key = 'HTTP_X_REAL_IP' def_key = 'REMOTE_ADDR' self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0')) - + #=================================================================== # AUTHENTICATE THIS GIT REQUEST #=================================================================== @@ -104,7 +104,7 @@ REMOTE_USER.update(environ, result) else: return result.wsgi_application(environ, start_response) - + #======================================================================= # GET REPOSITORY #======================================================================= @@ -206,5 +206,4 @@ """we know that some change was made to repositories and we should invalidate the cache to see the changes right away but only for push requests""" - invalidate_cache('cached_repo_list') - invalidate_cache('full_changelog', repo_name) + invalidate_cache('get_repo_cached_%s' % repo_name)
--- a/rhodecode/lib/middleware/simplehg.py Sat Nov 06 16:19:01 2010 +0100 +++ b/rhodecode/lib/middleware/simplehg.py Sun Nov 07 15:02:56 2010 +0100 @@ -52,20 +52,20 @@ self.repository = None self.username = None self.action = None - + def __call__(self, environ, start_response): if not is_mercurial(environ): return self.application(environ, start_response) - + proxy_key = 'HTTP_X_REAL_IP' def_key = 'REMOTE_ADDR' self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0')) - + #=================================================================== # AUTHENTICATE THIS MERCURIAL REQUEST #=================================================================== username = REMOTE_USER(environ) - + if not username: self.authenticate.realm = self.config['rhodecode_realm'] result = self.authenticate(environ) @@ -74,7 +74,7 @@ REMOTE_USER.update(environ, result) else: return result.wsgi_application(environ, start_response) - + #======================================================================= # GET REPOSITORY #======================================================================= @@ -114,7 +114,7 @@ 'repository.admin')\ (user, repo_name): return HTTPForbidden()(environ, start_response) - + self.extras = {'ip':self.ipaddr, 'username':self.username, 'action':self.action, @@ -200,8 +200,7 @@ """we know that some change was made to repositories and we should invalidate the cache to see the changes right away but only for push requests""" - invalidate_cache('cached_repo_list') - invalidate_cache('full_changelog', repo_name) + invalidate_cache('get_repo_cached_%s' % repo_name) def __load_web_settings(self, hgserve, extras={}): @@ -209,12 +208,12 @@ hgserve.repo.ui = self.baseui hgrc = os.path.join(self.repo_path, '.hg', 'hgrc') - + #inject some additional parameters that will be available in ui #for hooks for k, v in extras.items(): hgserve.repo.ui.setconfig('rhodecode_extras', k, v) - + repoui = make_ui('file', hgrc, False) if repoui: @@ -222,7 +221,7 @@ for section in ui_sections: for k, v in repoui.configitems(section): hgserve.repo.ui.setconfig(section, k, v) - + return hgserve
--- a/rhodecode/lib/utils.py Sat Nov 06 16:19:01 2010 +0100 +++ b/rhodecode/lib/utils.py Sun Nov 07 15:02:56 2010 +0100 @@ -275,25 +275,11 @@ config[k] = v def invalidate_cache(name, *args): - """Invalidates given name cache""" - - from beaker.cache import region_invalidate - log.info('INVALIDATING CACHE FOR %s', name) - - """propagate our arguments to make sure invalidation works. First - argument has to be the name of cached func name give to cache decorator - without that the invalidation would not work""" - tmp = [name] - tmp.extend(args) - args = tuple(tmp) - - if name == 'cached_repo_list': - from rhodecode.model.hg import _get_repos_cached - region_invalidate(_get_repos_cached, None, *args) - - if name == 'full_changelog': - from rhodecode.model.hg import _full_changelog_cached - region_invalidate(_full_changelog_cached, None, *args) + """ + Puts cache invalidation task into db for + further global cache invalidation + """ + pass class EmptyChangeset(BaseChangeset): """ @@ -352,7 +338,6 @@ } rm.create(form_data, user, just_db=True) - if remove_obsolete: #remove from database those repositories that are not in the filesystem for repo in sa.query(Repository).all(): @@ -360,10 +345,6 @@ sa.delete(repo) sa.commit() - - meta.Session.remove() - - class OrderedDict(dict, DictMixin): def __init__(self, *args, **kwds):
--- a/rhodecode/model/hg.py Sat Nov 06 16:19:01 2010 +0100 +++ b/rhodecode/model/hg.py Sun Nov 07 15:02:56 2010 +0100 @@ -22,57 +22,25 @@ Model for RhodeCode @author: marcink """ -from beaker.cache import cache_region +from beaker.cache import cache_region, region_invalidate from mercurial import ui from rhodecode.lib import helpers as h -from rhodecode.lib.utils import invalidate_cache from rhodecode.lib.auth import HasRepoPermissionAny +from rhodecode.lib.utils import get_repos from rhodecode.model import meta -from rhodecode.model.db import Repository, User +from rhodecode.model.caching_query import FromCache +from rhodecode.model.db import Repository, User, RhodeCodeUi from sqlalchemy.orm import joinedload +from vcs import get_repo as vcs_get_repo, get_backend +from vcs.backends.hg import MercurialRepository from vcs.exceptions import RepositoryError, VCSError +from vcs.utils.lazy import LazyProperty import logging -import sys +import os import time log = logging.getLogger(__name__) -try: - from vcs.backends.hg import MercurialRepository - from vcs.backends.git import GitRepository -except ImportError: - sys.stderr.write('You have to import vcs module') - raise Exception('Unable to import vcs') - -def _get_repos_cached_initial(app_globals, initial): - """return cached dict with repos - """ - g = app_globals - return HgModel().repo_scan(g.paths[0][1], g.baseui, initial) - -@cache_region('long_term', 'cached_repo_list') -def _get_repos_cached(): - """return cached dict with repos - """ - log.info('getting all repositories list') - from pylons import app_globals as g - return HgModel().repo_scan(g.paths[0][1], g.baseui) - -@cache_region('super_short_term', 'cached_repos_switcher_list') -def _get_repos_switcher_cached(cached_repo_list): - repos_lst = [] - for repo in [x for x in cached_repo_list.values()]: - if HasRepoPermissionAny('repository.write', 'repository.read', - 'repository.admin')(repo.name, 'main page check'): - repos_lst.append((repo.name, repo.dbrepo.private,)) - - return sorted(repos_lst, key=lambda k:k[0].lower()) - -@cache_region('long_term', 'full_changelog') -def _full_changelog_cached(repo_name): - log.info('getting full changelog for %s', repo_name) - return list(reversed(list(HgModel().get_repo(repo_name)))) - class HgModel(object): """ Mercurial Model @@ -84,6 +52,16 @@ else: self.sa = sa + + @LazyProperty + def repos_path(self): + """ + Get's the repositories root path from database + """ + q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one() + + return q.ui_value + def repo_scan(self, repos_path, baseui, initial=False): """ Listing of repositories in given path. This path should not be a @@ -91,93 +69,100 @@ :param repos_path: path to directory containing repositories :param baseui - :param initial: initial scann + :param initial: initial scan """ log.info('scanning for repositories in %s', repos_path) if not isinstance(baseui, ui.ui): baseui = ui.ui() - - from rhodecode.lib.utils import get_repos - repos = get_repos(repos_path) - - repos_list = {} - for name, path in repos: + for name, path in get_repos(repos_path): try: - #name = name.split('/')[-1] if repos_list.has_key(name): - raise RepositoryError('Duplicate repository name %s found in' - ' %s' % (name, path)) + raise RepositoryError('Duplicate repository name %s ' + 'found in %s' % (name, path)) else: + + klass = get_backend(path[0]) + if path[0] == 'hg': - repos_list[name] = MercurialRepository(path[1], baseui=baseui) - repos_list[name].name = name + repos_list[name] = klass(path[1], baseui=baseui) if path[0] == 'git': - repos_list[name] = GitRepository(path[1]) - repos_list[name].name = name - - dbrepo = None - if not initial: - #for initial scann on application first run we don't - #have db repos yet. - dbrepo = self.sa.query(Repository)\ - .options(joinedload(Repository.fork))\ - .filter(Repository.repo_name == name)\ - .scalar() - - if dbrepo: - log.info('Adding db instance to cached list') - repos_list[name].dbrepo = dbrepo - repos_list[name].description = dbrepo.description - if dbrepo.user: - repos_list[name].contact = dbrepo.user.full_contact - else: - repos_list[name].contact = self.sa.query(User)\ - .filter(User.admin == True).first().full_contact + repos_list[name] = klass(path[1]) except OSError: continue return repos_list - def get_repos(self): - for name, repo in _get_repos_cached().items(): + def get_repos(self, all_repos=None): + """ + Get all repos from db and for each such repo make backend and + fetch dependent data from db + """ + if not all_repos: + all_repos = self.sa.query(Repository).all() - if isinstance(repo, MercurialRepository) and repo._get_hidden(): - #skip hidden web repository - continue + for r in all_repos: + + repo = self.get(r.repo_name) - last_change = repo.last_change - tip = h.get_changeset_safe(repo, 'tip') + if repo is not None: + last_change = repo.last_change + tip = h.get_changeset_safe(repo, 'tip') - tmp_d = {} - tmp_d['name'] = repo.name - tmp_d['name_sort'] = tmp_d['name'].lower() - tmp_d['description'] = repo.description - tmp_d['description_sort'] = tmp_d['description'] - tmp_d['last_change'] = last_change - tmp_d['last_change_sort'] = time.mktime(last_change.timetuple()) - tmp_d['tip'] = tip.raw_id - tmp_d['tip_sort'] = tip.revision - tmp_d['rev'] = tip.revision - tmp_d['contact'] = repo.contact - tmp_d['contact_sort'] = tmp_d['contact'] - tmp_d['repo_archives'] = list(repo._get_archives()) - tmp_d['last_msg'] = tip.message - tmp_d['repo'] = repo - yield tmp_d + tmp_d = {} + tmp_d['name'] = repo.name + tmp_d['name_sort'] = tmp_d['name'].lower() + tmp_d['description'] = repo.dbrepo.description + tmp_d['description_sort'] = tmp_d['description'] + tmp_d['last_change'] = last_change + tmp_d['last_change_sort'] = time.mktime(last_change.timetuple()) + tmp_d['tip'] = tip.raw_id + tmp_d['tip_sort'] = tip.revision + tmp_d['rev'] = tip.revision + tmp_d['contact'] = repo.dbrepo.user.full_contact + tmp_d['contact_sort'] = tmp_d['contact'] + tmp_d['repo_archives'] = list(repo._get_archives()) + tmp_d['last_msg'] = tip.message + tmp_d['repo'] = repo + yield tmp_d def get_repo(self, repo_name): - try: - repo = _get_repos_cached()[repo_name] - return repo - except KeyError: - #i we're here and we got key errors let's try to invalidate the - #cahce and try again - invalidate_cache('cached_repo_list') - repo = _get_repos_cached()[repo_name] + return self.get(repo_name) + + def get(self, repo_name): + """ + Get's repository from given name, creates BackendInstance and + propagates it's data from database with all additional information + :param repo_name: + """ + if not HasRepoPermissionAny('repository.read', 'repository.write', + 'repository.admin')(repo_name, 'get repo check'): + return + + @cache_region('long_term', 'get_repo_cached_%s' % repo_name) + def _get_repo(repo_name): + + repo = vcs_get_repo(os.path.join(self.repos_path, repo_name), + alias=None, create=False) + + #skip hidden web repository + if isinstance(repo, MercurialRepository) and repo._get_hidden(): + return + + dbrepo = self.sa.query(Repository)\ + .options(joinedload(Repository.fork))\ + .options(joinedload(Repository.user))\ + .filter(Repository.repo_name == repo_name)\ + .scalar() + repo.dbrepo = dbrepo return repo + invalidate = False + if invalidate: + log.info('INVALIDATING CACHE FOR %s', repo_name) + region_invalidate(_get_repo, None, repo_name) + return _get_repo(repo_name)
--- a/rhodecode/templates/admin/users/user_edit_my_account.html Sat Nov 06 16:19:01 2010 +0100 +++ b/rhodecode/templates/admin/users/user_edit_my_account.html Sun Nov 07 15:02:56 2010 +0100 @@ -100,32 +100,32 @@ %for repo in c.user_repos: <tr> <td> - %if repo.dbrepo.repo_type =='hg': + %if repo['repo'].dbrepo.repo_type =='hg': <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/> - %elif repo.dbrepo.repo_type =='git': + %elif repo['repo'].dbrepo.repo_type =='git': <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/> %else: %endif - %if repo.dbrepo.private: + %if repo['repo'].dbrepo.private: <img class="icon" alt="${_('private')}" src="/images/icons/lock.png"/> %else: <img class="icon" alt="${_('public')}" src="/images/icons/lock_open.png"/> %endif - ${h.link_to(repo.name, h.url('summary_home',repo_name=repo.name),class_="repo_name")} - %if repo.dbrepo.fork: - <a href="${h.url('summary_home',repo_name=repo.dbrepo.fork.repo_name)}"> + ${h.link_to(repo['repo'].name, h.url('summary_home',repo_name=repo['repo'].name),class_="repo_name")} + %if repo['repo'].dbrepo.fork: + <a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}"> <img class="icon" alt="${_('public')}" - title="${_('Fork of')} ${repo.dbrepo.fork.repo_name}" + title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}" src="/images/icons/arrow_divide.png"/></a> %endif </td> - <td><span class="tooltip" tooltip_title="${repo.last_change}">${("r%s:%s") % (h.get_changeset_safe(repo,'tip').revision,h.short_id(h.get_changeset_safe(repo,'tip').raw_id))}</span></td> - <td><a href="${h.url('repo_settings_home',repo_name=repo.name)}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="/images/icons/application_form_edit.png"/></a></td> + <td><span class="tooltip" tooltip_title="${repo['repo'].last_change}">${("r%s:%s") % (h.get_changeset_safe(repo['repo'],'tip').revision,h.short_id(h.get_changeset_safe(repo['repo'],'tip').raw_id))}</span></td> + <td><a href="${h.url('repo_settings_home',repo_name=repo['repo'].name)}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="/images/icons/application_form_edit.png"/></a></td> <td> - ${h.form(url('repo_settings_delete', repo_name=repo.name),method='delete')} - ${h.submit('remove_%s' % repo.name,'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")} + ${h.form(url('repo_settings_delete', repo_name=repo['repo'].name),method='delete')} + ${h.submit('remove_%s' % repo['repo'].name,'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")} ${h.end_form()} </td> </tr>
--- a/rhodecode/templates/base/base.html Sat Nov 06 16:19:01 2010 +0100 +++ b/rhodecode/templates/base/base.html Sun Nov 07 15:02:56 2010 +0100 @@ -98,11 +98,12 @@ <span>↓</span> </a> <ul class="repo_switcher"> - %for repo,private in c.repo_switcher_list: - %if private: - <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="private_repo")}</li> + %for repo in c.cached_repo_list: + + %if repo['repo'].dbrepo.private: + <li>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="private_repo %s" % repo['repo'].dbrepo.repo_type)}</li> %else: - <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="public_repo")}</li> + <li>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="public_repo %s" % repo['repo'].dbrepo.repo_type)}</li> %endif %endfor </ul>