mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-28 09:54:33 +00:00
Add new make-file-executable
API for extensions (#10047)
This PR adds a new function, `make-file-executable`, to the Zed extension API that can be used to mark a given file as executable (typically the language server binary). This is available in v0.0.5 of the `zed_extension_api` crate. We also reworked how we represent the various WIT versions on disk to make it a bit clearer what the version number entails. Release Notes: - N/A --------- Co-authored-by: Max <max@zed.dev>
This commit is contained in:
parent
6e49a2460e
commit
8b586ef8e7
13 changed files with 97 additions and 46 deletions
47
Cargo.lock
generated
47
Cargo.lock
generated
|
@ -12670,28 +12670,21 @@ dependencies = [
|
|||
name = "zed_astro"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zed_extension_api 0.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_csharp"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zed_extension_api 0.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_erlang"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_extension_api"
|
||||
version = "0.0.4"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
"zed_extension_api 0.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -12703,67 +12696,83 @@ dependencies = [
|
|||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_extension_api"
|
||||
version = "0.0.5"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_extension_api"
|
||||
version = "0.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5f4ae4e302a80591635ef9a236b35fde6fcc26cfd060e66fde4ba9f9fd394a1"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_gleam"
|
||||
version = "0.0.2"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zed_extension_api 0.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_haskell"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zed_extension_api 0.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_php"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zed_extension_api 0.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_prisma"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zed_extension_api 0.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_purescript"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zed_extension_api 0.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_svelte"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zed_extension_api 0.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_toml"
|
||||
version = "0.0.2"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zed_extension_api 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_uiua"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zed_extension_api 0.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_zig"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zed_extension_api 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -57,8 +57,13 @@ impl LspAdapter for ExtensionLspAdapter {
|
|||
.host
|
||||
.path_from_extension(&self.extension.manifest.id, command.command.as_ref());
|
||||
|
||||
// TODO: Eventually we'll want to expose an extension API for doing this, but for
|
||||
// now we just manually set the file permissions for extensions that we know need it.
|
||||
// TODO: This should now be done via the `zed::make_file_executable` function in
|
||||
// Zed extension API, but we're leaving these existing usages in place temporarily
|
||||
// to avoid any compatibility issues between Zed and the extension versions.
|
||||
//
|
||||
// We can remove once the following extension versions no longer see any use:
|
||||
// - toml@0.0.2
|
||||
// - zig@0.0.1
|
||||
if ["toml", "zig"].contains(&self.extension.manifest.id.as_ref()) {
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
mod v0_0_1;
|
||||
mod v0_0_4;
|
||||
mod since_v0_0_1;
|
||||
mod since_v0_0_4;
|
||||
|
||||
use super::{wasm_engine, WasmState};
|
||||
use anyhow::{Context, Result};
|
||||
|
@ -11,7 +11,7 @@ use wasmtime::{
|
|||
Store,
|
||||
};
|
||||
|
||||
use v0_0_4 as latest;
|
||||
use since_v0_0_4 as latest;
|
||||
|
||||
pub use latest::{Command, LanguageServerConfig};
|
||||
|
||||
|
@ -30,12 +30,12 @@ fn wasi_view(state: &mut WasmState) -> &mut WasmState {
|
|||
|
||||
/// Returns whether the given Wasm API version is supported by the Wasm host.
|
||||
pub fn is_supported_wasm_api_version(version: SemanticVersion) -> bool {
|
||||
v0_0_1::VERSION <= version && version <= v0_0_4::VERSION
|
||||
since_v0_0_1::MIN_VERSION <= version && version <= latest::MAX_VERSION
|
||||
}
|
||||
|
||||
pub enum Extension {
|
||||
V004(v0_0_4::Extension),
|
||||
V001(v0_0_1::Extension),
|
||||
V004(since_v0_0_4::Extension),
|
||||
V001(since_v0_0_1::Extension),
|
||||
}
|
||||
|
||||
impl Extension {
|
||||
|
@ -44,17 +44,23 @@ impl Extension {
|
|||
version: SemanticVersion,
|
||||
component: &Component,
|
||||
) -> Result<(Self, Instance)> {
|
||||
if version < latest::VERSION {
|
||||
let (extension, instance) =
|
||||
v0_0_1::Extension::instantiate_async(store, &component, v0_0_1::linker())
|
||||
.await
|
||||
.context("failed to instantiate wasm extension")?;
|
||||
if version < latest::MIN_VERSION {
|
||||
let (extension, instance) = since_v0_0_1::Extension::instantiate_async(
|
||||
store,
|
||||
&component,
|
||||
since_v0_0_1::linker(),
|
||||
)
|
||||
.await
|
||||
.context("failed to instantiate wasm extension")?;
|
||||
Ok((Self::V001(extension), instance))
|
||||
} else {
|
||||
let (extension, instance) =
|
||||
v0_0_4::Extension::instantiate_async(store, &component, v0_0_4::linker())
|
||||
.await
|
||||
.context("failed to instantiate wasm extension")?;
|
||||
let (extension, instance) = since_v0_0_4::Extension::instantiate_async(
|
||||
store,
|
||||
&component,
|
||||
since_v0_0_4::linker(),
|
||||
)
|
||||
.await
|
||||
.context("failed to instantiate wasm extension")?;
|
||||
Ok((Self::V004(extension), instance))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,11 @@ use semantic_version::SemanticVersion;
|
|||
use std::sync::{Arc, OnceLock};
|
||||
use wasmtime::component::{Linker, Resource};
|
||||
|
||||
pub const VERSION: SemanticVersion = SemanticVersion::new(0, 0, 1);
|
||||
pub const MIN_VERSION: SemanticVersion = SemanticVersion::new(0, 0, 1);
|
||||
|
||||
wasmtime::component::bindgen!({
|
||||
async: true,
|
||||
path: "../extension_api/wit/0.0.1",
|
||||
path: "../extension_api/wit/since_v0.0.1",
|
||||
with: {
|
||||
"worktree": ExtensionWorktree,
|
||||
},
|
|
@ -6,6 +6,7 @@ use async_trait::async_trait;
|
|||
use futures::io::BufReader;
|
||||
use language::{LanguageServerBinaryStatus, LspAdapterDelegate};
|
||||
use semantic_version::SemanticVersion;
|
||||
use std::path::Path;
|
||||
use std::{
|
||||
env,
|
||||
path::PathBuf,
|
||||
|
@ -14,11 +15,12 @@ use std::{
|
|||
use util::maybe;
|
||||
use wasmtime::component::{Linker, Resource};
|
||||
|
||||
pub const VERSION: SemanticVersion = SemanticVersion::new(0, 0, 4);
|
||||
pub const MIN_VERSION: SemanticVersion = SemanticVersion::new(0, 0, 4);
|
||||
pub const MAX_VERSION: SemanticVersion = SemanticVersion::new(0, 0, 5);
|
||||
|
||||
wasmtime::component::bindgen!({
|
||||
async: true,
|
||||
path: "../extension_api/wit/0.0.4",
|
||||
path: "../extension_api/wit/since_v0.0.4",
|
||||
with: {
|
||||
"worktree": ExtensionWorktree,
|
||||
},
|
||||
|
@ -274,6 +276,28 @@ impl ExtensionImports for WasmState {
|
|||
.await;
|
||||
convert_result(result)
|
||||
}
|
||||
|
||||
async fn make_file_executable(&mut self, path: String) -> wasmtime::Result<Result<(), String>> {
|
||||
#[allow(unused)]
|
||||
let path = self
|
||||
.host
|
||||
.writeable_path_from_extension(&self.manifest.id, Path::new(&path))?;
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::fs::{self, Permissions};
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
return convert_result(
|
||||
fs::set_permissions(&path, Permissions::from_mode(0o755)).map_err(|error| {
|
||||
anyhow!("failed to set permissions for path {path:?}: {error}")
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
Ok(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_result<T>(result: Result<T>) -> wasmtime::Result<Result<T, String>> {
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zed_extension_api"
|
||||
version = "0.0.4"
|
||||
version = "0.0.5"
|
||||
description = "APIs for creating Zed extensions in Rust"
|
||||
repository = "https://github.com/zed-industries/zed"
|
||||
documentation = "https://docs.rs/zed_extension_api"
|
||||
|
|
|
@ -53,7 +53,7 @@ pub static ZED_API_VERSION: [u8; 6] = *include_bytes!(concat!(env!("OUT_DIR"), "
|
|||
mod wit {
|
||||
wit_bindgen::generate!({
|
||||
skip: ["init-extension"],
|
||||
path: "./wit/0.0.4",
|
||||
path: "./wit/since_v0.0.4",
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -62,9 +62,12 @@ world extension {
|
|||
/// Gets the latest release for the given GitHub repository.
|
||||
import latest-github-release: func(repo: string, options: github-release-options) -> result<github-release, string>;
|
||||
|
||||
/// Downloads a file from the given url, and saves it to the given filename within the extension's
|
||||
/// Downloads a file from the given url, and saves it to the given path within the extension's
|
||||
/// working directory. Extracts the file according to the given file type.
|
||||
import download-file: func(url: string, output-filename: string, file-type: downloaded-file-type) -> result<_, string>;
|
||||
import download-file: func(url: string, file-path: string, file-type: downloaded-file-type) -> result<_, string>;
|
||||
|
||||
/// Makes the file at the given path executable.
|
||||
import make-file-executable: func(filepath: string) -> result<_, string>;
|
||||
|
||||
/// Updates the installation status for the given language server.
|
||||
import set-language-server-installation-status: func(language-server-name: string, status: language-server-installation-status);
|
|
@ -13,4 +13,4 @@ path = "src/toml.rs"
|
|||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
zed_extension_api = "0.0.4"
|
||||
zed_extension_api = "0.0.5"
|
||||
|
|
|
@ -72,6 +72,8 @@ impl TomlExtension {
|
|||
)
|
||||
.map_err(|err| format!("failed to download file: {err}"))?;
|
||||
|
||||
zed::make_file_executable(&binary_path)?;
|
||||
|
||||
let entries = fs::read_dir(".")
|
||||
.map_err(|err| format!("failed to list working directory {err}"))?;
|
||||
for entry in entries {
|
||||
|
|
|
@ -13,4 +13,4 @@ path = "src/zig.rs"
|
|||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
zed_extension_api = "0.0.4"
|
||||
zed_extension_api = "0.0.5"
|
||||
|
|
|
@ -78,6 +78,8 @@ impl ZigExtension {
|
|||
)
|
||||
.map_err(|e| format!("failed to download file: {e}"))?;
|
||||
|
||||
zed::make_file_executable(&binary_path)?;
|
||||
|
||||
let entries =
|
||||
fs::read_dir(".").map_err(|e| format!("failed to list working directory {e}"))?;
|
||||
for entry in entries {
|
||||
|
|
Loading…
Reference in a new issue