diff --git a/.buildkite/windows/entrypoint.bat b/.buildkite/windows/entrypoint.bat index a40f4c364..99b0c03db 100755 --- a/.buildkite/windows/entrypoint.bat +++ b/.buildkite/windows/entrypoint.bat @@ -8,7 +8,15 @@ if exist \bazel\node_modules ( ) call %BAZEL% test %BUILDARGS% ... -IF %ERRORLEVEL% NEQ 0 exit /B 1 +IF %ERRORLEVEL% NEQ 0 ( + echo checking ts build + call %BAZEL% build //ts/... || ( + echo ts build failed, cleaning up build products + call %BAZEL% run tools:cleanup_js + ) + + exit /B 1 +) echo --- Cleanup move node_modules \bazel\node_modules diff --git a/docs/windows.md b/docs/windows.md index c0718cae2..8208fb3d9 100644 --- a/docs/windows.md +++ b/docs/windows.md @@ -82,6 +82,15 @@ To run Anki in optimized mode, use: .\tools\runopt ``` +## Stale TS Files + +The build process may break when .ts files are removed or renamed on Windows. If you're +tracking Anki's development and you run into a TS build error, try the following: + +``` +bazel run tools:cleanup_js +``` + ## More For info on running tests, building wheels and so on, please see diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index 464420f10..d672bdd3b 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -5,3 +5,8 @@ py_binary( stamp = 1, visibility = ["//visibility:public"], ) + +py_binary( + name = "cleanup_js", + srcs = ["cleanup_js.py"], +) diff --git a/tools/cleanup_js.py b/tools/cleanup_js.py new file mode 100644 index 000000000..732e04165 --- /dev/null +++ b/tools/cleanup_js.py @@ -0,0 +1,32 @@ +# Copyright: Ankitects Pty Ltd and contributors +# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +# Because Bazel doesn't support building on a sandbox on Windows, our TypeScript +# outputs are not getting properly tracked. When a ts file is renamed or removed, +# the old build product is not automatically cleaned up, and that leads to a +# build failure until the stale outputs are manually removed. This script runs +# through the output folder, and removes all .ts/.js files to unbreak the build. + +import os +from pathlib import Path +from typing import Iterable +import stat + +root = Path(os.environ["BUILD_WORKSPACE_DIRECTORY"]) +out_base = root / ".bazel" / "out" + + +def dts_and_js_files(path: Path) -> Iterable[Path]: + for entry in path.iterdir(): + if "runfiles" in entry.name: + continue + elif entry.is_dir(): + yield from dts_and_js_files(entry.resolve()) + elif entry.suffix in (".ts", ".js") and not entry.name.startswith("_"): + yield entry.resolve() + + +for output_folder in out_base.glob("*windows*/bin/ts"): + for path in dts_and_js_files(output_folder): + path.chmod(stat.S_IWRITE) + path.unlink()