diff --git a/py/path/common.py b/py/path/common.py index d8963f963..d138bc6aa 100644 --- a/py/path/common.py +++ b/py/path/common.py @@ -278,20 +278,20 @@ newline will be removed from the end of each line. """ if rec: if isinstance(rec, str): rec = fnmatch(fil) - elif not py.builtin.callable(rec): - rec = lambda x: True - reclist = [self] - while reclist: - current = reclist.pop(0) - try: - dirlist = current.listdir() - except ignore: - return - for p in dirlist: - if fil is None or fil(p): - yield p - if p.check(dir=1) and (rec is None or rec(p)): - reclist.append(p) + elif not hasattr(rec, '__call__'): + rec = None + try: + entries = self.listdir() + except ignore: + return + dirs = [p for p in entries + if p.check(dir=1) and (rec is None or rec(p))] + for subdir in dirs: + for p in subdir.visit(fil=fil, rec=rec, ignore=ignore): + yield p + for p in entries: + if fil is None or fil(p): + yield p def _sortlist(self, res, sort): if sort: diff --git a/py/path/local.py b/py/path/local.py index 5726a66ac..7adab5030 100644 --- a/py/path/local.py +++ b/py/path/local.py @@ -334,12 +334,12 @@ class LocalPath(FSBase): assert self!=target copychunked(self, target) else: - target.ensure(dir=1) def rec(p): return p.check(link=0) for x in self.visit(rec=rec): relpath = x.relto(self) newx = target.join(relpath) + newx.dirpath().ensure(dir=1) if x.check(link=1): newx.mksymlinkto(x.readlink()) elif x.check(file=1): diff --git a/testing/path/test_local.py b/testing/path/test_local.py index fd2bf7a8b..bb473cd41 100644 --- a/testing/path/test_local.py +++ b/testing/path/test_local.py @@ -198,6 +198,15 @@ class TestLocalPath(common.CommonFSTests): l2 = tmpdir.join(newfilename) assert l2.read() == 'foo' + def test_visit_depth_first(self, tmpdir): + p1 = tmpdir.ensure("a","1") + p2 = tmpdir.ensure("b","2") + p3 = tmpdir.ensure("breadth") + l = list(tmpdir.visit(lambda x: x.check(file=1))) + assert l[0] == p1 + assert l[1] == p2 + assert l[2] == p3 + class TestExecutionOnWindows: disabled = py.std.sys.platform != 'win32'