Merged in paylogic/pytest-xdist/rsyncignore-option (pull request #5)

add glob support for rsyncignore. add command line option for rsyncignore
This commit is contained in:
holger krekel
2013-12-06 13:25:19 +01:00
7 changed files with 65 additions and 31 deletions

View File

@@ -14,8 +14,14 @@ syntax:glob
*.class *.class
*.orig *.orig
*.sublime-*
.Python
build/ build/
dist/ dist/
include/
lib/
bin/
pytest_xdist.egg-info pytest_xdist.egg-info
issue/ issue/
3rdparty/ 3rdparty/

View File

@@ -1,9 +1,7 @@
1.10 unreleased 1.10 unreleased
------------------------- -------------------------
- ignore pyc files, dot files and directories for changes (editors write tmp/swap - add glob support for rsyncignores, add command line option to pass additional rsyncignores
files etc., which also affects mtime of directory)
- fix pytest issue382 - produce "pytest_runtest_logstart" event again - fix pytest issue382 - produce "pytest_runtest_logstart" event again
in master. Thanks Aron Curzon. in master. Thanks Aron Curzon.

View File

@@ -122,6 +122,13 @@ py.test references tests as a fully qualified python
module path. **You will otherwise get strange errors** module path. **You will otherwise get strange errors**
during setup of the remote side. during setup of the remote side.
You can specify multiple ``--rsyncignore`` glob-patterns
to be ignored when file are sent to the remote side.
There are also internal ignores: .*, *.pyc, *.pyo, *~
Those you cannot override using rsyncignore command-line or
ini-file option(s).
Sending tests to remote Socket Servers Sending tests to remote Socket Servers
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

View File

@@ -46,6 +46,11 @@ class TestDistOptions:
assert nm.roots assert nm.roots
assert testdir.tmpdir in nm.roots assert testdir.tmpdir in nm.roots
def test_getrsyncignore(self, testdir):
config = testdir.parseconfigure('--rsyncignore=fo*')
nm = NodeManager(config, specs=[execnet.XSpec("popen//chdir=qwe")])
assert 'fo*' in nm.rsyncoptions['ignores']
def test_getrsyncdirs_with_conftest(self, testdir): def test_getrsyncdirs_with_conftest(self, testdir):
p = py.path.local() p = py.path.local()
for bn in 'x y z'.split(): for bn in 'x y z'.split():

View File

@@ -113,7 +113,7 @@ class TestHRSync:
source.ensure(".svn", "entries") source.ensure(".svn", "entries")
source.ensure(".somedotfile", "moreentries") source.ensure(".somedotfile", "moreentries")
source.ensure("somedir", "editfile~") source.ensure("somedir", "editfile~")
syncer = HostRSync(source) syncer = HostRSync(source, ignores=NodeManager.DEFAULT_IGNORES)
l = list(source.visit(rec=syncer.filter, l = list(source.visit(rec=syncer.filter,
fil=syncer.filter)) fil=syncer.filter))
assert len(l) == 3 assert len(l) == 3
@@ -197,12 +197,15 @@ class TestNodeManager:
dir5 = source.ensure("dir5", "dir6", "bogus") dir5 = source.ensure("dir5", "dir6", "bogus")
dirf = source.ensure("dir5", "file") dirf = source.ensure("dir5", "file")
dir2.ensure("hello") dir2.ensure("hello")
dirfoo = source.ensure("foo", "bar")
dirbar = source.ensure("bar", "foo")
source.join("tox.ini").write(py.std.textwrap.dedent(""" source.join("tox.ini").write(py.std.textwrap.dedent("""
[pytest] [pytest]
rsyncdirs = dir1 dir5 rsyncdirs = dir1 dir5
rsyncignore = dir1/dir2 dir5/dir6 rsyncignore = dir1/dir2 dir5/dir6 foo*
""")) """))
config = testdir.parseconfig(source) config = testdir.parseconfig(source)
config.option.rsyncignore = ['bar']
nodemanager = NodeManager(config, ["popen//chdir=%s" % dest]) nodemanager = NodeManager(config, ["popen//chdir=%s" % dest])
nodemanager.makegateways() nodemanager.makegateways()
nodemanager.rsync_roots() nodemanager.rsync_roots()
@@ -210,6 +213,8 @@ class TestNodeManager:
assert not dest.join("dir1", "dir2").check() assert not dest.join("dir1", "dir2").check()
assert dest.join("dir5","file").check() assert dest.join("dir5","file").check()
assert not dest.join("dir6").check() assert not dest.join("dir6").check()
assert not dest.join('foo').check()
assert not dest.join('bar').check()
def test_optimise_popen(self, testdir, mysetup): def test_optimise_popen(self, testdir, mysetup):
source, dest = mysetup.source, mysetup.dest source, dest = mysetup.source, mysetup.dest

View File

@@ -1,5 +1,5 @@
import sys import py
import py, pytest import pytest
def pytest_addoption(parser): def pytest_addoption(parser):
group = parser.getgroup("xdist", "distributed and subprocess testing") group = parser.getgroup("xdist", "distributed and subprocess testing")
@@ -28,12 +28,14 @@ def pytest_addoption(parser):
group._addoption('-d', group._addoption('-d',
action="store_true", dest="distload", default=False, action="store_true", dest="distload", default=False,
help="load-balance tests. shortcut for '--dist=load'") help="load-balance tests. shortcut for '--dist=load'")
group.addoption('--rsyncdir', action="append", default=[], metavar="dir1", group.addoption('--rsyncdir', action="append", default=[], metavar="DIR",
help="add directory for rsyncing to remote tx nodes.") help="add directory for rsyncing to remote tx nodes.")
group.addoption('--rsyncignore', action="append", default=[], metavar="GLOB",
help="add expression for ignores when rsyncing to remote tx nodes.")
parser.addini('rsyncdirs', 'list of (relative) paths to be rsynced for' parser.addini('rsyncdirs', 'list of (relative) paths to be rsynced for'
' remote distributed testing.', type="pathlist") ' remote distributed testing.', type="pathlist")
parser.addini('rsyncignore', 'list of (relative) paths to be ignored ' parser.addini('rsyncignore', 'list of (relative) glob-style paths to be ignored '
'for rsyncing.', type="pathlist") 'for rsyncing.', type="pathlist")
parser.addini("looponfailroots", type="pathlist", parser.addini("looponfailroots", type="pathlist",
help="directories to check for changes", default=[py.path.local()]) help="directories to check for changes", default=[py.path.local()])

View File

@@ -1,5 +1,8 @@
import py, pytest import fnmatch
import sys, os import os
import py
import pytest
import execnet import execnet
import xdist.remote import xdist.remote
@@ -7,6 +10,7 @@ from _pytest import runner # XXX load dynamically
class NodeManager(object): class NodeManager(object):
EXIT_TIMEOUT = 10 EXIT_TIMEOUT = 10
DEFAULT_IGNORES = ['.*', '*.pyc', '*.pyo', '*~']
def __init__(self, config, specs=None, defaultchdir="pyexecnetcache"): def __init__(self, config, specs=None, defaultchdir="pyexecnetcache"):
self.config = config self.config = config
self._nodesready = py.std.threading.Event() self._nodesready = py.std.threading.Event()
@@ -23,20 +27,17 @@ class NodeManager(object):
self.group.allocate_id(spec) self.group.allocate_id(spec)
self.specs.append(spec) self.specs.append(spec)
self.roots = self._getrsyncdirs() self.roots = self._getrsyncdirs()
self.rsyncoptions = self._getrsyncoptions()
def rsync_roots(self): def rsync_roots(self):
""" make sure that all remote gateways """ make sure that all remote gateways
have the same set of roots in their have the same set of roots in their
current directory. current directory.
""" """
options = {
'ignores': self.config.getini("rsyncignore"),
'verbose': self.config.option.verbose,
}
if self.roots: if self.roots:
# send each rsync root # send each rsync root
for root in self.roots: for root in self.roots:
self.rsync(root, **options) self.rsync(root, **self.rsyncoptions)
def makegateways(self): def makegateways(self):
assert not list(self.group) assert not list(self.group)
@@ -98,6 +99,18 @@ class NodeManager(object):
roots.append(root) roots.append(root)
return roots return roots
def _getrsyncoptions(self):
"""Get options to be passed for rsync."""
ignores = list(self.DEFAULT_IGNORES)
ignores += self.config.option.rsyncignore
ignores += self.config.getini("rsyncignore")
return {
'ignores': ignores,
'verbose': self.config.option.verbose,
}
def rsync(self, source, notify=None, verbose=False, ignores=None): def rsync(self, source, notify=None, verbose=False, ignores=None):
""" perform rsync to all remote hosts. """ perform rsync to all remote hosts.
""" """
@@ -144,14 +157,12 @@ class HostRSync(execnet.RSync):
def filter(self, path): def filter(self, path):
path = py.path.local(path) path = py.path.local(path)
if not path.ext in ('.pyc', '.pyo'): for x in self._ignores:
if not path.basename.endswith('~'): x = getattr(x, 'strpath', x)
if path.check(dotfile=0): if fnmatch.fnmatch(path.basename, x) or fnmatch.fnmatch(path.strpath, x):
for x in self._ignores: return False
if path == x: else:
break return True
else:
return True
def add_target_host(self, gateway, finished=None): def add_target_host(self, gateway, finished=None):
remotepath = os.path.basename(self._sourcedir) remotepath = os.path.basename(self._sourcedir)