Skip to content

Commit 37909f7

Browse files
authored
Reland "Create utils.delete_file and utils.delete_dir in place of tempfiles.try_delete. NFC (#17512)" (#17775)
1 parent 28184f3 commit 37909f7

18 files changed

+167
-162
lines changed

emcc.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
from tools import webassembly
5252
from tools import config
5353
from tools.settings import settings, MEM_SIZE_SETTINGS, COMPILE_TIME_SETTINGS
54-
from tools.utils import read_file, write_file, read_binary
54+
from tools.utils import read_file, write_file, read_binary, delete_file
5555

5656
logger = logging.getLogger('emcc')
5757

@@ -3070,7 +3070,7 @@ def phase_final_emitting(options, state, target, wasm_target, memfile):
30703070
generate_worker_js(target, js_target, target_basename)
30713071

30723072
if embed_memfile() and memfile:
3073-
shared.try_delete(memfile)
3073+
delete_file(memfile)
30743074

30753075
if settings.SPLIT_MODULE:
30763076
diagnostics.warning('experimental', 'The SPLIT_MODULE setting is experimental and subject to change')
@@ -3561,7 +3561,7 @@ def preprocess_wasm2js_script():
35613561
if settings.WASM != 2:
35623562
final_js = wasm2js
35633563
# if we only target JS, we don't need the wasm any more
3564-
shared.try_delete(wasm_target)
3564+
delete_file(wasm_target)
35653565

35663566
save_intermediate('wasm2js')
35673567

@@ -3599,7 +3599,7 @@ def preprocess_wasm2js_script():
35993599
js = do_replace(js, '<<< WASM_BINARY_DATA >>>', base64_encode(read_binary(wasm_target)))
36003600
else:
36013601
js = do_replace(js, '<<< WASM_BINARY_FILE >>>', get_subresource_location(wasm_target))
3602-
shared.try_delete(wasm_target)
3602+
delete_file(wasm_target)
36033603
write_file(final_js, js)
36043604

36053605

@@ -3797,7 +3797,7 @@ def generate_traditional_runtime_html(target, options, js_target, target_basenam
37973797
js_contents = script.inline or ''
37983798
if script.src:
37993799
js_contents += read_file(js_target)
3800-
shared.try_delete(js_target)
3800+
delete_file(js_target)
38013801
script.src = None
38023802
script.inline = js_contents
38033803

test/common.py

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@
3131
import jsrun
3232
from tools.shared import TEMP_DIR, EMCC, EMXX, DEBUG, EMCONFIGURE, EMCMAKE
3333
from tools.shared import EMSCRIPTEN_TEMP_DIR
34-
from tools.shared import get_canonical_temp_dir, try_delete, path_from_root
34+
from tools.shared import get_canonical_temp_dir, path_from_root
3535
from tools.utils import MACOS, WINDOWS, read_file, read_binary, write_file, write_binary, exit_with_error
36-
from tools import shared, line_endings, building, config
36+
from tools import shared, line_endings, building, config, utils
3737

3838
logger = logging.getLogger('common')
3939

@@ -84,13 +84,6 @@
8484
PYTHON = sys.executable
8585

8686

87-
def delete_contents(pathname):
88-
for entry in os.listdir(pathname):
89-
try_delete(os.path.join(pathname, entry))
90-
# TODO(sbc): Should we make try_delete have a stronger guarantee?
91-
assert not os.path.exists(os.path.join(pathname, entry))
92-
93-
9487
def test_file(*path_components):
9588
"""Construct a path relative to the emscripten "tests" directory."""
9689
return str(Path(TEST_ROOT, *path_components))
@@ -308,6 +301,44 @@ def make_executable(name):
308301
Path(name).chmod(stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
309302

310303

304+
def make_dir_writeable(dirname):
305+
# Ensure all files are readable and writable by the current user.
306+
permission_bits = stat.S_IWRITE | stat.S_IREAD
307+
308+
def is_writable(path):
309+
return (os.stat(path).st_mode & permission_bits) != permission_bits
310+
311+
def make_writable(path):
312+
new_mode = os.stat(path).st_mode | permission_bits
313+
os.chmod(path, new_mode)
314+
315+
# Some tests make files and subdirectories read-only, so rmtree/unlink will not delete
316+
# them. Force-make everything writable in the subdirectory to make it
317+
# removable and re-attempt.
318+
if not is_writable(dirname):
319+
make_writable(dirname)
320+
321+
for directory, subdirs, files in os.walk(dirname):
322+
for item in files + subdirs:
323+
i = os.path.join(directory, item)
324+
if not os.path.islink(i):
325+
make_writable(i)
326+
327+
328+
def force_delete_dir(dirname):
329+
make_dir_writeable(dirname)
330+
if WINDOWS:
331+
# We have seen issues where windows was unable to cleanup the test directory
332+
# See: https://github.com/emscripten-core/emscripten/pull/17512
333+
# TODO: Remove this try/catch.
334+
try:
335+
utils.delete_dir(dirname)
336+
except IOError as e:
337+
logger.warning(f'failed to remove directory: {dirname} ({e})')
338+
else:
339+
utils.delete_dir(dirname)
340+
341+
311342
def parameterized(parameters):
312343
"""
313344
Mark a test as parameterized.
@@ -505,7 +536,7 @@ def setUp(self):
505536
# expect this. --no-clean can be used to keep the old contents for the new test
506537
# run. This can be useful when iterating on a given test with extra files you want to keep
507538
# around in the output directory.
508-
delete_contents(self.working_dir)
539+
utils.delete_contents(self.working_dir)
509540
else:
510541
print('Creating new test output directory')
511542
ensure_dir(self.working_dir)
@@ -523,7 +554,7 @@ def tearDown(self):
523554
if not EMTEST_SAVE_DIR:
524555
# rmtree() fails on Windows if the current working directory is inside the tree.
525556
os.chdir(os.path.dirname(self.get_dir()))
526-
try_delete(self.get_dir())
557+
force_delete_dir(self.get_dir())
527558

528559
if EMTEST_DETECT_TEMPFILE_LEAKS and not DEBUG:
529560
temp_files_after_run = []
@@ -981,9 +1012,9 @@ def get_library(self, name, generated_libs, configure=['sh', './configure'], #
9811012
cache_name, env_init=env_init, native=native)
9821013

9831014
def clear(self):
984-
delete_contents(self.get_dir())
1015+
utils.delete_contents(self.get_dir())
9851016
if EMSCRIPTEN_TEMP_DIR:
986-
delete_contents(EMSCRIPTEN_TEMP_DIR)
1017+
utils.delete_contents(EMSCRIPTEN_TEMP_DIR)
9871018

9881019
def run_process(self, cmd, check=True, **args):
9891020
# Wrapper around shared.run_process. This is desirable so that the tests
@@ -1753,7 +1784,7 @@ def btest(self, filename, expected=None, reference=None,
17531784
outfile = 'test.html'
17541785
args += [filename, '-o', outfile]
17551786
# print('all args:', args)
1756-
try_delete(outfile)
1787+
utils.delete_file(outfile)
17571788
self.compile_btest(args, reporting=reporting)
17581789
self.assertExists(outfile)
17591790
if post_build:

test/parallel_testsuite.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
import time
1111
import queue
1212

13-
from tools.tempfiles import try_delete
13+
import common
14+
1415

1516
NUM_CORES = None
1617

@@ -95,7 +96,7 @@ def collect_results(self):
9596
else:
9697
self.clear_finished_processes()
9798
for temp_dir in self.dedicated_temp_dirs:
98-
try_delete(temp_dir)
99+
common.force_delete_dir(temp_dir)
99100
return buffered_results
100101

101102
def clear_finished_processes(self):

test/test_benchmark.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
import common
2222
from tools.shared import CLANG_CC, CLANG_CXX
2323
from common import TEST_ROOT, test_file, read_file, read_binary
24-
from tools.shared import run_process, PIPE, try_delete, EMCC, config
25-
from tools import building
24+
from tools.shared import run_process, PIPE, EMCC, config
25+
from tools import building, utils
2626

2727
# standard arguments for timing:
2828
# 0: no runtime, just startup
@@ -197,7 +197,7 @@ def build(self, parent, filename, args, shared_args, emcc_args, native_args, nat
197197
emcc_args += lib_builder('js_' + llvm_root, native=False, env_init=env_init)
198198
final = os.path.dirname(filename) + os.path.sep + self.name + ('_' if self.name else '') + os.path.basename(filename) + '.js'
199199
final = final.replace('.cpp', '')
200-
try_delete(final)
200+
utils.delete_file(final)
201201
cmd = [
202202
EMCC, filename,
203203
OPTIMIZATIONS,
@@ -317,7 +317,7 @@ def build(self, parent, filename, args, shared_args, emcc_args, native_args, nat
317317
cheerp_args += ['-cheerp-pretty-code'] # get function names, like emcc --profiling
318318
final = os.path.dirname(filename) + os.path.sep + self.name + ('_' if self.name else '') + os.path.basename(filename) + '.js'
319319
final = final.replace('.cpp', '')
320-
try_delete(final)
320+
utils.delete_file(final)
321321
dirs_to_delete = []
322322
cheerp_args += ['-cheerp-preexecute']
323323
try:
@@ -339,7 +339,7 @@ def build(self, parent, filename, args, shared_args, emcc_args, native_args, nat
339339
run_binaryen_opts(final.replace('.js', '.wasm'), self.binaryen_opts)
340340
finally:
341341
for dir_ in dirs_to_delete:
342-
try_delete(dir_)
342+
utils.delete_dir(dir_)
343343

344344
def run(self, args):
345345
return jsrun.run_js(self.filename, engine=self.engine, args=args, stderr=PIPE)

test/test_browser.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from tools import shared
2727
from tools import ports
2828
from tools.shared import EMCC, WINDOWS, FILE_PACKAGER, PIPE
29-
from tools.shared import try_delete
29+
from tools.utils import delete_file, delete_dir
3030

3131

3232
def test_chunked_synchronous_xhr_server(support_byte_ranges, chunkSize, data, checksum, port):
@@ -245,8 +245,8 @@ def test_zzz_html_source_map(self):
245245
''')
246246
# use relative paths when calling emcc, because file:// URIs can only load
247247
# sourceContent when the maps are relative paths
248-
try_delete(html_file)
249-
try_delete(html_file + '.map')
248+
delete_file(html_file)
249+
delete_file(html_file + '.map')
250250
self.compile_btest(['src.cpp', '-o', 'src.html', '-gsource-map'])
251251
self.assertExists(html_file)
252252
self.assertExists('src.wasm.map')
@@ -339,7 +339,7 @@ def make_main(path):
339339
self.btest_exit('main.cpp', args=['--preload-file', absolute_src_path])
340340

341341
# Test subdirectory handling with asset packaging.
342-
try_delete('assets')
342+
delete_dir('assets')
343343
ensure_dir('assets/sub/asset1/'.replace('\\', '/'))
344344
ensure_dir('assets/sub/asset1/.git'.replace('\\', '/')) # Test adding directory that shouldn't exist.
345345
ensure_dir('assets/sub/asset2/'.replace('\\', '/'))
@@ -2559,8 +2559,8 @@ def test_uuid(self):
25592559
print(out)
25602560

25612561
# Tidy up files that might have been created by this test.
2562-
try_delete(test_file('uuid/test.js'))
2563-
try_delete(test_file('uuid/test.js.map'))
2562+
delete_file(test_file('uuid/test.js'))
2563+
delete_file(test_file('uuid/test.js.map'))
25642564

25652565
# Now run test in browser
25662566
self.btest_exit(test_file('uuid/test.c'), args=['-luuid'])
@@ -4039,7 +4039,7 @@ def test_pthread_custom_pthread_main_url(self):
40394039
# Test that it is possible to define "Module.locateFile(foo)" function to locate where worker.js will be loaded from.
40404040
create_file('shell2.html', read_file(path_from_root('src/shell.html')).replace('var Module = {', 'var Module = { locateFile: function(filename) { if (filename == "test.worker.js") return "cdn/test.worker.js"; else return filename; }, '))
40414041
self.compile_btest(['main.cpp', '--shell-file', 'shell2.html', '-sWASM=0', '-sIN_TEST_HARNESS', '-sUSE_PTHREADS', '-sPTHREAD_POOL_SIZE', '-o', 'test2.html'], reporting=Reporting.JS_ONLY)
4042-
try_delete('test.worker.js')
4042+
delete_file('test.worker.js')
40434043
self.run_browser('test2.html', '/report_result?exit:0')
40444044

40454045
# Test that if the main thread is performing a futex wait while a pthread needs it to do a proxied operation (before that pthread would wake up the main thread), that it's not a deadlock.
@@ -5305,7 +5305,7 @@ def test_wasmfs_fetch_backend(self, args):
53055305
create_file('data.dat', 'hello, fetch')
53065306
create_file('small.dat', 'hello')
53075307
create_file('test.txt', 'fetch 2')
5308-
try_delete('subdir')
5308+
delete_dir('subdir')
53095309
ensure_dir('subdir')
53105310
create_file('subdir/backendfile', 'file 1')
53115311
create_file('subdir/backendfile2', 'file 2')

test/test_core.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
if __name__ == '__main__':
2020
raise Exception('do not run this file directly; do something like: test/runner')
2121

22-
from tools.shared import try_delete, PIPE
22+
from tools.shared import PIPE
2323
from tools.shared import EMCC, EMAR
24-
from tools.utils import WINDOWS, MACOS, write_file
24+
from tools.utils import WINDOWS, MACOS, write_file, delete_file
2525
from tools import shared, building, config, webassembly
2626
import common
2727
from common import RunnerCore, path_from_root, requires_native_clang, test_file, create_file
@@ -4061,7 +4061,7 @@ def dylink_testf(self, main, side=None, expected=None, force_c=False, main_emcc_
40614061

40624062
if isinstance(main, list):
40634063
# main is just a library
4064-
try_delete('main.js')
4064+
delete_file('main.js')
40654065
self.run_process([EMCC] + main + self.get_emcc_args() + ['-o', 'main.js'])
40664066
self.do_run('main.js', expected, no_build=True, **kwargs)
40674067
else:
@@ -6402,7 +6402,7 @@ def test_dlmalloc(self):
64026402
if self.emcc_args == []:
64036403
# emcc should build in dlmalloc automatically, and do all the sign correction etc. for it
64046404

6405-
try_delete('src.js')
6405+
delete_file('src.js')
64066406
self.run_process([EMCC, test_file('dlmalloc_test.c'), '-sINITIAL_MEMORY=128MB', '-o', 'src.js'], stdout=PIPE, stderr=self.stderr_redirect)
64076407

64086408
self.do_run(None, '*1,0*', ['200', '1'], no_build=True)

0 commit comments

Comments
 (0)