2021-04-11 01:09:09 +03:00
|
|
|
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
2021-03-13 04:10:19 +03:00
|
|
|
#![cfg_attr(doc_cfg, feature(doc_cfg))]
|
|
|
|
|
|
|
|
pub use anyhow::Result;
|
|
|
|
|
2021-05-03 16:42:29 +03:00
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
|
2021-03-13 04:10:19 +03:00
|
|
|
#[cfg(feature = "codegen")]
|
|
|
|
mod codegen;
|
|
|
|
|
|
|
|
#[cfg(feature = "codegen")]
|
2021-08-13 17:40:57 +03:00
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "codegen")))]
|
2021-03-13 04:10:19 +03:00
|
|
|
pub use codegen::context::CodegenContext;
|
|
|
|
|
2021-05-03 16:42:29 +03:00
|
|
|
/// Attributes used on Windows.
|
|
|
|
#[allow(dead_code)]
|
2021-08-11 08:07:39 +03:00
|
|
|
#[derive(Debug)]
|
2021-05-03 16:42:29 +03:00
|
|
|
pub struct WindowsAttributes {
|
|
|
|
window_icon_path: PathBuf,
|
2021-11-16 17:18:13 +03:00
|
|
|
/// The path to the sdk location. This can be a absolute or relative path. If not supplied
|
|
|
|
/// this defaults to whatever `winres` crate determines is the best. See the
|
|
|
|
/// [winres documentation](https://docs.rs/winres/*/winres/struct.WindowsResource.html#method.set_toolkit_path)
|
|
|
|
sdk_dir: Option<PathBuf>,
|
2021-05-03 16:42:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for WindowsAttributes {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
window_icon_path: PathBuf::from("icons/icon.ico"),
|
2021-11-16 17:18:13 +03:00
|
|
|
sdk_dir: None,
|
2021-05-03 16:42:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl WindowsAttributes {
|
|
|
|
/// Creates the default attribute set.
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self::default()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the icon to use on the window. Currently only used on Windows.
|
|
|
|
/// It must be in `ico` format. Defaults to `icons/icon.ico`.
|
2022-01-17 16:46:14 +03:00
|
|
|
#[must_use]
|
2021-05-03 16:42:29 +03:00
|
|
|
pub fn window_icon_path<P: AsRef<Path>>(mut self, window_icon_path: P) -> Self {
|
|
|
|
self.window_icon_path = window_icon_path.as_ref().into();
|
|
|
|
self
|
|
|
|
}
|
2021-11-16 17:18:13 +03:00
|
|
|
|
|
|
|
/// Sets the sdk dir for windows. Currently only used on Windows. This must be a vaild UTF-8
|
|
|
|
/// path. Defaults to whatever the `winres` crate determines is best.
|
2022-01-17 16:46:14 +03:00
|
|
|
#[must_use]
|
2021-11-16 17:18:13 +03:00
|
|
|
pub fn sdk_dir<P: AsRef<Path>>(mut self, sdk_dir: P) -> Self {
|
|
|
|
self.sdk_dir = Some(sdk_dir.as_ref().into());
|
|
|
|
self
|
|
|
|
}
|
2021-05-03 16:42:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/// The attributes used on the build.
|
2021-08-11 08:07:39 +03:00
|
|
|
#[derive(Debug, Default)]
|
2021-05-03 16:42:29 +03:00
|
|
|
pub struct Attributes {
|
|
|
|
#[allow(dead_code)]
|
|
|
|
windows_attributes: WindowsAttributes,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Attributes {
|
|
|
|
/// Creates the default attribute set.
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self::default()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the icon to use on the window. Currently only used on Windows.
|
2022-01-17 16:46:14 +03:00
|
|
|
#[must_use]
|
2021-05-03 16:42:29 +03:00
|
|
|
pub fn windows_attributes(mut self, windows_attributes: WindowsAttributes) -> Self {
|
|
|
|
self.windows_attributes = windows_attributes;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-13 04:10:19 +03:00
|
|
|
/// Run all build time helpers for your Tauri Application.
|
|
|
|
///
|
|
|
|
/// The current helpers include the following:
|
|
|
|
/// * Generates a Windows Resource file when targeting Windows.
|
|
|
|
///
|
|
|
|
/// # Platforms
|
|
|
|
///
|
|
|
|
/// [`build()`] should be called inside of `build.rs` regardless of the platform:
|
|
|
|
/// * New helpers may target more platforms in the future.
|
|
|
|
/// * Platform specific code is handled by the helpers automatically.
|
|
|
|
/// * A build script is required in order to activate some cargo environmental variables that are
|
|
|
|
/// used when generating code and embedding assets - so [`build()`] may as well be called.
|
|
|
|
///
|
|
|
|
/// In short, this is saying don't put the call to [`build()`] behind a `#[cfg(windows)]`.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// If any of the build time helpers fail, they will [`std::panic!`] with the related error message.
|
|
|
|
/// This is typically desirable when running inside a build script; see [`try_build`] for no panics.
|
|
|
|
pub fn build() {
|
2021-05-03 16:42:29 +03:00
|
|
|
if let Err(error) = try_build(Attributes::default()) {
|
2021-03-13 04:10:19 +03:00
|
|
|
panic!("error found during tauri-build: {}", error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Non-panicking [`build()`].
|
2021-05-03 16:42:29 +03:00
|
|
|
#[allow(unused_variables)]
|
|
|
|
pub fn try_build(attributes: Attributes) -> Result<()> {
|
2022-01-09 16:55:09 +03:00
|
|
|
use anyhow::anyhow;
|
2021-10-25 17:50:38 +03:00
|
|
|
use cargo_toml::{Dependency, Manifest};
|
2022-02-04 19:37:23 +03:00
|
|
|
use tauri_utils::config::{Config, TauriConfig};
|
2022-01-09 16:55:09 +03:00
|
|
|
|
|
|
|
println!("cargo:rerun-if-changed=src/Cargo.toml");
|
2022-02-03 16:15:32 +03:00
|
|
|
println!("cargo:rerun-if-changed=tauri.conf.json");
|
|
|
|
#[cfg(feature = "config-json5")]
|
|
|
|
println!("cargo:rerun-if-changed=tauri.conf.json5");
|
|
|
|
|
|
|
|
let config: Config = if let Ok(env) = std::env::var("TAURI_CONFIG") {
|
|
|
|
serde_json::from_str(&env)?
|
|
|
|
} else {
|
|
|
|
serde_json::from_value(tauri_utils::config::parse::read_from(
|
|
|
|
std::env::current_dir().unwrap(),
|
|
|
|
)?)?
|
|
|
|
};
|
2022-01-09 16:55:09 +03:00
|
|
|
|
2021-10-25 17:50:38 +03:00
|
|
|
let mut manifest = Manifest::from_path("Cargo.toml")?;
|
|
|
|
if let Some(tauri) = manifest.dependencies.remove("tauri") {
|
2022-02-04 19:37:23 +03:00
|
|
|
let features = match tauri {
|
2021-10-25 17:50:38 +03:00
|
|
|
Dependency::Simple(_) => Vec::new(),
|
|
|
|
Dependency::Detailed(dep) => dep.features,
|
|
|
|
};
|
|
|
|
|
2022-02-04 19:37:23 +03:00
|
|
|
let all_cli_managed_features = TauriConfig::all_features();
|
|
|
|
let diff = features_diff(
|
|
|
|
&features
|
|
|
|
.into_iter()
|
|
|
|
.filter(|f| all_cli_managed_features.contains(&f.as_str()))
|
|
|
|
.collect::<Vec<String>>(),
|
|
|
|
&config
|
|
|
|
.tauri
|
|
|
|
.features()
|
|
|
|
.into_iter()
|
|
|
|
.map(|f| f.to_string())
|
|
|
|
.collect::<Vec<String>>(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut error_message = String::new();
|
|
|
|
if !diff.remove.is_empty() {
|
|
|
|
error_message.push_str("remove the `");
|
2022-02-04 20:03:27 +03:00
|
|
|
error_message.push_str(&diff.remove.join(", "));
|
2022-02-04 19:37:23 +03:00
|
|
|
error_message.push_str(if diff.remove.len() == 1 {
|
|
|
|
"` feature"
|
|
|
|
} else {
|
|
|
|
"` features"
|
|
|
|
});
|
|
|
|
if !diff.add.is_empty() {
|
|
|
|
error_message.push_str(" and ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !diff.add.is_empty() {
|
|
|
|
error_message.push_str("add the `");
|
2022-02-04 20:03:27 +03:00
|
|
|
error_message.push_str(&diff.add.join(", "));
|
2022-02-04 19:37:23 +03:00
|
|
|
error_message.push_str(if diff.add.len() == 1 {
|
|
|
|
"` feature"
|
|
|
|
} else {
|
|
|
|
"` features"
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if !error_message.is_empty() {
|
2021-10-25 17:50:38 +03:00
|
|
|
return Err(anyhow!("
|
2022-01-09 16:55:09 +03:00
|
|
|
The `tauri` dependency features on the `Cargo.toml` file does not match the allowlist defined under `tauri.conf.json`.
|
2022-02-04 19:37:23 +03:00
|
|
|
Please run `tauri dev` or `tauri build` or {}.
|
|
|
|
", error_message));
|
2021-10-25 17:50:38 +03:00
|
|
|
}
|
2022-01-09 16:55:09 +03:00
|
|
|
}
|
|
|
|
|
2021-03-13 04:10:19 +03:00
|
|
|
#[cfg(windows)]
|
|
|
|
{
|
2022-01-09 16:55:09 +03:00
|
|
|
use anyhow::Context;
|
2021-03-13 04:10:19 +03:00
|
|
|
use winres::WindowsResource;
|
|
|
|
|
2021-05-03 16:42:29 +03:00
|
|
|
let icon_path_string = attributes
|
|
|
|
.windows_attributes
|
|
|
|
.window_icon_path
|
|
|
|
.to_string_lossy()
|
|
|
|
.into_owned();
|
|
|
|
|
|
|
|
if attributes.windows_attributes.window_icon_path.exists() {
|
2021-03-13 04:10:19 +03:00
|
|
|
let mut res = WindowsResource::new();
|
2021-11-16 17:18:13 +03:00
|
|
|
if let Some(sdk_dir) = &attributes.windows_attributes.sdk_dir {
|
|
|
|
if let Some(sdk_dir_str) = sdk_dir.to_str() {
|
|
|
|
res.set_toolkit_path(sdk_dir_str);
|
|
|
|
} else {
|
|
|
|
return Err(anyhow!(
|
|
|
|
"sdk_dir path is not valid; only UTF-8 characters are allowed"
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
2021-06-05 07:16:54 +03:00
|
|
|
if let Some(version) = &config.package.version {
|
|
|
|
res.set("FileVersion", version);
|
|
|
|
res.set("ProductVersion", version);
|
|
|
|
}
|
|
|
|
if let Some(product_name) = &config.package.product_name {
|
|
|
|
res.set("ProductName", product_name);
|
|
|
|
res.set("FileDescription", product_name);
|
|
|
|
}
|
2021-05-03 16:42:29 +03:00
|
|
|
res.set_icon_with_id(&icon_path_string, "32512");
|
2021-03-13 04:10:19 +03:00
|
|
|
res.compile().with_context(|| {
|
2021-05-03 16:42:29 +03:00
|
|
|
format!(
|
|
|
|
"failed to compile `{}` into a Windows Resource file during tauri-build",
|
|
|
|
icon_path_string
|
|
|
|
)
|
2021-03-13 04:10:19 +03:00
|
|
|
})?;
|
|
|
|
} else {
|
2021-05-03 16:42:29 +03:00
|
|
|
return Err(anyhow!(format!(
|
|
|
|
"`{}` not found; required for generating a Windows Resource file during tauri-build",
|
|
|
|
icon_path_string
|
|
|
|
)));
|
2021-03-13 04:10:19 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-02-04 19:37:23 +03:00
|
|
|
|
|
|
|
#[derive(Debug, Default, PartialEq, Eq)]
|
|
|
|
struct Diff {
|
|
|
|
remove: Vec<String>,
|
|
|
|
add: Vec<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn features_diff(current: &[String], expected: &[String]) -> Diff {
|
|
|
|
let mut remove = Vec::new();
|
|
|
|
let mut add = Vec::new();
|
|
|
|
for feature in current {
|
2022-02-04 20:03:27 +03:00
|
|
|
if !expected.contains(feature) {
|
2022-02-04 19:37:23 +03:00
|
|
|
remove.push(feature.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for feature in expected {
|
|
|
|
if !current.contains(feature) {
|
|
|
|
add.push(feature.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Diff { remove, add }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::Diff;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn array_diff() {
|
|
|
|
for (current, expected, result) in [
|
|
|
|
(vec![], vec![], Default::default()),
|
|
|
|
(
|
|
|
|
vec!["a".into()],
|
|
|
|
vec![],
|
|
|
|
Diff {
|
|
|
|
remove: vec!["a".into()],
|
|
|
|
add: vec![],
|
|
|
|
},
|
|
|
|
),
|
|
|
|
(vec!["a".into()], vec!["a".into()], Default::default()),
|
|
|
|
(
|
|
|
|
vec!["a".into(), "b".into()],
|
|
|
|
vec!["a".into()],
|
|
|
|
Diff {
|
|
|
|
remove: vec!["b".into()],
|
|
|
|
add: vec![],
|
|
|
|
},
|
|
|
|
),
|
|
|
|
(
|
|
|
|
vec!["a".into(), "b".into()],
|
|
|
|
vec!["a".into(), "c".into()],
|
|
|
|
Diff {
|
|
|
|
remove: vec!["b".into()],
|
|
|
|
add: vec!["c".into()],
|
|
|
|
},
|
|
|
|
),
|
|
|
|
] {
|
|
|
|
assert_eq!(super::features_diff(¤t, &expected), result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|