cli/commands/build/
apple.rs1use super::{BuildContext, SharedBuildCommand};
2use crate::error::*;
3use apple_bundle::prelude::InfoPlist;
4use clap::Clap;
5use creator_tools::{commands::apple, types::*, utils::Config};
6use std::path::{Path, PathBuf};
7
8#[derive(Clap, Clone, Debug)]
9pub struct AppleBuildCommand {
10 #[clap(flatten)]
11 pub shared: SharedBuildCommand,
12 #[clap(long, conflicts_with = "example")]
14 pub bin: Option<String>,
15 #[clap(long, default_value = "aarch64-apple-ios")]
18 pub target: Vec<AppleTarget>,
19 #[clap(long, conflicts_with = "profile-path")]
21 pub profile_name: Option<String>,
22 #[clap(long)]
24 pub profile_path: Option<PathBuf>,
25 #[clap(long)]
27 pub team_identifier: Option<String>,
28 #[clap(long)]
30 pub identity: Option<String>,
31}
32
33impl AppleBuildCommand {
34 pub fn run(&self, config: &Config) -> Result<()> {
35 let context = BuildContext::new(config, self.shared.target_dir.clone())?;
36 self.execute(config, &context)?;
37 Ok(())
38 }
39
40 pub fn execute(
41 &self,
42 config: &Config,
43 context: &BuildContext,
44 ) -> Result<(InfoPlist, Vec<PathBuf>)> {
45 let project_path = &context.project_path;
46 let profile = self.shared.profile();
47 let (target, package_name) = if let Some(example) = &self.shared.example {
48 (Target::Example(example.clone()), example.clone())
49 } else if let Some(bin) = &self.bin {
50 (Target::Bin(bin.clone()), bin.clone())
51 } else {
52 (Target::Bin(context.package_name()), context.package_name())
53 };
54 let properties = context.gen_info_plist(&package_name)?;
55 config.status_message("Starting build process", &package_name)?;
56 config.status("Compiling app")?;
57 let build_targets = context.apple_build_targets(&self.target);
58 let mut app_paths = vec![];
59 for build_target in build_targets {
60 let app_path = self.build_app(
61 config,
62 context,
63 target.clone(),
64 project_path,
65 build_target,
66 &properties,
67 profile,
68 &package_name,
69 )?;
70 app_paths.push(app_path);
71 }
72 Ok((properties, app_paths))
73 }
74
75 fn build_app(
76 &self,
77 config: &Config,
78 context: &BuildContext,
79 target: Target,
80 project_path: &Path,
81 build_target: AppleTarget,
82 properties: &InfoPlist,
83 profile: Profile,
84 name: &str,
85 ) -> Result<PathBuf> {
86 let rust_triple = build_target.rust_triple();
87 config.status_message("Compiling for architecture", rust_triple)?;
88 apple::compile_rust_for_ios(
89 target,
90 build_target,
91 &project_path,
92 profile,
93 self.shared.features.clone(),
94 self.shared.all_features,
95 self.shared.no_default_features,
96 )?;
97 let out_dir = context.target_dir.join(rust_triple).join(&profile);
98 let bin_path = out_dir.join(&name);
99 config.status("Generating app folder")?;
100 let apple_target_dir = &context
101 .target_dir
102 .join("apple")
103 .join(rust_triple)
104 .join(&profile);
105 let app_path = apple::gen_apple_app_folder(
106 &apple_target_dir,
107 &name,
108 context.apple_res().as_ref().map(|r| project_path.join(r)),
109 context
110 .apple_assets()
111 .as_ref()
112 .map(|r| project_path.join(r)),
113 )?;
114 config.status("Copying binary to app folder")?;
115 std::fs::copy(&bin_path, &app_path.join(&name)).unwrap();
116 config.status_message("Generating", "Info.plist")?;
117 apple::save_apple_plist(&app_path, properties, false).unwrap();
118 if self.identity.is_some() {
119 config.status("Starting code signing process")?;
120 apple::copy_profile(
121 &app_path,
122 self.profile_name.clone(),
123 self.profile_path.clone(),
124 )?;
125 config.status_message("Generating", "xcent file")?;
126 let xcent_path = apple::gen_xcent(
127 &app_path,
128 &name,
129 self.team_identifier
130 .as_ref()
131 .ok_or(Error::TeamIdentifierNotProvided)?,
132 &properties.identification.bundle_identifier,
133 false,
134 )?;
135 config.status("Signing the binary")?;
136 apple::codesign(&app_path.join(&name), true, self.identity.clone(), None)?;
137 config.status("Signing the bundle itself")?;
138 apple::codesign(&app_path, true, self.identity.clone(), Some(xcent_path))?;
139 config.status("Code signing process finished")?;
140 }
141 config.status("Generating ipa file")?;
142 apple::gen_apple_ipa(&apple_target_dir, &app_path, &name)?;
143 config.status("Build finished successfully")?;
144 Ok(app_path)
145 }
146}