summaryrefslogtreecommitdiff
path: root/src/buildstream/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/buildstream/utils.py')
-rw-r--r--src/buildstream/utils.py38
1 files changed, 38 insertions, 0 deletions
diff --git a/src/buildstream/utils.py b/src/buildstream/utils.py
index 0307b8470..5009be338 100644
--- a/src/buildstream/utils.py
+++ b/src/buildstream/utils.py
@@ -779,6 +779,44 @@ def _is_main_process():
return os.getpid() == _MAIN_PID
+# Remove a path and any empty directories leading up to it.
+#
+# Args:
+# basedir - The basedir at which to stop pruning even if
+# it is empty.
+# path - A path relative to basedir that should be pruned.
+#
+# Raises:
+# FileNotFoundError - if the path itself doesn't exist.
+# OSError - if something else goes wrong
+#
+def _remove_path_with_parents(basedir: Union[Path, str], path: Union[Path, str]):
+ assert not os.path.isabs(path), "The path ({}) should be relative to basedir ({})".format(path, basedir)
+ path = os.path.join(basedir, path)
+
+ # Start by removing the path itself
+ os.unlink(path)
+
+ # Now walk up the directory tree and delete any empty directories
+ path = os.path.dirname(path)
+ while path != basedir:
+ try:
+ os.rmdir(path)
+ except FileNotFoundError:
+ # The parent directory did not exist (race conditions can
+ # cause this), but it's parent directory might still be
+ # ready to prune
+ pass
+ except OSError as e:
+ if e.errno == errno.ENOTEMPTY:
+ # The parent directory was not empty, so we
+ # cannot prune directories beyond this point
+ break
+ raise
+
+ path = os.path.dirname(path)
+
+
# Recursively remove directories, ignoring file permissions as much as
# possible.
def _force_rmtree(rootpath, **kwargs):