##// END OF EJS Templates
core: dropped usage of configobj entirely
super-admin -
r4975:0b11b7dc default
parent child Browse files
Show More
@@ -1,426 +1,428 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 Helpers for fixture generation
23 23 """
24 24
25 25 import os
26 26 import time
27 27 import tempfile
28 28 import shutil
29
30 import configobj
29 import configparser
31 30
32 31 from rhodecode.model.settings import SettingsModel
33 32 from rhodecode.tests import *
34 33 from rhodecode.model.db import Repository, User, RepoGroup, UserGroup, Gist, UserEmailMap
35 34 from rhodecode.model.meta import Session
36 35 from rhodecode.model.repo import RepoModel
37 36 from rhodecode.model.user import UserModel
38 37 from rhodecode.model.repo_group import RepoGroupModel
39 38 from rhodecode.model.user_group import UserGroupModel
40 39 from rhodecode.model.gist import GistModel
41 40 from rhodecode.model.auth_token import AuthTokenModel
42 41 from rhodecode.model.scm import ScmModel
43 42 from rhodecode.authentication.plugins.auth_rhodecode import \
44 43 RhodeCodeAuthPlugin
45 44
46 45 dn = os.path.dirname
47 46 FIXTURES = os.path.join(dn(dn(os.path.abspath(__file__))), 'tests', 'fixtures')
48 47
49 48
50 49 def error_function(*args, **kwargs):
51 50 raise Exception('Total Crash !')
52 51
53 52
54 53 class TestINI(object):
55 54 """
56 55 Allows to create a new test.ini file as a copy of existing one with edited
57 56 data. Example usage::
58 57
59 58 with TestINI('test.ini', [{'section':{'key':val'}]) as new_test_ini_path:
60 59 print('paster server %s' % new_test_ini)
61 60 """
62 61
63 62 def __init__(self, ini_file_path, ini_params, new_file_prefix='DEFAULT',
64 63 destroy=True, dir=None):
65 64 self.ini_file_path = ini_file_path
66 65 self.ini_params = ini_params
67 66 self.new_path = None
68 67 self.new_path_prefix = new_file_prefix
69 68 self._destroy = destroy
70 69 self._dir = dir
71 70
72 71 def __enter__(self):
73 72 return self.create()
74 73
75 74 def __exit__(self, exc_type, exc_val, exc_tb):
76 75 self.destroy()
77 76
78 77 def create(self):
79 config = configobj.ConfigObj(
80 self.ini_file_path, file_error=True, write_empty_values=True)
78 parser = configparser.ConfigParser()
79 parser.read(self.ini_file_path)
81 80
82 81 for data in self.ini_params:
83 section, ini_params = data.items()[0]
82 section, ini_params = list(data.items())[0]
83
84 84 for key, val in ini_params.items():
85 config[section][key] = val
85 parser[section][key] = str(val)
86
86 87 with tempfile.NamedTemporaryFile(
88 mode='w',
87 89 prefix=self.new_path_prefix, suffix='.ini', dir=self._dir,
88 90 delete=False) as new_ini_file:
89 config.write(new_ini_file)
91 parser.write(new_ini_file)
90 92 self.new_path = new_ini_file.name
91 93
92 94 return self.new_path
93 95
94 96 def destroy(self):
95 97 if self._destroy:
96 98 os.remove(self.new_path)
97 99
98 100
99 101 class Fixture(object):
100 102
101 103 def anon_access(self, status):
102 104 """
103 105 Context process for disabling anonymous access. use like:
104 106 fixture = Fixture()
105 107 with fixture.anon_access(False):
106 108 #tests
107 109
108 110 after this block anon access will be set to `not status`
109 111 """
110 112
111 113 class context(object):
112 114 def __enter__(self):
113 115 anon = User.get_default_user()
114 116 anon.active = status
115 117 Session().add(anon)
116 118 Session().commit()
117 119 time.sleep(1.5) # must sleep for cache (1s to expire)
118 120
119 121 def __exit__(self, exc_type, exc_val, exc_tb):
120 122 anon = User.get_default_user()
121 123 anon.active = not status
122 124 Session().add(anon)
123 125 Session().commit()
124 126
125 127 return context()
126 128
127 129 def auth_restriction(self, registry, auth_restriction):
128 130 """
129 131 Context process for changing the builtin rhodecode plugin auth restrictions.
130 132 Use like:
131 133 fixture = Fixture()
132 134 with fixture.auth_restriction('super_admin'):
133 135 #tests
134 136
135 137 after this block auth restriction will be taken off
136 138 """
137 139
138 140 class context(object):
139 141 def _get_plugin(self):
140 142 plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(RhodeCodeAuthPlugin.uid)
141 143 plugin = RhodeCodeAuthPlugin(plugin_id)
142 144 return plugin
143 145
144 146 def __enter__(self):
145 147
146 148 plugin = self._get_plugin()
147 149 plugin.create_or_update_setting('auth_restriction', auth_restriction)
148 150 Session().commit()
149 151 SettingsModel().invalidate_settings_cache()
150 152
151 153 def __exit__(self, exc_type, exc_val, exc_tb):
152 154
153 155 plugin = self._get_plugin()
154 156 plugin.create_or_update_setting(
155 157 'auth_restriction', RhodeCodeAuthPlugin.AUTH_RESTRICTION_NONE)
156 158 Session().commit()
157 159 SettingsModel().invalidate_settings_cache()
158 160
159 161 return context()
160 162
161 163 def scope_restriction(self, registry, scope_restriction):
162 164 """
163 165 Context process for changing the builtin rhodecode plugin scope restrictions.
164 166 Use like:
165 167 fixture = Fixture()
166 168 with fixture.scope_restriction('scope_http'):
167 169 #tests
168 170
169 171 after this block scope restriction will be taken off
170 172 """
171 173
172 174 class context(object):
173 175 def _get_plugin(self):
174 176 plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(RhodeCodeAuthPlugin.uid)
175 177 plugin = RhodeCodeAuthPlugin(plugin_id)
176 178 return plugin
177 179
178 180 def __enter__(self):
179 181 plugin = self._get_plugin()
180 182 plugin.create_or_update_setting('scope_restriction', scope_restriction)
181 183 Session().commit()
182 184 SettingsModel().invalidate_settings_cache()
183 185
184 186 def __exit__(self, exc_type, exc_val, exc_tb):
185 187 plugin = self._get_plugin()
186 188 plugin.create_or_update_setting(
187 189 'scope_restriction', RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_ALL)
188 190 Session().commit()
189 191 SettingsModel().invalidate_settings_cache()
190 192
191 193 return context()
192 194
193 195 def _get_repo_create_params(self, **custom):
194 196 repo_type = custom.get('repo_type') or 'hg'
195 197
196 198 default_landing_ref, landing_ref_lbl = ScmModel.backend_landing_ref(repo_type)
197 199
198 200 defs = {
199 201 'repo_name': None,
200 202 'repo_type': repo_type,
201 203 'clone_uri': '',
202 204 'push_uri': '',
203 205 'repo_group': '-1',
204 206 'repo_description': 'DESC',
205 207 'repo_private': False,
206 208 'repo_landing_commit_ref': default_landing_ref,
207 209 'repo_copy_permissions': False,
208 210 'repo_state': Repository.STATE_CREATED,
209 211 }
210 212 defs.update(custom)
211 213 if 'repo_name_full' not in custom:
212 214 defs.update({'repo_name_full': defs['repo_name']})
213 215
214 216 # fix the repo name if passed as repo_name_full
215 217 if defs['repo_name']:
216 218 defs['repo_name'] = defs['repo_name'].split('/')[-1]
217 219
218 220 return defs
219 221
220 222 def _get_group_create_params(self, **custom):
221 223 defs = {
222 224 'group_name': None,
223 225 'group_description': 'DESC',
224 226 'perm_updates': [],
225 227 'perm_additions': [],
226 228 'perm_deletions': [],
227 229 'group_parent_id': -1,
228 230 'enable_locking': False,
229 231 'recursive': False,
230 232 }
231 233 defs.update(custom)
232 234
233 235 return defs
234 236
235 237 def _get_user_create_params(self, name, **custom):
236 238 defs = {
237 239 'username': name,
238 240 'password': 'qweqwe',
239 241 'email': '%s+test@rhodecode.org' % name,
240 242 'firstname': 'TestUser',
241 243 'lastname': 'Test',
242 244 'description': 'test description',
243 245 'active': True,
244 246 'admin': False,
245 247 'extern_type': 'rhodecode',
246 248 'extern_name': None,
247 249 }
248 250 defs.update(custom)
249 251
250 252 return defs
251 253
252 254 def _get_user_group_create_params(self, name, **custom):
253 255 defs = {
254 256 'users_group_name': name,
255 257 'user_group_description': 'DESC',
256 258 'users_group_active': True,
257 259 'user_group_data': {},
258 260 }
259 261 defs.update(custom)
260 262
261 263 return defs
262 264
263 265 def create_repo(self, name, **kwargs):
264 266 repo_group = kwargs.get('repo_group')
265 267 if isinstance(repo_group, RepoGroup):
266 268 kwargs['repo_group'] = repo_group.group_id
267 269 name = name.split(Repository.NAME_SEP)[-1]
268 270 name = Repository.NAME_SEP.join((repo_group.group_name, name))
269 271
270 272 if 'skip_if_exists' in kwargs:
271 273 del kwargs['skip_if_exists']
272 274 r = Repository.get_by_repo_name(name)
273 275 if r:
274 276 return r
275 277
276 278 form_data = self._get_repo_create_params(repo_name=name, **kwargs)
277 279 cur_user = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
278 280 RepoModel().create(form_data, cur_user)
279 281 Session().commit()
280 282 repo = Repository.get_by_repo_name(name)
281 283 assert repo
282 284 return repo
283 285
284 286 def create_fork(self, repo_to_fork, fork_name, **kwargs):
285 287 repo_to_fork = Repository.get_by_repo_name(repo_to_fork)
286 288
287 289 form_data = self._get_repo_create_params(
288 290 repo_name=fork_name,
289 291 fork_parent_id=repo_to_fork.repo_id,
290 292 repo_type=repo_to_fork.repo_type,
291 293 **kwargs)
292 294
293 295 #TODO: fix it !!
294 296 form_data['description'] = form_data['repo_description']
295 297 form_data['private'] = form_data['repo_private']
296 298 form_data['landing_rev'] = form_data['repo_landing_commit_ref']
297 299
298 300 owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
299 301 RepoModel().create_fork(form_data, cur_user=owner)
300 302 Session().commit()
301 303 r = Repository.get_by_repo_name(fork_name)
302 304 assert r
303 305 return r
304 306
305 307 def destroy_repo(self, repo_name, **kwargs):
306 308 RepoModel().delete(repo_name, pull_requests='delete', **kwargs)
307 309 Session().commit()
308 310
309 311 def destroy_repo_on_filesystem(self, repo_name):
310 312 rm_path = os.path.join(RepoModel().repos_path, repo_name)
311 313 if os.path.isdir(rm_path):
312 314 shutil.rmtree(rm_path)
313 315
314 316 def create_repo_group(self, name, **kwargs):
315 317 if 'skip_if_exists' in kwargs:
316 318 del kwargs['skip_if_exists']
317 319 gr = RepoGroup.get_by_group_name(group_name=name)
318 320 if gr:
319 321 return gr
320 322 form_data = self._get_group_create_params(group_name=name, **kwargs)
321 323 owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
322 324 gr = RepoGroupModel().create(
323 325 group_name=form_data['group_name'],
324 326 group_description=form_data['group_name'],
325 327 owner=owner)
326 328 Session().commit()
327 329 gr = RepoGroup.get_by_group_name(gr.group_name)
328 330 return gr
329 331
330 332 def destroy_repo_group(self, repogroupid):
331 333 RepoGroupModel().delete(repogroupid)
332 334 Session().commit()
333 335
334 336 def create_user(self, name, **kwargs):
335 337 if 'skip_if_exists' in kwargs:
336 338 del kwargs['skip_if_exists']
337 339 user = User.get_by_username(name)
338 340 if user:
339 341 return user
340 342 form_data = self._get_user_create_params(name, **kwargs)
341 343 user = UserModel().create(form_data)
342 344
343 345 # create token for user
344 346 AuthTokenModel().create(
345 347 user=user, description=u'TEST_USER_TOKEN')
346 348
347 349 Session().commit()
348 350 user = User.get_by_username(user.username)
349 351 return user
350 352
351 353 def destroy_user(self, userid):
352 354 UserModel().delete(userid)
353 355 Session().commit()
354 356
355 357 def create_additional_user_email(self, user, email):
356 358 uem = UserEmailMap()
357 359 uem.user = user
358 360 uem.email = email
359 361 Session().add(uem)
360 362 return uem
361 363
362 364 def destroy_users(self, userid_iter):
363 365 for user_id in userid_iter:
364 366 if User.get_by_username(user_id):
365 367 UserModel().delete(user_id)
366 368 Session().commit()
367 369
368 370 def create_user_group(self, name, **kwargs):
369 371 if 'skip_if_exists' in kwargs:
370 372 del kwargs['skip_if_exists']
371 373 gr = UserGroup.get_by_group_name(group_name=name)
372 374 if gr:
373 375 return gr
374 376 # map active flag to the real attribute. For API consistency of fixtures
375 377 if 'active' in kwargs:
376 378 kwargs['users_group_active'] = kwargs['active']
377 379 del kwargs['active']
378 380 form_data = self._get_user_group_create_params(name, **kwargs)
379 381 owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
380 382 user_group = UserGroupModel().create(
381 383 name=form_data['users_group_name'],
382 384 description=form_data['user_group_description'],
383 385 owner=owner, active=form_data['users_group_active'],
384 386 group_data=form_data['user_group_data'])
385 387 Session().commit()
386 388 user_group = UserGroup.get_by_group_name(user_group.users_group_name)
387 389 return user_group
388 390
389 391 def destroy_user_group(self, usergroupid):
390 392 UserGroupModel().delete(user_group=usergroupid, force=True)
391 393 Session().commit()
392 394
393 395 def create_gist(self, **kwargs):
394 396 form_data = {
395 397 'description': 'new-gist',
396 398 'owner': TEST_USER_ADMIN_LOGIN,
397 399 'gist_type': GistModel.cls.GIST_PUBLIC,
398 400 'lifetime': -1,
399 401 'acl_level': Gist.ACL_LEVEL_PUBLIC,
400 402 'gist_mapping': {'filename1.txt': {'content': 'hello world'},}
401 403 }
402 404 form_data.update(kwargs)
403 405 gist = GistModel().create(
404 406 description=form_data['description'], owner=form_data['owner'],
405 407 gist_mapping=form_data['gist_mapping'], gist_type=form_data['gist_type'],
406 408 lifetime=form_data['lifetime'], gist_acl_level=form_data['acl_level']
407 409 )
408 410 Session().commit()
409 411 return gist
410 412
411 413 def destroy_gists(self, gistid=None):
412 414 for g in GistModel.cls.get_all():
413 415 if gistid:
414 416 if gistid == g.gist_access_id:
415 417 GistModel().delete(g)
416 418 else:
417 419 GistModel().delete(g)
418 420 Session().commit()
419 421
420 422 def load_resource(self, resource_name, strip=False):
421 423 with open(os.path.join(FIXTURES, resource_name)) as f:
422 424 source = f.read()
423 425 if strip:
424 426 source = source.strip()
425 427
426 428 return source
@@ -1,200 +1,201 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 import os
23 23 import time
24 24 import tempfile
25 25 import pytest
26 26 import subprocess
27 import configobj
28 27 import logging
29 28 from urllib.request import urlopen
30 29 from urllib.error import URLError
31 30 import configparser
32 31
33 32
34 33 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS
35 34 from rhodecode.tests.utils import is_url_reachable
36 35
37 36 log = logging.getLogger(__name__)
38 37
39 38
40 39 def get_port(pyramid_config):
41 40 config = configparser.ConfigParser()
42 41 config.read(pyramid_config)
43 42 return config.get('server:main', 'port')
44 43
45 44
46 45 def get_host_url(pyramid_config):
47 46 """Construct the host url using the port in the test configuration."""
48 return '127.0.0.1:%s' % get_port(pyramid_config)
47 port = get_port(pyramid_config)
48 return f'127.0.0.1:{port}'
49 49
50 50
51 51 def assert_no_running_instance(url):
52 52 if is_url_reachable(url):
53 print("Hint: Usually this means another instance of server "
54 "is running in the background at %s." % url)
55 pytest.fail(
56 "Port is not free at %s, cannot start server at" % url)
53 print(f"Hint: Usually this means another instance of server "
54 f"is running in the background at {url}.")
55 pytest.fail(f"Port is not free at {url}, cannot start server at")
57 56
58 57
59 58 class ServerBase(object):
60 59 _args = []
61 60 log_file_name = 'NOT_DEFINED.log'
62 61 status_url_tmpl = 'http://{host}:{port}'
63 62
64 63 def __init__(self, config_file, log_file):
65 64 self.config_file = config_file
66 config_data = configobj.ConfigObj(config_file)
67 self._config = config_data['server:main']
65 config = configparser.ConfigParser()
66 config.read(config_file)
67
68 self._config = {k: v for k, v in config['server:main'].items()}
68 69
69 70 self._args = []
70 71 self.log_file = log_file or os.path.join(
71 72 tempfile.gettempdir(), self.log_file_name)
72 73 self.process = None
73 74 self.server_out = None
74 75 log.info("Using the {} configuration:{}".format(
75 76 self.__class__.__name__, config_file))
76 77
77 78 if not os.path.isfile(config_file):
78 raise RuntimeError('Failed to get config at {}'.format(config_file))
79 raise RuntimeError(f'Failed to get config at {config_file}')
79 80
80 81 @property
81 82 def command(self):
82 83 return ' '.join(self._args)
83 84
84 85 @property
85 86 def http_url(self):
86 87 template = 'http://{host}:{port}/'
87 88 return template.format(**self._config)
88 89
89 90 def host_url(self):
90 91 return 'http://' + get_host_url(self.config_file)
91 92
92 93 def get_rc_log(self):
93 94 with open(self.log_file) as f:
94 95 return f.read()
95 96
96 97 def wait_until_ready(self, timeout=30):
97 98 host = self._config['host']
98 99 port = self._config['port']
99 100 status_url = self.status_url_tmpl.format(host=host, port=port)
100 101 start = time.time()
101 102
102 103 while time.time() - start < timeout:
103 104 try:
104 105 urlopen(status_url)
105 106 break
106 107 except URLError:
107 108 time.sleep(0.2)
108 109 else:
109 110 pytest.fail(
110 111 "Starting the {} failed or took more than {} "
111 112 "seconds. cmd: `{}`".format(
112 113 self.__class__.__name__, timeout, self.command))
113 114
114 115 log.info('Server of {} ready at url {}'.format(
115 116 self.__class__.__name__, status_url))
116 117
117 118 def shutdown(self):
118 119 self.process.kill()
119 120 self.server_out.flush()
120 121 self.server_out.close()
121 122
122 123 def get_log_file_with_port(self):
123 124 log_file = list(self.log_file.partition('.log'))
124 125 log_file.insert(1, get_port(self.config_file))
125 126 log_file = ''.join(log_file)
126 127 return log_file
127 128
128 129
129 130 class RcVCSServer(ServerBase):
130 131 """
131 132 Represents a running VCSServer instance.
132 133 """
133 134
134 135 log_file_name = 'rc-vcsserver.log'
135 136 status_url_tmpl = 'http://{host}:{port}/status'
136 137
137 138 def __init__(self, config_file, log_file=None):
138 139 super(RcVCSServer, self).__init__(config_file, log_file)
139 140 self._args = ['gunicorn', '--paste', self.config_file]
140 141
141 142 def start(self):
142 143 env = os.environ.copy()
143 144
144 145 self.log_file = self.get_log_file_with_port()
145 146 self.server_out = open(self.log_file, 'w')
146 147
147 148 host_url = self.host_url()
148 149 assert_no_running_instance(host_url)
149 150
150 151 log.info('rhodecode-vcsserver start command: {}'.format(' '.join(self._args)))
151 152 log.info('rhodecode-vcsserver starting at: {}'.format(host_url))
152 153 log.info('rhodecode-vcsserver command: {}'.format(self.command))
153 154 log.info('rhodecode-vcsserver logfile: {}'.format(self.log_file))
154 155
155 156 self.process = subprocess.Popen(
156 157 self._args, bufsize=0, env=env,
157 158 stdout=self.server_out, stderr=self.server_out)
158 159
159 160
160 161 class RcWebServer(ServerBase):
161 162 """
162 163 Represents a running RCE web server used as a test fixture.
163 164 """
164 165
165 166 log_file_name = 'rc-web.log'
166 167 status_url_tmpl = 'http://{host}:{port}/_admin/ops/ping'
167 168
168 169 def __init__(self, config_file, log_file=None):
169 170 super(RcWebServer, self).__init__(config_file, log_file)
170 171 self._args = [
171 172 'gunicorn', '--worker-class', 'gevent', '--paste', config_file]
172 173
173 174 def start(self):
174 175 env = os.environ.copy()
175 176 env['RC_NO_TMP_PATH'] = '1'
176 177
177 178 self.log_file = self.get_log_file_with_port()
178 179 self.server_out = open(self.log_file, 'w')
179 180
180 181 host_url = self.host_url()
181 182 assert_no_running_instance(host_url)
182 183
183 184 log.info('rhodecode-web starting at: {}'.format(host_url))
184 185 log.info('rhodecode-web command: {}'.format(self.command))
185 186 log.info('rhodecode-web logfile: {}'.format(self.log_file))
186 187
187 188 self.process = subprocess.Popen(
188 189 self._args, bufsize=0, env=env,
189 190 stdout=self.server_out, stderr=self.server_out)
190 191
191 192 def repo_clone_url(self, repo_name, **kwargs):
192 193 params = {
193 194 'user': TEST_USER_ADMIN_LOGIN,
194 195 'passwd': TEST_USER_ADMIN_PASS,
195 196 'host': get_host_url(self.config_file),
196 197 'cloned_repo': repo_name,
197 198 }
198 199 params.update(**kwargs)
199 200 _url = 'http://%(user)s:%(passwd)s@%(host)s/%(cloned_repo)s' % params
200 201 return _url
@@ -1,208 +1,208 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 # Import early to make sure things are patched up properly
22 22 from setuptools import setup, find_packages
23 23
24 24 import os
25 25 import re
26 26 import sys
27 27 import pkgutil
28 28 import platform
29 29 import codecs
30 30
31 31 import pip
32 32
33 33 pip_major_version = int(pip.__version__.split(".")[0])
34 34 if pip_major_version >= 20:
35 35 from pip._internal.req import parse_requirements
36 36 from pip._internal.network.session import PipSession
37 37 elif pip_major_version >= 10:
38 38 from pip._internal.req import parse_requirements
39 39 from pip._internal.download import PipSession
40 40 else:
41 41 from pip.req import parse_requirements
42 42 from pip.download import PipSession
43 43
44 44
45 45 def get_package_name(req_object):
46 46 package_name = None
47 47 try:
48 48 from pip._internal.req.constructors import install_req_from_parsed_requirement
49 49 except ImportError:
50 50 install_req_from_parsed_requirement = None
51 51
52 52 # In 20.1 of pip, the requirements object changed
53 53 if hasattr(req_object, 'req'):
54 54 package_name = req_object.req.name
55 55
56 56 if package_name is None:
57 57 if install_req_from_parsed_requirement:
58 58 package = install_req_from_parsed_requirement(req_object)
59 59 package_name = package.req.name
60 60
61 61 if package_name is None:
62 62 # fallback for older pip
63 63 package_name = re.split('===|<=|!=|==|>=|~=|<|>', req_object.requirement)[0]
64 64
65 65 return package_name
66 66
67 67
68 68 if sys.version_info < (3, 10):
69 69 raise Exception('RhodeCode requires Python 3.10 or later')
70 70
71 71 here = os.path.abspath(os.path.dirname(__file__))
72 72
73 73 # defines current platform
74 74 __platform__ = platform.system()
75 75 __license__ = 'AGPLv3, and Commercial License'
76 76 __author__ = 'RhodeCode GmbH'
77 77 __url__ = 'https://code.rhodecode.com'
78 78 is_windows = __platform__ in ('Windows',)
79 79
80 80
81 81 def _get_requirements(req_filename, exclude=None, extras=None):
82 82 extras = extras or []
83 83 exclude = exclude or []
84 84
85 85 try:
86 86 parsed = parse_requirements(
87 87 os.path.join(here, req_filename), session=PipSession())
88 88 except TypeError:
89 89 # try pip < 6.0.0, that doesn't support session
90 90 parsed = parse_requirements(os.path.join(here, req_filename))
91 91
92 92 requirements = []
93 93 for int_req in parsed:
94 94 req_name = get_package_name(int_req)
95 95 if req_name not in exclude:
96 96 requirements.append(req_name)
97 97 return requirements + extras
98 98
99 99
100 100 # requirements extract
101 101 setup_requirements = ['PasteScript']
102 102 install_requirements = _get_requirements(
103 103 'requirements.txt', exclude=['setuptools', 'entrypoints'])
104 104 test_requirements = _get_requirements(
105 'requirements_test.txt', extras=['configobj'])
105 'requirements_test.txt')
106 106
107 107
108 108 def get_version():
109 109 version = pkgutil.get_data('rhodecode', 'VERSION')
110 110 return version.decode().strip()
111 111
112 112
113 113 # additional files that goes into package itself
114 114 package_data = {
115 115 '': ['*.txt', '*.rst'],
116 116 'configs': ['*.ini'],
117 117 'rhodecode': ['VERSION', 'i18n/*/LC_MESSAGES/*.mo', ],
118 118 }
119 119
120 120 description = 'Source Code Management Platform'
121 121 keywords = ' '.join([
122 122 'rhodecode', 'mercurial', 'git', 'svn',
123 123 'code review',
124 124 'repo groups', 'ldap', 'repository management', 'hgweb',
125 125 'hgwebdir', 'gitweb', 'serving hgweb',
126 126 ])
127 127
128 128
129 129 # README/DESCRIPTION generation
130 130 readme_file = 'README.rst'
131 131 changelog_file = 'CHANGES.rst'
132 132 try:
133 133 long_description = codecs.open(readme_file).read() + '\n\n' + \
134 134 codecs.open(changelog_file).read()
135 135 except IOError as err:
136 136 sys.stderr.write(
137 137 "[WARNING] Cannot find file specified as long_description (%s)\n "
138 138 "or changelog (%s) skipping that file" % (readme_file, changelog_file))
139 139 long_description = description
140 140
141 141
142 142 setup(
143 143 name='rhodecode-enterprise-ce',
144 144 version=get_version(),
145 145 description=description,
146 146 long_description=long_description,
147 147 keywords=keywords,
148 148 license=__license__,
149 149 author=__author__,
150 150 author_email='support@rhodecode.com',
151 151 url=__url__,
152 152 setup_requires=setup_requirements,
153 153 install_requires=install_requirements,
154 154 tests_require=test_requirements,
155 155 zip_safe=False,
156 156 packages=find_packages(exclude=["docs", "tests*"]),
157 157 package_data=package_data,
158 158 include_package_data=True,
159 159 classifiers=[
160 160 'Development Status :: 6 - Mature',
161 161 'Environment :: Web Environment',
162 162 'Intended Audience :: Developers',
163 163 'Operating System :: OS Independent',
164 164 'Topic :: Software Development :: Version Control',
165 165 'License :: OSI Approved :: Affero GNU General Public License v3 or later (AGPLv3+)',
166 166 'Programming Language :: Python :: 3.10',
167 167 ],
168 168 message_extractors={
169 169 'rhodecode': [
170 170 ('**.py', 'python', None),
171 171 ('**.js', 'javascript', None),
172 172 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
173 173 ('templates/**.html', 'mako', {'input_encoding': 'utf-8'}),
174 174 ('public/**', 'ignore', None),
175 175 ]
176 176 },
177 177 paster_plugins=['PasteScript'],
178 178 entry_points={
179 179 'paste.app_factory': [
180 180 'main=rhodecode.config.middleware:make_pyramid_app',
181 181 ],
182 182 'paste.global_paster_command': [
183 183 'ishell=rhodecode.lib.paster_commands.ishell:Command',
184 184 'upgrade-db=rhodecode.lib.paster_commands.upgrade_db:UpgradeDb',
185 185
186 186 'setup-rhodecode=rhodecode.lib.paster_commands.deprecated.setup_rhodecode:Command',
187 187 'celeryd=rhodecode.lib.paster_commands.deprecated.celeryd:Command',
188 188 ],
189 189 'pyramid.pshell_runner': [
190 190 'ipython = rhodecode.lib.pyramid_shell:ipython_shell_runner',
191 191 ],
192 192 'pytest11': [
193 193 'pylons=rhodecode.tests.pylons_plugin',
194 194 'enterprise=rhodecode.tests.plugin',
195 195 ],
196 196 'console_scripts': [
197 197 'rc-setup-app=rhodecode.lib.rc_commands.setup_rc:main',
198 198 'rc-upgrade-db=rhodecode.lib.rc_commands.upgrade_db:main',
199 199 'rc-ishell=rhodecode.lib.rc_commands.ishell:main',
200 200 'rc-add-artifact=rhodecode.lib.rc_commands.add_artifact:main',
201 201 'rc-ssh-wrapper=rhodecode.apps.ssh_support.lib.ssh_wrapper:main',
202 202 ],
203 203 'beaker.backends': [
204 204 'memorylru_base=rhodecode.lib.memory_lru_dict:MemoryLRUNamespaceManagerBase',
205 205 'memorylru_debug=rhodecode.lib.memory_lru_dict:MemoryLRUNamespaceManagerDebug'
206 206 ]
207 207 },
208 208 )
General Comments 0
You need to be logged in to leave comments. Login now