objectstore: extract remove_tree()

Move remove_tree() into its own module in `osbuild.util.rmrf`. This way
we can use it in other modules as well, without cross-referencing
internal helpers.
This commit is contained in:
David Rheinsberg 2020-04-20 12:15:21 +02:00 committed by Tom Gundersen
parent 4ad4da4658
commit 2cc9160099
4 changed files with 152 additions and 77 deletions

View file

@ -1,14 +1,13 @@
import array
import contextlib
import errno
import fcntl
import hashlib
import os
import shutil
import subprocess
import tempfile
import weakref
from typing import Optional
import osbuild.util.rmrf as rmrf
from . import treesum
@ -54,53 +53,6 @@ def umount(target, lazy=True):
subprocess.run(["umount"] + args + [target], check=True)
def clear_mutable_flag(path):
FS_IOC_GETFLAGS = 0x80086601
FS_IOC_SETFLAGS = 0x40086602
FS_IMMUTABLE_FL = 0x010
fd = -1
try:
fd = os.open(path, os.O_RDONLY)
flags = array.array('L', [0])
fcntl.ioctl(fd, FS_IOC_GETFLAGS, flags, True)
flags[0] &= ~FS_IMMUTABLE_FL
fcntl.ioctl(fd, FS_IOC_SETFLAGS, flags, False)
except OSError:
pass # clearing flags is best effort
finally:
if fd > -1:
os.close(fd)
def remove_tree(path):
def fixperms(p):
clear_mutable_flag(p)
os.chmod(p, 0o777)
def unlink(p):
try:
os.unlink(p)
except IsADirectoryError:
remove_tree(p)
except FileNotFoundError:
pass
def on_error(_fn, p, exc_info):
e = exc_info[0]
if issubclass(e, FileNotFoundError):
pass
elif issubclass(e, PermissionError):
if p != path:
fixperms(os.path.dirname(p))
fixperms(p)
unlink(p)
else:
raise e
shutil.rmtree(path, onerror=on_error)
# pylint: disable=too-many-instance-attributes
class Object:
def __init__(self, store: "ObjectStore"):
@ -211,7 +163,7 @@ class Object:
# manually remove the tree, it might contain
# files with immutable flag set, which will
# throw off standard Python 3 tempdir cleanup
remove_tree(self._tree)
rmrf.rmtree(self._tree)
self._tree = None
if self._workdir:
self._workdir.cleanup()