1use crate::embedded_assets::{AssetOptions, EmbeddedAssets, EmbeddedAssetsError};
6use proc_macro2::TokenStream;
7use quote::quote;
8use std::path::{Path, PathBuf};
9use tauri_utils::config::{AppUrl, Config, WindowUrl};
10
11pub struct ContextData {
13 pub dev: bool,
14 pub config: Config,
15 pub config_parent: PathBuf,
16 pub root: TokenStream,
17}
18
19pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsError> {
21 let ContextData {
22 dev,
23 config,
24 config_parent,
25 root,
26 } = data;
27
28 let mut options = AssetOptions::new();
29 if let Some(csp) = &config.tauri.security.csp {
30 options = options.csp(csp.clone());
31 }
32
33 let app_url = if dev {
34 &config.build.dev_path
35 } else {
36 &config.build.dist_dir
37 };
38
39 let assets = match app_url {
40 AppUrl::Url(url) => match url {
41 WindowUrl::External(_) => Default::default(),
42 WindowUrl::App(path) => {
43 if path.components().count() == 0 {
44 panic!(
45 "The `{}` configuration cannot be empty",
46 if dev { "devPath" } else { "distDir" }
47 )
48 }
49 let assets_path = config_parent.join(path);
50 if !assets_path.exists() {
51 panic!(
52 "The `{}` configuration is set to `{:?}` but this path doesn't exist",
53 if dev { "devPath" } else { "distDir" },
54 path
55 )
56 }
57 EmbeddedAssets::new(&assets_path, options)?
58 }
59 _ => unimplemented!(),
60 },
61 AppUrl::Files(files) => EmbeddedAssets::load_paths(
62 files.iter().map(|p| config_parent.join(p)).collect(),
63 options,
64 )?,
65 _ => unimplemented!(),
66 };
67
68 let default_window_icon = if cfg!(windows) {
70 let icon_path = find_icon(
71 &config,
72 &config_parent,
73 |i| i.ends_with(".ico"),
74 "icons/icon.ico",
75 );
76 quote!(Some(include_bytes!(#icon_path).to_vec()))
77 } else if cfg!(target_os = "linux") {
78 let icon_path = find_icon(
79 &config,
80 &config_parent,
81 |i| i.ends_with(".png"),
82 "icons/icon.png",
83 );
84 quote!(Some(include_bytes!(#icon_path).to_vec()))
85 } else {
86 quote!(None)
87 };
88
89 let package_name = if let Some(product_name) = &config.package.product_name {
90 quote!(#product_name.to_string())
91 } else {
92 quote!(env!("CARGO_PKG_NAME").to_string())
93 };
94 let package_version = if let Some(version) = &config.package.version {
95 quote!(#version.to_string())
96 } else {
97 quote!(env!("CARGO_PKG_VERSION").to_string())
98 };
99 let package_info = quote!(
100 #root::api::PackageInfo {
101 name: #package_name,
102 version: #package_version,
103 }
104 );
105
106 #[cfg(target_os = "linux")]
107 let system_tray_icon = if let Some(tray) = &config.tauri.system_tray {
108 let mut system_tray_icon_path = tray.icon_path.clone();
109 system_tray_icon_path.set_extension("png");
110 if dev {
111 let system_tray_icon_path = config_parent
112 .join(system_tray_icon_path)
113 .display()
114 .to_string();
115 quote!(Some(#root::Icon::File(::std::path::PathBuf::from(#system_tray_icon_path))))
116 } else {
117 let system_tray_icon_file_path = system_tray_icon_path.to_string_lossy().to_string();
118 quote!(
119 Some(
120 #root::Icon::File(
121 #root::api::path::resolve_path(
122 &#config, &#package_info,
123 #system_tray_icon_file_path,
124 Some(#root::api::path::BaseDirectory::Resource)
125 ).expect("failed to resolve resource dir")
126 )
127 )
128 )
129 }
130 } else {
131 quote!(None)
132 };
133
134 #[cfg(not(target_os = "linux"))]
135 let system_tray_icon = if let Some(tray) = &config.tauri.system_tray {
136 let mut system_tray_icon_path = tray.icon_path.clone();
137 system_tray_icon_path.set_extension(if cfg!(windows) { "ico" } else { "png" });
138 let system_tray_icon_path = config_parent
139 .join(system_tray_icon_path)
140 .display()
141 .to_string();
142 quote!(Some(#root::Icon::Raw(include_bytes!(#system_tray_icon_path).to_vec())))
143 } else {
144 quote!(None)
145 };
146
147 Ok(quote!(#root::Context::new(
149 #config,
150 ::std::sync::Arc::new(#assets),
151 #default_window_icon,
152 #system_tray_icon,
153 #package_info,
154 )))
155}
156
157fn find_icon<F: Fn(&&String) -> bool>(
158 config: &Config,
159 config_parent: &Path,
160 predicate: F,
161 default: &str,
162) -> String {
163 let icon_path = config
164 .tauri
165 .bundle
166 .icon
167 .iter()
168 .find(|i| predicate(i))
169 .cloned()
170 .unwrap_or_else(|| default.to_string());
171 config_parent.join(icon_path).display().to_string()
172}