Skip to content

Commit 47d67c8

Browse files
committed
[FIX] runbot: fix rmtree permission issues
When trying to garbaged collect diretories if a file or a directory that the runbot user process own is not writable for the owner, the garbage collecting fails. The worst case is when both a file and its parent directory are not writable by the user. In that case, even by changing the file permission, the runbot cannot remove the file because of the directory not being writable. With this commit, a new `rmforest` function is made that tries, in case of permission error, to change the owner permission of the file and its parent directory to being writable before retrying to unlink them.
1 parent a33728b commit 47d67c8

File tree

1 file changed

+26
-2
lines changed

1 file changed

+26
-2
lines changed

runbot/models/build.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,30 @@
4343
USERUID = os.getuid()
4444
USERNAME = getpass.getuser()
4545

46+
47+
def force_rmtree(top_dir):
48+
"""Rewrite of rmtree that tries to handle permission errors (e.g.: when a directory that the user own is u-w)
49+
:param top_dir: diretory to remove
50+
:type top_dir: str or Path
51+
"""
52+
top = Path(top_dir)
53+
for root, dirs, files in top.walk(top_down=False):
54+
for name in files:
55+
f = root / name
56+
try:
57+
f.unlink()
58+
except PermissionError:
59+
perm = f.stat().st_mode | 0o00600
60+
f.chmod(perm)
61+
pperm = f.parent.stat().st_mode | 0o00700
62+
f.parent.chmod(pperm)
63+
f.unlink()
64+
for name in dirs:
65+
d = root / name
66+
d.rmdir()
67+
top.rmdir()
68+
69+
4670
def make_selection(array):
4771
return [(elem, elem.replace('_', ' ').capitalize()) if isinstance(elem, str) else elem for elem in array]
4872

@@ -646,15 +670,15 @@ def filter_ids(dest_list, label):
646670
for bdir_file in build_dir.iterdir():
647671
if bdir_file.is_dir() and bdir_file.name not in ('logs', 'tests'):
648672
try:
649-
shutil.rmtree(bdir_file)
673+
force_rmtree(bdir_file)
650674
except Exception:
651675
_logger.exception('Failed to remove %s', bdir_file)
652676
elif bdir_file.name == 'logs':
653677
for log_file_path in bdir_file.iterdir():
654678
if log_file_path.is_dir():
655679

656680
try:
657-
shutil.rmtree(log_file_path)
681+
force_rmtree(log_file_path)
658682
except Exception:
659683
_logger.exception('Failed to remove %s', log_file_path)
660684
elif log_file_path.name in ('run.txt', 'wake_up.txt') or not log_file_path.name.endswith('.txt'):

0 commit comments

Comments
 (0)