##// END OF EJS Templates
fix(svn): fixed problems with svn hooks binary dir not beeing propagates in mod_dav_svn
super-admin -
r1229:fe30068d v5.0.1 stable
parent child Browse files
Show More
@@ -0,0 +1,40 b''
1 # Copyright (C) 2010-2023 RhodeCode GmbH
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18 import os
19
20
21 def get_config(ini_path, **kwargs):
22 import configparser
23 parser = configparser.ConfigParser(**kwargs)
24 parser.read(ini_path)
25 return parser
26
27
28 def get_app_config_lightweight(ini_path):
29 parser = get_config(ini_path)
30 parser.set('app:main', 'here', os.getcwd())
31 parser.set('app:main', '__file__', ini_path)
32 return dict(parser.items('app:main'))
33
34
35 def get_app_config(ini_path):
36 """
37 This loads the app context and provides a heavy type iniliaziation of config
38 """
39 from paste.deploy.loadwsgi import appconfig
40 return appconfig(f'config:{ini_path}', relative_to=os.getcwd())
@@ -28,6 +28,7 b' from vcsserver.type_utils import str2boo'
28 28
29 29 log = logging.getLogger(__name__)
30 30
31
31 32 # skip keys, that are set here, so we don't double process those
32 33 set_keys = {
33 34 '__file__': ''
@@ -51,6 +52,10 b' class SettingsMaker:'
51 52 return int(input_val)
52 53
53 54 @classmethod
55 def _float_func(cls, input_val):
56 return float(input_val)
57
58 @classmethod
54 59 def _list_func(cls, input_val, sep=','):
55 60 return aslist(input_val, sep=sep)
56 61
@@ -61,8 +66,18 b' class SettingsMaker:'
61 66 return input_val
62 67
63 68 @classmethod
64 def _float_func(cls, input_val):
65 return float(input_val)
69 def _string_no_quote_func(cls, input_val, lower=True):
70 """
71 Special case string function that detects if value is set to empty quote string
72 e.g.
73
74 core.binary_dir = ""
75 """
76
77 input_val = cls._string_func(input_val, lower=lower)
78 if input_val in ['""', "''"]:
79 return ''
80 return input_val
66 81
67 82 @classmethod
68 83 def _dir_func(cls, input_val, ensure_dir=False, mode=0o755):
@@ -148,10 +163,12 b' class SettingsMaker:'
148 163 parser_func = {
149 164 'bool': self._bool_func,
150 165 'int': self._int_func,
166 'float': self._float_func,
151 167 'list': self._list_func,
152 168 'list:newline': functools.partial(self._list_func, sep='/n'),
153 169 'list:spacesep': functools.partial(self._list_func, sep=' '),
154 170 'string': functools.partial(self._string_func, lower=lower),
171 'string:noquote': functools.partial(self._string_no_quote_func, lower=lower),
155 172 'dir': self._dir_func,
156 173 'dir:ensured': functools.partial(self._dir_func, ensure_dir=True),
157 174 'file': self._file_path_func,
@@ -142,9 +142,9 b' def install_svn_hooks(repo_path, executa'
142 142
143 143 env_expand = str([
144 144 ('RC_CORE_BINARY_DIR', vcsserver.settings.BINARY_DIR),
145 ('RC_GIT_EXECUTABLE', vcsserver.settings.GIT_EXECUTABLE),
146 ('RC_SVN_EXECUTABLE', vcsserver.settings.SVN_EXECUTABLE),
147 ('RC_SVNLOOK_EXECUTABLE', vcsserver.settings.SVNLOOK_EXECUTABLE),
145 ('RC_GIT_EXECUTABLE', vcsserver.settings.GIT_EXECUTABLE()),
146 ('RC_SVN_EXECUTABLE', vcsserver.settings.SVN_EXECUTABLE()),
147 ('RC_SVNLOOK_EXECUTABLE', vcsserver.settings.SVNLOOK_EXECUTABLE()),
148 148
149 149 ])
150 150 try:
@@ -31,7 +31,6 b' from celery import Celery'
31 31 import mercurial.scmutil
32 32 import mercurial.node
33 33
34 import vcsserver.settings
35 34 from vcsserver.lib.rc_json import json
36 35 from vcsserver import exceptions, subprocessio, settings
37 36 from vcsserver.str_utils import ascii_str, safe_str
@@ -294,20 +293,23 b' def _get_hg_env(old_rev, new_rev, txnid,'
294 293 return [(k, v) for k, v in env.items()]
295 294
296 295
297 def _fix_hooks_executables():
296 def _fix_hooks_executables(ini_path=''):
298 297 """
299 298 This is a trick to set proper settings.EXECUTABLE paths for certain execution patterns
300 299 especially for subversion where hooks strip entire env, and calling just 'svn' command will most likely fail
301 300 because svn is not on PATH
302 301 """
303 vcsserver.settings.BINARY_DIR = (
304 os.environ.get('RC_BINARY_DIR') or vcsserver.settings.BINARY_DIR)
305 vcsserver.settings.GIT_EXECUTABLE = (
306 os.environ.get('RC_GIT_EXECUTABLE') or vcsserver.settings.GIT_EXECUTABLE)
307 vcsserver.settings.SVN_EXECUTABLE = (
308 os.environ.get('RC_SVN_EXECUTABLE') or vcsserver.settings.SVN_EXECUTABLE)
309 vcsserver.settings.SVNLOOK_EXECUTABLE = (
310 os.environ.get('RC_SVNLOOK_EXECUTABLE') or vcsserver.settings.SVNLOOK_EXECUTABLE)
302 from vcsserver.http_main import sanitize_settings_and_apply_defaults
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'
306 if ini_path:
307
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']
311
312 settings.BINARY_DIR = core_binary_dir
311 313
312 314
313 315 def repo_size(ui, repo, **kwargs):
@@ -568,10 +570,12 b' def git_pre_receive(unused_repo_path, re'
568 570 rev_data = _parse_git_ref_lines(revision_lines)
569 571 if 'push' not in extras['hooks']:
570 572 return 0
573 _fix_hooks_executables()
574
571 575 empty_commit_id = '0' * 40
572 576
573 577 detect_force_push = extras.get('detect_force_push')
574 _fix_hooks_executables()
578
575 579 for push_ref in rev_data:
576 580 # store our git-env which holds the temp store
577 581 push_ref['git_env'] = _get_git_env()
@@ -586,7 +590,7 b' def git_pre_receive(unused_repo_path, re'
586 590 if type_ == 'heads' and not (new_branch or delete_branch):
587 591 old_rev = push_ref['old_rev']
588 592 new_rev = push_ref['new_rev']
589 cmd = [settings.GIT_EXECUTABLE, 'rev-list', old_rev, f'^{new_rev}']
593 cmd = [settings.GIT_EXECUTABLE(), 'rev-list', old_rev, f'^{new_rev}']
590 594 stdout, stderr = subprocessio.run_command(
591 595 cmd, env=os.environ.copy())
592 596 # means we're having some non-reachable objects, this forced push was used
@@ -611,6 +615,7 b' def git_post_receive(unused_repo_path, r'
611 615 extras = json.loads(env['RC_SCM_DATA'])
612 616 if 'push' not in extras['hooks']:
613 617 return 0
618
614 619 _fix_hooks_executables()
615 620
616 621 rev_data = _parse_git_ref_lines(revision_lines)
@@ -645,14 +650,14 b' def git_post_receive(unused_repo_path, r'
645 650 repo.set_head(need_head_set)
646 651 print(f"Setting default branch to {push_ref_name}")
647 652
648 cmd = [settings.GIT_EXECUTABLE, 'for-each-ref', '--format=%(refname)', 'refs/heads/*']
653 cmd = [settings.GIT_EXECUTABLE(), 'for-each-ref', '--format=%(refname)', 'refs/heads/*']
649 654 stdout, stderr = subprocessio.run_command(
650 655 cmd, env=os.environ.copy())
651 656 heads = safe_str(stdout)
652 657 heads = heads.replace(push_ref['ref'], '')
653 658 heads = ' '.join(head for head
654 659 in heads.splitlines() if head) or '.'
655 cmd = [settings.GIT_EXECUTABLE, 'log', '--reverse',
660 cmd = [settings.GIT_EXECUTABLE(), 'log', '--reverse',
656 661 '--pretty=format:%H', '--', push_ref['new_rev'],
657 662 '--not', heads]
658 663 stdout, stderr = subprocessio.run_command(
@@ -666,7 +671,7 b' def git_post_receive(unused_repo_path, r'
666 671 if push_ref['name'] not in branches:
667 672 branches.append(push_ref['name'])
668 673
669 cmd = [settings.GIT_EXECUTABLE, 'log',
674 cmd = [settings.GIT_EXECUTABLE(), 'log',
670 675 f'{push_ref["old_rev"]}..{push_ref["new_rev"]}',
671 676 '--reverse', '--pretty=format:%H']
672 677 stdout, stderr = subprocessio.run_command(
@@ -716,9 +721,11 b' def git_post_receive(unused_repo_path, r'
716 721
717 722
718 723 def _get_extras_from_txn_id(path, txn_id):
724 _fix_hooks_executables()
725
719 726 extras = {}
720 727 try:
721 cmd = [settings.SVNLOOK_EXECUTABLE, 'pget',
728 cmd = [settings.SVNLOOK_EXECUTABLE(), 'pget',
722 729 '-t', txn_id,
723 730 '--revprop', path, 'rc-scm-extras']
724 731 stdout, stderr = subprocessio.run_command(
@@ -731,9 +738,11 b' def _get_extras_from_txn_id(path, txn_id'
731 738
732 739
733 740 def _get_extras_from_commit_id(commit_id, path):
741 _fix_hooks_executables()
742
734 743 extras = {}
735 744 try:
736 cmd = [settings.SVNLOOK_EXECUTABLE, 'pget',
745 cmd = [settings.SVNLOOK_EXECUTABLE(), 'pget',
737 746 '-r', commit_id,
738 747 '--revprop', path, 'rc-scm-extras']
739 748 stdout, stderr = subprocessio.run_command(
@@ -746,11 +755,11 b' def _get_extras_from_commit_id(commit_id'
746 755
747 756
748 757 def svn_pre_commit(repo_path, commit_data, env):
758
749 759 path, txn_id = commit_data
750 760 branches = []
751 761 tags = []
752 762
753 _fix_hooks_executables()
754 763 if env.get('RC_SCM_DATA'):
755 764 extras = json.loads(env['RC_SCM_DATA'])
756 765 else:
@@ -790,7 +799,6 b' def svn_post_commit(repo_path, commit_da'
790 799 branches = []
791 800 tags = []
792 801
793 _fix_hooks_executables()
794 802 if env.get('RC_SCM_DATA'):
795 803 extras = json.loads(env['RC_SCM_DATA'])
796 804 else:
@@ -263,11 +263,6 b' class HTTPApplication:'
263 263
264 264 settings.BINARY_DIR = binary_dir
265 265
266 # from core.binary dir we set executable paths
267 settings.GIT_EXECUTABLE = os.path.join(binary_dir, settings.GIT_EXECUTABLE)
268 settings.SVN_EXECUTABLE = os.path.join(binary_dir, settings.SVN_EXECUTABLE)
269 settings.SVNLOOK_EXECUTABLE = os.path.join(binary_dir, settings.SVNLOOK_EXECUTABLE)
270
271 266 # Store the settings to make them available to other modules.
272 267 vcsserver.PYRAMID_SETTINGS = settings_merged
273 268 vcsserver.CONFIG = settings_merged
@@ -716,7 +711,9 b' def sanitize_settings_and_apply_defaults'
716 711 settings_maker.make_setting('pyramid.default_locale_name', 'en')
717 712 settings_maker.make_setting('locale', 'en_US.UTF-8')
718 713
719 settings_maker.make_setting('core.binary_dir', '/usr/local/bin/rhodecode_bin/vcs_bin')
714 settings_maker.make_setting(
715 'core.binary_dir', '/usr/local/bin/rhodecode_bin/vcs_bin',
716 default_when_empty=True, parser='string:noquote')
720 717
721 718 temp_store = tempfile.gettempdir()
722 719 default_cache_dir = os.path.join(temp_store, 'rc_cache')
@@ -40,7 +40,7 b' from dulwich.repo import Repo as Dulwich'
40 40
41 41 import rhodecode
42 42 from vcsserver import exceptions, settings, subprocessio
43 from vcsserver.str_utils import safe_str, safe_int, safe_bytes, ascii_bytes, convert_to_str
43 from vcsserver.str_utils import safe_str, safe_int, safe_bytes, ascii_bytes, convert_to_str, splitnewlines
44 44 from vcsserver.base import RepoFactory, obfuscate_qs, ArchiveNode, store_archive_in_cache, BytesEnvelope, BinaryEnvelope
45 45 from vcsserver.hgcompat import (
46 46 hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler)
@@ -1347,7 +1347,8 b' class GitRemote(RemoteBase):'
1347 1347 with repo_init as repo:
1348 1348 commit = repo[commit_id]
1349 1349 blame_obj = repo.blame(path, newest_commit=commit_id)
1350 for i, line in enumerate(commit.tree[path].data.splitlines()):
1350 file_content = commit.tree[path].data
1351 for i, line in enumerate(splitnewlines(file_content)):
1351 1352 line_no = i + 1
1352 1353 hunk = blame_obj.for_line(line_no)
1353 1354 blame_commit_id = hunk.final_commit_id.hex
@@ -1423,7 +1424,7 b' class GitRemote(RemoteBase):'
1423 1424 gitenv['GIT_CONFIG_NOGLOBAL'] = '1'
1424 1425 gitenv['GIT_DISCOVERY_ACROSS_FILESYSTEM'] = '1'
1425 1426
1426 cmd = [settings.GIT_EXECUTABLE] + _copts + cmd
1427 cmd = [settings.GIT_EXECUTABLE()] + _copts + cmd
1427 1428 _opts = {'env': gitenv, 'shell': False}
1428 1429
1429 1430 proc = None
@@ -214,7 +214,7 b' def create_git_wsgi_app(repo_path, repo_'
214 214
215 215 :param config: is a dictionary holding the extras.
216 216 """
217 git_path = settings.GIT_EXECUTABLE
217 git_path = settings.GIT_EXECUTABLE()
218 218 update_server_info = config.pop('git_update_server_info')
219 219 app = GitHandler(
220 220 repo_path, repo_name, git_path, update_server_info, config)
@@ -244,7 +244,7 b' class GitLFSHandler:'
244 244
245 245
246 246 def create_git_lfs_wsgi_app(repo_path, repo_name, config):
247 git_path = settings.GIT_EXECUTABLE
247 git_path = settings.GIT_EXECUTABLE()
248 248 update_server_info = config.pop('git_update_server_info')
249 249 git_lfs_enabled = config.pop('git_lfs_enabled')
250 250 git_lfs_store_path = config.pop('git_lfs_store_path')
@@ -14,9 +14,18 b''
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software Foundation,
16 16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 import os
17 18
18 19 WIRE_ENCODING = 'UTF-8'
19 GIT_EXECUTABLE = 'git'
20 SVN_EXECUTABLE = 'svn'
21 SVNLOOK_EXECUTABLE = 'svnlook'
20
21 # Path where we can find binary dir
22 22 BINARY_DIR = ''
23
24 def GIT_EXECUTABLE() -> str:
25 return os.environ.get('RC_GIT_EXECUTABLE') or os.path.join(BINARY_DIR, 'git')
26
27 def SVN_EXECUTABLE() -> str:
28 return os.environ.get('RC_SVN_EXECUTABLE') or os.path.join(BINARY_DIR, 'svn')
29
30 def SVNLOOK_EXECUTABLE() -> str:
31 return os.environ.get('RC_SVNLOOK_EXECUTABLE') or os.path.join(BINARY_DIR, 'svnlook')
@@ -142,3 +142,17 b' def convert_to_str(data):'
142 142 return list(convert_to_str(item) for item in data)
143 143 else:
144 144 return data
145
146
147 def splitnewlines(text: bytes):
148 """
149 like splitlines, but only split on newlines.
150 """
151
152 lines = [_l + b'\n' for _l in text.split(b'\n')]
153 if lines:
154 if lines[-1] == b'\n':
155 lines.pop()
156 else:
157 lines[-1] = lines[-1][:-1]
158 return lines No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now