project.rs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. use crate::helpers::template;
  5. use cargo_mobile::{
  6. android::{
  7. config::{Config, Metadata},
  8. env::Env,
  9. ndk,
  10. target::Target,
  11. },
  12. dot_cargo, os,
  13. target::TargetTrait as _,
  14. util::{
  15. self,
  16. cli::{Report, TextWrapper},
  17. ln, prefix_path,
  18. },
  19. };
  20. use handlebars::Handlebars;
  21. use include_dir::{include_dir, Dir};
  22. use std::{
  23. ffi::OsStr,
  24. fs,
  25. path::{Path, PathBuf},
  26. };
  27. const TEMPLATE_DIR: Dir<'_> = include_dir!("templates/mobile/android");
  28. #[derive(Debug, thiserror::Error)]
  29. pub enum Error {
  30. #[error("failed to run rustup: {0}")]
  31. RustupFailed(bossy::Error),
  32. #[error("failed to process template: {0}")]
  33. TemplateProcessingFailed(String),
  34. #[error("failed to create directory at {path}: {cause}")]
  35. DirectoryCreationFailed {
  36. path: PathBuf,
  37. cause: std::io::Error,
  38. },
  39. #[error("failed to symlink asset directory")]
  40. AssetDirSymlinkFailed,
  41. #[error(transparent)]
  42. DotCargoGenFailed(ndk::MissingToolError),
  43. #[error("failed to copy {src} to {dest}: {cause}")]
  44. FileCopyFailed {
  45. src: PathBuf,
  46. dest: PathBuf,
  47. cause: std::io::Error,
  48. },
  49. #[error("asset source {0} is invalid")]
  50. AssetSourceInvalid(PathBuf),
  51. }
  52. pub fn gen(
  53. config: &Config,
  54. metadata: &Metadata,
  55. env: &Env,
  56. (handlebars, mut map): (Handlebars, template::JsonMap),
  57. wrapper: &TextWrapper,
  58. dot_cargo: &mut dot_cargo::DotCargo,
  59. ) -> Result<(), Error> {
  60. println!("Installing Android toolchains...");
  61. Target::install_all().map_err(Error::RustupFailed)?;
  62. println!("Generating Android Studio project...");
  63. let dest = config.project_dir();
  64. let asset_packs = metadata.asset_packs().unwrap_or_default();
  65. map.insert(
  66. "root-dir-rel",
  67. Path::new(&os::replace_path_separator(
  68. util::relativize_path(
  69. config.app().root_dir(),
  70. config.project_dir().join(config.app().name()),
  71. )
  72. .into_os_string(),
  73. )),
  74. );
  75. map.insert("root-dir", config.app().root_dir());
  76. map.insert("targets", Target::all().values().collect::<Vec<_>>());
  77. map.insert("target-names", Target::all().keys().collect::<Vec<_>>());
  78. map.insert(
  79. "arches",
  80. Target::all()
  81. .values()
  82. .map(|target| target.arch)
  83. .collect::<Vec<_>>(),
  84. );
  85. map.insert("android-app-plugins", metadata.app_plugins());
  86. map.insert(
  87. "android-project-dependencies",
  88. metadata.project_dependencies(),
  89. );
  90. map.insert("android-app-dependencies", metadata.app_dependencies());
  91. map.insert(
  92. "android-app-dependencies-platform",
  93. metadata.app_dependencies_platform(),
  94. );
  95. map.insert(
  96. "has-code",
  97. metadata.project_dependencies().is_some()
  98. || metadata.app_dependencies().is_some()
  99. || metadata.app_dependencies_platform().is_some(),
  100. );
  101. map.insert(
  102. "asset-packs",
  103. asset_packs
  104. .iter()
  105. .map(|p| p.name.as_str())
  106. .collect::<Vec<_>>(),
  107. );
  108. map.insert("windows", cfg!(windows));
  109. let domain = config.app().reverse_domain().replace('.', "/");
  110. let package_path = format!("java/{}/{}", domain, config.app().name());
  111. let mut created_dirs = Vec::new();
  112. template::render_with_generator(
  113. &handlebars,
  114. map.inner(),
  115. &TEMPLATE_DIR,
  116. &dest,
  117. &mut |path| {
  118. let path = if path.extension() == Some(OsStr::new("kt")) {
  119. let parent = path.parent().unwrap();
  120. let file_name = path.file_name().unwrap();
  121. let out_dir = dest.join(parent).join(&package_path);
  122. out_dir.join(file_name)
  123. } else {
  124. dest.join(path)
  125. };
  126. let parent = path.parent().unwrap().to_path_buf();
  127. if !created_dirs.contains(&parent) {
  128. fs::create_dir_all(&parent)?;
  129. created_dirs.push(parent);
  130. }
  131. fs::File::create(path)
  132. },
  133. )
  134. .map_err(|e| Error::TemplateProcessingFailed(e.to_string()))?;
  135. if !asset_packs.is_empty() {
  136. Report::action_request(
  137. "When running from Android Studio, you must first set your deployment option to \"APK from app bundle\".",
  138. "Android Studio will not be able to find your asset packs otherwise. The option can be found under \"Run > Edit Configurations > Deploy\"."
  139. ).print(wrapper);
  140. }
  141. let source_dest = dest.join("app");
  142. for source in metadata.app_sources() {
  143. let source_src = config.app().root_dir().join(&source);
  144. let source_file = source_src
  145. .file_name()
  146. .ok_or_else(|| Error::AssetSourceInvalid(source_src.clone()))?;
  147. fs::copy(&source_src, source_dest.join(source_file)).map_err(|cause| {
  148. Error::FileCopyFailed {
  149. src: source_src,
  150. dest: source_dest.clone(),
  151. cause,
  152. }
  153. })?;
  154. }
  155. let dest = prefix_path(dest, "app/src/main/");
  156. fs::create_dir_all(&dest).map_err(|cause| Error::DirectoryCreationFailed {
  157. path: dest.clone(),
  158. cause,
  159. })?;
  160. os::ln::force_symlink_relative(config.app().asset_dir(), dest, ln::TargetStyle::Directory)
  161. .map_err(|_| Error::AssetDirSymlinkFailed)?;
  162. {
  163. for target in Target::all().values() {
  164. dot_cargo.insert_target(
  165. target.triple.to_owned(),
  166. target
  167. .generate_cargo_config(config, env)
  168. .map_err(Error::DotCargoGenFailed)?,
  169. );
  170. }
  171. }
  172. Ok(())
  173. }