mod.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // Copyright 2016-2019 Cargo-Bundle developers <https://github.com/burtonageo/cargo-bundle>
  2. // Copyright 2019-2024 Tauri Programme within The Commons Conservancy
  3. // SPDX-License-Identifier: Apache-2.0
  4. // SPDX-License-Identifier: MIT
  5. use super::{
  6. super::{
  7. common::{self, CommandExt},
  8. path_utils,
  9. },
  10. debian,
  11. };
  12. use crate::{bundle::settings::Arch, Settings};
  13. use anyhow::Context;
  14. use handlebars::Handlebars;
  15. use std::{
  16. collections::BTreeMap,
  17. fs,
  18. path::PathBuf,
  19. process::{Command, Stdio},
  20. };
  21. /// Bundles the project.
  22. /// Returns a vector of PathBuf that shows where the AppImage was created.
  23. pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
  24. // generate the deb binary name
  25. let arch: &str = match settings.binary_arch() {
  26. Arch::X86_64 => "amd64",
  27. Arch::X86 => "i386",
  28. Arch::AArch64 => "aarch64",
  29. Arch::Armhf => "armhf",
  30. target => {
  31. return Err(crate::Error::ArchError(format!(
  32. "Unsupported architecture: {:?}",
  33. target
  34. )));
  35. }
  36. };
  37. let package_dir = settings.project_out_directory().join("bundle/appimage_deb");
  38. let main_binary = settings.main_binary()?;
  39. let mut settings = settings.clone();
  40. if main_binary.name().contains(" ") {
  41. let main_binary_path = settings.binary_path(main_binary);
  42. let project_out_directory = settings.project_out_directory();
  43. let main_binary_name_kebab = heck::AsKebabCase(main_binary.name()).to_string();
  44. let new_path = project_out_directory.join(&main_binary_name_kebab);
  45. fs::copy(main_binary_path, new_path)?;
  46. let main_binary = settings.main_binary_mut()?;
  47. main_binary.set_name(main_binary_name_kebab);
  48. }
  49. // generate deb_folder structure
  50. let (data_dir, icons) = debian::generate_data(&settings, &package_dir)
  51. .with_context(|| "Failed to build data folders and files")?;
  52. common::copy_custom_files(&settings.appimage().files, &data_dir)
  53. .with_context(|| "Failed to copy custom files")?;
  54. let output_path = settings.project_out_directory().join("bundle/appimage");
  55. if output_path.exists() {
  56. fs::remove_dir_all(&output_path)?;
  57. }
  58. fs::create_dir_all(output_path.clone())?;
  59. let app_dir_path = output_path.join(format!("{}.AppDir", settings.product_name()));
  60. let appimage_filename = format!(
  61. "{}_{}_{}.AppImage",
  62. settings.product_name(),
  63. settings.version_string(),
  64. arch
  65. );
  66. let appimage_path = output_path.join(&appimage_filename);
  67. path_utils::create(app_dir_path, true)?;
  68. // setup data to insert into shell script
  69. let mut sh_map = BTreeMap::new();
  70. sh_map.insert("arch", settings.target().split('-').next().unwrap());
  71. sh_map.insert("product_name", settings.product_name());
  72. sh_map.insert("appimage_filename", &appimage_filename);
  73. let tauri_tools_path = settings
  74. .local_tools_directory()
  75. .map(|d| d.join(".tauri"))
  76. .unwrap_or_else(|| {
  77. dirs::cache_dir().map_or_else(|| output_path.to_path_buf(), |p| p.join("tauri"))
  78. });
  79. std::fs::create_dir_all(&tauri_tools_path)?;
  80. let tauri_tools_path_str = tauri_tools_path.to_string_lossy();
  81. sh_map.insert("tauri_tools_path", &tauri_tools_path_str);
  82. let larger_icon = icons
  83. .iter()
  84. .filter(|i| i.width == i.height)
  85. .max_by_key(|i| i.width)
  86. .expect("couldn't find a square icon to use as AppImage icon");
  87. let larger_icon_path = larger_icon
  88. .path
  89. .strip_prefix(package_dir.join("data"))
  90. .unwrap()
  91. .to_string_lossy()
  92. .to_string();
  93. sh_map.insert("icon_path", &larger_icon_path);
  94. // initialize shell script template.
  95. let mut handlebars = Handlebars::new();
  96. handlebars.register_escape_fn(handlebars::no_escape);
  97. handlebars
  98. .register_template_string("appimage", include_str!("./appimage"))
  99. .expect("Failed to register template for handlebars");
  100. let temp = handlebars.render("appimage", &sh_map)?;
  101. // create the shell script file in the target/ folder.
  102. let sh_file = output_path.join("build_appimage.sh");
  103. log::info!(action = "Bundling"; "{} ({})", appimage_filename, appimage_path.display());
  104. fs::write(&sh_file, temp)?;
  105. // chmod script for execution
  106. Command::new("chmod")
  107. .arg("777")
  108. .arg(&sh_file)
  109. .current_dir(output_path.clone())
  110. .stdout(Stdio::piped())
  111. .stderr(Stdio::piped())
  112. .output()
  113. .expect("Failed to chmod script");
  114. // execute the shell script to build the appimage.
  115. Command::new(&sh_file)
  116. .current_dir(output_path)
  117. .output_ok()
  118. .context("error running build_appimage.sh")?;
  119. fs::remove_dir_all(&package_dir)?;
  120. Ok(vec![appimage_path])
  121. }