From 5a25751521d3f6e9da51eb5d0af34dc25d9b7ce8 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 5 Feb 2025 13:17:19 -0500 Subject: [PATCH] extension_cli: Include the list of what an extension provides in the generated manifest (#24295) This PR updates the Zed extension CLI with support for populating the `provides` field in the generated extension manifest. This field will contain the set of features that the extension provides. For example: ``` "provides": ["themes", "icon-themes"] ``` Release Notes: - N/A --- crates/collab/src/db/queries/extensions.rs | 2 + crates/collab/src/db/tests/extension_tests.rs | 12 +++- crates/extension_cli/src/main.rs | 61 +++++++++++++++---- crates/rpc/src/extension.rs | 18 ++++++ 4 files changed, 81 insertions(+), 12 deletions(-) diff --git a/crates/collab/src/db/queries/extensions.rs b/crates/collab/src/db/queries/extensions.rs index 93604868fa..51c6395632 100644 --- a/crates/collab/src/db/queries/extensions.rs +++ b/crates/collab/src/db/queries/extensions.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeSet; use std::str::FromStr; use chrono::Utc; @@ -370,6 +371,7 @@ fn metadata_from_extension_and_version( repository: version.repository, schema_version: Some(version.schema_version), wasm_api_version: version.wasm_api_version, + provides: BTreeSet::default(), }, published_at: convert_time_to_chrono(version.published_at), diff --git a/crates/collab/src/db/tests/extension_tests.rs b/crates/collab/src/db/tests/extension_tests.rs index b91570c494..84e53c5cab 100644 --- a/crates/collab/src/db/tests/extension_tests.rs +++ b/crates/collab/src/db/tests/extension_tests.rs @@ -1,10 +1,12 @@ +use std::collections::BTreeSet; +use std::sync::Arc; + use super::Database; use crate::db::ExtensionVersionConstraints; use crate::{ db::{queries::extensions::convert_time_to_chrono, ExtensionMetadata, NewExtensionVersion}, test_both_dbs, }; -use std::sync::Arc; test_both_dbs!( test_extensions, @@ -97,6 +99,7 @@ async fn test_extensions(db: &Arc) { repository: "ext1/repo".into(), schema_version: Some(1), wasm_api_version: None, + provides: BTreeSet::default(), }, published_at: t0_chrono, download_count: 0, @@ -111,6 +114,7 @@ async fn test_extensions(db: &Arc) { repository: "ext2/repo".into(), schema_version: Some(0), wasm_api_version: None, + provides: BTreeSet::default(), }, published_at: t0_chrono, download_count: 0 @@ -132,6 +136,7 @@ async fn test_extensions(db: &Arc) { repository: "ext2/repo".into(), schema_version: Some(0), wasm_api_version: None, + provides: BTreeSet::default(), }, published_at: t0_chrono, download_count: 0 @@ -172,6 +177,7 @@ async fn test_extensions(db: &Arc) { repository: "ext2/repo".into(), schema_version: Some(0), wasm_api_version: None, + provides: BTreeSet::default(), }, published_at: t0_chrono, download_count: 7 @@ -186,6 +192,7 @@ async fn test_extensions(db: &Arc) { repository: "ext1/repo".into(), schema_version: Some(1), wasm_api_version: None, + provides: BTreeSet::default(), }, published_at: t0_chrono, download_count: 5, @@ -258,6 +265,7 @@ async fn test_extensions(db: &Arc) { repository: "ext2/repo".into(), schema_version: Some(0), wasm_api_version: None, + provides: BTreeSet::default(), }, published_at: t0_chrono, download_count: 7 @@ -272,6 +280,7 @@ async fn test_extensions(db: &Arc) { repository: "ext1/repo".into(), schema_version: Some(1), wasm_api_version: None, + provides: BTreeSet::default(), }, published_at: t0_chrono, download_count: 5, @@ -378,6 +387,7 @@ async fn test_extensions_by_id(db: &Arc) { repository: "ext1/repo".into(), schema_version: Some(1), wasm_api_version: Some("0.0.4".into()), + provides: BTreeSet::default(), }, published_at: t0_chrono, download_count: 0, diff --git a/crates/extension_cli/src/main.rs b/crates/extension_cli/src/main.rs index 917eca96db..4428849129 100644 --- a/crates/extension_cli/src/main.rs +++ b/crates/extension_cli/src/main.rs @@ -1,20 +1,18 @@ -use std::{ - collections::HashMap, - env, fs, - path::{Path, PathBuf}, - process::Command, - sync::Arc, -}; +use std::collections::{BTreeSet, HashMap}; +use std::env; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::sync::Arc; use ::fs::{copy_recursive, CopyOptions, Fs, RealFs}; use anyhow::{anyhow, bail, Context, Result}; use clap::Parser; -use extension::{ - extension_builder::{CompileExtensionOptions, ExtensionBuilder}, - ExtensionManifest, -}; +use extension::extension_builder::{CompileExtensionOptions, ExtensionBuilder}; +use extension::ExtensionManifest; use language::LanguageConfig; use reqwest_client::ReqwestClient; +use rpc::ExtensionProvides; use tree_sitter::{Language, Query, WasmStore}; #[derive(Parser, Debug)] @@ -99,6 +97,8 @@ async fn main() -> Result<()> { ); } + let extension_provides = extension_provides(&manifest); + let manifest_json = serde_json::to_string(&rpc::ExtensionApiManifest { name: manifest.name, version: manifest.version, @@ -109,6 +109,7 @@ async fn main() -> Result<()> { .repository .ok_or_else(|| anyhow!("missing repository in extension manifest"))?, wasm_api_version: manifest.lib.version.map(|version| version.to_string()), + provides: extension_provides, })?; fs::remove_dir_all(&archive_dir)?; fs::write(output_dir.join("manifest.json"), manifest_json.as_bytes())?; @@ -116,6 +117,44 @@ async fn main() -> Result<()> { Ok(()) } +/// Returns the set of features provided by the extension. +fn extension_provides(manifest: &ExtensionManifest) -> BTreeSet { + let mut provides = BTreeSet::default(); + if !manifest.themes.is_empty() { + provides.insert(ExtensionProvides::Themes); + } + + if !manifest.icon_themes.is_empty() { + provides.insert(ExtensionProvides::IconThemes); + } + + if !manifest.languages.is_empty() { + provides.insert(ExtensionProvides::Languages); + } + + if !manifest.grammars.is_empty() { + provides.insert(ExtensionProvides::Grammars); + } + + if !manifest.language_servers.is_empty() { + provides.insert(ExtensionProvides::LanguageServers); + } + + if !manifest.context_servers.is_empty() { + provides.insert(ExtensionProvides::ContextServers); + } + + if !manifest.indexed_docs_providers.is_empty() { + provides.insert(ExtensionProvides::IndexedDocsProviders); + } + + if manifest.snippets.is_some() { + provides.insert(ExtensionProvides::Snippets); + } + + provides +} + async fn copy_extension_resources( manifest: &ExtensionManifest, extension_path: &Path, diff --git a/crates/rpc/src/extension.rs b/crates/rpc/src/extension.rs index f64e9feedd..67b9116b83 100644 --- a/crates/rpc/src/extension.rs +++ b/crates/rpc/src/extension.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeSet; + use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -11,6 +13,22 @@ pub struct ExtensionApiManifest { pub repository: String, pub schema_version: Option, pub wasm_api_version: Option, + #[serde(default)] + pub provides: BTreeSet, +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum ExtensionProvides { + Themes, + IconThemes, + Languages, + Grammars, + LanguageServers, + ContextServers, + SlashCommands, + IndexedDocsProviders, + Snippets, } #[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]