comparison rhodecode/model/hg_model.py @ 547:1e757ac98988

renamed project to rhodecode
author Marcin Kuzminski <marcin@python-works.com>
date Wed, 06 Oct 2010 03:18:16 +0200
parents pylons_app/model/hg_model.py@72778dda34cf
children 000b675e7c1d
comparison
equal deleted inserted replaced
546:7c2f5e4d7bbf 547:1e757ac98988
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Model for hg app
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
20 """
21 Created on April 9, 2010
22 Model for hg app
23 @author: marcink
24 """
25 from beaker.cache import cache_region
26 from mercurial import ui
27 from mercurial.hgweb.hgwebdir_mod import findrepos
28 from pylons.i18n.translation import _
29 from rhodecode.lib import helpers as h
30 from rhodecode.lib.utils import invalidate_cache
31 from rhodecode.lib.auth import HasRepoPermissionAny
32 from rhodecode.model import meta
33 from rhodecode.model.db import Repository, User
34 from sqlalchemy.orm import joinedload
35 from vcs.exceptions import RepositoryError, VCSError
36 import logging
37 import os
38 import sys
39 log = logging.getLogger(__name__)
40
41 try:
42 from vcs.backends.hg import MercurialRepository
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][0], 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][0], 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
76 class HgModel(object):
77 """Mercurial Model
78 """
79
80 def __init__(self):
81 pass
82
83 @staticmethod
84 def repo_scan(repos_prefix, repos_path, baseui, initial=False):
85 """
86 Listing of repositories in given path. This path should not be a
87 repository itself. Return a dictionary of repository objects
88 :param repos_path: path to directory it could take syntax with
89 * or ** for deep recursive displaying repositories
90 """
91 sa = meta.Session()
92 def check_repo_dir(path):
93 """Checks the repository
94 :param path:
95 """
96 repos_path = path.split('/')
97 if repos_path[-1] in ['*', '**']:
98 repos_path = repos_path[:-1]
99 if repos_path[0] != '/':
100 repos_path[0] = '/'
101 if not os.path.isdir(os.path.join(*repos_path)):
102 raise RepositoryError('Not a valid repository in %s' % path)
103 if not repos_path.endswith('*'):
104 raise VCSError('You need to specify * or ** at the end of path '
105 'for recursive scanning')
106
107 check_repo_dir(repos_path)
108 log.info('scanning for repositories in %s', repos_path)
109 repos = findrepos([(repos_prefix, repos_path)])
110 if not isinstance(baseui, ui.ui):
111 baseui = ui.ui()
112
113 repos_list = {}
114 for name, path in repos:
115 try:
116 #name = name.split('/')[-1]
117 if repos_list.has_key(name):
118 raise RepositoryError('Duplicate repository name %s found in'
119 ' %s' % (name, path))
120 else:
121
122 repos_list[name] = MercurialRepository(path, baseui=baseui)
123 repos_list[name].name = name
124
125 dbrepo = None
126 if not initial:
127 #for initial scann on application first run we don't
128 #have db repos yet.
129 dbrepo = sa.query(Repository)\
130 .options(joinedload(Repository.fork))\
131 .filter(Repository.repo_name == name)\
132 .scalar()
133
134 if dbrepo:
135 log.info('Adding db instance to cached list')
136 repos_list[name].dbrepo = dbrepo
137 repos_list[name].description = dbrepo.description
138 if dbrepo.user:
139 repos_list[name].contact = dbrepo.user.full_contact
140 else:
141 repos_list[name].contact = sa.query(User)\
142 .filter(User.admin == True).first().full_contact
143 except OSError:
144 continue
145 meta.Session.remove()
146 return repos_list
147
148 def get_repos(self):
149 for name, repo in _get_repos_cached().items():
150 if repo._get_hidden():
151 #skip hidden web repository
152 continue
153
154 last_change = repo.last_change
155 tip = h.get_changeset_safe(repo, 'tip')
156
157 tmp_d = {}
158 tmp_d['name'] = repo.name
159 tmp_d['name_sort'] = tmp_d['name'].lower()
160 tmp_d['description'] = repo.description
161 tmp_d['description_sort'] = tmp_d['description']
162 tmp_d['last_change'] = last_change
163 tmp_d['last_change_sort'] = last_change[1] - last_change[0]
164 tmp_d['tip'] = tip.short_id
165 tmp_d['tip_sort'] = tip.revision
166 tmp_d['rev'] = tip.revision
167 tmp_d['contact'] = repo.contact
168 tmp_d['contact_sort'] = tmp_d['contact']
169 tmp_d['repo_archives'] = list(repo._get_archives())
170 tmp_d['last_msg'] = tip.message
171 tmp_d['repo'] = repo
172 yield tmp_d
173
174 def get_repo(self, repo_name):
175 try:
176 repo = _get_repos_cached()[repo_name]
177 return repo
178 except KeyError:
179 #i we're here and we got key errors let's try to invalidate the
180 #cahce and try again
181 invalidate_cache('cached_repo_list')
182 repo = _get_repos_cached()[repo_name]
183 return repo
184
185
186