Skip to content

Commit 77defef

Browse files
feat(server): let packaged builds override the reported version (#656)
* feat(server): let packaged builds override the reported version /api/0/info reports the aw-server-rust package version, which is the version of a *component*, not of the product the user installed. On Android the webui footer showed "v0.14.0 (rust)" while the installed app was v0.14.0b2. Add version::set_version_override() so builds that embed aw-server-rust can report their own release version, plus a JNI entrypoint (setVersionOverride) mirroring the existing setDataDir pattern so aw-android can pass BuildConfig.VERSION_NAME at startup. The override is used verbatim — the caller owns the format, including any "v" prefix. Unset behaviour is unchanged. Refs ActivityWatch/aw-android#236 * test(version): use Drop guard to reset global state after test
1 parent 75722f3 commit 77defef

4 files changed

Lines changed: 78 additions & 2 deletions

File tree

aw-server/src/android/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,20 @@ pub mod android {
172172
dirs::set_android_data_dir(path);
173173
}
174174

175+
/// Report the Android app's release version from `/api/0/info` instead of
176+
/// the aw-server-rust package version, which is the version of a component
177+
/// rather than of the app the user installed.
178+
#[no_mangle]
179+
pub unsafe extern "C" fn Java_net_activitywatch_android_RustInterface_setVersionOverride(
180+
env: JNIEnv,
181+
_: JClass,
182+
java_version: JString,
183+
) {
184+
let version = &jstring_to_string(&env, java_version);
185+
debug!("Setting reported version to {}", version);
186+
crate::version::set_version_override(version);
187+
}
188+
175189
#[no_mangle]
176190
pub unsafe extern "C" fn Java_net_activitywatch_android_RustInterface_getBuckets(
177191
env: JNIEnv,

aw-server/src/endpoints/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,10 @@ fn root_manifest(state: &State<ServerState>) -> Option<(ContentType, Vec<u8>)> {
112112
fn server_info(config: &State<AWConfig>, state: &State<ServerState>) -> Json<Info> {
113113
#[allow(clippy::or_fun_call)]
114114
let hostname = gethostname().into_string().unwrap_or("unknown".to_string());
115-
const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
116115

117116
Json(Info {
118117
hostname,
119-
version: format!("v{} (rust)", VERSION.unwrap_or("(unknown)")),
118+
version: crate::version::version_string(),
120119
testing: config.testing,
121120
device_id: state.device_id.clone(),
122121
})

aw-server/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub mod device_id;
2424
pub mod dirs;
2525
pub mod endpoints;
2626
pub mod logging;
27+
pub mod version;
2728

2829
#[cfg(target_os = "android")]
2930
pub mod android;

aw-server/src/version.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//! Version string reported by `GET /api/0/info`.
2+
//!
3+
//! By default this is the aw-server-rust package version. That is wrong for
4+
//! builds that embed aw-server-rust as a component of a larger product: on
5+
//! Android the webui footer showed `v0.14.0 (rust)` (the Cargo.toml version)
6+
//! while the installed app was `v0.14.0b2`.
7+
//!
8+
//! Such builds call [`set_version_override`] at startup to report their own
9+
//! release version instead.
10+
11+
use std::sync::RwLock;
12+
13+
static VERSION_OVERRIDE: RwLock<Option<String>> = RwLock::new(None);
14+
15+
/// Report `version` from `/api/0/info` instead of the package version.
16+
///
17+
/// The string is used verbatim, so the caller controls the exact format
18+
/// (including any `v` prefix).
19+
pub fn set_version_override(version: &str) {
20+
let mut guard = VERSION_OVERRIDE.write().unwrap();
21+
*guard = Some(version.to_string());
22+
}
23+
24+
/// The version string to report from `/api/0/info`.
25+
pub fn version_string() -> String {
26+
if let Some(version) = VERSION_OVERRIDE.read().unwrap().as_ref() {
27+
return version.clone();
28+
}
29+
const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION");
30+
format!("v{} (rust)", VERSION.unwrap_or("(unknown)"))
31+
}
32+
33+
#[cfg(test)]
34+
mod tests {
35+
use super::*;
36+
37+
struct VersionGuard;
38+
impl Drop for VersionGuard {
39+
fn drop(&mut self) {
40+
*VERSION_OVERRIDE.write().unwrap() = None;
41+
}
42+
}
43+
44+
// These share process-global state, so they run as one test.
45+
#[test]
46+
fn override_replaces_package_version() {
47+
let _guard = VersionGuard; // resets VERSION_OVERRIDE on exit, even on panic
48+
49+
assert!(
50+
version_string().ends_with(" (rust)"),
51+
"default should report the package version, got {:?}",
52+
version_string()
53+
);
54+
55+
set_version_override("v0.14.0b2");
56+
assert_eq!(version_string(), "v0.14.0b2");
57+
58+
// Used verbatim: the caller owns the format.
59+
set_version_override("1.2.3-custom");
60+
assert_eq!(version_string(), "1.2.3-custom");
61+
}
62+
}

0 commit comments

Comments
 (0)