##// END OF EJS Templates
bumped version, some spelling fixes
marcink -
r569:000b675e default
parent child Browse files
Show More
@@ -1,35 +1,35 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Hg app, a web based mercurial repository managment based on pylons
3 # RhodeCode, a web based repository management based on pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
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
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on April 9, 2010
21 Created on April 9, 2010
22 Hg app, a web based mercurial repository managment based on pylons
22 RhodeCode, a web based repository management based on pylons
23 versioning implementation: http://semver.org/
23 versioning implementation: http://semver.org/
24 @author: marcink
24 @author: marcink
25 """
25 """
26
26
27 VERSION = (0, 8, 5, 'beta')
27 VERSION = (1, 0, 0, 'rc1')
28
28
29 __version__ = '.'.join((str(each) for each in VERSION[:4]))
29 __version__ = '.'.join((str(each) for each in VERSION[:4]))
30
30
31 def get_version():
31 def get_version():
32 """
32 """
33 Returns shorter version (digit parts only) as string.
33 Returns shorter version (digit parts only) as string.
34 """
34 """
35 return '.'.join((str(each) for each in VERSION[:3]))
35 return '.'.join((str(each) for each in VERSION[:3]))
@@ -1,270 +1,270 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # database managment for hg app
3 # database management for RhodeCode
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
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
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20
20
21 """
21 """
22 Created on April 10, 2010
22 Created on April 10, 2010
23 database managment and creation for hg app
23 database management and creation for RhodeCode
24 @author: marcink
24 @author: marcink
25 """
25 """
26
26
27 from os.path import dirname as dn, join as jn
27 from os.path import dirname as dn, join as jn
28 import os
28 import os
29 import sys
29 import sys
30 import uuid
30 import uuid
31
31
32 from rhodecode.lib.auth import get_crypt_password
32 from rhodecode.lib.auth import get_crypt_password
33 from rhodecode.lib.utils import ask_ok
33 from rhodecode.lib.utils import ask_ok
34 from rhodecode.model import init_model
34 from rhodecode.model import init_model
35 from rhodecode.model.db import User, Permission, RhodeCodeUi, RhodeCodeSettings, \
35 from rhodecode.model.db import User, Permission, RhodeCodeUi, RhodeCodeSettings, \
36 UserToPerm
36 UserToPerm
37 from rhodecode.model import meta
37 from rhodecode.model import meta
38 from sqlalchemy.engine import create_engine
38 from sqlalchemy.engine import create_engine
39 import logging
39 import logging
40
40
41 log = logging.getLogger(__name__)
41 log = logging.getLogger(__name__)
42
42
43 class DbManage(object):
43 class DbManage(object):
44 def __init__(self, log_sql, dbname, root, tests=False):
44 def __init__(self, log_sql, dbname, root, tests=False):
45 self.dbname = dbname
45 self.dbname = dbname
46 self.tests = tests
46 self.tests = tests
47 self.root = root
47 self.root = root
48 dburi = 'sqlite:////%s' % jn(self.root, self.dbname)
48 dburi = 'sqlite:////%s' % jn(self.root, self.dbname)
49 engine = create_engine(dburi, echo=log_sql)
49 engine = create_engine(dburi, echo=log_sql)
50 init_model(engine)
50 init_model(engine)
51 self.sa = meta.Session
51 self.sa = meta.Session
52 self.db_exists = False
52 self.db_exists = False
53
53
54 def check_for_db(self, override):
54 def check_for_db(self, override):
55 db_path = jn(self.root, self.dbname)
55 db_path = jn(self.root, self.dbname)
56 log.info('checking for existing db in %s', db_path)
56 log.info('checking for existing db in %s', db_path)
57 if os.path.isfile(db_path):
57 if os.path.isfile(db_path):
58 self.db_exists = True
58 self.db_exists = True
59 log.info('database exist')
59 log.info('database exist')
60 if not override:
60 if not override:
61 raise Exception('database already exists')
61 raise Exception('database already exists')
62
62
63 def create_tables(self, override=False):
63 def create_tables(self, override=False):
64 """
64 """
65 Create a auth database
65 Create a auth database
66 """
66 """
67 self.check_for_db(override)
67 self.check_for_db(override)
68 if override:
68 if override:
69 log.info("database exist and it's going to be destroyed")
69 log.info("database exist and it's going to be destroyed")
70 if self.tests:
70 if self.tests:
71 destroy = True
71 destroy = True
72 else:
72 else:
73 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
73 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
74 if not destroy:
74 if not destroy:
75 sys.exit()
75 sys.exit()
76 if self.db_exists and destroy:
76 if self.db_exists and destroy:
77 os.remove(jn(self.root, self.dbname))
77 os.remove(jn(self.root, self.dbname))
78 checkfirst = not override
78 checkfirst = not override
79 meta.Base.metadata.create_all(checkfirst=checkfirst)
79 meta.Base.metadata.create_all(checkfirst=checkfirst)
80 log.info('Created tables for %s', self.dbname)
80 log.info('Created tables for %s', self.dbname)
81
81
82 def admin_prompt(self):
82 def admin_prompt(self):
83 if not self.tests:
83 if not self.tests:
84 import getpass
84 import getpass
85 username = raw_input('Specify admin username:')
85 username = raw_input('Specify admin username:')
86 password = getpass.getpass('Specify admin password:')
86 password = getpass.getpass('Specify admin password:')
87 confirm = getpass.getpass('Confirm password:')
87 confirm = getpass.getpass('Confirm password:')
88 if password != confirm:
88 if password != confirm:
89 log.error('passwords mismatch')
89 log.error('passwords mismatch')
90 sys.exit()
90 sys.exit()
91 email = raw_input('Specify admin email:')
91 email = raw_input('Specify admin email:')
92 self.create_user(username, password, email, True)
92 self.create_user(username, password, email, True)
93 else:
93 else:
94 log.info('creating admin and regular test users')
94 log.info('creating admin and regular test users')
95 self.create_user('test_admin', 'test12', 'test_admin@mail.com', True)
95 self.create_user('test_admin', 'test12', 'test_admin@mail.com', True)
96 self.create_user('test_regular', 'test12', 'test_regular@mail.com', False)
96 self.create_user('test_regular', 'test12', 'test_regular@mail.com', False)
97 self.create_user('test_regular2', 'test12', 'test_regular2@mail.com', False)
97 self.create_user('test_regular2', 'test12', 'test_regular2@mail.com', False)
98
98
99
99
100
100
101 def config_prompt(self, test_repo_path=''):
101 def config_prompt(self, test_repo_path=''):
102 log.info('Setting up repositories config')
102 log.info('Setting up repositories config')
103
103
104 if not self.tests and not test_repo_path:
104 if not self.tests and not test_repo_path:
105 path = raw_input('Specify valid full path to your repositories'
105 path = raw_input('Specify valid full path to your repositories'
106 ' you can change this later in application settings:')
106 ' you can change this later in application settings:')
107 else:
107 else:
108 path = test_repo_path
108 path = test_repo_path
109
109
110 if not os.path.isdir(path):
110 if not os.path.isdir(path):
111 log.error('You entered wrong path: %s', path)
111 log.error('You entered wrong path: %s', path)
112 sys.exit()
112 sys.exit()
113
113
114 hooks1 = RhodeCodeUi()
114 hooks1 = RhodeCodeUi()
115 hooks1.ui_section = 'hooks'
115 hooks1.ui_section = 'hooks'
116 hooks1.ui_key = 'changegroup.update'
116 hooks1.ui_key = 'changegroup.update'
117 hooks1.ui_value = 'hg update >&2'
117 hooks1.ui_value = 'hg update >&2'
118 hooks1.ui_active = False
118 hooks1.ui_active = False
119
119
120 hooks2 = RhodeCodeUi()
120 hooks2 = RhodeCodeUi()
121 hooks2.ui_section = 'hooks'
121 hooks2.ui_section = 'hooks'
122 hooks2.ui_key = 'changegroup.repo_size'
122 hooks2.ui_key = 'changegroup.repo_size'
123 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
123 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
124
124
125 web1 = RhodeCodeUi()
125 web1 = RhodeCodeUi()
126 web1.ui_section = 'web'
126 web1.ui_section = 'web'
127 web1.ui_key = 'push_ssl'
127 web1.ui_key = 'push_ssl'
128 web1.ui_value = 'false'
128 web1.ui_value = 'false'
129
129
130 web2 = RhodeCodeUi()
130 web2 = RhodeCodeUi()
131 web2.ui_section = 'web'
131 web2.ui_section = 'web'
132 web2.ui_key = 'allow_archive'
132 web2.ui_key = 'allow_archive'
133 web2.ui_value = 'gz zip bz2'
133 web2.ui_value = 'gz zip bz2'
134
134
135 web3 = RhodeCodeUi()
135 web3 = RhodeCodeUi()
136 web3.ui_section = 'web'
136 web3.ui_section = 'web'
137 web3.ui_key = 'allow_push'
137 web3.ui_key = 'allow_push'
138 web3.ui_value = '*'
138 web3.ui_value = '*'
139
139
140 web4 = RhodeCodeUi()
140 web4 = RhodeCodeUi()
141 web4.ui_section = 'web'
141 web4.ui_section = 'web'
142 web4.ui_key = 'baseurl'
142 web4.ui_key = 'baseurl'
143 web4.ui_value = '/'
143 web4.ui_value = '/'
144
144
145 paths = RhodeCodeUi()
145 paths = RhodeCodeUi()
146 paths.ui_section = 'paths'
146 paths.ui_section = 'paths'
147 paths.ui_key = '/'
147 paths.ui_key = '/'
148 paths.ui_value = os.path.join(path, '*')
148 paths.ui_value = os.path.join(path, '*')
149
149
150
150
151 hgsettings1 = RhodeCodeSettings()
151 hgsettings1 = RhodeCodeSettings()
152
152
153 hgsettings1.app_settings_name = 'realm'
153 hgsettings1.app_settings_name = 'realm'
154 hgsettings1.app_settings_value = 'RhodeCode authentication'
154 hgsettings1.app_settings_value = 'RhodeCode authentication'
155
155
156 hgsettings2 = RhodeCodeSettings()
156 hgsettings2 = RhodeCodeSettings()
157 hgsettings2.app_settings_name = 'title'
157 hgsettings2.app_settings_name = 'title'
158 hgsettings2.app_settings_value = 'RhodeCode'
158 hgsettings2.app_settings_value = 'RhodeCode'
159
159
160 try:
160 try:
161 self.sa.add(hooks1)
161 self.sa.add(hooks1)
162 self.sa.add(hooks2)
162 self.sa.add(hooks2)
163 self.sa.add(web1)
163 self.sa.add(web1)
164 self.sa.add(web2)
164 self.sa.add(web2)
165 self.sa.add(web3)
165 self.sa.add(web3)
166 self.sa.add(web4)
166 self.sa.add(web4)
167 self.sa.add(paths)
167 self.sa.add(paths)
168 self.sa.add(hgsettings1)
168 self.sa.add(hgsettings1)
169 self.sa.add(hgsettings2)
169 self.sa.add(hgsettings2)
170 self.sa.commit()
170 self.sa.commit()
171 except:
171 except:
172 self.sa.rollback()
172 self.sa.rollback()
173 raise
173 raise
174 log.info('created ui config')
174 log.info('created ui config')
175
175
176 def create_user(self, username, password, email='', admin=False):
176 def create_user(self, username, password, email='', admin=False):
177 log.info('creating administrator user %s', username)
177 log.info('creating administrator user %s', username)
178 new_user = User()
178 new_user = User()
179 new_user.username = username
179 new_user.username = username
180 new_user.password = get_crypt_password(password)
180 new_user.password = get_crypt_password(password)
181 new_user.name = 'RhodeCode'
181 new_user.name = 'RhodeCode'
182 new_user.lastname = 'Admin'
182 new_user.lastname = 'Admin'
183 new_user.email = email
183 new_user.email = email
184 new_user.admin = admin
184 new_user.admin = admin
185 new_user.active = True
185 new_user.active = True
186
186
187 try:
187 try:
188 self.sa.add(new_user)
188 self.sa.add(new_user)
189 self.sa.commit()
189 self.sa.commit()
190 except:
190 except:
191 self.sa.rollback()
191 self.sa.rollback()
192 raise
192 raise
193
193
194 def create_default_user(self):
194 def create_default_user(self):
195 log.info('creating default user')
195 log.info('creating default user')
196 #create default user for handling default permissions.
196 #create default user for handling default permissions.
197 def_user = User()
197 def_user = User()
198 def_user.username = 'default'
198 def_user.username = 'default'
199 def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
199 def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
200 def_user.name = 'default'
200 def_user.name = 'default'
201 def_user.lastname = 'default'
201 def_user.lastname = 'default'
202 def_user.email = 'default@default.com'
202 def_user.email = 'default@default.com'
203 def_user.admin = False
203 def_user.admin = False
204 def_user.active = False
204 def_user.active = False
205 try:
205 try:
206 self.sa.add(def_user)
206 self.sa.add(def_user)
207 self.sa.commit()
207 self.sa.commit()
208 except:
208 except:
209 self.sa.rollback()
209 self.sa.rollback()
210 raise
210 raise
211
211
212 def create_permissions(self):
212 def create_permissions(self):
213 #module.(access|create|change|delete)_[name]
213 #module.(access|create|change|delete)_[name]
214 #module.(read|write|owner)
214 #module.(read|write|owner)
215 perms = [('repository.none', 'Repository no access'),
215 perms = [('repository.none', 'Repository no access'),
216 ('repository.read', 'Repository read access'),
216 ('repository.read', 'Repository read access'),
217 ('repository.write', 'Repository write access'),
217 ('repository.write', 'Repository write access'),
218 ('repository.admin', 'Repository admin access'),
218 ('repository.admin', 'Repository admin access'),
219 ('hg.admin', 'Hg Administrator'),
219 ('hg.admin', 'Hg Administrator'),
220 ('hg.create.repository', 'Repository create'),
220 ('hg.create.repository', 'Repository create'),
221 ('hg.create.none', 'Repository creation disabled'),
221 ('hg.create.none', 'Repository creation disabled'),
222 ('hg.register.none', 'Register disabled'),
222 ('hg.register.none', 'Register disabled'),
223 ('hg.register.manual_activate', 'Register new user with rhodecode without manual activation'),
223 ('hg.register.manual_activate', 'Register new user with rhodecode without manual activation'),
224 ('hg.register.auto_activate', 'Register new user with rhodecode without auto activation'),
224 ('hg.register.auto_activate', 'Register new user with rhodecode without auto activation'),
225 ]
225 ]
226
226
227 for p in perms:
227 for p in perms:
228 new_perm = Permission()
228 new_perm = Permission()
229 new_perm.permission_name = p[0]
229 new_perm.permission_name = p[0]
230 new_perm.permission_longname = p[1]
230 new_perm.permission_longname = p[1]
231 try:
231 try:
232 self.sa.add(new_perm)
232 self.sa.add(new_perm)
233 self.sa.commit()
233 self.sa.commit()
234 except:
234 except:
235 self.sa.rollback()
235 self.sa.rollback()
236 raise
236 raise
237
237
238 def populate_default_permissions(self):
238 def populate_default_permissions(self):
239 log.info('creating default user permissions')
239 log.info('creating default user permissions')
240
240
241 default_user = self.sa.query(User)\
241 default_user = self.sa.query(User)\
242 .filter(User.username == 'default').scalar()
242 .filter(User.username == 'default').scalar()
243
243
244 reg_perm = UserToPerm()
244 reg_perm = UserToPerm()
245 reg_perm.user = default_user
245 reg_perm.user = default_user
246 reg_perm.permission = self.sa.query(Permission)\
246 reg_perm.permission = self.sa.query(Permission)\
247 .filter(Permission.permission_name == 'hg.register.manual_activate')\
247 .filter(Permission.permission_name == 'hg.register.manual_activate')\
248 .scalar()
248 .scalar()
249
249
250 create_repo_perm = UserToPerm()
250 create_repo_perm = UserToPerm()
251 create_repo_perm.user = default_user
251 create_repo_perm.user = default_user
252 create_repo_perm.permission = self.sa.query(Permission)\
252 create_repo_perm.permission = self.sa.query(Permission)\
253 .filter(Permission.permission_name == 'hg.create.repository')\
253 .filter(Permission.permission_name == 'hg.create.repository')\
254 .scalar()
254 .scalar()
255
255
256 default_repo_perm = UserToPerm()
256 default_repo_perm = UserToPerm()
257 default_repo_perm.user = default_user
257 default_repo_perm.user = default_user
258 default_repo_perm.permission = self.sa.query(Permission)\
258 default_repo_perm.permission = self.sa.query(Permission)\
259 .filter(Permission.permission_name == 'repository.read')\
259 .filter(Permission.permission_name == 'repository.read')\
260 .scalar()
260 .scalar()
261
261
262 try:
262 try:
263 self.sa.add(reg_perm)
263 self.sa.add(reg_perm)
264 self.sa.add(create_repo_perm)
264 self.sa.add(create_repo_perm)
265 self.sa.add(default_repo_perm)
265 self.sa.add(default_repo_perm)
266 self.sa.commit()
266 self.sa.commit()
267 except:
267 except:
268 self.sa.rollback()
268 self.sa.rollback()
269 raise
269 raise
270
270
@@ -1,490 +1,490 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Utilities for hg app
3 # Utilities for RhodeCode
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; version 2
7 # as published by the Free Software Foundation; version 2
8 # of the License or (at your opinion) any later version of the license.
8 # of the License or (at your opinion) any later version of the license.
9 #
9 #
10 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
13 # GNU General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # MA 02110-1301, USA.
18 # MA 02110-1301, USA.
19
19
20 """
20 """
21 Created on April 18, 2010
21 Created on April 18, 2010
22 Utilities for hg app
22 Utilities for RhodeCode
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from beaker.cache import cache_region
25 from beaker.cache import cache_region
26 from mercurial import ui, config, hg
26 from mercurial import ui, config, hg
27 from mercurial.error import RepoError
27 from mercurial.error import RepoError
28 from rhodecode.model import meta
28 from rhodecode.model import meta
29 from rhodecode.model.db import Repository, User, RhodeCodeUi, RhodeCodeSettings, UserLog
29 from rhodecode.model.db import Repository, User, RhodeCodeUi, RhodeCodeSettings, UserLog
30 from vcs.backends.base import BaseChangeset
30 from vcs.backends.base import BaseChangeset
31 from vcs.utils.lazy import LazyProperty
31 from vcs.utils.lazy import LazyProperty
32 import logging
32 import logging
33 import datetime
33 import datetime
34 import os
34 import os
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 def get_repo_slug(request):
39 def get_repo_slug(request):
40 return request.environ['pylons.routes_dict'].get('repo_name')
40 return request.environ['pylons.routes_dict'].get('repo_name')
41
41
42 def is_mercurial(environ):
42 def is_mercurial(environ):
43 """
43 """
44 Returns True if request's target is mercurial server - header
44 Returns True if request's target is mercurial server - header
45 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
45 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
46 """
46 """
47 http_accept = environ.get('HTTP_ACCEPT')
47 http_accept = environ.get('HTTP_ACCEPT')
48 if http_accept and http_accept.startswith('application/mercurial'):
48 if http_accept and http_accept.startswith('application/mercurial'):
49 return True
49 return True
50 return False
50 return False
51
51
52 def action_logger(user, action, repo, ipaddr, sa=None):
52 def action_logger(user, action, repo, ipaddr, sa=None):
53 """
53 """
54 Action logger for various action made by users
54 Action logger for various action made by users
55 """
55 """
56
56
57 if not sa:
57 if not sa:
58 sa = meta.Session
58 sa = meta.Session
59
59
60 try:
60 try:
61 if hasattr(user, 'user_id'):
61 if hasattr(user, 'user_id'):
62 user_id = user.user_id
62 user_id = user.user_id
63 elif isinstance(user, basestring):
63 elif isinstance(user, basestring):
64 user_id = sa.query(User).filter(User.username == user).one()
64 user_id = sa.query(User).filter(User.username == user).one()
65 else:
65 else:
66 raise Exception('You have to provide user object or username')
66 raise Exception('You have to provide user object or username')
67
67
68 repo_name = repo.lstrip('/')
68 repo_name = repo.lstrip('/')
69 user_log = UserLog()
69 user_log = UserLog()
70 user_log.user_id = user_id
70 user_log.user_id = user_id
71 user_log.action = action
71 user_log.action = action
72 user_log.repository_name = repo_name
72 user_log.repository_name = repo_name
73 user_log.repository = sa.query(Repository)\
73 user_log.repository = sa.query(Repository)\
74 .filter(Repository.repo_name == repo_name).one()
74 .filter(Repository.repo_name == repo_name).one()
75 user_log.action_date = datetime.datetime.now()
75 user_log.action_date = datetime.datetime.now()
76 user_log.user_ip = ipaddr
76 user_log.user_ip = ipaddr
77 sa.add(user_log)
77 sa.add(user_log)
78 sa.commit()
78 sa.commit()
79 log.info('Adding user %s, action %s on %s',
79 log.info('Adding user %s, action %s on %s',
80 user.username, action, repo)
80 user.username, action, repo)
81 except Exception, e:
81 except Exception, e:
82 raise
82 raise
83 sa.rollback()
83 sa.rollback()
84 log.error('could not log user action:%s', str(e))
84 log.error('could not log user action:%s', str(e))
85
85
86 def check_repo_dir(paths):
86 def check_repo_dir(paths):
87 repos_path = paths[0][1].split('/')
87 repos_path = paths[0][1].split('/')
88 if repos_path[-1] in ['*', '**']:
88 if repos_path[-1] in ['*', '**']:
89 repos_path = repos_path[:-1]
89 repos_path = repos_path[:-1]
90 if repos_path[0] != '/':
90 if repos_path[0] != '/':
91 repos_path[0] = '/'
91 repos_path[0] = '/'
92 if not os.path.isdir(os.path.join(*repos_path)):
92 if not os.path.isdir(os.path.join(*repos_path)):
93 raise Exception('Not a valid repository in %s' % paths[0][1])
93 raise Exception('Not a valid repository in %s' % paths[0][1])
94
94
95 def check_repo_fast(repo_name, base_path):
95 def check_repo_fast(repo_name, base_path):
96 if os.path.isdir(os.path.join(base_path, repo_name)):return False
96 if os.path.isdir(os.path.join(base_path, repo_name)):return False
97 return True
97 return True
98
98
99 def check_repo(repo_name, base_path, verify=True):
99 def check_repo(repo_name, base_path, verify=True):
100
100
101 repo_path = os.path.join(base_path, repo_name)
101 repo_path = os.path.join(base_path, repo_name)
102
102
103 try:
103 try:
104 if not check_repo_fast(repo_name, base_path):
104 if not check_repo_fast(repo_name, base_path):
105 return False
105 return False
106 r = hg.repository(ui.ui(), repo_path)
106 r = hg.repository(ui.ui(), repo_path)
107 if verify:
107 if verify:
108 hg.verify(r)
108 hg.verify(r)
109 #here we hnow that repo exists it was verified
109 #here we hnow that repo exists it was verified
110 log.info('%s repo is already created', repo_name)
110 log.info('%s repo is already created', repo_name)
111 return False
111 return False
112 except RepoError:
112 except RepoError:
113 #it means that there is no valid repo there...
113 #it means that there is no valid repo there...
114 log.info('%s repo is free for creation', repo_name)
114 log.info('%s repo is free for creation', repo_name)
115 return True
115 return True
116
116
117 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
117 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
118 while True:
118 while True:
119 ok = raw_input(prompt)
119 ok = raw_input(prompt)
120 if ok in ('y', 'ye', 'yes'): return True
120 if ok in ('y', 'ye', 'yes'): return True
121 if ok in ('n', 'no', 'nop', 'nope'): return False
121 if ok in ('n', 'no', 'nop', 'nope'): return False
122 retries = retries - 1
122 retries = retries - 1
123 if retries < 0: raise IOError
123 if retries < 0: raise IOError
124 print complaint
124 print complaint
125
125
126 @cache_region('super_short_term', 'cached_hg_ui')
126 @cache_region('super_short_term', 'cached_hg_ui')
127 def get_hg_ui_cached():
127 def get_hg_ui_cached():
128 try:
128 try:
129 sa = meta.Session
129 sa = meta.Session
130 ret = sa.query(RhodeCodeUi).all()
130 ret = sa.query(RhodeCodeUi).all()
131 finally:
131 finally:
132 meta.Session.remove()
132 meta.Session.remove()
133 return ret
133 return ret
134
134
135
135
136 def get_hg_settings():
136 def get_hg_settings():
137 try:
137 try:
138 sa = meta.Session
138 sa = meta.Session
139 ret = sa.query(RhodeCodeSettings).all()
139 ret = sa.query(RhodeCodeSettings).all()
140 finally:
140 finally:
141 meta.Session.remove()
141 meta.Session.remove()
142
142
143 if not ret:
143 if not ret:
144 raise Exception('Could not get application settings !')
144 raise Exception('Could not get application settings !')
145 settings = {}
145 settings = {}
146 for each in ret:
146 for each in ret:
147 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
147 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
148
148
149 return settings
149 return settings
150
150
151 def get_hg_ui_settings():
151 def get_hg_ui_settings():
152 try:
152 try:
153 sa = meta.Session
153 sa = meta.Session
154 ret = sa.query(RhodeCodeUi).all()
154 ret = sa.query(RhodeCodeUi).all()
155 finally:
155 finally:
156 meta.Session.remove()
156 meta.Session.remove()
157
157
158 if not ret:
158 if not ret:
159 raise Exception('Could not get application ui settings !')
159 raise Exception('Could not get application ui settings !')
160 settings = {}
160 settings = {}
161 for each in ret:
161 for each in ret:
162 k = each.ui_key
162 k = each.ui_key
163 v = each.ui_value
163 v = each.ui_value
164 if k == '/':
164 if k == '/':
165 k = 'root_path'
165 k = 'root_path'
166
166
167 if k.find('.') != -1:
167 if k.find('.') != -1:
168 k = k.replace('.', '_')
168 k = k.replace('.', '_')
169
169
170 if each.ui_section == 'hooks':
170 if each.ui_section == 'hooks':
171 v = each.ui_active
171 v = each.ui_active
172
172
173 settings[each.ui_section + '_' + k] = v
173 settings[each.ui_section + '_' + k] = v
174
174
175 return settings
175 return settings
176
176
177 #propagated from mercurial documentation
177 #propagated from mercurial documentation
178 ui_sections = ['alias', 'auth',
178 ui_sections = ['alias', 'auth',
179 'decode/encode', 'defaults',
179 'decode/encode', 'defaults',
180 'diff', 'email',
180 'diff', 'email',
181 'extensions', 'format',
181 'extensions', 'format',
182 'merge-patterns', 'merge-tools',
182 'merge-patterns', 'merge-tools',
183 'hooks', 'http_proxy',
183 'hooks', 'http_proxy',
184 'smtp', 'patch',
184 'smtp', 'patch',
185 'paths', 'profiling',
185 'paths', 'profiling',
186 'server', 'trusted',
186 'server', 'trusted',
187 'ui', 'web', ]
187 'ui', 'web', ]
188
188
189 def make_ui(read_from='file', path=None, checkpaths=True):
189 def make_ui(read_from='file', path=None, checkpaths=True):
190 """
190 """
191 A function that will read python rc files or database
191 A function that will read python rc files or database
192 and make an mercurial ui object from read options
192 and make an mercurial ui object from read options
193
193
194 @param path: path to mercurial config file
194 @param path: path to mercurial config file
195 @param checkpaths: check the path
195 @param checkpaths: check the path
196 @param read_from: read from 'file' or 'db'
196 @param read_from: read from 'file' or 'db'
197 """
197 """
198
198
199 baseui = ui.ui()
199 baseui = ui.ui()
200
200
201 if read_from == 'file':
201 if read_from == 'file':
202 if not os.path.isfile(path):
202 if not os.path.isfile(path):
203 log.warning('Unable to read config file %s' % path)
203 log.warning('Unable to read config file %s' % path)
204 return False
204 return False
205 log.debug('reading hgrc from %s', path)
205 log.debug('reading hgrc from %s', path)
206 cfg = config.config()
206 cfg = config.config()
207 cfg.read(path)
207 cfg.read(path)
208 for section in ui_sections:
208 for section in ui_sections:
209 for k, v in cfg.items(section):
209 for k, v in cfg.items(section):
210 baseui.setconfig(section, k, v)
210 baseui.setconfig(section, k, v)
211 log.debug('settings ui from file[%s]%s:%s', section, k, v)
211 log.debug('settings ui from file[%s]%s:%s', section, k, v)
212 if checkpaths:check_repo_dir(cfg.items('paths'))
212 if checkpaths:check_repo_dir(cfg.items('paths'))
213
213
214
214
215 elif read_from == 'db':
215 elif read_from == 'db':
216 hg_ui = get_hg_ui_cached()
216 hg_ui = get_hg_ui_cached()
217 for ui_ in hg_ui:
217 for ui_ in hg_ui:
218 if ui_.ui_active:
218 if ui_.ui_active:
219 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section, ui_.ui_key, ui_.ui_value)
219 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section, ui_.ui_key, ui_.ui_value)
220 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
220 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
221
221
222
222
223 return baseui
223 return baseui
224
224
225
225
226 def set_rhodecode_config(config):
226 def set_rhodecode_config(config):
227 hgsettings = get_hg_settings()
227 hgsettings = get_hg_settings()
228
228
229 for k, v in hgsettings.items():
229 for k, v in hgsettings.items():
230 config[k] = v
230 config[k] = v
231
231
232 def invalidate_cache(name, *args):
232 def invalidate_cache(name, *args):
233 """Invalidates given name cache"""
233 """Invalidates given name cache"""
234
234
235 from beaker.cache import region_invalidate
235 from beaker.cache import region_invalidate
236 log.info('INVALIDATING CACHE FOR %s', name)
236 log.info('INVALIDATING CACHE FOR %s', name)
237
237
238 """propagate our arguments to make sure invalidation works. First
238 """propagate our arguments to make sure invalidation works. First
239 argument has to be the name of cached func name give to cache decorator
239 argument has to be the name of cached func name give to cache decorator
240 without that the invalidation would not work"""
240 without that the invalidation would not work"""
241 tmp = [name]
241 tmp = [name]
242 tmp.extend(args)
242 tmp.extend(args)
243 args = tuple(tmp)
243 args = tuple(tmp)
244
244
245 if name == 'cached_repo_list':
245 if name == 'cached_repo_list':
246 from rhodecode.model.hg_model import _get_repos_cached
246 from rhodecode.model.hg_model import _get_repos_cached
247 region_invalidate(_get_repos_cached, None, *args)
247 region_invalidate(_get_repos_cached, None, *args)
248
248
249 if name == 'full_changelog':
249 if name == 'full_changelog':
250 from rhodecode.model.hg_model import _full_changelog_cached
250 from rhodecode.model.hg_model import _full_changelog_cached
251 region_invalidate(_full_changelog_cached, None, *args)
251 region_invalidate(_full_changelog_cached, None, *args)
252
252
253 class EmptyChangeset(BaseChangeset):
253 class EmptyChangeset(BaseChangeset):
254 """
254 """
255 An dummy empty changeset.
255 An dummy empty changeset.
256 """
256 """
257
257
258 revision = -1
258 revision = -1
259 message = ''
259 message = ''
260 author = ''
260 author = ''
261 date = ''
261 date = ''
262 @LazyProperty
262 @LazyProperty
263 def raw_id(self):
263 def raw_id(self):
264 """
264 """
265 Returns raw string identifing this changeset, useful for web
265 Returns raw string identifing this changeset, useful for web
266 representation.
266 representation.
267 """
267 """
268 return '0' * 40
268 return '0' * 40
269
269
270 @LazyProperty
270 @LazyProperty
271 def short_id(self):
271 def short_id(self):
272 return self.raw_id[:12]
272 return self.raw_id[:12]
273
273
274 def get_file_changeset(self, path):
274 def get_file_changeset(self, path):
275 return self
275 return self
276
276
277 def get_file_content(self, path):
277 def get_file_content(self, path):
278 return u''
278 return u''
279
279
280 def get_file_size(self, path):
280 def get_file_size(self, path):
281 return 0
281 return 0
282
282
283 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
283 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
284 """
284 """
285 maps all found repositories into db
285 maps all found repositories into db
286 """
286 """
287 from rhodecode.model.repo_model import RepoModel
287 from rhodecode.model.repo_model import RepoModel
288
288
289 sa = meta.Session
289 sa = meta.Session
290 user = sa.query(User).filter(User.admin == True).first()
290 user = sa.query(User).filter(User.admin == True).first()
291
291
292 rm = RepoModel()
292 rm = RepoModel()
293
293
294 for name, repo in initial_repo_list.items():
294 for name, repo in initial_repo_list.items():
295 if not sa.query(Repository).filter(Repository.repo_name == name).scalar():
295 if not sa.query(Repository).filter(Repository.repo_name == name).scalar():
296 log.info('repository %s not found creating default', name)
296 log.info('repository %s not found creating default', name)
297
297
298 form_data = {
298 form_data = {
299 'repo_name':name,
299 'repo_name':name,
300 'description':repo.description if repo.description != 'unknown' else \
300 'description':repo.description if repo.description != 'unknown' else \
301 'auto description for %s' % name,
301 'auto description for %s' % name,
302 'private':False
302 'private':False
303 }
303 }
304 rm.create(form_data, user, just_db=True)
304 rm.create(form_data, user, just_db=True)
305
305
306
306
307 if remove_obsolete:
307 if remove_obsolete:
308 #remove from database those repositories that are not in the filesystem
308 #remove from database those repositories that are not in the filesystem
309 for repo in sa.query(Repository).all():
309 for repo in sa.query(Repository).all():
310 if repo.repo_name not in initial_repo_list.keys():
310 if repo.repo_name not in initial_repo_list.keys():
311 sa.delete(repo)
311 sa.delete(repo)
312 sa.commit()
312 sa.commit()
313
313
314
314
315 meta.Session.remove()
315 meta.Session.remove()
316
316
317 from UserDict import DictMixin
317 from UserDict import DictMixin
318
318
319 class OrderedDict(dict, DictMixin):
319 class OrderedDict(dict, DictMixin):
320
320
321 def __init__(self, *args, **kwds):
321 def __init__(self, *args, **kwds):
322 if len(args) > 1:
322 if len(args) > 1:
323 raise TypeError('expected at most 1 arguments, got %d' % len(args))
323 raise TypeError('expected at most 1 arguments, got %d' % len(args))
324 try:
324 try:
325 self.__end
325 self.__end
326 except AttributeError:
326 except AttributeError:
327 self.clear()
327 self.clear()
328 self.update(*args, **kwds)
328 self.update(*args, **kwds)
329
329
330 def clear(self):
330 def clear(self):
331 self.__end = end = []
331 self.__end = end = []
332 end += [None, end, end] # sentinel node for doubly linked list
332 end += [None, end, end] # sentinel node for doubly linked list
333 self.__map = {} # key --> [key, prev, next]
333 self.__map = {} # key --> [key, prev, next]
334 dict.clear(self)
334 dict.clear(self)
335
335
336 def __setitem__(self, key, value):
336 def __setitem__(self, key, value):
337 if key not in self:
337 if key not in self:
338 end = self.__end
338 end = self.__end
339 curr = end[1]
339 curr = end[1]
340 curr[2] = end[1] = self.__map[key] = [key, curr, end]
340 curr[2] = end[1] = self.__map[key] = [key, curr, end]
341 dict.__setitem__(self, key, value)
341 dict.__setitem__(self, key, value)
342
342
343 def __delitem__(self, key):
343 def __delitem__(self, key):
344 dict.__delitem__(self, key)
344 dict.__delitem__(self, key)
345 key, prev, next = self.__map.pop(key)
345 key, prev, next = self.__map.pop(key)
346 prev[2] = next
346 prev[2] = next
347 next[1] = prev
347 next[1] = prev
348
348
349 def __iter__(self):
349 def __iter__(self):
350 end = self.__end
350 end = self.__end
351 curr = end[2]
351 curr = end[2]
352 while curr is not end:
352 while curr is not end:
353 yield curr[0]
353 yield curr[0]
354 curr = curr[2]
354 curr = curr[2]
355
355
356 def __reversed__(self):
356 def __reversed__(self):
357 end = self.__end
357 end = self.__end
358 curr = end[1]
358 curr = end[1]
359 while curr is not end:
359 while curr is not end:
360 yield curr[0]
360 yield curr[0]
361 curr = curr[1]
361 curr = curr[1]
362
362
363 def popitem(self, last=True):
363 def popitem(self, last=True):
364 if not self:
364 if not self:
365 raise KeyError('dictionary is empty')
365 raise KeyError('dictionary is empty')
366 if last:
366 if last:
367 key = reversed(self).next()
367 key = reversed(self).next()
368 else:
368 else:
369 key = iter(self).next()
369 key = iter(self).next()
370 value = self.pop(key)
370 value = self.pop(key)
371 return key, value
371 return key, value
372
372
373 def __reduce__(self):
373 def __reduce__(self):
374 items = [[k, self[k]] for k in self]
374 items = [[k, self[k]] for k in self]
375 tmp = self.__map, self.__end
375 tmp = self.__map, self.__end
376 del self.__map, self.__end
376 del self.__map, self.__end
377 inst_dict = vars(self).copy()
377 inst_dict = vars(self).copy()
378 self.__map, self.__end = tmp
378 self.__map, self.__end = tmp
379 if inst_dict:
379 if inst_dict:
380 return (self.__class__, (items,), inst_dict)
380 return (self.__class__, (items,), inst_dict)
381 return self.__class__, (items,)
381 return self.__class__, (items,)
382
382
383 def keys(self):
383 def keys(self):
384 return list(self)
384 return list(self)
385
385
386 setdefault = DictMixin.setdefault
386 setdefault = DictMixin.setdefault
387 update = DictMixin.update
387 update = DictMixin.update
388 pop = DictMixin.pop
388 pop = DictMixin.pop
389 values = DictMixin.values
389 values = DictMixin.values
390 items = DictMixin.items
390 items = DictMixin.items
391 iterkeys = DictMixin.iterkeys
391 iterkeys = DictMixin.iterkeys
392 itervalues = DictMixin.itervalues
392 itervalues = DictMixin.itervalues
393 iteritems = DictMixin.iteritems
393 iteritems = DictMixin.iteritems
394
394
395 def __repr__(self):
395 def __repr__(self):
396 if not self:
396 if not self:
397 return '%s()' % (self.__class__.__name__,)
397 return '%s()' % (self.__class__.__name__,)
398 return '%s(%r)' % (self.__class__.__name__, self.items())
398 return '%s(%r)' % (self.__class__.__name__, self.items())
399
399
400 def copy(self):
400 def copy(self):
401 return self.__class__(self)
401 return self.__class__(self)
402
402
403 @classmethod
403 @classmethod
404 def fromkeys(cls, iterable, value=None):
404 def fromkeys(cls, iterable, value=None):
405 d = cls()
405 d = cls()
406 for key in iterable:
406 for key in iterable:
407 d[key] = value
407 d[key] = value
408 return d
408 return d
409
409
410 def __eq__(self, other):
410 def __eq__(self, other):
411 if isinstance(other, OrderedDict):
411 if isinstance(other, OrderedDict):
412 return len(self) == len(other) and self.items() == other.items()
412 return len(self) == len(other) and self.items() == other.items()
413 return dict.__eq__(self, other)
413 return dict.__eq__(self, other)
414
414
415 def __ne__(self, other):
415 def __ne__(self, other):
416 return not self == other
416 return not self == other
417
417
418
418
419 #===============================================================================
419 #===============================================================================
420 # TEST FUNCTIONS
420 # TEST FUNCTIONS
421 #===============================================================================
421 #===============================================================================
422 def create_test_index(repo_location, full_index):
422 def create_test_index(repo_location, full_index):
423 """Makes default test index
423 """Makes default test index
424 @param repo_location:
424 @param repo_location:
425 @param full_index:
425 @param full_index:
426 """
426 """
427 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
427 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
428 from rhodecode.lib.pidlock import DaemonLock, LockHeld
428 from rhodecode.lib.pidlock import DaemonLock, LockHeld
429 from rhodecode.lib.indexers import IDX_LOCATION
429 from rhodecode.lib.indexers import IDX_LOCATION
430 import shutil
430 import shutil
431
431
432 if os.path.exists(IDX_LOCATION):
432 if os.path.exists(IDX_LOCATION):
433 shutil.rmtree(IDX_LOCATION)
433 shutil.rmtree(IDX_LOCATION)
434
434
435 try:
435 try:
436 l = DaemonLock()
436 l = DaemonLock()
437 WhooshIndexingDaemon(repo_location=repo_location)\
437 WhooshIndexingDaemon(repo_location=repo_location)\
438 .run(full_index=full_index)
438 .run(full_index=full_index)
439 l.release()
439 l.release()
440 except LockHeld:
440 except LockHeld:
441 pass
441 pass
442
442
443 def create_test_env(repos_test_path, config):
443 def create_test_env(repos_test_path, config):
444 """Makes a fresh database and
444 """Makes a fresh database and
445 install test repository into tmp dir
445 install test repository into tmp dir
446 """
446 """
447 from rhodecode.lib.db_manage import DbManage
447 from rhodecode.lib.db_manage import DbManage
448 import tarfile
448 import tarfile
449 import shutil
449 import shutil
450 from os.path import dirname as dn, join as jn, abspath
450 from os.path import dirname as dn, join as jn, abspath
451
451
452 log = logging.getLogger('TestEnvCreator')
452 log = logging.getLogger('TestEnvCreator')
453 # create logger
453 # create logger
454 log.setLevel(logging.DEBUG)
454 log.setLevel(logging.DEBUG)
455 log.propagate = True
455 log.propagate = True
456 # create console handler and set level to debug
456 # create console handler and set level to debug
457 ch = logging.StreamHandler()
457 ch = logging.StreamHandler()
458 ch.setLevel(logging.DEBUG)
458 ch.setLevel(logging.DEBUG)
459
459
460 # create formatter
460 # create formatter
461 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
461 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
462
462
463 # add formatter to ch
463 # add formatter to ch
464 ch.setFormatter(formatter)
464 ch.setFormatter(formatter)
465
465
466 # add ch to logger
466 # add ch to logger
467 log.addHandler(ch)
467 log.addHandler(ch)
468
468
469 #PART ONE create db
469 #PART ONE create db
470 dbname = config['sqlalchemy.db1.url'].split('/')[-1]
470 dbname = config['sqlalchemy.db1.url'].split('/')[-1]
471 log.debug('making test db %s', dbname)
471 log.debug('making test db %s', dbname)
472
472
473 dbmanage = DbManage(log_sql=True, dbname=dbname, root=config['here'],
473 dbmanage = DbManage(log_sql=True, dbname=dbname, root=config['here'],
474 tests=True)
474 tests=True)
475 dbmanage.create_tables(override=True)
475 dbmanage.create_tables(override=True)
476 dbmanage.config_prompt(repos_test_path)
476 dbmanage.config_prompt(repos_test_path)
477 dbmanage.create_default_user()
477 dbmanage.create_default_user()
478 dbmanage.admin_prompt()
478 dbmanage.admin_prompt()
479 dbmanage.create_permissions()
479 dbmanage.create_permissions()
480 dbmanage.populate_default_permissions()
480 dbmanage.populate_default_permissions()
481
481
482 #PART TWO make test repo
482 #PART TWO make test repo
483 log.debug('making test vcs repo')
483 log.debug('making test vcs repo')
484 if os.path.isdir('/tmp/vcs_test'):
484 if os.path.isdir('/tmp/vcs_test'):
485 shutil.rmtree('/tmp/vcs_test')
485 shutil.rmtree('/tmp/vcs_test')
486
486
487 cur_dir = dn(dn(abspath(__file__)))
487 cur_dir = dn(dn(abspath(__file__)))
488 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test.tar.gz"))
488 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test.tar.gz"))
489 tar.extractall('/tmp')
489 tar.extractall('/tmp')
490 tar.close()
490 tar.close()
@@ -1,186 +1,186 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Model for hg app
3 # Model for RhodeCode
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
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
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on April 9, 2010
21 Created on April 9, 2010
22 Model for hg app
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
26 from mercurial import ui
26 from mercurial import ui
27 from mercurial.hgweb.hgwebdir_mod import findrepos
27 from mercurial.hgweb.hgwebdir_mod import findrepos
28 from pylons.i18n.translation import _
28 from pylons.i18n.translation import _
29 from rhodecode.lib import helpers as h
29 from rhodecode.lib import helpers as h
30 from rhodecode.lib.utils import invalidate_cache
30 from rhodecode.lib.utils import invalidate_cache
31 from rhodecode.lib.auth import HasRepoPermissionAny
31 from rhodecode.lib.auth import HasRepoPermissionAny
32 from rhodecode.model import meta
32 from rhodecode.model import meta
33 from rhodecode.model.db import Repository, User
33 from rhodecode.model.db import Repository, User
34 from sqlalchemy.orm import joinedload
34 from sqlalchemy.orm import joinedload
35 from vcs.exceptions import RepositoryError, VCSError
35 from vcs.exceptions import RepositoryError, VCSError
36 import logging
36 import logging
37 import os
37 import os
38 import sys
38 import sys
39 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
40
40
41 try:
41 try:
42 from vcs.backends.hg import MercurialRepository
42 from vcs.backends.hg import MercurialRepository
43 except ImportError:
43 except ImportError:
44 sys.stderr.write('You have to import vcs module')
44 sys.stderr.write('You have to import vcs module')
45 raise Exception('Unable to import vcs')
45 raise Exception('Unable to import vcs')
46
46
47 def _get_repos_cached_initial(app_globals, initial):
47 def _get_repos_cached_initial(app_globals, initial):
48 """return cached dict with repos
48 """return cached dict with repos
49 """
49 """
50 g = app_globals
50 g = app_globals
51 return HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui, initial)
51 return HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui, initial)
52
52
53 @cache_region('long_term', 'cached_repo_list')
53 @cache_region('long_term', 'cached_repo_list')
54 def _get_repos_cached():
54 def _get_repos_cached():
55 """return cached dict with repos
55 """return cached dict with repos
56 """
56 """
57 log.info('getting all repositories list')
57 log.info('getting all repositories list')
58 from pylons import app_globals as g
58 from pylons import app_globals as g
59 return HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
59 return HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
60
60
61 @cache_region('super_short_term', 'cached_repos_switcher_list')
61 @cache_region('super_short_term', 'cached_repos_switcher_list')
62 def _get_repos_switcher_cached(cached_repo_list):
62 def _get_repos_switcher_cached(cached_repo_list):
63 repos_lst = []
63 repos_lst = []
64 for repo in [x for x in cached_repo_list.values()]:
64 for repo in [x for x in cached_repo_list.values()]:
65 if HasRepoPermissionAny('repository.write', 'repository.read',
65 if HasRepoPermissionAny('repository.write', 'repository.read',
66 'repository.admin')(repo.name, 'main page check'):
66 'repository.admin')(repo.name, 'main page check'):
67 repos_lst.append((repo.name, repo.dbrepo.private,))
67 repos_lst.append((repo.name, repo.dbrepo.private,))
68
68
69 return sorted(repos_lst, key=lambda k:k[0].lower())
69 return sorted(repos_lst, key=lambda k:k[0].lower())
70
70
71 @cache_region('long_term', 'full_changelog')
71 @cache_region('long_term', 'full_changelog')
72 def _full_changelog_cached(repo_name):
72 def _full_changelog_cached(repo_name):
73 log.info('getting full changelog for %s', repo_name)
73 log.info('getting full changelog for %s', repo_name)
74 return list(reversed(list(HgModel().get_repo(repo_name))))
74 return list(reversed(list(HgModel().get_repo(repo_name))))
75
75
76 class HgModel(object):
76 class HgModel(object):
77 """Mercurial Model
77 """Mercurial Model
78 """
78 """
79
79
80 def __init__(self):
80 def __init__(self):
81 pass
81 pass
82
82
83 @staticmethod
83 @staticmethod
84 def repo_scan(repos_prefix, repos_path, baseui, initial=False):
84 def repo_scan(repos_prefix, repos_path, baseui, initial=False):
85 """
85 """
86 Listing of repositories in given path. This path should not be a
86 Listing of repositories in given path. This path should not be a
87 repository itself. Return a dictionary of repository objects
87 repository itself. Return a dictionary of repository objects
88 :param repos_path: path to directory it could take syntax with
88 :param repos_path: path to directory it could take syntax with
89 * or ** for deep recursive displaying repositories
89 * or ** for deep recursive displaying repositories
90 """
90 """
91 sa = meta.Session()
91 sa = meta.Session()
92 def check_repo_dir(path):
92 def check_repo_dir(path):
93 """Checks the repository
93 """Checks the repository
94 :param path:
94 :param path:
95 """
95 """
96 repos_path = path.split('/')
96 repos_path = path.split('/')
97 if repos_path[-1] in ['*', '**']:
97 if repos_path[-1] in ['*', '**']:
98 repos_path = repos_path[:-1]
98 repos_path = repos_path[:-1]
99 if repos_path[0] != '/':
99 if repos_path[0] != '/':
100 repos_path[0] = '/'
100 repos_path[0] = '/'
101 if not os.path.isdir(os.path.join(*repos_path)):
101 if not os.path.isdir(os.path.join(*repos_path)):
102 raise RepositoryError('Not a valid repository in %s' % path)
102 raise RepositoryError('Not a valid repository in %s' % path)
103 if not repos_path.endswith('*'):
103 if not repos_path.endswith('*'):
104 raise VCSError('You need to specify * or ** at the end of path '
104 raise VCSError('You need to specify * or ** at the end of path '
105 'for recursive scanning')
105 'for recursive scanning')
106
106
107 check_repo_dir(repos_path)
107 check_repo_dir(repos_path)
108 log.info('scanning for repositories in %s', repos_path)
108 log.info('scanning for repositories in %s', repos_path)
109 repos = findrepos([(repos_prefix, repos_path)])
109 repos = findrepos([(repos_prefix, repos_path)])
110 if not isinstance(baseui, ui.ui):
110 if not isinstance(baseui, ui.ui):
111 baseui = ui.ui()
111 baseui = ui.ui()
112
112
113 repos_list = {}
113 repos_list = {}
114 for name, path in repos:
114 for name, path in repos:
115 try:
115 try:
116 #name = name.split('/')[-1]
116 #name = name.split('/')[-1]
117 if repos_list.has_key(name):
117 if repos_list.has_key(name):
118 raise RepositoryError('Duplicate repository name %s found in'
118 raise RepositoryError('Duplicate repository name %s found in'
119 ' %s' % (name, path))
119 ' %s' % (name, path))
120 else:
120 else:
121
121
122 repos_list[name] = MercurialRepository(path, baseui=baseui)
122 repos_list[name] = MercurialRepository(path, baseui=baseui)
123 repos_list[name].name = name
123 repos_list[name].name = name
124
124
125 dbrepo = None
125 dbrepo = None
126 if not initial:
126 if not initial:
127 #for initial scann on application first run we don't
127 #for initial scann on application first run we don't
128 #have db repos yet.
128 #have db repos yet.
129 dbrepo = sa.query(Repository)\
129 dbrepo = sa.query(Repository)\
130 .options(joinedload(Repository.fork))\
130 .options(joinedload(Repository.fork))\
131 .filter(Repository.repo_name == name)\
131 .filter(Repository.repo_name == name)\
132 .scalar()
132 .scalar()
133
133
134 if dbrepo:
134 if dbrepo:
135 log.info('Adding db instance to cached list')
135 log.info('Adding db instance to cached list')
136 repos_list[name].dbrepo = dbrepo
136 repos_list[name].dbrepo = dbrepo
137 repos_list[name].description = dbrepo.description
137 repos_list[name].description = dbrepo.description
138 if dbrepo.user:
138 if dbrepo.user:
139 repos_list[name].contact = dbrepo.user.full_contact
139 repos_list[name].contact = dbrepo.user.full_contact
140 else:
140 else:
141 repos_list[name].contact = sa.query(User)\
141 repos_list[name].contact = sa.query(User)\
142 .filter(User.admin == True).first().full_contact
142 .filter(User.admin == True).first().full_contact
143 except OSError:
143 except OSError:
144 continue
144 continue
145 meta.Session.remove()
145 meta.Session.remove()
146 return repos_list
146 return repos_list
147
147
148 def get_repos(self):
148 def get_repos(self):
149 for name, repo in _get_repos_cached().items():
149 for name, repo in _get_repos_cached().items():
150 if repo._get_hidden():
150 if repo._get_hidden():
151 #skip hidden web repository
151 #skip hidden web repository
152 continue
152 continue
153
153
154 last_change = repo.last_change
154 last_change = repo.last_change
155 tip = h.get_changeset_safe(repo, 'tip')
155 tip = h.get_changeset_safe(repo, 'tip')
156
156
157 tmp_d = {}
157 tmp_d = {}
158 tmp_d['name'] = repo.name
158 tmp_d['name'] = repo.name
159 tmp_d['name_sort'] = tmp_d['name'].lower()
159 tmp_d['name_sort'] = tmp_d['name'].lower()
160 tmp_d['description'] = repo.description
160 tmp_d['description'] = repo.description
161 tmp_d['description_sort'] = tmp_d['description']
161 tmp_d['description_sort'] = tmp_d['description']
162 tmp_d['last_change'] = last_change
162 tmp_d['last_change'] = last_change
163 tmp_d['last_change_sort'] = last_change[1] - last_change[0]
163 tmp_d['last_change_sort'] = last_change[1] - last_change[0]
164 tmp_d['tip'] = tip.short_id
164 tmp_d['tip'] = tip.short_id
165 tmp_d['tip_sort'] = tip.revision
165 tmp_d['tip_sort'] = tip.revision
166 tmp_d['rev'] = tip.revision
166 tmp_d['rev'] = tip.revision
167 tmp_d['contact'] = repo.contact
167 tmp_d['contact'] = repo.contact
168 tmp_d['contact_sort'] = tmp_d['contact']
168 tmp_d['contact_sort'] = tmp_d['contact']
169 tmp_d['repo_archives'] = list(repo._get_archives())
169 tmp_d['repo_archives'] = list(repo._get_archives())
170 tmp_d['last_msg'] = tip.message
170 tmp_d['last_msg'] = tip.message
171 tmp_d['repo'] = repo
171 tmp_d['repo'] = repo
172 yield tmp_d
172 yield tmp_d
173
173
174 def get_repo(self, repo_name):
174 def get_repo(self, repo_name):
175 try:
175 try:
176 repo = _get_repos_cached()[repo_name]
176 repo = _get_repos_cached()[repo_name]
177 return repo
177 return repo
178 except KeyError:
178 except KeyError:
179 #i we're here and we got key errors let's try to invalidate the
179 #i we're here and we got key errors let's try to invalidate the
180 #cahce and try again
180 #cahce and try again
181 invalidate_cache('cached_repo_list')
181 invalidate_cache('cached_repo_list')
182 repo = _get_repos_cached()[repo_name]
182 repo = _get_repos_cached()[repo_name]
183 return repo
183 return repo
184
184
185
185
186
186
@@ -1,269 +1,269 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 <head>
4 <head>
5 <title>${next.title()}</title>
5 <title>${next.title()}</title>
6 <link rel="icon" href="/images/hgicon.png" type="image/png" />
6 <link rel="icon" href="/images/hgicon.png" type="image/png" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9 <!-- stylesheets -->
9 <!-- stylesheets -->
10 ${self.css()}
10 ${self.css()}
11 <!-- scripts -->
11 <!-- scripts -->
12 ${self.js()}
12 ${self.js()}
13 </head>
13 </head>
14 <body>
14 <body>
15 <!-- header -->
15 <!-- header -->
16 <div id="header">
16 <div id="header">
17 <!-- user -->
17 <!-- user -->
18 <ul id="logged-user">
18 <ul id="logged-user">
19 <li class="first">
19 <li class="first">
20 <div class="gravatar">
20 <div class="gravatar">
21 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,24)}" />
21 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,24)}" />
22 </div>
22 </div>
23 <div class="account">
23 <div class="account">
24 ${h.link_to('%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname),h.url('admin_settings_my_account'))}<br/>
24 ${h.link_to('%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname),h.url('admin_settings_my_account'))}<br/>
25 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'))}
25 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'))}
26 </div>
26 </div>
27 </li>
27 </li>
28 <li class="last highlight">${h.link_to(u'Logout',h.url('logout_home'))}</li>
28 <li class="last highlight">${h.link_to(u'Logout',h.url('logout_home'))}</li>
29 </ul>
29 </ul>
30 <!-- end user -->
30 <!-- end user -->
31 <div id="header-inner">
31 <div id="header-inner">
32 <div id="home">
32 <div id="home">
33 <a href="${h.url('hg_home')}"></a>
33 <a href="${h.url('hg_home')}"></a>
34 </div>
34 </div>
35 <!-- logo -->
35 <!-- logo -->
36 <div id="logo">
36 <div id="logo">
37 <h1><a href="${h.url('hg_home')}">${c.rhodecode_name}</a></h1>
37 <h1><a href="${h.url('hg_home')}">${c.rhodecode_name}</a></h1>
38 </div>
38 </div>
39 <!-- end logo -->
39 <!-- end logo -->
40 <!-- quick menu -->
40 <!-- quick menu -->
41 ${self.page_nav()}
41 ${self.page_nav()}
42 <!-- end quick -->
42 <!-- end quick -->
43 <div class="corner tl"></div>
43 <div class="corner tl"></div>
44 <div class="corner tr"></div>
44 <div class="corner tr"></div>
45 </div>
45 </div>
46 </div>
46 </div>
47 <!-- end header -->
47 <!-- end header -->
48
48
49 <!-- CONTENT -->
49 <!-- CONTENT -->
50 <div id="content">
50 <div id="content">
51 <div class="flash_msg">
51 <div class="flash_msg">
52 <% messages = h.flash.pop_messages() %>
52 <% messages = h.flash.pop_messages() %>
53 % if messages:
53 % if messages:
54 <ul id="flash-messages">
54 <ul id="flash-messages">
55 % for message in messages:
55 % for message in messages:
56 <li class="${message.category}_msg">${message}</li>
56 <li class="${message.category}_msg">${message}</li>
57 % endfor
57 % endfor
58 </ul>
58 </ul>
59 % endif
59 % endif
60 </div>
60 </div>
61 <div id="main">
61 <div id="main">
62 ${next.main()}
62 ${next.main()}
63 </div>
63 </div>
64 </div>
64 </div>
65 <!-- END CONTENT -->
65 <!-- END CONTENT -->
66
66
67 <!-- footer -->
67 <!-- footer -->
68 <div id="footer">
68 <div id="footer">
69 <p>Hg App ${c.rhodecode_version} &copy; 2010 by Marcin Kuzminski</p>
69 <p>RhodeCode ${c.rhodecode_version} &copy; 2010 by Marcin Kuzminski</p>
70 <script type="text/javascript">${h.tooltip.activate()}</script>
70 <script type="text/javascript">${h.tooltip.activate()}</script>
71 </div>
71 </div>
72 <!-- end footer -->
72 <!-- end footer -->
73 </body>
73 </body>
74
74
75 </html>
75 </html>
76
76
77 ### MAKO DEFS ###
77 ### MAKO DEFS ###
78 <%def name="page_nav()">
78 <%def name="page_nav()">
79 ${self.menu()}
79 ${self.menu()}
80 </%def>
80 </%def>
81
81
82 <%def name="menu(current=None)">
82 <%def name="menu(current=None)">
83 <%
83 <%
84 def is_current(selected):
84 def is_current(selected):
85 if selected == current:
85 if selected == current:
86 return h.literal('class="current"')
86 return h.literal('class="current"')
87 %>
87 %>
88 %if current not in ['home','admin']:
88 %if current not in ['home','admin']:
89 ##REGULAR MENU
89 ##REGULAR MENU
90 <ul id="quick">
90 <ul id="quick">
91 <!-- repo switcher -->
91 <!-- repo switcher -->
92 <li>
92 <li>
93 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
93 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
94 <span class="icon">
94 <span class="icon">
95 <img src="/images/icons/database.png" alt="${_('Products')}" />
95 <img src="/images/icons/database.png" alt="${_('Products')}" />
96 </span>
96 </span>
97 <span>&darr;</span>
97 <span>&darr;</span>
98 </a>
98 </a>
99 <ul class="repo_switcher">
99 <ul class="repo_switcher">
100 %for repo,private in c.repo_switcher_list:
100 %for repo,private in c.repo_switcher_list:
101 %if private:
101 %if private:
102 <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="private_repo")}</li>
102 <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="private_repo")}</li>
103 %else:
103 %else:
104 <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="public_repo")}</li>
104 <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="public_repo")}</li>
105 %endif
105 %endif
106 %endfor
106 %endfor
107 </ul>
107 </ul>
108 </li>
108 </li>
109
109
110 <li ${is_current('summary')}>
110 <li ${is_current('summary')}>
111 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
111 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
112 <span class="icon">
112 <span class="icon">
113 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
113 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
114 </span>
114 </span>
115 <span>${_('Summary')}</span>
115 <span>${_('Summary')}</span>
116 </a>
116 </a>
117 </li>
117 </li>
118 <li ${is_current('shortlog')}>
118 <li ${is_current('shortlog')}>
119 <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
119 <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
120 <span class="icon">
120 <span class="icon">
121 <img src="/images/icons/application_double.png" alt="${_('Shortlog')}" />
121 <img src="/images/icons/application_double.png" alt="${_('Shortlog')}" />
122 </span>
122 </span>
123 <span>${_('Shortlog')}</span>
123 <span>${_('Shortlog')}</span>
124 </a>
124 </a>
125 </li>
125 </li>
126 <li ${is_current('changelog')}>
126 <li ${is_current('changelog')}>
127 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
127 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
128 <span class="icon">
128 <span class="icon">
129 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
129 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
130 </span>
130 </span>
131 <span>${_('Changelog')}</span>
131 <span>${_('Changelog')}</span>
132 </a>
132 </a>
133 </li>
133 </li>
134
134
135 <li ${is_current('switch_to')}>
135 <li ${is_current('switch_to')}>
136 <a title="${_('Switch to')}" href="#">
136 <a title="${_('Switch to')}" href="#">
137 <span class="icon">
137 <span class="icon">
138 <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
138 <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
139 </span>
139 </span>
140 <span>${_('Switch to')}</span>
140 <span>${_('Switch to')}</span>
141 </a>
141 </a>
142 <ul>
142 <ul>
143 <li>
143 <li>
144 ${h.link_to(_('branches'),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
144 ${h.link_to(_('branches'),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
145 <ul>
145 <ul>
146 %if c.repository_branches.values():
146 %if c.repository_branches.values():
147 %for cnt,branch in enumerate(c.repository_branches.items()):
147 %for cnt,branch in enumerate(c.repository_branches.items()):
148 <li>${h.link_to('%s - %s' % (branch[0],branch[1]),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
148 <li>${h.link_to('%s - %s' % (branch[0],branch[1]),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
149 %endfor
149 %endfor
150 %else:
150 %else:
151 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
151 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
152 %endif
152 %endif
153 </ul>
153 </ul>
154 </li>
154 </li>
155 <li>
155 <li>
156 ${h.link_to(_('tags'),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
156 ${h.link_to(_('tags'),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
157 <ul>
157 <ul>
158 %if c.repository_tags.values():
158 %if c.repository_tags.values():
159 %for cnt,tag in enumerate(c.repository_tags.items()):
159 %for cnt,tag in enumerate(c.repository_tags.items()):
160 <li>${h.link_to('%s - %s' % (tag[0],tag[1]),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
160 <li>${h.link_to('%s - %s' % (tag[0],tag[1]),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
161 %endfor
161 %endfor
162 %else:
162 %else:
163 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
163 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
164 %endif
164 %endif
165 </ul>
165 </ul>
166 </li>
166 </li>
167 </ul>
167 </ul>
168 </li>
168 </li>
169 <li ${is_current('files')}>
169 <li ${is_current('files')}>
170 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
170 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
171 <span class="icon">
171 <span class="icon">
172 <img src="/images/icons/file.png" alt="${_('Files')}" />
172 <img src="/images/icons/file.png" alt="${_('Files')}" />
173 </span>
173 </span>
174 <span>${_('Files')}</span>
174 <span>${_('Files')}</span>
175 </a>
175 </a>
176 </li>
176 </li>
177
177
178 <li ${is_current('options')}>
178 <li ${is_current('options')}>
179 <a title="${_('Options')}" href="#">
179 <a title="${_('Options')}" href="#">
180 <span class="icon">
180 <span class="icon">
181 <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
181 <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
182 </span>
182 </span>
183 <span>${_('Options')}</span>
183 <span>${_('Options')}</span>
184 </a>
184 </a>
185 <ul>
185 <ul>
186 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
186 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
187 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
187 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
188 %endif
188 %endif
189 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
189 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
190 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
190 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
191 ## %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
191 ## %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
192 ## <li class="last">
192 ## <li class="last">
193 ## ${h.link_to(_('delete'),'#',class_='delete')}
193 ## ${h.link_to(_('delete'),'#',class_='delete')}
194 ## ${h.form(url('repo_settings_delete', repo_name=c.repo_name),method='delete')}
194 ## ${h.form(url('repo_settings_delete', repo_name=c.repo_name),method='delete')}
195 ## ${h.submit('remove_%s' % c.repo_name,'delete',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
195 ## ${h.submit('remove_%s' % c.repo_name,'delete',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
196 ## ${h.end_form()}
196 ## ${h.end_form()}
197 ## </li>
197 ## </li>
198 ## %endif
198 ## %endif
199 </ul>
199 </ul>
200 </li>
200 </li>
201 </ul>
201 </ul>
202 %else:
202 %else:
203 ##ROOT MENU
203 ##ROOT MENU
204 <ul id="quick">
204 <ul id="quick">
205 <li>
205 <li>
206 <a title="${_('Home')}" href="${h.url('hg_home')}">
206 <a title="${_('Home')}" href="${h.url('hg_home')}">
207 <span class="icon">
207 <span class="icon">
208 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
208 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
209 </span>
209 </span>
210 <span>${_('Home')}</span>
210 <span>${_('Home')}</span>
211 </a>
211 </a>
212 </li>
212 </li>
213
213
214 <li>
214 <li>
215 <a title="${_('Search')}" href="${h.url('search')}">
215 <a title="${_('Search')}" href="${h.url('search')}">
216 <span class="icon">
216 <span class="icon">
217 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
217 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
218 </span>
218 </span>
219 <span>${_('Search')}</span>
219 <span>${_('Search')}</span>
220 </a>
220 </a>
221 </li>
221 </li>
222
222
223 %if h.HasPermissionAll('hg.admin')('access admin main page'):
223 %if h.HasPermissionAll('hg.admin')('access admin main page'):
224 <li ${is_current('admin')}>
224 <li ${is_current('admin')}>
225 <a title="${_('Admin')}" href="${h.url('admin_home')}">
225 <a title="${_('Admin')}" href="${h.url('admin_home')}">
226 <span class="icon">
226 <span class="icon">
227 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
227 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
228 </span>
228 </span>
229 <span>${_('Admin')}</span>
229 <span>${_('Admin')}</span>
230 </a>
230 </a>
231 <ul>
231 <ul>
232 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
232 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
233 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
233 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
234 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
234 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
235 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
235 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
236 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
236 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
237 </ul>
237 </ul>
238 </li>
238 </li>
239 %endif
239 %endif
240
240
241 </ul>
241 </ul>
242 %endif
242 %endif
243 </%def>
243 </%def>
244
244
245
245
246 <%def name="css()">
246 <%def name="css()">
247 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
247 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
248 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
248 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
249 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
249 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
250 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
250 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
251 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
251 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
252 </%def>
252 </%def>
253
253
254 <%def name="js()">
254 <%def name="js()">
255 ##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
255 ##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
256 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
256 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
257 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
257 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
258 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
258 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
259
259
260 <script type="text/javascript" src="/js/yui2.js"></script>
260 <script type="text/javascript" src="/js/yui2.js"></script>
261 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
261 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
262 <script type="text/javascript" src="/js/yui.flot.js"></script>
262 <script type="text/javascript" src="/js/yui.flot.js"></script>
263 </%def>
263 </%def>
264
264
265 <%def name="breadcrumbs()">
265 <%def name="breadcrumbs()">
266 <div class="breadcrumbs">
266 <div class="breadcrumbs">
267 ${self.breadcrumbs_links()}
267 ${self.breadcrumbs_links()}
268 </div>
268 </div>
269 </%def> No newline at end of file
269 </%def>
@@ -1,49 +1,49 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${_('Repository managment')}
4 ${_('Repository management')}
5 </%def>
5 </%def>
6 <%def name="breadcrumbs_links()">
6 <%def name="breadcrumbs_links()">
7 ${h.link_to(u'Home',h.url('/'))}
7 ${h.link_to(u'Home',h.url('/'))}
8 &raquo;
8 &raquo;
9 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
9 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
10 &raquo;
10 &raquo;
11 ${'%s: %s %s %s' % (_('File diff'),c.diff2,'&rarr;',c.diff1)|n}
11 ${'%s: %s %s %s' % (_('File diff'),c.diff2,'&rarr;',c.diff1)|n}
12 </%def>
12 </%def>
13
13
14 <%def name="page_nav()">
14 <%def name="page_nav()">
15 ${self.menu('files')}
15 ${self.menu('files')}
16 </%def>
16 </%def>
17 <%def name="main()">
17 <%def name="main()">
18 <div class="box">
18 <div class="box">
19 <!-- box / title -->
19 <!-- box / title -->
20 <div class="title">
20 <div class="title">
21 ${self.breadcrumbs()}
21 ${self.breadcrumbs()}
22 </div>
22 </div>
23 <div class="table">
23 <div class="table">
24 <div id="body" class="diffblock">
24 <div id="body" class="diffblock">
25 <div class="code-header">
25 <div class="code-header">
26 <div>
26 <div>
27 <span>${h.link_to(c.f_path,h.url('files_home',repo_name=c.repo_name,
27 <span>${h.link_to(c.f_path,h.url('files_home',repo_name=c.repo_name,
28 revision=c.diff2.split(':')[1],f_path=c.f_path))}</span>
28 revision=c.diff2.split(':')[1],f_path=c.f_path))}</span>
29 &raquo; <span>${h.link_to(_('diff'),
29 &raquo; <span>${h.link_to(_('diff'),
30 h.url.current(diff2=c.diff2.split(':')[-1],diff1=c.diff1.split(':')[-1],diff='diff'))}</span>
30 h.url.current(diff2=c.diff2.split(':')[-1],diff1=c.diff1.split(':')[-1],diff='diff'))}</span>
31 &raquo; <span>${h.link_to(_('raw diff'),
31 &raquo; <span>${h.link_to(_('raw diff'),
32 h.url.current(diff2=c.diff2.split(':')[-1],diff1=c.diff1.split(':')[-1],diff='raw'))}</span>
32 h.url.current(diff2=c.diff2.split(':')[-1],diff1=c.diff1.split(':')[-1],diff='raw'))}</span>
33 &raquo; <span>${h.link_to(_('download diff'),
33 &raquo; <span>${h.link_to(_('download diff'),
34 h.url.current(diff2=c.diff2.split(':')[-1],diff1=c.diff1.split(':')[-1],diff='download'))}</span>
34 h.url.current(diff2=c.diff2.split(':')[-1],diff1=c.diff1.split(':')[-1],diff='download'))}</span>
35 </div>
35 </div>
36 </div>
36 </div>
37 <div class="code-body">
37 <div class="code-body">
38 %if c.no_changes:
38 %if c.no_changes:
39 ${_('No changes')}
39 ${_('No changes')}
40 %else:
40 %else:
41 ${c.cur_diff|n}
41 ${c.cur_diff|n}
42 %endif
42 %endif
43 </div>
43 </div>
44 </div>
44 </div>
45 </div>
45 </div>
46 </div>
46 </div>
47 </%def>
47 </%def>
48
48
49 No newline at end of file
49
General Comments 0
You need to be logged in to leave comments. Login now