Respect version constraints when installing extensions (#10052)
This PR modifies the extension installation and update process to respect version constraints (schema version and Wasm API version) to ensure only compatible versions of extensions are able to be installed. To achieve this there is a new `GET /extensions/updates` endpoint that will return extension versions based on the provided constraints. Release Notes: - N/A --------- Co-authored-by: Max <max@zed.dev>
This commit is contained in:
parent
39cc3c0778
commit
83ce783856
9 changed files with 304 additions and 78 deletions
|
@ -12,10 +12,6 @@ workspace = true
|
|||
path = "src/extension_store.rs"
|
||||
doctest = false
|
||||
|
||||
[[bin]]
|
||||
name = "extension_json_schemas"
|
||||
path = "src/extension_json_schemas.rs"
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
async-compression.workspace = true
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
use language::LanguageConfig;
|
||||
use schemars::schema_for;
|
||||
use theme::ThemeFamilyContent;
|
||||
|
||||
fn main() {
|
||||
let theme_family_schema = schema_for!(ThemeFamilyContent);
|
||||
let language_config_schema = schema_for!(LanguageConfig);
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::to_string_pretty(&theme_family_schema).unwrap()
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::to_string_pretty(&language_config_schema).unwrap()
|
||||
);
|
||||
}
|
|
@ -36,6 +36,7 @@ use node_runtime::NodeRuntime;
|
|||
use semantic_version::SemanticVersion;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::Settings;
|
||||
use std::ops::RangeInclusive;
|
||||
use std::str::FromStr;
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
|
@ -51,7 +52,10 @@ use util::{
|
|||
paths::EXTENSIONS_DIR,
|
||||
ResultExt,
|
||||
};
|
||||
use wasm_host::{wit::is_supported_wasm_api_version, WasmExtension, WasmHost};
|
||||
use wasm_host::{
|
||||
wit::{is_supported_wasm_api_version, wasm_api_version_range},
|
||||
WasmExtension, WasmHost,
|
||||
};
|
||||
|
||||
pub use extension_manifest::{
|
||||
ExtensionLibraryKind, ExtensionManifest, GrammarManifestEntry, OldExtensionManifest,
|
||||
|
@ -64,6 +68,11 @@ const FS_WATCH_LATENCY: Duration = Duration::from_millis(100);
|
|||
/// The current extension [`SchemaVersion`] supported by Zed.
|
||||
const CURRENT_SCHEMA_VERSION: SchemaVersion = SchemaVersion(1);
|
||||
|
||||
/// Returns the [`SchemaVersion`] range that is compatible with this version of Zed.
|
||||
pub fn schema_version_range() -> RangeInclusive<SchemaVersion> {
|
||||
SchemaVersion::ZERO..=CURRENT_SCHEMA_VERSION
|
||||
}
|
||||
|
||||
/// Returns whether the given extension version is compatible with this version of Zed.
|
||||
pub fn is_version_compatible(extension_version: &ExtensionMetadata) -> bool {
|
||||
let schema_version = extension_version.manifest.schema_version.unwrap_or(0);
|
||||
|
@ -412,15 +421,15 @@ impl ExtensionStore {
|
|||
query.push(("filter", search));
|
||||
}
|
||||
|
||||
self.fetch_extensions_from_api("/extensions", query, cx)
|
||||
self.fetch_extensions_from_api("/extensions", &query, cx)
|
||||
}
|
||||
|
||||
pub fn fetch_extensions_with_update_available(
|
||||
&mut self,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Vec<ExtensionMetadata>>> {
|
||||
let version = CURRENT_SCHEMA_VERSION.to_string();
|
||||
let mut query = vec![("max_schema_version", version.as_str())];
|
||||
let schema_versions = schema_version_range();
|
||||
let wasm_api_versions = wasm_api_version_range();
|
||||
let extension_settings = ExtensionSettings::get_global(cx);
|
||||
let extension_ids = self
|
||||
.extension_index
|
||||
|
@ -430,9 +439,20 @@ impl ExtensionStore {
|
|||
.filter(|id| extension_settings.should_auto_update(id))
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
query.push(("ids", &extension_ids));
|
||||
|
||||
let task = self.fetch_extensions_from_api("/extensions", query, cx);
|
||||
let task = self.fetch_extensions_from_api(
|
||||
"/extensions/updates",
|
||||
&[
|
||||
("min_schema_version", &schema_versions.start().to_string()),
|
||||
("max_schema_version", &schema_versions.end().to_string()),
|
||||
(
|
||||
"min_wasm_api_version",
|
||||
&wasm_api_versions.start().to_string(),
|
||||
),
|
||||
("max_wasm_api_version", &wasm_api_versions.end().to_string()),
|
||||
("ids", &extension_ids),
|
||||
],
|
||||
cx,
|
||||
);
|
||||
cx.spawn(move |this, mut cx| async move {
|
||||
let extensions = task.await?;
|
||||
this.update(&mut cx, |this, _cx| {
|
||||
|
@ -456,7 +476,7 @@ impl ExtensionStore {
|
|||
extension_id: &str,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Vec<ExtensionMetadata>>> {
|
||||
self.fetch_extensions_from_api(&format!("/extensions/{extension_id}"), Vec::new(), cx)
|
||||
self.fetch_extensions_from_api(&format!("/extensions/{extension_id}"), &[], cx)
|
||||
}
|
||||
|
||||
pub fn check_for_updates(&mut self, cx: &mut ModelContext<Self>) {
|
||||
|
@ -500,7 +520,7 @@ impl ExtensionStore {
|
|||
fn fetch_extensions_from_api(
|
||||
&self,
|
||||
path: &str,
|
||||
query: Vec<(&str, &str)>,
|
||||
query: &[(&str, &str)],
|
||||
cx: &mut ModelContext<'_, ExtensionStore>,
|
||||
) -> Task<Result<Vec<ExtensionMetadata>>> {
|
||||
let url = self.http_client.build_zed_api_url(path, &query);
|
||||
|
@ -614,9 +634,23 @@ impl ExtensionStore {
|
|||
) {
|
||||
log::info!("installing extension {extension_id} latest version");
|
||||
|
||||
let schema_versions = schema_version_range();
|
||||
let wasm_api_versions = wasm_api_version_range();
|
||||
|
||||
let Some(url) = self
|
||||
.http_client
|
||||
.build_zed_api_url(&format!("/extensions/{extension_id}/download"), &[])
|
||||
.build_zed_api_url(
|
||||
&format!("/extensions/{extension_id}/download"),
|
||||
&[
|
||||
("min_schema_version", &schema_versions.start().to_string()),
|
||||
("max_schema_version", &schema_versions.end().to_string()),
|
||||
(
|
||||
"min_wasm_api_version",
|
||||
&wasm_api_versions.start().to_string(),
|
||||
),
|
||||
("max_wasm_api_version", &wasm_api_versions.end().to_string()),
|
||||
],
|
||||
)
|
||||
.log_err()
|
||||
else {
|
||||
return;
|
||||
|
|
|
@ -5,6 +5,7 @@ use super::{wasm_engine, WasmState};
|
|||
use anyhow::{Context, Result};
|
||||
use language::LspAdapterDelegate;
|
||||
use semantic_version::SemanticVersion;
|
||||
use std::ops::RangeInclusive;
|
||||
use std::sync::Arc;
|
||||
use wasmtime::{
|
||||
component::{Component, Instance, Linker, Resource},
|
||||
|
@ -30,7 +31,13 @@ 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 {
|
||||
since_v0_0_1::MIN_VERSION <= version && version <= latest::MAX_VERSION
|
||||
wasm_api_version_range().contains(&version)
|
||||
}
|
||||
|
||||
/// Returns the Wasm API version range that is supported by the Wasm host.
|
||||
#[inline(always)]
|
||||
pub fn wasm_api_version_range() -> RangeInclusive<SemanticVersion> {
|
||||
since_v0_0_1::MIN_VERSION..=latest::MAX_VERSION
|
||||
}
|
||||
|
||||
pub enum Extension {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue