comparison rhodecode/model/scm.py @ 691:7486da5f0628 beta

Refactor codes for scm model Some test updates, added test for admin user controller
author Marcin Kuzminski <marcin@python-works.com>
date Sun, 14 Nov 2010 22:54:16 +0100
parents rhodecode/model/hg.py@4685f3eafd35
children cb0d9ce6ac5c
comparison
equal deleted inserted replaced
690:4685f3eafd35 691:7486da5f0628
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Model for RhodeCode
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 RhodeCode
23 @author: marcink
24 """
25 from beaker.cache import cache_region, region_invalidate
26 from mercurial import ui
27 from rhodecode.lib import helpers as h
28 from rhodecode.lib.auth import HasRepoPermissionAny
29 from rhodecode.lib.utils import get_repos
30 from rhodecode.model import meta
31 from rhodecode.model.db import Repository, User, RhodeCodeUi
32 from sqlalchemy.orm import joinedload
33 from vcs import get_backend
34 from vcs.utils.helpers import get_scm
35 from vcs.exceptions import RepositoryError, VCSError
36 from vcs.utils.lazy import LazyProperty
37 import logging
38 import os
39 import time
40
41 log = logging.getLogger(__name__)
42
43 class ScmModel(object):
44 """
45 Mercurial Model
46 """
47
48 def __init__(self, sa=None):
49 if not sa:
50 self.sa = meta.Session()
51 else:
52 self.sa = sa
53
54
55 @LazyProperty
56 def repos_path(self):
57 """
58 Get's the repositories root path from database
59 """
60 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
61
62 return q.ui_value
63
64 def repo_scan(self, repos_path, baseui, initial=False):
65 """
66 Listing of repositories in given path. This path should not be a
67 repository itself. Return a dictionary of repository objects
68
69 :param repos_path: path to directory containing repositories
70 :param baseui
71 :param initial: initial scan
72 """
73 log.info('scanning for repositories in %s', repos_path)
74
75 if not isinstance(baseui, ui.ui):
76 baseui = ui.ui()
77 repos_list = {}
78
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:
85
86 klass = get_backend(path[0])
87
88 if path[0] == 'hg':
89 repos_list[name] = klass(path[1], baseui=baseui)
90
91 if path[0] == 'git':
92 repos_list[name] = klass(path[1])
93 except OSError:
94 continue
95
96 return repos_list
97
98 def get_repos(self, all_repos=None):
99 """
100 Get all repos from db and for each repo create it's backend instance.
101 and fill that backed with information from database
102
103 :param all_repos: give specific repositories list, good for filtering
104 """
105 if not all_repos:
106 all_repos = self.sa.query(Repository).all()
107
108 for r in all_repos:
109
110 repo = self.get(r.repo_name)
111
112 if repo is not None:
113 last_change = repo.last_change
114 tip = h.get_changeset_safe(repo, 'tip')
115
116 tmp_d = {}
117 tmp_d['name'] = repo.name
118 tmp_d['name_sort'] = tmp_d['name'].lower()
119 tmp_d['description'] = repo.dbrepo.description
120 tmp_d['description_sort'] = tmp_d['description']
121 tmp_d['last_change'] = last_change
122 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
123 tmp_d['tip'] = tip.raw_id
124 tmp_d['tip_sort'] = tip.revision
125 tmp_d['rev'] = tip.revision
126 tmp_d['contact'] = repo.dbrepo.user.full_contact
127 tmp_d['contact_sort'] = tmp_d['contact']
128 tmp_d['repo_archives'] = list(repo._get_archives())
129 tmp_d['last_msg'] = tip.message
130 tmp_d['repo'] = repo
131 yield tmp_d
132
133 def get_repo(self, repo_name):
134 return self.get(repo_name)
135
136 def get(self, repo_name):
137 """
138 Get's repository from given name, creates BackendInstance and
139 propagates it's data from database with all additional information
140 :param repo_name:
141 """
142 if not HasRepoPermissionAny('repository.read', 'repository.write',
143 'repository.admin')(repo_name, 'get repo check'):
144 return
145
146 @cache_region('long_term', 'get_repo_cached_%s' % repo_name)
147 def _get_repo(repo_name):
148
149 repo_path = os.path.join(self.repos_path, repo_name)
150 alias = get_scm(repo_path)[0]
151
152 log.debug('Creating instance of %s repository', alias)
153 backend = get_backend(alias)
154
155 if alias == 'hg':
156 repo = backend(repo_path, create=False, baseui=None)
157 #skip hidden web repository
158 if repo._get_hidden():
159 return
160 else:
161 repo = backend(repo_path, create=False)
162
163 dbrepo = self.sa.query(Repository)\
164 .options(joinedload(Repository.fork))\
165 .options(joinedload(Repository.user))\
166 .filter(Repository.repo_name == repo_name)\
167 .scalar()
168 repo.dbrepo = dbrepo
169 return repo
170
171 invalidate = False
172 if invalidate:
173 log.info('INVALIDATING CACHE FOR %s', repo_name)
174 region_invalidate(_get_repo, None, repo_name)
175
176 return _get_repo(repo_name)
177