Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit47efb41

Browse files
committed
test: rework git-daemon helper wrapper
+ Extensive use of contextlib `ExitStack`.- DO NOT LEAVE DIRS ON DISK on failures (impossible now that usingtempfile standard files).+ cmd: Use subprocess.DEVNULL instead of opening file.+ PY2: Add `contextlib2` and `backports.tempfile` deps.
1 parent49a8cdd commit47efb41

9 files changed

+260
-235
lines changed

‎.appveyor.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ install:
5252
conda info -a &
5353
conda install --yes --quiet pip
5454
)
55-
-pip install nose ddt wheel codecov
55+
-pip installnose ddt wheel codecov
5656
-IF "%PYTHON_VERSION%"=="2.7" (
57-
pip install mock
57+
pip install mock contextlib2 backports.tempfile
5858
)
5959

6060
## Copied from `init-tests-after-clone.sh`.

‎.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ install:
1818
-git submodule update --init --recursive
1919
-git fetch --tags
2020
-pip install codecov flake8 ddt sphinx
21+
-if [ "$TRAVIS_PYTHON_VERSION" == '2.7' ]; then pip install mock contextlib2 backports.tempfile; fi
2122

2223
# generate some reflog as git-python tests need it (in master)
2324
-./init-tests-after-clone.sh

‎git/test/lib/helper.py

Lines changed: 142 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,38 @@
55
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
66
from __future__importprint_function
77

8+
importcontextlib
89
fromfunctoolsimportwraps
910
importio
1011
importlogging
1112
importos
12-
importtempfile
13+
importtempfile# @UnusedImport
1314
importtextwrap
1415
importtime
1516
fromunittestimportTestCase
1617

1718
fromgit.compatimportstring_types,is_win
18-
fromgit.utilimportrmtree
19-
19+
fromgit.utilimportrmtree,cwd
2020
importos.pathasosp
2121

2222

23+
try:
24+
fromunittestimportmock
25+
fromcontextlibimportExitStack
26+
fromtempfileimportTemporaryDirectory
27+
exceptImportError:# PY2
28+
fromcontextlib2importExitStack# @UnusedImport
29+
frombackports.tempfileimportTemporaryDirectory# @UnusedImport
30+
31+
2332
ospd=osp.dirname
2433

2534
GIT_REPO=os.environ.get("GIT_PYTHON_TEST_GIT_REPO_BASE",ospd(ospd(ospd(ospd(__file__)))))
2635
GIT_DAEMON_PORT=os.environ.get("GIT_PYTHON_TEST_GIT_DAEMON_PORT","19418")
2736

2837
__all__= (
2938
'fixture_path','fixture','StringProcessAdapter',
30-
'with_rw_directory','with_rw_repo','with_rw_and_rw_remote_repo','TestBase','TestCase',
39+
'with_rw_directory','with_rw_repo','rw_and_rw_remote_repos','TestBase','TestCase',
3140
'GIT_REPO','GIT_DAEMON_PORT'
3241
)
3342

@@ -162,39 +171,91 @@ def repo_creator(self):
162171
returnargument_passer
163172

164173

