diff --git a/e2e/webpack_devserver/BUILD.bazel b/e2e/webpack_devserver/BUILD.bazel index 950709f2b..e39c0e591 100644 --- a/e2e/webpack_devserver/BUILD.bazel +++ b/e2e/webpack_devserver/BUILD.bazel @@ -23,6 +23,7 @@ js_run_devserver( ], data = [ "package.json", + "src/404.html", "src/index.html", "src/index.js", "webpack.config.js", @@ -41,6 +42,7 @@ js_run_devserver( ], data = [ "package.json", + "src/404.html", "src/index.html", "src/index.js", "webpack.config.cjs", diff --git a/e2e/webpack_devserver/serve_test.sh b/e2e/webpack_devserver/serve_test.sh index 80198a0a3..1c2127a5d 100755 --- a/e2e/webpack_devserver/serve_test.sh +++ b/e2e/webpack_devserver/serve_test.sh @@ -28,6 +28,7 @@ function _exit { git checkout src/index.html >/dev/null 2>&1 git checkout mypkg/index.js >/dev/null 2>&1 git checkout mylib/index.js >/dev/null 2>&1 + git checkout BUILD.bazel >/dev/null 2>&1 rm -f "$ibazel_logs" } trap _exit EXIT @@ -93,48 +94,97 @@ if ! curl http://localhost:8080/main.js --fail 2>/dev/null | grep "chalk.cyan(pa exit 1 fi +_sedi 's#"src/404.html",##' BUILD.bazel + +echo "Waiting 10 seconds for ibazel rebuild after change to BUILD.bazel..." +sleep 10 + +git checkout BUILD.bazel >/dev/null 2>&1 + +echo "Waiting 10 seconds for ibazel rebuild after change to BUILD.bazel..." +sleep 10 + echo "Checking log file $ibazel_logs" count=$(grep -c "Syncing symlink node_modules/.aspect_rules_js/@mycorp+mylib@0.0.0/node_modules/@mycorp/mylib (1p)" "$ibazel_logs" || true) if [[ "$count" -ne 1 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" echo "ERROR: expected to have synced @mycorp/mylib symlink 1 time but found ${count}" exit 1 fi count=$(grep -c "Syncing file node_modules/.aspect_rules_js/@mycorp+mypkg@0.0.0/node_modules/@mycorp/mypkg/index.js" "$ibazel_logs" || true) if [[ "$count" -ne 2 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" echo "ERROR: expected to have synced @mycorp/mypkg/index.js 2 times but found ${count}" exit 1 fi count=$(grep -c "Syncing file mylib/index.js" "$ibazel_logs" || true) if [[ "$count" -ne 2 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" echo "ERROR: expected to have synced mylib/index.js 2 times but found ${count}" exit 1 fi count=$(grep -c "Skipping file node_modules/.aspect_rules_js/@mycorp+mypkg@0.0.0/node_modules/@mycorp/mypkg/index.js since its timestamp has not changed" "$ibazel_logs" || true) -if [[ "$count" -ne 2 ]]; then - echo "ERROR: expected to have skipped @mycorp/mypkg/index.js due to timestamp 2 times but found ${count}" +if [[ "$count" -ne 4 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" + echo "ERROR: expected to have skipped @mycorp/mypkg/index.js due to timestamp 4 times but found ${count}" exit 1 fi count=$(grep -c "Syncing file node_modules/.aspect_rules_js/@mycorp+mypkg@0.0.0/node_modules/@mycorp/mypkg/package.json" "$ibazel_logs" || true) if [[ "$count" -ne 1 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" echo "ERROR: expected to have synced @mycorp/mypkg/package.json 1 time but found ${count}" exit 1 fi count=$(grep -c "Skipping file node_modules/.aspect_rules_js/@mycorp+mypkg@0.0.0/node_modules/@mycorp/mypkg/package.json since its timestamp has not changed" "$ibazel_logs" || true) -if [[ "$count" -ne 2 ]]; then - echo "ERROR: expected to have skipped @mycorp/mypkg/package.json due to timestamp 2 times but found ${count}" +if [[ "$count" -ne 4 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" + echo "ERROR: expected to have skipped @mycorp/mypkg/package.json due to timestamp 4 times but found ${count}" exit 1 fi count=$(grep -c "Skipping file node_modules/.aspect_rules_js/@mycorp+mypkg@0.0.0/node_modules/@mycorp/mypkg/package.json since contents have not changed" "$ibazel_logs" || true) if [[ "$count" -ne 1 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" echo "ERROR: expected to have skipped @mycorp/mypkg/package.json due to contents 1 times but found ${count}" exit 1 fi +count=$(grep -c "Deleting src/404.html" "$ibazel_logs" || true) +if [[ "$count" -ne 1 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" + echo "ERROR: expected to have deleted src/404.html 1 time but found ${count}" + exit 1 +fi + +count=$(grep -c "Syncing file src/404.html" "$ibazel_logs" || true) +if [[ "$count" -ne 2 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" + echo "ERROR: expected to have synced src/404.html 2 times but found ${count}" + exit 1 +fi + echo "All tests passed" diff --git a/e2e/webpack_devserver/src/404.html b/e2e/webpack_devserver/src/404.html new file mode 100644 index 000000000..c12c1a76f --- /dev/null +++ b/e2e/webpack_devserver/src/404.html @@ -0,0 +1,10 @@ + + + + + 404 + + + 404 + + diff --git a/e2e/webpack_devserver_esm/BUILD.bazel b/e2e/webpack_devserver_esm/BUILD.bazel index fb0803222..cdfb9418e 100644 --- a/e2e/webpack_devserver_esm/BUILD.bazel +++ b/e2e/webpack_devserver_esm/BUILD.bazel @@ -23,6 +23,7 @@ js_run_devserver( ], data = [ "package.json", + "src/404.html", "src/index.html", "src/index.js", "webpack.config.mjs", diff --git a/e2e/webpack_devserver_esm/serve_test.sh b/e2e/webpack_devserver_esm/serve_test.sh index da754a0e7..b910e86d0 100755 --- a/e2e/webpack_devserver_esm/serve_test.sh +++ b/e2e/webpack_devserver_esm/serve_test.sh @@ -26,6 +26,7 @@ function _exit { git checkout src/index.html >/dev/null 2>&1 git checkout mypkg/index.js >/dev/null 2>&1 git checkout mylib/index.js >/dev/null 2>&1 + git checkout BUILD.bazel >/dev/null 2>&1 rm -f "$ibazel_logs" } trap _exit EXIT @@ -91,46 +92,97 @@ if ! curl http://localhost:8080/main.js --fail 2>/dev/null | grep "chalk__WEBPAC exit 1 fi +_sedi 's#"src/404.html",##' BUILD.bazel + +echo "Waiting 10 seconds for ibazel rebuild after change to BUILD.bazel..." +sleep 10 + +git checkout BUILD.bazel >/dev/null 2>&1 + +echo "Waiting 10 seconds for ibazel rebuild after change to BUILD.bazel..." +sleep 10 + +echo "Checking log file $ibazel_logs" + count=$(grep -c "Syncing symlink node_modules/.aspect_rules_js/@mycorp+mylib@0.0.0/node_modules/@mycorp/mylib (1p)" "$ibazel_logs" || true) if [[ "$count" -ne 1 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" echo "ERROR: expected to have synced @mycorp/mylib symlink 1 time but found ${count}" exit 1 fi count=$(grep -c "Syncing file node_modules/.aspect_rules_js/@mycorp+mypkg@0.0.0/node_modules/@mycorp/mypkg/index.js" "$ibazel_logs" || true) if [[ "$count" -ne 2 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" echo "ERROR: expected to have synced @mycorp/mypkg/index.js 2 times but found ${count}" exit 1 fi count=$(grep -c "Syncing file mylib/index.js" "$ibazel_logs" || true) if [[ "$count" -ne 2 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" echo "ERROR: expected to have synced mylib/index.js 2 times but found ${count}" exit 1 fi count=$(grep -c "Skipping file node_modules/.aspect_rules_js/@mycorp+mypkg@0.0.0/node_modules/@mycorp/mypkg/index.js since its timestamp has not changed" "$ibazel_logs" || true) -if [[ "$count" -ne 2 ]]; then - echo "ERROR: expected to have skipped @mycorp/mypkg/index.js due to timestamp 2 times but found ${count}" +if [[ "$count" -ne 4 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" + echo "ERROR: expected to have skipped @mycorp/mypkg/index.js due to timestamp 4 times but found ${count}" exit 1 fi count=$(grep -c "Syncing file node_modules/.aspect_rules_js/@mycorp+mypkg@0.0.0/node_modules/@mycorp/mypkg/package.json" "$ibazel_logs" || true) if [[ "$count" -ne 1 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" echo "ERROR: expected to have synced @mycorp/mypkg/package.json 1 time but found ${count}" exit 1 fi count=$(grep -c "Skipping file node_modules/.aspect_rules_js/@mycorp+mypkg@0.0.0/node_modules/@mycorp/mypkg/package.json since its timestamp has not changed" "$ibazel_logs" || true) -if [[ "$count" -ne 2 ]]; then - echo "ERROR: expected to have skipped @mycorp/mypkg/package.json due to timestamp 2 times but found ${count}" +if [[ "$count" -ne 4 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" + echo "ERROR: expected to have skipped @mycorp/mypkg/package.json due to timestamp 4 times but found ${count}" exit 1 fi count=$(grep -c "Skipping file node_modules/.aspect_rules_js/@mycorp+mypkg@0.0.0/node_modules/@mycorp/mypkg/package.json since contents have not changed" "$ibazel_logs" || true) if [[ "$count" -ne 1 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" echo "ERROR: expected to have skipped @mycorp/mypkg/package.json due to contents 1 times but found ${count}" exit 1 fi +count=$(grep -c "Deleting src/404.html" "$ibazel_logs" || true) +if [[ "$count" -ne 1 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" + echo "ERROR: expected to have deleted src/404.html 1 time but found ${count}" + exit 1 +fi + +count=$(grep -c "Syncing file src/404.html" "$ibazel_logs" || true) +if [[ "$count" -ne 2 ]]; then + echo "===========" + cat "$ibazel_logs" + echo "===========" + echo "ERROR: expected to have synced src/404.html 2 times but found ${count}" + exit 1 +fi + echo "All tests passed" diff --git a/e2e/webpack_devserver_esm/src/404.html b/e2e/webpack_devserver_esm/src/404.html new file mode 100644 index 000000000..c12c1a76f --- /dev/null +++ b/e2e/webpack_devserver_esm/src/404.html @@ -0,0 +1,10 @@ + + + + + 404 + + + 404 + + diff --git a/js/private/js_run_devserver.mjs b/js/private/js_run_devserver.mjs index f5ee38f79..3685e94bf 100644 --- a/js/private/js_run_devserver.mjs +++ b/js/private/js_run_devserver.mjs @@ -246,8 +246,62 @@ async function syncRecursive(src, dst, sandbox, writePerm) { } } +// Delete files from sandbox +async function deleteFiles(previousFiles, updatedFiles, sandbox) { + const startTime = perf_hooks.performance.now() + + let totalDeleted = 0 + + // Remove files that were previously synced but are no longer in the updated list of files to sync + const updatedFilesSet = new Set(updatedFiles) + for (const f of previousFiles) { + if (updatedFilesSet.has(f)) { + continue + } + + console.error(`Deleting ${f}`) + + // clear any matching files or files rooted at this folder from the + // syncedTime and syncedChecksum maps + const srcPath = path.join(RUNFILES_ROOT, f) + for (const k of syncedTime.keys()) { + if (k == srcPath || k.startsWith(srcPath + '/')) { + syncedTime.delete(k) + } + } + for (const k of syncedChecksum.keys()) { + if (k == srcPath || k.startsWith(srcPath + '/')) { + syncedChecksum.delete(k) + } + } + + // clear mkdirs if we have deleted any files so we re-populate on next sync + mkdirs.clear() + + const rmPath = path.join(sandbox, f) + try { + fs.rmSync(rmPath, { recursive: true, force: true }) + } catch (e) { + console.error( + `An error has occurred while deleting the synced file ${rmPath}. Error: ${e}` + ) + } + totalDeleted++ + } + + var endTime = perf_hooks.performance.now() + + if (totalDeleted > 0) { + console.error( + `${totalDeleted} file${totalDeleted > 1 ? 's' : ''}/folder${ + totalDeleted > 1 ? 's' : '' + } deleted in ${Math.round(endTime - startTime)} ms` + ) + } +} + // Sync list of files to the sandbox -async function sync(files, sandbox, writePerm) { +async function syncFiles(files, sandbox, writePerm) { console.error(`+ Syncing ${files.length} files && folders...`) const startTime = perf_hooks.performance.now() @@ -331,7 +385,7 @@ async function main(args, sandbox) { const config = JSON.parse(await fs.promises.readFile(configPath)) - await sync( + await syncFiles( config.data_files, sandbox, config.grant_sandbox_write_permissions @@ -402,14 +456,25 @@ async function main(args, sandbox) { console.error('IBAZEL_BUILD_COMPLETED SUCCESS') } // Chain promises via syncing.then() - syncing = syncing.then(() => - sync( - // Re-parse the config file to get the latest list of data files to copy - JSON.parse(fs.readFileSync(configPath)).data_files, + syncing = syncing.then(() => { + // Re-parse the config file to get the latest list of data files to copy + const updatedDataFiles = JSON.parse( + fs.readFileSync(configPath) + ).data_files + // Remove files that were previously synced but are no longer in the updated list of files to sync + deleteFiles( + config.data_files, + updatedDataFiles, + sandbox + ) + // Sync changed files + config.data_files = updatedDataFiles + syncFiles( + config.data_files, sandbox, config.grant_sandbox_write_permissions ) - ) + }) // Await promise to catch any exceptions, and wait for the // sync to be complete before writing to stdin of the child // process