Add new extension
crate (#20089)
This PR adds a new `extension` crate, containing some contents extracted from the `extension_host`. Right now it contains just the `ExtensionManifest` and `ExtensionBuilder`, although we may move more of the extension interface into here. The introduction of the `extension` crate allows us to depend on it in the `extension_cli`, thereby eliminating the need for the `no-webrtc` feature on a number of crates. Release Notes: - N/A
This commit is contained in:
parent
ea44c510a3
commit
770886880f
15 changed files with 122 additions and 68 deletions
|
@ -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",
|
||||
|
|
31
crates/extension/Cargo.toml
Normal file
31
crates/extension/Cargo.toml
Normal file
|
@ -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
|
1
crates/extension/LICENSE-GPL
Symbolic link
1
crates/extension/LICENSE-GPL
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE-GPL
|
50
crates/extension/src/extension.rs
Normal file
50
crates/extension/src/extension.rs
Normal file
|
@ -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<SemanticVersion> {
|
||||
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<SemanticVersion> {
|
||||
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
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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<Result<WasmExtension>> {
|
||||
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<SemanticVersion> {
|
||||
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<SemanticVersion> {
|
||||
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<T, Fn>(&self, f: Fn) -> T
|
||||
where
|
||||
|
|
|
@ -13,7 +13,6 @@ path = "src/workspace.rs"
|
|||
doctest = false
|
||||
|
||||
[features]
|
||||
no-webrtc = ["call/no-webrtc"]
|
||||
test-support = [
|
||||
"call/test-support",
|
||||
"client/test-support",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue