tauri_codegen/
context.rs

1// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
2// SPDX-License-Identifier: Apache-2.0
3// SPDX-License-Identifier: MIT
4
5use 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
11/// Necessary data needed by [`context_codegen`] to generate code for a Tauri application context.
12pub struct ContextData {
13  pub dev: bool,
14  pub config: Config,
15  pub config_parent: PathBuf,
16  pub root: TokenStream,
17}
18
19/// Build a `tauri::Context` for including in application code.
20pub 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  // handle default window icons for Windows targets
69  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  // double braces are purposeful to force the code into a block expression
148  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}