##// END OF EJS Templates
file-uploads: created simple upload capabilities....
ergo -
r3432:834ca581 default
parent child Browse files
Show More
@@ -0,0 +1,49 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 import os
21 from rhodecode.apps.upload_store import config_keys
22 from rhodecode.config.middleware import _bool_setting, _string_setting
23
24
25 def _sanitize_settings_and_apply_defaults(settings):
26 """
27 Set defaults, convert to python types and validate settings.
28 """
29 _bool_setting(settings, config_keys.enabled, 'true')
30
31 _string_setting(settings, config_keys.backend, 'local')
32
33 default_store = os.path.join(os.path.dirname(settings['__file__']), 'upload_store')
34 _string_setting(settings, config_keys.store_path, default_store)
35
36
37 def includeme(config):
38 settings = config.registry.settings
39 _sanitize_settings_and_apply_defaults(settings)
40
41 config.add_route(
42 name='upload_file',
43 pattern='/_file_store/upload')
44 config.add_route(
45 name='download_file',
46 pattern='/_file_store/download/{fid}')
47
48 # Scan module for configuration decorators.
49 config.scan('.views', ignore='.tests')
@@ -0,0 +1,27 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 # Definition of setting keys used to configure this module. Defined here to
23 # avoid repetition of keys throughout the module.
24
25 enabled = 'file_store.enabled'
26 backend = 'file_store.backend'
27 store_path = 'file_store.storage_path'
@@ -0,0 +1,31 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 class FileNotAllowedException(Exception):
23 """
24 Thrown if file does not have an allowed extension.
25 """
26
27
28 class FileOverSizeException(Exception):
29 """
30 Thrown if file is over the set limit.
31 """
@@ -0,0 +1,66 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 ANY = []
23 TEXT_EXT = ['txt', 'md', 'rst', 'log']
24 DOCUMENTS_EXT = ['pdf', 'rtf', 'odf', 'ods', 'gnumeric', 'abw', 'doc', 'docx', 'xls', 'xlsx']
25 IMAGES_EXT = ['jpg', 'jpe', 'jpeg', 'png', 'gif', 'svg', 'bmp', 'tiff']
26 AUDIO_EXT = ['wav', 'mp3', 'aac', 'ogg', 'oga', 'flac']
27 VIDEO_EXT = ['mpeg', '3gp', 'avi', 'divx', 'dvr', 'flv', 'mp4', 'wmv']
28 DATA_EXT = ['csv', 'ini', 'json', 'plist', 'xml', 'yaml', 'yml']
29 SCRIPTS_EXT = ['js', 'php', 'pl', 'py', 'rb', 'sh', 'go', 'c', 'h']
30 ARCHIVES_EXT = ['gz', 'bz2', 'zip', 'tar', 'tgz', 'txz', '7z']
31 EXECUTABLES_EXT = ['so', 'exe', 'dll']
32
33
34 DEFAULT = DOCUMENTS_EXT + TEXT_EXT + IMAGES_EXT + DATA_EXT
35
36 GROUPS = dict((
37 ('any', ANY),
38 ('text', TEXT_EXT),
39 ('documents', DOCUMENTS_EXT),
40 ('images', IMAGES_EXT),
41 ('audio', AUDIO_EXT),
42 ('video', VIDEO_EXT),
43 ('data', DATA_EXT),
44 ('scripts', SCRIPTS_EXT),
45 ('archives', ARCHIVES_EXT),
46 ('executables', EXECUTABLES_EXT),
47 ('default', DEFAULT),
48 ))
49
50
51 def resolve_extensions(extensions, groups=None):
52 """
53 Calculate allowed extensions based on a list of extensions provided, and optional
54 groups of extensions from the available lists.
55
56 :param extensions: a list of extensions e.g ['py', 'txt']
57 :param groups: additionally groups to extend the extensions.
58 """
59 groups = groups or []
60 valid_exts = set([x.lower() for x in extensions])
61
62 for group in groups:
63 if group in GROUPS:
64 valid_exts.update(GROUPS[group])
65
66 return valid_exts
@@ -0,0 +1,167 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import os
22 import shutil
23
24 from rhodecode.lib.ext_json import json
25 from rhodecode.apps.upload_store import utils
26 from rhodecode.apps.upload_store.extensions import resolve_extensions
27 from rhodecode.apps.upload_store.exceptions import FileNotAllowedException
28
29
30 class LocalFileStorage(object):
31
32 @classmethod
33 def resolve_name(cls, name, directory):
34 """
35 Resolves a unique name and the correct path. If a filename
36 for that path already exists then a numeric prefix with values > 0 will be
37 added, for example test.jpg -> test-1.jpg etc. initially file would have 0 prefix.
38
39 :param name: base name of file
40 :param directory: absolute directory path
41 """
42
43 basename, ext = os.path.splitext(name)
44 counter = 0
45 while True:
46 name = '%s-%d%s' % (basename, counter, ext)
47 path = os.path.join(directory, name)
48 if not os.path.exists(path):
49 return name, path
50 counter += 1
51
52 def __init__(self, base_path, extension_groups=None):
53
54 """
55 Local file storage
56
57 :param base_path: the absolute base path where uploads are stored
58 :param extension_groups: extensions string
59 """
60
61 extension_groups = extension_groups or ['any']
62 self.base_path = base_path
63 self.extensions = resolve_extensions([], groups=extension_groups)
64
65 def store_path(self, filename):
66 """
67 Returns absolute file path of the filename, joined to the
68 base_path.
69
70 :param filename: base name of file
71 """
72 return os.path.join(self.base_path, filename)
73
74 def delete(self, filename):
75 """
76 Deletes the filename. Filename is resolved with the
77 absolute path based on base_path. If file does not exist,
78 returns **False**, otherwise **True**
79
80 :param filename: base name of file
81 """
82 if self.exists(filename):
83 os.remove(self.store_path(filename))
84 return True
85 return False
86
87 def exists(self, filename):
88 """
89 Checks if file exists. Resolves filename's absolute
90 path based on base_path.
91
92 :param filename: base name of file
93 """
94 return os.path.exists(self.store_path(filename))
95
96 def filename_allowed(self, filename, extensions=None):
97 """Checks if a filename has an allowed extension
98
99 :param filename: base name of file
100 :param extensions: iterable of extensions (or self.extensions)
101 """
102 _, ext = os.path.splitext(filename)
103 return self.extension_allowed(ext, extensions)
104
105 def extension_allowed(self, ext, extensions=None):
106 """
107 Checks if an extension is permitted. Both e.g. ".jpg" and
108 "jpg" can be passed in. Extension lookup is case-insensitive.
109
110 :param extensions: iterable of extensions (or self.extensions)
111 """
112
113 extensions = extensions or self.extensions
114 if not extensions:
115 return True
116 if ext.startswith('.'):
117 ext = ext[1:]
118 return ext.lower() in extensions
119
120 def save_file(self, file_obj, filename, directory=None, extensions=None,
121 metadata=None, **kwargs):
122 """
123 Saves a file object to the uploads location.
124 Returns the resolved filename, i.e. the directory +
125 the (randomized/incremented) base name.
126
127 :param file_obj: **cgi.FieldStorage** object (or similar)
128 :param filename: original filename
129 :param directory: relative path of sub-directory
130 :param extensions: iterable of allowed extensions, if not default
131 :param metadata: JSON metadata to store next to the file with .meta suffix
132 :returns: modified filename
133 """
134
135 extensions = extensions or self.extensions
136
137 if not self.filename_allowed(filename, extensions):
138 raise FileNotAllowedException()
139
140 if directory:
141 dest_directory = os.path.join(self.base_path, directory)
142 else:
143 dest_directory = self.base_path
144
145 if not os.path.exists(dest_directory):
146 os.makedirs(dest_directory)
147
148 filename = utils.uid_filename(filename)
149
150 filename, path = self.resolve_name(filename, dest_directory)
151 filename_meta = filename + '.meta'
152
153 file_obj.seek(0)
154
155 with open(path, "wb") as dest:
156 shutil.copyfileobj(file_obj, dest)
157
158 if metadata:
159 size = os.stat(path).st_size
160 metadata.update({'size': size})
161 with open(os.path.join(dest_directory, filename_meta), "wb") as dest_meta:
162 dest_meta.write(json.dumps(metadata))
163
164 if directory:
165 filename = os.path.join(directory, filename)
166
167 return filename
@@ -0,0 +1,20 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
@@ -0,0 +1,110 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 import os
21 import pytest
22
23 from rhodecode.lib.ext_json import json
24 from rhodecode.tests import TestController
25 from rhodecode.apps.upload_store import utils, config_keys
26
27
28 def route_path(name, params=None, **kwargs):
29 import urllib
30
31 base_url = {
32 'upload_file': '/_file_store/upload',
33 'download_file': '/_file_store/download/{fid}',
34
35 }[name].format(**kwargs)
36
37 if params:
38 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
39 return base_url
40
41
42 class TestFileStoreViews(TestController):
43
44 @pytest.mark.parametrize("fid, content, exists", [
45 ('abcde-0.jpg', "xxxxx", True),
46 ('abcde-0.exe', "1234567", True),
47 ('abcde-0.jpg', "xxxxx", False),
48 ])
49 def test_get_files_from_store(self, fid, content, exists, tmpdir):
50 self.log_user()
51 store_path = self.app._pyramid_settings[config_keys.store_path]
52
53 if exists:
54 status = 200
55 store = utils.get_file_storage({config_keys.store_path: store_path})
56 filesystem_file = os.path.join(str(tmpdir), fid)
57 with open(filesystem_file, 'wb') as f:
58 f.write(content)
59
60 with open(filesystem_file, 'rb') as f:
61 fid = store.save_file(f, fid, metadata={'filename': fid})
62
63 else:
64 status = 404
65
66 response = self.app.get(route_path('download_file', fid=fid), status=status)
67
68 if exists:
69 assert response.text == content
70 metadata = os.path.join(store_path, fid + '.meta')
71 assert os.path.exists(metadata)
72 with open(metadata, 'rb') as f:
73 json_data = json.loads(f.read())
74
75 assert json_data
76 assert 'size' in json_data
77
78 def test_upload_files_without_content_to_store(self):
79 self.log_user()
80 response = self.app.post(
81 route_path('upload_file'),
82 params={'csrf_token': self.csrf_token},
83 status=200)
84
85 assert response.json == {
86 u'error': u'store_file data field is missing',
87 u'access_path': None,
88 u'store_fid': None}
89
90 def test_upload_files_bogus_content_to_store(self):
91 self.log_user()
92 response = self.app.post(
93 route_path('upload_file'),
94 params={'csrf_token': self.csrf_token, 'store_file': 'bogus'},
95 status=200)
96
97 assert response.json == {
98 u'error': u'filename cannot be read from the data field',
99 u'access_path': None,
100 u'store_fid': None}
101
102 def test_upload_content_to_store(self):
103 self.log_user()
104 response = self.app.post(
105 route_path('upload_file'),
106 upload_files=[('store_file', 'myfile.txt', 'SOME CONTENT')],
107 params={'csrf_token': self.csrf_token},
108 status=200)
109
110 assert response.json['store_fid']
@@ -0,0 +1,47 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 import os
23 import uuid
24
25
26 def get_file_storage(settings):
27 from rhodecode.apps.upload_store.local_store import LocalFileStorage
28 from rhodecode.apps.upload_store import config_keys
29 store_path = settings.get(config_keys.store_path)
30 return LocalFileStorage(base_path=store_path)
31
32
33 def uid_filename(filename, randomized=True):
34 """
35 Generates a randomized or stable (uuid) filename,
36 preserving the original extension.
37
38 :param filename: the original filename
39 :param randomized: define if filename should be stable (sha1 based) or randomized
40 """
41 _, ext = os.path.splitext(filename)
42 if randomized:
43 uid = uuid.uuid4()
44 else:
45 hash_key = '{}.{}'.format(filename, 'store')
46 uid = uuid.uuid5(uuid.NAMESPACE_URL, hash_key)
47 return str(uid) + ext.lower()
@@ -0,0 +1,97 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 import logging
21
22 from pyramid.view import view_config
23 from pyramid.response import FileResponse
24 from pyramid.httpexceptions import HTTPFound, HTTPNotFound
25
26 from rhodecode.apps._base import BaseAppView
27 from rhodecode.apps.upload_store import utils
28 from rhodecode.apps.upload_store.exceptions import (
29 FileNotAllowedException,FileOverSizeException)
30
31 from rhodecode.lib import helpers as h
32 from rhodecode.lib import audit_logger
33 from rhodecode.lib.auth import (CSRFRequired, NotAnonymous)
34
35 log = logging.getLogger(__name__)
36
37
38 class FileStoreView(BaseAppView):
39 upload_key = 'store_file'
40
41 def load_default_context(self):
42 c = self._get_local_tmpl_context()
43 self.storage = utils.get_file_storage(self.request.registry.settings)
44 return c
45
46 @NotAnonymous()
47 @CSRFRequired()
48 @view_config(route_name='upload_file', request_method='POST', renderer='json_ext')
49 def upload_file(self):
50 self.load_default_context()
51 file_obj = self.request.POST.get(self.upload_key)
52
53 if file_obj is None:
54 return {'store_fid': None,
55 'access_path': None,
56 'error': '{} data field is missing'.format(self.upload_key)}
57
58 if not hasattr(file_obj, 'filename'):
59 return {'store_fid': None,
60 'access_path': None,
61 'error': 'filename cannot be read from the data field'}
62
63 filename = file_obj.filename
64
65 metadata = {
66 'filename': filename,
67 'size': '', # filled by save_file
68 'user_uploaded': {'username': self._rhodecode_user.username,
69 'user_id': self._rhodecode_user.user_id,
70 'ip': self._rhodecode_user.ip_addr}}
71 try:
72 store_fid = self.storage.save_file(file_obj.file, filename,
73 metadata=metadata)
74 except FileNotAllowedException:
75 return {'store_fid': None,
76 'access_path': None,
77 'error': 'File {} is not allowed.'.format(filename)}
78
79 except FileOverSizeException:
80 return {'store_fid': None,
81 'access_path': None,
82 'error': 'File {} is exceeding allowed limit.'.format(filename)}
83
84 return {'store_fid': store_fid,
85 'access_path': h.route_path('download_file', fid=store_fid)}
86
87 @view_config(route_name='download_file')
88 def download_file(self):
89 self.load_default_context()
90 file_uid = self.request.matchdict['fid']
91 log.debug('Requesting FID:%s from store %s', file_uid, self.storage)
92 if not self.storage.exists(file_uid):
93 log.debug('File with FID:%s not found in the store', file_uid)
94 raise HTTPNotFound()
95
96 file_path = self.storage.store_path(file_uid)
97 return FileResponse(file_path)
@@ -1,718 +1,725 b''
1
1
2
2
3 ################################################################################
3 ################################################################################
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 ################################################################################
5 ################################################################################
6
6
7 [DEFAULT]
7 [DEFAULT]
8 ## Debug flag sets all loggers to debug, and enables request tracking
8 ## Debug flag sets all loggers to debug, and enables request tracking
9 debug = true
9 debug = true
10
10
11 ################################################################################
11 ################################################################################
12 ## EMAIL CONFIGURATION ##
12 ## EMAIL CONFIGURATION ##
13 ## Uncomment and replace with the email address which should receive ##
13 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
14 ## any error reports after an application crash ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
16 ################################################################################
16 ################################################################################
17
17
18 ## prefix all emails subjects with given prefix, helps filtering out emails
18 ## prefix all emails subjects with given prefix, helps filtering out emails
19 #email_prefix = [RhodeCode]
19 #email_prefix = [RhodeCode]
20
20
21 ## email FROM address all mails will be sent
21 ## email FROM address all mails will be sent
22 #app_email_from = rhodecode-noreply@localhost
22 #app_email_from = rhodecode-noreply@localhost
23
23
24 #smtp_server = mail.server.com
24 #smtp_server = mail.server.com
25 #smtp_username =
25 #smtp_username =
26 #smtp_password =
26 #smtp_password =
27 #smtp_port =
27 #smtp_port =
28 #smtp_use_tls = false
28 #smtp_use_tls = false
29 #smtp_use_ssl = true
29 #smtp_use_ssl = true
30
30
31 [server:main]
31 [server:main]
32 ## COMMON ##
32 ## COMMON ##
33 host = 127.0.0.1
33 host = 127.0.0.1
34 port = 5000
34 port = 5000
35
35
36 ###########################################################
36 ###########################################################
37 ## WAITRESS WSGI SERVER - Recommended for Development ####
37 ## WAITRESS WSGI SERVER - Recommended for Development ####
38 ###########################################################
38 ###########################################################
39
39
40 use = egg:waitress#main
40 use = egg:waitress#main
41 ## number of worker threads
41 ## number of worker threads
42 threads = 5
42 threads = 5
43 ## MAX BODY SIZE 100GB
43 ## MAX BODY SIZE 100GB
44 max_request_body_size = 107374182400
44 max_request_body_size = 107374182400
45 ## Use poll instead of select, fixes file descriptors limits problems.
45 ## Use poll instead of select, fixes file descriptors limits problems.
46 ## May not work on old windows systems.
46 ## May not work on old windows systems.
47 asyncore_use_poll = true
47 asyncore_use_poll = true
48
48
49
49
50 ##########################
50 ##########################
51 ## GUNICORN WSGI SERVER ##
51 ## GUNICORN WSGI SERVER ##
52 ##########################
52 ##########################
53 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
53 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
54
54
55 #use = egg:gunicorn#main
55 #use = egg:gunicorn#main
56 ## Sets the number of process workers. More workers means more concurent connections
56 ## Sets the number of process workers. More workers means more concurent connections
57 ## RhodeCode can handle at the same time. Each additional worker also it increases
57 ## RhodeCode can handle at the same time. Each additional worker also it increases
58 ## memory usage as each has it's own set of caches.
58 ## memory usage as each has it's own set of caches.
59 ## Recommended value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers, but no more
59 ## Recommended value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers, but no more
60 ## than 8-10 unless for really big deployments .e.g 700-1000 users.
60 ## than 8-10 unless for really big deployments .e.g 700-1000 users.
61 ## `instance_id = *` must be set in the [app:main] section below (which is the default)
61 ## `instance_id = *` must be set in the [app:main] section below (which is the default)
62 ## when using more than 1 worker.
62 ## when using more than 1 worker.
63 #workers = 2
63 #workers = 2
64 ## process name visible in process list
64 ## process name visible in process list
65 #proc_name = rhodecode
65 #proc_name = rhodecode
66 ## type of worker class, one of sync, gevent
66 ## type of worker class, one of sync, gevent
67 ## recommended for bigger setup is using of of other than sync one
67 ## recommended for bigger setup is using of of other than sync one
68 #worker_class = gevent
68 #worker_class = gevent
69 ## The maximum number of simultaneous clients. Valid only for Gevent
69 ## The maximum number of simultaneous clients. Valid only for Gevent
70 #worker_connections = 10
70 #worker_connections = 10
71 ## max number of requests that worker will handle before being gracefully
71 ## max number of requests that worker will handle before being gracefully
72 ## restarted, could prevent memory leaks
72 ## restarted, could prevent memory leaks
73 #max_requests = 1000
73 #max_requests = 1000
74 #max_requests_jitter = 30
74 #max_requests_jitter = 30
75 ## amount of time a worker can spend with handling a request before it
75 ## amount of time a worker can spend with handling a request before it
76 ## gets killed and restarted. Set to 6hrs
76 ## gets killed and restarted. Set to 6hrs
77 #timeout = 21600
77 #timeout = 21600
78
78
79
79
80 ## prefix middleware for RhodeCode.
80 ## prefix middleware for RhodeCode.
81 ## recommended when using proxy setup.
81 ## recommended when using proxy setup.
82 ## allows to set RhodeCode under a prefix in server.
82 ## allows to set RhodeCode under a prefix in server.
83 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
83 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
84 ## And set your prefix like: `prefix = /custom_prefix`
84 ## And set your prefix like: `prefix = /custom_prefix`
85 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
85 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
86 ## to make your cookies only work on prefix url
86 ## to make your cookies only work on prefix url
87 [filter:proxy-prefix]
87 [filter:proxy-prefix]
88 use = egg:PasteDeploy#prefix
88 use = egg:PasteDeploy#prefix
89 prefix = /
89 prefix = /
90
90
91 [app:main]
91 [app:main]
92 ## The %(here)s variable will be replaced with the absolute path of parent directory
92 ## The %(here)s variable will be replaced with the absolute path of parent directory
93 ## of this file
93 ## of this file
94 ## In addition ENVIRONMENT variables usage is possible, e.g
94 ## In addition ENVIRONMENT variables usage is possible, e.g
95 ## sqlalchemy.db1.url = {ENV_RC_DB_URL}
95 ## sqlalchemy.db1.url = {ENV_RC_DB_URL}
96
96
97 use = egg:rhodecode-enterprise-ce
97 use = egg:rhodecode-enterprise-ce
98
98
99 ## enable proxy prefix middleware, defined above
99 ## enable proxy prefix middleware, defined above
100 #filter-with = proxy-prefix
100 #filter-with = proxy-prefix
101
101
102 # During development the we want to have the debug toolbar enabled
102 # During development the we want to have the debug toolbar enabled
103 pyramid.includes =
103 pyramid.includes =
104 pyramid_debugtoolbar
104 pyramid_debugtoolbar
105 rhodecode.lib.middleware.request_wrapper
105 rhodecode.lib.middleware.request_wrapper
106
106
107 pyramid.reload_templates = true
107 pyramid.reload_templates = true
108
108
109 debugtoolbar.hosts = 0.0.0.0/0
109 debugtoolbar.hosts = 0.0.0.0/0
110 debugtoolbar.exclude_prefixes =
110 debugtoolbar.exclude_prefixes =
111 /css
111 /css
112 /fonts
112 /fonts
113 /images
113 /images
114 /js
114 /js
115
115
116 ## RHODECODE PLUGINS ##
116 ## RHODECODE PLUGINS ##
117 rhodecode.includes =
117 rhodecode.includes =
118 rhodecode.api
118 rhodecode.api
119
119
120
120
121 # api prefix url
121 # api prefix url
122 rhodecode.api.url = /_admin/api
122 rhodecode.api.url = /_admin/api
123
123
124
124
125 ## END RHODECODE PLUGINS ##
125 ## END RHODECODE PLUGINS ##
126
126
127 ## encryption key used to encrypt social plugin tokens,
127 ## encryption key used to encrypt social plugin tokens,
128 ## remote_urls with credentials etc, if not set it defaults to
128 ## remote_urls with credentials etc, if not set it defaults to
129 ## `beaker.session.secret`
129 ## `beaker.session.secret`
130 #rhodecode.encrypted_values.secret =
130 #rhodecode.encrypted_values.secret =
131
131
132 ## decryption strict mode (enabled by default). It controls if decryption raises
132 ## decryption strict mode (enabled by default). It controls if decryption raises
133 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
133 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
134 #rhodecode.encrypted_values.strict = false
134 #rhodecode.encrypted_values.strict = false
135
135
136 ## return gzipped responses from Rhodecode (static files/application)
136 ## return gzipped responses from Rhodecode (static files/application)
137 gzip_responses = false
137 gzip_responses = false
138
138
139 ## autogenerate javascript routes file on startup
139 ## autogenerate javascript routes file on startup
140 generate_js_files = false
140 generate_js_files = false
141
141
142 ## System global default language.
142 ## System global default language.
143 ## All available languages: en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
143 ## All available languages: en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
144 lang = en
144 lang = en
145
145
146 ## Perform a full repository scan and import on each server start.
146 ## Perform a full repository scan and import on each server start.
147 ## Settings this to true could lead to very long startup time.
147 ## Settings this to true could lead to very long startup time.
148 startup.import_repos = false
148 startup.import_repos = false
149
149
150 ## Uncomment and set this path to use archive download cache.
150 ## Uncomment and set this path to use archive download cache.
151 ## Once enabled, generated archives will be cached at this location
151 ## Once enabled, generated archives will be cached at this location
152 ## and served from the cache during subsequent requests for the same archive of
152 ## and served from the cache during subsequent requests for the same archive of
153 ## the repository.
153 ## the repository.
154 #archive_cache_dir = /tmp/tarballcache
154 #archive_cache_dir = /tmp/tarballcache
155
155
156 ## URL at which the application is running. This is used for bootstraping
156 ## URL at which the application is running. This is used for bootstraping
157 ## requests in context when no web request is available. Used in ishell, or
157 ## requests in context when no web request is available. Used in ishell, or
158 ## SSH calls. Set this for events to receive proper url for SSH calls.
158 ## SSH calls. Set this for events to receive proper url for SSH calls.
159 app.base_url = http://rhodecode.local
159 app.base_url = http://rhodecode.local
160
160
161 ## Unique application ID. Should be a random unique string for security.
161 ## Unique application ID. Should be a random unique string for security.
162 app_instance_uuid = rc-production
162 app_instance_uuid = rc-production
163
163
164 ## Cut off limit for large diffs (size in bytes). If overall diff size on
164 ## Cut off limit for large diffs (size in bytes). If overall diff size on
165 ## commit, or pull request exceeds this limit this diff will be displayed
165 ## commit, or pull request exceeds this limit this diff will be displayed
166 ## partially. E.g 512000 == 512Kb
166 ## partially. E.g 512000 == 512Kb
167 cut_off_limit_diff = 512000
167 cut_off_limit_diff = 512000
168
168
169 ## Cut off limit for large files inside diffs (size in bytes). Each individual
169 ## Cut off limit for large files inside diffs (size in bytes). Each individual
170 ## file inside diff which exceeds this limit will be displayed partially.
170 ## file inside diff which exceeds this limit will be displayed partially.
171 ## E.g 128000 == 128Kb
171 ## E.g 128000 == 128Kb
172 cut_off_limit_file = 128000
172 cut_off_limit_file = 128000
173
173
174 ## use cached version of vcs repositories everywhere. Recommended to be `true`
174 ## use cached version of vcs repositories everywhere. Recommended to be `true`
175 vcs_full_cache = true
175 vcs_full_cache = true
176
176
177 ## Force https in RhodeCode, fixes https redirects, assumes it's always https.
177 ## Force https in RhodeCode, fixes https redirects, assumes it's always https.
178 ## Normally this is controlled by proper http flags sent from http server
178 ## Normally this is controlled by proper http flags sent from http server
179 force_https = false
179 force_https = false
180
180
181 ## use Strict-Transport-Security headers
181 ## use Strict-Transport-Security headers
182 use_htsts = false
182 use_htsts = false
183
183
184 ## git rev filter option, --all is the default filter, if you need to
184 ## git rev filter option, --all is the default filter, if you need to
185 ## hide all refs in changelog switch this to --branches --tags
185 ## hide all refs in changelog switch this to --branches --tags
186 git_rev_filter = --branches --tags
186 git_rev_filter = --branches --tags
187
187
188 # Set to true if your repos are exposed using the dumb protocol
188 # Set to true if your repos are exposed using the dumb protocol
189 git_update_server_info = false
189 git_update_server_info = false
190
190
191 ## RSS/ATOM feed options
191 ## RSS/ATOM feed options
192 rss_cut_off_limit = 256000
192 rss_cut_off_limit = 256000
193 rss_items_per_page = 10
193 rss_items_per_page = 10
194 rss_include_diff = false
194 rss_include_diff = false
195
195
196 ## gist URL alias, used to create nicer urls for gist. This should be an
196 ## gist URL alias, used to create nicer urls for gist. This should be an
197 ## url that does rewrites to _admin/gists/{gistid}.
197 ## url that does rewrites to _admin/gists/{gistid}.
198 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
198 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
199 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
199 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
200 gist_alias_url =
200 gist_alias_url =
201
201
202 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
202 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
203 ## used for access.
203 ## used for access.
204 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
204 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
205 ## came from the the logged in user who own this authentication token.
205 ## came from the the logged in user who own this authentication token.
206 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
206 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
207 ## authentication token. Such view would be only accessible when used together
207 ## authentication token. Such view would be only accessible when used together
208 ## with this authentication token
208 ## with this authentication token
209 ##
209 ##
210 ## list of all views can be found under `/_admin/permissions/auth_token_access`
210 ## list of all views can be found under `/_admin/permissions/auth_token_access`
211 ## The list should be "," separated and on a single line.
211 ## The list should be "," separated and on a single line.
212 ##
212 ##
213 ## Most common views to enable:
213 ## Most common views to enable:
214 # RepoCommitsView:repo_commit_download
214 # RepoCommitsView:repo_commit_download
215 # RepoCommitsView:repo_commit_patch
215 # RepoCommitsView:repo_commit_patch
216 # RepoCommitsView:repo_commit_raw
216 # RepoCommitsView:repo_commit_raw
217 # RepoCommitsView:repo_commit_raw@TOKEN
217 # RepoCommitsView:repo_commit_raw@TOKEN
218 # RepoFilesView:repo_files_diff
218 # RepoFilesView:repo_files_diff
219 # RepoFilesView:repo_archivefile
219 # RepoFilesView:repo_archivefile
220 # RepoFilesView:repo_file_raw
220 # RepoFilesView:repo_file_raw
221 # GistView:*
221 # GistView:*
222 api_access_controllers_whitelist =
222 api_access_controllers_whitelist =
223
223
224 ## Default encoding used to convert from and to unicode
224 ## Default encoding used to convert from and to unicode
225 ## can be also a comma separated list of encoding in case of mixed encodings
225 ## can be also a comma separated list of encoding in case of mixed encodings
226 default_encoding = UTF-8
226 default_encoding = UTF-8
227
227
228 ## instance-id prefix
228 ## instance-id prefix
229 ## a prefix key for this instance used for cache invalidation when running
229 ## a prefix key for this instance used for cache invalidation when running
230 ## multiple instances of rhodecode, make sure it's globally unique for
230 ## multiple instances of rhodecode, make sure it's globally unique for
231 ## all running rhodecode instances. Leave empty if you don't use it
231 ## all running rhodecode instances. Leave empty if you don't use it
232 instance_id =
232 instance_id =
233
233
234 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
234 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
235 ## of an authentication plugin also if it is disabled by it's settings.
235 ## of an authentication plugin also if it is disabled by it's settings.
236 ## This could be useful if you are unable to log in to the system due to broken
236 ## This could be useful if you are unable to log in to the system due to broken
237 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
237 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
238 ## module to log in again and fix the settings.
238 ## module to log in again and fix the settings.
239 ##
239 ##
240 ## Available builtin plugin IDs (hash is part of the ID):
240 ## Available builtin plugin IDs (hash is part of the ID):
241 ## egg:rhodecode-enterprise-ce#rhodecode
241 ## egg:rhodecode-enterprise-ce#rhodecode
242 ## egg:rhodecode-enterprise-ce#pam
242 ## egg:rhodecode-enterprise-ce#pam
243 ## egg:rhodecode-enterprise-ce#ldap
243 ## egg:rhodecode-enterprise-ce#ldap
244 ## egg:rhodecode-enterprise-ce#jasig_cas
244 ## egg:rhodecode-enterprise-ce#jasig_cas
245 ## egg:rhodecode-enterprise-ce#headers
245 ## egg:rhodecode-enterprise-ce#headers
246 ## egg:rhodecode-enterprise-ce#crowd
246 ## egg:rhodecode-enterprise-ce#crowd
247 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
247 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
248
248
249 ## alternative return HTTP header for failed authentication. Default HTTP
249 ## alternative return HTTP header for failed authentication. Default HTTP
250 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
250 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
251 ## handling that causing a series of failed authentication calls.
251 ## handling that causing a series of failed authentication calls.
252 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
252 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
253 ## This will be served instead of default 401 on bad authnetication
253 ## This will be served instead of default 401 on bad authnetication
254 auth_ret_code =
254 auth_ret_code =
255
255
256 ## use special detection method when serving auth_ret_code, instead of serving
256 ## use special detection method when serving auth_ret_code, instead of serving
257 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
257 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
258 ## and then serve auth_ret_code to clients
258 ## and then serve auth_ret_code to clients
259 auth_ret_code_detection = false
259 auth_ret_code_detection = false
260
260
261 ## locking return code. When repository is locked return this HTTP code. 2XX
261 ## locking return code. When repository is locked return this HTTP code. 2XX
262 ## codes don't break the transactions while 4XX codes do
262 ## codes don't break the transactions while 4XX codes do
263 lock_ret_code = 423
263 lock_ret_code = 423
264
264
265 ## allows to change the repository location in settings page
265 ## allows to change the repository location in settings page
266 allow_repo_location_change = true
266 allow_repo_location_change = true
267
267
268 ## allows to setup custom hooks in settings page
268 ## allows to setup custom hooks in settings page
269 allow_custom_hooks_settings = true
269 allow_custom_hooks_settings = true
270
270
271 ## Generated license token required for EE edition license.
271 ## Generated license token required for EE edition license.
272 ## New generated token value can be found in Admin > settings > license page.
272 ## New generated token value can be found in Admin > settings > license page.
273 license_token =
273 license_token =
274
274
275 ## supervisor connection uri, for managing supervisor and logs.
275 ## supervisor connection uri, for managing supervisor and logs.
276 supervisor.uri =
276 supervisor.uri =
277 ## supervisord group name/id we only want this RC instance to handle
277 ## supervisord group name/id we only want this RC instance to handle
278 supervisor.group_id = dev
278 supervisor.group_id = dev
279
279
280 ## Display extended labs settings
280 ## Display extended labs settings
281 labs_settings_active = true
281 labs_settings_active = true
282
282
283 ## Custom exception store path, defaults to TMPDIR
283 ## Custom exception store path, defaults to TMPDIR
284 ## This is used to store exception from RhodeCode in shared directory
284 ## This is used to store exception from RhodeCode in shared directory
285 #exception_tracker.store_path =
285 #exception_tracker.store_path =
286
286
287 ## File store configuration. This is used to store and serve uploaded files
288 file_store.enabled = true
289 ## backend, only available one is local
290 file_store.backend = local
291 ## path to store the uploaded binaries
292 file_store.storage_path = %(here)s/data/file_store
293
287
294
288 ####################################
295 ####################################
289 ### CELERY CONFIG ####
296 ### CELERY CONFIG ####
290 ####################################
297 ####################################
291 ## run: /path/to/celery worker \
298 ## run: /path/to/celery worker \
292 ## -E --beat --app rhodecode.lib.celerylib.loader \
299 ## -E --beat --app rhodecode.lib.celerylib.loader \
293 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
300 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
294 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
301 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
295
302
296 use_celery = false
303 use_celery = false
297
304
298 ## connection url to the message broker (default rabbitmq)
305 ## connection url to the message broker (default rabbitmq)
299 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
306 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
300
307
301 ## maximum tasks to execute before worker restart
308 ## maximum tasks to execute before worker restart
302 celery.max_tasks_per_child = 100
309 celery.max_tasks_per_child = 100
303
310
304 ## tasks will never be sent to the queue, but executed locally instead.
311 ## tasks will never be sent to the queue, but executed locally instead.
305 celery.task_always_eager = false
312 celery.task_always_eager = false
306
313
307 #####################################
314 #####################################
308 ### DOGPILE CACHE ####
315 ### DOGPILE CACHE ####
309 #####################################
316 #####################################
310 ## Default cache dir for caches. Putting this into a ramdisk
317 ## Default cache dir for caches. Putting this into a ramdisk
311 ## can boost performance, eg. /tmpfs/data_ramdisk, however this directory might require
318 ## can boost performance, eg. /tmpfs/data_ramdisk, however this directory might require
312 ## large amount of space
319 ## large amount of space
313 cache_dir = %(here)s/data
320 cache_dir = %(here)s/data
314
321
315 ## `cache_perms` cache settings for permission tree, auth TTL.
322 ## `cache_perms` cache settings for permission tree, auth TTL.
316 rc_cache.cache_perms.backend = dogpile.cache.rc.file_namespace
323 rc_cache.cache_perms.backend = dogpile.cache.rc.file_namespace
317 rc_cache.cache_perms.expiration_time = 300
324 rc_cache.cache_perms.expiration_time = 300
318
325
319 ## alternative `cache_perms` redis backend with distributed lock
326 ## alternative `cache_perms` redis backend with distributed lock
320 #rc_cache.cache_perms.backend = dogpile.cache.rc.redis
327 #rc_cache.cache_perms.backend = dogpile.cache.rc.redis
321 #rc_cache.cache_perms.expiration_time = 300
328 #rc_cache.cache_perms.expiration_time = 300
322 ## redis_expiration_time needs to be greater then expiration_time
329 ## redis_expiration_time needs to be greater then expiration_time
323 #rc_cache.cache_perms.arguments.redis_expiration_time = 7200
330 #rc_cache.cache_perms.arguments.redis_expiration_time = 7200
324 #rc_cache.cache_perms.arguments.socket_timeout = 30
331 #rc_cache.cache_perms.arguments.socket_timeout = 30
325 #rc_cache.cache_perms.arguments.host = localhost
332 #rc_cache.cache_perms.arguments.host = localhost
326 #rc_cache.cache_perms.arguments.port = 6379
333 #rc_cache.cache_perms.arguments.port = 6379
327 #rc_cache.cache_perms.arguments.db = 0
334 #rc_cache.cache_perms.arguments.db = 0
328 #rc_cache.cache_perms.arguments.distributed_lock = true
335 #rc_cache.cache_perms.arguments.distributed_lock = true
329
336
330 ## `cache_repo` cache settings for FileTree, Readme, RSS FEEDS
337 ## `cache_repo` cache settings for FileTree, Readme, RSS FEEDS
331 rc_cache.cache_repo.backend = dogpile.cache.rc.file_namespace
338 rc_cache.cache_repo.backend = dogpile.cache.rc.file_namespace
332 rc_cache.cache_repo.expiration_time = 2592000
339 rc_cache.cache_repo.expiration_time = 2592000
333
340
334 ## alternative `cache_repo` redis backend with distributed lock
341 ## alternative `cache_repo` redis backend with distributed lock
335 #rc_cache.cache_repo.backend = dogpile.cache.rc.redis
342 #rc_cache.cache_repo.backend = dogpile.cache.rc.redis
336 #rc_cache.cache_repo.expiration_time = 2592000
343 #rc_cache.cache_repo.expiration_time = 2592000
337 ## redis_expiration_time needs to be greater then expiration_time
344 ## redis_expiration_time needs to be greater then expiration_time
338 #rc_cache.cache_repo.arguments.redis_expiration_time = 2678400
345 #rc_cache.cache_repo.arguments.redis_expiration_time = 2678400
339 #rc_cache.cache_repo.arguments.socket_timeout = 30
346 #rc_cache.cache_repo.arguments.socket_timeout = 30
340 #rc_cache.cache_repo.arguments.host = localhost
347 #rc_cache.cache_repo.arguments.host = localhost
341 #rc_cache.cache_repo.arguments.port = 6379
348 #rc_cache.cache_repo.arguments.port = 6379
342 #rc_cache.cache_repo.arguments.db = 1
349 #rc_cache.cache_repo.arguments.db = 1
343 #rc_cache.cache_repo.arguments.distributed_lock = true
350 #rc_cache.cache_repo.arguments.distributed_lock = true
344
351
345 ## cache settings for SQL queries, this needs to use memory type backend
352 ## cache settings for SQL queries, this needs to use memory type backend
346 rc_cache.sql_cache_short.backend = dogpile.cache.rc.memory_lru
353 rc_cache.sql_cache_short.backend = dogpile.cache.rc.memory_lru
347 rc_cache.sql_cache_short.expiration_time = 30
354 rc_cache.sql_cache_short.expiration_time = 30
348
355
349 ## `cache_repo_longterm` cache for repo object instances, this needs to use memory
356 ## `cache_repo_longterm` cache for repo object instances, this needs to use memory
350 ## type backend as the objects kept are not pickle serializable
357 ## type backend as the objects kept are not pickle serializable
351 rc_cache.cache_repo_longterm.backend = dogpile.cache.rc.memory_lru
358 rc_cache.cache_repo_longterm.backend = dogpile.cache.rc.memory_lru
352 ## by default we use 96H, this is using invalidation on push anyway
359 ## by default we use 96H, this is using invalidation on push anyway
353 rc_cache.cache_repo_longterm.expiration_time = 345600
360 rc_cache.cache_repo_longterm.expiration_time = 345600
354 ## max items in LRU cache, reduce this number to save memory, and expire last used
361 ## max items in LRU cache, reduce this number to save memory, and expire last used
355 ## cached objects
362 ## cached objects
356 rc_cache.cache_repo_longterm.max_size = 10000
363 rc_cache.cache_repo_longterm.max_size = 10000
357
364
358
365
359 ####################################
366 ####################################
360 ### BEAKER SESSION ####
367 ### BEAKER SESSION ####
361 ####################################
368 ####################################
362
369
363 ## .session.type is type of storage options for the session, current allowed
370 ## .session.type is type of storage options for the session, current allowed
364 ## types are file, ext:memcached, ext:redis, ext:database, and memory (default).
371 ## types are file, ext:memcached, ext:redis, ext:database, and memory (default).
365 beaker.session.type = file
372 beaker.session.type = file
366 beaker.session.data_dir = %(here)s/data/sessions
373 beaker.session.data_dir = %(here)s/data/sessions
367
374
368 ## db based session, fast, and allows easy management over logged in users
375 ## db based session, fast, and allows easy management over logged in users
369 #beaker.session.type = ext:database
376 #beaker.session.type = ext:database
370 #beaker.session.table_name = db_session
377 #beaker.session.table_name = db_session
371 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
378 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
372 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
379 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
373 #beaker.session.sa.pool_recycle = 3600
380 #beaker.session.sa.pool_recycle = 3600
374 #beaker.session.sa.echo = false
381 #beaker.session.sa.echo = false
375
382
376 beaker.session.key = rhodecode
383 beaker.session.key = rhodecode
377 beaker.session.secret = develop-rc-uytcxaz
384 beaker.session.secret = develop-rc-uytcxaz
378 beaker.session.lock_dir = %(here)s/data/sessions/lock
385 beaker.session.lock_dir = %(here)s/data/sessions/lock
379
386
380 ## Secure encrypted cookie. Requires AES and AES python libraries
387 ## Secure encrypted cookie. Requires AES and AES python libraries
381 ## you must disable beaker.session.secret to use this
388 ## you must disable beaker.session.secret to use this
382 #beaker.session.encrypt_key = key_for_encryption
389 #beaker.session.encrypt_key = key_for_encryption
383 #beaker.session.validate_key = validation_key
390 #beaker.session.validate_key = validation_key
384
391
385 ## sets session as invalid(also logging out user) if it haven not been
392 ## sets session as invalid(also logging out user) if it haven not been
386 ## accessed for given amount of time in seconds
393 ## accessed for given amount of time in seconds
387 beaker.session.timeout = 2592000
394 beaker.session.timeout = 2592000
388 beaker.session.httponly = true
395 beaker.session.httponly = true
389 ## Path to use for the cookie. Set to prefix if you use prefix middleware
396 ## Path to use for the cookie. Set to prefix if you use prefix middleware
390 #beaker.session.cookie_path = /custom_prefix
397 #beaker.session.cookie_path = /custom_prefix
391
398
392 ## uncomment for https secure cookie
399 ## uncomment for https secure cookie
393 beaker.session.secure = false
400 beaker.session.secure = false
394
401
395 ## auto save the session to not to use .save()
402 ## auto save the session to not to use .save()
396 beaker.session.auto = false
403 beaker.session.auto = false
397
404
398 ## default cookie expiration time in seconds, set to `true` to set expire
405 ## default cookie expiration time in seconds, set to `true` to set expire
399 ## at browser close
406 ## at browser close
400 #beaker.session.cookie_expires = 3600
407 #beaker.session.cookie_expires = 3600
401
408
402 ###################################
409 ###################################
403 ## SEARCH INDEXING CONFIGURATION ##
410 ## SEARCH INDEXING CONFIGURATION ##
404 ###################################
411 ###################################
405 ## Full text search indexer is available in rhodecode-tools under
412 ## Full text search indexer is available in rhodecode-tools under
406 ## `rhodecode-tools index` command
413 ## `rhodecode-tools index` command
407
414
408 ## WHOOSH Backend, doesn't require additional services to run
415 ## WHOOSH Backend, doesn't require additional services to run
409 ## it works good with few dozen repos
416 ## it works good with few dozen repos
410 search.module = rhodecode.lib.index.whoosh
417 search.module = rhodecode.lib.index.whoosh
411 search.location = %(here)s/data/index
418 search.location = %(here)s/data/index
412
419
413 ########################################
420 ########################################
414 ### CHANNELSTREAM CONFIG ####
421 ### CHANNELSTREAM CONFIG ####
415 ########################################
422 ########################################
416 ## channelstream enables persistent connections and live notification
423 ## channelstream enables persistent connections and live notification
417 ## in the system. It's also used by the chat system
424 ## in the system. It's also used by the chat system
418
425
419 channelstream.enabled = false
426 channelstream.enabled = false
420
427
421 ## server address for channelstream server on the backend
428 ## server address for channelstream server on the backend
422 channelstream.server = 127.0.0.1:9800
429 channelstream.server = 127.0.0.1:9800
423
430
424 ## location of the channelstream server from outside world
431 ## location of the channelstream server from outside world
425 ## use ws:// for http or wss:// for https. This address needs to be handled
432 ## use ws:// for http or wss:// for https. This address needs to be handled
426 ## by external HTTP server such as Nginx or Apache
433 ## by external HTTP server such as Nginx or Apache
427 ## see nginx/apache configuration examples in our docs
434 ## see nginx/apache configuration examples in our docs
428 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
435 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
429 channelstream.secret = secret
436 channelstream.secret = secret
430 channelstream.history.location = %(here)s/channelstream_history
437 channelstream.history.location = %(here)s/channelstream_history
431
438
432 ## Internal application path that Javascript uses to connect into.
439 ## Internal application path that Javascript uses to connect into.
433 ## If you use proxy-prefix the prefix should be added before /_channelstream
440 ## If you use proxy-prefix the prefix should be added before /_channelstream
434 channelstream.proxy_path = /_channelstream
441 channelstream.proxy_path = /_channelstream
435
442
436
443
437 ###################################
444 ###################################
438 ## APPENLIGHT CONFIG ##
445 ## APPENLIGHT CONFIG ##
439 ###################################
446 ###################################
440
447
441 ## Appenlight is tailored to work with RhodeCode, see
448 ## Appenlight is tailored to work with RhodeCode, see
442 ## http://appenlight.com for details how to obtain an account
449 ## http://appenlight.com for details how to obtain an account
443
450
444 ## appenlight integration enabled
451 ## appenlight integration enabled
445 appenlight = false
452 appenlight = false
446
453
447 appenlight.server_url = https://api.appenlight.com
454 appenlight.server_url = https://api.appenlight.com
448 appenlight.api_key = YOUR_API_KEY
455 appenlight.api_key = YOUR_API_KEY
449 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
456 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
450
457
451 # used for JS client
458 # used for JS client
452 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
459 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
453
460
454 ## TWEAK AMOUNT OF INFO SENT HERE
461 ## TWEAK AMOUNT OF INFO SENT HERE
455
462
456 ## enables 404 error logging (default False)
463 ## enables 404 error logging (default False)
457 appenlight.report_404 = false
464 appenlight.report_404 = false
458
465
459 ## time in seconds after request is considered being slow (default 1)
466 ## time in seconds after request is considered being slow (default 1)
460 appenlight.slow_request_time = 1
467 appenlight.slow_request_time = 1
461
468
462 ## record slow requests in application
469 ## record slow requests in application
463 ## (needs to be enabled for slow datastore recording and time tracking)
470 ## (needs to be enabled for slow datastore recording and time tracking)
464 appenlight.slow_requests = true
471 appenlight.slow_requests = true
465
472
466 ## enable hooking to application loggers
473 ## enable hooking to application loggers
467 appenlight.logging = true
474 appenlight.logging = true
468
475
469 ## minimum log level for log capture
476 ## minimum log level for log capture
470 appenlight.logging.level = WARNING
477 appenlight.logging.level = WARNING
471
478
472 ## send logs only from erroneous/slow requests
479 ## send logs only from erroneous/slow requests
473 ## (saves API quota for intensive logging)
480 ## (saves API quota for intensive logging)
474 appenlight.logging_on_error = false
481 appenlight.logging_on_error = false
475
482
476 ## list of additonal keywords that should be grabbed from environ object
483 ## list of additonal keywords that should be grabbed from environ object
477 ## can be string with comma separated list of words in lowercase
484 ## can be string with comma separated list of words in lowercase
478 ## (by default client will always send following info:
485 ## (by default client will always send following info:
479 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
486 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
480 ## start with HTTP* this list be extended with additional keywords here
487 ## start with HTTP* this list be extended with additional keywords here
481 appenlight.environ_keys_whitelist =
488 appenlight.environ_keys_whitelist =
482
489
483 ## list of keywords that should be blanked from request object
490 ## list of keywords that should be blanked from request object
484 ## can be string with comma separated list of words in lowercase
491 ## can be string with comma separated list of words in lowercase
485 ## (by default client will always blank keys that contain following words
492 ## (by default client will always blank keys that contain following words
486 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
493 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
487 ## this list be extended with additional keywords set here
494 ## this list be extended with additional keywords set here
488 appenlight.request_keys_blacklist =
495 appenlight.request_keys_blacklist =
489
496
490 ## list of namespaces that should be ignores when gathering log entries
497 ## list of namespaces that should be ignores when gathering log entries
491 ## can be string with comma separated list of namespaces
498 ## can be string with comma separated list of namespaces
492 ## (by default the client ignores own entries: appenlight_client.client)
499 ## (by default the client ignores own entries: appenlight_client.client)
493 appenlight.log_namespace_blacklist =
500 appenlight.log_namespace_blacklist =
494
501
495 # enable debug style page
502 # enable debug style page
496 debug_style = true
503 debug_style = true
497
504
498 ###########################################
505 ###########################################
499 ### MAIN RHODECODE DATABASE CONFIG ###
506 ### MAIN RHODECODE DATABASE CONFIG ###
500 ###########################################
507 ###########################################
501 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
508 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
502 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
509 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
503 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode?charset=utf8
510 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode?charset=utf8
504 # pymysql is an alternative driver for MySQL, use in case of problems with default one
511 # pymysql is an alternative driver for MySQL, use in case of problems with default one
505 #sqlalchemy.db1.url = mysql+pymysql://root:qweqwe@localhost/rhodecode
512 #sqlalchemy.db1.url = mysql+pymysql://root:qweqwe@localhost/rhodecode
506
513
507 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
514 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
508
515
509 # see sqlalchemy docs for other advanced settings
516 # see sqlalchemy docs for other advanced settings
510
517
511 ## print the sql statements to output
518 ## print the sql statements to output
512 sqlalchemy.db1.echo = false
519 sqlalchemy.db1.echo = false
513 ## recycle the connections after this amount of seconds
520 ## recycle the connections after this amount of seconds
514 sqlalchemy.db1.pool_recycle = 3600
521 sqlalchemy.db1.pool_recycle = 3600
515 sqlalchemy.db1.convert_unicode = true
522 sqlalchemy.db1.convert_unicode = true
516
523
517 ## the number of connections to keep open inside the connection pool.
524 ## the number of connections to keep open inside the connection pool.
518 ## 0 indicates no limit
525 ## 0 indicates no limit
519 #sqlalchemy.db1.pool_size = 5
526 #sqlalchemy.db1.pool_size = 5
520
527
521 ## the number of connections to allow in connection pool "overflow", that is
528 ## the number of connections to allow in connection pool "overflow", that is
522 ## connections that can be opened above and beyond the pool_size setting,
529 ## connections that can be opened above and beyond the pool_size setting,
523 ## which defaults to five.
530 ## which defaults to five.
524 #sqlalchemy.db1.max_overflow = 10
531 #sqlalchemy.db1.max_overflow = 10
525
532
526 ## Connection check ping, used to detect broken database connections
533 ## Connection check ping, used to detect broken database connections
527 ## could be enabled to better handle cases if MySQL has gone away errors
534 ## could be enabled to better handle cases if MySQL has gone away errors
528 #sqlalchemy.db1.ping_connection = true
535 #sqlalchemy.db1.ping_connection = true
529
536
530 ##################
537 ##################
531 ### VCS CONFIG ###
538 ### VCS CONFIG ###
532 ##################
539 ##################
533 vcs.server.enable = true
540 vcs.server.enable = true
534 vcs.server = localhost:9900
541 vcs.server = localhost:9900
535
542
536 ## Web server connectivity protocol, responsible for web based VCS operatations
543 ## Web server connectivity protocol, responsible for web based VCS operatations
537 ## Available protocols are:
544 ## Available protocols are:
538 ## `http` - use http-rpc backend (default)
545 ## `http` - use http-rpc backend (default)
539 vcs.server.protocol = http
546 vcs.server.protocol = http
540
547
541 ## Push/Pull operations protocol, available options are:
548 ## Push/Pull operations protocol, available options are:
542 ## `http` - use http-rpc backend (default)
549 ## `http` - use http-rpc backend (default)
543 vcs.scm_app_implementation = http
550 vcs.scm_app_implementation = http
544
551
545 ## Push/Pull operations hooks protocol, available options are:
552 ## Push/Pull operations hooks protocol, available options are:
546 ## `http` - use http-rpc backend (default)
553 ## `http` - use http-rpc backend (default)
547 vcs.hooks.protocol = http
554 vcs.hooks.protocol = http
548
555
549 ## Host on which this instance is listening for hooks. If vcsserver is in other location
556 ## Host on which this instance is listening for hooks. If vcsserver is in other location
550 ## this should be adjusted.
557 ## this should be adjusted.
551 vcs.hooks.host = 127.0.0.1
558 vcs.hooks.host = 127.0.0.1
552
559
553 vcs.server.log_level = debug
560 vcs.server.log_level = debug
554 ## Start VCSServer with this instance as a subprocess, useful for development
561 ## Start VCSServer with this instance as a subprocess, useful for development
555 vcs.start_server = false
562 vcs.start_server = false
556
563
557 ## List of enabled VCS backends, available options are:
564 ## List of enabled VCS backends, available options are:
558 ## `hg` - mercurial
565 ## `hg` - mercurial
559 ## `git` - git
566 ## `git` - git
560 ## `svn` - subversion
567 ## `svn` - subversion
561 vcs.backends = hg, git, svn
568 vcs.backends = hg, git, svn
562
569
563 vcs.connection_timeout = 3600
570 vcs.connection_timeout = 3600
564 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
571 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
565 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
572 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
566 #vcs.svn.compatible_version = pre-1.8-compatible
573 #vcs.svn.compatible_version = pre-1.8-compatible
567
574
568
575
569 ############################################################
576 ############################################################
570 ### Subversion proxy support (mod_dav_svn) ###
577 ### Subversion proxy support (mod_dav_svn) ###
571 ### Maps RhodeCode repo groups into SVN paths for Apache ###
578 ### Maps RhodeCode repo groups into SVN paths for Apache ###
572 ############################################################
579 ############################################################
573 ## Enable or disable the config file generation.
580 ## Enable or disable the config file generation.
574 svn.proxy.generate_config = false
581 svn.proxy.generate_config = false
575 ## Generate config file with `SVNListParentPath` set to `On`.
582 ## Generate config file with `SVNListParentPath` set to `On`.
576 svn.proxy.list_parent_path = true
583 svn.proxy.list_parent_path = true
577 ## Set location and file name of generated config file.
584 ## Set location and file name of generated config file.
578 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
585 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
579 ## alternative mod_dav config template. This needs to be a mako template
586 ## alternative mod_dav config template. This needs to be a mako template
580 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
587 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
581 ## Used as a prefix to the `Location` block in the generated config file.
588 ## Used as a prefix to the `Location` block in the generated config file.
582 ## In most cases it should be set to `/`.
589 ## In most cases it should be set to `/`.
583 svn.proxy.location_root = /
590 svn.proxy.location_root = /
584 ## Command to reload the mod dav svn configuration on change.
591 ## Command to reload the mod dav svn configuration on change.
585 ## Example: `/etc/init.d/apache2 reload`
592 ## Example: `/etc/init.d/apache2 reload`
586 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
593 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
587 ## If the timeout expires before the reload command finishes, the command will
594 ## If the timeout expires before the reload command finishes, the command will
588 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
595 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
589 #svn.proxy.reload_timeout = 10
596 #svn.proxy.reload_timeout = 10
590
597
591 ############################################################
598 ############################################################
592 ### SSH Support Settings ###
599 ### SSH Support Settings ###
593 ############################################################
600 ############################################################
594
601
595 ## Defines if a custom authorized_keys file should be created and written on
602 ## Defines if a custom authorized_keys file should be created and written on
596 ## any change user ssh keys. Setting this to false also disables posibility
603 ## any change user ssh keys. Setting this to false also disables posibility
597 ## of adding SSH keys by users from web interface. Super admins can still
604 ## of adding SSH keys by users from web interface. Super admins can still
598 ## manage SSH Keys.
605 ## manage SSH Keys.
599 ssh.generate_authorized_keyfile = false
606 ssh.generate_authorized_keyfile = false
600
607
601 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
608 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
602 # ssh.authorized_keys_ssh_opts =
609 # ssh.authorized_keys_ssh_opts =
603
610
604 ## Path to the authrozied_keys file where the generate entries are placed.
611 ## Path to the authrozied_keys file where the generate entries are placed.
605 ## It is possible to have multiple key files specified in `sshd_config` e.g.
612 ## It is possible to have multiple key files specified in `sshd_config` e.g.
606 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
613 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
607 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
614 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
608
615
609 ## Command to execute the SSH wrapper. The binary is available in the
616 ## Command to execute the SSH wrapper. The binary is available in the
610 ## rhodecode installation directory.
617 ## rhodecode installation directory.
611 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
618 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
612 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
619 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
613
620
614 ## Allow shell when executing the ssh-wrapper command
621 ## Allow shell when executing the ssh-wrapper command
615 ssh.wrapper_cmd_allow_shell = false
622 ssh.wrapper_cmd_allow_shell = false
616
623
617 ## Enables logging, and detailed output send back to the client during SSH
624 ## Enables logging, and detailed output send back to the client during SSH
618 ## operations. Usefull for debugging, shouldn't be used in production.
625 ## operations. Usefull for debugging, shouldn't be used in production.
619 ssh.enable_debug_logging = true
626 ssh.enable_debug_logging = true
620
627
621 ## Paths to binary executable, by default they are the names, but we can
628 ## Paths to binary executable, by default they are the names, but we can
622 ## override them if we want to use a custom one
629 ## override them if we want to use a custom one
623 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
630 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
624 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
631 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
625 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
632 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
626
633
627
634
628 ## Dummy marker to add new entries after.
635 ## Dummy marker to add new entries after.
629 ## Add any custom entries below. Please don't remove.
636 ## Add any custom entries below. Please don't remove.
630 custom.conf = 1
637 custom.conf = 1
631
638
632
639
633 ################################
640 ################################
634 ### LOGGING CONFIGURATION ####
641 ### LOGGING CONFIGURATION ####
635 ################################
642 ################################
636 [loggers]
643 [loggers]
637 keys = root, sqlalchemy, beaker, celery, rhodecode, ssh_wrapper
644 keys = root, sqlalchemy, beaker, celery, rhodecode, ssh_wrapper
638
645
639 [handlers]
646 [handlers]
640 keys = console, console_sql
647 keys = console, console_sql
641
648
642 [formatters]
649 [formatters]
643 keys = generic, color_formatter, color_formatter_sql
650 keys = generic, color_formatter, color_formatter_sql
644
651
645 #############
652 #############
646 ## LOGGERS ##
653 ## LOGGERS ##
647 #############
654 #############
648 [logger_root]
655 [logger_root]
649 level = NOTSET
656 level = NOTSET
650 handlers = console
657 handlers = console
651
658
652 [logger_sqlalchemy]
659 [logger_sqlalchemy]
653 level = INFO
660 level = INFO
654 handlers = console_sql
661 handlers = console_sql
655 qualname = sqlalchemy.engine
662 qualname = sqlalchemy.engine
656 propagate = 0
663 propagate = 0
657
664
658 [logger_beaker]
665 [logger_beaker]
659 level = DEBUG
666 level = DEBUG
660 handlers =
667 handlers =
661 qualname = beaker.container
668 qualname = beaker.container
662 propagate = 1
669 propagate = 1
663
670
664 [logger_rhodecode]
671 [logger_rhodecode]
665 level = DEBUG
672 level = DEBUG
666 handlers =
673 handlers =
667 qualname = rhodecode
674 qualname = rhodecode
668 propagate = 1
675 propagate = 1
669
676
670 [logger_ssh_wrapper]
677 [logger_ssh_wrapper]
671 level = DEBUG
678 level = DEBUG
672 handlers =
679 handlers =
673 qualname = ssh_wrapper
680 qualname = ssh_wrapper
674 propagate = 1
681 propagate = 1
675
682
676 [logger_celery]
683 [logger_celery]
677 level = DEBUG
684 level = DEBUG
678 handlers =
685 handlers =
679 qualname = celery
686 qualname = celery
680
687
681
688
682 ##############
689 ##############
683 ## HANDLERS ##
690 ## HANDLERS ##
684 ##############
691 ##############
685
692
686 [handler_console]
693 [handler_console]
687 class = StreamHandler
694 class = StreamHandler
688 args = (sys.stderr, )
695 args = (sys.stderr, )
689 level = DEBUG
696 level = DEBUG
690 formatter = color_formatter
697 formatter = color_formatter
691
698
692 [handler_console_sql]
699 [handler_console_sql]
693 # "level = DEBUG" logs SQL queries and results.
700 # "level = DEBUG" logs SQL queries and results.
694 # "level = INFO" logs SQL queries.
701 # "level = INFO" logs SQL queries.
695 # "level = WARN" logs neither. (Recommended for production systems.)
702 # "level = WARN" logs neither. (Recommended for production systems.)
696 class = StreamHandler
703 class = StreamHandler
697 args = (sys.stderr, )
704 args = (sys.stderr, )
698 level = WARN
705 level = WARN
699 formatter = color_formatter_sql
706 formatter = color_formatter_sql
700
707
701 ################
708 ################
702 ## FORMATTERS ##
709 ## FORMATTERS ##
703 ################
710 ################
704
711
705 [formatter_generic]
712 [formatter_generic]
706 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
713 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
707 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
714 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
708 datefmt = %Y-%m-%d %H:%M:%S
715 datefmt = %Y-%m-%d %H:%M:%S
709
716
710 [formatter_color_formatter]
717 [formatter_color_formatter]
711 class = rhodecode.lib.logging_formatter.ColorFormatter
718 class = rhodecode.lib.logging_formatter.ColorFormatter
712 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
719 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
713 datefmt = %Y-%m-%d %H:%M:%S
720 datefmt = %Y-%m-%d %H:%M:%S
714
721
715 [formatter_color_formatter_sql]
722 [formatter_color_formatter_sql]
716 class = rhodecode.lib.logging_formatter.ColorFormatterSql
723 class = rhodecode.lib.logging_formatter.ColorFormatterSql
717 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
724 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
718 datefmt = %Y-%m-%d %H:%M:%S
725 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,691 +1,698 b''
1
1
2
2
3 ################################################################################
3 ################################################################################
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 ################################################################################
5 ################################################################################
6
6
7 [DEFAULT]
7 [DEFAULT]
8 ## Debug flag sets all loggers to debug, and enables request tracking
8 ## Debug flag sets all loggers to debug, and enables request tracking
9 debug = false
9 debug = false
10
10
11 ################################################################################
11 ################################################################################
12 ## EMAIL CONFIGURATION ##
12 ## EMAIL CONFIGURATION ##
13 ## Uncomment and replace with the email address which should receive ##
13 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
14 ## any error reports after an application crash ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
16 ################################################################################
16 ################################################################################
17
17
18 ## prefix all emails subjects with given prefix, helps filtering out emails
18 ## prefix all emails subjects with given prefix, helps filtering out emails
19 #email_prefix = [RhodeCode]
19 #email_prefix = [RhodeCode]
20
20
21 ## email FROM address all mails will be sent
21 ## email FROM address all mails will be sent
22 #app_email_from = rhodecode-noreply@localhost
22 #app_email_from = rhodecode-noreply@localhost
23
23
24 #smtp_server = mail.server.com
24 #smtp_server = mail.server.com
25 #smtp_username =
25 #smtp_username =
26 #smtp_password =
26 #smtp_password =
27 #smtp_port =
27 #smtp_port =
28 #smtp_use_tls = false
28 #smtp_use_tls = false
29 #smtp_use_ssl = true
29 #smtp_use_ssl = true
30
30
31 [server:main]
31 [server:main]
32 ## COMMON ##
32 ## COMMON ##
33 host = 127.0.0.1
33 host = 127.0.0.1
34 port = 5000
34 port = 5000
35
35
36 ###########################################################
36 ###########################################################
37 ## WAITRESS WSGI SERVER - Recommended for Development ####
37 ## WAITRESS WSGI SERVER - Recommended for Development ####
38 ###########################################################
38 ###########################################################
39
39
40 #use = egg:waitress#main
40 #use = egg:waitress#main
41 ## number of worker threads
41 ## number of worker threads
42 #threads = 5
42 #threads = 5
43 ## MAX BODY SIZE 100GB
43 ## MAX BODY SIZE 100GB
44 #max_request_body_size = 107374182400
44 #max_request_body_size = 107374182400
45 ## Use poll instead of select, fixes file descriptors limits problems.
45 ## Use poll instead of select, fixes file descriptors limits problems.
46 ## May not work on old windows systems.
46 ## May not work on old windows systems.
47 #asyncore_use_poll = true
47 #asyncore_use_poll = true
48
48
49
49
50 ##########################
50 ##########################
51 ## GUNICORN WSGI SERVER ##
51 ## GUNICORN WSGI SERVER ##
52 ##########################
52 ##########################
53 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
53 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
54
54
55 use = egg:gunicorn#main
55 use = egg:gunicorn#main
56 ## Sets the number of process workers. More workers means more concurent connections
56 ## Sets the number of process workers. More workers means more concurent connections
57 ## RhodeCode can handle at the same time. Each additional worker also it increases
57 ## RhodeCode can handle at the same time. Each additional worker also it increases
58 ## memory usage as each has it's own set of caches.
58 ## memory usage as each has it's own set of caches.
59 ## Recommended value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers, but no more
59 ## Recommended value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers, but no more
60 ## than 8-10 unless for really big deployments .e.g 700-1000 users.
60 ## than 8-10 unless for really big deployments .e.g 700-1000 users.
61 ## `instance_id = *` must be set in the [app:main] section below (which is the default)
61 ## `instance_id = *` must be set in the [app:main] section below (which is the default)
62 ## when using more than 1 worker.
62 ## when using more than 1 worker.
63 workers = 2
63 workers = 2
64 ## process name visible in process list
64 ## process name visible in process list
65 proc_name = rhodecode
65 proc_name = rhodecode
66 ## type of worker class, one of sync, gevent
66 ## type of worker class, one of sync, gevent
67 ## recommended for bigger setup is using of of other than sync one
67 ## recommended for bigger setup is using of of other than sync one
68 worker_class = gevent
68 worker_class = gevent
69 ## The maximum number of simultaneous clients. Valid only for Gevent
69 ## The maximum number of simultaneous clients. Valid only for Gevent
70 worker_connections = 10
70 worker_connections = 10
71 ## max number of requests that worker will handle before being gracefully
71 ## max number of requests that worker will handle before being gracefully
72 ## restarted, could prevent memory leaks
72 ## restarted, could prevent memory leaks
73 max_requests = 1000
73 max_requests = 1000
74 max_requests_jitter = 30
74 max_requests_jitter = 30
75 ## amount of time a worker can spend with handling a request before it
75 ## amount of time a worker can spend with handling a request before it
76 ## gets killed and restarted. Set to 6hrs
76 ## gets killed and restarted. Set to 6hrs
77 timeout = 21600
77 timeout = 21600
78
78
79
79
80 ## prefix middleware for RhodeCode.
80 ## prefix middleware for RhodeCode.
81 ## recommended when using proxy setup.
81 ## recommended when using proxy setup.
82 ## allows to set RhodeCode under a prefix in server.
82 ## allows to set RhodeCode under a prefix in server.
83 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
83 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
84 ## And set your prefix like: `prefix = /custom_prefix`
84 ## And set your prefix like: `prefix = /custom_prefix`
85 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
85 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
86 ## to make your cookies only work on prefix url
86 ## to make your cookies only work on prefix url
87 [filter:proxy-prefix]
87 [filter:proxy-prefix]
88 use = egg:PasteDeploy#prefix
88 use = egg:PasteDeploy#prefix
89 prefix = /
89 prefix = /
90
90
91 [app:main]
91 [app:main]
92 ## The %(here)s variable will be replaced with the absolute path of parent directory
92 ## The %(here)s variable will be replaced with the absolute path of parent directory
93 ## of this file
93 ## of this file
94 ## In addition ENVIRONMENT variables usage is possible, e.g
94 ## In addition ENVIRONMENT variables usage is possible, e.g
95 ## sqlalchemy.db1.url = {ENV_RC_DB_URL}
95 ## sqlalchemy.db1.url = {ENV_RC_DB_URL}
96
96
97 use = egg:rhodecode-enterprise-ce
97 use = egg:rhodecode-enterprise-ce
98
98
99 ## enable proxy prefix middleware, defined above
99 ## enable proxy prefix middleware, defined above
100 #filter-with = proxy-prefix
100 #filter-with = proxy-prefix
101
101
102 ## encryption key used to encrypt social plugin tokens,
102 ## encryption key used to encrypt social plugin tokens,
103 ## remote_urls with credentials etc, if not set it defaults to
103 ## remote_urls with credentials etc, if not set it defaults to
104 ## `beaker.session.secret`
104 ## `beaker.session.secret`
105 #rhodecode.encrypted_values.secret =
105 #rhodecode.encrypted_values.secret =
106
106
107 ## decryption strict mode (enabled by default). It controls if decryption raises
107 ## decryption strict mode (enabled by default). It controls if decryption raises
108 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
108 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
109 #rhodecode.encrypted_values.strict = false
109 #rhodecode.encrypted_values.strict = false
110
110
111 ## return gzipped responses from Rhodecode (static files/application)
111 ## return gzipped responses from Rhodecode (static files/application)
112 gzip_responses = false
112 gzip_responses = false
113
113
114 ## autogenerate javascript routes file on startup
114 ## autogenerate javascript routes file on startup
115 generate_js_files = false
115 generate_js_files = false
116
116
117 ## System global default language.
117 ## System global default language.
118 ## All available languages: en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
118 ## All available languages: en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
119 lang = en
119 lang = en
120
120
121 ## Perform a full repository scan and import on each server start.
121 ## Perform a full repository scan and import on each server start.
122 ## Settings this to true could lead to very long startup time.
122 ## Settings this to true could lead to very long startup time.
123 startup.import_repos = false
123 startup.import_repos = false
124
124
125 ## Uncomment and set this path to use archive download cache.
125 ## Uncomment and set this path to use archive download cache.
126 ## Once enabled, generated archives will be cached at this location
126 ## Once enabled, generated archives will be cached at this location
127 ## and served from the cache during subsequent requests for the same archive of
127 ## and served from the cache during subsequent requests for the same archive of
128 ## the repository.
128 ## the repository.
129 #archive_cache_dir = /tmp/tarballcache
129 #archive_cache_dir = /tmp/tarballcache
130
130
131 ## URL at which the application is running. This is used for bootstraping
131 ## URL at which the application is running. This is used for bootstraping
132 ## requests in context when no web request is available. Used in ishell, or
132 ## requests in context when no web request is available. Used in ishell, or
133 ## SSH calls. Set this for events to receive proper url for SSH calls.
133 ## SSH calls. Set this for events to receive proper url for SSH calls.
134 app.base_url = http://rhodecode.local
134 app.base_url = http://rhodecode.local
135
135
136 ## Unique application ID. Should be a random unique string for security.
136 ## Unique application ID. Should be a random unique string for security.
137 app_instance_uuid = rc-production
137 app_instance_uuid = rc-production
138
138
139 ## Cut off limit for large diffs (size in bytes). If overall diff size on
139 ## Cut off limit for large diffs (size in bytes). If overall diff size on
140 ## commit, or pull request exceeds this limit this diff will be displayed
140 ## commit, or pull request exceeds this limit this diff will be displayed
141 ## partially. E.g 512000 == 512Kb
141 ## partially. E.g 512000 == 512Kb
142 cut_off_limit_diff = 512000
142 cut_off_limit_diff = 512000
143
143
144 ## Cut off limit for large files inside diffs (size in bytes). Each individual
144 ## Cut off limit for large files inside diffs (size in bytes). Each individual
145 ## file inside diff which exceeds this limit will be displayed partially.
145 ## file inside diff which exceeds this limit will be displayed partially.
146 ## E.g 128000 == 128Kb
146 ## E.g 128000 == 128Kb
147 cut_off_limit_file = 128000
147 cut_off_limit_file = 128000
148
148
149 ## use cached version of vcs repositories everywhere. Recommended to be `true`
149 ## use cached version of vcs repositories everywhere. Recommended to be `true`
150 vcs_full_cache = true
150 vcs_full_cache = true
151
151
152 ## Force https in RhodeCode, fixes https redirects, assumes it's always https.
152 ## Force https in RhodeCode, fixes https redirects, assumes it's always https.
153 ## Normally this is controlled by proper http flags sent from http server
153 ## Normally this is controlled by proper http flags sent from http server
154 force_https = false
154 force_https = false
155
155
156 ## use Strict-Transport-Security headers
156 ## use Strict-Transport-Security headers
157 use_htsts = false
157 use_htsts = false
158
158
159 ## git rev filter option, --all is the default filter, if you need to
159 ## git rev filter option, --all is the default filter, if you need to
160 ## hide all refs in changelog switch this to --branches --tags
160 ## hide all refs in changelog switch this to --branches --tags
161 git_rev_filter = --branches --tags
161 git_rev_filter = --branches --tags
162
162
163 # Set to true if your repos are exposed using the dumb protocol
163 # Set to true if your repos are exposed using the dumb protocol
164 git_update_server_info = false
164 git_update_server_info = false
165
165
166 ## RSS/ATOM feed options
166 ## RSS/ATOM feed options
167 rss_cut_off_limit = 256000
167 rss_cut_off_limit = 256000
168 rss_items_per_page = 10
168 rss_items_per_page = 10
169 rss_include_diff = false
169 rss_include_diff = false
170
170
171 ## gist URL alias, used to create nicer urls for gist. This should be an
171 ## gist URL alias, used to create nicer urls for gist. This should be an
172 ## url that does rewrites to _admin/gists/{gistid}.
172 ## url that does rewrites to _admin/gists/{gistid}.
173 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
173 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
174 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
174 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
175 gist_alias_url =
175 gist_alias_url =
176
176
177 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
177 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
178 ## used for access.
178 ## used for access.
179 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
179 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
180 ## came from the the logged in user who own this authentication token.
180 ## came from the the logged in user who own this authentication token.
181 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
181 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
182 ## authentication token. Such view would be only accessible when used together
182 ## authentication token. Such view would be only accessible when used together
183 ## with this authentication token
183 ## with this authentication token
184 ##
184 ##
185 ## list of all views can be found under `/_admin/permissions/auth_token_access`
185 ## list of all views can be found under `/_admin/permissions/auth_token_access`
186 ## The list should be "," separated and on a single line.
186 ## The list should be "," separated and on a single line.
187 ##
187 ##
188 ## Most common views to enable:
188 ## Most common views to enable:
189 # RepoCommitsView:repo_commit_download
189 # RepoCommitsView:repo_commit_download
190 # RepoCommitsView:repo_commit_patch
190 # RepoCommitsView:repo_commit_patch
191 # RepoCommitsView:repo_commit_raw
191 # RepoCommitsView:repo_commit_raw
192 # RepoCommitsView:repo_commit_raw@TOKEN
192 # RepoCommitsView:repo_commit_raw@TOKEN
193 # RepoFilesView:repo_files_diff
193 # RepoFilesView:repo_files_diff
194 # RepoFilesView:repo_archivefile
194 # RepoFilesView:repo_archivefile
195 # RepoFilesView:repo_file_raw
195 # RepoFilesView:repo_file_raw
196 # GistView:*
196 # GistView:*
197 api_access_controllers_whitelist =
197 api_access_controllers_whitelist =
198
198
199 ## Default encoding used to convert from and to unicode
199 ## Default encoding used to convert from and to unicode
200 ## can be also a comma separated list of encoding in case of mixed encodings
200 ## can be also a comma separated list of encoding in case of mixed encodings
201 default_encoding = UTF-8
201 default_encoding = UTF-8
202
202
203 ## instance-id prefix
203 ## instance-id prefix
204 ## a prefix key for this instance used for cache invalidation when running
204 ## a prefix key for this instance used for cache invalidation when running
205 ## multiple instances of rhodecode, make sure it's globally unique for
205 ## multiple instances of rhodecode, make sure it's globally unique for
206 ## all running rhodecode instances. Leave empty if you don't use it
206 ## all running rhodecode instances. Leave empty if you don't use it
207 instance_id =
207 instance_id =
208
208
209 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
209 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
210 ## of an authentication plugin also if it is disabled by it's settings.
210 ## of an authentication plugin also if it is disabled by it's settings.
211 ## This could be useful if you are unable to log in to the system due to broken
211 ## This could be useful if you are unable to log in to the system due to broken
212 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
212 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
213 ## module to log in again and fix the settings.
213 ## module to log in again and fix the settings.
214 ##
214 ##
215 ## Available builtin plugin IDs (hash is part of the ID):
215 ## Available builtin plugin IDs (hash is part of the ID):
216 ## egg:rhodecode-enterprise-ce#rhodecode
216 ## egg:rhodecode-enterprise-ce#rhodecode
217 ## egg:rhodecode-enterprise-ce#pam
217 ## egg:rhodecode-enterprise-ce#pam
218 ## egg:rhodecode-enterprise-ce#ldap
218 ## egg:rhodecode-enterprise-ce#ldap
219 ## egg:rhodecode-enterprise-ce#jasig_cas
219 ## egg:rhodecode-enterprise-ce#jasig_cas
220 ## egg:rhodecode-enterprise-ce#headers
220 ## egg:rhodecode-enterprise-ce#headers
221 ## egg:rhodecode-enterprise-ce#crowd
221 ## egg:rhodecode-enterprise-ce#crowd
222 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
222 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
223
223
224 ## alternative return HTTP header for failed authentication. Default HTTP
224 ## alternative return HTTP header for failed authentication. Default HTTP
225 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
225 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
226 ## handling that causing a series of failed authentication calls.
226 ## handling that causing a series of failed authentication calls.
227 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
227 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
228 ## This will be served instead of default 401 on bad authnetication
228 ## This will be served instead of default 401 on bad authnetication
229 auth_ret_code =
229 auth_ret_code =
230
230
231 ## use special detection method when serving auth_ret_code, instead of serving
231 ## use special detection method when serving auth_ret_code, instead of serving
232 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
232 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
233 ## and then serve auth_ret_code to clients
233 ## and then serve auth_ret_code to clients
234 auth_ret_code_detection = false
234 auth_ret_code_detection = false
235
235
236 ## locking return code. When repository is locked return this HTTP code. 2XX
236 ## locking return code. When repository is locked return this HTTP code. 2XX
237 ## codes don't break the transactions while 4XX codes do
237 ## codes don't break the transactions while 4XX codes do
238 lock_ret_code = 423
238 lock_ret_code = 423
239
239
240 ## allows to change the repository location in settings page
240 ## allows to change the repository location in settings page
241 allow_repo_location_change = true
241 allow_repo_location_change = true
242
242
243 ## allows to setup custom hooks in settings page
243 ## allows to setup custom hooks in settings page
244 allow_custom_hooks_settings = true
244 allow_custom_hooks_settings = true
245
245
246 ## Generated license token required for EE edition license.
246 ## Generated license token required for EE edition license.
247 ## New generated token value can be found in Admin > settings > license page.
247 ## New generated token value can be found in Admin > settings > license page.
248 license_token =
248 license_token =
249
249
250 ## supervisor connection uri, for managing supervisor and logs.
250 ## supervisor connection uri, for managing supervisor and logs.
251 supervisor.uri =
251 supervisor.uri =
252 ## supervisord group name/id we only want this RC instance to handle
252 ## supervisord group name/id we only want this RC instance to handle
253 supervisor.group_id = prod
253 supervisor.group_id = prod
254
254
255 ## Display extended labs settings
255 ## Display extended labs settings
256 labs_settings_active = true
256 labs_settings_active = true
257
257
258 ## Custom exception store path, defaults to TMPDIR
258 ## Custom exception store path, defaults to TMPDIR
259 ## This is used to store exception from RhodeCode in shared directory
259 ## This is used to store exception from RhodeCode in shared directory
260 #exception_tracker.store_path =
260 #exception_tracker.store_path =
261
261
262 ## File store configuration. This is used to store and serve uploaded files
263 file_store.enabled = true
264 ## backend, only available one is local
265 file_store.backend = local
266 ## path to store the uploaded binaries
267 file_store.storage_path = %(here)s/data/file_store
268
262
269
263 ####################################
270 ####################################
264 ### CELERY CONFIG ####
271 ### CELERY CONFIG ####
265 ####################################
272 ####################################
266 ## run: /path/to/celery worker \
273 ## run: /path/to/celery worker \
267 ## -E --beat --app rhodecode.lib.celerylib.loader \
274 ## -E --beat --app rhodecode.lib.celerylib.loader \
268 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
275 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
269 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
276 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
270
277
271 use_celery = false
278 use_celery = false
272
279
273 ## connection url to the message broker (default rabbitmq)
280 ## connection url to the message broker (default rabbitmq)
274 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
281 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
275
282
276 ## maximum tasks to execute before worker restart
283 ## maximum tasks to execute before worker restart
277 celery.max_tasks_per_child = 100
284 celery.max_tasks_per_child = 100
278
285
279 ## tasks will never be sent to the queue, but executed locally instead.
286 ## tasks will never be sent to the queue, but executed locally instead.
280 celery.task_always_eager = false
287 celery.task_always_eager = false
281
288
282 #####################################
289 #####################################
283 ### DOGPILE CACHE ####
290 ### DOGPILE CACHE ####
284 #####################################
291 #####################################
285 ## Default cache dir for caches. Putting this into a ramdisk
292 ## Default cache dir for caches. Putting this into a ramdisk
286 ## can boost performance, eg. /tmpfs/data_ramdisk, however this directory might require
293 ## can boost performance, eg. /tmpfs/data_ramdisk, however this directory might require
287 ## large amount of space
294 ## large amount of space
288 cache_dir = %(here)s/data
295 cache_dir = %(here)s/data
289
296
290 ## `cache_perms` cache settings for permission tree, auth TTL.
297 ## `cache_perms` cache settings for permission tree, auth TTL.
291 rc_cache.cache_perms.backend = dogpile.cache.rc.file_namespace
298 rc_cache.cache_perms.backend = dogpile.cache.rc.file_namespace
292 rc_cache.cache_perms.expiration_time = 300
299 rc_cache.cache_perms.expiration_time = 300
293
300
294 ## alternative `cache_perms` redis backend with distributed lock
301 ## alternative `cache_perms` redis backend with distributed lock
295 #rc_cache.cache_perms.backend = dogpile.cache.rc.redis
302 #rc_cache.cache_perms.backend = dogpile.cache.rc.redis
296 #rc_cache.cache_perms.expiration_time = 300
303 #rc_cache.cache_perms.expiration_time = 300
297 ## redis_expiration_time needs to be greater then expiration_time
304 ## redis_expiration_time needs to be greater then expiration_time
298 #rc_cache.cache_perms.arguments.redis_expiration_time = 7200
305 #rc_cache.cache_perms.arguments.redis_expiration_time = 7200
299 #rc_cache.cache_perms.arguments.socket_timeout = 30
306 #rc_cache.cache_perms.arguments.socket_timeout = 30
300 #rc_cache.cache_perms.arguments.host = localhost
307 #rc_cache.cache_perms.arguments.host = localhost
301 #rc_cache.cache_perms.arguments.port = 6379
308 #rc_cache.cache_perms.arguments.port = 6379
302 #rc_cache.cache_perms.arguments.db = 0
309 #rc_cache.cache_perms.arguments.db = 0
303 #rc_cache.cache_perms.arguments.distributed_lock = true
310 #rc_cache.cache_perms.arguments.distributed_lock = true
304
311
305 ## `cache_repo` cache settings for FileTree, Readme, RSS FEEDS
312 ## `cache_repo` cache settings for FileTree, Readme, RSS FEEDS
306 rc_cache.cache_repo.backend = dogpile.cache.rc.file_namespace
313 rc_cache.cache_repo.backend = dogpile.cache.rc.file_namespace
307 rc_cache.cache_repo.expiration_time = 2592000
314 rc_cache.cache_repo.expiration_time = 2592000
308
315
309 ## alternative `cache_repo` redis backend with distributed lock
316 ## alternative `cache_repo` redis backend with distributed lock
310 #rc_cache.cache_repo.backend = dogpile.cache.rc.redis
317 #rc_cache.cache_repo.backend = dogpile.cache.rc.redis
311 #rc_cache.cache_repo.expiration_time = 2592000
318 #rc_cache.cache_repo.expiration_time = 2592000
312 ## redis_expiration_time needs to be greater then expiration_time
319 ## redis_expiration_time needs to be greater then expiration_time
313 #rc_cache.cache_repo.arguments.redis_expiration_time = 2678400
320 #rc_cache.cache_repo.arguments.redis_expiration_time = 2678400
314 #rc_cache.cache_repo.arguments.socket_timeout = 30
321 #rc_cache.cache_repo.arguments.socket_timeout = 30
315 #rc_cache.cache_repo.arguments.host = localhost
322 #rc_cache.cache_repo.arguments.host = localhost
316 #rc_cache.cache_repo.arguments.port = 6379
323 #rc_cache.cache_repo.arguments.port = 6379
317 #rc_cache.cache_repo.arguments.db = 1
324 #rc_cache.cache_repo.arguments.db = 1
318 #rc_cache.cache_repo.arguments.distributed_lock = true
325 #rc_cache.cache_repo.arguments.distributed_lock = true
319
326
320 ## cache settings for SQL queries, this needs to use memory type backend
327 ## cache settings for SQL queries, this needs to use memory type backend
321 rc_cache.sql_cache_short.backend = dogpile.cache.rc.memory_lru
328 rc_cache.sql_cache_short.backend = dogpile.cache.rc.memory_lru
322 rc_cache.sql_cache_short.expiration_time = 30
329 rc_cache.sql_cache_short.expiration_time = 30
323
330
324 ## `cache_repo_longterm` cache for repo object instances, this needs to use memory
331 ## `cache_repo_longterm` cache for repo object instances, this needs to use memory
325 ## type backend as the objects kept are not pickle serializable
332 ## type backend as the objects kept are not pickle serializable
326 rc_cache.cache_repo_longterm.backend = dogpile.cache.rc.memory_lru
333 rc_cache.cache_repo_longterm.backend = dogpile.cache.rc.memory_lru
327 ## by default we use 96H, this is using invalidation on push anyway
334 ## by default we use 96H, this is using invalidation on push anyway
328 rc_cache.cache_repo_longterm.expiration_time = 345600
335 rc_cache.cache_repo_longterm.expiration_time = 345600
329 ## max items in LRU cache, reduce this number to save memory, and expire last used
336 ## max items in LRU cache, reduce this number to save memory, and expire last used
330 ## cached objects
337 ## cached objects
331 rc_cache.cache_repo_longterm.max_size = 10000
338 rc_cache.cache_repo_longterm.max_size = 10000
332
339
333
340
334 ####################################
341 ####################################
335 ### BEAKER SESSION ####
342 ### BEAKER SESSION ####
336 ####################################
343 ####################################
337
344
338 ## .session.type is type of storage options for the session, current allowed
345 ## .session.type is type of storage options for the session, current allowed
339 ## types are file, ext:memcached, ext:redis, ext:database, and memory (default).
346 ## types are file, ext:memcached, ext:redis, ext:database, and memory (default).
340 beaker.session.type = file
347 beaker.session.type = file
341 beaker.session.data_dir = %(here)s/data/sessions
348 beaker.session.data_dir = %(here)s/data/sessions
342
349
343 ## db based session, fast, and allows easy management over logged in users
350 ## db based session, fast, and allows easy management over logged in users
344 #beaker.session.type = ext:database
351 #beaker.session.type = ext:database
345 #beaker.session.table_name = db_session
352 #beaker.session.table_name = db_session
346 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
353 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
347 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
354 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
348 #beaker.session.sa.pool_recycle = 3600
355 #beaker.session.sa.pool_recycle = 3600
349 #beaker.session.sa.echo = false
356 #beaker.session.sa.echo = false
350
357
351 beaker.session.key = rhodecode
358 beaker.session.key = rhodecode
352 beaker.session.secret = production-rc-uytcxaz
359 beaker.session.secret = production-rc-uytcxaz
353 beaker.session.lock_dir = %(here)s/data/sessions/lock
360 beaker.session.lock_dir = %(here)s/data/sessions/lock
354
361
355 ## Secure encrypted cookie. Requires AES and AES python libraries
362 ## Secure encrypted cookie. Requires AES and AES python libraries
356 ## you must disable beaker.session.secret to use this
363 ## you must disable beaker.session.secret to use this
357 #beaker.session.encrypt_key = key_for_encryption
364 #beaker.session.encrypt_key = key_for_encryption
358 #beaker.session.validate_key = validation_key
365 #beaker.session.validate_key = validation_key
359
366
360 ## sets session as invalid(also logging out user) if it haven not been
367 ## sets session as invalid(also logging out user) if it haven not been
361 ## accessed for given amount of time in seconds
368 ## accessed for given amount of time in seconds
362 beaker.session.timeout = 2592000
369 beaker.session.timeout = 2592000
363 beaker.session.httponly = true
370 beaker.session.httponly = true
364 ## Path to use for the cookie. Set to prefix if you use prefix middleware
371 ## Path to use for the cookie. Set to prefix if you use prefix middleware
365 #beaker.session.cookie_path = /custom_prefix
372 #beaker.session.cookie_path = /custom_prefix
366
373
367 ## uncomment for https secure cookie
374 ## uncomment for https secure cookie
368 beaker.session.secure = false
375 beaker.session.secure = false
369
376
370 ## auto save the session to not to use .save()
377 ## auto save the session to not to use .save()
371 beaker.session.auto = false
378 beaker.session.auto = false
372
379
373 ## default cookie expiration time in seconds, set to `true` to set expire
380 ## default cookie expiration time in seconds, set to `true` to set expire
374 ## at browser close
381 ## at browser close
375 #beaker.session.cookie_expires = 3600
382 #beaker.session.cookie_expires = 3600
376
383
377 ###################################
384 ###################################
378 ## SEARCH INDEXING CONFIGURATION ##
385 ## SEARCH INDEXING CONFIGURATION ##
379 ###################################
386 ###################################
380 ## Full text search indexer is available in rhodecode-tools under
387 ## Full text search indexer is available in rhodecode-tools under
381 ## `rhodecode-tools index` command
388 ## `rhodecode-tools index` command
382
389
383 ## WHOOSH Backend, doesn't require additional services to run
390 ## WHOOSH Backend, doesn't require additional services to run
384 ## it works good with few dozen repos
391 ## it works good with few dozen repos
385 search.module = rhodecode.lib.index.whoosh
392 search.module = rhodecode.lib.index.whoosh
386 search.location = %(here)s/data/index
393 search.location = %(here)s/data/index
387
394
388 ########################################
395 ########################################
389 ### CHANNELSTREAM CONFIG ####
396 ### CHANNELSTREAM CONFIG ####
390 ########################################
397 ########################################
391 ## channelstream enables persistent connections and live notification
398 ## channelstream enables persistent connections and live notification
392 ## in the system. It's also used by the chat system
399 ## in the system. It's also used by the chat system
393
400
394 channelstream.enabled = false
401 channelstream.enabled = false
395
402
396 ## server address for channelstream server on the backend
403 ## server address for channelstream server on the backend
397 channelstream.server = 127.0.0.1:9800
404 channelstream.server = 127.0.0.1:9800
398
405
399 ## location of the channelstream server from outside world
406 ## location of the channelstream server from outside world
400 ## use ws:// for http or wss:// for https. This address needs to be handled
407 ## use ws:// for http or wss:// for https. This address needs to be handled
401 ## by external HTTP server such as Nginx or Apache
408 ## by external HTTP server such as Nginx or Apache
402 ## see nginx/apache configuration examples in our docs
409 ## see nginx/apache configuration examples in our docs
403 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
410 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
404 channelstream.secret = secret
411 channelstream.secret = secret
405 channelstream.history.location = %(here)s/channelstream_history
412 channelstream.history.location = %(here)s/channelstream_history
406
413
407 ## Internal application path that Javascript uses to connect into.
414 ## Internal application path that Javascript uses to connect into.
408 ## If you use proxy-prefix the prefix should be added before /_channelstream
415 ## If you use proxy-prefix the prefix should be added before /_channelstream
409 channelstream.proxy_path = /_channelstream
416 channelstream.proxy_path = /_channelstream
410
417
411
418
412 ###################################
419 ###################################
413 ## APPENLIGHT CONFIG ##
420 ## APPENLIGHT CONFIG ##
414 ###################################
421 ###################################
415
422
416 ## Appenlight is tailored to work with RhodeCode, see
423 ## Appenlight is tailored to work with RhodeCode, see
417 ## http://appenlight.com for details how to obtain an account
424 ## http://appenlight.com for details how to obtain an account
418
425
419 ## appenlight integration enabled
426 ## appenlight integration enabled
420 appenlight = false
427 appenlight = false
421
428
422 appenlight.server_url = https://api.appenlight.com
429 appenlight.server_url = https://api.appenlight.com
423 appenlight.api_key = YOUR_API_KEY
430 appenlight.api_key = YOUR_API_KEY
424 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
431 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
425
432
426 # used for JS client
433 # used for JS client
427 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
434 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
428
435
429 ## TWEAK AMOUNT OF INFO SENT HERE
436 ## TWEAK AMOUNT OF INFO SENT HERE
430
437
431 ## enables 404 error logging (default False)
438 ## enables 404 error logging (default False)
432 appenlight.report_404 = false
439 appenlight.report_404 = false
433
440
434 ## time in seconds after request is considered being slow (default 1)
441 ## time in seconds after request is considered being slow (default 1)
435 appenlight.slow_request_time = 1
442 appenlight.slow_request_time = 1
436
443
437 ## record slow requests in application
444 ## record slow requests in application
438 ## (needs to be enabled for slow datastore recording and time tracking)
445 ## (needs to be enabled for slow datastore recording and time tracking)
439 appenlight.slow_requests = true
446 appenlight.slow_requests = true
440
447
441 ## enable hooking to application loggers
448 ## enable hooking to application loggers
442 appenlight.logging = true
449 appenlight.logging = true
443
450
444 ## minimum log level for log capture
451 ## minimum log level for log capture
445 appenlight.logging.level = WARNING
452 appenlight.logging.level = WARNING
446
453
447 ## send logs only from erroneous/slow requests
454 ## send logs only from erroneous/slow requests
448 ## (saves API quota for intensive logging)
455 ## (saves API quota for intensive logging)
449 appenlight.logging_on_error = false
456 appenlight.logging_on_error = false
450
457
451 ## list of additonal keywords that should be grabbed from environ object
458 ## list of additonal keywords that should be grabbed from environ object
452 ## can be string with comma separated list of words in lowercase
459 ## can be string with comma separated list of words in lowercase
453 ## (by default client will always send following info:
460 ## (by default client will always send following info:
454 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
461 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
455 ## start with HTTP* this list be extended with additional keywords here
462 ## start with HTTP* this list be extended with additional keywords here
456 appenlight.environ_keys_whitelist =
463 appenlight.environ_keys_whitelist =
457
464
458 ## list of keywords that should be blanked from request object
465 ## list of keywords that should be blanked from request object
459 ## can be string with comma separated list of words in lowercase
466 ## can be string with comma separated list of words in lowercase
460 ## (by default client will always blank keys that contain following words
467 ## (by default client will always blank keys that contain following words
461 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
468 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
462 ## this list be extended with additional keywords set here
469 ## this list be extended with additional keywords set here
463 appenlight.request_keys_blacklist =
470 appenlight.request_keys_blacklist =
464
471
465 ## list of namespaces that should be ignores when gathering log entries
472 ## list of namespaces that should be ignores when gathering log entries
466 ## can be string with comma separated list of namespaces
473 ## can be string with comma separated list of namespaces
467 ## (by default the client ignores own entries: appenlight_client.client)
474 ## (by default the client ignores own entries: appenlight_client.client)
468 appenlight.log_namespace_blacklist =
475 appenlight.log_namespace_blacklist =
469
476
470
477
471 ###########################################
478 ###########################################
472 ### MAIN RHODECODE DATABASE CONFIG ###
479 ### MAIN RHODECODE DATABASE CONFIG ###
473 ###########################################
480 ###########################################
474 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
481 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
475 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
482 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
476 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode?charset=utf8
483 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode?charset=utf8
477 # pymysql is an alternative driver for MySQL, use in case of problems with default one
484 # pymysql is an alternative driver for MySQL, use in case of problems with default one
478 #sqlalchemy.db1.url = mysql+pymysql://root:qweqwe@localhost/rhodecode
485 #sqlalchemy.db1.url = mysql+pymysql://root:qweqwe@localhost/rhodecode
479
486
480 sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
487 sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
481
488
482 # see sqlalchemy docs for other advanced settings
489 # see sqlalchemy docs for other advanced settings
483
490
484 ## print the sql statements to output
491 ## print the sql statements to output
485 sqlalchemy.db1.echo = false
492 sqlalchemy.db1.echo = false
486 ## recycle the connections after this amount of seconds
493 ## recycle the connections after this amount of seconds
487 sqlalchemy.db1.pool_recycle = 3600
494 sqlalchemy.db1.pool_recycle = 3600
488 sqlalchemy.db1.convert_unicode = true
495 sqlalchemy.db1.convert_unicode = true
489
496
490 ## the number of connections to keep open inside the connection pool.
497 ## the number of connections to keep open inside the connection pool.
491 ## 0 indicates no limit
498 ## 0 indicates no limit
492 #sqlalchemy.db1.pool_size = 5
499 #sqlalchemy.db1.pool_size = 5
493
500
494 ## the number of connections to allow in connection pool "overflow", that is
501 ## the number of connections to allow in connection pool "overflow", that is
495 ## connections that can be opened above and beyond the pool_size setting,
502 ## connections that can be opened above and beyond the pool_size setting,
496 ## which defaults to five.
503 ## which defaults to five.
497 #sqlalchemy.db1.max_overflow = 10
504 #sqlalchemy.db1.max_overflow = 10
498
505
499 ## Connection check ping, used to detect broken database connections
506 ## Connection check ping, used to detect broken database connections
500 ## could be enabled to better handle cases if MySQL has gone away errors
507 ## could be enabled to better handle cases if MySQL has gone away errors
501 #sqlalchemy.db1.ping_connection = true
508 #sqlalchemy.db1.ping_connection = true
502
509
503 ##################
510 ##################
504 ### VCS CONFIG ###
511 ### VCS CONFIG ###
505 ##################
512 ##################
506 vcs.server.enable = true
513 vcs.server.enable = true
507 vcs.server = localhost:9900
514 vcs.server = localhost:9900
508
515
509 ## Web server connectivity protocol, responsible for web based VCS operatations
516 ## Web server connectivity protocol, responsible for web based VCS operatations
510 ## Available protocols are:
517 ## Available protocols are:
511 ## `http` - use http-rpc backend (default)
518 ## `http` - use http-rpc backend (default)
512 vcs.server.protocol = http
519 vcs.server.protocol = http
513
520
514 ## Push/Pull operations protocol, available options are:
521 ## Push/Pull operations protocol, available options are:
515 ## `http` - use http-rpc backend (default)
522 ## `http` - use http-rpc backend (default)
516 vcs.scm_app_implementation = http
523 vcs.scm_app_implementation = http
517
524
518 ## Push/Pull operations hooks protocol, available options are:
525 ## Push/Pull operations hooks protocol, available options are:
519 ## `http` - use http-rpc backend (default)
526 ## `http` - use http-rpc backend (default)
520 vcs.hooks.protocol = http
527 vcs.hooks.protocol = http
521
528
522 ## Host on which this instance is listening for hooks. If vcsserver is in other location
529 ## Host on which this instance is listening for hooks. If vcsserver is in other location
523 ## this should be adjusted.
530 ## this should be adjusted.
524 vcs.hooks.host = 127.0.0.1
531 vcs.hooks.host = 127.0.0.1
525
532
526 vcs.server.log_level = info
533 vcs.server.log_level = info
527 ## Start VCSServer with this instance as a subprocess, useful for development
534 ## Start VCSServer with this instance as a subprocess, useful for development
528 vcs.start_server = false
535 vcs.start_server = false
529
536
530 ## List of enabled VCS backends, available options are:
537 ## List of enabled VCS backends, available options are:
531 ## `hg` - mercurial
538 ## `hg` - mercurial
532 ## `git` - git
539 ## `git` - git
533 ## `svn` - subversion
540 ## `svn` - subversion
534 vcs.backends = hg, git, svn
541 vcs.backends = hg, git, svn
535
542
536 vcs.connection_timeout = 3600
543 vcs.connection_timeout = 3600
537 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
544 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
538 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
545 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
539 #vcs.svn.compatible_version = pre-1.8-compatible
546 #vcs.svn.compatible_version = pre-1.8-compatible
540
547
541
548
542 ############################################################
549 ############################################################
543 ### Subversion proxy support (mod_dav_svn) ###
550 ### Subversion proxy support (mod_dav_svn) ###
544 ### Maps RhodeCode repo groups into SVN paths for Apache ###
551 ### Maps RhodeCode repo groups into SVN paths for Apache ###
545 ############################################################
552 ############################################################
546 ## Enable or disable the config file generation.
553 ## Enable or disable the config file generation.
547 svn.proxy.generate_config = false
554 svn.proxy.generate_config = false
548 ## Generate config file with `SVNListParentPath` set to `On`.
555 ## Generate config file with `SVNListParentPath` set to `On`.
549 svn.proxy.list_parent_path = true
556 svn.proxy.list_parent_path = true
550 ## Set location and file name of generated config file.
557 ## Set location and file name of generated config file.
551 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
558 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
552 ## alternative mod_dav config template. This needs to be a mako template
559 ## alternative mod_dav config template. This needs to be a mako template
553 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
560 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
554 ## Used as a prefix to the `Location` block in the generated config file.
561 ## Used as a prefix to the `Location` block in the generated config file.
555 ## In most cases it should be set to `/`.
562 ## In most cases it should be set to `/`.
556 svn.proxy.location_root = /
563 svn.proxy.location_root = /
557 ## Command to reload the mod dav svn configuration on change.
564 ## Command to reload the mod dav svn configuration on change.
558 ## Example: `/etc/init.d/apache2 reload`
565 ## Example: `/etc/init.d/apache2 reload`
559 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
566 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
560 ## If the timeout expires before the reload command finishes, the command will
567 ## If the timeout expires before the reload command finishes, the command will
561 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
568 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
562 #svn.proxy.reload_timeout = 10
569 #svn.proxy.reload_timeout = 10
563
570
564 ############################################################
571 ############################################################
565 ### SSH Support Settings ###
572 ### SSH Support Settings ###
566 ############################################################
573 ############################################################
567
574
568 ## Defines if a custom authorized_keys file should be created and written on
575 ## Defines if a custom authorized_keys file should be created and written on
569 ## any change user ssh keys. Setting this to false also disables posibility
576 ## any change user ssh keys. Setting this to false also disables posibility
570 ## of adding SSH keys by users from web interface. Super admins can still
577 ## of adding SSH keys by users from web interface. Super admins can still
571 ## manage SSH Keys.
578 ## manage SSH Keys.
572 ssh.generate_authorized_keyfile = false
579 ssh.generate_authorized_keyfile = false
573
580
574 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
581 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
575 # ssh.authorized_keys_ssh_opts =
582 # ssh.authorized_keys_ssh_opts =
576
583
577 ## Path to the authrozied_keys file where the generate entries are placed.
584 ## Path to the authrozied_keys file where the generate entries are placed.
578 ## It is possible to have multiple key files specified in `sshd_config` e.g.
585 ## It is possible to have multiple key files specified in `sshd_config` e.g.
579 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
586 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
580 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
587 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
581
588
582 ## Command to execute the SSH wrapper. The binary is available in the
589 ## Command to execute the SSH wrapper. The binary is available in the
583 ## rhodecode installation directory.
590 ## rhodecode installation directory.
584 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
591 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
585 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
592 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
586
593
587 ## Allow shell when executing the ssh-wrapper command
594 ## Allow shell when executing the ssh-wrapper command
588 ssh.wrapper_cmd_allow_shell = false
595 ssh.wrapper_cmd_allow_shell = false
589
596
590 ## Enables logging, and detailed output send back to the client during SSH
597 ## Enables logging, and detailed output send back to the client during SSH
591 ## operations. Usefull for debugging, shouldn't be used in production.
598 ## operations. Usefull for debugging, shouldn't be used in production.
592 ssh.enable_debug_logging = false
599 ssh.enable_debug_logging = false
593
600
594 ## Paths to binary executable, by default they are the names, but we can
601 ## Paths to binary executable, by default they are the names, but we can
595 ## override them if we want to use a custom one
602 ## override them if we want to use a custom one
596 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
603 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
597 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
604 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
598 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
605 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
599
606
600
607
601 ## Dummy marker to add new entries after.
608 ## Dummy marker to add new entries after.
602 ## Add any custom entries below. Please don't remove.
609 ## Add any custom entries below. Please don't remove.
603 custom.conf = 1
610 custom.conf = 1
604
611
605
612
606 ################################
613 ################################
607 ### LOGGING CONFIGURATION ####
614 ### LOGGING CONFIGURATION ####
608 ################################
615 ################################
609 [loggers]
616 [loggers]
610 keys = root, sqlalchemy, beaker, celery, rhodecode, ssh_wrapper
617 keys = root, sqlalchemy, beaker, celery, rhodecode, ssh_wrapper
611
618
612 [handlers]
619 [handlers]
613 keys = console, console_sql
620 keys = console, console_sql
614
621
615 [formatters]
622 [formatters]
616 keys = generic, color_formatter, color_formatter_sql
623 keys = generic, color_formatter, color_formatter_sql
617
624
618 #############
625 #############
619 ## LOGGERS ##
626 ## LOGGERS ##
620 #############
627 #############
621 [logger_root]
628 [logger_root]
622 level = NOTSET
629 level = NOTSET
623 handlers = console
630 handlers = console
624
631
625 [logger_sqlalchemy]
632 [logger_sqlalchemy]
626 level = INFO
633 level = INFO
627 handlers = console_sql
634 handlers = console_sql
628 qualname = sqlalchemy.engine
635 qualname = sqlalchemy.engine
629 propagate = 0
636 propagate = 0
630
637
631 [logger_beaker]
638 [logger_beaker]
632 level = DEBUG
639 level = DEBUG
633 handlers =
640 handlers =
634 qualname = beaker.container
641 qualname = beaker.container
635 propagate = 1
642 propagate = 1
636
643
637 [logger_rhodecode]
644 [logger_rhodecode]
638 level = DEBUG
645 level = DEBUG
639 handlers =
646 handlers =
640 qualname = rhodecode
647 qualname = rhodecode
641 propagate = 1
648 propagate = 1
642
649
643 [logger_ssh_wrapper]
650 [logger_ssh_wrapper]
644 level = DEBUG
651 level = DEBUG
645 handlers =
652 handlers =
646 qualname = ssh_wrapper
653 qualname = ssh_wrapper
647 propagate = 1
654 propagate = 1
648
655
649 [logger_celery]
656 [logger_celery]
650 level = DEBUG
657 level = DEBUG
651 handlers =
658 handlers =
652 qualname = celery
659 qualname = celery
653
660
654
661
655 ##############
662 ##############
656 ## HANDLERS ##
663 ## HANDLERS ##
657 ##############
664 ##############
658
665
659 [handler_console]
666 [handler_console]
660 class = StreamHandler
667 class = StreamHandler
661 args = (sys.stderr, )
668 args = (sys.stderr, )
662 level = INFO
669 level = INFO
663 formatter = generic
670 formatter = generic
664
671
665 [handler_console_sql]
672 [handler_console_sql]
666 # "level = DEBUG" logs SQL queries and results.
673 # "level = DEBUG" logs SQL queries and results.
667 # "level = INFO" logs SQL queries.
674 # "level = INFO" logs SQL queries.
668 # "level = WARN" logs neither. (Recommended for production systems.)
675 # "level = WARN" logs neither. (Recommended for production systems.)
669 class = StreamHandler
676 class = StreamHandler
670 args = (sys.stderr, )
677 args = (sys.stderr, )
671 level = WARN
678 level = WARN
672 formatter = generic
679 formatter = generic
673
680
674 ################
681 ################
675 ## FORMATTERS ##
682 ## FORMATTERS ##
676 ################
683 ################
677
684
678 [formatter_generic]
685 [formatter_generic]
679 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
686 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
680 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
687 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
681 datefmt = %Y-%m-%d %H:%M:%S
688 datefmt = %Y-%m-%d %H:%M:%S
682
689
683 [formatter_color_formatter]
690 [formatter_color_formatter]
684 class = rhodecode.lib.logging_formatter.ColorFormatter
691 class = rhodecode.lib.logging_formatter.ColorFormatter
685 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
692 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
686 datefmt = %Y-%m-%d %H:%M:%S
693 datefmt = %Y-%m-%d %H:%M:%S
687
694
688 [formatter_color_formatter_sql]
695 [formatter_color_formatter_sql]
689 class = rhodecode.lib.logging_formatter.ColorFormatterSql
696 class = rhodecode.lib.logging_formatter.ColorFormatterSql
690 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
697 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
691 datefmt = %Y-%m-%d %H:%M:%S
698 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,739 +1,740 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import sys
22 import sys
23 import logging
23 import logging
24 import collections
24 import collections
25 import tempfile
25 import tempfile
26 import time
26 import time
27
27
28 from paste.gzipper import make_gzip_middleware
28 from paste.gzipper import make_gzip_middleware
29 import pyramid.events
29 import pyramid.events
30 from pyramid.wsgi import wsgiapp
30 from pyramid.wsgi import wsgiapp
31 from pyramid.authorization import ACLAuthorizationPolicy
31 from pyramid.authorization import ACLAuthorizationPolicy
32 from pyramid.config import Configurator
32 from pyramid.config import Configurator
33 from pyramid.settings import asbool, aslist
33 from pyramid.settings import asbool, aslist
34 from pyramid.httpexceptions import (
34 from pyramid.httpexceptions import (
35 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound, HTTPNotFound)
35 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound, HTTPNotFound)
36 from pyramid.renderers import render_to_response
36 from pyramid.renderers import render_to_response
37
37
38 from rhodecode.model import meta
38 from rhodecode.model import meta
39 from rhodecode.config import patches
39 from rhodecode.config import patches
40 from rhodecode.config import utils as config_utils
40 from rhodecode.config import utils as config_utils
41 from rhodecode.config.environment import load_pyramid_environment
41 from rhodecode.config.environment import load_pyramid_environment
42
42
43 import rhodecode.events
43 import rhodecode.events
44 from rhodecode.lib.middleware.vcs import VCSMiddleware
44 from rhodecode.lib.middleware.vcs import VCSMiddleware
45 from rhodecode.lib.request import Request
45 from rhodecode.lib.request import Request
46 from rhodecode.lib.vcs import VCSCommunicationError
46 from rhodecode.lib.vcs import VCSCommunicationError
47 from rhodecode.lib.exceptions import VCSServerUnavailable
47 from rhodecode.lib.exceptions import VCSServerUnavailable
48 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
48 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
49 from rhodecode.lib.middleware.https_fixup import HttpsFixup
49 from rhodecode.lib.middleware.https_fixup import HttpsFixup
50 from rhodecode.lib.celerylib.loader import configure_celery
50 from rhodecode.lib.celerylib.loader import configure_celery
51 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
51 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
52 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
52 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
53 from rhodecode.lib.exc_tracking import store_exception
53 from rhodecode.lib.exc_tracking import store_exception
54 from rhodecode.subscribers import (
54 from rhodecode.subscribers import (
55 scan_repositories_if_enabled, write_js_routes_if_enabled,
55 scan_repositories_if_enabled, write_js_routes_if_enabled,
56 write_metadata_if_needed, inject_app_settings)
56 write_metadata_if_needed, inject_app_settings)
57
57
58
58
59 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
60
60
61
61
62 def is_http_error(response):
62 def is_http_error(response):
63 # error which should have traceback
63 # error which should have traceback
64 return response.status_code > 499
64 return response.status_code > 499
65
65
66
66
67 def should_load_all():
67 def should_load_all():
68 """
68 """
69 Returns if all application components should be loaded. In some cases it's
69 Returns if all application components should be loaded. In some cases it's
70 desired to skip apps loading for faster shell script execution
70 desired to skip apps loading for faster shell script execution
71 """
71 """
72 return True
72 return True
73
73
74
74
75 def make_pyramid_app(global_config, **settings):
75 def make_pyramid_app(global_config, **settings):
76 """
76 """
77 Constructs the WSGI application based on Pyramid.
77 Constructs the WSGI application based on Pyramid.
78
78
79 Specials:
79 Specials:
80
80
81 * The application can also be integrated like a plugin via the call to
81 * The application can also be integrated like a plugin via the call to
82 `includeme`. This is accompanied with the other utility functions which
82 `includeme`. This is accompanied with the other utility functions which
83 are called. Changing this should be done with great care to not break
83 are called. Changing this should be done with great care to not break
84 cases when these fragments are assembled from another place.
84 cases when these fragments are assembled from another place.
85
85
86 """
86 """
87
87
88 # Allows to use format style "{ENV_NAME}" placeholders in the configuration. It
88 # Allows to use format style "{ENV_NAME}" placeholders in the configuration. It
89 # will be replaced by the value of the environment variable "NAME" in this case.
89 # will be replaced by the value of the environment variable "NAME" in this case.
90 start_time = time.time()
90 start_time = time.time()
91
91
92 debug = asbool(global_config.get('debug'))
92 debug = asbool(global_config.get('debug'))
93 if debug:
93 if debug:
94 enable_debug()
94 enable_debug()
95
95
96 environ = {'ENV_{}'.format(key): value for key, value in os.environ.items()}
96 environ = {'ENV_{}'.format(key): value for key, value in os.environ.items()}
97
97
98 global_config = _substitute_values(global_config, environ)
98 global_config = _substitute_values(global_config, environ)
99 settings = _substitute_values(settings, environ)
99 settings = _substitute_values(settings, environ)
100
100
101 sanitize_settings_and_apply_defaults(global_config, settings)
101 sanitize_settings_and_apply_defaults(global_config, settings)
102
102
103 config = Configurator(settings=settings)
103 config = Configurator(settings=settings)
104
104
105 # Apply compatibility patches
105 # Apply compatibility patches
106 patches.inspect_getargspec()
106 patches.inspect_getargspec()
107
107
108 load_pyramid_environment(global_config, settings)
108 load_pyramid_environment(global_config, settings)
109
109
110 # Static file view comes first
110 # Static file view comes first
111 includeme_first(config)
111 includeme_first(config)
112
112
113 includeme(config)
113 includeme(config)
114
114
115 pyramid_app = config.make_wsgi_app()
115 pyramid_app = config.make_wsgi_app()
116 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
116 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
117 pyramid_app.config = config
117 pyramid_app.config = config
118
118
119 config.configure_celery(global_config['__file__'])
119 config.configure_celery(global_config['__file__'])
120 # creating the app uses a connection - return it after we are done
120 # creating the app uses a connection - return it after we are done
121 meta.Session.remove()
121 meta.Session.remove()
122 total_time = time.time() - start_time
122 total_time = time.time() - start_time
123 log.info('Pyramid app `%s` created and configured in %.2fs',
123 log.info('Pyramid app `%s` created and configured in %.2fs',
124 pyramid_app.func_name, total_time)
124 pyramid_app.func_name, total_time)
125
125
126 return pyramid_app
126 return pyramid_app
127
127
128
128
129 def not_found_view(request):
129 def not_found_view(request):
130 """
130 """
131 This creates the view which should be registered as not-found-view to
131 This creates the view which should be registered as not-found-view to
132 pyramid.
132 pyramid.
133 """
133 """
134
134
135 if not getattr(request, 'vcs_call', None):
135 if not getattr(request, 'vcs_call', None):
136 # handle like regular case with our error_handler
136 # handle like regular case with our error_handler
137 return error_handler(HTTPNotFound(), request)
137 return error_handler(HTTPNotFound(), request)
138
138
139 # handle not found view as a vcs call
139 # handle not found view as a vcs call
140 settings = request.registry.settings
140 settings = request.registry.settings
141 ae_client = getattr(request, 'ae_client', None)
141 ae_client = getattr(request, 'ae_client', None)
142 vcs_app = VCSMiddleware(
142 vcs_app = VCSMiddleware(
143 HTTPNotFound(), request.registry, settings,
143 HTTPNotFound(), request.registry, settings,
144 appenlight_client=ae_client)
144 appenlight_client=ae_client)
145
145
146 return wsgiapp(vcs_app)(None, request)
146 return wsgiapp(vcs_app)(None, request)
147
147
148
148
149 def error_handler(exception, request):
149 def error_handler(exception, request):
150 import rhodecode
150 import rhodecode
151 from rhodecode.lib import helpers
151 from rhodecode.lib import helpers
152
152
153 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
153 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
154
154
155 base_response = HTTPInternalServerError()
155 base_response = HTTPInternalServerError()
156 # prefer original exception for the response since it may have headers set
156 # prefer original exception for the response since it may have headers set
157 if isinstance(exception, HTTPException):
157 if isinstance(exception, HTTPException):
158 base_response = exception
158 base_response = exception
159 elif isinstance(exception, VCSCommunicationError):
159 elif isinstance(exception, VCSCommunicationError):
160 base_response = VCSServerUnavailable()
160 base_response = VCSServerUnavailable()
161
161
162 if is_http_error(base_response):
162 if is_http_error(base_response):
163 log.exception(
163 log.exception(
164 'error occurred handling this request for path: %s', request.path)
164 'error occurred handling this request for path: %s', request.path)
165
165
166 error_explanation = base_response.explanation or str(base_response)
166 error_explanation = base_response.explanation or str(base_response)
167 if base_response.status_code == 404:
167 if base_response.status_code == 404:
168 error_explanation += " Optionally you don't have permission to access this page."
168 error_explanation += " Optionally you don't have permission to access this page."
169 c = AttributeDict()
169 c = AttributeDict()
170 c.error_message = base_response.status
170 c.error_message = base_response.status
171 c.error_explanation = error_explanation
171 c.error_explanation = error_explanation
172 c.visual = AttributeDict()
172 c.visual = AttributeDict()
173
173
174 c.visual.rhodecode_support_url = (
174 c.visual.rhodecode_support_url = (
175 request.registry.settings.get('rhodecode_support_url') or
175 request.registry.settings.get('rhodecode_support_url') or
176 request.route_url('rhodecode_support')
176 request.route_url('rhodecode_support')
177 )
177 )
178 c.redirect_time = 0
178 c.redirect_time = 0
179 c.rhodecode_name = rhodecode_title
179 c.rhodecode_name = rhodecode_title
180 if not c.rhodecode_name:
180 if not c.rhodecode_name:
181 c.rhodecode_name = 'Rhodecode'
181 c.rhodecode_name = 'Rhodecode'
182
182
183 c.causes = []
183 c.causes = []
184 if is_http_error(base_response):
184 if is_http_error(base_response):
185 c.causes.append('Server is overloaded.')
185 c.causes.append('Server is overloaded.')
186 c.causes.append('Server database connection is lost.')
186 c.causes.append('Server database connection is lost.')
187 c.causes.append('Server expected unhandled error.')
187 c.causes.append('Server expected unhandled error.')
188
188
189 if hasattr(base_response, 'causes'):
189 if hasattr(base_response, 'causes'):
190 c.causes = base_response.causes
190 c.causes = base_response.causes
191
191
192 c.messages = helpers.flash.pop_messages(request=request)
192 c.messages = helpers.flash.pop_messages(request=request)
193
193
194 exc_info = sys.exc_info()
194 exc_info = sys.exc_info()
195 c.exception_id = id(exc_info)
195 c.exception_id = id(exc_info)
196 c.show_exception_id = isinstance(base_response, VCSServerUnavailable) \
196 c.show_exception_id = isinstance(base_response, VCSServerUnavailable) \
197 or base_response.status_code > 499
197 or base_response.status_code > 499
198 c.exception_id_url = request.route_url(
198 c.exception_id_url = request.route_url(
199 'admin_settings_exception_tracker_show', exception_id=c.exception_id)
199 'admin_settings_exception_tracker_show', exception_id=c.exception_id)
200
200
201 if c.show_exception_id:
201 if c.show_exception_id:
202 store_exception(c.exception_id, exc_info)
202 store_exception(c.exception_id, exc_info)
203
203
204 response = render_to_response(
204 response = render_to_response(
205 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
205 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
206 response=base_response)
206 response=base_response)
207
207
208 return response
208 return response
209
209
210
210
211 def includeme_first(config):
211 def includeme_first(config):
212 # redirect automatic browser favicon.ico requests to correct place
212 # redirect automatic browser favicon.ico requests to correct place
213 def favicon_redirect(context, request):
213 def favicon_redirect(context, request):
214 return HTTPFound(
214 return HTTPFound(
215 request.static_path('rhodecode:public/images/favicon.ico'))
215 request.static_path('rhodecode:public/images/favicon.ico'))
216
216
217 config.add_view(favicon_redirect, route_name='favicon')
217 config.add_view(favicon_redirect, route_name='favicon')
218 config.add_route('favicon', '/favicon.ico')
218 config.add_route('favicon', '/favicon.ico')
219
219
220 def robots_redirect(context, request):
220 def robots_redirect(context, request):
221 return HTTPFound(
221 return HTTPFound(
222 request.static_path('rhodecode:public/robots.txt'))
222 request.static_path('rhodecode:public/robots.txt'))
223
223
224 config.add_view(robots_redirect, route_name='robots')
224 config.add_view(robots_redirect, route_name='robots')
225 config.add_route('robots', '/robots.txt')
225 config.add_route('robots', '/robots.txt')
226
226
227 config.add_static_view(
227 config.add_static_view(
228 '_static/deform', 'deform:static')
228 '_static/deform', 'deform:static')
229 config.add_static_view(
229 config.add_static_view(
230 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
230 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
231
231
232
232
233 def includeme(config):
233 def includeme(config):
234 log.debug('Initializing main includeme from %s', os.path.basename(__file__))
234 log.debug('Initializing main includeme from %s', os.path.basename(__file__))
235 settings = config.registry.settings
235 settings = config.registry.settings
236 config.set_request_factory(Request)
236 config.set_request_factory(Request)
237
237
238 # plugin information
238 # plugin information
239 config.registry.rhodecode_plugins = collections.OrderedDict()
239 config.registry.rhodecode_plugins = collections.OrderedDict()
240
240
241 config.add_directive(
241 config.add_directive(
242 'register_rhodecode_plugin', register_rhodecode_plugin)
242 'register_rhodecode_plugin', register_rhodecode_plugin)
243
243
244 config.add_directive('configure_celery', configure_celery)
244 config.add_directive('configure_celery', configure_celery)
245
245
246 if asbool(settings.get('appenlight', 'false')):
246 if asbool(settings.get('appenlight', 'false')):
247 config.include('appenlight_client.ext.pyramid_tween')
247 config.include('appenlight_client.ext.pyramid_tween')
248
248
249 load_all = should_load_all()
249 load_all = should_load_all()
250
250
251 # Includes which are required. The application would fail without them.
251 # Includes which are required. The application would fail without them.
252 config.include('pyramid_mako')
252 config.include('pyramid_mako')
253 config.include('pyramid_beaker')
253 config.include('pyramid_beaker')
254 config.include('rhodecode.lib.rc_cache')
254 config.include('rhodecode.lib.rc_cache')
255
255
256 config.include('rhodecode.apps._base.navigation')
256 config.include('rhodecode.apps._base.navigation')
257 config.include('rhodecode.apps._base.subscribers')
257 config.include('rhodecode.apps._base.subscribers')
258 config.include('rhodecode.tweens')
258 config.include('rhodecode.tweens')
259
259
260 config.include('rhodecode.integrations')
260 config.include('rhodecode.integrations')
261 config.include('rhodecode.authentication')
261 config.include('rhodecode.authentication')
262
262
263 if load_all:
263 if load_all:
264 from rhodecode.authentication import discover_legacy_plugins
264 from rhodecode.authentication import discover_legacy_plugins
265 # load CE authentication plugins
265 # load CE authentication plugins
266 config.include('rhodecode.authentication.plugins.auth_crowd')
266 config.include('rhodecode.authentication.plugins.auth_crowd')
267 config.include('rhodecode.authentication.plugins.auth_headers')
267 config.include('rhodecode.authentication.plugins.auth_headers')
268 config.include('rhodecode.authentication.plugins.auth_jasig_cas')
268 config.include('rhodecode.authentication.plugins.auth_jasig_cas')
269 config.include('rhodecode.authentication.plugins.auth_ldap')
269 config.include('rhodecode.authentication.plugins.auth_ldap')
270 config.include('rhodecode.authentication.plugins.auth_pam')
270 config.include('rhodecode.authentication.plugins.auth_pam')
271 config.include('rhodecode.authentication.plugins.auth_rhodecode')
271 config.include('rhodecode.authentication.plugins.auth_rhodecode')
272 config.include('rhodecode.authentication.plugins.auth_token')
272 config.include('rhodecode.authentication.plugins.auth_token')
273
273
274 # Auto discover authentication plugins and include their configuration.
274 # Auto discover authentication plugins and include their configuration.
275 discover_legacy_plugins(config)
275 discover_legacy_plugins(config)
276
276
277 # apps
277 # apps
278 config.include('rhodecode.apps._base')
278 config.include('rhodecode.apps._base')
279
279
280 if load_all:
280 if load_all:
281 config.include('rhodecode.apps.ops')
281 config.include('rhodecode.apps.ops')
282 config.include('rhodecode.apps.admin')
282 config.include('rhodecode.apps.admin')
283 config.include('rhodecode.apps.channelstream')
283 config.include('rhodecode.apps.channelstream')
284 config.include('rhodecode.apps.upload_store')
284 config.include('rhodecode.apps.login')
285 config.include('rhodecode.apps.login')
285 config.include('rhodecode.apps.home')
286 config.include('rhodecode.apps.home')
286 config.include('rhodecode.apps.journal')
287 config.include('rhodecode.apps.journal')
287 config.include('rhodecode.apps.repository')
288 config.include('rhodecode.apps.repository')
288 config.include('rhodecode.apps.repo_group')
289 config.include('rhodecode.apps.repo_group')
289 config.include('rhodecode.apps.user_group')
290 config.include('rhodecode.apps.user_group')
290 config.include('rhodecode.apps.search')
291 config.include('rhodecode.apps.search')
291 config.include('rhodecode.apps.user_profile')
292 config.include('rhodecode.apps.user_profile')
292 config.include('rhodecode.apps.user_group_profile')
293 config.include('rhodecode.apps.user_group_profile')
293 config.include('rhodecode.apps.my_account')
294 config.include('rhodecode.apps.my_account')
294 config.include('rhodecode.apps.svn_support')
295 config.include('rhodecode.apps.svn_support')
295 config.include('rhodecode.apps.ssh_support')
296 config.include('rhodecode.apps.ssh_support')
296 config.include('rhodecode.apps.gist')
297 config.include('rhodecode.apps.gist')
297 config.include('rhodecode.apps.debug_style')
298 config.include('rhodecode.apps.debug_style')
298 config.include('rhodecode.api')
299 config.include('rhodecode.api')
299
300
300 config.add_route('rhodecode_support', 'https://rhodecode.com/help/', static=True)
301 config.add_route('rhodecode_support', 'https://rhodecode.com/help/', static=True)
301 config.add_translation_dirs('rhodecode:i18n/')
302 config.add_translation_dirs('rhodecode:i18n/')
302 settings['default_locale_name'] = settings.get('lang', 'en')
303 settings['default_locale_name'] = settings.get('lang', 'en')
303
304
304 # Add subscribers.
305 # Add subscribers.
305 config.add_subscriber(inject_app_settings,
306 config.add_subscriber(inject_app_settings,
306 pyramid.events.ApplicationCreated)
307 pyramid.events.ApplicationCreated)
307 config.add_subscriber(scan_repositories_if_enabled,
308 config.add_subscriber(scan_repositories_if_enabled,
308 pyramid.events.ApplicationCreated)
309 pyramid.events.ApplicationCreated)
309 config.add_subscriber(write_metadata_if_needed,
310 config.add_subscriber(write_metadata_if_needed,
310 pyramid.events.ApplicationCreated)
311 pyramid.events.ApplicationCreated)
311 config.add_subscriber(write_js_routes_if_enabled,
312 config.add_subscriber(write_js_routes_if_enabled,
312 pyramid.events.ApplicationCreated)
313 pyramid.events.ApplicationCreated)
313
314
314 # request custom methods
315 # request custom methods
315 config.add_request_method(
316 config.add_request_method(
316 'rhodecode.lib.partial_renderer.get_partial_renderer',
317 'rhodecode.lib.partial_renderer.get_partial_renderer',
317 'get_partial_renderer')
318 'get_partial_renderer')
318
319
319 # Set the authorization policy.
320 # Set the authorization policy.
320 authz_policy = ACLAuthorizationPolicy()
321 authz_policy = ACLAuthorizationPolicy()
321 config.set_authorization_policy(authz_policy)
322 config.set_authorization_policy(authz_policy)
322
323
323 # Set the default renderer for HTML templates to mako.
324 # Set the default renderer for HTML templates to mako.
324 config.add_mako_renderer('.html')
325 config.add_mako_renderer('.html')
325
326
326 config.add_renderer(
327 config.add_renderer(
327 name='json_ext',
328 name='json_ext',
328 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
329 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
329
330
330 # include RhodeCode plugins
331 # include RhodeCode plugins
331 includes = aslist(settings.get('rhodecode.includes', []))
332 includes = aslist(settings.get('rhodecode.includes', []))
332 for inc in includes:
333 for inc in includes:
333 config.include(inc)
334 config.include(inc)
334
335
335 # custom not found view, if our pyramid app doesn't know how to handle
336 # custom not found view, if our pyramid app doesn't know how to handle
336 # the request pass it to potential VCS handling ap
337 # the request pass it to potential VCS handling ap
337 config.add_notfound_view(not_found_view)
338 config.add_notfound_view(not_found_view)
338 if not settings.get('debugtoolbar.enabled', False):
339 if not settings.get('debugtoolbar.enabled', False):
339 # disabled debugtoolbar handle all exceptions via the error_handlers
340 # disabled debugtoolbar handle all exceptions via the error_handlers
340 config.add_view(error_handler, context=Exception)
341 config.add_view(error_handler, context=Exception)
341
342
342 # all errors including 403/404/50X
343 # all errors including 403/404/50X
343 config.add_view(error_handler, context=HTTPError)
344 config.add_view(error_handler, context=HTTPError)
344
345
345
346
346 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
347 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
347 """
348 """
348 Apply outer WSGI middlewares around the application.
349 Apply outer WSGI middlewares around the application.
349 """
350 """
350 registry = config.registry
351 registry = config.registry
351 settings = registry.settings
352 settings = registry.settings
352
353
353 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
354 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
354 pyramid_app = HttpsFixup(pyramid_app, settings)
355 pyramid_app = HttpsFixup(pyramid_app, settings)
355
356
356 pyramid_app, _ae_client = wrap_in_appenlight_if_enabled(
357 pyramid_app, _ae_client = wrap_in_appenlight_if_enabled(
357 pyramid_app, settings)
358 pyramid_app, settings)
358 registry.ae_client = _ae_client
359 registry.ae_client = _ae_client
359
360
360 if settings['gzip_responses']:
361 if settings['gzip_responses']:
361 pyramid_app = make_gzip_middleware(
362 pyramid_app = make_gzip_middleware(
362 pyramid_app, settings, compress_level=1)
363 pyramid_app, settings, compress_level=1)
363
364
364 # this should be the outer most middleware in the wsgi stack since
365 # this should be the outer most middleware in the wsgi stack since
365 # middleware like Routes make database calls
366 # middleware like Routes make database calls
366 def pyramid_app_with_cleanup(environ, start_response):
367 def pyramid_app_with_cleanup(environ, start_response):
367 try:
368 try:
368 return pyramid_app(environ, start_response)
369 return pyramid_app(environ, start_response)
369 finally:
370 finally:
370 # Dispose current database session and rollback uncommitted
371 # Dispose current database session and rollback uncommitted
371 # transactions.
372 # transactions.
372 meta.Session.remove()
373 meta.Session.remove()
373
374
374 # In a single threaded mode server, on non sqlite db we should have
375 # In a single threaded mode server, on non sqlite db we should have
375 # '0 Current Checked out connections' at the end of a request,
376 # '0 Current Checked out connections' at the end of a request,
376 # if not, then something, somewhere is leaving a connection open
377 # if not, then something, somewhere is leaving a connection open
377 pool = meta.Base.metadata.bind.engine.pool
378 pool = meta.Base.metadata.bind.engine.pool
378 log.debug('sa pool status: %s', pool.status())
379 log.debug('sa pool status: %s', pool.status())
379 log.debug('Request processing finalized')
380 log.debug('Request processing finalized')
380
381
381 return pyramid_app_with_cleanup
382 return pyramid_app_with_cleanup
382
383
383
384
384 def sanitize_settings_and_apply_defaults(global_config, settings):
385 def sanitize_settings_and_apply_defaults(global_config, settings):
385 """
386 """
386 Applies settings defaults and does all type conversion.
387 Applies settings defaults and does all type conversion.
387
388
388 We would move all settings parsing and preparation into this place, so that
389 We would move all settings parsing and preparation into this place, so that
389 we have only one place left which deals with this part. The remaining parts
390 we have only one place left which deals with this part. The remaining parts
390 of the application would start to rely fully on well prepared settings.
391 of the application would start to rely fully on well prepared settings.
391
392
392 This piece would later be split up per topic to avoid a big fat monster
393 This piece would later be split up per topic to avoid a big fat monster
393 function.
394 function.
394 """
395 """
395
396
396 settings.setdefault('rhodecode.edition', 'Community Edition')
397 settings.setdefault('rhodecode.edition', 'Community Edition')
397
398
398 if 'mako.default_filters' not in settings:
399 if 'mako.default_filters' not in settings:
399 # set custom default filters if we don't have it defined
400 # set custom default filters if we don't have it defined
400 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
401 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
401 settings['mako.default_filters'] = 'h_filter'
402 settings['mako.default_filters'] = 'h_filter'
402
403
403 if 'mako.directories' not in settings:
404 if 'mako.directories' not in settings:
404 mako_directories = settings.setdefault('mako.directories', [
405 mako_directories = settings.setdefault('mako.directories', [
405 # Base templates of the original application
406 # Base templates of the original application
406 'rhodecode:templates',
407 'rhodecode:templates',
407 ])
408 ])
408 log.debug(
409 log.debug(
409 "Using the following Mako template directories: %s",
410 "Using the following Mako template directories: %s",
410 mako_directories)
411 mako_directories)
411
412
412 # Default includes, possible to change as a user
413 # Default includes, possible to change as a user
413 pyramid_includes = settings.setdefault('pyramid.includes', [
414 pyramid_includes = settings.setdefault('pyramid.includes', [
414 'rhodecode.lib.middleware.request_wrapper',
415 'rhodecode.lib.middleware.request_wrapper',
415 ])
416 ])
416 log.debug(
417 log.debug(
417 "Using the following pyramid.includes: %s",
418 "Using the following pyramid.includes: %s",
418 pyramid_includes)
419 pyramid_includes)
419
420
420 # TODO: johbo: Re-think this, usually the call to config.include
421 # TODO: johbo: Re-think this, usually the call to config.include
421 # should allow to pass in a prefix.
422 # should allow to pass in a prefix.
422 settings.setdefault('rhodecode.api.url', '/_admin/api')
423 settings.setdefault('rhodecode.api.url', '/_admin/api')
423 settings.setdefault('__file__', global_config.get('__file__'))
424 settings.setdefault('__file__', global_config.get('__file__'))
424
425
425 # Sanitize generic settings.
426 # Sanitize generic settings.
426 _list_setting(settings, 'default_encoding', 'UTF-8')
427 _list_setting(settings, 'default_encoding', 'UTF-8')
427 _bool_setting(settings, 'is_test', 'false')
428 _bool_setting(settings, 'is_test', 'false')
428 _bool_setting(settings, 'gzip_responses', 'false')
429 _bool_setting(settings, 'gzip_responses', 'false')
429
430
430 # Call split out functions that sanitize settings for each topic.
431 # Call split out functions that sanitize settings for each topic.
431 _sanitize_appenlight_settings(settings)
432 _sanitize_appenlight_settings(settings)
432 _sanitize_vcs_settings(settings)
433 _sanitize_vcs_settings(settings)
433 _sanitize_cache_settings(settings)
434 _sanitize_cache_settings(settings)
434
435
435 # configure instance id
436 # configure instance id
436 config_utils.set_instance_id(settings)
437 config_utils.set_instance_id(settings)
437
438
438 return settings
439 return settings
439
440
440
441
441 def enable_debug():
442 def enable_debug():
442 """
443 """
443 Helper to enable debug on running instance
444 Helper to enable debug on running instance
444 :return:
445 :return:
445 """
446 """
446 import tempfile
447 import tempfile
447 import textwrap
448 import textwrap
448 import logging.config
449 import logging.config
449
450
450 ini_template = textwrap.dedent("""
451 ini_template = textwrap.dedent("""
451 #####################################
452 #####################################
452 ### DEBUG LOGGING CONFIGURATION ####
453 ### DEBUG LOGGING CONFIGURATION ####
453 #####################################
454 #####################################
454 [loggers]
455 [loggers]
455 keys = root, sqlalchemy, beaker, celery, rhodecode, ssh_wrapper
456 keys = root, sqlalchemy, beaker, celery, rhodecode, ssh_wrapper
456
457
457 [handlers]
458 [handlers]
458 keys = console, console_sql
459 keys = console, console_sql
459
460
460 [formatters]
461 [formatters]
461 keys = generic, color_formatter, color_formatter_sql
462 keys = generic, color_formatter, color_formatter_sql
462
463
463 #############
464 #############
464 ## LOGGERS ##
465 ## LOGGERS ##
465 #############
466 #############
466 [logger_root]
467 [logger_root]
467 level = NOTSET
468 level = NOTSET
468 handlers = console
469 handlers = console
469
470
470 [logger_sqlalchemy]
471 [logger_sqlalchemy]
471 level = INFO
472 level = INFO
472 handlers = console_sql
473 handlers = console_sql
473 qualname = sqlalchemy.engine
474 qualname = sqlalchemy.engine
474 propagate = 0
475 propagate = 0
475
476
476 [logger_beaker]
477 [logger_beaker]
477 level = DEBUG
478 level = DEBUG
478 handlers =
479 handlers =
479 qualname = beaker.container
480 qualname = beaker.container
480 propagate = 1
481 propagate = 1
481
482
482 [logger_rhodecode]
483 [logger_rhodecode]
483 level = DEBUG
484 level = DEBUG
484 handlers =
485 handlers =
485 qualname = rhodecode
486 qualname = rhodecode
486 propagate = 1
487 propagate = 1
487
488
488 [logger_ssh_wrapper]
489 [logger_ssh_wrapper]
489 level = DEBUG
490 level = DEBUG
490 handlers =
491 handlers =
491 qualname = ssh_wrapper
492 qualname = ssh_wrapper
492 propagate = 1
493 propagate = 1
493
494
494 [logger_celery]
495 [logger_celery]
495 level = DEBUG
496 level = DEBUG
496 handlers =
497 handlers =
497 qualname = celery
498 qualname = celery
498
499
499
500
500 ##############
501 ##############
501 ## HANDLERS ##
502 ## HANDLERS ##
502 ##############
503 ##############
503
504
504 [handler_console]
505 [handler_console]
505 class = StreamHandler
506 class = StreamHandler
506 args = (sys.stderr, )
507 args = (sys.stderr, )
507 level = DEBUG
508 level = DEBUG
508 formatter = color_formatter
509 formatter = color_formatter
509
510
510 [handler_console_sql]
511 [handler_console_sql]
511 # "level = DEBUG" logs SQL queries and results.
512 # "level = DEBUG" logs SQL queries and results.
512 # "level = INFO" logs SQL queries.
513 # "level = INFO" logs SQL queries.
513 # "level = WARN" logs neither. (Recommended for production systems.)
514 # "level = WARN" logs neither. (Recommended for production systems.)
514 class = StreamHandler
515 class = StreamHandler
515 args = (sys.stderr, )
516 args = (sys.stderr, )
516 level = WARN
517 level = WARN
517 formatter = color_formatter_sql
518 formatter = color_formatter_sql
518
519
519 ################
520 ################
520 ## FORMATTERS ##
521 ## FORMATTERS ##
521 ################
522 ################
522
523
523 [formatter_generic]
524 [formatter_generic]
524 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
525 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
525 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | %(req_id)s
526 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | %(req_id)s
526 datefmt = %Y-%m-%d %H:%M:%S
527 datefmt = %Y-%m-%d %H:%M:%S
527
528
528 [formatter_color_formatter]
529 [formatter_color_formatter]
529 class = rhodecode.lib.logging_formatter.ColorRequestTrackingFormatter
530 class = rhodecode.lib.logging_formatter.ColorRequestTrackingFormatter
530 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | %(req_id)s
531 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | %(req_id)s
531 datefmt = %Y-%m-%d %H:%M:%S
532 datefmt = %Y-%m-%d %H:%M:%S
532
533
533 [formatter_color_formatter_sql]
534 [formatter_color_formatter_sql]
534 class = rhodecode.lib.logging_formatter.ColorFormatterSql
535 class = rhodecode.lib.logging_formatter.ColorFormatterSql
535 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
536 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
536 datefmt = %Y-%m-%d %H:%M:%S
537 datefmt = %Y-%m-%d %H:%M:%S
537 """)
538 """)
538
539
539 with tempfile.NamedTemporaryFile(prefix='rc_debug_logging_', suffix='.ini',
540 with tempfile.NamedTemporaryFile(prefix='rc_debug_logging_', suffix='.ini',
540 delete=False) as f:
541 delete=False) as f:
541 log.info('Saved Temporary DEBUG config at %s', f.name)
542 log.info('Saved Temporary DEBUG config at %s', f.name)
542 f.write(ini_template)
543 f.write(ini_template)
543
544
544 logging.config.fileConfig(f.name)
545 logging.config.fileConfig(f.name)
545 log.debug('DEBUG MODE ON')
546 log.debug('DEBUG MODE ON')
546 os.remove(f.name)
547 os.remove(f.name)
547
548
548
549
549 def _sanitize_appenlight_settings(settings):
550 def _sanitize_appenlight_settings(settings):
550 _bool_setting(settings, 'appenlight', 'false')
551 _bool_setting(settings, 'appenlight', 'false')
551
552
552
553
553 def _sanitize_vcs_settings(settings):
554 def _sanitize_vcs_settings(settings):
554 """
555 """
555 Applies settings defaults and does type conversion for all VCS related
556 Applies settings defaults and does type conversion for all VCS related
556 settings.
557 settings.
557 """
558 """
558 _string_setting(settings, 'vcs.svn.compatible_version', '')
559 _string_setting(settings, 'vcs.svn.compatible_version', '')
559 _string_setting(settings, 'git_rev_filter', '--all')
560 _string_setting(settings, 'git_rev_filter', '--all')
560 _string_setting(settings, 'vcs.hooks.protocol', 'http')
561 _string_setting(settings, 'vcs.hooks.protocol', 'http')
561 _string_setting(settings, 'vcs.hooks.host', '127.0.0.1')
562 _string_setting(settings, 'vcs.hooks.host', '127.0.0.1')
562 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
563 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
563 _string_setting(settings, 'vcs.server', '')
564 _string_setting(settings, 'vcs.server', '')
564 _string_setting(settings, 'vcs.server.log_level', 'debug')
565 _string_setting(settings, 'vcs.server.log_level', 'debug')
565 _string_setting(settings, 'vcs.server.protocol', 'http')
566 _string_setting(settings, 'vcs.server.protocol', 'http')
566 _bool_setting(settings, 'startup.import_repos', 'false')
567 _bool_setting(settings, 'startup.import_repos', 'false')
567 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
568 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
568 _bool_setting(settings, 'vcs.server.enable', 'true')
569 _bool_setting(settings, 'vcs.server.enable', 'true')
569 _bool_setting(settings, 'vcs.start_server', 'false')
570 _bool_setting(settings, 'vcs.start_server', 'false')
570 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
571 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
571 _int_setting(settings, 'vcs.connection_timeout', 3600)
572 _int_setting(settings, 'vcs.connection_timeout', 3600)
572
573
573 # Support legacy values of vcs.scm_app_implementation. Legacy
574 # Support legacy values of vcs.scm_app_implementation. Legacy
574 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http', or
575 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http', or
575 # disabled since 4.13 'vcsserver.scm_app' which is now mapped to 'http'.
576 # disabled since 4.13 'vcsserver.scm_app' which is now mapped to 'http'.
576 scm_app_impl = settings['vcs.scm_app_implementation']
577 scm_app_impl = settings['vcs.scm_app_implementation']
577 if scm_app_impl in ['rhodecode.lib.middleware.utils.scm_app_http', 'vcsserver.scm_app']:
578 if scm_app_impl in ['rhodecode.lib.middleware.utils.scm_app_http', 'vcsserver.scm_app']:
578 settings['vcs.scm_app_implementation'] = 'http'
579 settings['vcs.scm_app_implementation'] = 'http'
579
580
580
581
581 def _sanitize_cache_settings(settings):
582 def _sanitize_cache_settings(settings):
582 temp_store = tempfile.gettempdir()
583 temp_store = tempfile.gettempdir()
583 default_cache_dir = os.path.join(temp_store, 'rc_cache')
584 default_cache_dir = os.path.join(temp_store, 'rc_cache')
584
585
585 # save default, cache dir, and use it for all backends later.
586 # save default, cache dir, and use it for all backends later.
586 default_cache_dir = _string_setting(
587 default_cache_dir = _string_setting(
587 settings,
588 settings,
588 'cache_dir',
589 'cache_dir',
589 default_cache_dir, lower=False, default_when_empty=True)
590 default_cache_dir, lower=False, default_when_empty=True)
590
591
591 # ensure we have our dir created
592 # ensure we have our dir created
592 if not os.path.isdir(default_cache_dir):
593 if not os.path.isdir(default_cache_dir):
593 os.makedirs(default_cache_dir, mode=0o755)
594 os.makedirs(default_cache_dir, mode=0o755)
594
595
595 # exception store cache
596 # exception store cache
596 _string_setting(
597 _string_setting(
597 settings,
598 settings,
598 'exception_tracker.store_path',
599 'exception_tracker.store_path',
599 temp_store, lower=False, default_when_empty=True)
600 temp_store, lower=False, default_when_empty=True)
600
601
601 # cache_perms
602 # cache_perms
602 _string_setting(
603 _string_setting(
603 settings,
604 settings,
604 'rc_cache.cache_perms.backend',
605 'rc_cache.cache_perms.backend',
605 'dogpile.cache.rc.file_namespace', lower=False)
606 'dogpile.cache.rc.file_namespace', lower=False)
606 _int_setting(
607 _int_setting(
607 settings,
608 settings,
608 'rc_cache.cache_perms.expiration_time',
609 'rc_cache.cache_perms.expiration_time',
609 60)
610 60)
610 _string_setting(
611 _string_setting(
611 settings,
612 settings,
612 'rc_cache.cache_perms.arguments.filename',
613 'rc_cache.cache_perms.arguments.filename',
613 os.path.join(default_cache_dir, 'rc_cache_1'), lower=False)
614 os.path.join(default_cache_dir, 'rc_cache_1'), lower=False)
614
615
615 # cache_repo
616 # cache_repo
616 _string_setting(
617 _string_setting(
617 settings,
618 settings,
618 'rc_cache.cache_repo.backend',
619 'rc_cache.cache_repo.backend',
619 'dogpile.cache.rc.file_namespace', lower=False)
620 'dogpile.cache.rc.file_namespace', lower=False)
620 _int_setting(
621 _int_setting(
621 settings,
622 settings,
622 'rc_cache.cache_repo.expiration_time',
623 'rc_cache.cache_repo.expiration_time',
623 60)
624 60)
624 _string_setting(
625 _string_setting(
625 settings,
626 settings,
626 'rc_cache.cache_repo.arguments.filename',
627 'rc_cache.cache_repo.arguments.filename',
627 os.path.join(default_cache_dir, 'rc_cache_2'), lower=False)
628 os.path.join(default_cache_dir, 'rc_cache_2'), lower=False)
628
629
629 # cache_license
630 # cache_license
630 _string_setting(
631 _string_setting(
631 settings,
632 settings,
632 'rc_cache.cache_license.backend',
633 'rc_cache.cache_license.backend',
633 'dogpile.cache.rc.file_namespace', lower=False)
634 'dogpile.cache.rc.file_namespace', lower=False)
634 _int_setting(
635 _int_setting(
635 settings,
636 settings,
636 'rc_cache.cache_license.expiration_time',
637 'rc_cache.cache_license.expiration_time',
637 5*60)
638 5*60)
638 _string_setting(
639 _string_setting(
639 settings,
640 settings,
640 'rc_cache.cache_license.arguments.filename',
641 'rc_cache.cache_license.arguments.filename',
641 os.path.join(default_cache_dir, 'rc_cache_3'), lower=False)
642 os.path.join(default_cache_dir, 'rc_cache_3'), lower=False)
642
643
643 # cache_repo_longterm memory, 96H
644 # cache_repo_longterm memory, 96H
644 _string_setting(
645 _string_setting(
645 settings,
646 settings,
646 'rc_cache.cache_repo_longterm.backend',
647 'rc_cache.cache_repo_longterm.backend',
647 'dogpile.cache.rc.memory_lru', lower=False)
648 'dogpile.cache.rc.memory_lru', lower=False)
648 _int_setting(
649 _int_setting(
649 settings,
650 settings,
650 'rc_cache.cache_repo_longterm.expiration_time',
651 'rc_cache.cache_repo_longterm.expiration_time',
651 345600)
652 345600)
652 _int_setting(
653 _int_setting(
653 settings,
654 settings,
654 'rc_cache.cache_repo_longterm.max_size',
655 'rc_cache.cache_repo_longterm.max_size',
655 10000)
656 10000)
656
657
657 # sql_cache_short
658 # sql_cache_short
658 _string_setting(
659 _string_setting(
659 settings,
660 settings,
660 'rc_cache.sql_cache_short.backend',
661 'rc_cache.sql_cache_short.backend',
661 'dogpile.cache.rc.memory_lru', lower=False)
662 'dogpile.cache.rc.memory_lru', lower=False)
662 _int_setting(
663 _int_setting(
663 settings,
664 settings,
664 'rc_cache.sql_cache_short.expiration_time',
665 'rc_cache.sql_cache_short.expiration_time',
665 30)
666 30)
666 _int_setting(
667 _int_setting(
667 settings,
668 settings,
668 'rc_cache.sql_cache_short.max_size',
669 'rc_cache.sql_cache_short.max_size',
669 10000)
670 10000)
670
671
671
672
672 def _int_setting(settings, name, default):
673 def _int_setting(settings, name, default):
673 settings[name] = int(settings.get(name, default))
674 settings[name] = int(settings.get(name, default))
674 return settings[name]
675 return settings[name]
675
676
676
677
677 def _bool_setting(settings, name, default):
678 def _bool_setting(settings, name, default):
678 input_val = settings.get(name, default)
679 input_val = settings.get(name, default)
679 if isinstance(input_val, unicode):
680 if isinstance(input_val, unicode):
680 input_val = input_val.encode('utf8')
681 input_val = input_val.encode('utf8')
681 settings[name] = asbool(input_val)
682 settings[name] = asbool(input_val)
682 return settings[name]
683 return settings[name]
683
684
684
685
685 def _list_setting(settings, name, default):
686 def _list_setting(settings, name, default):
686 raw_value = settings.get(name, default)
687 raw_value = settings.get(name, default)
687
688
688 old_separator = ','
689 old_separator = ','
689 if old_separator in raw_value:
690 if old_separator in raw_value:
690 # If we get a comma separated list, pass it to our own function.
691 # If we get a comma separated list, pass it to our own function.
691 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
692 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
692 else:
693 else:
693 # Otherwise we assume it uses pyramids space/newline separation.
694 # Otherwise we assume it uses pyramids space/newline separation.
694 settings[name] = aslist(raw_value)
695 settings[name] = aslist(raw_value)
695 return settings[name]
696 return settings[name]
696
697
697
698
698 def _string_setting(settings, name, default, lower=True, default_when_empty=False):
699 def _string_setting(settings, name, default, lower=True, default_when_empty=False):
699 value = settings.get(name, default)
700 value = settings.get(name, default)
700
701
701 if default_when_empty and not value:
702 if default_when_empty and not value:
702 # use default value when value is empty
703 # use default value when value is empty
703 value = default
704 value = default
704
705
705 if lower:
706 if lower:
706 value = value.lower()
707 value = value.lower()
707 settings[name] = value
708 settings[name] = value
708 return settings[name]
709 return settings[name]
709
710
710
711
711 def _substitute_values(mapping, substitutions):
712 def _substitute_values(mapping, substitutions):
712 result = {}
713 result = {}
713
714
714 try:
715 try:
715 for key, value in mapping.items():
716 for key, value in mapping.items():
716 # initialize without substitution first
717 # initialize without substitution first
717 result[key] = value
718 result[key] = value
718
719
719 # Note: Cannot use regular replacements, since they would clash
720 # Note: Cannot use regular replacements, since they would clash
720 # with the implementation of ConfigParser. Using "format" instead.
721 # with the implementation of ConfigParser. Using "format" instead.
721 try:
722 try:
722 result[key] = value.format(**substitutions)
723 result[key] = value.format(**substitutions)
723 except KeyError as e:
724 except KeyError as e:
724 env_var = '{}'.format(e.args[0])
725 env_var = '{}'.format(e.args[0])
725
726
726 msg = 'Failed to substitute: `{key}={{{var}}}` with environment entry. ' \
727 msg = 'Failed to substitute: `{key}={{{var}}}` with environment entry. ' \
727 'Make sure your environment has {var} set, or remove this ' \
728 'Make sure your environment has {var} set, or remove this ' \
728 'variable from config file'.format(key=key, var=env_var)
729 'variable from config file'.format(key=key, var=env_var)
729
730
730 if env_var.startswith('ENV_'):
731 if env_var.startswith('ENV_'):
731 raise ValueError(msg)
732 raise ValueError(msg)
732 else:
733 else:
733 log.warning(msg)
734 log.warning(msg)
734
735
735 except ValueError as e:
736 except ValueError as e:
736 log.warning('Failed to substitute ENV variable: %s', e)
737 log.warning('Failed to substitute ENV variable: %s', e)
737 result = mapping
738 result = mapping
738
739
739 return result
740 return result
@@ -1,360 +1,362 b''
1
1
2 /******************************************************************************
2 /******************************************************************************
3 * *
3 * *
4 * DO NOT CHANGE THIS FILE MANUALLY *
4 * DO NOT CHANGE THIS FILE MANUALLY *
5 * *
5 * *
6 * *
6 * *
7 * This file is automatically generated when the app starts up with *
7 * This file is automatically generated when the app starts up with *
8 * generate_js_files = true *
8 * generate_js_files = true *
9 * *
9 * *
10 * To add a route here pass jsroute=True to the route definition in the app *
10 * To add a route here pass jsroute=True to the route definition in the app *
11 * *
11 * *
12 ******************************************************************************/
12 ******************************************************************************/
13 function registerRCRoutes() {
13 function registerRCRoutes() {
14 // routes registration
14 // routes registration
15 pyroutes.register('favicon', '/favicon.ico', []);
15 pyroutes.register('favicon', '/favicon.ico', []);
16 pyroutes.register('robots', '/robots.txt', []);
16 pyroutes.register('robots', '/robots.txt', []);
17 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
17 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
18 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
18 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
19 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
19 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
20 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
20 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
21 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
21 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
22 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
22 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
23 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
23 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
24 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
24 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
25 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
25 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
26 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
26 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
27 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
27 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
28 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
28 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
29 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
29 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
30 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
30 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
31 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
31 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
32 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
32 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
33 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
33 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
34 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
34 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
35 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
35 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
36 pyroutes.register('ops_ping_legacy', '/_admin/ping', []);
36 pyroutes.register('ops_ping_legacy', '/_admin/ping', []);
37 pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []);
37 pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []);
38 pyroutes.register('admin_home', '/_admin', []);
38 pyroutes.register('admin_home', '/_admin', []);
39 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
39 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
40 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
40 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
41 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
41 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
42 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
42 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
43 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
43 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
44 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
44 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
45 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
45 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
46 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
46 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
47 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
47 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
48 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
48 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
49 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions/delete', []);
49 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions/delete', []);
50 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
50 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
51 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
51 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
52 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
52 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
53 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
53 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
54 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
54 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
55 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
55 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
56 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
56 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
57 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
57 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
58 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
58 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
59 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
59 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
60 pyroutes.register('admin_settings', '/_admin/settings', []);
60 pyroutes.register('admin_settings', '/_admin/settings', []);
61 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
61 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
62 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
62 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
63 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
63 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
64 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
64 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
65 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
65 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
66 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
66 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
67 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
67 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
68 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
68 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
69 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
69 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
70 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
70 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
71 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
71 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
72 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
72 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
73 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
73 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
74 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
74 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
75 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
75 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
76 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
76 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
77 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
77 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
78 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
78 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
79 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
79 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
80 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
80 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
81 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
81 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
82 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
82 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
83 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
83 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
84 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
84 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
85 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
85 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
86 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
86 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
87 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
87 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
88 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
88 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
89 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
89 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
90 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
90 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
91 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
91 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
92 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
92 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
93 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
93 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
94 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
94 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
95 pyroutes.register('users', '/_admin/users', []);
95 pyroutes.register('users', '/_admin/users', []);
96 pyroutes.register('users_data', '/_admin/users_data', []);
96 pyroutes.register('users_data', '/_admin/users_data', []);
97 pyroutes.register('users_create', '/_admin/users/create', []);
97 pyroutes.register('users_create', '/_admin/users/create', []);
98 pyroutes.register('users_new', '/_admin/users/new', []);
98 pyroutes.register('users_new', '/_admin/users/new', []);
99 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
99 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
100 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
100 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
101 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
101 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
102 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
102 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
103 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
103 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
104 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
104 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
105 pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']);
105 pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']);
106 pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']);
106 pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']);
107 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
107 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
108 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
108 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
109 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
109 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
110 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
110 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
111 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
111 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
112 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
112 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
113 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
113 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
114 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
114 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
115 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
115 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
116 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
116 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
117 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
117 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
118 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
118 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
119 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
119 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
120 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
120 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
121 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
121 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
122 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
122 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
123 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
123 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
124 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
124 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
125 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
125 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
126 pyroutes.register('user_groups', '/_admin/user_groups', []);
126 pyroutes.register('user_groups', '/_admin/user_groups', []);
127 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
127 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
128 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
128 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
129 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
129 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
130 pyroutes.register('repos', '/_admin/repos', []);
130 pyroutes.register('repos', '/_admin/repos', []);
131 pyroutes.register('repo_new', '/_admin/repos/new', []);
131 pyroutes.register('repo_new', '/_admin/repos/new', []);
132 pyroutes.register('repo_create', '/_admin/repos/create', []);
132 pyroutes.register('repo_create', '/_admin/repos/create', []);
133 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
133 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
134 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
134 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
135 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
135 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
136 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
136 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
137 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
137 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
138 pyroutes.register('channelstream_proxy', '/_channelstream', []);
138 pyroutes.register('channelstream_proxy', '/_channelstream', []);
139 pyroutes.register('upload_file', '/_file_store/upload', []);
140 pyroutes.register('download_file', '/_file_store/download/%(fid)s', ['fid']);
139 pyroutes.register('logout', '/_admin/logout', []);
141 pyroutes.register('logout', '/_admin/logout', []);
140 pyroutes.register('reset_password', '/_admin/password_reset', []);
142 pyroutes.register('reset_password', '/_admin/password_reset', []);
141 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
143 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
142 pyroutes.register('home', '/', []);
144 pyroutes.register('home', '/', []);
143 pyroutes.register('user_autocomplete_data', '/_users', []);
145 pyroutes.register('user_autocomplete_data', '/_users', []);
144 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
146 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
145 pyroutes.register('repo_list_data', '/_repos', []);
147 pyroutes.register('repo_list_data', '/_repos', []);
146 pyroutes.register('repo_group_list_data', '/_repo_groups', []);
148 pyroutes.register('repo_group_list_data', '/_repo_groups', []);
147 pyroutes.register('goto_switcher_data', '/_goto_data', []);
149 pyroutes.register('goto_switcher_data', '/_goto_data', []);
148 pyroutes.register('markup_preview', '/_markup_preview', []);
150 pyroutes.register('markup_preview', '/_markup_preview', []);
149 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
151 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
150 pyroutes.register('journal', '/_admin/journal', []);
152 pyroutes.register('journal', '/_admin/journal', []);
151 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
153 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
152 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
154 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
153 pyroutes.register('journal_public', '/_admin/public_journal', []);
155 pyroutes.register('journal_public', '/_admin/public_journal', []);
154 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
156 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
155 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
157 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
156 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
158 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
157 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
159 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
158 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
160 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
159 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
161 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
160 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
162 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
161 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
163 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
162 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
164 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
163 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
165 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
164 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
166 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
165 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
167 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
166 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
168 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
167 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
169 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
168 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
170 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
169 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
171 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
170 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
172 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
171 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
173 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
172 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
174 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
173 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
175 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
174 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
176 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
175 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
177 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
176 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
178 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
177 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
179 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
178 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
180 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
179 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
181 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
180 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
182 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
181 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
183 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
182 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
184 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
183 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
185 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
184 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
186 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
185 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
187 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
186 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
188 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
187 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
189 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
188 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
190 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
189 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
191 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
190 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
192 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
191 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
193 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
192 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
194 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
193 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
195 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
194 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
196 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
195 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
197 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
196 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
198 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
197 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
199 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
198 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
200 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
199 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
201 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
200 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
202 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
201 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
203 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
202 pyroutes.register('repo_changelog_elements', '/%(repo_name)s/changelog_elements', ['repo_name']);
204 pyroutes.register('repo_changelog_elements', '/%(repo_name)s/changelog_elements', ['repo_name']);
203 pyroutes.register('repo_changelog_elements_file', '/%(repo_name)s/changelog_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
205 pyroutes.register('repo_changelog_elements_file', '/%(repo_name)s/changelog_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
204 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
206 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
205 pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
207 pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
206 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
208 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
207 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
209 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
208 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
210 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
209 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
211 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
210 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
212 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
211 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
213 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
212 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
214 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
213 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
215 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
214 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
216 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
215 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
217 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
216 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
218 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
217 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
219 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
218 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
220 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
219 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
221 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
220 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
222 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
221 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
223 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
222 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
224 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
223 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
225 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
224 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
226 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
225 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
227 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
226 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
228 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
227 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
229 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
228 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
230 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
229 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
231 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
230 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
232 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
231 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
233 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
232 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
234 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
233 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
235 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
234 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
236 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
235 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
237 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
236 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
238 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
237 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
239 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
238 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
240 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
239 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
241 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
240 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
242 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
241 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
243 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
242 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
244 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
243 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
245 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
244 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
246 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
245 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
247 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
246 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
248 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
247 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
249 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
248 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
250 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
249 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
251 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
250 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
252 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
251 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
253 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
252 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
254 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
253 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
255 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
254 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
256 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
255 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
257 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
256 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
258 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
257 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
259 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
258 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed/rss', ['repo_name']);
260 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed/rss', ['repo_name']);
259 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed/atom', ['repo_name']);
261 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed/atom', ['repo_name']);
260 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
262 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
261 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
263 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
262 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
264 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
263 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
265 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
264 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
266 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
265 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
267 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
266 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
268 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
267 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
269 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
268 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
270 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
269 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
271 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
270 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
272 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
271 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
273 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
272 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
274 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
273 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
275 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
274 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
276 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
275 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
277 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
276 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
278 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
277 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
279 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
278 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
280 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
279 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
281 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
280 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
282 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
281 pyroutes.register('search', '/_admin/search', []);
283 pyroutes.register('search', '/_admin/search', []);
282 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
284 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
283 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
285 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
284 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
286 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
285 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
287 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
286 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
288 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
287 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
289 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
288 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
290 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
289 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
291 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
290 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
292 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
291 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
293 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
292 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
294 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
293 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
295 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
294 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
296 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
295 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
297 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
296 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
298 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
297 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
299 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
298 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
300 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
299 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
301 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
300 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
302 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
301 pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []);
303 pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []);
302 pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []);
304 pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []);
303 pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']);
305 pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']);
304 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
306 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
305 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
307 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
306 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
308 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
307 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
309 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
308 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
310 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
309 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
311 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
310 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
312 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
311 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
313 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
312 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
314 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
313 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
315 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
314 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
316 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
315 pyroutes.register('gists_show', '/_admin/gists', []);
317 pyroutes.register('gists_show', '/_admin/gists', []);
316 pyroutes.register('gists_new', '/_admin/gists/new', []);
318 pyroutes.register('gists_new', '/_admin/gists/new', []);
317 pyroutes.register('gists_create', '/_admin/gists/create', []);
319 pyroutes.register('gists_create', '/_admin/gists/create', []);
318 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
320 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
319 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
321 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
320 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
322 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
321 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
323 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
322 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
324 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
323 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
325 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
324 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
326 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
325 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
327 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
326 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
328 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
327 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
329 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
328 pyroutes.register('apiv2', '/_admin/api', []);
330 pyroutes.register('apiv2', '/_admin/api', []);
329 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
331 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
330 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
332 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
331 pyroutes.register('login', '/_admin/login', []);
333 pyroutes.register('login', '/_admin/login', []);
332 pyroutes.register('register', '/_admin/register', []);
334 pyroutes.register('register', '/_admin/register', []);
333 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
335 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
334 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
336 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
335 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
337 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
336 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
338 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
337 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
339 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
338 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
340 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
339 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
341 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
340 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
342 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
341 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
343 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
342 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
344 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
343 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
345 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
344 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
346 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
345 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
347 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
346 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
348 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
347 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
349 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
348 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
350 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
349 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
351 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
350 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
352 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
351 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
353 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
352 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
354 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
353 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
355 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
354 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
356 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
355 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
357 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
356 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
358 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
357 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
359 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
358 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
360 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
359 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
361 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
360 }
362 }
@@ -1,458 +1,465 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import threading
21 import threading
22 import time
22 import time
23 import logging
23 import logging
24 import os.path
24 import os.path
25 import subprocess32
25 import subprocess32
26 import tempfile
26 import tempfile
27 import urllib2
27 import urllib2
28 from lxml.html import fromstring, tostring
28 from lxml.html import fromstring, tostring
29 from lxml.cssselect import CSSSelector
29 from lxml.cssselect import CSSSelector
30 from urlparse import urlparse, parse_qsl
30 from urlparse import urlparse, parse_qsl
31 from urllib import unquote_plus
31 from urllib import unquote_plus
32 import webob
32 import webob
33
33
34 from webtest.app import TestResponse, TestApp, string_types
34 from webtest.app import TestResponse, TestApp, string_types
35 from webtest.compat import print_stderr
35 from webtest.compat import print_stderr
36
36
37 import pytest
37 import pytest
38 import rc_testdata
38 import rc_testdata
39
39
40 from rhodecode.model.db import User, Repository
40 from rhodecode.model.db import User, Repository
41 from rhodecode.model.meta import Session
41 from rhodecode.model.meta import Session
42 from rhodecode.model.scm import ScmModel
42 from rhodecode.model.scm import ScmModel
43 from rhodecode.lib.vcs.backends.svn.repository import SubversionRepository
43 from rhodecode.lib.vcs.backends.svn.repository import SubversionRepository
44 from rhodecode.lib.vcs.backends.base import EmptyCommit
44 from rhodecode.lib.vcs.backends.base import EmptyCommit
45 from rhodecode.tests import login_user_session
45 from rhodecode.tests import login_user_session
46
46
47 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
48
48
49
49
50 class CustomTestResponse(TestResponse):
50 class CustomTestResponse(TestResponse):
51 def _save_output(self, out):
51 def _save_output(self, out):
52 f = tempfile.NamedTemporaryFile(
52 f = tempfile.NamedTemporaryFile(
53 delete=False, prefix='rc-test-', suffix='.html')
53 delete=False, prefix='rc-test-', suffix='.html')
54 f.write(out)
54 f.write(out)
55 return f.name
55 return f.name
56
56
57 def mustcontain(self, *strings, **kw):
57 def mustcontain(self, *strings, **kw):
58 """
58 """
59 Assert that the response contains all of the strings passed
59 Assert that the response contains all of the strings passed
60 in as arguments.
60 in as arguments.
61
61
62 Equivalent to::
62 Equivalent to::
63
63
64 assert string in res
64 assert string in res
65 """
65 """
66 if 'no' in kw:
66 if 'no' in kw:
67 no = kw['no']
67 no = kw['no']
68 del kw['no']
68 del kw['no']
69 if isinstance(no, string_types):
69 if isinstance(no, string_types):
70 no = [no]
70 no = [no]
71 else:
71 else:
72 no = []
72 no = []
73 if kw:
73 if kw:
74 raise TypeError(
74 raise TypeError(
75 "The only keyword argument allowed is 'no' got %s" % kw)
75 "The only keyword argument allowed is 'no' got %s" % kw)
76
76
77 f = self._save_output(str(self))
77 f = self._save_output(str(self))
78
78
79 for s in strings:
79 for s in strings:
80 if not s in self:
80 if not s in self:
81 print_stderr("Actual response (no %r):" % s)
81 print_stderr("Actual response (no %r):" % s)
82 print_stderr(str(self))
82 print_stderr(str(self))
83 raise IndexError(
83 raise IndexError(
84 "Body does not contain string %r, output saved as %s" % (
84 "Body does not contain string %r, output saved as %s" % (
85 s, f))
85 s, f))
86
86
87 for no_s in no:
87 for no_s in no:
88 if no_s in self:
88 if no_s in self:
89 print_stderr("Actual response (has %r)" % no_s)
89 print_stderr("Actual response (has %r)" % no_s)
90 print_stderr(str(self))
90 print_stderr(str(self))
91 raise IndexError(
91 raise IndexError(
92 "Body contains bad string %r, output saved as %s" % (
92 "Body contains bad string %r, output saved as %s" % (
93 no_s, f))
93 no_s, f))
94
94
95 def assert_response(self):
95 def assert_response(self):
96 return AssertResponse(self)
96 return AssertResponse(self)
97
97
98 def get_session_from_response(self):
98 def get_session_from_response(self):
99 """
99 """
100 This returns the session from a response object.
100 This returns the session from a response object.
101 """
101 """
102
102
103 from pyramid_beaker import session_factory_from_settings
103 from pyramid_beaker import session_factory_from_settings
104 session = session_factory_from_settings(
104 session = session_factory_from_settings(self.test_app._pyramid_settings)
105 self.test_app.app.config.get_settings())
106 return session(self.request)
105 return session(self.request)
107
106
108
107
109 class TestRequest(webob.BaseRequest):
108 class TestRequest(webob.BaseRequest):
110
109
111 # for py.test
110 # for py.test
112 disabled = True
111 disabled = True
113 ResponseClass = CustomTestResponse
112 ResponseClass = CustomTestResponse
114
113
115 def add_response_callback(self, callback):
114 def add_response_callback(self, callback):
116 pass
115 pass
117
116
118
117
119 class CustomTestApp(TestApp):
118 class CustomTestApp(TestApp):
120 """
119 """
121 Custom app to make mustcontain more usefull, and extract special methods
120 Custom app to make mustcontain more usefull, and extract special methods
122 """
121 """
123 RequestClass = TestRequest
122 RequestClass = TestRequest
124 rc_login_data = {}
123 rc_login_data = {}
125 rc_current_session = None
124 rc_current_session = None
126
125
127 def login(self, username=None, password=None):
126 def login(self, username=None, password=None):
128 from rhodecode.lib import auth
127 from rhodecode.lib import auth
129
128
130 if username and password:
129 if username and password:
131 session = login_user_session(self, username, password)
130 session = login_user_session(self, username, password)
132 else:
131 else:
133 session = login_user_session(self)
132 session = login_user_session(self)
134
133
135 self.rc_login_data['csrf_token'] = auth.get_csrf_token(session)
134 self.rc_login_data['csrf_token'] = auth.get_csrf_token(session)
136 self.rc_current_session = session
135 self.rc_current_session = session
137 return session['rhodecode_user']
136 return session['rhodecode_user']
138
137
139 @property
138 @property
140 def csrf_token(self):
139 def csrf_token(self):
141 return self.rc_login_data['csrf_token']
140 return self.rc_login_data['csrf_token']
142
141
142 @property
143 def _pyramid_registry(self):
144 return self.app.config.registry
145
146 @property
147 def _pyramid_settings(self):
148 return self._pyramid_registry.settings
149
143
150
144 def set_anonymous_access(enabled):
151 def set_anonymous_access(enabled):
145 """(Dis)allows anonymous access depending on parameter `enabled`"""
152 """(Dis)allows anonymous access depending on parameter `enabled`"""
146 user = User.get_default_user()
153 user = User.get_default_user()
147 user.active = enabled
154 user.active = enabled
148 Session().add(user)
155 Session().add(user)
149 Session().commit()
156 Session().commit()
150 time.sleep(1.5) # must sleep for cache (1s to expire)
157 time.sleep(1.5) # must sleep for cache (1s to expire)
151 log.info('anonymous access is now: %s', enabled)
158 log.info('anonymous access is now: %s', enabled)
152 assert enabled == User.get_default_user().active, (
159 assert enabled == User.get_default_user().active, (
153 'Cannot set anonymous access')
160 'Cannot set anonymous access')
154
161
155
162
156 def check_xfail_backends(node, backend_alias):
163 def check_xfail_backends(node, backend_alias):
157 # Using "xfail_backends" here intentionally, since this marks work
164 # Using "xfail_backends" here intentionally, since this marks work
158 # which is "to be done" soon.
165 # which is "to be done" soon.
159 skip_marker = node.get_closest_marker('xfail_backends')
166 skip_marker = node.get_closest_marker('xfail_backends')
160 if skip_marker and backend_alias in skip_marker.args:
167 if skip_marker and backend_alias in skip_marker.args:
161 msg = "Support for backend %s to be developed." % (backend_alias, )
168 msg = "Support for backend %s to be developed." % (backend_alias, )
162 msg = skip_marker.kwargs.get('reason', msg)
169 msg = skip_marker.kwargs.get('reason', msg)
163 pytest.xfail(msg)
170 pytest.xfail(msg)
164
171
165
172
166 def check_skip_backends(node, backend_alias):
173 def check_skip_backends(node, backend_alias):
167 # Using "skip_backends" here intentionally, since this marks work which is
174 # Using "skip_backends" here intentionally, since this marks work which is
168 # not supported.
175 # not supported.
169 skip_marker = node.get_closest_marker('skip_backends')
176 skip_marker = node.get_closest_marker('skip_backends')
170 if skip_marker and backend_alias in skip_marker.args:
177 if skip_marker and backend_alias in skip_marker.args:
171 msg = "Feature not supported for backend %s." % (backend_alias, )
178 msg = "Feature not supported for backend %s." % (backend_alias, )
172 msg = skip_marker.kwargs.get('reason', msg)
179 msg = skip_marker.kwargs.get('reason', msg)
173 pytest.skip(msg)
180 pytest.skip(msg)
174
181
175
182
176 def extract_git_repo_from_dump(dump_name, repo_name):
183 def extract_git_repo_from_dump(dump_name, repo_name):
177 """Create git repo `repo_name` from dump `dump_name`."""
184 """Create git repo `repo_name` from dump `dump_name`."""
178 repos_path = ScmModel().repos_path
185 repos_path = ScmModel().repos_path
179 target_path = os.path.join(repos_path, repo_name)
186 target_path = os.path.join(repos_path, repo_name)
180 rc_testdata.extract_git_dump(dump_name, target_path)
187 rc_testdata.extract_git_dump(dump_name, target_path)
181 return target_path
188 return target_path
182
189
183
190
184 def extract_hg_repo_from_dump(dump_name, repo_name):
191 def extract_hg_repo_from_dump(dump_name, repo_name):
185 """Create hg repo `repo_name` from dump `dump_name`."""
192 """Create hg repo `repo_name` from dump `dump_name`."""
186 repos_path = ScmModel().repos_path
193 repos_path = ScmModel().repos_path
187 target_path = os.path.join(repos_path, repo_name)
194 target_path = os.path.join(repos_path, repo_name)
188 rc_testdata.extract_hg_dump(dump_name, target_path)
195 rc_testdata.extract_hg_dump(dump_name, target_path)
189 return target_path
196 return target_path
190
197
191
198
192 def extract_svn_repo_from_dump(dump_name, repo_name):
199 def extract_svn_repo_from_dump(dump_name, repo_name):
193 """Create a svn repo `repo_name` from dump `dump_name`."""
200 """Create a svn repo `repo_name` from dump `dump_name`."""
194 repos_path = ScmModel().repos_path
201 repos_path = ScmModel().repos_path
195 target_path = os.path.join(repos_path, repo_name)
202 target_path = os.path.join(repos_path, repo_name)
196 SubversionRepository(target_path, create=True)
203 SubversionRepository(target_path, create=True)
197 _load_svn_dump_into_repo(dump_name, target_path)
204 _load_svn_dump_into_repo(dump_name, target_path)
198 return target_path
205 return target_path
199
206
200
207
201 def assert_message_in_log(log_records, message, levelno, module):
208 def assert_message_in_log(log_records, message, levelno, module):
202 messages = [
209 messages = [
203 r.message for r in log_records
210 r.message for r in log_records
204 if r.module == module and r.levelno == levelno
211 if r.module == module and r.levelno == levelno
205 ]
212 ]
206 assert message in messages
213 assert message in messages
207
214
208
215
209 def _load_svn_dump_into_repo(dump_name, repo_path):
216 def _load_svn_dump_into_repo(dump_name, repo_path):
210 """
217 """
211 Utility to populate a svn repository with a named dump
218 Utility to populate a svn repository with a named dump
212
219
213 Currently the dumps are in rc_testdata. They might later on be
220 Currently the dumps are in rc_testdata. They might later on be
214 integrated with the main repository once they stabilize more.
221 integrated with the main repository once they stabilize more.
215 """
222 """
216 dump = rc_testdata.load_svn_dump(dump_name)
223 dump = rc_testdata.load_svn_dump(dump_name)
217 load_dump = subprocess32.Popen(
224 load_dump = subprocess32.Popen(
218 ['svnadmin', 'load', repo_path],
225 ['svnadmin', 'load', repo_path],
219 stdin=subprocess32.PIPE, stdout=subprocess32.PIPE,
226 stdin=subprocess32.PIPE, stdout=subprocess32.PIPE,
220 stderr=subprocess32.PIPE)
227 stderr=subprocess32.PIPE)
221 out, err = load_dump.communicate(dump)
228 out, err = load_dump.communicate(dump)
222 if load_dump.returncode != 0:
229 if load_dump.returncode != 0:
223 log.error("Output of load_dump command: %s", out)
230 log.error("Output of load_dump command: %s", out)
224 log.error("Error output of load_dump command: %s", err)
231 log.error("Error output of load_dump command: %s", err)
225 raise Exception(
232 raise Exception(
226 'Failed to load dump "%s" into repository at path "%s".'
233 'Failed to load dump "%s" into repository at path "%s".'
227 % (dump_name, repo_path))
234 % (dump_name, repo_path))
228
235
229
236
230 class AssertResponse(object):
237 class AssertResponse(object):
231 """
238 """
232 Utility that helps to assert things about a given HTML response.
239 Utility that helps to assert things about a given HTML response.
233 """
240 """
234
241
235 def __init__(self, response):
242 def __init__(self, response):
236 self.response = response
243 self.response = response
237
244
238 def get_imports(self):
245 def get_imports(self):
239 return fromstring, tostring, CSSSelector
246 return fromstring, tostring, CSSSelector
240
247
241 def one_element_exists(self, css_selector):
248 def one_element_exists(self, css_selector):
242 self.get_element(css_selector)
249 self.get_element(css_selector)
243
250
244 def no_element_exists(self, css_selector):
251 def no_element_exists(self, css_selector):
245 assert not self._get_elements(css_selector)
252 assert not self._get_elements(css_selector)
246
253
247 def element_equals_to(self, css_selector, expected_content):
254 def element_equals_to(self, css_selector, expected_content):
248 element = self.get_element(css_selector)
255 element = self.get_element(css_selector)
249 element_text = self._element_to_string(element)
256 element_text = self._element_to_string(element)
250 assert expected_content in element_text
257 assert expected_content in element_text
251
258
252 def element_contains(self, css_selector, expected_content):
259 def element_contains(self, css_selector, expected_content):
253 element = self.get_element(css_selector)
260 element = self.get_element(css_selector)
254 assert expected_content in element.text_content()
261 assert expected_content in element.text_content()
255
262
256 def element_value_contains(self, css_selector, expected_content):
263 def element_value_contains(self, css_selector, expected_content):
257 element = self.get_element(css_selector)
264 element = self.get_element(css_selector)
258 assert expected_content in element.value
265 assert expected_content in element.value
259
266
260 def contains_one_link(self, link_text, href):
267 def contains_one_link(self, link_text, href):
261 fromstring, tostring, CSSSelector = self.get_imports()
268 fromstring, tostring, CSSSelector = self.get_imports()
262 doc = fromstring(self.response.body)
269 doc = fromstring(self.response.body)
263 sel = CSSSelector('a[href]')
270 sel = CSSSelector('a[href]')
264 elements = [
271 elements = [
265 e for e in sel(doc) if e.text_content().strip() == link_text]
272 e for e in sel(doc) if e.text_content().strip() == link_text]
266 assert len(elements) == 1, "Did not find link or found multiple links"
273 assert len(elements) == 1, "Did not find link or found multiple links"
267 self._ensure_url_equal(elements[0].attrib.get('href'), href)
274 self._ensure_url_equal(elements[0].attrib.get('href'), href)
268
275
269 def contains_one_anchor(self, anchor_id):
276 def contains_one_anchor(self, anchor_id):
270 fromstring, tostring, CSSSelector = self.get_imports()
277 fromstring, tostring, CSSSelector = self.get_imports()
271 doc = fromstring(self.response.body)
278 doc = fromstring(self.response.body)
272 sel = CSSSelector('#' + anchor_id)
279 sel = CSSSelector('#' + anchor_id)
273 elements = sel(doc)
280 elements = sel(doc)
274 assert len(elements) == 1, 'cannot find 1 element {}'.format(anchor_id)
281 assert len(elements) == 1, 'cannot find 1 element {}'.format(anchor_id)
275
282
276 def _ensure_url_equal(self, found, expected):
283 def _ensure_url_equal(self, found, expected):
277 assert _Url(found) == _Url(expected)
284 assert _Url(found) == _Url(expected)
278
285
279 def get_element(self, css_selector):
286 def get_element(self, css_selector):
280 elements = self._get_elements(css_selector)
287 elements = self._get_elements(css_selector)
281 assert len(elements) == 1, 'cannot find 1 element {}'.format(css_selector)
288 assert len(elements) == 1, 'cannot find 1 element {}'.format(css_selector)
282 return elements[0]
289 return elements[0]
283
290
284 def get_elements(self, css_selector):
291 def get_elements(self, css_selector):
285 return self._get_elements(css_selector)
292 return self._get_elements(css_selector)
286
293
287 def _get_elements(self, css_selector):
294 def _get_elements(self, css_selector):
288 fromstring, tostring, CSSSelector = self.get_imports()
295 fromstring, tostring, CSSSelector = self.get_imports()
289 doc = fromstring(self.response.body)
296 doc = fromstring(self.response.body)
290 sel = CSSSelector(css_selector)
297 sel = CSSSelector(css_selector)
291 elements = sel(doc)
298 elements = sel(doc)
292 return elements
299 return elements
293
300
294 def _element_to_string(self, element):
301 def _element_to_string(self, element):
295 fromstring, tostring, CSSSelector = self.get_imports()
302 fromstring, tostring, CSSSelector = self.get_imports()
296 return tostring(element)
303 return tostring(element)
297
304
298
305
299 class _Url(object):
306 class _Url(object):
300 """
307 """
301 A url object that can be compared with other url orbjects
308 A url object that can be compared with other url orbjects
302 without regard to the vagaries of encoding, escaping, and ordering
309 without regard to the vagaries of encoding, escaping, and ordering
303 of parameters in query strings.
310 of parameters in query strings.
304
311
305 Inspired by
312 Inspired by
306 http://stackoverflow.com/questions/5371992/comparing-two-urls-in-python
313 http://stackoverflow.com/questions/5371992/comparing-two-urls-in-python
307 """
314 """
308
315
309 def __init__(self, url):
316 def __init__(self, url):
310 parts = urlparse(url)
317 parts = urlparse(url)
311 _query = frozenset(parse_qsl(parts.query))
318 _query = frozenset(parse_qsl(parts.query))
312 _path = unquote_plus(parts.path)
319 _path = unquote_plus(parts.path)
313 parts = parts._replace(query=_query, path=_path)
320 parts = parts._replace(query=_query, path=_path)
314 self.parts = parts
321 self.parts = parts
315
322
316 def __eq__(self, other):
323 def __eq__(self, other):
317 return self.parts == other.parts
324 return self.parts == other.parts
318
325
319 def __hash__(self):
326 def __hash__(self):
320 return hash(self.parts)
327 return hash(self.parts)
321
328
322
329
323 def run_test_concurrently(times, raise_catched_exc=True):
330 def run_test_concurrently(times, raise_catched_exc=True):
324 """
331 """
325 Add this decorator to small pieces of code that you want to test
332 Add this decorator to small pieces of code that you want to test
326 concurrently
333 concurrently
327
334
328 ex:
335 ex:
329
336
330 @test_concurrently(25)
337 @test_concurrently(25)
331 def my_test_function():
338 def my_test_function():
332 ...
339 ...
333 """
340 """
334 def test_concurrently_decorator(test_func):
341 def test_concurrently_decorator(test_func):
335 def wrapper(*args, **kwargs):
342 def wrapper(*args, **kwargs):
336 exceptions = []
343 exceptions = []
337
344
338 def call_test_func():
345 def call_test_func():
339 try:
346 try:
340 test_func(*args, **kwargs)
347 test_func(*args, **kwargs)
341 except Exception as e:
348 except Exception as e:
342 exceptions.append(e)
349 exceptions.append(e)
343 if raise_catched_exc:
350 if raise_catched_exc:
344 raise
351 raise
345 threads = []
352 threads = []
346 for i in range(times):
353 for i in range(times):
347 threads.append(threading.Thread(target=call_test_func))
354 threads.append(threading.Thread(target=call_test_func))
348 for t in threads:
355 for t in threads:
349 t.start()
356 t.start()
350 for t in threads:
357 for t in threads:
351 t.join()
358 t.join()
352 if exceptions:
359 if exceptions:
353 raise Exception(
360 raise Exception(
354 'test_concurrently intercepted %s exceptions: %s' % (
361 'test_concurrently intercepted %s exceptions: %s' % (
355 len(exceptions), exceptions))
362 len(exceptions), exceptions))
356 return wrapper
363 return wrapper
357 return test_concurrently_decorator
364 return test_concurrently_decorator
358
365
359
366
360 def wait_for_url(url, timeout=10):
367 def wait_for_url(url, timeout=10):
361 """
368 """
362 Wait until URL becomes reachable.
369 Wait until URL becomes reachable.
363
370
364 It polls the URL until the timeout is reached or it became reachable.
371 It polls the URL until the timeout is reached or it became reachable.
365 If will call to `py.test.fail` in case the URL is not reachable.
372 If will call to `py.test.fail` in case the URL is not reachable.
366 """
373 """
367 timeout = time.time() + timeout
374 timeout = time.time() + timeout
368 last = 0
375 last = 0
369 wait = 0.1
376 wait = 0.1
370
377
371 while timeout > last:
378 while timeout > last:
372 last = time.time()
379 last = time.time()
373 if is_url_reachable(url):
380 if is_url_reachable(url):
374 break
381 break
375 elif (last + wait) > time.time():
382 elif (last + wait) > time.time():
376 # Go to sleep because not enough time has passed since last check.
383 # Go to sleep because not enough time has passed since last check.
377 time.sleep(wait)
384 time.sleep(wait)
378 else:
385 else:
379 pytest.fail("Timeout while waiting for URL {}".format(url))
386 pytest.fail("Timeout while waiting for URL {}".format(url))
380
387
381
388
382 def is_url_reachable(url):
389 def is_url_reachable(url):
383 try:
390 try:
384 urllib2.urlopen(url)
391 urllib2.urlopen(url)
385 except urllib2.URLError:
392 except urllib2.URLError:
386 return False
393 return False
387 return True
394 return True
388
395
389
396
390 def repo_on_filesystem(repo_name):
397 def repo_on_filesystem(repo_name):
391 from rhodecode.lib import vcs
398 from rhodecode.lib import vcs
392 from rhodecode.tests import TESTS_TMP_PATH
399 from rhodecode.tests import TESTS_TMP_PATH
393 repo = vcs.get_vcs_instance(
400 repo = vcs.get_vcs_instance(
394 os.path.join(TESTS_TMP_PATH, repo_name), create=False)
401 os.path.join(TESTS_TMP_PATH, repo_name), create=False)
395 return repo is not None
402 return repo is not None
396
403
397
404
398 def commit_change(
405 def commit_change(
399 repo, filename, content, message, vcs_type, parent=None, newfile=False):
406 repo, filename, content, message, vcs_type, parent=None, newfile=False):
400 from rhodecode.tests import TEST_USER_ADMIN_LOGIN
407 from rhodecode.tests import TEST_USER_ADMIN_LOGIN
401
408
402 repo = Repository.get_by_repo_name(repo)
409 repo = Repository.get_by_repo_name(repo)
403 _commit = parent
410 _commit = parent
404 if not parent:
411 if not parent:
405 _commit = EmptyCommit(alias=vcs_type)
412 _commit = EmptyCommit(alias=vcs_type)
406
413
407 if newfile:
414 if newfile:
408 nodes = {
415 nodes = {
409 filename: {
416 filename: {
410 'content': content
417 'content': content
411 }
418 }
412 }
419 }
413 commit = ScmModel().create_nodes(
420 commit = ScmModel().create_nodes(
414 user=TEST_USER_ADMIN_LOGIN, repo=repo,
421 user=TEST_USER_ADMIN_LOGIN, repo=repo,
415 message=message,
422 message=message,
416 nodes=nodes,
423 nodes=nodes,
417 parent_commit=_commit,
424 parent_commit=_commit,
418 author=TEST_USER_ADMIN_LOGIN,
425 author=TEST_USER_ADMIN_LOGIN,
419 )
426 )
420 else:
427 else:
421 commit = ScmModel().commit_change(
428 commit = ScmModel().commit_change(
422 repo=repo.scm_instance(), repo_name=repo.repo_name,
429 repo=repo.scm_instance(), repo_name=repo.repo_name,
423 commit=parent, user=TEST_USER_ADMIN_LOGIN,
430 commit=parent, user=TEST_USER_ADMIN_LOGIN,
424 author=TEST_USER_ADMIN_LOGIN,
431 author=TEST_USER_ADMIN_LOGIN,
425 message=message,
432 message=message,
426 content=content,
433 content=content,
427 f_path=filename
434 f_path=filename
428 )
435 )
429 return commit
436 return commit
430
437
431
438
432 def permission_update_data_generator(csrf_token, default=None, grant=None, revoke=None):
439 def permission_update_data_generator(csrf_token, default=None, grant=None, revoke=None):
433 if not default:
440 if not default:
434 raise ValueError('Permission for default user must be given')
441 raise ValueError('Permission for default user must be given')
435 form_data = [(
442 form_data = [(
436 'csrf_token', csrf_token
443 'csrf_token', csrf_token
437 )]
444 )]
438 # add default
445 # add default
439 form_data.extend([
446 form_data.extend([
440 ('u_perm_1', default)
447 ('u_perm_1', default)
441 ])
448 ])
442
449
443 if grant:
450 if grant:
444 for cnt, (obj_id, perm, obj_name, obj_type) in enumerate(grant, 1):
451 for cnt, (obj_id, perm, obj_name, obj_type) in enumerate(grant, 1):
445 form_data.extend([
452 form_data.extend([
446 ('perm_new_member_perm_new{}'.format(cnt), perm),
453 ('perm_new_member_perm_new{}'.format(cnt), perm),
447 ('perm_new_member_id_new{}'.format(cnt), obj_id),
454 ('perm_new_member_id_new{}'.format(cnt), obj_id),
448 ('perm_new_member_name_new{}'.format(cnt), obj_name),
455 ('perm_new_member_name_new{}'.format(cnt), obj_name),
449 ('perm_new_member_type_new{}'.format(cnt), obj_type),
456 ('perm_new_member_type_new{}'.format(cnt), obj_type),
450
457
451 ])
458 ])
452 if revoke:
459 if revoke:
453 for obj_id, obj_type in revoke:
460 for obj_id, obj_type in revoke:
454 form_data.extend([
461 form_data.extend([
455 ('perm_del_member_id_{}'.format(obj_id), obj_id),
462 ('perm_del_member_id_{}'.format(obj_id), obj_id),
456 ('perm_del_member_type_{}'.format(obj_id), obj_type),
463 ('perm_del_member_type_{}'.format(obj_id), obj_type),
457 ])
464 ])
458 return form_data
465 return form_data
General Comments 0
You need to be logged in to leave comments. Login now