main.rs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. pub use anyhow::Result;
  5. use clap::{crate_version, load_yaml, App, AppSettings, ArgMatches};
  6. use dialoguer::Input;
  7. use serde::Deserialize;
  8. mod build;
  9. mod dev;
  10. mod helpers;
  11. mod info;
  12. mod init;
  13. mod interface;
  14. mod sign;
  15. // temporary fork from https://github.com/mitsuhiko/console until 0.14.1+ release
  16. #[allow(dead_code)]
  17. mod console;
  18. // temporary fork from https://github.com/mitsuhiko/dialoguer until 0.8.0+ release
  19. #[allow(dead_code)]
  20. mod dialoguer;
  21. use helpers::framework::{infer_from_package_json as infer_framework, Framework};
  22. use std::{env::current_dir, fs::read_to_string, path::PathBuf};
  23. #[derive(Deserialize)]
  24. struct PackageJson {
  25. name: Option<String>,
  26. product_name: Option<String>,
  27. }
  28. #[derive(Default)]
  29. struct InitDefaults {
  30. app_name: Option<String>,
  31. framework: Option<Framework>,
  32. }
  33. macro_rules! value_or_prompt {
  34. ($init_runner: ident, $setter_fn: ident, $value: ident, $ci: ident, $prompt_message: expr, $prompt_default: expr) => {{
  35. let mut init_runner = $init_runner;
  36. if let Some(value) = $value {
  37. init_runner = init_runner.$setter_fn(value);
  38. } else if !$ci {
  39. let mut builder = Input::<String>::new();
  40. builder.with_prompt($prompt_message);
  41. if let Some(default) = $prompt_default {
  42. builder.default(default);
  43. }
  44. let input = builder.interact_text()?;
  45. init_runner = init_runner.$setter_fn(input);
  46. }
  47. init_runner
  48. }};
  49. }
  50. fn init_command(matches: &ArgMatches) -> Result<()> {
  51. let force = matches.is_present("force");
  52. let directory = matches.value_of("directory");
  53. let tauri_path = matches.value_of("tauri-path");
  54. let app_name = matches.value_of("app-name");
  55. let window_title = matches.value_of("window-title");
  56. let dist_dir = matches.value_of("dist-dir");
  57. let dev_path = matches.value_of("dev-path");
  58. let ci = matches.is_present("ci") || std::env::var("CI").is_ok();
  59. let mut init_runner = init::Init::new();
  60. if force {
  61. init_runner = init_runner.force();
  62. }
  63. let base_directory = if let Some(directory) = directory {
  64. init_runner = init_runner.directory(directory);
  65. PathBuf::from(directory)
  66. } else {
  67. current_dir().expect("failed to read cwd")
  68. };
  69. if let Some(tauri_path) = tauri_path {
  70. init_runner = init_runner.tauri_path(tauri_path);
  71. }
  72. let package_json_path = base_directory.join("package.json");
  73. let init_defaults = if package_json_path.exists() {
  74. let package_json_text = read_to_string(package_json_path)?;
  75. let package_json: PackageJson = serde_json::from_str(&package_json_text)?;
  76. let (framework, _) = infer_framework(&package_json_text);
  77. InitDefaults {
  78. app_name: package_json.product_name.or(package_json.name),
  79. framework,
  80. }
  81. } else {
  82. Default::default()
  83. };
  84. init_runner = value_or_prompt!(
  85. init_runner,
  86. app_name,
  87. app_name,
  88. ci,
  89. "What is your app name?",
  90. init_defaults.app_name.clone()
  91. );
  92. init_runner = value_or_prompt!(
  93. init_runner,
  94. window_title,
  95. window_title,
  96. ci,
  97. "What should the window title be?",
  98. init_defaults.app_name.clone()
  99. );
  100. init_runner = value_or_prompt!(
  101. init_runner,
  102. dist_dir,
  103. dist_dir,
  104. ci,
  105. r#"Where are your web assets (HTML/CSS/JS) located, relative to the "<current dir>/src-tauri" folder that will be created?"#,
  106. init_defaults.framework.as_ref().map(|f| f.dist_dir())
  107. );
  108. init_runner = value_or_prompt!(
  109. init_runner,
  110. dev_path,
  111. dev_path,
  112. ci,
  113. "What is the url of your dev server?",
  114. init_defaults.framework.map(|f| f.dev_path())
  115. );
  116. init_runner.run()
  117. }
  118. fn dev_command(matches: &ArgMatches) -> Result<()> {
  119. let runner = matches.value_of("runner");
  120. let target = matches.value_of("target");
  121. let features: Vec<String> = matches
  122. .values_of("features")
  123. .map(|a| a.into_iter().map(|v| v.to_string()).collect())
  124. .unwrap_or_default();
  125. let exit_on_panic = matches.is_present("exit-on-panic");
  126. let config = matches.value_of("config");
  127. let args: Vec<String> = matches
  128. .values_of("args")
  129. .map(|a| a.into_iter().map(|v| v.to_string()).collect())
  130. .unwrap_or_default();
  131. let mut dev_runner = dev::Dev::new()
  132. .exit_on_panic(exit_on_panic)
  133. .args(args)
  134. .features(features);
  135. if let Some(runner) = runner {
  136. dev_runner = dev_runner.runner(runner.to_string());
  137. }
  138. if let Some(target) = target {
  139. dev_runner = dev_runner.target(target.to_string());
  140. }
  141. if let Some(config) = config {
  142. dev_runner = dev_runner.config(config.to_string());
  143. }
  144. dev_runner.run()
  145. }
  146. fn build_command(matches: &ArgMatches) -> Result<()> {
  147. let runner = matches.value_of("runner");
  148. let target = matches.value_of("target");
  149. let features: Vec<String> = matches
  150. .values_of("features")
  151. .map(|a| a.into_iter().map(|v| v.to_string()).collect())
  152. .unwrap_or_default();
  153. let debug = matches.is_present("debug");
  154. let verbose = matches.is_present("verbose");
  155. let bundles = matches.values_of_lossy("bundle");
  156. let config = matches.value_of("config");
  157. let mut build_runner = build::Build::new().features(features);
  158. if let Some(runner) = runner {
  159. build_runner = build_runner.runner(runner.to_string());
  160. }
  161. if let Some(target) = target {
  162. build_runner = build_runner.target(target.to_string());
  163. }
  164. if debug {
  165. build_runner = build_runner.debug();
  166. }
  167. if verbose {
  168. build_runner = build_runner.verbose();
  169. }
  170. if let Some(bundles) = bundles {
  171. build_runner = build_runner.bundles(bundles);
  172. }
  173. if let Some(config) = config {
  174. build_runner = build_runner.config(config.to_string());
  175. }
  176. build_runner.run()
  177. }
  178. fn info_command() -> Result<()> {
  179. info::Info::new().run()
  180. }
  181. fn sign_command(matches: &ArgMatches) -> Result<()> {
  182. let private_key = matches.value_of("private-key");
  183. let private_key_path = matches.value_of("private-key-path");
  184. let file = matches.value_of("sign-file");
  185. let password = matches.value_of("password");
  186. let no_password = matches.is_present("no-password");
  187. let write_keys = matches.value_of("write-keys");
  188. let force = matches.is_present("force");
  189. // generate keypair
  190. if matches.is_present("generate") {
  191. let mut keygen_runner = sign::KeyGenerator::new();
  192. if no_password {
  193. keygen_runner = keygen_runner.empty_password();
  194. }
  195. if force {
  196. keygen_runner = keygen_runner.force();
  197. }
  198. if let Some(write_keys) = write_keys {
  199. keygen_runner = keygen_runner.output_path(write_keys);
  200. }
  201. if let Some(password) = password {
  202. keygen_runner = keygen_runner.password(password);
  203. }
  204. return keygen_runner.generate_keys();
  205. }
  206. // sign our binary / archive
  207. let mut sign_runner = sign::Signer::new();
  208. if let Some(private_key) = private_key {
  209. sign_runner = sign_runner.private_key(private_key);
  210. }
  211. if let Some(private_key_path) = private_key_path {
  212. sign_runner = sign_runner.private_key_path(private_key_path);
  213. }
  214. if let Some(file) = file {
  215. sign_runner = sign_runner.file_to_sign(file);
  216. }
  217. if let Some(password) = password {
  218. sign_runner = sign_runner.password(password);
  219. }
  220. if no_password {
  221. sign_runner = sign_runner.empty_password();
  222. }
  223. sign_runner.run()
  224. }
  225. fn main() -> Result<()> {
  226. let yaml = load_yaml!("cli.yml");
  227. let app = App::from(yaml)
  228. .version(crate_version!())
  229. .setting(AppSettings::ArgRequiredElseHelp)
  230. .setting(AppSettings::GlobalVersion)
  231. .setting(AppSettings::SubcommandRequired);
  232. let app_matches = app.get_matches();
  233. let matches = app_matches.subcommand_matches("tauri").unwrap();
  234. if let Some(matches) = matches.subcommand_matches("init") {
  235. init_command(&matches)?;
  236. } else if let Some(matches) = matches.subcommand_matches("dev") {
  237. dev_command(&matches)?;
  238. } else if let Some(matches) = matches.subcommand_matches("build") {
  239. build_command(&matches)?;
  240. } else if matches.subcommand_matches("info").is_some() {
  241. info_command()?;
  242. } else if let Some(matches) = matches.subcommand_matches("sign") {
  243. sign_command(&matches)?;
  244. }
  245. Ok(())
  246. }