windows: Fix rust-analyzer download (#20408)
After https://github.com/rust-lang/rust-analyzer/pull/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
This commit is contained in:
parent
aad3ed7f91
commit
181c3724aa
1 changed files with 62 additions and 18 deletions
|
@ -1,18 +1,18 @@
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use async_compression::futures::bufread::GzipDecoder;
|
use async_compression::futures::bufread::GzipDecoder;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use futures::{io::BufReader, StreamExt};
|
use futures::{io::BufReader, StreamExt};
|
||||||
use gpui::{AppContext, AsyncAppContext};
|
use gpui::{AppContext, AsyncAppContext};
|
||||||
|
use http_client::github::AssetKind;
|
||||||
use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
|
use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
|
||||||
pub use language::*;
|
pub use language::*;
|
||||||
use lsp::{LanguageServerBinary, LanguageServerName};
|
use lsp::{LanguageServerBinary, LanguageServerName};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use smol::fs::{self, File};
|
use smol::fs::{self};
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
env::consts,
|
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
sync::LazyLock,
|
sync::LazyLock,
|
||||||
|
@ -24,8 +24,41 @@ use crate::language_settings::language_settings;
|
||||||
|
|
||||||
pub struct RustLspAdapter;
|
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 {
|
impl RustLspAdapter {
|
||||||
const SERVER_NAME: LanguageServerName = LanguageServerName::new_static("rust-analyzer");
|
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)]
|
#[async_trait(?Send)]
|
||||||
|
@ -79,13 +112,8 @@ impl LspAdapter for RustLspAdapter {
|
||||||
delegate.http_client(),
|
delegate.http_client(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let os = match consts::OS {
|
let asset_name = Self::build_asset_name();
|
||||||
"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 = release
|
let asset = release
|
||||||
.assets
|
.assets
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -105,31 +133,47 @@ impl LspAdapter for RustLspAdapter {
|
||||||
) -> Result<LanguageServerBinary> {
|
) -> Result<LanguageServerBinary> {
|
||||||
let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
|
let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
|
||||||
let destination_path = container_dir.join(format!("rust-analyzer-{}", version.name));
|
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
|
let mut response = delegate
|
||||||
.http_client()
|
.http_client()
|
||||||
.get(&version.url, Default::default(), true)
|
.get(&version.url, Default::default(), true)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| anyhow!("error downloading release: {}", err))?;
|
.map_err(|err| anyhow!("error downloading release: {}", err))?;
|
||||||
|
match Self::GITHUB_ASSET_KIND {
|
||||||
|
AssetKind::TarGz => {
|
||||||
let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
|
let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
|
||||||
let mut file = File::create(&destination_path).await?;
|
let archive = async_tar::Archive::new(decompressed_bytes);
|
||||||
futures::io::copy(decompressed_bytes, &mut file).await?;
|
archive.unpack(&destination_path).await?;
|
||||||
|
}
|
||||||
|
AssetKind::Zip => {
|
||||||
|
node_runtime::extract_zip(
|
||||||
|
&destination_path,
|
||||||
|
BufReader::new(response.body_mut()),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// todo("windows")
|
// todo("windows")
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
{
|
{
|
||||||
fs::set_permissions(
|
fs::set_permissions(
|
||||||
&destination_path,
|
&server_path,
|
||||||
<fs::Permissions as fs::unix::PermissionsExt>::from_mode(0o755),
|
<fs::Permissions as fs::unix::PermissionsExt>::from_mode(0o755),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_matching(&container_dir, |entry| entry != destination_path).await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(LanguageServerBinary {
|
Ok(LanguageServerBinary {
|
||||||
path: destination_path,
|
path: server_path,
|
||||||
env: None,
|
env: None,
|
||||||
arguments: Default::default(),
|
arguments: Default::default(),
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue