Route some more information for reinstall after startup failure
Doesn't actually reinstall on that particular failure due to wrong variant in hashmap
This commit is contained in:
parent
abe5ecc5ec
commit
da2ee55013
3 changed files with 125 additions and 78 deletions
|
@ -141,7 +141,7 @@ impl CachedLspAdapter {
|
||||||
self.adapter.cached_server_binary(container_dir).await
|
self.adapter.cached_server_binary(container_dir).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn installation_test_binary(
|
pub async fn installation_test_binary(
|
||||||
&self,
|
&self,
|
||||||
container_dir: PathBuf,
|
container_dir: PathBuf,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
|
@ -544,6 +544,7 @@ struct LanguageRegistryState {
|
||||||
pub struct PendingLanguageServer {
|
pub struct PendingLanguageServer {
|
||||||
pub server_id: LanguageServerId,
|
pub server_id: LanguageServerId,
|
||||||
pub task: Task<Result<lsp::LanguageServer>>,
|
pub task: Task<Result<lsp::LanguageServer>>,
|
||||||
|
pub container_dir: Option<Arc<Path>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LanguageRegistry {
|
impl LanguageRegistry {
|
||||||
|
@ -824,8 +825,8 @@ impl LanguageRegistry {
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Option<PendingLanguageServer> {
|
) -> Option<PendingLanguageServer> {
|
||||||
let server_id = self.state.write().next_language_server_id();
|
let server_id = self.state.write().next_language_server_id();
|
||||||
log::info!(
|
println!(
|
||||||
"starting language server name:{}, path:{root_path:?}, id:{server_id}",
|
"starting language server {:?}, path: {root_path:?}, id: {server_id}",
|
||||||
adapter.name.0
|
adapter.name.0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -858,7 +859,11 @@ impl LanguageRegistry {
|
||||||
Ok(server)
|
Ok(server)
|
||||||
});
|
});
|
||||||
|
|
||||||
return Some(PendingLanguageServer { server_id, task });
|
return Some(PendingLanguageServer {
|
||||||
|
server_id,
|
||||||
|
task,
|
||||||
|
container_dir: None,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let download_dir = self
|
let download_dir = self
|
||||||
|
@ -869,24 +874,26 @@ impl LanguageRegistry {
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
let language = language.clone();
|
let language = language.clone();
|
||||||
let http_client = http_client.clone();
|
let http_client = http_client.clone();
|
||||||
let download_dir = download_dir.clone();
|
let container_dir: Arc<Path> = Arc::from(download_dir.join(adapter.name.0.as_ref()));
|
||||||
let root_path = root_path.clone();
|
let root_path = root_path.clone();
|
||||||
let adapter = adapter.clone();
|
let adapter = adapter.clone();
|
||||||
let lsp_binary_statuses = self.lsp_binary_statuses_tx.clone();
|
let lsp_binary_statuses = self.lsp_binary_statuses_tx.clone();
|
||||||
let login_shell_env_loaded = self.login_shell_env_loaded.clone();
|
let login_shell_env_loaded = self.login_shell_env_loaded.clone();
|
||||||
|
|
||||||
let task = cx.spawn(|cx| async move {
|
let task = {
|
||||||
|
let container_dir = container_dir.clone();
|
||||||
|
cx.spawn(|cx| async move {
|
||||||
login_shell_env_loaded.await;
|
login_shell_env_loaded.await;
|
||||||
|
|
||||||
let mut lock = this.lsp_binary_paths.lock();
|
let mut lock = this.lsp_binary_paths.lock();
|
||||||
let entry = lock
|
let entry = lock
|
||||||
.entry(adapter.name.clone())
|
.entry(adapter.name.clone())
|
||||||
.or_insert_with(|| {
|
.or_insert_with(|| {
|
||||||
get_binary(
|
get_binaries(
|
||||||
adapter.clone(),
|
adapter.clone(),
|
||||||
language.clone(),
|
language.clone(),
|
||||||
http_client,
|
http_client,
|
||||||
download_dir,
|
container_dir,
|
||||||
lsp_binary_statuses,
|
lsp_binary_statuses,
|
||||||
)
|
)
|
||||||
.map_err(Arc::new)
|
.map_err(Arc::new)
|
||||||
|
@ -896,19 +903,25 @@ impl LanguageRegistry {
|
||||||
.clone();
|
.clone();
|
||||||
drop(lock);
|
drop(lock);
|
||||||
|
|
||||||
let binary = entry.clone().map_err(|e| anyhow!(e)).await?;
|
let binaries = entry.clone().map_err(|e| anyhow!(e)).await?;
|
||||||
|
println!("starting server");
|
||||||
let server = lsp::LanguageServer::new(
|
let server = lsp::LanguageServer::new(
|
||||||
server_id,
|
server_id,
|
||||||
binary,
|
binaries,
|
||||||
&root_path,
|
&root_path,
|
||||||
adapter.code_action_kinds(),
|
adapter.code_action_kinds(),
|
||||||
cx,
|
cx,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(server)
|
Ok(server)
|
||||||
});
|
})
|
||||||
|
};
|
||||||
|
|
||||||
Some(PendingLanguageServer { server_id, task })
|
Some(PendingLanguageServer {
|
||||||
|
server_id,
|
||||||
|
task,
|
||||||
|
container_dir: Some(container_dir),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn language_server_binary_statuses(
|
pub fn language_server_binary_statuses(
|
||||||
|
@ -922,6 +935,7 @@ impl LanguageRegistry {
|
||||||
adapter: Arc<CachedLspAdapter>,
|
adapter: Arc<CachedLspAdapter>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Task<()> {
|
) -> Task<()> {
|
||||||
|
println!("deleting server container");
|
||||||
let mut lock = self.lsp_binary_paths.lock();
|
let mut lock = self.lsp_binary_paths.lock();
|
||||||
lock.remove(&adapter.name);
|
lock.remove(&adapter.name);
|
||||||
|
|
||||||
|
@ -984,20 +998,20 @@ impl Default for LanguageRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_binary(
|
async fn get_binaries(
|
||||||
adapter: Arc<CachedLspAdapter>,
|
adapter: Arc<CachedLspAdapter>,
|
||||||
language: Arc<Language>,
|
language: Arc<Language>,
|
||||||
http_client: Arc<dyn HttpClient>,
|
http_client: Arc<dyn HttpClient>,
|
||||||
download_dir: Arc<Path>,
|
container_dir: Arc<Path>,
|
||||||
statuses: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
|
statuses: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
|
||||||
) -> Result<LanguageServerBinaries> {
|
) -> Result<LanguageServerBinaries> {
|
||||||
let container_dir = download_dir.join(adapter.name.0.as_ref());
|
|
||||||
if !container_dir.exists() {
|
if !container_dir.exists() {
|
||||||
smol::fs::create_dir_all(&container_dir)
|
smol::fs::create_dir_all(&container_dir)
|
||||||
.await
|
.await
|
||||||
.context("failed to create container directory")?;
|
.context("failed to create container directory")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println!("fetching binary");
|
||||||
let binary = fetch_latest_binary(
|
let binary = fetch_latest_binary(
|
||||||
adapter.clone(),
|
adapter.clone(),
|
||||||
language.clone(),
|
language.clone(),
|
||||||
|
@ -1008,11 +1022,16 @@ async fn get_binary(
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
if let Err(error) = binary.as_ref() {
|
if let Err(error) = binary.as_ref() {
|
||||||
if let Some(binary) = adapter.cached_server_binary(container_dir.clone()).await {
|
if let Some(binary) = adapter
|
||||||
|
.cached_server_binary(container_dir.to_path_buf())
|
||||||
|
.await
|
||||||
|
{
|
||||||
statuses
|
statuses
|
||||||
.broadcast((language.clone(), LanguageServerBinaryStatus::Cached))
|
.broadcast((language.clone(), LanguageServerBinaryStatus::Cached))
|
||||||
.await?;
|
.await?;
|
||||||
let installation_test_binary = adapter.installation_test_binary(container_dir).await;
|
let installation_test_binary = adapter
|
||||||
|
.installation_test_binary(container_dir.to_path_buf())
|
||||||
|
.await;
|
||||||
return Ok(LanguageServerBinaries {
|
return Ok(LanguageServerBinaries {
|
||||||
binary,
|
binary,
|
||||||
installation_test_binary,
|
installation_test_binary,
|
||||||
|
|
|
@ -65,7 +65,7 @@ pub struct LanguageServer {
|
||||||
output_done_rx: Mutex<Option<barrier::Receiver>>,
|
output_done_rx: Mutex<Option<barrier::Receiver>>,
|
||||||
root_path: PathBuf,
|
root_path: PathBuf,
|
||||||
server: Option<Mutex<Child>>,
|
server: Option<Mutex<Child>>,
|
||||||
test_installation_binary: Option<LanguageServerBinary>,
|
installation_test_binary: Option<LanguageServerBinary>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -190,7 +190,7 @@ impl LanguageServer {
|
||||||
stdin: Stdin,
|
stdin: Stdin,
|
||||||
stdout: Stdout,
|
stdout: Stdout,
|
||||||
server: Option<Child>,
|
server: Option<Child>,
|
||||||
test_installation_binary: Option<LanguageServerBinary>,
|
installation_test_binary: Option<LanguageServerBinary>,
|
||||||
root_path: &Path,
|
root_path: &Path,
|
||||||
code_action_kinds: Option<Vec<CodeActionKind>>,
|
code_action_kinds: Option<Vec<CodeActionKind>>,
|
||||||
cx: AsyncAppContext,
|
cx: AsyncAppContext,
|
||||||
|
@ -245,7 +245,7 @@ impl LanguageServer {
|
||||||
output_done_rx: Mutex::new(Some(output_done_rx)),
|
output_done_rx: Mutex::new(Some(output_done_rx)),
|
||||||
root_path: root_path.to_path_buf(),
|
root_path: root_path.to_path_buf(),
|
||||||
server: server.map(|server| Mutex::new(server)),
|
server: server.map(|server| Mutex::new(server)),
|
||||||
test_installation_binary,
|
installation_test_binary,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,8 +262,8 @@ impl LanguageServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_installation_binary(&self) -> &Option<LanguageServerBinary> {
|
pub fn installation_test_binary(&self) -> &Option<LanguageServerBinary> {
|
||||||
&self.test_installation_binary
|
&self.installation_test_binary
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
|
pub fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
|
||||||
|
|
|
@ -45,7 +45,7 @@ use language::{
|
||||||
use log::error;
|
use log::error;
|
||||||
use lsp::{
|
use lsp::{
|
||||||
DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions,
|
DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions,
|
||||||
DocumentHighlightKind, LanguageServer, LanguageServerId, OneOf,
|
DocumentHighlightKind, LanguageServer, LanguageServerBinary, LanguageServerId, OneOf,
|
||||||
};
|
};
|
||||||
use lsp_command::*;
|
use lsp_command::*;
|
||||||
use postage::watch;
|
use postage::watch;
|
||||||
|
@ -2442,22 +2442,23 @@ impl Project {
|
||||||
}
|
}
|
||||||
|
|
||||||
let server_id = pending_server.server_id;
|
let server_id = pending_server.server_id;
|
||||||
|
let container_dir = pending_server.container_dir.clone();
|
||||||
let state = LanguageServerState::Starting({
|
let state = LanguageServerState::Starting({
|
||||||
let server_name = adapter.name.0.clone();
|
let server_name = adapter.name.0.clone();
|
||||||
let languages = self.languages.clone();
|
let languages = self.languages.clone();
|
||||||
let key = key.clone();
|
let key = key.clone();
|
||||||
|
|
||||||
cx.spawn_weak(|this, cx| async move {
|
cx.spawn_weak(|this, mut cx| async move {
|
||||||
let result = Self::setup_and_insert_language_server(
|
let result = Self::setup_and_insert_language_server(
|
||||||
this,
|
this,
|
||||||
initialization_options,
|
initialization_options,
|
||||||
pending_server,
|
pending_server,
|
||||||
adapter,
|
adapter.clone(),
|
||||||
languages,
|
languages,
|
||||||
language,
|
language,
|
||||||
server_id,
|
server_id,
|
||||||
key,
|
key,
|
||||||
cx,
|
&mut cx,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -2465,8 +2466,24 @@ impl Project {
|
||||||
Ok(server) => Some(server),
|
Ok(server) => Some(server),
|
||||||
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Error starting language server {:?}: {}", server_name, err);
|
println!("failed to start language server {:?}: {}", server_name, err);
|
||||||
// TODO: Prompt installation validity check LSP ERROR
|
|
||||||
|
if let Some(this) = this.upgrade(&cx) {
|
||||||
|
if let Some(container_dir) = container_dir {
|
||||||
|
let installation_test_binary = adapter
|
||||||
|
.installation_test_binary(container_dir.to_path_buf())
|
||||||
|
.await;
|
||||||
|
|
||||||
|
this.update(&mut cx, |_, cx| {
|
||||||
|
Self::check_errored_server_id(
|
||||||
|
server_id,
|
||||||
|
installation_test_binary,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2482,6 +2499,7 @@ impl Project {
|
||||||
server_id: LanguageServerId,
|
server_id: LanguageServerId,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Option<Task<()>> {
|
) -> Option<Task<()>> {
|
||||||
|
println!("starting to reinstall server");
|
||||||
let (adapter, language, server) = match self.language_servers.remove(&server_id) {
|
let (adapter, language, server) = match self.language_servers.remove(&server_id) {
|
||||||
Some(LanguageServerState::Running {
|
Some(LanguageServerState::Running {
|
||||||
adapter,
|
adapter,
|
||||||
|
@ -2495,6 +2513,7 @@ impl Project {
|
||||||
|
|
||||||
Some(cx.spawn(move |this, mut cx| async move {
|
Some(cx.spawn(move |this, mut cx| async move {
|
||||||
if let Some(task) = server.shutdown() {
|
if let Some(task) = server.shutdown() {
|
||||||
|
println!("shutting down existing server");
|
||||||
task.await;
|
task.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2516,6 +2535,7 @@ impl Project {
|
||||||
let worktree_id = worktree.id();
|
let worktree_id = worktree.id();
|
||||||
let root_path = worktree.abs_path();
|
let root_path = worktree.abs_path();
|
||||||
|
|
||||||
|
println!("prompting server start: {:?}", &adapter.name.0);
|
||||||
this.start_language_server(
|
this.start_language_server(
|
||||||
worktree_id,
|
worktree_id,
|
||||||
root_path,
|
root_path,
|
||||||
|
@ -2537,7 +2557,7 @@ impl Project {
|
||||||
language: Arc<Language>,
|
language: Arc<Language>,
|
||||||
server_id: LanguageServerId,
|
server_id: LanguageServerId,
|
||||||
key: (WorktreeId, LanguageServerName),
|
key: (WorktreeId, LanguageServerName),
|
||||||
mut cx: AsyncAppContext,
|
cx: &mut AsyncAppContext,
|
||||||
) -> Result<Arc<LanguageServer>> {
|
) -> Result<Arc<LanguageServer>> {
|
||||||
let language_server = Self::setup_pending_language_server(
|
let language_server = Self::setup_pending_language_server(
|
||||||
this,
|
this,
|
||||||
|
@ -2546,16 +2566,16 @@ impl Project {
|
||||||
adapter.clone(),
|
adapter.clone(),
|
||||||
languages,
|
languages,
|
||||||
server_id,
|
server_id,
|
||||||
&mut cx,
|
cx,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let this = match this.upgrade(&mut cx) {
|
let this = match this.upgrade(cx) {
|
||||||
Some(this) => this,
|
Some(this) => this,
|
||||||
None => return Err(anyhow!("failed to upgrade project handle")),
|
None => return Err(anyhow!("failed to upgrade project handle")),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
this.insert_newly_running_language_server(
|
this.insert_newly_running_language_server(
|
||||||
language,
|
language,
|
||||||
adapter,
|
adapter,
|
||||||
|
@ -3012,25 +3032,32 @@ impl Project {
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_errored_lsp_installation(
|
fn check_errored_language_server(
|
||||||
&self,
|
&self,
|
||||||
language_server: Arc<LanguageServer>,
|
language_server: Arc<LanguageServer>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) {
|
) {
|
||||||
cx.spawn(|this, mut cx| async move {
|
|
||||||
if !language_server.is_dead() {
|
if !language_server.is_dead() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let server_id = language_server.server_id();
|
|
||||||
|
|
||||||
|
let server_id = language_server.server_id();
|
||||||
|
let installation_test_binary = language_server.installation_test_binary().clone();
|
||||||
|
Self::check_errored_server_id(server_id, installation_test_binary, cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_errored_server_id(
|
||||||
|
server_id: LanguageServerId,
|
||||||
|
installation_test_binary: Option<LanguageServerBinary>,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) {
|
||||||
|
cx.spawn(|this, mut cx| async move {
|
||||||
|
println!("About to spawn test binary");
|
||||||
// A lack of test binary counts as a failure
|
// A lack of test binary counts as a failure
|
||||||
let process = language_server
|
let process = installation_test_binary.and_then(|binary| {
|
||||||
.test_installation_binary()
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|binary| {
|
|
||||||
smol::process::Command::new(&binary.path)
|
smol::process::Command::new(&binary.path)
|
||||||
.current_dir(&binary.path)
|
.current_dir(&binary.path)
|
||||||
.args(&binary.arguments)
|
.args(binary.arguments)
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::inherit())
|
.stderr(Stdio::inherit())
|
||||||
|
@ -3046,13 +3073,14 @@ impl Project {
|
||||||
if let Some(mut process) = process {
|
if let Some(mut process) = process {
|
||||||
futures::select! {
|
futures::select! {
|
||||||
status = process.status().fuse() => match status {
|
status = process.status().fuse() => match status {
|
||||||
Ok(status) => errored = !status.success(),
|
Ok(status) => errored = !dbg!(status.success()),
|
||||||
Err(_) => errored = true,
|
Err(_) => errored = true,
|
||||||
},
|
},
|
||||||
|
|
||||||
_ = timeout => {}
|
_ = timeout => { println!("test binary time-ed out"); }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
println!("test binary failed to launch");
|
||||||
errored = true;
|
errored = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3883,7 +3911,7 @@ impl Project {
|
||||||
);
|
);
|
||||||
|
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
this.check_errored_lsp_installation(language_server.clone(), cx);
|
this.check_errored_language_server(language_server.clone(), cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
None
|
None
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue