cli/commands/build/
build_context.rs

1use crate::{
2    cargo_manifest::{CargoManifest, CargoPackage, Metadata},
3    error::{Error, Result},
4};
5use creator_tools::{
6    commands::{
7        android, apple, find_package_cargo_manifest_path, find_workspace_cargo_manifest_path,
8    },
9    tools::AndroidSdk,
10    types::{
11        android_manifest::AndroidManifest, apple_bundle::prelude::InfoPlist, AndroidTarget,
12        AppleTarget,
13    },
14    utils::Config,
15};
16use std::path::PathBuf;
17
18pub struct BuildContext {
19    pub workspace_manifest_path: PathBuf,
20    pub package_manifest_path: PathBuf,
21    pub project_path: PathBuf,
22    pub cargo_manifest: CargoManifest,
23    pub cargo_package: CargoPackage<Metadata>,
24    pub target_dir: PathBuf,
25}
26
27impl BuildContext {
28    pub fn new(config: &Config, target_dir: Option<PathBuf>) -> Result<Self> {
29        let workspace_manifest_path = find_workspace_cargo_manifest_path(config.current_dir())?;
30        let package_manifest_path = find_package_cargo_manifest_path(config.current_dir())?;
31        let project_path = package_manifest_path.parent().unwrap().to_owned();
32        let target_dir =
33            target_dir.unwrap_or_else(|| workspace_manifest_path.parent().unwrap().join("target"));
34        info!("Parsing Cargo.toml");
35        let cargo_manifest = CargoManifest::from_path_with_metadata(&package_manifest_path)?;
36        let cargo_package = cargo_manifest
37            .package
38            .clone()
39            .ok_or(Error::InvalidManifest)?;
40        Ok(Self {
41            workspace_manifest_path,
42            package_manifest_path,
43            project_path,
44            cargo_manifest,
45            cargo_package,
46            target_dir,
47        })
48    }
49
50    pub fn package_name(&self) -> String {
51        self.cargo_package.name.clone()
52    }
53
54    pub fn package_version(&self) -> String {
55        self.cargo_package.version.clone()
56    }
57
58    pub fn target_sdk_version(&self, sdk: &AndroidSdk) -> u32 {
59        if let Some(metadata) = &self.cargo_package.metadata {
60            if let Some(target_sdk_version) = metadata.target_sdk_version {
61                return target_sdk_version;
62            };
63        };
64        sdk.default_platform()
65    }
66
67    pub fn android_build_targets(&self, build_targets: &Vec<AndroidTarget>) -> Vec<AndroidTarget> {
68        if !build_targets.is_empty() {
69            return build_targets.clone();
70        };
71        if self.cargo_package.metadata.is_none() {
72            return vec![AndroidTarget::Aarch64LinuxAndroid];
73        };
74        let targets = self
75            .cargo_package
76            .metadata
77            .clone()
78            .unwrap()
79            .android_build_targets;
80        if targets.is_some() && !targets.as_ref().unwrap().is_empty() {
81            return targets.unwrap();
82        };
83        vec![AndroidTarget::Aarch64LinuxAndroid]
84    }
85
86    pub fn android_res(&self) -> Option<PathBuf> {
87        self.cargo_package
88            .metadata
89            .as_ref()
90            .map(|m| m.android_res.clone())
91            .unwrap_or_default()
92    }
93
94    pub fn android_assets(&self) -> Option<PathBuf> {
95        self.cargo_package
96            .metadata
97            .as_ref()
98            .map(|m| m.android_assets.clone())
99            .unwrap_or_default()
100    }
101
102    pub fn gen_android_manifest(
103        &self,
104        sdk: &AndroidSdk,
105        package_name: &String,
106        debuggable: bool,
107    ) -> Result<AndroidManifest> {
108        if let Some(metadata) = &self.cargo_package.metadata {
109            if metadata.use_android_manifest {
110                let path = metadata
111                    .android_manifest_path
112                    .clone()
113                    .unwrap_or_else(|| self.project_path.join("AndroidManifest.xml"));
114                Ok(android::read_android_manifest(&path)?)
115            } else {
116                let mut manifest = android::gen_minimal_android_manifest(
117                    metadata.android_app_id.clone(),
118                    package_name,
119                    metadata.app_name.clone(),
120                    metadata
121                        .version_name
122                        .clone()
123                        .unwrap_or(self.package_version()),
124                    metadata.version_code.clone(),
125                    metadata.min_sdk_version,
126                    metadata
127                        .target_sdk_version
128                        .unwrap_or_else(|| sdk.default_platform()),
129                    metadata.max_sdk_version,
130                    metadata.icon.clone(),
131                    debuggable,
132                );
133                if !metadata.android_permissions.is_empty() {
134                    manifest.uses_permission = metadata.android_permissions.clone();
135                }
136                Ok(manifest)
137            }
138        } else {
139            let target_sdk_version = sdk.default_platform();
140            Ok(android::gen_minimal_android_manifest(
141                None,
142                package_name,
143                None,
144                self.package_version(),
145                None,
146                None,
147                target_sdk_version,
148                None,
149                None,
150                debuggable,
151            ))
152        }
153    }
154
155    pub fn gen_info_plist(&self, package_name: &String) -> Result<InfoPlist> {
156        if let Some(metadata) = &self.cargo_package.metadata {
157            if metadata.use_info_plist {
158                let path = metadata
159                    .info_plist_path
160                    .clone()
161                    .unwrap_or_else(|| self.project_path.join("Info.plist"));
162                Ok(apple::read_info_plist(&path)?)
163            } else {
164                Ok(apple::gen_minimal_info_plist(
165                    package_name,
166                    metadata.app_name.clone(),
167                    metadata
168                        .version_name
169                        .clone()
170                        .unwrap_or(self.package_version()),
171                ))
172            }
173        } else {
174            Ok(apple::gen_minimal_info_plist(
175                package_name,
176                None,
177                self.package_version(),
178            ))
179        }
180    }
181
182    pub fn apple_build_targets(&self, build_targets: &Vec<AppleTarget>) -> Vec<AppleTarget> {
183        if !build_targets.is_empty() {
184            return build_targets.clone();
185        };
186        if self.cargo_package.metadata.is_none() {
187            return vec![AppleTarget::X86_64AppleIos];
188        };
189        let targets = self
190            .cargo_package
191            .metadata
192            .clone()
193            .unwrap()
194            .apple_build_targets;
195        if targets.is_some() && !targets.as_ref().unwrap().is_empty() {
196            return targets.unwrap();
197        };
198        vec![AppleTarget::X86_64AppleIos]
199    }
200
201    pub fn apple_res(&self) -> Option<PathBuf> {
202        self.cargo_package
203            .metadata
204            .as_ref()
205            .map(|m| m.apple_res.clone())
206            .unwrap_or_default()
207    }
208
209    pub fn apple_assets(&self) -> Option<PathBuf> {
210        self.cargo_package
211            .metadata
212            .as_ref()
213            .map(|m| m.apple_assets.clone())
214            .unwrap_or_default()
215    }
216}