Skip to content

Commit f3e9bec

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 504a02a commit f3e9bec

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 rmforest(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

@@ -645,15 +669,15 @@ def filter_ids(dest_list, label):
645669
for bdir_file in build_dir.iterdir():
646670
if bdir_file.is_dir() and bdir_file.name not in ('logs', 'tests'):
647671
try:
648-
shutil.rmtree(bdir_file)
672+
rmforest(bdir_file)
649673
except Exception:
650674
_logger.exception('Failed to remove %s', bdir_file)
651675
elif bdir_file.name == 'logs':
652676
for log_file_path in bdir_file.iterdir():
653677
if log_file_path.is_dir():
654678

655679
try:
656-
shutil.rmtree(log_file_path)
680+
rmforest(log_file_path)
657681
except Exception:
658682
_logger.exception('Failed to remove %s', log_file_path)
659683
elif log_file_path.name in ('run.txt', 'wake_up.txt') or not log_file_path.name.endswith('.txt'):

0 commit comments

Comments
 (0)