Show More
@@ -0,0 +1,111 b'' | |||||
|
1 | # RhodeCode VCSServer provides access to different vcs backends via network. | |||
|
2 | # Copyright (C) 2014-2023 RhodeCode GmbH | |||
|
3 | # | |||
|
4 | # This program is free software; you can redistribute it and/or modify | |||
|
5 | # it under the terms of the GNU General Public License as published by | |||
|
6 | # the Free Software Foundation; either version 3 of the License, or | |||
|
7 | # (at your option) any later version. | |||
|
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 General Public License | |||
|
15 | # along with this program; if not, write to the Free Software Foundation, | |||
|
16 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
|
17 | ||||
|
18 | import logging | |||
|
19 | import redis | |||
|
20 | ||||
|
21 | from ..lib import rc_cache | |||
|
22 | from ..lib.ext_json import json | |||
|
23 | ||||
|
24 | ||||
|
25 | log = logging.getLogger(__name__) | |||
|
26 | ||||
|
27 | redis_client = None | |||
|
28 | ||||
|
29 | ||||
|
30 | class RedisTxnClient: | |||
|
31 | ||||
|
32 | def __init__(self, url): | |||
|
33 | self.url = url | |||
|
34 | self._create_client(url) | |||
|
35 | ||||
|
36 | def _create_client(self, url): | |||
|
37 | connection_pool = redis.ConnectionPool.from_url(url) | |||
|
38 | self.writer_client = redis.StrictRedis( | |||
|
39 | connection_pool=connection_pool | |||
|
40 | ) | |||
|
41 | self.reader_client = self.writer_client | |||
|
42 | ||||
|
43 | def set(self, key, value): | |||
|
44 | self.writer_client.set(key, value) | |||
|
45 | ||||
|
46 | def get(self, key): | |||
|
47 | return self.reader_client.get(key) | |||
|
48 | ||||
|
49 | def delete(self, key): | |||
|
50 | self.writer_client.delete(key) | |||
|
51 | ||||
|
52 | ||||
|
53 | def get_redis_client(url=''): | |||
|
54 | ||||
|
55 | global redis_client | |||
|
56 | if redis_client is not None: | |||
|
57 | return redis_client | |||
|
58 | if not url: | |||
|
59 | from vcsserver import CONFIG | |||
|
60 | url = CONFIG['vcs.svn.redis_conn'] | |||
|
61 | redis_client = RedisTxnClient(url) | |||
|
62 | return redis_client | |||
|
63 | ||||
|
64 | ||||
|
65 | def get_txn_id_data_key(repo_path, svn_txn_id): | |||
|
66 | log.debug('svn-txn-id: %s, obtaining data path', svn_txn_id) | |||
|
67 | repo_key = rc_cache.utils.compute_key_from_params(repo_path) | |||
|
68 | final_key = f'{repo_key}.{svn_txn_id}.svn_txn_id' | |||
|
69 | log.debug('computed final key: %s', final_key) | |||
|
70 | ||||
|
71 | return final_key | |||
|
72 | ||||
|
73 | ||||
|
74 | def store_txn_id_data(repo_path, svn_txn_id, data_dict): | |||
|
75 | log.debug('svn-txn-id: %s, storing data', svn_txn_id) | |||
|
76 | ||||
|
77 | if not svn_txn_id: | |||
|
78 | log.warning('Cannot store txn_id because it is empty') | |||
|
79 | return | |||
|
80 | ||||
|
81 | redis_conn = get_redis_client() | |||
|
82 | ||||
|
83 | store_key = get_txn_id_data_key(repo_path, svn_txn_id) | |||
|
84 | store_data = json.dumps(data_dict) | |||
|
85 | redis_conn.set(store_key, store_data) | |||
|
86 | ||||
|
87 | ||||
|
88 | def get_txn_id_from_store(repo_path, svn_txn_id, rm_on_read=False): | |||
|
89 | """ | |||
|
90 | Reads txn_id from store and if present returns the data for callback manager | |||
|
91 | """ | |||
|
92 | log.debug('svn-txn-id: %s, retrieving data', svn_txn_id) | |||
|
93 | redis_conn = get_redis_client() | |||
|
94 | ||||
|
95 | store_key = get_txn_id_data_key(repo_path, svn_txn_id) | |||
|
96 | data = {} | |||
|
97 | redis_conn.get(store_key) | |||
|
98 | raw_data = 'not-set' | |||
|
99 | try: | |||
|
100 | raw_data = redis_conn.get(store_key) | |||
|
101 | if not raw_data: | |||
|
102 | raise ValueError(f'Failed to get txn_id metadata, from store: {store_key}') | |||
|
103 | data = json.loads(raw_data) | |||
|
104 | except Exception: | |||
|
105 | log.exception('Failed to get txn_id metadata: %s', raw_data) | |||
|
106 | ||||
|
107 | if rm_on_read: | |||
|
108 | log.debug('Cleaning up txn_id at %s', store_key) | |||
|
109 | redis_conn.delete(store_key) | |||
|
110 | ||||
|
111 | return data |
@@ -66,6 +66,10 b' debugtoolbar.exclude_prefixes =' | |||||
66 | ; or /usr/local/bin/rhodecode_bin/vcs_bin |
|
66 | ; or /usr/local/bin/rhodecode_bin/vcs_bin | |
67 | core.binary_dir = |
|
67 | core.binary_dir = | |
68 |
|
68 | |||
|
69 | ; Redis connection settings for svn integrations logic | |||
|
70 | ; This connection string needs to be the same on ce and vcsserver | |||
|
71 | vcs.svn.redis_conn = redis://redis:6379/0 | |||
|
72 | ||||
69 | ; Custom exception store path, defaults to TMPDIR |
|
73 | ; Custom exception store path, defaults to TMPDIR | |
70 | ; This is used to store exception from RhodeCode in shared directory |
|
74 | ; This is used to store exception from RhodeCode in shared directory | |
71 | #exception_tracker.store_path = |
|
75 | #exception_tracker.store_path = |
@@ -46,6 +46,10 b' use = egg:rhodecode-vcsserver' | |||||
46 | ; or /usr/local/bin/rhodecode_bin/vcs_bin |
|
46 | ; or /usr/local/bin/rhodecode_bin/vcs_bin | |
47 | core.binary_dir = |
|
47 | core.binary_dir = | |
48 |
|
48 | |||
|
49 | ; Redis connection settings for svn integrations logic | |||
|
50 | ; This connection string needs to be the same on ce and vcsserver | |||
|
51 | vcs.svn.redis_conn = redis://redis:6379/0 | |||
|
52 | ||||
49 | ; Custom exception store path, defaults to TMPDIR |
|
53 | ; Custom exception store path, defaults to TMPDIR | |
50 | ; This is used to store exception from RhodeCode in shared directory |
|
54 | ; This is used to store exception from RhodeCode in shared directory | |
51 | #exception_tracker.store_path = |
|
55 | #exception_tracker.store_path = |
@@ -87,8 +87,16 b' def install_git_hooks(repo_path, bare, e' | |||||
87 |
|
87 | |||
88 | if _rhodecode_hook or force_create: |
|
88 | if _rhodecode_hook or force_create: | |
89 | log.debug('writing git %s hook file at %s !', h_type, _hook_file) |
|
89 | log.debug('writing git %s hook file at %s !', h_type, _hook_file) | |
|
90 | env_expand = str([ | |||
|
91 | ('RC_INI_FILE', vcsserver.CONFIG['__file__']), | |||
|
92 | ('RC_CORE_BINARY_DIR', vcsserver.settings.BINARY_DIR), | |||
|
93 | ('RC_GIT_EXECUTABLE', vcsserver.settings.GIT_EXECUTABLE()), | |||
|
94 | ('RC_SVN_EXECUTABLE', vcsserver.settings.SVN_EXECUTABLE()), | |||
|
95 | ('RC_SVNLOOK_EXECUTABLE', vcsserver.settings.SVNLOOK_EXECUTABLE()), | |||
|
96 | ]) | |||
90 | try: |
|
97 | try: | |
91 | with open(_hook_file, 'wb') as f: |
|
98 | with open(_hook_file, 'wb') as f: | |
|
99 | template = template.replace(b'_OS_EXPAND_', safe_bytes(env_expand)) | |||
92 | template = template.replace(b'_TMPL_', safe_bytes(vcsserver.get_version())) |
|
100 | template = template.replace(b'_TMPL_', safe_bytes(vcsserver.get_version())) | |
93 | template = template.replace(b'_DATE_', safe_bytes(timestamp)) |
|
101 | template = template.replace(b'_DATE_', safe_bytes(timestamp)) | |
94 | template = template.replace(b'_ENV_', safe_bytes(executable)) |
|
102 | template = template.replace(b'_ENV_', safe_bytes(executable)) | |
@@ -141,17 +149,17 b' def install_svn_hooks(repo_path, executa' | |||||
141 | log.debug('writing svn %s hook file at %s !', h_type, _hook_file) |
|
149 | log.debug('writing svn %s hook file at %s !', h_type, _hook_file) | |
142 |
|
150 | |||
143 | env_expand = str([ |
|
151 | env_expand = str([ | |
|
152 | ('RC_INI_FILE', vcsserver.CONFIG['__file__']), | |||
144 | ('RC_CORE_BINARY_DIR', vcsserver.settings.BINARY_DIR), |
|
153 | ('RC_CORE_BINARY_DIR', vcsserver.settings.BINARY_DIR), | |
145 | ('RC_GIT_EXECUTABLE', vcsserver.settings.GIT_EXECUTABLE()), |
|
154 | ('RC_GIT_EXECUTABLE', vcsserver.settings.GIT_EXECUTABLE()), | |
146 | ('RC_SVN_EXECUTABLE', vcsserver.settings.SVN_EXECUTABLE()), |
|
155 | ('RC_SVN_EXECUTABLE', vcsserver.settings.SVN_EXECUTABLE()), | |
147 | ('RC_SVNLOOK_EXECUTABLE', vcsserver.settings.SVNLOOK_EXECUTABLE()), |
|
156 | ('RC_SVNLOOK_EXECUTABLE', vcsserver.settings.SVNLOOK_EXECUTABLE()), | |
148 |
|
||||
149 | ]) |
|
157 | ]) | |
150 | try: |
|
158 | try: | |
151 | with open(_hook_file, 'wb') as f: |
|
159 | with open(_hook_file, 'wb') as f: | |
|
160 | template = template.replace(b'_OS_EXPAND_', safe_bytes(env_expand)) | |||
152 | template = template.replace(b'_TMPL_', safe_bytes(vcsserver.get_version())) |
|
161 | template = template.replace(b'_TMPL_', safe_bytes(vcsserver.get_version())) | |
153 | template = template.replace(b'_DATE_', safe_bytes(timestamp)) |
|
162 | template = template.replace(b'_DATE_', safe_bytes(timestamp)) | |
154 | template = template.replace(b'_OS_EXPAND_', safe_bytes(env_expand)) |
|
|||
155 | template = template.replace(b'_ENV_', safe_bytes(executable)) |
|
163 | template = template.replace(b'_ENV_', safe_bytes(executable)) | |
156 | template = template.replace(b'_PATH_', safe_bytes(path)) |
|
164 | template = template.replace(b'_PATH_', safe_bytes(path)) | |
157 |
|
165 |
@@ -1,4 +1,5 b'' | |||||
1 | #!_ENV_ |
|
1 | #!_ENV_ | |
|
2 | ||||
2 | import os |
|
3 | import os | |
3 | import sys |
|
4 | import sys | |
4 | path_adjust = [_PATH_] |
|
5 | path_adjust = [_PATH_] | |
@@ -6,6 +7,11 b' path_adjust = [_PATH_]' | |||||
6 | if path_adjust: |
|
7 | if path_adjust: | |
7 | sys.path = path_adjust |
|
8 | sys.path = path_adjust | |
8 |
|
9 | |||
|
10 | # special trick to pass in some information from rc to hooks | |||
|
11 | # mod_dav strips ALL env vars and we can't even access things like PATH | |||
|
12 | for env_k, env_v in _OS_EXPAND_: | |||
|
13 | os.environ[env_k] = env_v | |||
|
14 | ||||
9 | try: |
|
15 | try: | |
10 | from vcsserver import hooks |
|
16 | from vcsserver import hooks | |
11 | except ImportError: |
|
17 | except ImportError: | |
@@ -30,11 +36,13 b' def main():' | |||||
30 |
|
36 | |||
31 | repo_path = os.getcwd() |
|
37 | repo_path = os.getcwd() | |
32 | push_data = sys.stdin.readlines() |
|
38 | push_data = sys.stdin.readlines() | |
33 | os.environ['RC_HOOK_VER'] = RC_HOOK_VER |
|
39 | ||
34 | # os.environ is modified here by a subprocess call that |
|
40 | # os.environ is modified here by a subprocess call that | |
35 | # runs git and later git executes this hook. |
|
41 | # runs git and later git executes this hook. | |
36 | # Environ gets some additional info from rhodecode system |
|
42 | # Environ gets some additional info from rhodecode system | |
37 | # like IP or username from basic-auth |
|
43 | # like IP or username from basic-auth | |
|
44 | ||||
|
45 | os.environ['RC_HOOK_VER'] = RC_HOOK_VER | |||
38 | try: |
|
46 | try: | |
39 | result = hooks.git_post_receive(repo_path, push_data, os.environ) |
|
47 | result = hooks.git_post_receive(repo_path, push_data, os.environ) | |
40 | sys.exit(result) |
|
48 | sys.exit(result) |
@@ -1,4 +1,5 b'' | |||||
1 | #!_ENV_ |
|
1 | #!_ENV_ | |
|
2 | ||||
2 | import os |
|
3 | import os | |
3 | import sys |
|
4 | import sys | |
4 | path_adjust = [_PATH_] |
|
5 | path_adjust = [_PATH_] | |
@@ -6,6 +7,11 b' path_adjust = [_PATH_]' | |||||
6 | if path_adjust: |
|
7 | if path_adjust: | |
7 | sys.path = path_adjust |
|
8 | sys.path = path_adjust | |
8 |
|
9 | |||
|
10 | # special trick to pass in some information from rc to hooks | |||
|
11 | # mod_dav strips ALL env vars and we can't even access things like PATH | |||
|
12 | for env_k, env_v in _OS_EXPAND_: | |||
|
13 | os.environ[env_k] = env_v | |||
|
14 | ||||
9 | try: |
|
15 | try: | |
10 | from vcsserver import hooks |
|
16 | from vcsserver import hooks | |
11 | except ImportError: |
|
17 | except ImportError: | |
@@ -30,11 +36,13 b' def main():' | |||||
30 |
|
36 | |||
31 | repo_path = os.getcwd() |
|
37 | repo_path = os.getcwd() | |
32 | push_data = sys.stdin.readlines() |
|
38 | push_data = sys.stdin.readlines() | |
33 | os.environ['RC_HOOK_VER'] = RC_HOOK_VER |
|
39 | ||
34 | # os.environ is modified here by a subprocess call that |
|
40 | # os.environ is modified here by a subprocess call that | |
35 | # runs git and later git executes this hook. |
|
41 | # runs git and later git executes this hook. | |
36 | # Environ gets some additional info from rhodecode system |
|
42 | # Environ gets some additional info from rhodecode system | |
37 | # like IP or username from basic-auth |
|
43 | # like IP or username from basic-auth | |
|
44 | ||||
|
45 | os.environ['RC_HOOK_VER'] = RC_HOOK_VER | |||
38 | try: |
|
46 | try: | |
39 | result = hooks.git_pre_receive(repo_path, push_data, os.environ) |
|
47 | result = hooks.git_pre_receive(repo_path, push_data, os.environ) | |
40 | sys.exit(result) |
|
48 | sys.exit(result) |
@@ -7,6 +7,11 b' path_adjust = [_PATH_]' | |||||
7 | if path_adjust: |
|
7 | if path_adjust: | |
8 | sys.path = path_adjust |
|
8 | sys.path = path_adjust | |
9 |
|
9 | |||
|
10 | # special trick to pass in some information from rc to hooks | |||
|
11 | # mod_dav strips ALL env vars and we can't even access things like PATH | |||
|
12 | for env_k, env_v in _OS_EXPAND_: | |||
|
13 | os.environ[env_k] = env_v | |||
|
14 | ||||
10 | try: |
|
15 | try: | |
11 | from vcsserver import hooks |
|
16 | from vcsserver import hooks | |
12 | except ImportError: |
|
17 | except ImportError: | |
@@ -20,11 +25,6 b' except ImportError:' | |||||
20 | RC_HOOK_VER = '_TMPL_' |
|
25 | RC_HOOK_VER = '_TMPL_' | |
21 |
|
26 | |||
22 |
|
27 | |||
23 | # special trick to pass in some information from rc to hooks |
|
|||
24 | # mod_dav strips ALL env vars and we can't even access things like PATH |
|
|||
25 | for env_k, env_v in _OS_EXPAND_: |
|
|||
26 | os.environ[env_k] = env_v |
|
|||
27 |
|
||||
28 | def main(): |
|
28 | def main(): | |
29 | if hooks is None: |
|
29 | if hooks is None: | |
30 | # exit with success if we cannot import vcsserver.hooks !! |
|
30 | # exit with success if we cannot import vcsserver.hooks !! | |
@@ -33,13 +33,13 b' def main():' | |||||
33 |
|
33 | |||
34 | if os.environ.get('RC_SKIP_HOOKS') or os.environ.get('RC_SKIP_SVN_HOOKS'): |
|
34 | if os.environ.get('RC_SKIP_HOOKS') or os.environ.get('RC_SKIP_SVN_HOOKS'): | |
35 | sys.exit(0) |
|
35 | sys.exit(0) | |
36 | repo_path = os.getcwd() |
|
36 | cwd_repo_path = os.getcwd() | |
37 | push_data = sys.argv[1:] |
|
37 | push_data = sys.argv[1:] | |
38 |
|
38 | |||
39 | os.environ['RC_HOOK_VER'] = RC_HOOK_VER |
|
39 | os.environ['RC_HOOK_VER'] = RC_HOOK_VER | |
40 |
|
40 | |||
41 | try: |
|
41 | try: | |
42 | result = hooks.svn_post_commit(repo_path, push_data, os.environ) |
|
42 | result = hooks.svn_post_commit(cwd_repo_path, push_data, os.environ) | |
43 | sys.exit(result) |
|
43 | sys.exit(result) | |
44 | except Exception as error: |
|
44 | except Exception as error: | |
45 | # TODO: johbo: Improve handling of this special case |
|
45 | # TODO: johbo: Improve handling of this special case |
@@ -7,6 +7,11 b' path_adjust = [_PATH_]' | |||||
7 | if path_adjust: |
|
7 | if path_adjust: | |
8 | sys.path = path_adjust |
|
8 | sys.path = path_adjust | |
9 |
|
9 | |||
|
10 | # special trick to pass in some information from rc to hooks | |||
|
11 | # mod_dav strips ALL env vars and we can't even access things like PATH | |||
|
12 | for env_k, env_v in _OS_EXPAND_: | |||
|
13 | os.environ[env_k] = env_v | |||
|
14 | ||||
10 | try: |
|
15 | try: | |
11 | from vcsserver import hooks |
|
16 | from vcsserver import hooks | |
12 | except ImportError: |
|
17 | except ImportError: | |
@@ -20,11 +25,6 b' except ImportError:' | |||||
20 | RC_HOOK_VER = '_TMPL_' |
|
25 | RC_HOOK_VER = '_TMPL_' | |
21 |
|
26 | |||
22 |
|
27 | |||
23 | # special trick to pass in some information from rc to hooks |
|
|||
24 | # mod_dav strips ALL env vars and we can't even access things like PATH |
|
|||
25 | for env_k, env_v in _OS_EXPAND_: |
|
|||
26 | os.environ[env_k] = env_v |
|
|||
27 |
|
||||
28 | def main(): |
|
28 | def main(): | |
29 | if os.environ.get('SSH_READ_ONLY') == '1': |
|
29 | if os.environ.get('SSH_READ_ONLY') == '1': | |
30 | sys.stderr.write('Only read-only access is allowed') |
|
30 | sys.stderr.write('Only read-only access is allowed') | |
@@ -37,13 +37,12 b' def main():' | |||||
37 |
|
37 | |||
38 | if os.environ.get('RC_SKIP_HOOKS') or os.environ.get('RC_SKIP_SVN_HOOKS'): |
|
38 | if os.environ.get('RC_SKIP_HOOKS') or os.environ.get('RC_SKIP_SVN_HOOKS'): | |
39 | sys.exit(0) |
|
39 | sys.exit(0) | |
40 | repo_path = os.getcwd() |
|
40 | cwd_repo_path = os.getcwd() | |
41 | push_data = sys.argv[1:] |
|
41 | push_data = sys.argv[1:] | |
42 |
|
42 | |||
43 | os.environ['RC_HOOK_VER'] = RC_HOOK_VER |
|
43 | os.environ['RC_HOOK_VER'] = RC_HOOK_VER | |
44 |
|
||||
45 | try: |
|
44 | try: | |
46 | result = hooks.svn_pre_commit(repo_path, push_data, os.environ) |
|
45 | result = hooks.svn_pre_commit(cwd_repo_path, push_data, os.environ) | |
47 | sys.exit(result) |
|
46 | sys.exit(result) | |
48 | except Exception as error: |
|
47 | except Exception as error: | |
49 | # TODO: johbo: Improve handling of this special case |
|
48 | # TODO: johbo: Improve handling of this special case |
@@ -31,9 +31,10 b' from celery import Celery' | |||||
31 | import mercurial.scmutil |
|
31 | import mercurial.scmutil | |
32 | import mercurial.node |
|
32 | import mercurial.node | |
33 |
|
33 | |||
|
34 | from vcsserver import exceptions, subprocessio, settings | |||
34 | from vcsserver.lib.ext_json import json |
|
35 | from vcsserver.lib.ext_json import json | |
35 | from vcsserver import exceptions, subprocessio, settings |
|
|||
36 | from vcsserver.lib.str_utils import ascii_str, safe_str |
|
36 | from vcsserver.lib.str_utils import ascii_str, safe_str | |
|
37 | from vcsserver.lib.svn_txn_utils import get_txn_id_from_store | |||
37 | from vcsserver.remote.git_remote import Repository |
|
38 | from vcsserver.remote.git_remote import Repository | |
38 |
|
39 | |||
39 | celery_app = Celery('__vcsserver__') |
|
40 | celery_app = Celery('__vcsserver__') | |
@@ -293,20 +294,28 b' def _get_hg_env(old_rev, new_rev, txnid,' | |||||
293 | return [(k, v) for k, v in env.items()] |
|
294 | return [(k, v) for k, v in env.items()] | |
294 |
|
295 | |||
295 |
|
296 | |||
|
297 | def _get_ini_settings(ini_file): | |||
|
298 | from vcsserver.http_main import sanitize_settings_and_apply_defaults | |||
|
299 | from vcsserver.lib.config_utils import get_app_config_lightweight, configure_and_store_settings | |||
|
300 | ||||
|
301 | global_config = {'__file__': ini_file} | |||
|
302 | ini_settings = get_app_config_lightweight(ini_file) | |||
|
303 | sanitize_settings_and_apply_defaults(global_config, ini_settings) | |||
|
304 | configure_and_store_settings(global_config, ini_settings) | |||
|
305 | ||||
|
306 | return ini_settings | |||
|
307 | ||||
|
308 | ||||
296 | def _fix_hooks_executables(ini_path=''): |
|
309 | def _fix_hooks_executables(ini_path=''): | |
297 | """ |
|
310 | """ | |
298 | This is a trick to set proper settings.EXECUTABLE paths for certain execution patterns |
|
311 | This is a trick to set proper settings.EXECUTABLE paths for certain execution patterns | |
299 | especially for subversion where hooks strip entire env, and calling just 'svn' command will most likely fail |
|
312 | especially for subversion where hooks strip entire env, and calling just 'svn' command will most likely fail | |
300 | because svn is not on PATH |
|
313 | because svn is not on PATH | |
301 | """ |
|
314 | """ | |
302 | from vcsserver.http_main import sanitize_settings_and_apply_defaults |
|
315 | # set defaults, in case we can't read from ini_file | |
303 | from vcsserver.lib.config_utils import get_app_config_lightweight |
|
|||
304 |
|
||||
305 | core_binary_dir = settings.BINARY_DIR or '/usr/local/bin/rhodecode_bin/vcs_bin' |
|
316 | core_binary_dir = settings.BINARY_DIR or '/usr/local/bin/rhodecode_bin/vcs_bin' | |
306 | if ini_path: |
|
317 | if ini_path: | |
307 |
|
318 | ini_settings = _get_ini_settings(ini_path) | ||
308 | ini_settings = get_app_config_lightweight(ini_path) |
|
|||
309 | ini_settings = sanitize_settings_and_apply_defaults({'__file__': ini_path}, ini_settings) |
|
|||
310 | core_binary_dir = ini_settings['core.binary_dir'] |
|
319 | core_binary_dir = ini_settings['core.binary_dir'] | |
311 |
|
320 | |||
312 | settings.BINARY_DIR = core_binary_dir |
|
321 | settings.BINARY_DIR = core_binary_dir | |
@@ -570,7 +579,7 b' def git_pre_receive(unused_repo_path, re' | |||||
570 | rev_data = _parse_git_ref_lines(revision_lines) |
|
579 | rev_data = _parse_git_ref_lines(revision_lines) | |
571 | if 'push' not in extras['hooks']: |
|
580 | if 'push' not in extras['hooks']: | |
572 | return 0 |
|
581 | return 0 | |
573 | _fix_hooks_executables() |
|
582 | _fix_hooks_executables(env.get('RC_INI_FILE')) | |
574 |
|
583 | |||
575 | empty_commit_id = '0' * 40 |
|
584 | empty_commit_id = '0' * 40 | |
576 |
|
585 | |||
@@ -616,7 +625,7 b' def git_post_receive(unused_repo_path, r' | |||||
616 | if 'push' not in extras['hooks']: |
|
625 | if 'push' not in extras['hooks']: | |
617 | return 0 |
|
626 | return 0 | |
618 |
|
627 | |||
619 | _fix_hooks_executables() |
|
628 | _fix_hooks_executables(env.get('RC_INI_FILE')) | |
620 |
|
629 | |||
621 | rev_data = _parse_git_ref_lines(revision_lines) |
|
630 | rev_data = _parse_git_ref_lines(revision_lines) | |
622 |
|
631 | |||
@@ -720,37 +729,8 b' def git_post_receive(unused_repo_path, r' | |||||
720 | return status_code |
|
729 | return status_code | |
721 |
|
730 | |||
722 |
|
731 | |||
723 |
def |
|
732 | def get_extras_from_txn_id(repo_path, txn_id): | |
724 | _fix_hooks_executables() |
|
733 | extras = get_txn_id_from_store(repo_path, txn_id) | |
725 |
|
||||
726 | extras = {} |
|
|||
727 | try: |
|
|||
728 | cmd = [settings.SVNLOOK_EXECUTABLE(), 'pget', |
|
|||
729 | '-t', txn_id, |
|
|||
730 | '--revprop', path, 'rc-scm-extras'] |
|
|||
731 | stdout, stderr = subprocessio.run_command( |
|
|||
732 | cmd, env=os.environ.copy()) |
|
|||
733 | extras = json.loads(base64.urlsafe_b64decode(stdout)) |
|
|||
734 | except Exception: |
|
|||
735 | log.exception('Failed to extract extras info from txn_id') |
|
|||
736 |
|
||||
737 | return extras |
|
|||
738 |
|
||||
739 |
|
||||
740 | def _get_extras_from_commit_id(commit_id, path): |
|
|||
741 | _fix_hooks_executables() |
|
|||
742 |
|
||||
743 | extras = {} |
|
|||
744 | try: |
|
|||
745 | cmd = [settings.SVNLOOK_EXECUTABLE(), 'pget', |
|
|||
746 | '-r', commit_id, |
|
|||
747 | '--revprop', path, 'rc-scm-extras'] |
|
|||
748 | stdout, stderr = subprocessio.run_command( |
|
|||
749 | cmd, env=os.environ.copy()) |
|
|||
750 | extras = json.loads(base64.urlsafe_b64decode(stdout)) |
|
|||
751 | except Exception: |
|
|||
752 | log.exception('Failed to extract extras info from commit_id') |
|
|||
753 |
|
||||
754 | return extras |
|
734 | return extras | |
755 |
|
735 | |||
756 |
|
736 | |||
@@ -763,13 +743,18 b' def svn_pre_commit(repo_path, commit_dat' | |||||
763 | if env.get('RC_SCM_DATA'): |
|
743 | if env.get('RC_SCM_DATA'): | |
764 | extras = json.loads(env['RC_SCM_DATA']) |
|
744 | extras = json.loads(env['RC_SCM_DATA']) | |
765 | else: |
|
745 | else: | |
|
746 | ini_path = env.get('RC_INI_FILE') | |||
|
747 | if ini_path: | |||
|
748 | _get_ini_settings(ini_path) | |||
766 | # fallback method to read from TXN-ID stored data |
|
749 | # fallback method to read from TXN-ID stored data | |
767 |
extras = |
|
750 | extras = get_extras_from_txn_id(path, txn_id) | |
768 |
|
751 | |||
769 | if not extras: |
|
752 | if not extras: | |
770 | #TODO: temporary fix until svn txn-id changes are merged |
|
753 | raise ValueError('SVN-PRE-COMMIT: Failed to extract context data in called extras for hook execution') | |
|
754 | ||||
|
755 | if extras.get('rc_internal_commit'): | |||
|
756 | # special marker for internal commit, we don't call hooks client | |||
771 | return 0 |
|
757 | return 0 | |
772 | raise ValueError('Failed to extract context data called extras for hook execution') |
|
|||
773 |
|
758 | |||
774 | extras['hook_type'] = 'pre_commit' |
|
759 | extras['hook_type'] = 'pre_commit' | |
775 | extras['commit_ids'] = [txn_id] |
|
760 | extras['commit_ids'] = [txn_id] | |
@@ -805,13 +790,18 b' def svn_post_commit(repo_path, commit_da' | |||||
805 | if env.get('RC_SCM_DATA'): |
|
790 | if env.get('RC_SCM_DATA'): | |
806 | extras = json.loads(env['RC_SCM_DATA']) |
|
791 | extras = json.loads(env['RC_SCM_DATA']) | |
807 | else: |
|
792 | else: | |
|
793 | ini_path = env.get('RC_INI_FILE') | |||
|
794 | if ini_path: | |||
|
795 | _get_ini_settings(ini_path) | |||
808 | # fallback method to read from TXN-ID stored data |
|
796 | # fallback method to read from TXN-ID stored data | |
809 |
extras = |
|
797 | extras = get_extras_from_txn_id(path, txn_id) | |
810 |
|
798 | |||
811 | if not extras: |
|
799 | if not extras and txn_id: | |
812 | #TODO: temporary fix until svn txn-id changes are merged |
|
800 | raise ValueError('SVN-POST-COMMIT: Failed to extract context data in called extras for hook execution') | |
|
801 | ||||
|
802 | if extras.get('rc_internal_commit'): | |||
|
803 | # special marker for internal commit, we don't call hooks client | |||
813 | return 0 |
|
804 | return 0 | |
814 | raise ValueError('Failed to extract context data called extras for hook execution') |
|
|||
815 |
|
805 | |||
816 | extras['hook_type'] = 'post_commit' |
|
806 | extras['hook_type'] = 'post_commit' | |
817 | extras['commit_ids'] = [commit_id] |
|
807 | extras['commit_ids'] = [commit_id] |
@@ -37,20 +37,23 b' from pyramid.wsgi import wsgiapp' | |||||
37 | from pyramid.response import Response |
|
37 | from pyramid.response import Response | |
38 |
|
38 | |||
39 | from vcsserver.base import BytesEnvelope, BinaryEnvelope |
|
39 | from vcsserver.base import BytesEnvelope, BinaryEnvelope | |
40 | from vcsserver.lib.ext_json import json |
|
40 | ||
41 | from vcsserver.config.settings_maker import SettingsMaker |
|
41 | from vcsserver.config.settings_maker import SettingsMaker | |
42 | from vcsserver.lib.str_utils import safe_int |
|
42 | ||
43 | from vcsserver.lib.statsd_client import StatsdClient |
|
|||
44 | from vcsserver.tweens.request_wrapper import get_headers_call_context |
|
43 | from vcsserver.tweens.request_wrapper import get_headers_call_context | |
45 |
|
44 | |||
46 | import vcsserver |
|
45 | from vcsserver import remote_wsgi, scm_app, hgpatches | |
47 | from vcsserver import remote_wsgi, scm_app, settings, hgpatches |
|
46 | from vcsserver.server import VcsServer | |
48 | from vcsserver.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT |
|
47 | from vcsserver.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT | |
49 | from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub |
|
48 | from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub | |
50 | from vcsserver.echo_stub.echo_app import EchoApp |
|
49 | from vcsserver.echo_stub.echo_app import EchoApp | |
51 | from vcsserver.exceptions import HTTPRepoLocked, HTTPRepoBranchProtected |
|
50 | from vcsserver.exceptions import HTTPRepoLocked, HTTPRepoBranchProtected | |
52 | from vcsserver.lib.exc_tracking import store_exception, format_exc |
|
51 | from vcsserver.lib.exc_tracking import store_exception, format_exc | |
53 |
from vcsserver. |
|
52 | from vcsserver.lib.str_utils import safe_int | |
|
53 | from vcsserver.lib.statsd_client import StatsdClient | |||
|
54 | from vcsserver.lib.ext_json import json | |||
|
55 | from vcsserver.lib.config_utils import configure_and_store_settings | |||
|
56 | ||||
54 |
|
57 | |||
55 | strict_vcs = True |
|
58 | strict_vcs = True | |
56 |
|
59 | |||
@@ -94,8 +97,7 b' log = logging.getLogger(__name__)' | |||||
94 | try: |
|
97 | try: | |
95 | locale.setlocale(locale.LC_ALL, '') |
|
98 | locale.setlocale(locale.LC_ALL, '') | |
96 | except locale.Error as e: |
|
99 | except locale.Error as e: | |
97 | log.error( |
|
100 | log.error('LOCALE ERROR: failed to set LC_ALL, fallback to LC_ALL=C, org error: %s', e) | |
98 | 'LOCALE ERROR: failed to set LC_ALL, fallback to LC_ALL=C, org error: %s', e) |
|
|||
99 | os.environ['LC_ALL'] = 'C' |
|
101 | os.environ['LC_ALL'] = 'C' | |
100 |
|
102 | |||
101 |
|
103 | |||
@@ -248,25 +250,10 b' class HTTPApplication:' | |||||
248 | log.warning("Using EchoApp for VCS operations.") |
|
250 | log.warning("Using EchoApp for VCS operations.") | |
249 | self.remote_wsgi = remote_wsgi_stub |
|
251 | self.remote_wsgi = remote_wsgi_stub | |
250 |
|
252 | |||
251 |
|
|
253 | configure_and_store_settings(global_config, settings) | |
252 |
|
254 | |||
253 | self._configure() |
|
255 | self._configure() | |
254 |
|
256 | |||
255 | def _configure_settings(self, global_config, app_settings): |
|
|||
256 | """ |
|
|||
257 | Configure the settings module. |
|
|||
258 | """ |
|
|||
259 | settings_merged = global_config.copy() |
|
|||
260 | settings_merged.update(app_settings) |
|
|||
261 |
|
||||
262 | binary_dir = app_settings['core.binary_dir'] |
|
|||
263 |
|
||||
264 | settings.BINARY_DIR = binary_dir |
|
|||
265 |
|
||||
266 | # Store the settings to make them available to other modules. |
|
|||
267 | vcsserver.PYRAMID_SETTINGS = settings_merged |
|
|||
268 | vcsserver.CONFIG = settings_merged |
|
|||
269 |
|
||||
270 | def _configure(self): |
|
257 | def _configure(self): | |
271 | self.config.add_renderer(name='msgpack', factory=self._msgpack_renderer_factory) |
|
258 | self.config.add_renderer(name='msgpack', factory=self._msgpack_renderer_factory) | |
272 |
|
259 | |||
@@ -715,6 +702,8 b' def sanitize_settings_and_apply_defaults' | |||||
715 | 'core.binary_dir', '/usr/local/bin/rhodecode_bin/vcs_bin', |
|
702 | 'core.binary_dir', '/usr/local/bin/rhodecode_bin/vcs_bin', | |
716 | default_when_empty=True, parser='string:noquote') |
|
703 | default_when_empty=True, parser='string:noquote') | |
717 |
|
704 | |||
|
705 | settings_maker.make_setting('vcs.svn.redis_conn', 'redis://redis:6379/0') | |||
|
706 | ||||
718 | temp_store = tempfile.gettempdir() |
|
707 | temp_store = tempfile.gettempdir() | |
719 | default_cache_dir = os.path.join(temp_store, 'rc_cache') |
|
708 | default_cache_dir = os.path.join(temp_store, 'rc_cache') | |
720 | # save default, cache dir, and use it for all backends later. |
|
709 | # save default, cache dir, and use it for all backends later. |
@@ -16,6 +16,8 b'' | |||||
16 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
16 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
18 | import os |
|
18 | import os | |
|
19 | import vcsserver | |||
|
20 | import vcsserver.settings | |||
19 |
|
21 | |||
20 |
|
22 | |||
21 | def get_config(ini_path, **kwargs): |
|
23 | def get_config(ini_path, **kwargs): | |
@@ -38,3 +40,19 b' def get_app_config(ini_path):' | |||||
38 | """ |
|
40 | """ | |
39 | from paste.deploy.loadwsgi import appconfig |
|
41 | from paste.deploy.loadwsgi import appconfig | |
40 | return appconfig(f'config:{ini_path}', relative_to=os.getcwd()) |
|
42 | return appconfig(f'config:{ini_path}', relative_to=os.getcwd()) | |
|
43 | ||||
|
44 | ||||
|
45 | def configure_and_store_settings(global_config, app_settings): | |||
|
46 | """ | |||
|
47 | Configure the settings module. | |||
|
48 | """ | |||
|
49 | settings_merged = global_config.copy() | |||
|
50 | settings_merged.update(app_settings) | |||
|
51 | ||||
|
52 | binary_dir = app_settings['core.binary_dir'] | |||
|
53 | ||||
|
54 | vcsserver.settings.BINARY_DIR = binary_dir | |||
|
55 | ||||
|
56 | # Store the settings to make them available to other modules. | |||
|
57 | vcsserver.PYRAMID_SETTINGS = settings_merged | |||
|
58 | vcsserver.CONFIG = settings_merged |
@@ -28,7 +28,6 b' import urllib.parse' | |||||
28 | import urllib.error |
|
28 | import urllib.error | |
29 | import traceback |
|
29 | import traceback | |
30 |
|
30 | |||
31 |
|
||||
32 | import svn.client # noqa |
|
31 | import svn.client # noqa | |
33 | import svn.core # noqa |
|
32 | import svn.core # noqa | |
34 | import svn.delta # noqa |
|
33 | import svn.delta # noqa | |
@@ -47,10 +46,11 b' from vcsserver.base import (' | |||||
47 | BinaryEnvelope, |
|
46 | BinaryEnvelope, | |
48 | ) |
|
47 | ) | |
49 | from vcsserver.exceptions import NoContentException |
|
48 | from vcsserver.exceptions import NoContentException | |
|
49 | from vcsserver.vcs_base import RemoteBase | |||
50 | from vcsserver.lib.str_utils import safe_str, safe_bytes |
|
50 | from vcsserver.lib.str_utils import safe_str, safe_bytes | |
51 | from vcsserver.lib.type_utils import assert_bytes |
|
51 | from vcsserver.lib.type_utils import assert_bytes | |
52 | from vcsserver.vcs_base import RemoteBase |
|
|||
53 | from vcsserver.lib.svnremoterepo import svnremoterepo |
|
52 | from vcsserver.lib.svnremoterepo import svnremoterepo | |
|
53 | from vcsserver.lib.svn_txn_utils import store_txn_id_data | |||
54 |
|
54 | |||
55 | log = logging.getLogger(__name__) |
|
55 | log = logging.getLogger(__name__) | |
56 |
|
56 | |||
@@ -503,6 +503,11 b' class SvnRemote(RemoteBase):' | |||||
503 | for node in removed: |
|
503 | for node in removed: | |
504 | TxnNodeProcessor(node, txn_root).remove() |
|
504 | TxnNodeProcessor(node, txn_root).remove() | |
505 |
|
505 | |||
|
506 | svn_txn_id = safe_str(svn.fs.svn_fs_txn_name(txn)) | |||
|
507 | full_repo_path = wire['path'] | |||
|
508 | txn_id_data = {'svn_txn_id': svn_txn_id, 'rc_internal_commit': True} | |||
|
509 | ||||
|
510 | store_txn_id_data(full_repo_path, svn_txn_id, txn_id_data) | |||
506 | commit_id = svn.repos.fs_commit_txn(repo, txn) |
|
511 | commit_id = svn.repos.fs_commit_txn(repo, txn) | |
507 |
|
512 | |||
508 | if timestamp: |
|
513 | if timestamp: |
General Comments 0
You need to be logged in to leave comments.
Login now