##// END OF EJS Templates
release: Release 5.2.0
release: Release 5.2.0

File last commit:

r1261:0f8db01d default
r1292:50174967 merge v5.2.0 stable
Show More
__init__.py
238 lines | 8.7 KiB | text/x-python | PythonLexer
svn: added support for hooks management of git and subversion....
r407 # RhodeCode VCSServer provides access to different vcs backends via network.
source-code: updated copyrights to 2023
r1126 # Copyright (C) 2014-2023 RhodeCode GmbH
svn: added support for hooks management of git and subversion....
r407 #
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
fix(svn-hooks): fixed problem with svn subprocess execution fixes RCCE-62
r1214
svn: added support for hooks management of git and subversion....
r407 import re
import os
import sys
import datetime
import logging
import pkg_resources
import vcsserver
fix(svn-hooks): fixed problem with svn subprocess execution fixes RCCE-62
r1214 import vcsserver.settings
core: moved str_utils and type_utils to lib so it's consistent with ce, and easier to sync up codebases
r1249 from vcsserver.lib.str_utils import safe_bytes
svn: added support for hooks management of git and subversion....
r407
log = logging.getLogger(__name__)
fix(hooks): make compat for WSL filesystem better by explicity only changing permissions if they are lower at creation time.
r1186 HOOKS_DIR_MODE = 0o755
HOOKS_FILE_MODE = 0o755
def set_permissions_if_needed(path_to_check, perms: oct):
# Get current permissions
current_permissions = os.stat(path_to_check).st_mode & 0o777 # Extract permission bits
# Check if current permissions are lower than required
if current_permissions < int(perms):
# Change the permissions if they are lower than required
os.chmod(path_to_check, perms)
svn: added support for hooks management of git and subversion....
r407
hooks: expose logic to fetch hook file information.
r623 def get_git_hooks_path(repo_path, bare):
hooks_path = os.path.join(repo_path, 'hooks')
if not bare:
hooks_path = os.path.join(repo_path, '.git', 'hooks')
return hooks_path
svn: added support for hooks management of git and subversion....
r407 def install_git_hooks(repo_path, bare, executable=None, force_create=False):
"""
Creates a RhodeCode hook inside a git repository
:param repo_path: path to repository
fix(hooks): improve the code that manages hooks dir and files to be more prone to permissions issues
r1179 :param bare: defines if repository is considered a bare git repo
svn: added support for hooks management of git and subversion....
r407 :param executable: binary executable to put in the hooks
fix(hooks): improve the code that manages hooks dir and files to be more prone to permissions issues
r1179 :param force_create: Creates even if the same name hook exists
svn: added support for hooks management of git and subversion....
r407 """
executable = executable or sys.executable
hooks: expose logic to fetch hook file information.
r623 hooks_path = get_git_hooks_path(repo_path, bare)
fix(hooks): improve the code that manages hooks dir and files to be more prone to permissions issues
r1179 # we always call it to ensure dir exists and it has a proper mode
if not os.path.exists(hooks_path):
# If it doesn't exist, create a new directory with the specified mode
fix(hooks): make compat for WSL filesystem better by explicity only changing permissions if they are lower at creation time.
r1186 os.makedirs(hooks_path, mode=HOOKS_DIR_MODE, exist_ok=True)
# If it exists, change the directory's mode to the specified mode
set_permissions_if_needed(hooks_path, perms=HOOKS_DIR_MODE)
svn: added support for hooks management of git and subversion....
r407
tmpl_post = pkg_resources.resource_string(
'vcsserver', '/'.join(
('hook_utils', 'hook_templates', 'git_post_receive.py.tmpl')))
tmpl_pre = pkg_resources.resource_string(
'vcsserver', '/'.join(
('hook_utils', 'hook_templates', 'git_pre_receive.py.tmpl')))
path = '' # not used for now
timestamp = datetime.datetime.utcnow().isoformat()
for h_type, template in [('pre', tmpl_pre), ('post', tmpl_post)]:
log.debug('Installing git hook in repo %s', repo_path)
lint: auto-fixes
r1152 _hook_file = os.path.join(hooks_path, f'{h_type}-receive')
svn: added support for hooks management of git and subversion....
r407 _rhodecode_hook = check_rhodecode_hook(_hook_file)
if _rhodecode_hook or force_create:
log.debug('writing git %s hook file at %s !', h_type, _hook_file)
fix(svn): svn events fixes
r1261 env_expand = str([
('RC_INI_FILE', vcsserver.CONFIG['__file__']),
('RC_CORE_BINARY_DIR', vcsserver.settings.BINARY_DIR),
('RC_GIT_EXECUTABLE', vcsserver.settings.GIT_EXECUTABLE()),
('RC_SVN_EXECUTABLE', vcsserver.settings.SVN_EXECUTABLE()),
('RC_SVNLOOK_EXECUTABLE', vcsserver.settings.SVNLOOK_EXECUTABLE()),
])
svn: added support for hooks management of git and subversion....
r407 try:
with open(_hook_file, 'wb') as f:
fix(svn): svn events fixes
r1261 template = template.replace(b'_OS_EXPAND_', safe_bytes(env_expand))
fix(core): don't rely on pkgutil to extract the version info of project
r1188 template = template.replace(b'_TMPL_', safe_bytes(vcsserver.get_version()))
python3: code change for py3 support...
r1048 template = template.replace(b'_DATE_', safe_bytes(timestamp))
template = template.replace(b'_ENV_', safe_bytes(executable))
template = template.replace(b'_PATH_', safe_bytes(path))
svn: added support for hooks management of git and subversion....
r407 f.write(template)
fix(hooks): make compat for WSL filesystem better by explicity only changing permissions if they are lower at creation time.
r1186 set_permissions_if_needed(_hook_file, perms=HOOKS_FILE_MODE)
vcsserver: modernize code for python3
r1130 except OSError:
svn: added support for hooks management of git and subversion....
r407 log.exception('error writing hook file %s', _hook_file)
else:
log.debug('skipping writing hook file')
return True
hooks: expose logic to fetch hook file information.
r623 def get_svn_hooks_path(repo_path):
hooks_path = os.path.join(repo_path, 'hooks')
return hooks_path
svn: added support for hooks management of git and subversion....
r407 def install_svn_hooks(repo_path, executable=None, force_create=False):
"""
Creates RhodeCode hooks inside a svn repository
:param repo_path: path to repository
:param executable: binary executable to put in the hooks
:param force_create: Create even if same name hook exists
"""
executable = executable or sys.executable
hooks: expose logic to fetch hook file information.
r623 hooks_path = get_svn_hooks_path(repo_path)
svn: added support for hooks management of git and subversion....
r407 if not os.path.isdir(hooks_path):
hooks: make sure exist_ok is used for multiprocess errors
r1120 os.makedirs(hooks_path, mode=0o777, exist_ok=True)
svn: added support for hooks management of git and subversion....
r407
tmpl_post = pkg_resources.resource_string(
'vcsserver', '/'.join(
('hook_utils', 'hook_templates', 'svn_post_commit_hook.py.tmpl')))
tmpl_pre = pkg_resources.resource_string(
'vcsserver', '/'.join(
('hook_utils', 'hook_templates', 'svn_pre_commit_hook.py.tmpl')))
path = '' # not used for now
timestamp = datetime.datetime.utcnow().isoformat()
for h_type, template in [('pre', tmpl_pre), ('post', tmpl_post)]:
log.debug('Installing svn hook in repo %s', repo_path)
lint: auto-fixes
r1152 _hook_file = os.path.join(hooks_path, f'{h_type}-commit')
svn: added support for hooks management of git and subversion....
r407 _rhodecode_hook = check_rhodecode_hook(_hook_file)
if _rhodecode_hook or force_create:
log.debug('writing svn %s hook file at %s !', h_type, _hook_file)
fix(svn-hooks): fixed problem with svn subprocess execution fixes RCCE-62
r1214 env_expand = str([
fix(svn): svn events fixes
r1261 ('RC_INI_FILE', vcsserver.CONFIG['__file__']),
fix(svn-hooks): fixed problem with svn subprocess execution fixes RCCE-62
r1214 ('RC_CORE_BINARY_DIR', vcsserver.settings.BINARY_DIR),
fix(svn): fixed problems with svn hooks binary dir not beeing propagates in mod_dav_svn
r1230 ('RC_GIT_EXECUTABLE', vcsserver.settings.GIT_EXECUTABLE()),
('RC_SVN_EXECUTABLE', vcsserver.settings.SVN_EXECUTABLE()),
('RC_SVNLOOK_EXECUTABLE', vcsserver.settings.SVNLOOK_EXECUTABLE()),
fix(svn-hooks): fixed problem with svn subprocess execution fixes RCCE-62
r1214 ])
svn: added support for hooks management of git and subversion....
r407 try:
with open(_hook_file, 'wb') as f:
fix(svn): svn events fixes
r1261 template = template.replace(b'_OS_EXPAND_', safe_bytes(env_expand))
fix(core): don't rely on pkgutil to extract the version info of project
r1188 template = template.replace(b'_TMPL_', safe_bytes(vcsserver.get_version()))
python3: code change for py3 support...
r1048 template = template.replace(b'_DATE_', safe_bytes(timestamp))
template = template.replace(b'_ENV_', safe_bytes(executable))
template = template.replace(b'_PATH_', safe_bytes(path))
svn: added support for hooks management of git and subversion....
r407
f.write(template)
code: fix deprecated octal usage for py3 compatability.
r590 os.chmod(_hook_file, 0o755)
vcsserver: modernize code for python3
r1130 except OSError:
svn: added support for hooks management of git and subversion....
r407 log.exception('error writing hook file %s', _hook_file)
else:
log.debug('skipping writing hook file')
return True
hooks: expose logic to fetch hook file information.
r623 def get_version_from_hook(hook_path):
python3: code change for py3 support...
r1048 version = b''
hooks: expose logic to fetch hook file information.
r623 hook_content = read_hook_content(hook_path)
hooks: make sure exist_ok is used for multiprocess errors
r1120 matches = re.search(rb'RC_HOOK_VER\s*=\s*(.*)', hook_content)
hooks: expose logic to fetch hook file information.
r623 if matches:
try:
version = matches.groups()[0]
log.debug('got version %s from hooks.', version)
except Exception:
log.exception("Exception while reading the hook version.")
python3: code change for py3 support...
r1048 return version.replace(b"'", b"")
hooks: expose logic to fetch hook file information.
r623
svn: added support for hooks management of git and subversion....
r407 def check_rhodecode_hook(hook_path):
"""
Check if the hook was created by RhodeCode
"""
if not os.path.exists(hook_path):
return True
hooks: expose logic to fetch hook file information.
r623 log.debug('hook exists, checking if it is from RhodeCode')
version = get_version_from_hook(hook_path)
if version:
return True
svn: added support for hooks management of git and subversion....
r407
return False
vcsserver: fixed some bytes issues with status command/read hooks info endpoint
r1066 def read_hook_content(hook_path) -> bytes:
content = b''
hooks: do not crash when hook files are empty
r691 if os.path.isfile(hook_path):
with open(hook_path, 'rb') as f:
content = f.read()
svn: added support for hooks management of git and subversion....
r407 return content
hooks: expose logic to fetch hook file information.
r623
def get_git_pre_hook_version(repo_path, bare):
hooks_path = get_git_hooks_path(repo_path, bare)
_hook_file = os.path.join(hooks_path, 'pre-receive')
version = get_version_from_hook(_hook_file)
return version
def get_git_post_hook_version(repo_path, bare):
hooks_path = get_git_hooks_path(repo_path, bare)
_hook_file = os.path.join(hooks_path, 'post-receive')
version = get_version_from_hook(_hook_file)
return version
def get_svn_pre_hook_version(repo_path):
hooks_path = get_svn_hooks_path(repo_path)
_hook_file = os.path.join(hooks_path, 'pre-commit')
version = get_version_from_hook(_hook_file)
return version
def get_svn_post_hook_version(repo_path):
hooks_path = get_svn_hooks_path(repo_path)
_hook_file = os.path.join(hooks_path, 'post-commit')
version = get_version_from_hook(_hook_file)
return version