Skip to content

Commit 181c372

Browse files
windows: Fix rust-analyzer download (#20408)
After rust-lang/rust-analyzer#18412, there is no longer a .gz file for windows rust-analyzer targets, and the rust analyzer LSP fails to download. This fixes it by using the .zip version on windows. The .zip also extracts to a _folder_ containing rust-analyzer.exe rather than just a file. I've handled it in this code, but am not 100% sure if other parts of the code need too be aware of it. Release Notes: - N/A
1 parent aad3ed7 commit 181c372

File tree

1 file changed

+62
-18
lines changed

1 file changed

+62
-18
lines changed

crates/languages/src/rust.rs

+62-18
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
use anyhow::{anyhow, bail, Context, Result};
1+
use anyhow::{anyhow, Context, Result};
22
use async_compression::futures::bufread::GzipDecoder;
33
use async_trait::async_trait;
44
use collections::HashMap;
55
use futures::{io::BufReader, StreamExt};
66
use gpui::{AppContext, AsyncAppContext};
7+
use http_client::github::AssetKind;
78
use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
89
pub use language::*;
910
use lsp::{LanguageServerBinary, LanguageServerName};
1011
use regex::Regex;
11-
use smol::fs::{self, File};
12+
use smol::fs::{self};
1213
use std::{
1314
any::Any,
1415
borrow::Cow,
15-
env::consts,
1616
path::{Path, PathBuf},
1717
sync::Arc,
1818
sync::LazyLock,
@@ -24,8 +24,41 @@ use crate::language_settings::language_settings;
2424

2525
pub struct RustLspAdapter;
2626

27+
#[cfg(target_os = "macos")]
28+
impl RustLspAdapter {
29+
const GITHUB_ASSET_KIND: AssetKind = AssetKind::TarGz;
30+
const ARCH_SERVER_NAME: &str = "apple-darwin";
31+
}
32+
33+
#[cfg(target_os = "linux")]
34+
impl RustLspAdapter {
35+
const GITHUB_ASSET_KIND: AssetKind = AssetKind::TarGz;
36+
const ARCH_SERVER_NAME: &str = "unknown-linux-gnu";
37+
}
38+
39+
#[cfg(target_os = "windows")]
40+
impl RustLspAdapter {
41+
const GITHUB_ASSET_KIND: AssetKind = AssetKind::Zip;
42+
const ARCH_SERVER_NAME: &str = "pc-windows-msvc";
43+
}
44+
2745
impl RustLspAdapter {
2846
const SERVER_NAME: LanguageServerName = LanguageServerName::new_static("rust-analyzer");
47+
48+
fn build_asset_name() -> String {
49+
let extension = match Self::GITHUB_ASSET_KIND {
50+
AssetKind::TarGz => "gz", // Nb: rust-analyzer releases use .gz not .tar.gz
51+
AssetKind::Zip => "zip",
52+
};
53+
54+
format!(
55+
"{}-{}-{}.{}",
56+
Self::SERVER_NAME,
57+
std::env::consts::ARCH,
58+
Self::ARCH_SERVER_NAME,
59+
extension
60+
)
61+
}
2962
}
3063

3164
#[async_trait(?Send)]
@@ -79,13 +112,8 @@ impl LspAdapter for RustLspAdapter {
79112
delegate.http_client(),
80113
)
81114
.await?;
82-
let os = match consts::OS {
83-
"macos" => "apple-darwin",
84-
"linux" => "unknown-linux-gnu",
85-
"windows" => "pc-windows-msvc",
86-
other => bail!("Running on unsupported os: {other}"),
87-
};
88-
let asset_name = format!("rust-analyzer-{}-{os}.gz", consts::ARCH);
115+
let asset_name = Self::build_asset_name();
116+
89117
let asset = release
90118
.assets
91119
.iter()
@@ -105,31 +133,47 @@ impl LspAdapter for RustLspAdapter {
105133
) -> Result<LanguageServerBinary> {
106134
let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
107135
let destination_path = container_dir.join(format!("rust-analyzer-{}", version.name));
136+
let server_path = match Self::GITHUB_ASSET_KIND {
137+
AssetKind::TarGz => destination_path.clone(), // Tar extracts in place.
138+
AssetKind::Zip => destination_path.clone().join("rust-analyzer.exe"), // zip contains a .exe
139+
};
140+
141+
if fs::metadata(&server_path).await.is_err() {
142+
remove_matching(&container_dir, |entry| entry != destination_path).await;
108143

109-
if fs::metadata(&destination_path).await.is_err() {
110144
let mut response = delegate
111145
.http_client()
112146
.get(&version.url, Default::default(), true)
113147
.await
114148
.map_err(|err| anyhow!("error downloading release: {}", err))?;
115-
let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
116-
let mut file = File::create(&destination_path).await?;
117-
futures::io::copy(decompressed_bytes, &mut file).await?;
149+
match Self::GITHUB_ASSET_KIND {
150+
AssetKind::TarGz => {
151+
let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
152+
let archive = async_tar::Archive::new(decompressed_bytes);
153+
archive.unpack(&destination_path).await?;
154+
}
155+
AssetKind::Zip => {
156+
node_runtime::extract_zip(
157+
&destination_path,
158+
BufReader::new(response.body_mut()),
159+
)
160+
.await?;
161+
}
162+
};
163+
118164
// todo("windows")
119165
#[cfg(not(windows))]
120166
{
121167
fs::set_permissions(
122-
&destination_path,
168+
&server_path,
123169
<fs::Permissions as fs::unix::PermissionsExt>::from_mode(0o755),
124170
)
125171
.await?;
126172
}
127-
128-
remove_matching(&container_dir, |entry| entry != destination_path).await;
129173
}
130174

131175
Ok(LanguageServerBinary {
132-
path: destination_path,
176+
path: server_path,
133177
env: None,
134178
arguments: Default::default(),
135179
})

0 commit comments

Comments
 (0)