Show More
@@ -53,12 +53,6 b' def ArchiveException(org_exc=None):' | |||||
53 | return _make_exception_wrapper |
|
53 | return _make_exception_wrapper | |
54 |
|
54 | |||
55 |
|
55 | |||
56 | def ClientNotSupportedException(org_exc=None): |
|
|||
57 | def _make_exception_wrapper(*args): |
|
|||
58 | return _make_exception('client_not_supported', org_exc, *args) |
|
|||
59 | return _make_exception_wrapper |
|
|||
60 |
|
||||
61 |
|
||||
62 | def LookupException(org_exc=None): |
|
56 | def LookupException(org_exc=None): | |
63 | def _make_exception_wrapper(*args): |
|
57 | def _make_exception_wrapper(*args): | |
64 | return _make_exception('lookup', org_exc, *args) |
|
58 | return _make_exception('lookup', org_exc, *args) | |
@@ -82,6 +76,10 b' def RepositoryBranchProtectedException(o' | |||||
82 | return _make_exception('repo_branch_protected', org_exc, *args) |
|
76 | return _make_exception('repo_branch_protected', org_exc, *args) | |
83 | return _make_exception_wrapper |
|
77 | return _make_exception_wrapper | |
84 |
|
78 | |||
|
79 | def ClientNotSupportedException(org_exc=None): | |||
|
80 | def _make_exception_wrapper(*args): | |||
|
81 | return _make_exception('client_not_supported', org_exc, *args) | |||
|
82 | return _make_exception_wrapper | |||
85 |
|
83 | |||
86 | def RequirementException(org_exc=None): |
|
84 | def RequirementException(org_exc=None): | |
87 | def _make_exception_wrapper(*args): |
|
85 | def _make_exception_wrapper(*args): | |
@@ -118,9 +116,18 b' class HTTPRepoLocked(HTTPLocked):' | |||||
118 | super().__init__(**kwargs) |
|
116 | super().__init__(**kwargs) | |
119 |
|
117 | |||
120 |
|
118 | |||
121 |
class HTTPRepoBranchProtected(HTTP |
|
119 | class HTTPRepoBranchProtected(HTTPLocked): | |
122 |
def __init__(self, |
|
120 | def __init__(self, title, status_code=None, **kwargs): | |
123 | super(HTTPForbidden, self).__init__(*args, **kwargs) |
|
121 | self.code = status_code or HTTPLocked.code | |
|
122 | self.title = title | |||
|
123 | super().__init__(**kwargs) | |||
|
124 | ||||
|
125 | ||||
|
126 | class HTTPClientNotSupported(HTTPLocked): | |||
|
127 | def __init__(self, title, status_code=None, **kwargs): | |||
|
128 | self.code = status_code or HTTPLocked.code | |||
|
129 | self.title = title | |||
|
130 | super().__init__(**kwargs) | |||
124 |
|
131 | |||
125 |
|
132 | |||
126 | class RefNotFoundException(KeyError): |
|
133 | class RefNotFoundException(KeyError): |
@@ -1,5 +1,5 b'' | |||||
1 | # RhodeCode VCSServer provides access to different vcs backends via network. |
|
1 | # RhodeCode VCSServer provides access to different vcs backends via network. | |
2 |
# Copyright (C) 2014-202 |
|
2 | # Copyright (C) 2014-2024 RhodeCode GmbH | |
3 | # |
|
3 | # | |
4 | # This program is free software; you can redistribute it and/or modify |
|
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 |
|
5 | # it under the terms of the GNU General Public License as published by | |
@@ -56,6 +56,9 b' class HooksCeleryClient:' | |||||
56 | self.celery_app = celery_app |
|
56 | self.celery_app = celery_app | |
57 |
|
57 | |||
58 | def __call__(self, method, extras): |
|
58 | def __call__(self, method, extras): | |
|
59 | # NOTE: exception handling for those tasks executed is in | |||
|
60 | # @adapt_for_celery decorator | |||
|
61 | # also see: _maybe_handle_exception which is handling exceptions | |||
59 | inquired_task = self.celery_app.signature( |
|
62 | inquired_task = self.celery_app.signature( | |
60 | f'rhodecode.lib.celerylib.tasks.{method}' |
|
63 | f'rhodecode.lib.celerylib.tasks.{method}' | |
61 | ) |
|
64 | ) | |
@@ -83,11 +86,8 b' class HgMessageWriter(RemoteMessageWrite' | |||||
83 | self.ui = ui |
|
86 | self.ui = ui | |
84 |
|
87 | |||
85 | def write(self, message: str): |
|
88 | def write(self, message: str): | |
86 | # TODO: Check why the quiet flag is set by default. |
|
89 | args = (message.encode('utf-8'),) | |
87 | old = self.ui.quiet |
|
90 | self.ui._writemsg(self.ui._fmsgerr, type=b'status', *args) | |
88 | self.ui.quiet = False |
|
|||
89 | self.ui.status(message.encode('utf-8')) |
|
|||
90 | self.ui.quiet = old |
|
|||
91 |
|
91 | |||
92 |
|
92 | |||
93 | class GitMessageWriter(RemoteMessageWriter): |
|
93 | class GitMessageWriter(RemoteMessageWriter): | |
@@ -97,7 +97,7 b' class GitMessageWriter(RemoteMessageWrit' | |||||
97 | self.stdout = stdout or sys.stdout |
|
97 | self.stdout = stdout or sys.stdout | |
98 |
|
98 | |||
99 | def write(self, message: str): |
|
99 | def write(self, message: str): | |
100 | self.stdout.write(message) |
|
100 | self.stdout.write(message + "\n" if message else "") | |
101 |
|
101 | |||
102 |
|
102 | |||
103 | class SvnMessageWriter(RemoteMessageWriter): |
|
103 | class SvnMessageWriter(RemoteMessageWriter): | |
@@ -111,28 +111,30 b' class SvnMessageWriter(RemoteMessageWrit' | |||||
111 | self.stderr.write(message) |
|
111 | self.stderr.write(message) | |
112 |
|
112 | |||
113 |
|
113 | |||
114 | def _maybe_handle_exception(result): |
|
114 | def _maybe_handle_exception(writer, result): | |
115 |
|
115 | """ | ||
|
116 | adopt_for_celery defines the exception/exception_traceback | |||
|
117 | Ths result is a direct output from a celery task | |||
|
118 | """ | |||
116 |
|
119 | |||
117 | exception_class = result.get('exception') |
|
120 | exception_class = result.get('exception') | |
118 | exception_traceback = result.get('exception_traceback') |
|
121 | exception_traceback = result.get('exception_traceback') | |
119 | if not exception_class: |
|
|||
120 | return |
|
|||
121 |
|
122 | |||
122 | log.debug('Handling hook-call exception: %s', exception_class) |
|
123 | match exception_class: | |
123 |
|
124 | # NOTE: the underlying exceptions are setting _vcs_kind special marker | ||
124 | if exception_traceback: |
|
125 | # which is later handled by `handle_vcs_exception` and translated into a special HTTP exception | |
125 | log.error('Got traceback from remote call:%s', exception_traceback) |
|
126 | # propagated later to the client | |
126 |
|
127 | case 'HTTPLockedRepo': | ||
127 | if exception_class == 'HTTPLockedRepo': |
|
|||
128 | raise exceptions.LockedRepoException()(*result['exception_args']) |
|
128 | raise exceptions.LockedRepoException()(*result['exception_args']) | |
129 |
|
|
129 | case 'ClientNotSupported': | |
130 | raise exceptions.ClientNotSupportedException()(*result['exception_args']) |
|
130 | raise exceptions.ClientNotSupportedException()(*result['exception_args']) | |
131 |
|
|
131 | case 'HTTPBranchProtected': | |
132 | raise exceptions.RepositoryBranchProtectedException()(*result['exception_args']) |
|
132 | raise exceptions.RepositoryBranchProtectedException()(*result['exception_args']) | |
133 |
|
|
133 | case 'RepositoryError': | |
134 | raise exceptions.VcsException()(*result['exception_args']) |
|
134 | raise exceptions.VcsException()(*result['exception_args']) | |
135 | elif exception_class: |
|
135 | case _: | |
|
136 | if exception_class: | |||
|
137 | log.error('Handling hook-call exception. Got traceback from remote call:%s', exception_traceback) | |||
136 | raise Exception( |
|
138 | raise Exception( | |
137 | f"""Got remote exception "{exception_class}" with args "{result['exception_args']}" """ |
|
139 | f"""Got remote exception "{exception_class}" with args "{result['exception_args']}" """ | |
138 | ) |
|
140 | ) | |
@@ -156,7 +158,7 b' def _call_hook(hook_name, extras, writer' | |||||
156 | log.debug('Hooks, using client:%s', hooks_client) |
|
158 | log.debug('Hooks, using client:%s', hooks_client) | |
157 | result = hooks_client(hook_name, extras) |
|
159 | result = hooks_client(hook_name, extras) | |
158 | log.debug('Hooks got result: %s', result) |
|
160 | log.debug('Hooks got result: %s', result) | |
159 | _maybe_handle_exception(result) |
|
161 | _maybe_handle_exception(writer, result) | |
160 | writer.write(result['output']) |
|
162 | writer.write(result['output']) | |
161 |
|
163 | |||
162 | return result['status'] |
|
164 | return result['status'] |
@@ -47,7 +47,7 b' from vcsserver.server import VcsServer' | |||||
47 | 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 | |
48 | from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub |
|
48 | from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub | |
49 | from vcsserver.echo_stub.echo_app import EchoApp |
|
49 | from vcsserver.echo_stub.echo_app import EchoApp | |
50 | from vcsserver.exceptions import HTTPRepoLocked, HTTPRepoBranchProtected |
|
50 | from vcsserver.exceptions import HTTPRepoLocked, HTTPRepoBranchProtected, HTTPClientNotSupported | |
51 | from vcsserver.lib.exc_tracking import store_exception, format_exc |
|
51 | from vcsserver.lib.exc_tracking import store_exception, format_exc | |
52 | from vcsserver.lib.str_utils import safe_int |
|
52 | from vcsserver.lib.str_utils import safe_int | |
53 | from vcsserver.lib.statsd_client import StatsdClient |
|
53 | from vcsserver.lib.statsd_client import StatsdClient | |
@@ -635,19 +635,21 b' class HTTPApplication:' | |||||
635 | return _git_stream |
|
635 | return _git_stream | |
636 |
|
636 | |||
637 | def handle_vcs_exception(self, exception, request): |
|
637 | def handle_vcs_exception(self, exception, request): | |
638 | _vcs_kind = getattr(exception, '_vcs_kind', '') |
|
|||
639 |
|
638 | |||
640 |
|
|
639 | match _vcs_kind := getattr(exception, '_vcs_kind', ''): | |
|
640 | case 'repo_locked': | |||
641 | headers_call_context = get_headers_call_context(request.environ) |
|
641 | headers_call_context = get_headers_call_context(request.environ) | |
642 | status_code = safe_int(headers_call_context['locked_status_code']) |
|
642 | status_code = safe_int(headers_call_context['locked_status_code']) | |
643 |
|
643 | |||
644 | return HTTPRepoLocked( |
|
644 | return HTTPRepoLocked( | |
645 | title=str(exception), status_code=status_code, headers=[('X-Rc-Locked', '1')]) |
|
645 | title=str(exception), status_code=status_code, headers=[('X-Rc-Locked', '1')]) | |
646 |
|
646 | case 'repo_branch_protected': | ||
647 | elif _vcs_kind == 'repo_branch_protected': |
|
|||
648 | # Get custom repo-branch-protected status code if present. |
|
647 | # Get custom repo-branch-protected status code if present. | |
649 | return HTTPRepoBranchProtected( |
|
648 | return HTTPRepoBranchProtected( | |
650 | title=str(exception), headers=[('X-Rc-Branch-Protection', '1')]) |
|
649 | title=str(exception), headers=[('X-Rc-Branch-Protection', '1')]) | |
|
650 | case 'client_not_supported': | |||
|
651 | return HTTPClientNotSupported( | |||
|
652 | title=str(exception), headers=[('X-Rc-Client-Not-Supported', '1')]) | |||
651 |
|
653 | |||
652 | exc_info = request.exc_info |
|
654 | exc_info = request.exc_info | |
653 | store_exception(id(exc_info), exc_info) |
|
655 | store_exception(id(exc_info), exc_info) |
@@ -415,6 +415,7 b' class SubprocessIOChunker:' | |||||
415 | return_code = _p.poll() |
|
415 | return_code = _p.poll() | |
416 | ret_code_ok = return_code in [None, 0] |
|
416 | ret_code_ok = return_code in [None, 0] | |
417 | ret_code_fail = return_code is not None and return_code != 0 |
|
417 | ret_code_fail = return_code is not None and return_code != 0 | |
|
418 | ||||
418 | if ( |
|
419 | if ( | |
419 | (ret_code_fail and fail_on_return_code) or |
|
420 | (ret_code_fail and fail_on_return_code) or | |
420 | (ret_code_ok and fail_on_stderr and bg_err.length) |
|
421 | (ret_code_ok and fail_on_stderr and bg_err.length) |
General Comments 0
You need to be logged in to leave comments.
Login now