##// END OF EJS Templates
fixed hooks broken symlink issue...
marcink -
r679:d85b0948 rhodecode-0.0.1.0.2 default
parent child Browse files
Show More
@@ -1,14 +1,15 b''
1 1 include rhodecode/config/deployment.ini_tmpl
2 2
3 3 include README.rst
4 4 recursive-include rhodecode/i18n/ *
5 5
6 6 #images
7 7 recursive-include rhodecode/public/css *
8 8 recursive-include rhodecode/public/images *
9 9 #js
10 10 include rhodecode/public/js/yui2.js
11 11 include rhodecode/public/js/excanvas.min.js
12 12 include rhodecode/public/js/yui.flot.js
13 include rhodecode/public/js/graph.js
13 14 #templates
14 15 recursive-include rhodecode/templates *
@@ -1,46 +1,54 b''
1 1 .. _changelog:
2 2
3 3 Changelog
4 4 =========
5 5
6 1.0.2 (**2010-11-XX**)
7 ----------------------
8
9 - fixed #59 missing graph.js
10 - fixed repo_size crash when repository had broken symlinks
11 - fixed python2.5 crashes.
12 - tested under python2.7
13 - bumped sqlalcehmy and celery versions
6 14
7 15 1.0.1 (**2010-11-10**)
8 16 ----------------------
9 17
10 18 - fixed #53 python2.5 incompatible enumerate calls
11 19 - fixed #52 disable mercurial extension for web
12 20 - fixed #51 deleting repositories don't delete it's dependent objects
13 21 - small css updated
14 22
15 23
16 24 1.0.0 (**2010-11-02**)
17 25 ----------------------
18 26
19 27 - security bugfix simplehg wasn't checking for permissions on commands
20 28 other than pull or push.
21 29 - fixed doubled messages after push or pull in admin journal
22 30 - templating and css corrections, fixed repo switcher on chrome, updated titles
23 31 - admin menu accessible from options menu on repository view
24 32 - permissions cached queries
25 33
26 34 1.0.0rc4 (**2010-10-12**)
27 35 --------------------------
28 36
29 37 - fixed python2.5 missing simplejson imports (thanks to Jens BΓ€ckman)
30 38 - removed cache_manager settings from sqlalchemy meta
31 39 - added sqlalchemy cache settings to ini files
32 40 - validated password length and added second try of failure on paster setup-app
33 41 - fixed setup database destroy prompt even when there was no db
34 42
35 43
36 44 1.0.0rc3 (**2010-10-11**)
37 45 -------------------------
38 46
39 47 - fixed i18n during installation.
40 48
41 49 1.0.0rc2 (**2010-10-11**)
42 50 -------------------------
43 51
44 52 - Disabled dirsize in file browser, it's causing nasty bug when dir renames
45 53 occure. After vcs is fixed it'll be put back again.
46 54 - templating/css rewrites, optimized css.
@@ -1,35 +1,35 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 # RhodeCode, a web based repository management based on pylons
4 4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; version 2
9 9 # of the License or (at your opinion) any later version of the license.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 19 # MA 02110-1301, USA.
20 20 """
21 21 Created on April 9, 2010
22 22 RhodeCode, a web based repository management based on pylons
23 23 versioning implementation: http://semver.org/
24 24 @author: marcink
25 25 """
26 26
27 VERSION = (1, 0, 1,)
27 VERSION = (1, 0, 2,)
28 28
29 29 __version__ = '.'.join((str(each) for each in VERSION[:4]))
30 30
31 31 def get_version():
32 32 """
33 33 Returns shorter version (digit parts only) as string.
34 34 """
35 35 return '.'.join((str(each) for each in VERSION[:3]))
@@ -1,64 +1,71 b''
1 1 from rhodecode.lib.pidlock import DaemonLock, LockHeld
2 2 from vcs.utils.lazy import LazyProperty
3 3 from decorator import decorator
4 4 import logging
5 5 import os
6 6 import sys
7 7 import traceback
8 8 from hashlib import md5
9 9 import socket
10 10 log = logging.getLogger(__name__)
11 11
12 12 class ResultWrapper(object):
13 13 def __init__(self, task):
14 14 self.task = task
15
15
16 16 @LazyProperty
17 17 def result(self):
18 18 return self.task
19 19
20 20 def run_task(task, *args, **kwargs):
21 21 try:
22 22 t = task.delay(*args, **kwargs)
23 23 log.info('running task %s', t.task_id)
24 24 return t
25 25 except socket.error, e:
26 if e.errno == 111:
26
27 try:
28 conn_failed = e.errno == 111
29 except AttributeError:
30 conn_failed = False
31
32 if conn_failed:
27 33 log.debug('Unable to connect to celeryd. Sync execution')
28 34 else:
29 log.error(traceback.format_exc())
35 log.debug('Unable to connect to celeryd. Sync execution')
36
30 37 except KeyError, e:
31 38 log.debug('Unable to connect to celeryd. Sync execution')
32 39 except Exception, e:
33 40 log.error(traceback.format_exc())
34
41
35 42 return ResultWrapper(task(*args, **kwargs))
36 43
37 44
38 45 def locked_task(func):
39 46 def __wrapper(func, *fargs, **fkwargs):
40 47 params = list(fargs)
41 48 params.extend(['%s-%s' % ar for ar in fkwargs.items()])
42
49
43 50 lockkey = 'task_%s' % \
44 51 md5(str(func.__name__) + '-' + \
45 52 '-'.join(map(str, params))).hexdigest()
46 53 log.info('running task with lockkey %s', lockkey)
47 54 try:
48 55 l = DaemonLock(lockkey)
49 56 ret = func(*fargs, **fkwargs)
50 57 l.release()
51 58 return ret
52 59 except LockHeld:
53 60 log.info('LockHeld')
54 return 'Task with key %s already running' % lockkey
61 return 'Task with key %s already running' % lockkey
55 62
56 return decorator(__wrapper, func)
57
63 return decorator(__wrapper, func)
64
65
58 66
59
60
61
62
63
64
67
68
69
70
71
@@ -1,78 +1,84 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 # custom hooks for application
4 4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; version 2
9 9 # of the License or (at your opinion) any later version of the license.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 19 # MA 02110-1301, USA.
20 20 """
21 21 Created on Aug 6, 2010
22 22
23 23 @author: marcink
24 24 """
25 25
26 26 import sys
27 27 import os
28 28 from rhodecode.lib import helpers as h
29 29 from rhodecode.model import meta
30 30 from rhodecode.model.db import UserLog, User
31 31
32 32 def repo_size(ui, repo, hooktype=None, **kwargs):
33 33
34 34 if hooktype != 'changegroup':
35 35 return False
36 36 size_hg, size_root = 0, 0
37 37 for path, dirs, files in os.walk(repo.root):
38 38 if path.find('.hg') != -1:
39 39 for f in files:
40 size_hg += os.path.getsize(os.path.join(path, f))
40 try:
41 size_hg += os.path.getsize(os.path.join(path, f))
42 except OSError:
43 pass
41 44 else:
42 45 for f in files:
43 size_root += os.path.getsize(os.path.join(path, f))
44
46 try:
47 size_root += os.path.getsize(os.path.join(path, f))
48 except OSError:
49 pass
50
45 51 size_hg_f = h.format_byte_size(size_hg)
46 52 size_root_f = h.format_byte_size(size_root)
47 53 size_total_f = h.format_byte_size(size_root + size_hg)
48 54 sys.stdout.write('Repository size .hg:%s repo:%s total:%s\n' \
49 55 % (size_hg_f, size_root_f, size_total_f))
50 56
51 57 user_action_mapper(ui, repo, hooktype, **kwargs)
52 58
53 59 def user_action_mapper(ui, repo, hooktype=None, **kwargs):
54 60 """
55 61 Maps user last push action to new changeset id, from mercurial
56 62 :param ui:
57 63 :param repo:
58 64 :param hooktype:
59 65 """
60 66
61 67 try:
62 68 sa = meta.Session
63 69 username = kwargs['url'].split(':')[-1]
64 70 user_log = sa.query(UserLog)\
65 71 .filter(UserLog.user == sa.query(User)\
66 72 .filter(User.username == username).one())\
67 73 .order_by(UserLog.user_log_id.desc()).first()
68 74
69 75 if user_log and not user_log.revision:
70 76 user_log.revision = str(repo['tip'])
71 77 sa.add(user_log)
72 78 sa.commit()
73 79
74 80 except Exception, e:
75 81 sa.rollback()
76 82 raise
77 83 finally:
78 84 meta.Session.remove()
@@ -1,512 +1,515 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 # Utilities for RhodeCode
4 4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 5 # This program is free software; you can redistribute it and/or
6 6 # modify it under the terms of the GNU General Public License
7 7 # as published by the Free Software Foundation; version 2
8 8 # of the License or (at your opinion) any later version of the license.
9 9 #
10 10 # This program is distributed in the hope that it will be useful,
11 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 13 # GNU General Public License for more details.
14 14 #
15 15 # You should have received a copy of the GNU General Public License
16 16 # along with this program; if not, write to the Free Software
17 17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 18 # MA 02110-1301, USA.
19 19
20 20 """
21 21 Created on April 18, 2010
22 22 Utilities for RhodeCode
23 23 @author: marcink
24 24 """
25 25 from beaker.cache import cache_region
26 26 from mercurial import ui, config, hg
27 27 from mercurial.error import RepoError
28 28 from rhodecode.model import meta
29 29 from rhodecode.model.db import Repository, User, RhodeCodeUi, RhodeCodeSettings, UserLog
30 30 from vcs.backends.base import BaseChangeset
31 31 from vcs.utils.lazy import LazyProperty
32 32 import logging
33 33 import datetime
34 34 import os
35 35
36 36 log = logging.getLogger(__name__)
37 37
38 38
39 39 def get_repo_slug(request):
40 40 return request.environ['pylons.routes_dict'].get('repo_name')
41 41
42 42 def is_mercurial(environ):
43 43 """
44 44 Returns True if request's target is mercurial server - header
45 45 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
46 46 """
47 47 http_accept = environ.get('HTTP_ACCEPT')
48 48 if http_accept and http_accept.startswith('application/mercurial'):
49 49 return True
50 50 return False
51 51
52 52 def is_git(environ):
53 53 """
54 54 Returns True if request's target is git server. ``HTTP_USER_AGENT`` would
55 55 then have git client version given.
56 56
57 57 :param environ:
58 58 """
59 59 http_user_agent = environ.get('HTTP_USER_AGENT')
60 60 if http_user_agent.startswith('git'):
61 61 return True
62 62 return False
63 63
64 64 def action_logger(user, action, repo, ipaddr, sa=None):
65 65 """
66 66 Action logger for various action made by users
67 67 """
68 68
69 69 if not sa:
70 70 sa = meta.Session
71 71
72 72 try:
73 73 if hasattr(user, 'user_id'):
74 74 user_id = user.user_id
75 75 elif isinstance(user, basestring):
76 76 user_id = sa.query(User).filter(User.username == user).one()
77 77 else:
78 78 raise Exception('You have to provide user object or username')
79 79
80 80 repo_name = repo.lstrip('/')
81 81 user_log = UserLog()
82 82 user_log.user_id = user_id
83 83 user_log.action = action
84 84 user_log.repository_name = repo_name
85 85 user_log.repository = sa.query(Repository)\
86 86 .filter(Repository.repo_name == repo_name).one()
87 87 user_log.action_date = datetime.datetime.now()
88 88 user_log.user_ip = ipaddr
89 89 sa.add(user_log)
90 90 sa.commit()
91 91
92 92 log.info('Adding user %s, action %s on %s',
93 93 user.username, action, repo)
94 94 except Exception, e:
95 95 sa.rollback()
96 96 log.error('could not log user action:%s', str(e))
97 97
98 98 def check_repo_dir(paths):
99 99 repos_path = paths[0][1].split('/')
100 100 if repos_path[-1] in ['*', '**']:
101 101 repos_path = repos_path[:-1]
102 102 if repos_path[0] != '/':
103 103 repos_path[0] = '/'
104 104 if not os.path.isdir(os.path.join(*repos_path)):
105 105 raise Exception('Not a valid repository in %s' % paths[0][1])
106 106
107 107 def check_repo_fast(repo_name, base_path):
108 108 if os.path.isdir(os.path.join(base_path, repo_name)):return False
109 109 return True
110 110
111 111 def check_repo(repo_name, base_path, verify=True):
112 112
113 113 repo_path = os.path.join(base_path, repo_name)
114 114
115 115 try:
116 116 if not check_repo_fast(repo_name, base_path):
117 117 return False
118 118 r = hg.repository(ui.ui(), repo_path)
119 119 if verify:
120 120 hg.verify(r)
121 121 #here we hnow that repo exists it was verified
122 122 log.info('%s repo is already created', repo_name)
123 123 return False
124 124 except RepoError:
125 125 #it means that there is no valid repo there...
126 126 log.info('%s repo is free for creation', repo_name)
127 127 return True
128 128
129 129 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
130 130 while True:
131 131 ok = raw_input(prompt)
132 132 if ok in ('y', 'ye', 'yes'): return True
133 133 if ok in ('n', 'no', 'nop', 'nope'): return False
134 134 retries = retries - 1
135 135 if retries < 0: raise IOError
136 136 print complaint
137 137
138 138 @cache_region('super_short_term', 'cached_hg_ui')
139 139 def get_hg_ui_cached():
140 140 try:
141 141 sa = meta.Session
142 142 ret = sa.query(RhodeCodeUi).all()
143 143 finally:
144 144 meta.Session.remove()
145 145 return ret
146 146
147 147
148 148 def get_hg_settings():
149 149 try:
150 150 sa = meta.Session
151 151 ret = sa.query(RhodeCodeSettings).all()
152 152 finally:
153 153 meta.Session.remove()
154 154
155 155 if not ret:
156 156 raise Exception('Could not get application settings !')
157 157 settings = {}
158 158 for each in ret:
159 159 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
160 160
161 161 return settings
162 162
163 163 def get_hg_ui_settings():
164 164 try:
165 165 sa = meta.Session
166 166 ret = sa.query(RhodeCodeUi).all()
167 167 finally:
168 168 meta.Session.remove()
169 169
170 170 if not ret:
171 171 raise Exception('Could not get application ui settings !')
172 172 settings = {}
173 173 for each in ret:
174 174 k = each.ui_key
175 175 v = each.ui_value
176 176 if k == '/':
177 177 k = 'root_path'
178 178
179 179 if k.find('.') != -1:
180 180 k = k.replace('.', '_')
181 181
182 182 if each.ui_section == 'hooks':
183 183 v = each.ui_active
184 184
185 185 settings[each.ui_section + '_' + k] = v
186 186
187 187 return settings
188 188
189 189 #propagated from mercurial documentation
190 190 ui_sections = ['alias', 'auth',
191 191 'decode/encode', 'defaults',
192 192 'diff', 'email',
193 193 'extensions', 'format',
194 194 'merge-patterns', 'merge-tools',
195 195 'hooks', 'http_proxy',
196 196 'smtp', 'patch',
197 197 'paths', 'profiling',
198 198 'server', 'trusted',
199 199 'ui', 'web', ]
200 200
201 201 def make_ui(read_from='file', path=None, checkpaths=True):
202 202 """
203 203 A function that will read python rc files or database
204 204 and make an mercurial ui object from read options
205 205
206 206 :param path: path to mercurial config file
207 207 :param checkpaths: check the path
208 208 :param read_from: read from 'file' or 'db'
209 209 """
210 210
211 211 baseui = ui.ui()
212 212
213 213 if read_from == 'file':
214 214 if not os.path.isfile(path):
215 215 log.warning('Unable to read config file %s' % path)
216 216 return False
217 217 log.debug('reading hgrc from %s', path)
218 218 cfg = config.config()
219 219 cfg.read(path)
220 220 for section in ui_sections:
221 221 for k, v in cfg.items(section):
222 222 baseui.setconfig(section, k, v)
223 223 log.debug('settings ui from file[%s]%s:%s', section, k, v)
224 224
225 225 for k, v in baseui.configitems('extensions'):
226 226 baseui.setconfig('extensions', k, '0')
227 227 #just enable mq
228 228 baseui.setconfig('extensions', 'mq', '1')
229 229 if checkpaths:check_repo_dir(cfg.items('paths'))
230 230
231 231
232 232 elif read_from == 'db':
233 233 hg_ui = get_hg_ui_cached()
234 234 for ui_ in hg_ui:
235 235 if ui_.ui_active:
236 236 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section, ui_.ui_key, ui_.ui_value)
237 237 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
238 238
239 239
240 240 return baseui
241 241
242 242
243 243 def set_rhodecode_config(config):
244 244 hgsettings = get_hg_settings()
245 245
246 246 for k, v in hgsettings.items():
247 247 config[k] = v
248 248
249 249 def invalidate_cache(name, *args):
250 250 """Invalidates given name cache"""
251 251
252 252 from beaker.cache import region_invalidate
253 253 log.info('INVALIDATING CACHE FOR %s', name)
254 254
255 255 """propagate our arguments to make sure invalidation works. First
256 256 argument has to be the name of cached func name give to cache decorator
257 257 without that the invalidation would not work"""
258 258 tmp = [name]
259 259 tmp.extend(args)
260 260 args = tuple(tmp)
261 261
262 262 if name == 'cached_repo_list':
263 263 from rhodecode.model.hg_model import _get_repos_cached
264 264 region_invalidate(_get_repos_cached, None, *args)
265 265
266 266 if name == 'full_changelog':
267 267 from rhodecode.model.hg_model import _full_changelog_cached
268 268 region_invalidate(_full_changelog_cached, None, *args)
269 269
270 270 class EmptyChangeset(BaseChangeset):
271 271 """
272 272 An dummy empty changeset.
273 273 """
274 274
275 275 revision = -1
276 276 message = ''
277 277 author = ''
278 278 date = ''
279 279 @LazyProperty
280 280 def raw_id(self):
281 281 """
282 282 Returns raw string identifing this changeset, useful for web
283 283 representation.
284 284 """
285 285 return '0' * 40
286 286
287 287 @LazyProperty
288 288 def short_id(self):
289 289 return self.raw_id[:12]
290 290
291 291 def get_file_changeset(self, path):
292 292 return self
293 293
294 294 def get_file_content(self, path):
295 295 return u''
296 296
297 297 def get_file_size(self, path):
298 298 return 0
299 299
300 300 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
301 301 """
302 302 maps all found repositories into db
303 303 """
304 304 from rhodecode.model.repo_model import RepoModel
305 305
306 306 sa = meta.Session
307 307 user = sa.query(User).filter(User.admin == True).first()
308 308
309 309 rm = RepoModel()
310 310
311 311 for name, repo in initial_repo_list.items():
312 312 if not sa.query(Repository).filter(Repository.repo_name == name).scalar():
313 313 log.info('repository %s not found creating default', name)
314 314
315 315 form_data = {
316 316 'repo_name':name,
317 317 'description':repo.description if repo.description != 'unknown' else \
318 318 'auto description for %s' % name,
319 319 'private':False
320 320 }
321 321 rm.create(form_data, user, just_db=True)
322 322
323 323
324 324 if remove_obsolete:
325 325 #remove from database those repositories that are not in the filesystem
326 326 for repo in sa.query(Repository).all():
327 327 if repo.repo_name not in initial_repo_list.keys():
328 328 sa.delete(repo)
329 329 sa.commit()
330 330
331 331
332 332 meta.Session.remove()
333 333
334 334 from UserDict import DictMixin
335 335
336 336 class OrderedDict(dict, DictMixin):
337 337
338 338 def __init__(self, *args, **kwds):
339 339 if len(args) > 1:
340 340 raise TypeError('expected at most 1 arguments, got %d' % len(args))
341 341 try:
342 342 self.__end
343 343 except AttributeError:
344 344 self.clear()
345 345 self.update(*args, **kwds)
346 346
347 347 def clear(self):
348 348 self.__end = end = []
349 349 end += [None, end, end] # sentinel node for doubly linked list
350 350 self.__map = {} # key --> [key, prev, next]
351 351 dict.clear(self)
352 352
353 353 def __setitem__(self, key, value):
354 354 if key not in self:
355 355 end = self.__end
356 356 curr = end[1]
357 357 curr[2] = end[1] = self.__map[key] = [key, curr, end]
358 358 dict.__setitem__(self, key, value)
359 359
360 360 def __delitem__(self, key):
361 361 dict.__delitem__(self, key)
362 362 key, prev, next = self.__map.pop(key)
363 363 prev[2] = next
364 364 next[1] = prev
365 365
366 366 def __iter__(self):
367 367 end = self.__end
368 368 curr = end[2]
369 369 while curr is not end:
370 370 yield curr[0]
371 371 curr = curr[2]
372 372
373 373 def __reversed__(self):
374 374 end = self.__end
375 375 curr = end[1]
376 376 while curr is not end:
377 377 yield curr[0]
378 378 curr = curr[1]
379 379
380 380 def popitem(self, last=True):
381 381 if not self:
382 382 raise KeyError('dictionary is empty')
383 383 if last:
384 384 key = reversed(self).next()
385 385 else:
386 386 key = iter(self).next()
387 387 value = self.pop(key)
388 388 return key, value
389 389
390 390 def __reduce__(self):
391 391 items = [[k, self[k]] for k in self]
392 392 tmp = self.__map, self.__end
393 393 del self.__map, self.__end
394 394 inst_dict = vars(self).copy()
395 395 self.__map, self.__end = tmp
396 396 if inst_dict:
397 397 return (self.__class__, (items,), inst_dict)
398 398 return self.__class__, (items,)
399 399
400 400 def keys(self):
401 401 return list(self)
402 402
403 403 setdefault = DictMixin.setdefault
404 404 update = DictMixin.update
405 405 pop = DictMixin.pop
406 406 values = DictMixin.values
407 407 items = DictMixin.items
408 408 iterkeys = DictMixin.iterkeys
409 409 itervalues = DictMixin.itervalues
410 410 iteritems = DictMixin.iteritems
411 411
412 412 def __repr__(self):
413 413 if not self:
414 414 return '%s()' % (self.__class__.__name__,)
415 415 return '%s(%r)' % (self.__class__.__name__, self.items())
416 416
417 417 def copy(self):
418 418 return self.__class__(self)
419 419
420 420 @classmethod
421 421 def fromkeys(cls, iterable, value=None):
422 422 d = cls()
423 423 for key in iterable:
424 424 d[key] = value
425 425 return d
426 426
427 427 def __eq__(self, other):
428 428 if isinstance(other, OrderedDict):
429 429 return len(self) == len(other) and self.items() == other.items()
430 430 return dict.__eq__(self, other)
431 431
432 432 def __ne__(self, other):
433 433 return not self == other
434 434
435 435
436 436 #===============================================================================
437 437 # TEST FUNCTIONS
438 438 #===============================================================================
439 439 def create_test_index(repo_location, full_index):
440 440 """Makes default test index
441 441 :param repo_location:
442 442 :param full_index:
443 443 """
444 444 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
445 445 from rhodecode.lib.pidlock import DaemonLock, LockHeld
446 446 from rhodecode.lib.indexers import IDX_LOCATION
447 447 import shutil
448 448
449 449 if os.path.exists(IDX_LOCATION):
450 450 shutil.rmtree(IDX_LOCATION)
451 451
452 452 try:
453 453 l = DaemonLock()
454 454 WhooshIndexingDaemon(repo_location=repo_location)\
455 455 .run(full_index=full_index)
456 456 l.release()
457 457 except LockHeld:
458 458 pass
459 459
460 460 def create_test_env(repos_test_path, config):
461 461 """Makes a fresh database and
462 462 install test repository into tmp dir
463 463 """
464 464 from rhodecode.lib.db_manage import DbManage
465 465 import tarfile
466 466 import shutil
467 467 from os.path import dirname as dn, join as jn, abspath
468 from rhodecode.tests import REPO_PATH, NEW_REPO_PATH
468 from rhodecode.tests import REPO_PATH, NEW_REPO_PATH, FORK_REPO_PATH
469 469
470 470 log = logging.getLogger('TestEnvCreator')
471 471 # create logger
472 472 log.setLevel(logging.DEBUG)
473 473 log.propagate = True
474 474 # create console handler and set level to debug
475 475 ch = logging.StreamHandler()
476 476 ch.setLevel(logging.DEBUG)
477 477
478 478 # create formatter
479 479 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
480 480
481 481 # add formatter to ch
482 482 ch.setFormatter(formatter)
483 483
484 484 # add ch to logger
485 485 log.addHandler(ch)
486 486
487 487 #PART ONE create db
488 488 dbname = config['sqlalchemy.db1.url'].split('/')[-1]
489 489 log.debug('making test db %s', dbname)
490 490
491 491 dbmanage = DbManage(log_sql=True, dbname=dbname, root=config['here'],
492 492 tests=True)
493 493 dbmanage.create_tables(override=True)
494 494 dbmanage.config_prompt(repos_test_path)
495 495 dbmanage.create_default_user()
496 496 dbmanage.admin_prompt()
497 497 dbmanage.create_permissions()
498 498 dbmanage.populate_default_permissions()
499 499
500 500 #PART TWO make test repo
501 501 log.debug('making test vcs repo')
502 502 if os.path.isdir(REPO_PATH):
503 503 log.debug('REMOVING %s', REPO_PATH)
504 504 shutil.rmtree(REPO_PATH)
505 505 if os.path.isdir(NEW_REPO_PATH):
506 506 log.debug('REMOVING %s', NEW_REPO_PATH)
507 507 shutil.rmtree(NEW_REPO_PATH)
508 if os.path.isdir(FORK_REPO_PATH):
509 log.debug('REMOVING %s', FORK_REPO_PATH)
510 shutil.rmtree(FORK_REPO_PATH)
508 511
509 512 cur_dir = dn(dn(abspath(__file__)))
510 513 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test.tar.gz"))
511 514 tar.extractall('/tmp')
512 515 tar.close()
@@ -1,60 +1,61 b''
1 1 """Pylons application test package
2 2
3 3 This package assumes the Pylons environment is already loaded, such as
4 4 when this script is imported from the `nosetests --with-pylons=test.ini`
5 5 command.
6 6
7 7 This module initializes the application via ``websetup`` (`paster
8 8 setup-app`) and provides the base testing objects.
9 9 """
10 10 from unittest import TestCase
11 11
12 12 from paste.deploy import loadapp
13 13 from paste.script.appinstall import SetupCommand
14 14 from pylons import config, url
15 15 from routes.util import URLGenerator
16 16 from webtest import TestApp
17 17 import os
18 18 from rhodecode.model import meta
19 19 import logging
20 20
21 21 log = logging.getLogger(__name__)
22 22
23 23 import pylons.test
24 24
25 25 __all__ = ['environ', 'url', 'TestController']
26 26
27 27 # Invoke websetup with the current config file
28 28 #SetupCommand('setup-app').run([config_file])
29 29
30 30 ##RUNNING DESIRED TESTS
31 31 #nosetests rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
32 32
33 33 environ = {}
34 34 TEST_DIR = '/tmp'
35 35 REPO_PATH = os.path.join(TEST_DIR, 'vcs_test')
36 36 NEW_REPO_PATH = os.path.join(TEST_DIR, 'vcs_test_new')
37 FORK_REPO_PATH = os.path.join(TEST_DIR, 'vcs_test_fork')
37 38
38 39 class TestController(TestCase):
39 40
40 41 def __init__(self, *args, **kwargs):
41 42 wsgiapp = pylons.test.pylonsapp
42 43 config = wsgiapp.config
43 44 self.app = TestApp(wsgiapp)
44 45 url._push_object(URLGenerator(config['routes.map'], environ))
45 46 self.sa = meta.Session
46 47
47 48 TestCase.__init__(self, *args, **kwargs)
48 49
49 50 def log_user(self, username='test_admin', password='test12'):
50 51 response = self.app.post(url(controller='login', action='index'),
51 52 {'username':username,
52 53 'password':password})
53 54 print response
54 55
55 56 if 'invalid user name' in response.body:
56 57 assert False, 'could not login using %s %s' % (username, password)
57 58
58 59 assert response.status == '302 Found', 'Wrong response code from login got %s' % response.status
59 60 assert response.session['rhodecode_user'].username == username, 'wrong logged in user got %s expected %s' % (response.session['rhodecode_user'].username, username)
60 61 return response.follow()
@@ -1,88 +1,88 b''
1 1 from rhodecode import get_version
2 2 import sys
3 3 py_version = sys.version_info
4 4
5 5 requirements = [
6 6 "Pylons>=1.0.0",
7 "SQLAlchemy==0.6.4",
7 "SQLAlchemy==0.6.5",
8 8 "Mako>=0.3.2",
9 9 "vcs==0.1.8",
10 10 "pygments>=1.3.0",
11 11 "mercurial==1.6.4",
12 12 "whoosh==1.2.5",
13 "celery==2.1.2",
13 "celery==2.1.3",
14 14 "py-bcrypt",
15 15 "babel",
16 16 ]
17 17
18 18 classifiers = ["Development Status :: 5 - Production/Stable",
19 19 'Environment :: Web Environment',
20 20 'Framework :: Pylons',
21 21 'Intended Audience :: Developers',
22 22 'License :: OSI Approved :: BSD License',
23 23 'Operating System :: OS Independent',
24 24 'Programming Language :: Python', ]
25 25
26 26 if sys.version_info < (2, 6):
27 27 requirements.append("simplejson")
28 28 requirements.append("pysqlite")
29 29
30 30 #additional files from project that goes somewhere in the filesystem
31 31 #relative to sys.prefix
32 32 data_files = []
33 33
34 34 #additional files that goes into package itself
35 35 package_data = {'rhodecode': ['i18n/*/LC_MESSAGES/*.mo', ], }
36 36
37 37 description = 'Mercurial repository serving and browsing app'
38 38 #long description
39 39 try:
40 40 readme_file = 'README.rst'
41 41 long_description = open(readme_file).read()
42 42 except IOError, err:
43 43 sys.stderr.write("[WARNING] Cannot find file specified as "
44 44 "long_description (%s)\n skipping that file" % readme_file)
45 45 long_description = description
46 46
47 47
48 48 try:
49 49 from setuptools import setup, find_packages
50 50 except ImportError:
51 51 from ez_setup import use_setuptools
52 52 use_setuptools()
53 53 from setuptools import setup, find_packages
54 54 #packages
55 55 packages = find_packages(exclude=['ez_setup'])
56 56
57 57 setup(
58 58 name='RhodeCode',
59 59 version=get_version(),
60 60 description=description,
61 61 long_description=long_description,
62 62 keywords='rhodiumcode mercurial web hgwebdir replacement serving hgweb rhodecode',
63 63 license='BSD',
64 64 author='Marcin Kuzminski',
65 65 author_email='marcin@python-works.com',
66 66 url='http://hg.python-works.com',
67 67 install_requires=requirements,
68 68 classifiers=classifiers,
69 69 setup_requires=["PasteScript>=1.6.3"],
70 70 data_files=data_files,
71 71 packages=packages,
72 72 include_package_data=True,
73 73 test_suite='nose.collector',
74 74 package_data=package_data,
75 75 message_extractors={'rhodecode': [
76 76 ('**.py', 'python', None),
77 77 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
78 78 ('public/**', 'ignore', None)]},
79 79 zip_safe=False,
80 80 paster_plugins=['PasteScript', 'Pylons'],
81 81 entry_points="""
82 82 [paste.app_factory]
83 83 main = rhodecode.config.middleware:make_app
84 84
85 85 [paste.app_install]
86 86 main = pylons.util:PylonsInstaller
87 87 """,
88 88 )
General Comments 0
You need to be logged in to leave comments. Login now