tauri_plugin/build/
mod.rs1use std::{
6 collections::BTreeMap,
7 path::{Path, PathBuf},
8};
9
10use anyhow::Result;
11use tauri_utils::acl::{self, Error};
12
13pub mod mobile;
14
15use serde::de::DeserializeOwned;
16
17use std::{env, io::Cursor};
18
19const RESERVED_PLUGIN_NAMES: &[&str] = &["core", "tauri"];
20
21pub fn plugin_config<T: DeserializeOwned>(name: &str) -> Option<T> {
22 let config_env_var_name = format!(
23 "TAURI_{}_PLUGIN_CONFIG",
24 name.to_uppercase().replace('-', "_")
25 );
26 if let Ok(config_str) = env::var(&config_env_var_name) {
27 println!("cargo:rerun-if-env-changed={config_env_var_name}");
28 serde_json::from_reader(Cursor::new(config_str))
29 .map(Some)
30 .expect("failed to parse configuration")
31 } else {
32 None
33 }
34}
35
36pub struct Builder<'a> {
37 commands: &'a [&'static str],
38 global_scope_schema: Option<schemars::schema::RootSchema>,
39 global_api_script_path: Option<PathBuf>,
40 android_path: Option<PathBuf>,
41 ios_path: Option<PathBuf>,
42}
43
44impl<'a> Builder<'a> {
45 pub fn new(commands: &'a [&'static str]) -> Self {
46 Self {
47 commands,
48 global_scope_schema: None,
49 global_api_script_path: None,
50 android_path: None,
51 ios_path: None,
52 }
53 }
54
55 pub fn global_scope_schema(mut self, schema: schemars::schema::RootSchema) -> Self {
57 self.global_scope_schema.replace(schema);
58 self
59 }
60
61 pub fn global_api_script_path<P: Into<PathBuf>>(mut self, path: P) -> Self {
65 self.global_api_script_path.replace(path.into());
66 self
67 }
68
69 pub fn android_path<P: Into<PathBuf>>(mut self, android_path: P) -> Self {
71 self.android_path.replace(android_path.into());
72 self
73 }
74
75 pub fn ios_path<P: Into<PathBuf>>(mut self, ios_path: P) -> Self {
77 self.ios_path.replace(ios_path.into());
78 self
79 }
80
81 pub fn build(self) {
83 if let Err(error) = self.try_build() {
84 println!("{}: {error:#}", env!("CARGO_PKG_NAME"));
85 std::process::exit(1);
86 }
87 }
88
89 pub fn try_build(self) -> Result<()> {
96 let name = build_var("CARGO_PKG_NAME")?;
98 if name.contains('_') {
99 anyhow::bail!("plugin names cannot contain underscores");
100 }
101 if RESERVED_PLUGIN_NAMES.contains(&name.as_str()) {
102 anyhow::bail!("plugin name `{name}` is reserved");
103 }
104
105 let out_dir = PathBuf::from(build_var("OUT_DIR")?);
106
107 let _links = std::env::var("CARGO_MANIFEST_LINKS").map_err(|_| Error::LinksMissing)?;
109
110 let autogenerated = Path::new("permissions").join(acl::build::AUTOGENERATED_FOLDER_NAME);
111 std::fs::create_dir_all(&autogenerated).expect("unable to create permissions dir");
112
113 let commands_dir = autogenerated.join("commands");
114 if !self.commands.is_empty() {
115 acl::build::autogenerate_command_permissions(&commands_dir, self.commands, "", true);
116 }
117
118 println!("cargo:rerun-if-changed=permissions");
119 let permissions =
120 acl::build::define_permissions("./permissions/**/*.*", &name, &out_dir, |_| true)?;
121
122 if permissions.is_empty() {
123 let _ = std::fs::remove_file(format!(
124 "./permissions/{}/{}",
125 acl::PERMISSION_SCHEMAS_FOLDER_NAME,
126 acl::PERMISSION_SCHEMA_FILE_NAME
127 ));
128 let _ = std::fs::remove_file(autogenerated.join(acl::build::PERMISSION_DOCS_FILE_NAME));
129 } else {
130 acl::schema::generate_permissions_schema(&permissions, "./permissions")?;
131 acl::build::generate_docs(
132 &permissions,
133 &autogenerated,
134 name.strip_prefix("tauri-plugin-").unwrap_or(&name),
135 )?;
136 }
137
138 let mut permissions_map = BTreeMap::new();
139 permissions_map.insert(name.clone(), permissions);
140 tauri_utils::acl::build::generate_allowed_commands(&out_dir, None, permissions_map)?;
141
142 if let Some(global_scope_schema) = self.global_scope_schema {
143 acl::build::define_global_scope_schema(global_scope_schema, &name, &out_dir)?;
144 }
145
146 if let Some(path) = self.global_api_script_path {
147 tauri_utils::plugin::define_global_api_script_path(&path);
148 }
149
150 mobile::setup(self.android_path, self.ios_path)?;
151
152 Ok(())
153 }
154}
155
156fn cfg_alias(alias: &str, has_feature: bool) {
157 println!("cargo:rustc-check-cfg=cfg({alias})");
158 if has_feature {
159 println!("cargo:rustc-cfg={alias}");
160 }
161}
162
163fn build_var(key: &'static str) -> Result<String, Error> {
165 std::env::var(key).map_err(|_| Error::BuildVar(key))
166}