Skip to main content

waterui_cli/android/
ndk_version.rs

1//! The pinned Android NDK release and its runtime-Gradle parser.
2
3/// NDK version the toolchain installs.
4///
5/// Mirrors the Android runtime's Gradle `ndkVersion`, embedded as a literal so
6/// an installed CLI never has to locate any source checkout to answer it. The
7/// runtime lives in `water-rs/android-backend`, pinned as the
8/// `backends/android` gitlink of the `water-rs/waterui` revision this crate's
9/// manifest builds against;
10/// `embedded_ndk_version_matches_the_pinned_android_backend` asserts the two
11/// stay in lockstep.
12pub const ANDROID_NDK_VERSION: &str = "29.0.14206865";
13
14/// Extracts the `ndkVersion = "…"` assignment from the Android runtime's
15/// `build.gradle.kts`. Returns `None` when the declaration is absent or
16/// malformed; comment-prefixed lines are ignored.
17#[must_use]
18pub fn parse_android_ndk_version_from_runtime_build_gradle(contents: &str) -> Option<String> {
19    contents.lines().find_map(|line| {
20        let line = line.split("//").next()?.trim();
21        let remainder = line.strip_prefix("ndkVersion")?;
22        let (_, value) = remainder.split_once('=')?;
23        let version = value.trim().trim_matches('"');
24        if version.is_empty() {
25            None
26        } else {
27            Some(version.to_string())
28        }
29    })
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35
36    #[test]
37    fn parse_android_ndk_version_from_runtime_build_gradle_extracts_declared_version() {
38        let contents = r#"
39android {
40    compileSdk = 37
41    ndkVersion = "29.0.14206865"
42}
43"#;
44        assert_eq!(
45            parse_android_ndk_version_from_runtime_build_gradle(contents),
46            Some("29.0.14206865".to_string())
47        );
48    }
49
50    /// `ANDROID_NDK_VERSION` must not drift from the runtime Gradle
51    /// declaration. The runtime is the `android-backend-revision` the pinned
52    /// framework revision declares (or its `backends/android` gitlink before
53    /// that declaration existed), so the comparison resolves that commit and
54    /// fetches `runtime/build.gradle.kts` there — network-bound, hence
55    /// nightly-only.
56    #[test]
57    #[ignore = "fetches the pinned water-rs/android-backend revision over the network"]
58    fn embedded_ndk_version_matches_the_pinned_android_backend() {
59        let (framework, revision) = crate::pinned_framework::source();
60        let (backend_commit, backend) =
61            crate::pinned_framework::android_backend(&framework, &revision);
62        let contents = String::from_utf8(crate::pinned_framework::fetch(
63            &crate::pinned_framework::raw_url(
64                &backend,
65                &backend_commit,
66                "runtime/build.gradle.kts",
67            ),
68        ))
69        .expect("runtime build.gradle.kts is UTF-8");
70        assert_eq!(
71            parse_android_ndk_version_from_runtime_build_gradle(&contents).as_deref(),
72            Some(ANDROID_NDK_VERSION),
73            "ANDROID_NDK_VERSION drifted from the pinned android-backend's \
74             runtime `ndkVersion` ({backend}@{backend_commit})"
75        );
76    }
77}