Skip to content

Commit fabcdfb

Browse files
ahornbymeta-codesync[bot]
authored andcommitted
fix --free-up-disk action on windows
Summary: X-link: facebook/watchman#1314 on windows git checkout sets some files in readonly mode, which can block the free up disk action. Add a variant of rmtree that checks for this and clears the readonly flag e.g. failure in https://github.com/facebook/watchman/actions/runs/19267503560/job/55086850056 ``` File "C:\hostedtoolcache\windows\Python\3.9.13\x64\lib\shutil.py", line 629, in _rmtree_unsafe onerror(os.unlink, fullname, sys.exc_info()) File "C:\hostedtoolcache\windows\Python\3.9.13\x64\lib\shutil.py", line 627, in _rmtree_unsafe os.unlink(fullname) PermissionError: [WinError 5] Access is denied: 'Z:\build\fbthrift\source\.git\objects\pack\pack-1e9bd81db474c833f5ee1eec341f0ae8f4c05a51.idx' ``` Reviewed By: bigfootjon Differential Revision: D86773115 fbshipit-source-id: f665d43fb70dfe6ee1a8dc596f8cd09ac8a5bf7f
1 parent 0ac32d0 commit fabcdfb

2 files changed

Lines changed: 31 additions & 2 deletions

File tree

build/fbcode_builder/getdeps/builder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from shlex import quote as shellquote
1919
from typing import Optional
2020

21-
from .copytree import simple_copytree
21+
from .copytree import rmtree_more, simple_copytree
2222
from .dyndeps import create_dyn_dep_munger
2323
from .envfuncs import add_path_entry, Env, path_search
2424
from .fetcher import copy_if_different, is_public_commit
@@ -203,7 +203,7 @@ def build(self, reconfigure: bool) -> None:
203203
if os.path.islink(self.build_dir):
204204
os.remove(self.build_dir)
205205
else:
206-
shutil.rmtree(self.build_dir)
206+
rmtree_more(self.build_dir)
207207
elif self.build_opts.is_windows():
208208
# On Windows, emit a wrapper script that can be used to run build artifacts
209209
# directly from the build directory, without installing them. On Windows $PATH

build/fbcode_builder/getdeps/copytree.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import os
99
import shutil
10+
import stat
1011
import subprocess
1112

1213
from .platform import is_windows
@@ -97,3 +98,31 @@ def simple_copytree(src_dir, dest_dir, symlinks=False):
9798
return dest_dir
9899
else:
99100
return shutil.copytree(src_dir, dest_dir, symlinks=symlinks)
101+
102+
103+
def _remove_readonly_and_try_again(func, path, exc_info):
104+
"""
105+
Error handler for shutil.rmtree.
106+
If the error is due to an access error (read only file)
107+
it attempts to add write permission and then retries the operation.
108+
Any other failure propagates.
109+
"""
110+
# exc_info is a tuple (exc_type, exc_value, traceback)
111+
exc_type = exc_info[0]
112+
if exc_type is PermissionError:
113+
os.chmod(path, stat.S_IWRITE)
114+
# Retry the original function (os.remove or os.rmdir)
115+
try:
116+
func(path)
117+
except Exception:
118+
# If it still fails, the original exception from func() will propagate
119+
raise
120+
else:
121+
# If the error is not a PermissionError, re-raise the original exception
122+
raise exc_info[1]
123+
124+
125+
def rmtree_more(path):
126+
"""Wrapper around shutil.rmtree() that makes it remove readonly files as well.
127+
Useful when git on windows decides to make some files readonly on checkout"""
128+
shutil.rmtree(path, onerror=_remove_readonly_and_try_again)

0 commit comments

Comments
 (0)