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

Commitadc35f2

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 parent6310480 commitadc35f2

File tree

9 files changed

+261
-235
lines changed

9 files changed

+261
-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: 143 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,39 @@
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+
importmock
29+
fromcontextlib2importExitStack# @UnusedImport
30+
frombackports.tempfileimportTemporaryDirectory# @UnusedImport
31+
32+
2333
ospd=osp.dirname
2434

2535
GIT_REPO=os.environ.get("GIT_PYTHON_TEST_GIT_REPO_BASE",ospd(ospd(ospd(ospd(__file__)))))
2636
GIT_DAEMON_PORT=os.environ.get("GIT_PYTHON_TEST_GIT_DAEMON_PORT","19418")
2737

2838
__all__= (
2939
'fixture_path','fixture','StringProcessAdapter',
30-
'with_rw_directory','with_rw_repo','with_rw_and_rw_remote_repo','TestBase','TestCase',
40+
'with_rw_directory','with_rw_repo','rw_and_rw_remote_repos','TestBase','TestCase',
3141
'GIT_REPO','GIT_DAEMON_PORT'
3242
)
3343

@@ -162,39 +172,91 @@ def repo_creator(self):
162172
returnargument_passer
163173

164174

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

219283
assertisinstance(working_tree_ref,string_types),"Decorator requires ref name for working tree checkout"
220284

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-
285+
withExitStack()asstack:
286+
rw_remote_repo=stack.enter_context(tmp_clone(repo,
287+
clone_prefix="remote_bare_repo_%s",
288+
shared=True,
289+
bare=True))
290+
rw_repo=stack.enter_context(tmp_clone(rw_remote_repo,
291+
clone_prefix="remote_clone_non_bare_repo_",
292+
shared=True,
293+
bare=False,
294+
n=True))
295+
remote_repo_dir=rw_remote_repo.working_dir
296+
297+
# recursive alternates info ?
298+
rw_repo.head.commit=working_tree_ref
299+
rw_repo.head.reference.checkout()
300+
301+
# Allow git-daemon in bare-repo (https://git-scm.com/book/en/v2/Git-on-the-Server-Git-Daemon).
302+
rw_remote_repo.daemon_export=True
303+
304+
section="daemon"
305+
withrw_remote_repo.config_writer()ascrw:
257306
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)
307+
crw.add_section(section)# TODO: Add section if not exists.
308+
exceptException:
309+
pass
310+
crw.set(section,"receivepack",True)
292311

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
312+
# Initialize the non-bare repo - first do it as local remote and pull, then
313+
# we change the URL to point to the "relative" against "daemon's `--base-path`.
314+
#
315+
d_remote=Remote.create(rw_repo,"daemon_origin",remote_repo_dir)
316+
d_remote.fetch()
317+
base_path,rel_repo_dir=osp.split(remote_repo_dir)
318+
remote_repo_url=Git.polish_url("git://localhost:%s/%s"% (GIT_DAEMON_PORT,rel_repo_dir))
319+
withd_remote.config_writerascw:
320+
cw.set('url',remote_repo_url)
300321

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)
322+
stack.enter_context(launch_git_daemon(Git.polish_url(base_path),'127.0.0.1',GIT_DAEMON_PORT))
310323

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
324+
# Try listing remotes, to diagnose whether the daemon is up.
325+
rw_repo.git.ls_remote(d_remote)
318326

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

321331
#} END decorators
322332

‎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