/
githubmirror
/
tauri
Обзор
Документация
Войти
/
githubmirror
/
tauri
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
crates/tauri-cli/src/helpers/config.rs
360 строк
10 KB
Fabian-Lars
chore(deps): update dependencies of tauri-cli (#15641)
06 июл 2026, 13:36
Не верифицирован
06 июл 2026, 13:36
7632efd
Код
Авторство
О чём код?
// Copyright 2019-2025 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT use itertools::Itertools; use json_patch::merge; use serde_json::Value as JsonValue; use tauri_utils::acl::REMOVE_UNUSED_COMMANDS_ENV_VAR; pub use tauri_utils::{config::*, platform::Target}; use std::{ collections::HashMap, env::{current_dir, set_current_dir, set_var}, ffi::{OsStr, OsString}, path::Path, process::exit, sync::LazyLock, }; use crate::error::Context; pub const MERGE_CONFIG_EXTENSION_NAME: &str = "--config"; pub struct ConfigMetadata { /// The current target. target: Target, original_identifier: Option<String>, /// The actual configuration, merged with any extension. inner: Config, /// The config extensions (platform-specific config files or the config CLI argument). /// Maps the extension name to its value. extensions: HashMap<OsString, JsonValue>, } impl std::ops::Deref for ConfigMetadata { type Target = Config; #[inline(always)] fn deref(&self) -> &Config { &self.inner } } impl ConfigMetadata { /// The original bundle identifier from the config file. /// This does not take any extensions into account. pub fn original_identifier(&self) -> Option<&str> { self.original_identifier.as_deref() } /// Checks which config is overwriting the bundle identifier. pub fn find_bundle_identifier_overwriter(&self) -> Option<OsString> { for (ext, config) in &self.extensions { if let Some(identifier) = config .as_object() .and_then(|bundle_config| bundle_config.get("identifier")?.as_str()) { if identifier == self.inner.identifier { return Some(ext.clone()); } } } None } } pub fn wix_settings(config: WixConfig) -> tauri_bundler::WixSettings { tauri_bundler::WixSettings { version: config.version, upgrade_code: config.upgrade_code, fips_compliant: std::env::var_os("TAURI_BUNDLER_WIX_FIPS_COMPLIANT") .map(|v| v == "true") .unwrap_or(config.fips_compliant), language: tauri_bundler::WixLanguage(match config.language { WixLanguage::One(lang) => vec![(lang, Default::default())], WixLanguage::List(languages) => languages .into_iter() .map(|lang| (lang, Default::default())) .collect(), WixLanguage::Localized(languages) => languages .into_iter() .map(|(lang, config)| { ( lang, tauri_bundler::WixLanguageConfig { locale_path: config.locale_path.map(Into::into), }, ) }) .collect(), }), template: config.template, fragment_paths: config.fragment_paths, component_group_refs: config.component_group_refs, component_refs: config.component_refs, feature_group_refs: config.feature_group_refs, feature_refs: config.feature_refs, merge_refs: config.merge_refs, enable_elevated_update_task: config.enable_elevated_update_task, banner_path: config.banner_path, dialog_image_path: config.dialog_image_path, } } pub fn nsis_settings(config: NsisConfig) -> tauri_bundler::NsisSettings { tauri_bundler::NsisSettings { template: config.template, header_image: config.header_image, sidebar_image: config.sidebar_image, installer_icon: config.installer_icon, uninstaller_icon: config.uninstaller_icon, uninstaller_header_image: config.uninstaller_header_image, install_mode: config.install_mode, languages: config.languages, custom_language_files: config.custom_language_files, display_language_selector: config.display_language_selector, compression: config.compression, start_menu_folder: config.start_menu_folder, installer_hooks: config.installer_hooks, #[allow(deprecated)] minimum_webview2_version: config.minimum_webview2_version, } } pub fn custom_sign_settings( config: CustomSignCommandConfig, ) -> tauri_bundler::CustomSignCommandSettings { match config { CustomSignCommandConfig::Command(command) => { let mut tokens = command.split(' '); tauri_bundler::CustomSignCommandSettings { cmd: tokens.next().unwrap().to_string(), // split always has at least one element args: tokens.map(String::from).collect(), } } CustomSignCommandConfig::CommandWithOptions { cmd, args } => { tauri_bundler::CustomSignCommandSettings { cmd, args } } } } static CONFIG_SCHEMA_VALIDATOR: LazyLock<jsonschema::Validator> = LazyLock::new(|| { let schema: JsonValue = serde_json::from_str(include_str!("../../config.schema.json")) .expect("Failed to parse config schema bundled in the tauri-cli"); jsonschema::validator_for(&schema).expect("Config schema bundled in the tauri-cli is invalid") }); fn load_config( merge_configs: &[&serde_json::Value], reload: bool, target: Target, tauri_dir: &Path, ) -> crate::Result<ConfigMetadata> { let (mut config, config_path) = tauri_utils::config::parse::parse_value(target, tauri_dir.join("tauri.conf.json")) .context("failed to parse config")?; let config_file_name = config_path.file_name().unwrap(); let mut extensions = HashMap::new(); let original_identifier = config .as_object() .and_then(|config| config.get("identifier")?.as_str()) .map(ToString::to_string); if let Some((platform_config, config_path)) = tauri_utils::config::parse::read_platform(target, tauri_dir) .context("failed to parse platform config")? { merge(&mut config, &platform_config); extensions.insert(config_path.file_name().unwrap().into(), platform_config); } if !merge_configs.is_empty() { let mut merge_config = serde_json::Value::Object(Default::default()); for conf in merge_configs { merge_patches(&mut merge_config, conf); } let merge_config_str = serde_json::to_string(&merge_config).unwrap(); set_var("TAURI_CONFIG", merge_config_str); merge(&mut config, &merge_config); extensions.insert(MERGE_CONFIG_EXTENSION_NAME.into(), merge_config); } if config_path.extension() == Some(OsStr::new("json")) || config_path.extension() == Some(OsStr::new("json5")) { let mut errors = CONFIG_SCHEMA_VALIDATOR.iter_errors(&config).peekable(); if errors.peek().is_some() { for error in errors { let path = error.instance_path().into_iter().join(" > "); if path.is_empty() { log::error!("`{config_file_name:?}` error: {error}"); } else { log::error!("`{config_file_name:?}` error on `{path}`: {error}"); } } if !reload { exit(1); } } } // the `Config` deserializer for `package > version` can resolve the version from a path relative to the config path // so we actually need to change the current working directory here let current_dir = current_dir().context("failed to resolve current directory")?; set_current_dir(config_path.parent().unwrap()).context("failed to set current directory")?; let config: Config = serde_json::from_value(config).context("failed to parse config")?; // revert to previous working directory set_current_dir(current_dir).context("failed to set current directory")?; for (plugin, conf) in &config.plugins.0 { set_var( format!( "TAURI_{}_PLUGIN_CONFIG", plugin.to_uppercase().replace('-', "_") ), serde_json::to_string(&conf).context("failed to serialize config")?, ); } if config.build.remove_unused_commands { std::env::set_var(REMOVE_UNUSED_COMMANDS_ENV_VAR, tauri_dir); } Ok(ConfigMetadata { target, original_identifier, inner: config, extensions, }) } pub fn get_config( target: Target, merge_configs: &[&serde_json::Value], tauri_dir: &Path, ) -> crate::Result<ConfigMetadata> { load_config(merge_configs, false, target, tauri_dir) } pub fn reload_config( config: &mut ConfigMetadata, merge_configs: &[&serde_json::Value], tauri_dir: &Path, ) -> crate::Result<()> { let target = config.target; *config = load_config(merge_configs, true, target, tauri_dir)?; Ok(()) } /// merges the loaded config with the given value pub fn merge_config_with( config: &mut ConfigMetadata, merge_configs: &[&serde_json::Value], ) -> crate::Result<()> { if merge_configs.is_empty() { return Ok(()); } let mut merge_config = serde_json::Value::Object(Default::default()); for conf in merge_configs { merge_patches(&mut merge_config, conf); } let merge_config_str = serde_json::to_string(&merge_config).unwrap(); set_var("TAURI_CONFIG", merge_config_str); let mut value = serde_json::to_value(config.inner.clone()).context("failed to serialize config")?; merge(&mut value, &merge_config); config.inner = serde_json::from_value(value).context("failed to parse config")?; Ok(()) } /// Same as [`json_patch::merge`] but doesn't delete the key when the patch's value is `null` fn merge_patches(doc: &mut serde_json::Value, patch: &serde_json::Value) { use serde_json::{Map, Value}; if !patch.is_object() { *doc = patch.clone(); return; } if !doc.is_object() { *doc = Value::Object(Map::new()); } let map = doc.as_object_mut().unwrap(); for (key, value) in patch.as_object().unwrap() { merge_patches(map.entry(key.as_str()).or_insert(Value::Null), value); } } #[cfg(test)] mod tests { #[test] fn merge_patches() { let mut json = serde_json::Value::Object(Default::default()); super::merge_patches( &mut json, &serde_json::json!({ "app": { "withGlobalTauri": true, "windows": [] }, "plugins": { "test": "tauri" }, "build": { "devUrl": "http://localhost:8080" } }), ); super::merge_patches( &mut json, &serde_json::json!({ "app": { "withGlobalTauri": null } }), ); super::merge_patches( &mut json, &serde_json::json!({ "app": { "windows": null } }), ); super::merge_patches( &mut json, &serde_json::json!({ "plugins": { "updater": { "endpoints": ["https://tauri.app"] } } }), ); assert_eq!( json, serde_json::json!({ "app": { "withGlobalTauri": null, "windows": null }, "plugins": { "test": "tauri", "updater": { "endpoints": ["https://tauri.app"] } }, "build": { "devUrl": "http://localhost:8080" } }) ) } }