summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@gmail.com>2014-11-12 14:14:46 +0000
committerRichard Maw <richard.maw@gmail.com>2014-11-12 14:47:08 +0000
commit824b1600d41d8906e87fa98cc78d776e406c19e5 (patch)
treee74348a03644de6dd76c390093b35656cdd9906f
parente82909361a50f5046295a1453f48735752318696 (diff)
downloadmorph-824b1600d41d8906e87fa98cc78d776e406c19e5.tar.gz
Make invert_paths work more reliably for writable-all
-rw-r--r--morphlib/fsutils.py67
-rw-r--r--morphlib/fsutils_tests.py25
2 files changed, 51 insertions, 41 deletions
diff --git a/morphlib/fsutils.py b/morphlib/fsutils.py
index 6d651171..8a4128d9 100644
--- a/morphlib/fsutils.py
+++ b/morphlib/fsutils.py
@@ -97,48 +97,43 @@ def invert_paths(tree_walker, paths):
'''
- def is_subpath(prefix, path):
- prefix_components = prefix.split(os.sep)
- path_components = path.split(os.sep)
- return path_components[:len(prefix_components)] == prefix_components
+ def normpath(path):
+ if path == '.':
+ return path
+ path = os.path.normpath(path)
+ if not os.path.isabs(path):
+ path = os.path.join('.', path)
+ return path
+ def any_paths_are_subpath_of(prefix):
+ prefix = normpath(prefix)
+ norm_paths = (normpath(path) for path in paths)
+ return any(path[:len(prefix)] == prefix
+ for path in norm_paths)
+
+ def path_is_listed(path):
+ return any(normpath(path) == normpath(other)
+ for other in paths)
for dirpath, dirnames, filenames in tree_walker:
- if any(p == dirpath for p in paths): # pragma: no cover
- # Dir is an exact match for a path
- # don't recurse any further
- # Don't yield it, since we don't return listed paths
- continue
- dn_copy = list(dirnames)
- for subdir in dn_copy:
- subdirpath = os.path.join(dirpath, subdir)
-
- if any(p == subdirpath for p in paths):
- # Subdir is an exact match for a path
- # Don't recurse into it, so remove from list
- # Don't yield it, since we don't return listed paths
- dirnames.remove(subdir)
- elif any(is_subpath(subdirpath, p) for p in paths):
- # This directory is a parent directory of one
- # of our paths
- # Recurse into it, so don't remove it from the list
- # Don't yield it, since we don't return listed paths
- pass
- else:
- # This directory is neither one marked for writing,
- # nor a parent of a file marked for writing
- # Don't recurse, so remove it from the list
- # Yield it, since we return listed paths
- dirnames.remove(subdir)
- yield subdirpath
+ if path_is_listed(dirpath):
+ # No subpaths need to be considered
+ del dirnames[:]
+ del filenames[:]
+ elif any_paths_are_subpath_of(dirpath):
+ # Subpaths may be marked, or may not, need to leave this
+ # writable, so don't yield, but we don't cull.
+ pass
+ else:
+ # not listed as a parent or an exact match, needs to be
+ # yielded, but we don't need to consider subdirs, so can cull
+ yield dirpath
+ del dirnames[:]
+ del filenames[:]
for filename in filenames:
fullpath = os.path.join(dirpath, filename)
- if any(is_subpath(p, fullpath) for p in paths):
- # The file path is a child of one of the paths
- # or is equal.
- # Don't yield because either it is one of the specified
- # paths, or is a file in a directory specified by a path
+ if path_is_listed(fullpath):
pass
else:
yield fullpath
diff --git a/morphlib/fsutils_tests.py b/morphlib/fsutils_tests.py
index 7b159665..47a4488e 100644
--- a/morphlib/fsutils_tests.py
+++ b/morphlib/fsutils_tests.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2013 Codethink Limited
+# Copyright (C) 2013, 2014 Codethink Limited
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -51,11 +51,26 @@ class InvertPathsTests(unittest.TestCase):
},
}
- def test_flat_lists_single_files(self):
+ def test_flat_lists_top_dir(self):
walker = dummy_top_down_walker('.', self.flat_tree)
- self.assertEqual(sorted(["./foo", "./bar", "./baz"]),
+ self.assertEqual(["."],
sorted(morphlib.fsutils.invert_paths(walker, [])))
+ def test_flat_skips_all_with_root_pased(self):
+ walker = dummy_top_down_walker('.', self.flat_tree)
+ self.assertEqual([],
+ list(morphlib.fsutils.invert_paths(walker, ['.'])))
+
+ def test_flat_lists_top_dir(self):
+ walker = dummy_top_down_walker('.', self.nested_tree)
+ self.assertEqual(["."],
+ sorted(morphlib.fsutils.invert_paths(walker, [])))
+
+ def test_flat_skips_all_with_root_pased(self):
+ walker = dummy_top_down_walker('.', self.nested_tree)
+ self.assertEqual([],
+ list(morphlib.fsutils.invert_paths(walker, ['.'])))
+
def test_flat_excludes_listed_files(self):
walker = dummy_top_down_walker('.', self.flat_tree)
self.assertTrue(
@@ -95,5 +110,5 @@ class InvertPathsTests(unittest.TestCase):
"./tmp/morph/staging/inst",
"./tmp",
]))
- expected = ("./bin",)
- self.assertEqual(sorted(found), sorted(expected))
+ expected = ["./bin"]
+ self.assertEqual(sorted(found), expected)