diff --git a/Cargo.lock b/Cargo.lock index c720155429..6129d42f31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4089,6 +4089,29 @@ dependencies = [ "zune-inflate", ] +[[package]] +name = "extension" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-compression", + "async-tar", + "collections", + "fs", + "futures 0.3.30", + "http_client", + "language", + "log", + "lsp", + "semantic_version", + "serde", + "serde_json", + "toml 0.8.19", + "wasm-encoder 0.215.0", + "wasmparser 0.215.0", + "wit-component", +] + [[package]] name = "extension_cli" version = "0.1.0" @@ -4096,7 +4119,7 @@ dependencies = [ "anyhow", "clap", "env_logger 0.11.5", - "extension_host", + "extension", "fs", "language", "log", @@ -4124,6 +4147,7 @@ dependencies = [ "collections", "ctor", "env_logger 0.11.5", + "extension", "fs", "futures 0.3.30", "gpui", @@ -4151,11 +4175,8 @@ dependencies = [ "ui", "url", "util", - "wasm-encoder 0.215.0", - "wasmparser 0.215.0", "wasmtime", "wasmtime-wasi", - "wit-component", "workspace", ] diff --git a/Cargo.toml b/Cargo.toml index 853372dd3c..a9511a59e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ members = [ "crates/docs_preprocessor", "crates/editor", "crates/evals", + "crates/extension", "crates/extension_api", "crates/extension_cli", "crates/extension_host", @@ -201,6 +202,7 @@ copilot = { path = "crates/copilot" } db = { path = "crates/db" } diagnostics = { path = "crates/diagnostics" } editor = { path = "crates/editor" } +extension = { path = "crates/extension" } extension_host = { path = "crates/extension_host" } extensions_ui = { path = "crates/extensions_ui" } feature_flags = { path = "crates/feature_flags" } diff --git a/crates/call/Cargo.toml b/crates/call/Cargo.toml index 468d381258..974c860c08 100644 --- a/crates/call/Cargo.toml +++ b/crates/call/Cargo.toml @@ -13,7 +13,6 @@ path = "src/call.rs" doctest = false [features] -no-webrtc = ["live_kit_client/no-webrtc"] test-support = [ "client/test-support", "collections/test-support", diff --git a/crates/extension/Cargo.toml b/crates/extension/Cargo.toml new file mode 100644 index 0000000000..824e00b468 --- /dev/null +++ b/crates/extension/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "extension" +version = "0.1.0" +edition = "2021" +publish = false +license = "GPL-3.0-or-later" + +[lints] +workspace = true + +[lib] +path = "src/extension.rs" + +[dependencies] +anyhow.workspace = true +async-compression.workspace = true +async-tar.workspace = true +collections.workspace = true +fs.workspace = true +futures.workspace = true +http_client.workspace = true +language.workspace = true +log.workspace = true +lsp.workspace = true +semantic_version.workspace = true +serde.workspace = true +serde_json.workspace = true +toml.workspace = true +wasm-encoder.workspace = true +wasmparser.workspace = true +wit-component.workspace = true diff --git a/crates/extension/LICENSE-GPL b/crates/extension/LICENSE-GPL new file mode 120000 index 0000000000..89e542f750 --- /dev/null +++ b/crates/extension/LICENSE-GPL @@ -0,0 +1 @@ +../../LICENSE-GPL \ No newline at end of file diff --git a/crates/extension/src/extension.rs b/crates/extension/src/extension.rs new file mode 100644 index 0000000000..3635096d54 --- /dev/null +++ b/crates/extension/src/extension.rs @@ -0,0 +1,50 @@ +pub mod extension_builder; +mod extension_manifest; + +use anyhow::{anyhow, bail, Context as _, Result}; +use semantic_version::SemanticVersion; + +pub use crate::extension_manifest::*; + +pub fn parse_wasm_extension_version( + extension_id: &str, + wasm_bytes: &[u8], +) -> Result { + let mut version = None; + + for part in wasmparser::Parser::new(0).parse_all(wasm_bytes) { + if let wasmparser::Payload::CustomSection(s) = + part.context("error parsing wasm extension")? + { + if s.name() == "zed:api-version" { + version = parse_wasm_extension_version_custom_section(s.data()); + if version.is_none() { + bail!( + "extension {} has invalid zed:api-version section: {:?}", + extension_id, + s.data() + ); + } + } + } + } + + // The reason we wait until we're done parsing all of the Wasm bytes to return the version + // is to work around a panic that can happen inside of Wasmtime when the bytes are invalid. + // + // By parsing the entirety of the Wasm bytes before we return, we're able to detect this problem + // earlier as an `Err` rather than as a panic. + version.ok_or_else(|| anyhow!("extension {} has no zed:api-version section", extension_id)) +} + +fn parse_wasm_extension_version_custom_section(data: &[u8]) -> Option { + if data.len() == 6 { + Some(SemanticVersion::new( + u16::from_be_bytes([data[0], data[1]]) as _, + u16::from_be_bytes([data[2], data[3]]) as _, + u16::from_be_bytes([data[4], data[5]]) as _, + )) + } else { + None + } +} diff --git a/crates/extension_host/src/extension_builder.rs b/crates/extension/src/extension_builder.rs similarity index 99% rename from crates/extension_host/src/extension_builder.rs rename to crates/extension/src/extension_builder.rs index 7380e699f9..a92d878d1e 100644 --- a/crates/extension_host/src/extension_builder.rs +++ b/crates/extension/src/extension_builder.rs @@ -1,6 +1,6 @@ -use crate::wasm_host::parse_wasm_extension_version; -use crate::ExtensionManifest; -use crate::{extension_manifest::ExtensionLibraryKind, GrammarManifestEntry}; +use crate::{ + parse_wasm_extension_version, ExtensionLibraryKind, ExtensionManifest, GrammarManifestEntry, +}; use anyhow::{anyhow, bail, Context as _, Result}; use async_compression::futures::bufread::GzipDecoder; use async_tar::Archive; diff --git a/crates/extension_host/src/extension_manifest.rs b/crates/extension/src/extension_manifest.rs similarity index 100% rename from crates/extension_host/src/extension_manifest.rs rename to crates/extension/src/extension_manifest.rs diff --git a/crates/extension_cli/Cargo.toml b/crates/extension_cli/Cargo.toml index 8cf3e9b6be..d7ec5aa7cf 100644 --- a/crates/extension_cli/Cargo.toml +++ b/crates/extension_cli/Cargo.toml @@ -16,7 +16,7 @@ path = "src/main.rs" anyhow.workspace = true clap = { workspace = true, features = ["derive"] } env_logger.workspace = true -extension_host = { workspace = true, features = ["no-webrtc"] } +extension.workspace = true fs.workspace = true language.workspace = true log.workspace = true diff --git a/crates/extension_cli/src/main.rs b/crates/extension_cli/src/main.rs index 58bee34923..ffa9555c21 100644 --- a/crates/extension_cli/src/main.rs +++ b/crates/extension_cli/src/main.rs @@ -9,7 +9,7 @@ use std::{ use ::fs::{copy_recursive, CopyOptions, Fs, RealFs}; use anyhow::{anyhow, bail, Context, Result}; use clap::Parser; -use extension_host::{ +use extension::{ extension_builder::{CompileExtensionOptions, ExtensionBuilder}, ExtensionManifest, }; diff --git a/crates/extension_host/Cargo.toml b/crates/extension_host/Cargo.toml index dd31c2af86..4eb5d22f72 100644 --- a/crates/extension_host/Cargo.toml +++ b/crates/extension_host/Cargo.toml @@ -12,9 +12,6 @@ workspace = true path = "src/extension_host.rs" doctest = false -[features] -no-webrtc = ["workspace/no-webrtc"] - [dependencies] anyhow.workspace = true assistant_slash_command.workspace = true @@ -23,6 +20,7 @@ async-tar.workspace = true async-trait.workspace = true client.workspace = true collections.workspace = true +extension.workspace = true fs.workspace = true futures.workspace = true gpui.workspace = true @@ -48,11 +46,8 @@ toml.workspace = true ui.workspace = true url.workspace = true util.workspace = true -wasm-encoder.workspace = true -wasmparser.workspace = true wasmtime-wasi.workspace = true wasmtime.workspace = true -wit-component.workspace = true workspace.workspace = true [dev-dependencies] diff --git a/crates/extension_host/src/extension_host.rs b/crates/extension_host/src/extension_host.rs index f9b4523cac..e53f8eeb75 100644 --- a/crates/extension_host/src/extension_host.rs +++ b/crates/extension_host/src/extension_host.rs @@ -1,7 +1,5 @@ -pub mod extension_builder; mod extension_indexed_docs_provider; mod extension_lsp_adapter; -mod extension_manifest; mod extension_settings; mod extension_slash_command; mod wasm_host; @@ -10,7 +8,6 @@ mod wasm_host; mod extension_store_test; use crate::extension_indexed_docs_provider::ExtensionIndexedDocsProvider; -use crate::extension_manifest::SchemaVersion; use crate::extension_slash_command::ExtensionSlashCommand; use crate::{extension_lsp_adapter::ExtensionLspAdapter, wasm_host::wit}; use anyhow::{anyhow, bail, Context as _, Result}; @@ -19,7 +16,8 @@ use async_compression::futures::bufread::GzipDecoder; use async_tar::Archive; use client::{telemetry::Telemetry, Client, ExtensionMetadata, GetExtensionsResponse}; use collections::{btree_map, BTreeMap, HashSet}; -use extension_builder::{CompileExtensionOptions, ExtensionBuilder}; +use extension::extension_builder::{CompileExtensionOptions, ExtensionBuilder}; +use extension::SchemaVersion; use fs::{Fs, RemoveOptions}; use futures::{ channel::{ @@ -62,7 +60,7 @@ use wasm_host::{ WasmExtension, WasmHost, }; -pub use extension_manifest::{ +pub use extension::{ ExtensionLibraryKind, ExtensionManifest, GrammarManifestEntry, OldExtensionManifest, }; pub use extension_settings::ExtensionSettings; diff --git a/crates/extension_host/src/extension_store_test.rs b/crates/extension_host/src/extension_store_test.rs index f14707c3ba..194625883c 100644 --- a/crates/extension_host/src/extension_store_test.rs +++ b/crates/extension_host/src/extension_store_test.rs @@ -1,4 +1,3 @@ -use crate::extension_manifest::SchemaVersion; use crate::extension_settings::ExtensionSettings; use crate::{ Event, ExtensionIndex, ExtensionIndexEntry, ExtensionIndexLanguageEntry, @@ -8,6 +7,7 @@ use crate::{ use assistant_slash_command::SlashCommandRegistry; use async_compression::futures::bufread::GzipEncoder; use collections::BTreeMap; +use extension::SchemaVersion; use fs::{FakeFs, Fs, RealFs}; use futures::{io::BufReader, AsyncReadExt, StreamExt}; use gpui::{Context, SemanticVersion, TestAppContext}; diff --git a/crates/extension_host/src/wasm_host.rs b/crates/extension_host/src/wasm_host.rs index b3fd13a5ba..4241f3f551 100644 --- a/crates/extension_host/src/wasm_host.rs +++ b/crates/extension_host/src/wasm_host.rs @@ -1,7 +1,7 @@ pub(crate) mod wit; use crate::ExtensionManifest; -use anyhow::{anyhow, bail, Context as _, Result}; +use anyhow::{anyhow, Context as _, Result}; use fs::{normalize_path, Fs}; use futures::future::LocalBoxFuture; use futures::{ @@ -112,7 +112,8 @@ impl WasmHost { ) -> Task> { let this = self.clone(); executor.clone().spawn(async move { - let zed_api_version = parse_wasm_extension_version(&manifest.id, &wasm_bytes)?; + let zed_api_version = + extension::parse_wasm_extension_version(&manifest.id, &wasm_bytes)?; let component = Component::from_binary(&this.engine, &wasm_bytes) .context("failed to compile wasm component")?; @@ -197,49 +198,6 @@ impl WasmHost { } } -pub fn parse_wasm_extension_version( - extension_id: &str, - wasm_bytes: &[u8], -) -> Result { - let mut version = None; - - for part in wasmparser::Parser::new(0).parse_all(wasm_bytes) { - if let wasmparser::Payload::CustomSection(s) = - part.context("error parsing wasm extension")? - { - if s.name() == "zed:api-version" { - version = parse_wasm_extension_version_custom_section(s.data()); - if version.is_none() { - bail!( - "extension {} has invalid zed:api-version section: {:?}", - extension_id, - s.data() - ); - } - } - } - } - - // The reason we wait until we're done parsing all of the Wasm bytes to return the version - // is to work around a panic that can happen inside of Wasmtime when the bytes are invalid. - // - // By parsing the entirety of the Wasm bytes before we return, we're able to detect this problem - // earlier as an `Err` rather than as a panic. - version.ok_or_else(|| anyhow!("extension {} has no zed:api-version section", extension_id)) -} - -fn parse_wasm_extension_version_custom_section(data: &[u8]) -> Option { - if data.len() == 6 { - Some(SemanticVersion::new( - u16::from_be_bytes([data[0], data[1]]) as _, - u16::from_be_bytes([data[2], data[3]]) as _, - u16::from_be_bytes([data[4], data[5]]) as _, - )) - } else { - None - } -} - impl WasmExtension { pub async fn call(&self, f: Fn) -> T where diff --git a/crates/workspace/Cargo.toml b/crates/workspace/Cargo.toml index 6486302152..6e3a4a7970 100644 --- a/crates/workspace/Cargo.toml +++ b/crates/workspace/Cargo.toml @@ -13,7 +13,6 @@ path = "src/workspace.rs" doctest = false [features] -no-webrtc = ["call/no-webrtc"] test-support = [ "call/test-support", "client/test-support",