5
5
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
6
6
from __future__ import print_function
7
7
8
+ import contextlib
8
9
from functools import wraps
9
10
import io
10
11
import logging
16
17
import unittest
17
18
18
19
from git .compat import string_types , is_win , PY3
19
- from git .util import rmtree
20
+ from git .util import rmtree , cwd
20
21
21
22
import os .path as osp
22
23
@@ -151,32 +152,67 @@ def repo_creator(self):
151
152
return argument_passer
152
153
153
154
154
- def launch_git_daemon (base_path , ip , port ):
155
- from git import Git
156
- if is_win :
157
- ## On MINGW-git, daemon exists in .\Git\mingw64\libexec\git-core\,
158
- # but if invoked as 'git daemon', it detaches from parent `git` cmd,
159
- # and then CANNOT DIE!
160
- # So, invoke it as a single command.
161
- ## Cygwin-git has no daemon. But it can use MINGW's.
162
- #
163
- daemon_cmd = ['git-daemon' ,
164
- '--enable=receive-pack' ,
165
- '--listen=%s' % ip ,
166
- '--port=%s' % port ,
167
- '--base-path=%s' % base_path ,
168
- base_path ]
169
- gd = Git ().execute (daemon_cmd , as_process = True )
170
- else :
171
- gd = Git ().daemon (base_path ,
172
- enable = 'receive-pack' ,
173
- listen = ip ,
174
- port = port ,
175
- base_path = base_path ,
176
- as_process = True )
177
- # yes, I know ... fortunately, this is always going to work if sleep time is just large enough
178
- time .sleep (0.5 )
179
- return gd
155
+ @contextlib .contextmanager
156
+ def git_daemon_launched (base_path , ip , port ):
157
+ from git import Git # Avoid circular deps.
158
+
159
+ gd = None
160
+ try :
161
+ if is_win :
162
+ ## On MINGW-git, daemon exists in .\Git\mingw64\libexec\git-core\,
163
+ # but if invoked as 'git daemon', it detaches from parent `git` cmd,
164
+ # and then CANNOT DIE!
165
+ # So, invoke it as a single command.
166
+ ## Cygwin-git has no daemon. But it can use MINGW's.
167
+ #
168
+ daemon_cmd = ['git-daemon' ,
169
+ '--enable=receive-pack' ,
170
+ '--listen=%s' % ip ,
171
+ '--port=%s' % port ,
172
+ '--base-path=%s' % base_path ,
173
+ base_path ]
174
+ gd = Git ().execute (daemon_cmd , as_process = True )
175
+ else :
176
+ gd = Git ().daemon (base_path ,
177
+ enable = 'receive-pack' ,
178
+ listen = ip ,
179
+ port = port ,
180
+ base_path = base_path ,
181
+ as_process = True )
182
+ # yes, I know ... fortunately, this is always going to work if sleep time is just large enough
183
+ time .sleep (0.5 * (1 + is_win ))
184
+
185
+ yield
186
+
187
+ except Exception as ex :
188
+ msg = textwrap .dedent ("""
189
+ Launching git-daemon failed due to: %s
190
+ Probably test will fail subsequently.
191
+
192
+ BUT you may start *git-daemon* manually with this command:"
193
+ git daemon --enable=receive-pack --listen=%s --port=%s --base-path=%s %s
194
+ You may also run the daemon on a different port by passing --port=<port>"
195
+ and setting the environment variable GIT_PYTHON_TEST_GIT_DAEMON_PORT to <port>
196
+ """ )
197
+ if is_win :
198
+ msg += textwrap .dedent ("""
199
+
200
+ On Windows,
201
+ the `git-daemon.exe` must be in PATH.
202
+ For MINGW, look into .\Git\mingw64\libexec\git-core\), but problems with paths might appear.
203
+ CYGWIN has no daemon, but if one exists, it gets along fine (but has also paths problems).""" )
204
+ log .warning (msg , ex , ip , port , base_path , base_path , exc_info = 1 )
205
+
206
+ yield
207
+
208
+ finally :
209
+ if gd :
210
+ try :
211
+ log .debug ("Killing git-daemon..." )
212
+ gd .proc .kill ()
213
+ except Exception as ex :
214
+ ## Either it has died (and we're here), or it won't die, again here...
215
+ log .debug ("Hidden error while Killing git-daemon: %s" , ex , exc_info = 1 )
180
216
181
217
182
218
def with_rw_and_rw_remote_repo (working_tree_ref ):
@@ -193,10 +229,10 @@ def with_rw_and_rw_remote_repo(working_tree_ref):
193
229
directories in it.
194
230
195
231
The following scetch demonstrates this::
196
- rorepo ---<bare clone>---> rw_remote_repo ---<clone>---> rw_repo
232
+ rorepo ---<bare clone>---> rw_daemon_repo ---<clone>---> rw_repo
197
233
198
234
The test case needs to support the following signature::
199
- def case(self, rw_repo, rw_remote_repo )
235
+ def case(self, rw_repo, rw_daemon_repo )
200
236
201
237
This setup allows you to test push and pull scenarios and hooks nicely.
202
238
@@ -211,94 +247,65 @@ def argument_passer(func):
211
247
212
248
@wraps (func )
213
249
def remote_repo_creator (self ):
214
- remote_repo_dir = tempfile .mktemp ("remote_repo_%s " % func .__name__ )
215
- repo_dir = tempfile .mktemp ("remote_clone_non_bare_repo" )
250
+ rw_daemon_repo_dir = tempfile .mktemp (prefix = "daemon_repo-%s- " % func .__name__ )
251
+ rw_repo_dir = tempfile .mktemp ("daemon_cloned_repo-%s-" % func . __name__ )
216
252
217
- rw_remote_repo = self .rorepo .clone (remote_repo_dir , shared = True , bare = True )
253
+ rw_daemon_repo = self .rorepo .clone (rw_daemon_repo_dir , shared = True , bare = True )
218
254
# recursive alternates info ?
219
- rw_repo = rw_remote_repo .clone (repo_dir , shared = True , bare = False , n = True )
220
- rw_repo .head .commit = working_tree_ref
221
- rw_repo .head .reference .checkout ()
222
-
223
- # prepare for git-daemon
224
- rw_remote_repo .daemon_export = True
225
-
226
- # this thing is just annoying !
227
- with rw_remote_repo .config_writer () as crw :
228
- section = "daemon"
229
- try :
230
- crw .add_section (section )
231
- except Exception :
232
- pass
233
- crw .set (section , "receivepack" , True )
234
-
235
- # Initialize the remote - first do it as local remote and pull, then
236
- # we change the url to point to the daemon.
237
- d_remote = Remote .create (rw_repo , "daemon_origin" , remote_repo_dir )
238
- d_remote .fetch ()
239
-
240
- base_path , rel_repo_dir = osp .split (remote_repo_dir )
241
-
242
- remote_repo_url = Git .polish_url ("git://localhost:%s/%s" % (GIT_DAEMON_PORT , rel_repo_dir ))
243
- with d_remote .config_writer as cw :
244
- cw .set ('url' , remote_repo_url )
245
-
255
+ rw_repo = rw_daemon_repo .clone (rw_repo_dir , shared = True , bare = False , n = True )
246
256
try :
247
- gd = launch_git_daemon (Git .polish_url (base_path ), '127.0.0.1' , GIT_DAEMON_PORT )
248
- except Exception as ex :
249
- if is_win :
250
- msg = textwrap .dedent ("""
251
- The `git-daemon.exe` must be in PATH.
252
- For MINGW, look into .\Git\mingw64\libexec\git-core\), but problems with paths might appear.
253
- CYGWIN has no daemon, but if one exists, it gets along fine (has also paths problems)
254
- Anyhow, alternatively try starting `git-daemon` manually:""" )
255
- else :
256
- msg = "Please try starting `git-daemon` manually:"
257
- msg += textwrap .dedent ("""
258
- git daemon --enable=receive-pack --base-path=%s %s
259
- You can also run the daemon on a different port by passing --port=<port>"
260
- and setting the environment variable GIT_PYTHON_TEST_GIT_DAEMON_PORT to <port>
261
- """ % (base_path , base_path ))
262
- raise AssertionError (ex , msg )
263
- # END make assertion
264
- else :
265
- # Try listing remotes, to diagnose whether the daemon is up.
266
- rw_repo .git .ls_remote (d_remote )
267
-
268
- # adjust working dir
269
- prev_cwd = os .getcwd ()
270
- os .chdir (rw_repo .working_dir )
257
+ rw_repo .head .commit = working_tree_ref
258
+ rw_repo .head .reference .checkout ()
271
259
272
- try :
273
- return func (self , rw_repo , rw_remote_repo )
274
- except :
275
- log .info ("Keeping repos after failure: repo_dir = %s, remote_repo_dir = %s" ,
276
- repo_dir , remote_repo_dir )
277
- repo_dir = remote_repo_dir = None
278
- raise
279
- finally :
280
- os .chdir (prev_cwd )
260
+ # prepare for git-daemon
261
+ rw_daemon_repo .daemon_export = True
262
+
263
+ # this thing is just annoying !
264
+ with rw_daemon_repo .config_writer () as crw :
265
+ section = "daemon"
266
+ try :
267
+ crw .add_section (section )
268
+ except Exception :
269
+ pass
270
+ crw .set (section , "receivepack" , True )
271
+
272
+ # Initialize the remote - first do it as local remote and pull, then
273
+ # we change the url to point to the daemon.
274
+ d_remote = Remote .create (rw_repo , "daemon_origin" , rw_daemon_repo_dir )
275
+ d_remote .fetch ()
276
+
277
+ base_daemon_path , rel_repo_dir = osp .split (rw_daemon_repo_dir )
278
+
279
+ remote_repo_url = Git .polish_url ("git://localhost:%s/%s" % (GIT_DAEMON_PORT , rel_repo_dir ))
280
+ with d_remote .config_writer as cw :
281
+ cw .set ('url' , remote_repo_url )
282
+
283
+ with git_daemon_launched (Git .polish_url (base_daemon_path , is_cygwin = False ), # No daemon in Cygwin.
284
+ '127.0.0.1' ,
285
+ GIT_DAEMON_PORT ):
286
+ # Try listing remotes, to diagnose whether the daemon is up.
287
+ rw_repo .git .ls_remote (d_remote )
288
+
289
+ with cwd (rw_repo .working_dir ):
290
+ try :
291
+ return func (self , rw_repo , rw_daemon_repo )
292
+ except :
293
+ log .info ("Keeping repos after failure: \n rw_repo_dir: %s \n rw_daemon_repo_dir: %s" ,
294
+ rw_repo_dir , rw_daemon_repo_dir )
295
+ rw_repo_dir = rw_daemon_repo_dir = None
296
+ raise
281
297
282
298
finally :
283
- try :
284
- log .debug ("Killing git-daemon..." )
285
- gd .proc .kill ()
286
- except :
287
- ## Either it has died (and we're here), or it won't die, again here...
288
- pass
289
-
290
299
rw_repo .git .clear_cache ()
291
- rw_remote_repo .git .clear_cache ()
292
- rw_repo = rw_remote_repo = None
300
+ rw_daemon_repo .git .clear_cache ()
301
+ del rw_repo
302
+ del rw_daemon_repo
293
303
import gc
294
304
gc .collect ()
295
- if repo_dir :
296
- rmtree (repo_dir )
297
- if remote_repo_dir :
298
- rmtree (remote_repo_dir )
299
-
300
- if gd is not None :
301
- gd .proc .wait ()
305
+ if rw_repo_dir :
306
+ rmtree (rw_repo_dir )
307
+ if rw_daemon_repo_dir :
308
+ rmtree (rw_daemon_repo_dir )
302
309
# END cleanup
303
310
# END bare repo creator
304
311
return remote_repo_creator
0 commit comments