Skip to content

Commit

Permalink
windows: Fix rust-analyzer download (#20408)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ArthurBrussee authored Nov 12, 2024
1 parent aad3ed7 commit 181c372
Showing 1 changed file with 62 additions and 18 deletions.
80 changes: 62 additions & 18 deletions crates/languages/src/rust.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
use anyhow::{anyhow, bail, Context, Result};
use anyhow::{anyhow, Context, Result};
use async_compression::futures::bufread::GzipDecoder;
use async_trait::async_trait;
use collections::HashMap;
use futures::{io::BufReader, StreamExt};
use gpui::{AppContext, AsyncAppContext};
use http_client::github::AssetKind;
use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
pub use language::*;
use lsp::{LanguageServerBinary, LanguageServerName};
use regex::Regex;
use smol::fs::{self, File};
use smol::fs::{self};
use std::{
any::Any,
borrow::Cow,
env::consts,
path::{Path, PathBuf},
sync::Arc,
sync::LazyLock,
Expand All @@ -24,8 +24,41 @@ use crate::language_settings::language_settings;

pub struct RustLspAdapter;

#[cfg(target_os = "macos")]
impl RustLspAdapter {
const GITHUB_ASSET_KIND: AssetKind = AssetKind::TarGz;
const ARCH_SERVER_NAME: &str = "apple-darwin";
}

#[cfg(target_os = "linux")]
impl RustLspAdapter {
const GITHUB_ASSET_KIND: AssetKind = AssetKind::TarGz;
const ARCH_SERVER_NAME: &str = "unknown-linux-gnu";
}

#[cfg(target_os = "windows")]
impl RustLspAdapter {
const GITHUB_ASSET_KIND: AssetKind = AssetKind::Zip;
const ARCH_SERVER_NAME: &str = "pc-windows-msvc";
}

impl RustLspAdapter {
const SERVER_NAME: LanguageServerName = LanguageServerName::new_static("rust-analyzer");

fn build_asset_name() -> String {
let extension = match Self::GITHUB_ASSET_KIND {
AssetKind::TarGz => "gz", // Nb: rust-analyzer releases use .gz not .tar.gz
AssetKind::Zip => "zip",
};

format!(
"{}-{}-{}.{}",
Self::SERVER_NAME,
std::env::consts::ARCH,
Self::ARCH_SERVER_NAME,
extension
)
}
}

#[async_trait(?Send)]
Expand Down Expand Up @@ -79,13 +112,8 @@ impl LspAdapter for RustLspAdapter {
delegate.http_client(),
)
.await?;
let os = match consts::OS {
"macos" => "apple-darwin",
"linux" => "unknown-linux-gnu",
"windows" => "pc-windows-msvc",
other => bail!("Running on unsupported os: {other}"),
};
let asset_name = format!("rust-analyzer-{}-{os}.gz", consts::ARCH);
let asset_name = Self::build_asset_name();

let asset = release
.assets
.iter()
Expand All @@ -105,31 +133,47 @@ impl LspAdapter for RustLspAdapter {
) -> Result<LanguageServerBinary> {
let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
let destination_path = container_dir.join(format!("rust-analyzer-{}", version.name));
let server_path = match Self::GITHUB_ASSET_KIND {
AssetKind::TarGz => destination_path.clone(), // Tar extracts in place.
AssetKind::Zip => destination_path.clone().join("rust-analyzer.exe"), // zip contains a .exe
};

if fs::metadata(&server_path).await.is_err() {
remove_matching(&container_dir, |entry| entry != destination_path).await;

if fs::metadata(&destination_path).await.is_err() {
let mut response = delegate
.http_client()
.get(&version.url, Default::default(), true)
.await
.map_err(|err| anyhow!("error downloading release: {}", err))?;
let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
let mut file = File::create(&destination_path).await?;
futures::io::copy(decompressed_bytes, &mut file).await?;
match Self::GITHUB_ASSET_KIND {
AssetKind::TarGz => {
let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
let archive = async_tar::Archive::new(decompressed_bytes);
archive.unpack(&destination_path).await?;
}
AssetKind::Zip => {
node_runtime::extract_zip(
&destination_path,
BufReader::new(response.body_mut()),
)
.await?;
}
};

// todo("windows")
#[cfg(not(windows))]
{
fs::set_permissions(
&destination_path,
&server_path,
<fs::Permissions as fs::unix::PermissionsExt>::from_mode(0o755),
)
.await?;
}

remove_matching(&container_dir, |entry| entry != destination_path).await;
}

Ok(LanguageServerBinary {
path: destination_path,
path: server_path,
env: None,
arguments: Default::default(),
})
Expand Down

0 comments on commit 181c372

Please sign in to comment.