Skip to content

Commit 03a1fb1

Browse files
committed
Create utils.delete_file and utils.delete_dir in place of tempfiles.try_delete. NFC
The code in `tempfiles.try_delete` went to great lengths to never fail and change the permission bits of the things it was trying to delete. However, in most cases is undesirable and overkill. We don't want to silently fail if the delete fails, and we don't want to delete read only files in most cases. The exception is the test suite were we do sometimes create read only and we want to be able to clean them up. So I created a test-only helper called `force_delete_dir`, but even then we don't want to silently fail so the try/catch was removed here.
1 parent 517cc86 commit 03a1fb1

18 files changed

+159
-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

@@ -3044,7 +3044,7 @@ def phase_final_emitting(options, state, target, wasm_target, memfile):
30443044
generate_worker_js(target, js_target, target_basename)
30453045

30463046
if embed_memfile() and memfile:
3047-
shared.try_delete(memfile)
3047+
delete_file(memfile)
30483048

30493049
if settings.SPLIT_MODULE:
30503050
diagnostics.warning('experimental', 'The SPLIT_MODULE setting is experimental and subject to change')
@@ -3532,7 +3532,7 @@ def preprocess_wasm2js_script():
35323532
if settings.WASM != 2:
35333533
final_js = wasm2js
35343534
# if we only target JS, we don't need the wasm any more
3535-
shared.try_delete(wasm_target)
3535+
delete_file(wasm_target)
35363536

35373537
save_intermediate('wasm2js')
35383538

@@ -3570,7 +3570,7 @@ def preprocess_wasm2js_script():
35703570
js = do_replace(js, '<<< WASM_BINARY_DATA >>>', base64_encode(read_binary(wasm_target)))
35713571
else:
35723572
js = do_replace(js, '<<< WASM_BINARY_FILE >>>', get_subresource_location(wasm_target))
3573-
shared.try_delete(wasm_target)
3573+
delete_file(wasm_target)
35743574
write_file(final_js, js)
35753575

35763576

@@ -3768,7 +3768,7 @@ def generate_traditional_runtime_html(target, options, js_target, target_basenam
37683768
js_contents = script.inline or ''
37693769
if script.src:
37703770
js_contents += read_file(js_target)
3771-
shared.try_delete(js_target)
3771+
delete_file(js_target)
37723772
script.src = None
37733773
script.inline = js_contents
37743774

test/common.py

Lines changed: 36 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,35 @@ 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+
utils.delete_dir(dirname)
331+
332+
311333
def parameterized(parameters):
312334
"""
313335
Mark a test as parameterized.
@@ -509,7 +531,7 @@ def setUp(self):
509531
# expect this. --no-clean can be used to keep the old contents for the new test
510532
# run. This can be useful when iterating on a given test with extra files you want to keep
511533
# around in the output directory.
512-
delete_contents(self.working_dir)
534+
utils.delete_contents(self.working_dir)
513535
else:
514536
print('Creating new test output directory')
515537
ensure_dir(self.working_dir)
@@ -527,7 +549,7 @@ def tearDown(self):
527549
if not EMTEST_SAVE_DIR:
528550
# rmtree() fails on Windows if the current working directory is inside the tree.
529551
os.chdir(os.path.dirname(self.get_dir()))
530-
try_delete(self.get_dir())
552+
force_delete_dir(self.get_dir())
531553

532554
if EMTEST_DETECT_TEMPFILE_LEAKS and not DEBUG:
533555
temp_files_after_run = []
@@ -949,9 +971,9 @@ def get_library(self, name, generated_libs, configure=['sh', './configure'], #
949971
cache_name, env_init=env_init, native=native)
950972

951973
def clear(self):
952-
delete_contents(self.get_dir())
974+
utils.delete_contents(self.get_dir())
953975
if EMSCRIPTEN_TEMP_DIR:
954-
delete_contents(EMSCRIPTEN_TEMP_DIR)
976+
utils.delete_contents(EMSCRIPTEN_TEMP_DIR)
955977

956978
def run_process(self, cmd, check=True, **args):
957979
# Wrapper around shared.run_process. This is desirable so that the tests
@@ -1717,7 +1739,7 @@ def btest(self, filename, expected=None, reference=None,
17171739
outfile = 'test.html'
17181740
args += [filename, '-o', outfile]
17191741
# print('all args:', args)
1720-
try_delete(outfile)
1742+
utils.delete_file(outfile)
17211743
self.compile_btest(args, reporting=reporting)
17221744
self.assertExists(outfile)
17231745
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('\\', '/'))
@@ -2560,8 +2560,8 @@ def test_uuid(self):
25602560
print(out)
25612561

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

25662566
# Now run test in browser
25672567
self.btest_exit(test_file('uuid/test.c'), args=['-luuid'])
@@ -4040,7 +4040,7 @@ def test_pthread_custom_pthread_main_url(self):
40404040
# Test that it is possible to define "Module.locateFile(foo)" function to locate where worker.js will be loaded from.
40414041
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; }, '))
40424042
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)
4043-
try_delete('test.worker.js')
4043+
delete_file('test.worker.js')
40444044
self.run_browser('test2.html', '/report_result?exit:0')
40454045

40464046
# 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.
@@ -5295,7 +5295,7 @@ def test_wasmfs_fetch_backend(self, args):
52955295
return self.skipTest('ff hangs on the main_thread version. browser bug?')
52965296
create_file('data.dat', 'hello, fetch')
52975297
create_file('test.txt', 'fetch 2')
5298-
try_delete('subdir')
5298+
delete_dir('subdir')
52995299
ensure_dir('subdir')
53005300
create_file('subdir/backendfile', 'file 1')
53015301
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
@@ -4064,7 +4064,7 @@ def dylink_testf(self, main, side=None, expected=None, force_c=False, main_emcc_
40644064

40654065
if isinstance(main, list):
40664066
# main is just a library
4067-
try_delete('main.js')
4067+
delete_file('main.js')
40684068
self.run_process([EMCC] + main + self.get_emcc_args() + ['-o', 'main.js'])
40694069
self.do_run('main.js', expected, no_build=True, **kwargs)
40704070
else:
@@ -6380,7 +6380,7 @@ def test_dlmalloc(self):
63806380
if self.emcc_args == []:
63816381
# emcc should build in dlmalloc automatically, and do all the sign correction etc. for it
63826382

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

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

0 commit comments

Comments
 (0)