浏览代码

initial plugin metadata implementation

Lucas Nogueira 2 年之前
父节点
当前提交
0811f512c5

+ 4 - 0
core/tauri-build/src/lib.rs

@@ -34,6 +34,8 @@ mod codegen;
 pub mod config;
 /// Mobile build functions.
 pub mod mobile;
+/// Build scripts for Tauri plugins.
+pub mod plugin;
 mod static_vcruntime;
 
 #[cfg(feature = "codegen")]
@@ -473,6 +475,8 @@ pub fn try_build(attributes: Attributes) -> Result<()> {
     }
   }
 
+  let _manifests = plugin::manifests();
+
   Ok(())
 }
 

+ 130 - 0
core/tauri-build/src/plugin.rs

@@ -0,0 +1,130 @@
+use serde::{Deserialize, Serialize};
+
+use std::{
+  collections::HashMap,
+  env::{var_os, vars_os},
+  fs::{read_to_string, write},
+  path::PathBuf,
+};
+
+const PLUGIN_METADATA_KEY: &str = "PLUGIN_MANIFEST_PATH";
+
+#[derive(Debug, Serialize, Deserialize)]
+pub enum ScopeType {
+  String,
+}
+
+#[derive(Debug, Default, Serialize, Deserialize)]
+pub struct CapabilityScope {
+  #[serde(default)]
+  allowed: Vec<serde_json::Value>,
+  #[serde(default)]
+  blocked: Vec<serde_json::Value>,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct Capability {
+  id: Option<String>,
+  description: String,
+  #[serde(default)]
+  features: Vec<String>,
+  #[serde(default)]
+  scope: CapabilityScope,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct Manifest {
+  plugin: String,
+  default_capability: Option<Capability>,
+  capabilities: Vec<Capability>,
+  features: Vec<String>,
+  scope_type: Vec<ScopeType>,
+}
+
+impl Manifest {
+  pub fn new(plugin: impl Into<String>) -> Self {
+    Self {
+      plugin: plugin.into(),
+      default_capability: None,
+      capabilities: Vec::new(),
+      features: Vec::new(),
+      scope_type: Vec::new(),
+    }
+  }
+
+  pub fn default_capability(mut self, default_capability: impl AsRef<str>) -> Self {
+    let mut capability: Capability = serde_json::from_str(default_capability.as_ref())
+      .expect("failed to deserialize default capability");
+    assert!(
+      capability.id.is_none(),
+      "default capability cannot have an specific identifier"
+    );
+    capability.id.replace("default".into());
+    self.default_capability.replace(capability);
+    self
+  }
+
+  pub fn capability(mut self, capability: impl AsRef<str>) -> Self {
+    let capability: Capability =
+      serde_json::from_str(capability.as_ref()).expect("failed to deserialize default capability");
+    assert!(
+      capability.id.is_some(),
+      "capability must have an specific identifier"
+    );
+    self.capabilities.push(capability);
+    self
+  }
+
+  pub fn feature(mut self, feature: impl Into<String>) -> Self {
+    self.features.push(feature.into());
+    self
+  }
+
+  pub fn features<I: IntoIterator<Item = S>, S: Into<String>>(mut self, features: I) -> Self {
+    for feature in features {
+      self = self.feature(feature);
+    }
+    self
+  }
+
+  pub fn scope_type(mut self, ty: ScopeType) -> Self {
+    self.scope_type.push(ty);
+    self
+  }
+}
+
+pub fn set_manifest(manifest: Manifest) {
+  let manifest_str = serde_json::to_string(&manifest).expect("failed to serialize plugin manifest");
+  let manifest_path = var_os("OUT_DIR")
+    .map(PathBuf::from)
+    .expect(
+      "missing OUT_DIR environment variable.. are you sure you are running this on a build script?",
+    )
+    .join("plugin-manifest.json");
+  write(&manifest_path, manifest_str).expect("failed to save manifest file");
+
+  println!("cargo:{PLUGIN_METADATA_KEY}={}", manifest_path.display());
+}
+
+pub(crate) fn manifests() -> HashMap<String, Manifest> {
+  let mut manifests = HashMap::new();
+
+  for (key, value) in vars_os() {
+    let key = key.to_string_lossy();
+    if let Some(_plugin_crate_name) = key
+      .strip_prefix("DEP_")
+      .and_then(|v| v.strip_suffix(&format!("_{PLUGIN_METADATA_KEY}")))
+      .map(|p| p.to_lowercase())
+    {
+      let plugin_manifest_path = PathBuf::from(value);
+      let plugin_manifest_str =
+        read_to_string(&plugin_manifest_path).expect("failed to read plugin manifest");
+      let manifest: Manifest =
+        serde_json::from_str(&plugin_manifest_str).expect("failed to deserialize plugin manifest");
+
+      manifests.insert(manifest.plugin.clone(), manifest);
+    }
+  }
+
+  manifests
+}

+ 1 - 0
examples/api/src-tauri/Cargo.lock

@@ -3364,6 +3364,7 @@ dependencies = [
  "cargo_toml",
  "heck",
  "json-patch",
+ "plist",
  "quote",
  "semver",
  "serde",

文件差异内容过多而无法显示
+ 554 - 112
examples/api/src-tauri/tauri-plugin-sample/Cargo.lock


+ 13 - 1
examples/api/src-tauri/tauri-plugin-sample/build.rs

@@ -3,9 +3,13 @@
 // SPDX-License-Identifier: MIT
 
 use std::process::exit;
+use tauri_build::{
+  mobile::PluginBuilder,
+  plugin::{set_manifest, Manifest, ScopeType},
+};
 
 fn main() {
-  if let Err(error) = tauri_build::mobile::PluginBuilder::new()
+  if let Err(error) = PluginBuilder::new()
     .android_path("android")
     .ios_path("ios")
     .run()
@@ -13,4 +17,12 @@ fn main() {
     println!("{error:#}");
     exit(1);
   }
+
+  set_manifest(
+    Manifest::new("sample")
+      .default_capability(include_str!("capabilities/default.json"))
+      .capability(include_str!("capabilities/ping.json"))
+      .feature("ping")
+      .scope_type(ScopeType::String),
+  );
 }

+ 8 - 0
examples/api/src-tauri/tauri-plugin-sample/capabilities/default.json

@@ -0,0 +1,8 @@
+{
+  "features": [],
+  "description": "Default empty capability set",
+  "scope": {
+    "allowed": [],
+    "denied": []
+  }
+}

+ 7 - 0
examples/api/src-tauri/tauri-plugin-sample/capabilities/ping.json

@@ -0,0 +1,7 @@
+{
+  "id": "allow-ping",
+  "description": "Allows the ping command",
+  "features": [
+    "ping"
+  ]
+}

部分文件因为文件数量过多而无法显示