supermaven_api: Ensure downloaded Supermaven binary has executable permissions set (#32576)

Closes #32068
Closes #15653

Not entirely sure that it fixes the latter issue, but I am fairly
certain given the comments in #32068 and the available logs in the
issue.

This PR fixes an issue where the Supermaven provider would not leave the
"Initializing" stage. This happened due to the downloaded binary missing
executable permissions. The change here ensures that freshly downloaded
binaries as well as existing binaries downloaded by Zed have executable
permissions set. I decided on also adding this for the latter since
existing downloads would continue to be broken and Supermaven does not
seem to change versions often given the logs provided by users.


While I was at it, I also added a `make_file_executable` to the util
crate mirroring the method of the `zed_extensions_api` and refactored
existing usages where possible to use that method instead. This makes
the code slightly more readable in my opinion, yet adds a method to
non-unix systems that practically does nothing. I can revert this should
that be preferred.


Release Notes:

- Fixed an issue where the Supermaven completion provider would not
leave the "Initializing" stage.

---------

Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
This commit is contained in:
Finn Evers 2025-06-17 16:39:45 +02:00 committed by GitHub
parent dd850dcf13
commit a391d67366
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 54 additions and 60 deletions

View file

@ -20,4 +20,5 @@ paths.workspace = true
serde.workspace = true
serde_json.workspace = true
smol.workspace = true
util.workspace = true
workspace-hack.workspace = true

View file

@ -5,10 +5,11 @@ use http_client::{AsyncBody, HttpClient, Request as HttpRequest};
use paths::supermaven_dir;
use serde::{Deserialize, Serialize};
use smol::fs::{self, File};
use smol::stream::StreamExt;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use util::fs::{make_file_executable, remove_matching};
#[derive(Serialize)]
pub struct GetExternalUserRequest {
pub id: String,
@ -253,6 +254,11 @@ pub async fn get_supermaven_agent_path(client: Arc<dyn HttpClient>) -> Result<Pa
let binary_path = version_path(download_info.version);
if has_version(&binary_path).await {
// Due to an issue with the Supermaven binary not being made executable on
// earlier Zed versions and Supermaven releases not occurring that frequently,
// we ensure here that the found binary is actually executable.
make_file_executable(&binary_path).await?;
return Ok(binary_path);
}
@ -271,13 +277,9 @@ pub async fn get_supermaven_agent_path(client: Arc<dyn HttpClient>) -> Result<Pa
.await
.with_context(|| format!("Unable to write binary to file at {:?}", binary_path))?;
let mut old_binary_paths = fs::read_dir(supermaven_dir()).await?;
while let Some(old_binary_path) = old_binary_paths.next().await {
let old_binary_path = old_binary_path?;
if old_binary_path.path() != binary_path {
fs::remove_file(old_binary_path.path()).await?;
}
}
make_file_executable(&binary_path).await?;
remove_matching(supermaven_dir(), |file| file != binary_path).await;
Ok(binary_path)
}