diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index 7bdae5362..43ef9967f 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -280,16 +280,16 @@ jobs: matrix: include: - platform: "macos-latest" - # Enable CI feature so prod() spawns backend + sync in release builds - args: "--target aarch64-apple-darwin --features ci" + # Enable bundled-sidecars feature so prod() spawns backend + sync in release builds + args: "--target aarch64-apple-darwin --features bundled-sidecars" server-artifact: "PictoPy-MacOS" sync-artifact: "PictoPy-Sync-MacOS" - platform: "ubuntu-22.04" - args: "--features ci" + args: "--features bundled-sidecars" server-artifact: "PictoPy-Ubuntu" sync-artifact: "PictoPy-Sync-Ubuntu" - platform: "windows-latest" - args: "--features ci" + args: "--features bundled-sidecars" server-artifact: "PictoPy-Windows" sync-artifact: "PictoPy-Sync-Windows" runs-on: ${{ matrix.platform }} diff --git a/.github/workflows/pr-check-build.yml b/.github/workflows/pr-check-build.yml index 8e6614df6..565cbdd7b 100644 --- a/.github/workflows/pr-check-build.yml +++ b/.github/workflows/pr-check-build.yml @@ -14,11 +14,11 @@ jobs: matrix: include: - platform: "macos-latest" - args: "--target aarch64-apple-darwin --features ci" + args: "--target aarch64-apple-darwin --features bundled-sidecars" - platform: "ubuntu-22.04" - args: "--features ci" + args: "--features bundled-sidecars" - platform: "windows-latest" - args: "--features ci" + args: "--features bundled-sidecars" runs-on: ${{ matrix.platform }} steps: - uses: actions/checkout@v4 diff --git a/frontend/src-tauri/Cargo.toml b/frontend/src-tauri/Cargo.toml index c16753a36..6689f20db 100644 --- a/frontend/src-tauri/Cargo.toml +++ b/frontend/src-tauri/Cargo.toml @@ -41,6 +41,9 @@ tauri-plugin-opener = "2.5.2" [features] # This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!! custom-protocol = ["tauri/custom-protocol"] -ci = [] +# Enables spawning the bundled Python backend/sync sidecars. Required for +# release builds (see frontend/src-tauri/src/main.rs); without it `prod()` +# fails loudly in release builds instead of silently launching a backend-less app. +bundled-sidecars = [] [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] diff --git a/frontend/src-tauri/src/main.rs b/frontend/src-tauri/src/main.rs index 5b7aa6acc..32a99138e 100644 --- a/frontend/src-tauri/src/main.rs +++ b/frontend/src-tauri/src/main.rs @@ -21,7 +21,7 @@ const ENDPOINTS: [(&str, &str, &str); 2] = [ ), ]; -#[cfg(feature = "ci")] +#[cfg(feature = "bundled-sidecars")] fn is_process_alive() -> bool { use reqwest::blocking::Client; @@ -102,9 +102,9 @@ fn kill_process_tree() -> Result<(), String> { Ok(()) } -#[cfg(feature = "ci")] +#[cfg(feature = "bundled-sidecars")] fn prod(app: &tauri::AppHandle, resource_path: &std::path::Path) -> Result<(), String> { - println!("`ci` feature enabled"); + println!("`bundled-sidecars` feature enabled"); let backend_path = resource_path.join("backend"); let backend_executable = backend_path.join("PictoPy_Server"); @@ -183,9 +183,43 @@ fn prod(app: &tauri::AppHandle, resource_path: &std::path::Path) -> Result<(), S Ok(()) } -#[cfg(not(feature = "ci"))] +#[cfg(not(feature = "bundled-sidecars"))] fn prod(_app: &tauri::AppHandle, _resource_path: &std::path::Path) -> Result<(), String> { - Ok(()) + prod_without_bundled_sidecars() +} + +#[cfg(not(feature = "bundled-sidecars"))] +fn prod_without_bundled_sidecars() -> Result<(), String> { + // `cargo tauri dev` intentionally omits this feature; the backend/sync + // services are run separately during local development. + if cfg!(debug_assertions) { + return Ok(()); + } + + // A release build without this feature would otherwise launch with no + // backend and no indication anything is wrong (see issue #1347). + Err( + "Release build is missing the `bundled-sidecars` feature: the bundled \ + backend/sync services will never be started. Rebuild with \ + `--features bundled-sidecars`." + .to_string(), + ) +} + +#[cfg(all(test, not(feature = "bundled-sidecars")))] +mod tests { + use super::*; + + #[test] + fn no_op_in_debug_builds_fails_loudly_in_release_builds() { + let result = prod_without_bundled_sidecars(); + + if cfg!(debug_assertions) { + assert_eq!(result, Ok(())); + } else { + assert!(result.is_err()); + } + } } fn main() {