diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6f6b778478..11f8e7e596 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -96,6 +96,9 @@ jobs: # integration tests for `cargo test`, so `test-utils` is not # required here. cargo_args: "--no-default-features --features server-bin --bin codeg-server --lib" + # macOS builds the lib's unit tests on their own first; see + # "Unit-test build on its own (macOS)". + lib_test_args: "--no-default-features --features server-bin --lib" # Server clippy intentionally skips `--all-targets`: integration # tests are already linted in the desktop cells, and pulling # them in here would force `test-utils` (a test-only feature) @@ -146,6 +149,26 @@ jobs: mkdir -p out printf '\n' > out/index.html + - name: Unit-test build on its own (macOS) + # The macOS runners have 3 cores and 7 GB of memory. `cargo test` + # compiles codeg_lib twice, the rlib that the bins link and the lib's + # own unit-test build, each several GB on its own; side by side they + # push the server cell deep into swap. With the unit tests built + # first, the `cargo test` below finds them fresh and compiles the + # rlib alone. It has to be a `cargo test` build: only test builds turn + # on the dev-dependencies' features (tokio's `test-util`), so a lib + # from `cargo build` is not one `cargo test` reuses. + # + # Not the desktop cell. Tauri's `generate_context!` writes its + # embedded assets into the build script's out dir during the crate's + # first compile, after that compile started, so the next cargo run + # takes them for changes and builds the unit tests again. Alone, the + # desktop unit-test build still took 18 minutes. The cli cell builds + # only the unit tests, and Linux and Windows fit both at once. + if: runner.os == 'macOS' && matrix.lib_test_args + working-directory: src-tauri + run: cargo test ${{ matrix.lib_test_args }} --no-run + - name: cargo test # Windows desktop test binaries link the Tauri runtime and can fail at # process load on GitHub-hosted runners before Rust tests start. Keep diff --git a/src-tauri/build.rs b/src-tauri/build.rs index 83bad86789..e8c175198f 100644 --- a/src-tauri/build.rs +++ b/src-tauri/build.rs @@ -73,11 +73,20 @@ fn fingerprint_helper_sources() { /// /// If you ever bypass those wrappers (e.g. invoking the Tauri CLI directly /// without beforeBuildCommand) you'd ship the placeholder, so emit a -/// cargo:warning that surfaces in any compile log to make that loud. +/// cargo:warning that surfaces in any compile log to make that loud. Cargo +/// replays it on builds that do not rerun this script. +/// +/// The placeholder is watched (`rerun-if-changed`), so that the real sidecar +/// landing reruns this script, and cargo counts a watched file as changed +/// when it is newer than the start of the script's last run. A placeholder +/// that already exists is therefore left alone, and a new one is dated back +/// to 1970: writing it during the run would make the next build rerun the +/// script, and rebuild every target of the crate after it, every time. #[cfg(feature = "tauri-runtime")] fn ensure_sidecar_placeholder() { use std::fs; use std::path::PathBuf; + use std::time::SystemTime; let triple = std::env::var("TARGET").unwrap_or_default(); if triple.is_empty() { @@ -95,32 +104,34 @@ fn ensure_sidecar_placeholder() { println!("cargo:rerun-if-changed={}", path.display()); - let needs_placeholder = match fs::metadata(&path) { - Ok(meta) => meta.len() == 0, - Err(_) => true, - }; - - if needs_placeholder { - if let Err(e) = fs::create_dir_all(&dir) { - panic!("failed to create {}: {e}", dir.display()); - } - if let Err(e) = fs::write(&path, b"") { - panic!( - "failed to write sidecar placeholder {}: {e}", - path.display() - ); - } - #[cfg(unix)] - { - use std::os::unix::fs::PermissionsExt; - let _ = fs::set_permissions(&path, fs::Permissions::from_mode(0o755)); + match fs::metadata(&path) { + Ok(meta) if meta.len() > 0 => continue, + Ok(_) => {} + Err(_) => { + if let Err(e) = fs::create_dir_all(&dir) { + panic!("failed to create {}: {e}", dir.display()); + } + let placeholder = match fs::File::create(&path) { + Ok(file) => file, + Err(e) => panic!( + "failed to write sidecar placeholder {}: {e}", + path.display() + ), + }; + // Should this fail, the next build reruns the script once. + let _ = placeholder.set_modified(SystemTime::UNIX_EPOCH); + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let _ = fs::set_permissions(&path, fs::Permissions::from_mode(0o755)); + } } - println!( - "cargo:warning={name} sidecar missing at {}; wrote 0-byte placeholder. \ - Run `pnpm tauri:prepare-sidecars` before `tauri build` to ship a working binary.", - path.display() - ); } + println!( + "cargo:warning={name} sidecar at {} is a 0-byte placeholder. \ + Run `pnpm tauri:prepare-sidecars` before `tauri build` to ship a working binary.", + path.display() + ); } }