diff --git a/crates/rust-analyzer/build.rs b/crates/rust-analyzer/build.rs index 99780343fd..292a7ad70a 100644 --- a/crates/rust-analyzer/build.rs +++ b/crates/rust-analyzer/build.rs @@ -4,11 +4,14 @@ use std::{env, path::PathBuf, process::Command}; fn main() { set_rerun(); - println!("cargo:rustc-env=REV={}", rev()); + set_commit_info(); + if option_env!("CFG_RELEASE").is_none() { + println!("cargo:rustc-env=POKE_RA_DEVS=1"); + } } fn set_rerun() { - println!("cargo:rerun-if-env-changed=RUST_ANALYZER_REV"); + println!("cargo:rerun-if-env-changed=CFG_RELEASE"); let mut manifest_dir = PathBuf::from( env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is always set by cargo."), @@ -27,47 +30,21 @@ fn set_rerun() { println!("cargo:warning=Could not find `.git/HEAD` from manifest dir!"); } -fn rev() -> String { - if let Ok(rev) = env::var("RUST_ANALYZER_REV") { - return rev; - } - - if let Some(commit_hash) = commit_hash() { - let mut buf = commit_hash; - - if let Some(date) = build_date() { - buf.push(' '); - buf.push_str(&date); - } - - let channel = env::var("RUST_ANALYZER_CHANNEL").unwrap_or_else(|_| "dev".to_string()); - buf.push(' '); - buf.push_str(&channel); - - return buf; - } - - "???????".to_string() -} - -fn commit_hash() -> Option { - exec("git rev-parse --short HEAD").ok() -} - -fn build_date() -> Option { - exec("date -u +%Y-%m-%d").ok() -} - -fn exec(command: &str) -> std::io::Result { - let args = command.split_ascii_whitespace().collect::>(); - let output = Command::new(args[0]).args(&args[1..]).output()?; - if !output.status.success() { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("command {:?} returned non-zero code", command,), - )); - } - let stdout = String::from_utf8(output.stdout) - .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?; - Ok(stdout.trim().to_string()) +fn set_commit_info() { + let output = match Command::new("git") + .arg("log") + .arg("-1") + .arg("--date=short") + .arg("--format=%H %h %cd") + .output() + { + Ok(output) if output.status.success() => output, + _ => return, + }; + let stdout = String::from_utf8(output.stdout).unwrap(); + let mut parts = stdout.split_whitespace(); + let mut next = || parts.next().unwrap(); + println!("cargo:rustc-env=RA_COMMIT_HASH={}", next()); + println!("cargo:rustc-env=RA_COMMIT_SHORT_HASH={}", next()); + println!("cargo:rustc-env=RA_COMMIT_DATE={}", next()) } diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 4787786cac..45a3a23554 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -70,7 +70,7 @@ fn try_main() -> Result<()> { return Ok(()); } if cmd.version { - println!("rust-analyzer {}", env!("REV")); + println!("rust-analyzer {}", rust_analyzer::version()); return Ok(()); } if cmd.help { @@ -148,7 +148,7 @@ fn with_extra_thread( } fn run_server() -> Result<()> { - tracing::info!("server version {} will start", env!("REV")); + tracing::info!("server version {} will start", rust_analyzer::version()); let (connection, io_threads) = Connection::stdio(); @@ -190,7 +190,7 @@ fn run_server() -> Result<()> { capabilities: server_capabilities, server_info: Some(lsp_types::ServerInfo { name: String::from("rust-analyzer"), - version: Some(String::from(env!("REV"))), + version: Some(rust_analyzer::version().to_string()), }), offset_encoding: if supports_utf8(config.caps()) { Some("utf-8".to_string()) diff --git a/crates/rust-analyzer/src/cli/lsif.rs b/crates/rust-analyzer/src/cli/lsif.rs index 5e6d286987..491c55a04f 100644 --- a/crates/rust-analyzer/src/cli/lsif.rs +++ b/crates/rust-analyzer/src/cli/lsif.rs @@ -22,6 +22,7 @@ use crate::cli::{ }; use crate::line_index::{LineEndings, LineIndex, OffsetEncoding}; use crate::to_proto; +use crate::version::version; /// Need to wrap Snapshot to provide `Clone` impl for `map_with` struct Snap(DB); @@ -312,7 +313,7 @@ impl flags::Lsif { tool_info: Some(lsp_types::lsif::ToolInfo { name: "rust-analyzer".to_string(), args: vec![], - version: Some(env!("REV").to_string()), + version: Some(version().to_string()), }), })); for file in si.files { diff --git a/crates/rust-analyzer/src/dispatch.rs b/crates/rust-analyzer/src/dispatch.rs index 4d94630a56..f16559148e 100644 --- a/crates/rust-analyzer/src/dispatch.rs +++ b/crates/rust-analyzer/src/dispatch.rs @@ -8,6 +8,7 @@ use serde::{de::DeserializeOwned, Serialize}; use crate::{ global_state::{GlobalState, GlobalStateSnapshot}, main_loop::Task, + version::version, LspError, Result, }; @@ -144,7 +145,7 @@ impl<'a> RequestDispatcher<'a> { match res { Ok(params) => { let panic_context = - format!("\nversion: {}\nrequest: {} {:#?}", env!("REV"), R::METHOD, params); + format!("\nversion: {}\nrequest: {} {:#?}", version(), R::METHOD, params); Some((req, params, panic_context)) } Err(err) => { @@ -248,7 +249,7 @@ impl<'a> NotificationDispatcher<'a> { }; let _pctx = stdx::panic_context::enter(format!( "\nversion: {}\nnotification: {}", - env!("REV"), + version(), N::METHOD )); f(self.global_state, params)?; diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index d5bc8f65f8..e04df7dea4 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -16,26 +16,28 @@ macro_rules! eprintln { ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; } -mod global_state; -mod reload; -mod main_loop; -mod dispatch; -mod handlers; mod caps; mod cargo_target_spec; -mod to_proto; -mod from_proto; -mod semantic_tokens; -mod markdown; mod diagnostics; +mod diff; +mod dispatch; +mod from_proto; +mod global_state; +mod handlers; mod line_index; mod lsp_utils; -mod task_pool; +mod main_loop; +mod markdown; mod mem_docs; -mod diff; mod op_queue; -pub mod lsp_ext; +mod reload; +mod semantic_tokens; +mod task_pool; +mod to_proto; +mod version; + pub mod config; +pub mod lsp_ext; #[cfg(test)] mod integrated_benchmarks; @@ -44,7 +46,7 @@ use std::fmt; use serde::de::DeserializeOwned; -pub use crate::{caps::server_capabilities, main_loop::main_loop}; +pub use crate::{caps::server_capabilities, main_loop::main_loop, version::version}; pub type Error = Box; pub type Result = std::result::Result; diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index 22bab8fa82..5a37cbe2e3 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs @@ -74,7 +74,7 @@ impl GlobalState { /// panicky is a good idea, let's see if we can keep our awesome bleeding /// edge users from being upset! pub(crate) fn poke_rust_analyzer_developer(&mut self, message: String) { - let from_source_build = env!("REV").contains("dev"); + let from_source_build = option_env!("POKE_RA_DEVS").is_some(); let profiling_enabled = std::env::var("RA_PROFILE").is_ok(); if from_source_build || profiling_enabled { self.show_message(lsp_types::MessageType::ERROR, message) diff --git a/crates/rust-analyzer/src/version.rs b/crates/rust-analyzer/src/version.rs new file mode 100644 index 0000000000..1e829299e6 --- /dev/null +++ b/crates/rust-analyzer/src/version.rs @@ -0,0 +1,57 @@ +//! Code for representing rust-analyzer's release version number. + +use std::fmt; + +/// Information about the git repository where rust-analyzer was built from. +pub struct CommitInfo { + pub short_commit_hash: &'static str, + pub commit_hash: &'static str, + pub commit_date: &'static str, +} + +/// Cargo's version. +pub struct VersionInfo { + /// rust-analyzer's version, such as "1.57.0", "1.58.0-beta.1", "1.59.0-nightly", etc. + pub version: &'static str, + /// The release channel we were built for (stable/beta/nightly/dev). + /// + /// `None` if not built via rustbuild. + pub release_channel: Option<&'static str>, + /// Information about the Git repository we may have been built from. + /// + /// `None` if not built from a git repo. + pub commit_info: Option, +} + +impl fmt::Display for VersionInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.version)?; + + if let Some(ci) = &self.commit_info { + write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?; + }; + Ok(()) + } +} + +/// Returns information about cargo's version. +pub const fn version() -> VersionInfo { + let version = match option_env!("CFG_RELEASE") { + Some(x) => x, + None => "0.0.0", + }; + + let release_channel = option_env!("CFG_RELEASE_CHANNEL"); + let commit_info = match ( + option_env!("RA_COMMIT_SHORT_HASH"), + option_env!("RA_COMMIT_HASH"), + option_env!("RA_COMMIT_DATE"), + ) { + (Some(short_commit_hash), Some(commit_hash), Some(commit_date)) => { + Some(CommitInfo { short_commit_hash, commit_hash, commit_date }) + } + _ => None, + }; + + VersionInfo { version, release_channel, commit_info } +} diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs index 2ea452377e..c82867d3b4 100644 --- a/xtask/src/dist.rs +++ b/xtask/src/dist.rs @@ -72,7 +72,8 @@ fn dist_client( } fn dist_server(sh: &Shell, release_channel: &str, target: &Target) -> anyhow::Result<()> { - let _e = sh.push_env("RUST_ANALYZER_CHANNEL", release_channel); + let _e = sh.push_env("CFG_RELEASE_CHANNEL", release_channel); + let _e = sh.push_env("CFG_RELEASE", "0.0.0"); let _e = sh.push_env("CARGO_PROFILE_RELEASE_LTO", "thin"); // Uncomment to enable debug info for releases. Note that: