Add a schema to extensions, to prevent installing extensions on too old of a Zed version (#9599)

Release Notes:

- N/A

---------

Co-authored-by: Marshall <marshall@zed.dev>
This commit is contained in:
Max Brunsfeld 2024-03-20 14:33:26 -07:00 committed by GitHub
parent b1feeb9f29
commit 585e8671e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 165 additions and 44 deletions

View file

@ -37,6 +37,7 @@ serde_json.workspace = true
settings.workspace = true
theme.workspace = true
toml.workspace = true
url.workspace = true
util.workspace = true
wasm-encoder.workspace = true
wasmtime.workspace = true

View file

@ -29,6 +29,7 @@ pub struct ExtensionManifest {
pub id: Arc<str>,
pub name: String,
pub version: Arc<str>,
pub schema_version: i32,
#[serde(default)]
pub description: Option<String>,

View file

@ -35,6 +35,7 @@ use std::{
time::{Duration, Instant},
};
use theme::{ThemeRegistry, ThemeSettings};
use url::Url;
use util::{
http::{AsyncBody, HttpClient, HttpClientWithUrl},
paths::EXTENSIONS_DIR,
@ -49,6 +50,8 @@ pub use extension_manifest::{
const RELOAD_DEBOUNCE_DURATION: Duration = Duration::from_millis(200);
const FS_WATCH_LATENCY: Duration = Duration::from_millis(100);
const CURRENT_SCHEMA_VERSION: i64 = 1;
#[derive(Deserialize)]
pub struct ExtensionsApiResponse {
pub data: Vec<ExtensionApiResponse>,
@ -377,15 +380,18 @@ impl ExtensionStore {
search: Option<&str>,
cx: &mut ModelContext<Self>,
) -> Task<Result<Vec<ExtensionApiResponse>>> {
let url = self.http_client.build_zed_api_url(&format!(
"/extensions{query}",
query = search
.map(|search| format!("?filter={search}"))
.unwrap_or_default()
));
let version = CURRENT_SCHEMA_VERSION.to_string();
let mut query = vec![("max_schema_version", version.as_str())];
if let Some(search) = search {
query.push(("filter", search));
}
let url = self.http_client.build_zed_api_url("/extensions", &query);
let http_client = self.http_client.clone();
cx.spawn(move |_, _| async move {
let mut response = http_client.get(&url, AsyncBody::empty(), true).await?;
let mut response = http_client
.get(&url?.as_ref(), AsyncBody::empty(), true)
.await?;
let mut body = Vec::new();
response
@ -420,7 +426,7 @@ impl ExtensionStore {
fn install_or_upgrade_extension_at_endpoint(
&mut self,
extension_id: Arc<str>,
url: String,
url: Url,
operation: ExtensionOperation,
cx: &mut ModelContext<Self>,
) {
@ -447,7 +453,7 @@ impl ExtensionStore {
});
let mut response = http_client
.get(&url, Default::default(), true)
.get(&url.as_ref(), Default::default(), true)
.await
.map_err(|err| anyhow!("error downloading extension: {}", err))?;
let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
@ -482,9 +488,13 @@ impl ExtensionStore {
) {
log::info!("installing extension {extension_id} latest version");
let url = self
let Some(url) = self
.http_client
.build_zed_api_url(&format!("/extensions/{extension_id}/download"));
.build_zed_api_url(&format!("/extensions/{extension_id}/download"), &[])
.log_err()
else {
return;
};
self.install_or_upgrade_extension_at_endpoint(
extension_id,
@ -511,9 +521,16 @@ impl ExtensionStore {
cx: &mut ModelContext<Self>,
) {
log::info!("installing extension {extension_id} {version}");
let url = self
let Some(url) = self
.http_client
.build_zed_api_url(&format!("/extensions/{extension_id}/{version}/download"));
.build_zed_api_url(
&format!("/extensions/{extension_id}/{version}/download"),
&[],
)
.log_err()
else {
return;
};
self.install_or_upgrade_extension_at_endpoint(extension_id, url, operation, cx);
}
@ -1104,6 +1121,7 @@ fn manifest_from_old_manifest(
description: manifest_json.description,
repository: manifest_json.repository,
authors: manifest_json.authors,
schema_version: 0,
lib: Default::default(),
themes: {
let mut themes = manifest_json.themes.into_values().collect::<Vec<_>>();

View file

@ -145,6 +145,7 @@ async fn test_extension_store(cx: &mut TestAppContext) {
id: "zed-ruby".into(),
name: "Zed Ruby".into(),
version: "1.0.0".into(),
schema_version: 0,
description: None,
authors: Vec::new(),
repository: None,
@ -169,6 +170,7 @@ async fn test_extension_store(cx: &mut TestAppContext) {
id: "zed-monokai".into(),
name: "Zed Monokai".into(),
version: "2.0.0".into(),
schema_version: 0,
description: None,
authors: vec![],
repository: None,
@ -324,6 +326,7 @@ async fn test_extension_store(cx: &mut TestAppContext) {
id: "zed-gruvbox".into(),
name: "Zed Gruvbox".into(),
version: "1.0.0".into(),
schema_version: 0,
description: None,
authors: vec![],
repository: None,