Skip to content

Commit 7543395

Browse files
committed
Add version command to proc-macro-srv
1 parent 1975c98 commit 7543395

File tree

4 files changed

+139
-18
lines changed

4 files changed

+139
-18
lines changed

src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,26 +63,33 @@ impl ProcMacroServerProcess {
6363
let mut srv = create_srv()?;
6464
tracing::info!("sending proc-macro server version check");
6565
match srv.version_check() {
66-
Ok(v) if v > version::CURRENT_API_VERSION => Err(io::Error::other(
67-
format!( "The version of the proc-macro server ({v}) in your Rust toolchain is newer than the version supported by your rust-analyzer ({}).
68-
This will prevent proc-macro expansion from working. Please consider updating your rust-analyzer to ensure compatibility with your current toolchain."
69-
,version::CURRENT_API_VERSION
70-
),
71-
)),
66+
Ok(v) if v > version::CURRENT_API_VERSION => {
67+
#[allow(clippy::disallowed_methods)]
68+
let process_version = Command::new(process_path)
69+
.arg("--version")
70+
.output()
71+
.map(|output| String::from_utf8_lossy(&output.stdout).trim().to_owned())
72+
.unwrap_or_else(|_| "unknown version".to_owned());
73+
Err(io::Error::other(format!(
74+
"Your installed proc-macro server is too new for your rust-analyzer. API version: {}, server version: {process_version}. \
75+
This will prevent proc-macro expansion from working. Please consider updating your rust-analyzer to ensure compatibility with your current toolchain.",
76+
version::CURRENT_API_VERSION
77+
)))
78+
}
7279
Ok(v) => {
7380
tracing::info!("Proc-macro server version: {v}");
7481
srv.version = v;
75-
if srv.version >= version::RUST_ANALYZER_SPAN_SUPPORT && let Ok(mode) = srv.enable_rust_analyzer_spans() {
82+
if srv.version >= version::RUST_ANALYZER_SPAN_SUPPORT
83+
&& let Ok(mode) = srv.enable_rust_analyzer_spans()
84+
{
7685
srv.protocol = Protocol::LegacyJson { mode };
7786
}
7887
tracing::info!("Proc-macro server protocol: {:?}", srv.protocol);
7988
Ok(srv)
8089
}
8190
Err(e) => {
8291
tracing::info!(%e, "proc-macro version check failed");
83-
Err(
84-
io::Error::other(format!("proc-macro server version check failed: {e}")),
85-
)
92+
Err(io::Error::other(format!("proc-macro server version check failed: {e}")))
8693
}
8794
}
8895
}
Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,49 @@
1-
//! This teaches cargo about our cfg(rust_analyzer)
1+
//! Construct version in the `commit-hash date channel` format
2+
3+
use std::{env, path::PathBuf, process::Command};
24

35
fn main() {
4-
println!("cargo:rustc-check-cfg=cfg(rust_analyzer)");
6+
set_rerun();
7+
set_commit_info();
8+
println!("cargo::rustc-check-cfg=cfg(rust_analyzer)");
9+
}
10+
11+
fn set_rerun() {
12+
println!("cargo:rerun-if-env-changed=CFG_RELEASE");
13+
14+
let mut manifest_dir = PathBuf::from(
15+
env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is always set by cargo."),
16+
);
17+
18+
while manifest_dir.parent().is_some() {
19+
let head_ref = manifest_dir.join(".git/HEAD");
20+
if head_ref.exists() {
21+
println!("cargo:rerun-if-changed={}", head_ref.display());
22+
return;
23+
}
24+
25+
manifest_dir.pop();
26+
}
27+
28+
println!("cargo:warning=Could not find `.git/HEAD` from manifest dir!");
29+
}
30+
31+
fn set_commit_info() {
32+
#[allow(clippy::disallowed_methods)]
33+
let output = match Command::new("git")
34+
.arg("log")
35+
.arg("-1")
36+
.arg("--date=short")
37+
.arg("--format=%H %h %cd")
38+
.output()
39+
{
40+
Ok(output) if output.status.success() => output,
41+
_ => return,
42+
};
43+
let stdout = String::from_utf8(output.stdout).unwrap();
44+
let mut parts = stdout.split_whitespace();
45+
let mut next = || parts.next().unwrap();
46+
println!("cargo:rustc-env=RA_COMMIT_HASH={}", next());
47+
println!("cargo:rustc-env=RA_COMMIT_SHORT_HASH={}", next());
48+
println!("cargo:rustc-env=RA_COMMIT_DATE={}", next())
549
}

src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
//! Driver for proc macro server
33
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
44
#![cfg_attr(not(feature = "sysroot-abi"), allow(unused_crate_dependencies))]
5-
#![allow(clippy::print_stderr)]
5+
#![allow(clippy::print_stdout, clippy::print_stderr)]
66

77
#[cfg(feature = "in-rust-tree")]
88
extern crate rustc_driver as _;
99

10+
mod version;
11+
1012
#[cfg(any(feature = "sysroot-abi", rust_analyzer))]
1113
mod main_loop;
1214
use clap::{Command, ValueEnum};
@@ -25,12 +27,22 @@ fn main() -> std::io::Result<()> {
2527
std::process::exit(122);
2628
}
2729
let matches = Command::new("proc-macro-srv")
28-
.args(&[clap::Arg::new("format")
29-
.long("format")
30-
.action(clap::ArgAction::Set)
31-
.default_value("json")
32-
.value_parser(clap::builder::EnumValueParser::<ProtocolFormat>::new())])
30+
.args(&[
31+
clap::Arg::new("format")
32+
.long("format")
33+
.action(clap::ArgAction::Set)
34+
.default_value("json")
35+
.value_parser(clap::builder::EnumValueParser::<ProtocolFormat>::new()),
36+
clap::Arg::new("version")
37+
.long("version")
38+
.action(clap::ArgAction::SetTrue)
39+
.help("Prints the version of the proc-macro-srv"),
40+
])
3341
.get_matches();
42+
if matches.get_flag("version") {
43+
println!("rust-analyzer-proc-macro-srv {}", version::version());
44+
return Ok(());
45+
}
3446
let &format =
3547
matches.get_one::<ProtocolFormat>("format").expect("format value should always be present");
3648
run(format)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//! Code for representing rust-analyzer's release version number.
2+
#![expect(dead_code)]
3+
4+
use std::fmt;
5+
6+
/// Information about the git repository where rust-analyzer was built from.
7+
pub(crate) struct CommitInfo {
8+
pub(crate) short_commit_hash: &'static str,
9+
pub(crate) commit_hash: &'static str,
10+
pub(crate) commit_date: &'static str,
11+
}
12+
13+
/// Cargo's version.
14+
pub(crate) struct VersionInfo {
15+
/// rust-analyzer's version, such as "1.57.0", "1.58.0-beta.1", "1.59.0-nightly", etc.
16+
pub(crate) version: &'static str,
17+
/// The release channel we were built for (stable/beta/nightly/dev).
18+
///
19+
/// `None` if not built via bootstrap.
20+
pub(crate) release_channel: Option<&'static str>,
21+
/// Information about the Git repository we may have been built from.
22+
///
23+
/// `None` if not built from a git repo.
24+
pub(crate) commit_info: Option<CommitInfo>,
25+
}
26+
27+
impl fmt::Display for VersionInfo {
28+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29+
write!(f, "{}", self.version)?;
30+
31+
if let Some(ci) = &self.commit_info {
32+
write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?;
33+
};
34+
Ok(())
35+
}
36+
}
37+
38+
/// Returns information about cargo's version.
39+
pub(crate) const fn version() -> VersionInfo {
40+
let version = match option_env!("CFG_RELEASE") {
41+
Some(x) => x,
42+
None => "0.0.0",
43+
};
44+
45+
let release_channel = option_env!("CFG_RELEASE_CHANNEL");
46+
let commit_info = match (
47+
option_env!("RA_COMMIT_SHORT_HASH"),
48+
option_env!("RA_COMMIT_HASH"),
49+
option_env!("RA_COMMIT_DATE"),
50+
) {
51+
(Some(short_commit_hash), Some(commit_hash), Some(commit_date)) => {
52+
Some(CommitInfo { short_commit_hash, commit_hash, commit_date })
53+
}
54+
_ => None,
55+
};
56+
57+
VersionInfo { version, release_channel, commit_info }
58+
}

0 commit comments

Comments
 (0)