diff --git a/tools/fs/files.ts b/tools/fs/files.ts index 24d57da570..5df5b6eb16 100644 --- a/tools/fs/files.ts +++ b/tools/fs/files.ts @@ -1694,29 +1694,40 @@ const wrappedRename = wrapDestructiveFsFunc("rename", fs.renameSync, [0, 1]); export const rename = isWindowsLikeFilesystem() ? function (from: string, to: string) { // Retries are necessary only on Windows, because the rename call can // fail with EBUSY, which means the file is in use. - let maxTries = 10; - let success = false; const osTo = convertToOSPath(to); + const startTimeMs = Date.now(); + const intervalMs = 50; + const timeLimitMs = 1000; - while (! success && maxTries-- > 0) { - try { - // Despite previous failures, the top-level destination directory - // may have been successfully created, so we must remove it to - // avoid moving the source file *into* the destination directory. - rimraf.sync(osTo); - wrappedRename(from, to); - success = true; - } catch (err) { - if (err.code !== 'EPERM' && err.code !== 'EACCES') { - throw err; + return new Promise((resolve, reject) => { + function attempt() { + try { + // Despite previous failures, the top-level destination directory + // may have been successfully created, so we must remove it to + // avoid moving the source file *into* the destination directory. + rimraf.sync(osTo); + wrappedRename(from, to); + resolve(); + } catch (err) { + if (err.code !== 'EPERM' && err.code !== 'EACCES') { + reject(err); + } else if (Date.now() - startTimeMs < timeLimitMs) { + setTimeout(attempt, intervalMs); + } else { + reject(err); + } } } - } - - if (! success) { - cp_r(from, to, { preserveSymlinks: true }); - rm_recursive(from); - } + attempt(); + }).catch(error => { + if (error.code === 'EPERM' || + error.code === 'EACCESS') { + cp_r(from, to, { preserveSymlinks: true }); + rm_recursive(from); + } else { + throw error; + } + }).await(); } : wrappedRename; // Warning: doesn't convert slashes in the second 'cache' arg diff --git a/tools/isobuild/import-scanner.ts b/tools/isobuild/import-scanner.ts index 5fc67fd472..b4377f95dc 100644 --- a/tools/isobuild/import-scanner.ts +++ b/tools/isobuild/import-scanner.ts @@ -142,7 +142,9 @@ class DefaultHandlers { file.hash, this.bundleArch, ); - process.nextTick(writeFileAtomically, cacheFileName, code); + Promise.resolve().then( + () => writeFileAtomically(cacheFileName, code), + ); return code; } } else { diff --git a/tools/tool-testing/run.js b/tools/tool-testing/run.js index d457ffbd03..0f45f73cea 100644 --- a/tools/tool-testing/run.js +++ b/tools/tool-testing/run.js @@ -461,10 +461,37 @@ export default class Run { if (failure instanceof TestFailure) { const frames = parseStackParse(failure).outsideFiber; - const relpath = files.pathRelative(files.getCurrentToolsDir(), - frames[0].file); + const toolsDir = files.getCurrentToolsDir(); + let pathWithLineNumber; + frames.some(frame => { + // The parsed stack trace will typically include frame.file + // strings of the form "/tools/tests/whatever.js", which can be + // made absolute by joining them with toolsDir. If the resulting + // absPath exists, then we know we interpreted the frame.file + // correctly, and we can normalize away the leading '/' + // character to get a safe relative path. + const absPath = files.pathJoin(toolsDir, frame.file); + if (files.exists(absPath)) { + const relPath = files.pathRelative(toolsDir, absPath); + const parts = relPath.split("/"); + if (parts[0] === "tools" && + parts[1] === "tool-testing") { + // Ignore frames inside the /tools/tool-testing directory, + // like run.js and selftest.js. + return false; + } + pathWithLineNumber = `${relPath}:${frame.line}`; + return true; + } + // If frame.file was not joinable with toolsDir to obtain an + // absolute path that exists, show it to the user without trying + // to interpret what it means. + pathWithLineNumber = `${frame.file}:${frame.line}`; + return true; + }); + Console.rawError( - ` => ${failure.reason} at ${relpath}:${frames[0].line}\n`); + ` => ${failure.reason} at ${pathWithLineNumber}\n`); if (failure.reason === 'no-match' || failure.reason === 'junk-before' || failure.reason === 'match-timeout') { Console.arrowError(`Pattern: ${failure.details.pattern}`, 2); diff --git a/tools/tool-testing/sandbox.js b/tools/tool-testing/sandbox.js index d7b34ad820..88e753f84a 100644 --- a/tools/tool-testing/sandbox.js +++ b/tools/tool-testing/sandbox.js @@ -368,7 +368,7 @@ export default class Sandbox { // Allow user to set TOOL_NODE_FLAGS for self-test app. if (process.env.TOOL_NODE_FLAGS && ! process.env.SELF_TEST_TOOL_NODE_FLAGS) console.log('Consider setting SELF_TEST_TOOL_NODE_FLAGS to configure ' + - 'self-test test applicaion spawns'); + 'self-test test application spawns'); env.TOOL_NODE_FLAGS = process.env.SELF_TEST_TOOL_NODE_FLAGS || ''; return env;