bundle.rs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. use core::panic;
  2. use std::{fs::create_dir_all, str::FromStr};
  3. use tauri_bundler::{BundleSettings, PackageSettings, SettingsBuilder};
  4. use super::*;
  5. use crate::{build_desktop, cfg::ConfigOptsBundle};
  6. /// Bundle the Rust desktop app and all of its assets
  7. #[derive(Clone, Debug, Parser)]
  8. #[clap(name = "bundle")]
  9. pub struct Bundle {
  10. #[clap(long)]
  11. pub package: Option<Vec<String>>,
  12. #[clap(flatten)]
  13. pub build: ConfigOptsBundle,
  14. }
  15. #[derive(Clone, Debug)]
  16. pub enum PackageType {
  17. MacOsBundle,
  18. IosBundle,
  19. WindowsMsi,
  20. Deb,
  21. Rpm,
  22. AppImage,
  23. Dmg,
  24. Updater,
  25. }
  26. impl FromStr for PackageType {
  27. type Err = String;
  28. fn from_str(s: &str) -> Result<Self, Self::Err> {
  29. match s {
  30. "macos" => Ok(PackageType::MacOsBundle),
  31. "ios" => Ok(PackageType::IosBundle),
  32. "msi" => Ok(PackageType::WindowsMsi),
  33. "deb" => Ok(PackageType::Deb),
  34. "rpm" => Ok(PackageType::Rpm),
  35. "appimage" => Ok(PackageType::AppImage),
  36. "dmg" => Ok(PackageType::Dmg),
  37. _ => Err(format!("{} is not a valid package type", s)),
  38. }
  39. }
  40. }
  41. impl From<PackageType> for tauri_bundler::PackageType {
  42. fn from(val: PackageType) -> Self {
  43. match val {
  44. PackageType::MacOsBundle => tauri_bundler::PackageType::MacOsBundle,
  45. PackageType::IosBundle => tauri_bundler::PackageType::IosBundle,
  46. PackageType::WindowsMsi => tauri_bundler::PackageType::WindowsMsi,
  47. PackageType::Deb => tauri_bundler::PackageType::Deb,
  48. PackageType::Rpm => tauri_bundler::PackageType::Rpm,
  49. PackageType::AppImage => tauri_bundler::PackageType::AppImage,
  50. PackageType::Dmg => tauri_bundler::PackageType::Dmg,
  51. PackageType::Updater => tauri_bundler::PackageType::Updater,
  52. }
  53. }
  54. }
  55. impl Bundle {
  56. pub fn bundle(self, bin: Option<PathBuf>) -> Result<()> {
  57. let mut crate_config = crate::CrateConfig::new(bin)?;
  58. // change the release state.
  59. crate_config.with_release(self.build.release);
  60. crate_config.with_verbose(self.build.verbose);
  61. if self.build.example.is_some() {
  62. crate_config.as_example(self.build.example.unwrap());
  63. }
  64. if self.build.profile.is_some() {
  65. crate_config.set_profile(self.build.profile.unwrap());
  66. }
  67. // build the desktop app
  68. build_desktop(&crate_config, false)?;
  69. // copy the binary to the out dir
  70. let package = crate_config.manifest.package.unwrap();
  71. let mut name: PathBuf = match &crate_config.executable {
  72. crate::ExecutableType::Binary(name)
  73. | crate::ExecutableType::Lib(name)
  74. | crate::ExecutableType::Example(name) => name,
  75. }
  76. .into();
  77. if cfg!(windows) {
  78. name.set_extension("exe");
  79. }
  80. // bundle the app
  81. let binaries = vec![
  82. tauri_bundler::BundleBinary::new(name.display().to_string(), true)
  83. .set_src_path(Some(crate_config.crate_dir.display().to_string())),
  84. ];
  85. let mut bundle_settings: BundleSettings = crate_config.dioxus_config.bundle.clone().into();
  86. if cfg!(windows) {
  87. let windows_icon_override = crate_config
  88. .dioxus_config
  89. .bundle
  90. .windows
  91. .as_ref()
  92. .map(|w| &w.icon_path);
  93. if windows_icon_override.is_none() {
  94. let icon_path = bundle_settings
  95. .icon
  96. .as_ref()
  97. .and_then(|icons| icons.first());
  98. let icon_path = if let Some(icon_path) = icon_path {
  99. icon_path.into()
  100. } else {
  101. let path = PathBuf::from("./icons/icon.ico");
  102. // create the icon if it doesn't exist
  103. if !path.exists() {
  104. create_dir_all(path.parent().unwrap()).unwrap();
  105. let mut file = File::create(&path).unwrap();
  106. file.write_all(include_bytes!("../assets/icon.ico"))
  107. .unwrap();
  108. }
  109. path
  110. };
  111. bundle_settings.windows.icon_path = icon_path;
  112. }
  113. }
  114. let mut settings = SettingsBuilder::new()
  115. .project_out_directory(crate_config.out_dir)
  116. .package_settings(PackageSettings {
  117. product_name: crate_config.dioxus_config.application.name.clone(),
  118. version: package.version().to_string(),
  119. description: package.description().unwrap_or_default().to_string(),
  120. homepage: Some(package.homepage().unwrap_or_default().to_string()),
  121. authors: Some(Vec::from(package.authors())),
  122. default_run: Some(crate_config.dioxus_config.application.name.clone()),
  123. })
  124. .binaries(binaries)
  125. .bundle_settings(bundle_settings);
  126. if let Some(packages) = self.package {
  127. settings = settings.package_types(
  128. packages
  129. .into_iter()
  130. .map(|p| p.parse::<PackageType>().unwrap().into())
  131. .collect(),
  132. );
  133. }
  134. let settings = settings.build();
  135. // on macos we need to set CI=true (https://github.com/tauri-apps/tauri/issues/2567)
  136. #[cfg(target_os = "macos")]
  137. std::env::set_var("CI", "true");
  138. tauri_bundler::bundle::bundle_project(settings.unwrap()).unwrap_or_else(|err|{
  139. #[cfg(target_os = "macos")]
  140. panic!("Failed to bundle project: {}\nMake sure you have automation enabled in your terminal (https://github.com/tauri-apps/tauri/issues/3055#issuecomment-1624389208) and full disk access enabled for your terminal (https://github.com/tauri-apps/tauri/issues/3055#issuecomment-1624389208)", err);
  141. #[cfg(not(target_os = "macos"))]
  142. panic!("Failed to bundle project: {}", err);
  143. });
  144. Ok(())
  145. }
  146. }