174+
@contextlib.contextmanager
165175
deflaunch_git_daemon(base_path,ip,port):
166-
fromgitimportGit
167-
ifis_win:
168-
## On MINGW-git, daemon exists in .\Git\mingw64\libexec\git-core\,
169-
# but if invoked as 'git daemon', it detaches from parent `git` cmd,
170-
# and then CANNOT DIE!
171-
# So, invoke it as a single command.
172-
## Cygwin-git has no daemon. But it can use MINGW's.
173-
#
174-
daemon_cmd= ['git-daemon',
175-
'--enable=receive-pack',
176-
'--listen=%s'%ip,
177-
'--port=%s'%port,
178-
'--base-path=%s'%base_path,
179-
base_path]
180-
gd=Git().execute(daemon_cmd,as_process=True)
181-
else:
182-
gd=Git().daemon(base_path,
183-
enable='receive-pack',
184-
listen=ip,
185-
port=port,
186-
base_path=base_path,
187-
as_process=True)
188-
# yes, I know ... fortunately, this is always going to work if sleep time is just large enough
189-
time.sleep(0.5)
190-
returngd
191-
192-
193-
defwith_rw_and_rw_remote_repo(working_tree_ref):
176+
fromgitimportGit# Avoid circular deps.
177+
178+
gd_launched=False
179+
try:
180+
ifis_win:
181+
## On MINGW-git, daemon exists in .\Git\mingw64\libexec\git-core\,
182+
# but if invoked as 'git daemon', it detaches from parent `git` cmd,
183+
# and then CANNOT DIE!
184+
# So, invoke it as a single command.
185+
## Cygwin-git has no daemon. But it can use MINGW's.
186+
#
187+
daemon_cmd= ['git-daemon',
188+
'--enable=receive-pack',
189+
'--listen=%s'%ip,
190+
'--port=%s'%port,
191+
'--base-path=%s'%base_path,
192+
base_path]
193+
gd=Git().execute(daemon_cmd,as_process=True)
194+
else:
195+
gd=Git().daemon(base_path,
196+
enable='receive-pack',
197+
listen=ip,
198+
port=port,
199+
base_path=base_path,
200+
as_process=True)
201+
gd_launched=True
202+
# yes, I know ... fortunately, this is always going to work if sleep time is just large enough
203+
time.sleep(0.5* (1+is_win))
204+
205+
yieldgd
206+
207+
exceptExceptionasex:
208+
msg=textwrap.dedent("""
209+
Launching git-daemon failed due to: %s
210+
Probably test will fail subsequently.
211+
212+
BUT you may start *git-daemon* manually with this command:"
213+
git daemon --enable=receive-pack --listen=%s --port=%s --base-path=%s %s
214+
You may also run the daemon on a different port by passing --port=<port>"
215+
and setting the environment variable GIT_PYTHON_TEST_GIT_DAEMON_PORT to <port>
216+
""")
217+
ifis_win:
218+
msg+=textwrap.dedent("""
219+
220+
On Windows,
221+
the `git-daemon.exe` must be in PATH.
222+
For MINGW, look into .\Git\mingw64\libexec\git-core\), but problems with paths might appear.
223+
CYGWIN has no daemon, but if one exists, it gets along fine (but has also paths problems).""")
224+
log.warning(msg,ex,ip,port,base_path,base_path,exc_info=1)
225+
226+
yieldmock.MagicMock()# @UndefinedVariable
227+
228+
finally:
229+
ifgd_launched:
230+
try:
231+
log.debug("Killing git-daemon...")
232+
gd.proc.kill()
233+
exceptExceptionasex:
234+
## Either it has died (and we're here), or it won't die, again here...
235+
log.debug("Hidden error while Killing git-daemon: %s",ex,exc_info=1)
236+
237+
238+
@contextlib.contextmanager
239+
deftmp_clone(repo,clone_prefix,**clone_kwargs):
240+
defcleanup_clone(repo):
241+
repo.git.clear_cache()
242+
importgc
243+
gc.collect()
244+
245+
withExitStack()asstack:
246+
clone_dir=stack.enter_context(TemporaryDirectory(prefix=clone_prefix))
247+
clone=repo.clone(clone_dir,**clone_kwargs)
248+
stack.callback(cleanup_clone,clone)
249+
250+
yieldclone
251+
252+
253+
@contextlib.contextmanager
254+
defrw_and_rw_remote_repos(repo,working_tree_ref):
194255
"""
195-
Same as with_rw_repo, but also provides a writable remote repository from which the
196-
rw_repo has been forked as well as a handle for a git-daemon that may be started to
197-
run the remote_repo.
256+
A context-manager creating the same temporary-repo as `with_rw_repo` and in addition
257+
a writable remote non-bare repository from which therw_repo has been forked as well as a handle
258+
for a git-daemon that may be started torun the remote_repo.
198259
The remote repository was cloned as bare repository from the rorepo, wheras
199260
the rw repo has a working tree and was cloned from the remote repository.
200261
@@ -203,11 +264,13 @@ def with_rw_and_rw_remote_repo(working_tree_ref):
203264
and should be an inetd service that serves tempdir.gettempdir() and all
204265
directories in it.
205266
206-
The following scetch demonstrates this::
207-
rorepo ---<bare clone>---> rw_remote_repo ---<clone>---> rw_repo
267+
The following sketch demonstrates this::
268+
rorepo ---<bare clone>---> remote_repo ---<clone>---> rw_repo
269+
270+
It is used like that::
208271
209-
The test case needs to support the following signature::
210-
def case(self, rw_repo, rw_remote_repo)
272+
with rw_and_rw_remote_repos(origin_repo) as (rw_repo, remote_repo):
273+
...
211274
212275
This setup allows you to test push and pull scenarios and hooks nicely.
213276
@@ -218,105 +281,51 @@ def case(self, rw_repo, rw_remote_repo)
218281

219282
assertisinstance(working_tree_ref,string_types),"Decorator requires ref name for working tree checkout"
220283

221-
defargument_passer(func):
222-
223-
@wraps(func)
224-
defremote_repo_creator(self):
225-
remote_repo_dir=_mktemp("remote_repo_%s"%func.__name__)
226-
repo_dir=_mktemp("remote_clone_non_bare_repo")
227-
228-
rw_remote_repo=self.rorepo.clone(remote_repo_dir,shared=True,bare=True)
229-
# recursive alternates info ?
230-
rw_repo=rw_remote_repo.clone(repo_dir,shared=True,bare=False,n=True)
231-
rw_repo.head.commit=working_tree_ref
232-
rw_repo.head.reference.checkout()
233-
234-
# prepare for git-daemon
235-
rw_remote_repo.daemon_export=True
236-
237-
# this thing is just annoying !
238-
withrw_remote_repo.config_writer()ascrw:
239-
section="daemon"
240-
try:
241-
crw.add_section(section)
242-
exceptException:
243-
pass
244-
crw.set(section,"receivepack",True)
245-
246-
# Initialize the remote - first do it as local remote and pull, then
247-
# we change the url to point to the daemon.
248-
d_remote=Remote.create(rw_repo,"daemon_origin",remote_repo_dir)
249-
d_remote.fetch()
250-
251-
base_path,rel_repo_dir=osp.split(remote_repo_dir)
252-
253-
remote_repo_url=Git.polish_url("git://localhost:%s/%s"% (GIT_DAEMON_PORT,rel_repo_dir))
254-
withd_remote.config_writerascw:
255-
cw.set('url',remote_repo_url)
256-
284+
withExitStack()asstack:
285+
rw_remote_repo=stack.enter_context(tmp_clone(repo,
286+
clone_prefix="remote_bare_repo_%s",
287+
shared=True,
288+
bare=True))
289+
rw_repo=stack.enter_context(tmp_clone(rw_remote_repo,
290+
clone_prefix="remote_clone_non_bare_repo_",
291+
shared=True,
292+
bare=False,
293+
n=True))
294+
remote_repo_dir=rw_remote_repo.working_dir
295+
296+
# recursive alternates info ?
297+
rw_repo.head.commit=working_tree_ref
298+
rw_repo.head.reference.checkout()
299+
300+
# Allow git-daemon in bare-repo (https://git-scm.com/book/en/v2/Git-on-the-Server-Git-Daemon).
301+
rw_remote_repo.daemon_export=True
302+
303+
section="daemon"
304+
withrw_remote_repo.config_writer()ascrw:
257305
try:
258-
gd=launch_git_daemon(Git.polish_url(base_path),'127.0.0.1',GIT_DAEMON_PORT)
259-
exceptExceptionasex:
260-
ifis_win:
261-
msg=textwrap.dedent("""
262-
The `git-daemon.exe` must be in PATH.
263-
For MINGW, look into .\Git\mingw64\libexec\git-core\), but problems with paths might appear.
264-
CYGWIN has no daemon, but if one exists, it gets along fine (has also paths problems)
265-
Anyhow, alternatively try starting `git-daemon` manually:""")
266-
else:
267-
msg="Please try starting `git-daemon` manually:"
268-
msg+=textwrap.dedent("""
269-
git daemon --enable=receive-pack --base-path=%s %s
270-
You can also run the daemon on a different port by passing --port=<port>"
271-
and setting the environment variable GIT_PYTHON_TEST_GIT_DAEMON_PORT to <port>
272-
"""% (base_path,base_path))
273-
raiseAssertionError(ex,msg)
274-
# END make assertion
275-
else:
276-
# Try listing remotes, to diagnose whether the daemon is up.
277-
rw_repo.git.ls_remote(d_remote)
278-
279-
# adjust working dir
280-
prev_cwd=os.getcwd()
281-
os.chdir(rw_repo.working_dir)
282-
283-
try:
284-
returnfunc(self,rw_repo,rw_remote_repo)
285-
except:
286-
log.info("Keeping repos after failure: repo_dir = %s, remote_repo_dir = %s",
287-
repo_dir,remote_repo_dir)
288-
repo_dir=remote_repo_dir=None
289-
raise
290-
finally:
291-
os.chdir(prev_cwd)
306+
crw.add_section(section)# TODO: Add section if not exists.
307+
exceptException:
308+
pass
309+
crw.set(section,"receivepack",True)
292310

293-
finally:
294-
try:
295-
log.debug("Killing git-daemon...")
296-
gd.proc.kill()
297-
except:
298-
## Either it has died (and we're here), or it won't die, again here...
299-
pass
311+
# Initialize the non-bare repo - first do it as local remote and pull, then
312+
# we change the URL to point to the "relative" against "daemon's `--base-path`.
313+
#
314+
d_remote=Remote.create(rw_repo,"daemon_origin",remote_repo_dir)
315+
d_remote.fetch()
316+
base_path,rel_repo_dir=osp.split(remote_repo_dir)
317+
remote_repo_url=Git.polish_url("git://localhost:%s/%s"% (GIT_DAEMON_PORT,rel_repo_dir))
318+
withd_remote.config_writerascw:
319+
cw.set('url',remote_repo_url)
300320

301-
rw_repo.git.clear_cache()
302-
rw_remote_repo.git.clear_cache()
303-
rw_repo=rw_remote_repo=None
304-
importgc
305-
gc.collect()
306-
ifrepo_dir:
307-
rmtree(repo_dir)
308-
ifremote_repo_dir:
309-
rmtree(remote_repo_dir)
321+
stack.enter_context(launch_git_daemon(Git.polish_url(base_path),'127.0.0.1',GIT_DAEMON_PORT))
310322

311-
ifgdisnotNone:
312-
gd.proc.wait()
313-
# END cleanup
314-
# END bare repo creator
315-
returnremote_repo_creator
316-
# END remote repo creator
317-
# END argument parser
323+
# Try listing remotes, to diagnose whether the daemon is up.
324+
rw_repo.git.ls_remote(d_remote)
318325

319-
returnargument_passer
326+
# adjust working dir
327+
stack.enter_context(cwd(rw_repo.working_dir))
328+
yieldrw_repo,rw_remote_repo
320329

321330
#} END decorators
322331

‎git/test/test_base.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
TestBase,
1515
assert_raises,
1616
with_rw_repo,
17-
with_rw_and_rw_remote_repo
17+
rw_and_rw_remote_repos
1818
)
1919
fromgitimport (
2020
Blob,
@@ -25,6 +25,7 @@
2525
fromgit.objects.utilimportget_object_type_by_name
2626
fromgitdb.utilimporthex_to_bin
2727
fromgit.compatimportis_win
28+
fromgit.utilimportHIDE_WINDOWS_KNOWN_ERRORS
2829

2930

3031
classTestBase(TestBase):
@@ -110,11 +111,12 @@ def test_with_rw_repo(self, rw_repo):
110111
assertnotrw_repo.config_reader("repository").getboolean("core","bare")
111112
assertos.path.isdir(os.path.join(rw_repo.working_tree_dir,'lib'))
112113

113-
@with_rw_and_rw_remote_repo('0.1.6')
114-
deftest_with_rw_remote_and_rw_repo(self,rw_repo,rw_remote_repo):
115-
assertnotrw_repo.config_reader("repository").getboolean("core","bare")
116-
assertrw_remote_repo.config_reader("repository").getboolean("core","bare")
117-
assertos.path.isdir(os.path.join(rw_repo.working_tree_dir,'lib'))
114+
@skipIf(HIDE_WINDOWS_KNOWN_ERRORS,"FIXME: Freezes!")
115+
deftest_with_rw_remote_and_rw_repo(self):
116+
withrw_and_rw_remote_repos(self.rorepo,'0.1.6')as (rw_repo,rw_remote_repo):
117+
assertnotrw_repo.config_reader("repository").getboolean("core","bare")
118+
assertrw_remote_repo.config_reader("repository").getboolean("core","bare")
119+
assertos.path.isdir(os.path.join(rw_repo.working_tree_dir,'lib'))
118120

119121
@skipIf(sys.version_info< (3,)andis_win,
120122
"Unicode woes, see https://github.com/gitpython-developers/GitPython/pull/519")

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp