Implement updating for node-based language servers (#9361)
Fixes: https://github.com/zed-industries/zed/issues/9234 This doesn't address `vue` as it has a slightly different install code, but it should be fairly simple to add - I'll add it in in a follow-up. This PR will allow all (except `vue`) node-based language servers to update. It is mostly just throwing in a method into the `NodeRuntime` trait that is used for checking if a package doesn't exist locally, or is out of date, by checking the version against what's newest, and installing. If any parsing of the `package.json` data fails along the way, it assumes something has gone awry on the users system, logs the error, and then proceeds with trying to install the package, so that users don't get stuck on version if their package has some bad data. Outside of adding this method, it just adds that check in all of the language server's individual `fetch_server_binary` methods. Release Notes: - Added updating for node-based language servers ([#9234](https://github.com/zed-industries/zed/issues/9234)).
This commit is contained in:
parent
cb16003133
commit
276139f792
19 changed files with 213 additions and 94 deletions
|
@ -19,6 +19,7 @@ async-tar.workspace = true
|
|||
async-trait.workspace = true
|
||||
futures.workspace = true
|
||||
log.workspace = true
|
||||
semver.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
smol.workspace = true
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use async_compression::futures::bufread::GzipDecoder;
|
||||
use async_tar::Archive;
|
||||
use futures::AsyncReadExt;
|
||||
use semver::Version;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
use smol::{fs, io::BufReader, lock::Mutex, process::Command};
|
||||
use std::process::{Output, Stdio};
|
||||
use std::{
|
||||
|
@ -10,6 +13,7 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
use util::http::HttpClient;
|
||||
use util::ResultExt;
|
||||
|
||||
const VERSION: &str = "v18.15.0";
|
||||
|
||||
|
@ -41,6 +45,56 @@ pub trait NodeRuntime: Send + Sync {
|
|||
|
||||
async fn npm_install_packages(&self, directory: &Path, packages: &[(&str, &str)])
|
||||
-> Result<()>;
|
||||
|
||||
async fn should_install_npm_package(
|
||||
&self,
|
||||
package_name: &str,
|
||||
local_executable_path: &Path,
|
||||
local_package_directory: &PathBuf,
|
||||
latest_version: &str,
|
||||
) -> bool {
|
||||
// In the case of the local system not having the package installed,
|
||||
// or in the instances where we fail to parse package.json data,
|
||||
// we attempt to install the package.
|
||||
if fs::metadata(local_executable_path).await.is_err() {
|
||||
return true;
|
||||
}
|
||||
|
||||
let package_json_path = local_package_directory.join("package.json");
|
||||
|
||||
let mut contents = String::new();
|
||||
|
||||
let Some(mut file) = fs::File::open(package_json_path).await.log_err() else {
|
||||
return true;
|
||||
};
|
||||
|
||||
file.read_to_string(&mut contents).await.log_err();
|
||||
|
||||
let Some(package_json): Option<Value> = serde_json::from_str(&contents).log_err() else {
|
||||
return true;
|
||||
};
|
||||
|
||||
let installed_version = package_json
|
||||
.get("dependencies")
|
||||
.and_then(|deps| deps.get(package_name))
|
||||
.and_then(|server_name| server_name.as_str());
|
||||
|
||||
let Some(installed_version) = installed_version else {
|
||||
return true;
|
||||
};
|
||||
|
||||
let Some(latest_version) = Version::parse(latest_version).log_err() else {
|
||||
return true;
|
||||
};
|
||||
|
||||
let installed_version = installed_version.trim_start_matches(|c: char| !c.is_ascii_digit());
|
||||
|
||||
let Some(installed_version) = Version::parse(installed_version).log_err() else {
|
||||
return true;
|
||||
};
|
||||
|
||||
installed_version < latest_version
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RealNodeRuntime {
|
||||
|
@ -239,6 +293,7 @@ impl NodeRuntime for RealNodeRuntime {
|
|||
|
||||
let mut arguments: Vec<_> = packages.iter().map(|p| p.as_str()).collect();
|
||||
arguments.extend_from_slice(&[
|
||||
"--save-exact",
|
||||
"--fetch-retry-mintimeout",
|
||||
"2000",
|
||||
"--fetch-retry-maxtimeout",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue