diff --git a/Cargo.lock b/Cargo.lock index f4b658b..3bddacd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -187,6 +187,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] @@ -299,6 +301,26 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const_format" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -723,6 +745,19 @@ dependencies = [ "wasip2", ] +[[package]] +name = "git2" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "url", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -956,6 +991,16 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + [[package]] name = "js-sys" version = "0.3.82" @@ -992,6 +1037,18 @@ version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +[[package]] +name = "libgit2-sys" +version = "0.18.2+1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + [[package]] name = "libm" version = "0.2.15" @@ -1019,6 +1076,18 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "libz-sys" +version = "1.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15d118bbf3771060e7311cc7bb0545b01d08a8b4a7de949198dec1fa0ca1c0f7" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -1092,9 +1161,11 @@ dependencies = [ "clap", "clap-verbosity-flag", "clap_complete", + "const_format", "derive_more", "dialoguer", "futures-util", + "git2", "indoc", "itertools", "landlock", diff --git a/Cargo.toml b/Cargo.toml index 6c65c43..0ad5f76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,9 +20,10 @@ autolib = false anyhow = "1.0.100" async-bincode = "0.8.0" bincode = "2.0.1" -clap = { version = "4.5.53", features = ["derive"] } +clap = { version = "4.5.53", features = ["cargo", "derive"] } clap-verbosity-flag = { version = "3.0.4", features = [ "tracing" ] } clap_complete = { version = "4.5.61", features = ["unstable-dynamic"] } +const_format = "0.2.35" derive_more = { version = "2.0.1", features = ["display", "error"] } dialoguer = "0.12.0" futures-util = "0.3.31" @@ -66,6 +67,7 @@ codegen-units = 1 [build-dependencies] anyhow = "1.0.100" +git2 = { version = "0.20.2", default-features = false } [dev-dependencies] regex = "1.12.2" diff --git a/build.rs b/build.rs index 68bd5fa..bbb4fb5 100644 --- a/build.rs +++ b/build.rs @@ -3,6 +3,30 @@ use anyhow::anyhow; #[cfg(feature = "mysql-admutils-compatibility")] use std::{env, os::unix::fs::symlink, path::PathBuf}; +fn get_git_commit() -> Option { + let repo = git2::Repository::discover(".").ok()?; + let head = repo.head().ok()?; + let commit = head.peel_to_commit().ok()?; + Some(commit.id().to_string()) +} + +fn embed_build_time_info() { + let commit = option_env!("GIT_COMMIT") + .map(|s| s.to_string()) + .or_else(get_git_commit) + .unwrap_or_else(|| "unknown".to_string()); + + let build_profile = std::env::var("OUT_DIR") + .unwrap_or_else(|_| "unknown".to_string()) + .split(std::path::MAIN_SEPARATOR) + .nth_back(3) + .unwrap_or("unknown") + .to_string(); + + println!("cargo:rustc-env=GIT_COMMIT={}", commit); + println!("cargo:rustc-env=BUILD_PROFILE={}", build_profile); +} + fn generate_mysql_admutils_symlinks() -> anyhow::Result<()> { // NOTE: This is slightly illegal, and depends on implementation details. // But it is only here for ease of testing the compatibility layer, @@ -42,5 +66,7 @@ fn main() -> anyhow::Result<()> { #[cfg(feature = "mysql-admutils-compatibility")] generate_mysql_admutils_symlinks()?; + embed_build_time_info(); + Ok(()) } diff --git a/src/main.rs b/src/main.rs index 7a1eb23..bf6803a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ extern crate prettytable; use anyhow::Context; -use clap::{CommandFactory, Parser, ValueEnum}; +use clap::{CommandFactory, Parser, ValueEnum, crate_version}; use clap_complete::{CompleteEnv, Shell, generate}; use clap_verbosity_flag::{InfoLevel, Verbosity}; @@ -30,6 +30,38 @@ mod server; mod client; mod core; +const fn long_version() -> &'static str { + macro_rules! feature { + ($title:expr, $flag:expr) => { + if cfg!(feature = $flag) { + concat!($title, ": enabled") + } else { + concat!($title, ": disabled") + } + }; + } + const_format::concatcp!( + crate_version!(), + "\n", + "build profile: ", + env!("BUILD_PROFILE"), + "\n", + "commit: ", + env!("GIT_COMMIT"), + "\n\n", + "[features]\n", + feature!("SUID/SGID mode", "suid-sgid-mode"), + "\n", + feature!( + "mysql-admutils compatibility", + "mysql-admutils-compatibility" + ), + "\n", + ) +} + +const LONG_VERSION: &str = long_version(); + /// Database administration tool for non-admin users to manage their own MySQL databases and users. /// /// This tool allows you to manage users and databases in MySQL. @@ -45,6 +77,7 @@ mod core; disable_help_subcommand = true, before_long_help = ASCII_BANNER, after_long_help = KIND_REGARDS, + long_version = LONG_VERSION, )] struct Args { #[command(subcommand)] @@ -73,7 +106,7 @@ struct Args { config: Option, #[command(flatten)] - verbose: Verbosity + verbose: Verbosity, } #[derive(Parser, Debug, Clone)]