##// END OF EJS Templates
fix(hooks): improve the code that manages hooks dir and files to be more prone to permissions issues
super-admin -
r1179:4e9d64b6 default
parent child Browse files
Show More
@@ -1,202 +1,208 b''
1 1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 2 # Copyright (C) 2014-2023 RhodeCode GmbH
3 3 #
4 4 # This program is free software; you can redistribute it and/or modify
5 5 # it under the terms of the GNU General Public License as published by
6 6 # the Free Software Foundation; either version 3 of the License, or
7 7 # (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
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 17
18 18 import re
19 19 import os
20 20 import sys
21 21 import datetime
22 22 import logging
23 23 import pkg_resources
24 24
25 25 import vcsserver
26 26 from vcsserver.str_utils import safe_bytes
27 27
28 28 log = logging.getLogger(__name__)
29 29
30 30
31 31 def get_git_hooks_path(repo_path, bare):
32 32 hooks_path = os.path.join(repo_path, 'hooks')
33 33 if not bare:
34 34 hooks_path = os.path.join(repo_path, '.git', 'hooks')
35 35
36 36 return hooks_path
37 37
38 38
39 39 def install_git_hooks(repo_path, bare, executable=None, force_create=False):
40 40 """
41 41 Creates a RhodeCode hook inside a git repository
42 42
43 43 :param repo_path: path to repository
44 :param bare: defines if repository is considered a bare git repo
44 45 :param executable: binary executable to put in the hooks
45 :param force_create: Create even if same name hook exists
46 :param force_create: Creates even if the same name hook exists
46 47 """
47 48 executable = executable or sys.executable
48 49 hooks_path = get_git_hooks_path(repo_path, bare)
49 50
50 if not os.path.isdir(hooks_path):
51 # we always call it to ensure dir exists and it has a proper mode
52 if not os.path.exists(hooks_path):
53 # If it doesn't exist, create a new directory with the specified mode
51 54 os.makedirs(hooks_path, mode=0o777, exist_ok=True)
55 else:
56 # If it exists, change the directory's mode to the specified mode
57 os.chmod(hooks_path, mode=0o777)
52 58
53 59 tmpl_post = pkg_resources.resource_string(
54 60 'vcsserver', '/'.join(
55 61 ('hook_utils', 'hook_templates', 'git_post_receive.py.tmpl')))
56 62 tmpl_pre = pkg_resources.resource_string(
57 63 'vcsserver', '/'.join(
58 64 ('hook_utils', 'hook_templates', 'git_pre_receive.py.tmpl')))
59 65
60 66 path = '' # not used for now
61 67 timestamp = datetime.datetime.utcnow().isoformat()
62 68
63 69 for h_type, template in [('pre', tmpl_pre), ('post', tmpl_post)]:
64 70 log.debug('Installing git hook in repo %s', repo_path)
65 71 _hook_file = os.path.join(hooks_path, f'{h_type}-receive')
66 72 _rhodecode_hook = check_rhodecode_hook(_hook_file)
67 73
68 74 if _rhodecode_hook or force_create:
69 75 log.debug('writing git %s hook file at %s !', h_type, _hook_file)
70 76 try:
71 77 with open(_hook_file, 'wb') as f:
72 78 template = template.replace(b'_TMPL_', safe_bytes(vcsserver.__version__))
73 79 template = template.replace(b'_DATE_', safe_bytes(timestamp))
74 80 template = template.replace(b'_ENV_', safe_bytes(executable))
75 81 template = template.replace(b'_PATH_', safe_bytes(path))
76 82 f.write(template)
77 83 os.chmod(_hook_file, 0o755)
78 84 except OSError:
79 85 log.exception('error writing hook file %s', _hook_file)
80 86 else:
81 87 log.debug('skipping writing hook file')
82 88
83 89 return True
84 90
85 91
86 92 def get_svn_hooks_path(repo_path):
87 93 hooks_path = os.path.join(repo_path, 'hooks')
88 94
89 95 return hooks_path
90 96
91 97
92 98 def install_svn_hooks(repo_path, executable=None, force_create=False):
93 99 """
94 100 Creates RhodeCode hooks inside a svn repository
95 101
96 102 :param repo_path: path to repository
97 103 :param executable: binary executable to put in the hooks
98 104 :param force_create: Create even if same name hook exists
99 105 """
100 106 executable = executable or sys.executable
101 107 hooks_path = get_svn_hooks_path(repo_path)
102 108 if not os.path.isdir(hooks_path):
103 109 os.makedirs(hooks_path, mode=0o777, exist_ok=True)
104 110
105 111 tmpl_post = pkg_resources.resource_string(
106 112 'vcsserver', '/'.join(
107 113 ('hook_utils', 'hook_templates', 'svn_post_commit_hook.py.tmpl')))
108 114 tmpl_pre = pkg_resources.resource_string(
109 115 'vcsserver', '/'.join(
110 116 ('hook_utils', 'hook_templates', 'svn_pre_commit_hook.py.tmpl')))
111 117
112 118 path = '' # not used for now
113 119 timestamp = datetime.datetime.utcnow().isoformat()
114 120
115 121 for h_type, template in [('pre', tmpl_pre), ('post', tmpl_post)]:
116 122 log.debug('Installing svn hook in repo %s', repo_path)
117 123 _hook_file = os.path.join(hooks_path, f'{h_type}-commit')
118 124 _rhodecode_hook = check_rhodecode_hook(_hook_file)
119 125
120 126 if _rhodecode_hook or force_create:
121 127 log.debug('writing svn %s hook file at %s !', h_type, _hook_file)
122 128
123 129 try:
124 130 with open(_hook_file, 'wb') as f:
125 131 template = template.replace(b'_TMPL_', safe_bytes(vcsserver.__version__))
126 132 template = template.replace(b'_DATE_', safe_bytes(timestamp))
127 133 template = template.replace(b'_ENV_', safe_bytes(executable))
128 134 template = template.replace(b'_PATH_', safe_bytes(path))
129 135
130 136 f.write(template)
131 137 os.chmod(_hook_file, 0o755)
132 138 except OSError:
133 139 log.exception('error writing hook file %s', _hook_file)
134 140 else:
135 141 log.debug('skipping writing hook file')
136 142
137 143 return True
138 144
139 145
140 146 def get_version_from_hook(hook_path):
141 147 version = b''
142 148 hook_content = read_hook_content(hook_path)
143 149 matches = re.search(rb'RC_HOOK_VER\s*=\s*(.*)', hook_content)
144 150 if matches:
145 151 try:
146 152 version = matches.groups()[0]
147 153 log.debug('got version %s from hooks.', version)
148 154 except Exception:
149 155 log.exception("Exception while reading the hook version.")
150 156 return version.replace(b"'", b"")
151 157
152 158
153 159 def check_rhodecode_hook(hook_path):
154 160 """
155 161 Check if the hook was created by RhodeCode
156 162 """
157 163 if not os.path.exists(hook_path):
158 164 return True
159 165
160 166 log.debug('hook exists, checking if it is from RhodeCode')
161 167
162 168 version = get_version_from_hook(hook_path)
163 169 if version:
164 170 return True
165 171
166 172 return False
167 173
168 174
169 175 def read_hook_content(hook_path) -> bytes:
170 176 content = b''
171 177 if os.path.isfile(hook_path):
172 178 with open(hook_path, 'rb') as f:
173 179 content = f.read()
174 180 return content
175 181
176 182
177 183 def get_git_pre_hook_version(repo_path, bare):
178 184 hooks_path = get_git_hooks_path(repo_path, bare)
179 185 _hook_file = os.path.join(hooks_path, 'pre-receive')
180 186 version = get_version_from_hook(_hook_file)
181 187 return version
182 188
183 189
184 190 def get_git_post_hook_version(repo_path, bare):
185 191 hooks_path = get_git_hooks_path(repo_path, bare)
186 192 _hook_file = os.path.join(hooks_path, 'post-receive')
187 193 version = get_version_from_hook(_hook_file)
188 194 return version
189 195
190 196
191 197 def get_svn_pre_hook_version(repo_path):
192 198 hooks_path = get_svn_hooks_path(repo_path)
193 199 _hook_file = os.path.join(hooks_path, 'pre-commit')
194 200 version = get_version_from_hook(_hook_file)
195 201 return version
196 202
197 203
198 204 def get_svn_post_hook_version(repo_path):
199 205 hooks_path = get_svn_hooks_path(repo_path)
200 206 _hook_file = os.path.join(hooks_path, 'post-commit')
201 207 version = get_version_from_hook(_hook_file)
202 208 return version
General Comments 0
You need to be logged in to leave comments. Login now