From 1f393f1c7f108c2e6d5f0d5e0c1775f2ce73e2ad Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Sun, 1 Sep 2024 14:55:51 -0700 Subject: [PATCH] Add server and client build versions --- Cargo.lock | 228 +++++++++++++++++++++++++++++++- server/Cargo.toml | 4 + server/build.rs | 5 + server/src/bin/server.rs | 3 + server/src/graphql.rs | 4 + shared/Cargo.toml | 1 + shared/src/lib.rs | 20 +++ web/Cargo.toml | 4 + web/build.rs | 5 + web/graphql/front_page.graphql | 1 + web/graphql/schema.json | 16 +++ web/graphql/show_thread.graphql | 1 + web/src/state.rs | 28 +++- web/src/view/desktop.rs | 5 +- web/src/view/mobile.rs | 5 +- web/src/view/mod.rs | 19 ++- web/src/view/tablet.rs | 6 +- 17 files changed, 342 insertions(+), 13 deletions(-) create mode 100644 server/build.rs create mode 100644 web/build.rs diff --git a/Cargo.lock b/Cargo.lock index 7364fd4..9f785c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -358,6 +358,15 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.2.1" @@ -382,6 +391,70 @@ dependencies = [ "generic-array", ] +[[package]] +name = "build-info" +version = "0.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3465eaabbf2f3bf2a28a4ee66d16316071ef63c1ab9f336e833ea67f519c0348" +dependencies = [ + "bincode", + "build-info-common", + "build-info-proc", +] + +[[package]] +name = "build-info-build" +version = "0.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c967db0724d13dfcd67d6f54023bfd0f7093872810c1377f00c6b86ce507513f" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bincode", + "build-info-common", + "cargo_metadata", + "chrono", + "git2", + "glob", + "pretty_assertions", + "rustc_version", + "serde_json", + "zstd", +] + +[[package]] +name = "build-info-common" +version = "0.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c88e36f2531db6136c2d42810698ced69af85872f4559c7b6dccb8e7c30485d2" +dependencies = [ + "chrono", + "derive_more 1.0.0", + "semver", + "serde", +] + +[[package]] +name = "build-info-proc" +version = "0.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58463d44fa27e9afbf377c0f5661eaf8d3b69b1a4a45b0fa601b822ccf7512e8" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bincode", + "build-info-common", + "chrono", + "num-bigint", + "num-traits", + "proc-macro-error", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.69", + "zstd", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -409,11 +482,48 @@ dependencies = [ "serde", ] +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cc" version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437" +dependencies = [ + "jobserver", + "libc", + "once_cell", +] [[package]] name = "cfg-if" @@ -441,6 +551,7 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", + "serde", "wasm-bindgen", "windows-targets 0.52.6", ] @@ -758,6 +869,27 @@ dependencies = [ "syn 2.0.69", ] +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", + "unicode-xid", +] + [[package]] name = "devise" version = "0.4.1" @@ -1174,6 +1306,19 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +[[package]] +name = "git2" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" +dependencies = [ + "bitflags 2.6.0", + "libc", + "libgit2-sys", + "log", + "url", +] + [[package]] name = "glob" version = "0.3.1" @@ -1854,6 +1999,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.69" @@ -1882,6 +2036,8 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" name = "letterbox" version = "0.1.0" dependencies = [ + "build-info", + "build-info-build", "chrono", "console_error_panic_hook", "console_log", @@ -1907,6 +2063,18 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "libgit2-sys" +version = "0.17.0+1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + [[package]] name = "libm" version = "0.2.8" @@ -1924,6 +2092,18 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "libz-sys" +version = "1.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linkify" version = "0.10.0" @@ -2224,6 +2404,16 @@ dependencies = [ "thiserror", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-bigint-dig" version = "0.8.4" @@ -3455,7 +3645,7 @@ checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" dependencies = [ "bitflags 1.2.1", "cssparser 0.27.2", - "derive_more", + "derive_more 0.99.18", "fxhash", "log", "matches", @@ -3475,7 +3665,7 @@ checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06" dependencies = [ "bitflags 2.6.0", "cssparser 0.31.2", - "derive_more", + "derive_more 0.99.18", "fxhash", "log", "new_debug_unreachable", @@ -3491,6 +3681,9 @@ name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] [[package]] name = "serde" @@ -3564,6 +3757,8 @@ dependencies = [ "async-graphql", "async-graphql-rocket", "async-trait", + "build-info", + "build-info-build", "css-inline", "glog", "html-escape", @@ -3642,6 +3837,7 @@ dependencies = [ name = "shared" version = "0.1.0" dependencies = [ + "build-info", "notmuch", "serde", ] @@ -5115,3 +5311,31 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/server/Cargo.toml b/server/Cargo.toml index eebf166..f637df8 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -12,6 +12,7 @@ anyhow = "1.0.79" async-graphql = { version = "6.0.11", features = ["log"] } async-graphql-rocket = "6.0.11" async-trait = "0.1.81" +build-info = "0.0.38" css-inline = "0.13.0" glog = "0.1.0" html-escape = "0.2.13" @@ -34,3 +35,6 @@ thiserror = "1.0.37" tokio = "1.26.0" url = "2.5.2" urlencoding = "2.1.3" + +[build-dependencies] +build-info-build = "0.0.38" diff --git a/server/build.rs b/server/build.rs new file mode 100644 index 0000000..a860094 --- /dev/null +++ b/server/build.rs @@ -0,0 +1,5 @@ +fn main() { + // Calling `build_info_build::build_script` collects all data and makes it available to `build_info::build_info!` + // and `build_info::format!` in the main program. + build_info_build::build_script(); +} diff --git a/server/src/bin/server.rs b/server/src/bin/server.rs index 55f4f8d..2a6b2a4 100644 --- a/server/src/bin/server.rs +++ b/server/src/bin/server.rs @@ -183,6 +183,7 @@ async fn graphql_request( request.execute(schema.inner()).await } + #[rocket::main] async fn main() -> Result<(), Box> { glog::new() @@ -193,6 +194,8 @@ async fn main() -> Result<(), Box> { ..Default::default() }) .unwrap(); + build_info::build_info!(fn bi); + info!("Build Info: {}", shared::build_version(bi)); let allowed_origins = AllowedOrigins::all(); let cors = rocket_cors::CorsOptions { allowed_origins, diff --git a/server/src/graphql.rs b/server/src/graphql.rs index 744a4e4..2aa5a78 100644 --- a/server/src/graphql.rs +++ b/server/src/graphql.rs @@ -229,6 +229,10 @@ struct SearchCursor { pub struct QueryRoot; #[Object] impl QueryRoot { + async fn version<'ctx>(&self, _ctx: &Context<'ctx>) -> Result { + build_info::build_info!(fn bi); + Ok(shared::build_version(bi)) + } async fn count<'ctx>(&self, ctx: &Context<'ctx>, query: String) -> Result { let nm = ctx.data_unchecked::(); let pool = ctx.data_unchecked::(); diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 7ca8b97..3372208 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -6,5 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +build-info = "0.0.38" notmuch = { path = "../notmuch" } serde = { version = "1.0.147", features = ["derive"] } diff --git a/shared/src/lib.rs b/shared/src/lib.rs index e5f5cf3..9ccdca4 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -1,4 +1,5 @@ use notmuch::SearchSummary; +use build_info::{VersionControl,BuildInfo}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] @@ -33,3 +34,22 @@ pub mod urls { } } } +pub fn build_version(bi:fn()->&'static BuildInfo) -> String { + fn commit(git: &Option) -> String { + let Some(VersionControl::Git(git)) = git else { + return String::new(); + }; + let mut s = vec![git.commit_short_id.clone()]; + if git.dirty { + s.push(".+".to_string()); + } + + if let Some(branch) = &git.branch { + s.push(format!(" ({branch})")); + } + s.join("") + } + let bi = bi(); + + format!("{}-{}", bi.crate_info.version, commit(&bi.version_control)).to_string() +} diff --git a/web/Cargo.toml b/web/Cargo.toml index 8bce6af..484c4ad 100644 --- a/web/Cargo.toml +++ b/web/Cargo.toml @@ -9,6 +9,9 @@ license = "MIT" readme = "./README.md" edition = "2018" +[build-dependencies] +build-info-build = "0.0.38" + [dev-dependencies] wasm-bindgen-test = "0.3.33" @@ -29,6 +32,7 @@ thiserror = "1.0.50" seed_hooks = { git = "https://github.com/wathiede/styles_hooks", package = "seed_hooks", branch = "main" } gloo-net = { version = "0.4.0", features = ["json", "serde_json"] } human_format = "1.1.0" +build-info = "0.0.38" [package.metadata.wasm-pack.profile.release] wasm-opt = ['-Os'] diff --git a/web/build.rs b/web/build.rs new file mode 100644 index 0000000..a860094 --- /dev/null +++ b/web/build.rs @@ -0,0 +1,5 @@ +fn main() { + // Calling `build_info_build::build_script` collects all data and makes it available to `build_info::build_info!` + // and `build_info::format!` in the main program. + build_info_build::build_script(); +} diff --git a/web/graphql/front_page.graphql b/web/graphql/front_page.graphql index 5a5fd22..79c056c 100644 --- a/web/graphql/front_page.graphql +++ b/web/graphql/front_page.graphql @@ -22,4 +22,5 @@ query FrontPageQuery($query: String!, $after: String $before: String, $first: In fgColor unread } + version } diff --git a/web/graphql/schema.json b/web/graphql/schema.json index d0305ca..23400d9 100644 --- a/web/graphql/schema.json +++ b/web/graphql/schema.json @@ -1111,6 +1111,22 @@ "description": null, "enumValues": null, "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "version", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, { "args": [ { diff --git a/web/graphql/show_thread.graphql b/web/graphql/show_thread.graphql index 46cfadf..33092ab 100644 --- a/web/graphql/show_thread.graphql +++ b/web/graphql/show_thread.graphql @@ -64,4 +64,5 @@ query ShowThreadQuery($threadId: String!) { fgColor unread } + version } diff --git a/web/src/state.rs b/web/src/state.rs index ed65527..60964ec 100644 --- a/web/src/state.rs +++ b/web/src/state.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use graphql_client::GraphQLQuery; -use log::{error, info}; +use log::{error, info, warn}; use seed::{prelude::*, *}; use thiserror::Error; @@ -27,6 +27,8 @@ pub fn unread_query() -> &'static str { // `init` describes what should happen when your app started. pub fn init(url: Url, orders: &mut impl Orders) -> Model { + let version = shared::build_version(bi); + info!("Build Info: {}", version); if url.hash().is_none() { orders.request_url(urls::search(unread_query(), 0)); } else { @@ -41,12 +43,17 @@ pub fn init(url: Url, orders: &mut impl Orders) -> Model { compute_scroll_ratio() })); + build_info::build_info!(fn bi); Model { context: Context::None, query: "".to_string(), refreshing_state: RefreshingState::None, tags: None, read_completion_ratio: 0., + versions: Version { + client: version, + server: None, + }, } } @@ -335,6 +342,7 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { pager: data.search.page_info, selected_threads, }; + orders.send_msg(Msg::UpdateServerVersion(data.version)); } Msg::ShowThreadRequest { thread_id } => { @@ -384,6 +392,7 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { }; } } + orders.send_msg(Msg::UpdateServerVersion(data.version)); } Msg::ShowThreadResult(bad) => { error!("show_thread_query error: {bad:#?}"); @@ -507,6 +516,15 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { Msg::SetProgress(ratio) => { model.read_completion_ratio = ratio; } + Msg::UpdateServerVersion(version) => { + if version != model.versions.client { + warn!( + "Server ({}) and client ({}) version mismatch", + version, model.versions.client + ); + } + model.versions.server = Some(version); + } } } // `Model` describes our app state. @@ -516,6 +534,13 @@ pub struct Model { pub refreshing_state: RefreshingState, pub tags: Option>, pub read_completion_ratio: f64, + pub versions: Version, +} + +#[derive(Debug)] +pub struct Version { + pub client: String, + pub server: Option, } #[derive(Error, Debug)] @@ -612,4 +637,5 @@ pub enum Msg { CopyToClipboard(String), SetProgress(f64), + UpdateServerVersion(String), } diff --git a/web/src/view/desktop.rs b/web/src/view/desktop.rs index d521058..2babae6 100644 --- a/web/src/view/desktop.rs +++ b/web/src/view/desktop.rs @@ -4,12 +4,11 @@ use seed_hooks::topo; use crate::{ graphql::show_thread_query::*, state::{Context, Model, Msg}, - view::{self, reading_progress, view_header, view_search_results, view_tags}, + view::{self, reading_progress, view_header, view_search_results}, }; #[topo::nested] pub(super) fn view(model: &Model) -> Node { - log::info!("tablet::view"); let show_icon_text = true; // Do two queries, one without `unread` so it loads fast, then a second with unread. let content = match &model.context { @@ -40,7 +39,7 @@ pub(super) fn view(model: &Model) -> Node { div![ C!["main-content"], reading_progress(model.read_completion_ratio), - view_tags(model), + div![view::tags(model), view::versions(&model.versions)], div![ view_header(&model.query, &model.refreshing_state), content, diff --git a/web/src/view/mobile.rs b/web/src/view/mobile.rs index 0ec70b3..fcab129 100644 --- a/web/src/view/mobile.rs +++ b/web/src/view/mobile.rs @@ -8,12 +8,11 @@ use crate::{ state::{Context, Model, Msg}, view::{ self, human_age, pretty_authors, reading_progress, search_toolbar, set_title, tags_chiclet, - view_header, view_tags, + view_header, }, }; pub(super) fn view(model: &Model) -> Node { - log::info!("mobile::view"); let show_icon_text = false; let content = match &model.context { Context::None => div![h1!["Loading"]], @@ -45,7 +44,7 @@ pub(super) fn view(model: &Model) -> Node { view_header(&model.query, &model.refreshing_state), content, view_header(&model.query, &model.refreshing_state), - view_tags(model), + div![view::tags(model), view::versions(&model.versions)] ] } diff --git a/web/src/view/mod.rs b/web/src/view/mod.rs index 11a142d..9427494 100644 --- a/web/src/view/mod.rs +++ b/web/src/view/mod.rs @@ -976,7 +976,7 @@ pub fn view(model: &Model) -> Node { _ => div![C!["desktop"], desktop::view(model)], },] } -pub fn view_tags(model: &Model) -> Node { +pub fn tags(model: &Model) -> Node { fn view_tag_li(display_name: &str, indent: usize, t: &Tag, search_unread: bool) -> Node { let href = if search_unread { urls::search(&format!("is:unread tag:{}", t.name), 0) @@ -1199,3 +1199,20 @@ fn reading_progress(ratio: f64) -> Node { format!("{percent}%") ] } +pub fn versions(versions: &crate::state::Version) -> Node { + info!("versions {versions:?}"); + aside![ + C!["tags-menu", "menu"], + p![C!["menu-label"], "Versions"], + ul![ + C!["menu-list"], + li!["Client"], + li![span![C!["tag-indent"], &versions.client]] + ], + versions.server.as_ref().map(|v| ul![ + C!["menu-list"], + li!["Server"], + li![span![C!["tag-indent"], v]] + ]) + ] +} diff --git a/web/src/view/tablet.rs b/web/src/view/tablet.rs index 73b32cd..e3b0b8d 100644 --- a/web/src/view/tablet.rs +++ b/web/src/view/tablet.rs @@ -3,11 +3,10 @@ use seed::{prelude::*, *}; use crate::{ graphql::show_thread_query::*, state::{Context, Model, Msg}, - view::{self, reading_progress, view_header, view_search_results, view_tags}, + view::{self, reading_progress, view_header, view_search_results}, }; pub(super) fn view(model: &Model) -> Node { - log::info!("tablet::view"); let show_icon_text = false; // Do two queries, one without `unread` so it loads fast, then a second with unread. let content = match &model.context { @@ -42,7 +41,8 @@ pub(super) fn view(model: &Model) -> Node { view_header(&model.query, &model.refreshing_state), content, view_header(&model.query, &model.refreshing_state), - view_tags(model), + view::tags(model), + view::versions(&model.versions) ] ] }