creator_tools/tools/
android_sdk.rs1use crate::error::*;
2use std::path::{Path, PathBuf};
3use std::process::Command as ProcessCommand;
4
5pub struct AndroidSdk {
6 sdk_path: PathBuf,
7 build_deps_path: PathBuf,
8 build_deps_version: String,
9 platforms_path: PathBuf,
10 platforms: Vec<u32>,
11}
12
13impl AndroidSdk {
14 pub fn from_env() -> Result<Self> {
15 let sdk_path = {
16 let sdk_path = std::env::var("ANDROID_SDK_ROOT")
17 .ok()
18 .or_else(|| std::env::var("ANDROID_SDK_PATH").ok())
19 .or_else(|| std::env::var("ANDROID_HOME").ok());
20 PathBuf::from(sdk_path.ok_or(AndroidError::AndroidSdkNotFound)?)
21 };
22 let build_deps_path = sdk_path.join("build-tools");
23 let build_deps_version = std::fs::read_dir(&build_deps_path)
24 .map_err(|_| Error::PathNotFound(build_deps_path.clone()))?
25 .filter_map(|path| path.ok())
26 .filter(|path| path.path().is_dir())
27 .filter_map(|path| path.file_name().into_string().ok())
28 .filter(|name| name.chars().next().unwrap().is_digit(10))
29 .max()
30 .ok_or(AndroidError::BuildToolsNotFound)?;
31 let platforms_path = sdk_path.join("platforms");
32 let platforms: Vec<u32> = std::fs::read_dir(&platforms_path)
33 .map_err(|_| Error::PathNotFound(platforms_path.clone()))?
34 .filter_map(|path| path.ok())
35 .filter(|path| path.path().is_dir())
36 .filter_map(|path| path.file_name().into_string().ok())
37 .filter_map(|name| {
38 name.strip_prefix("android-")
39 .and_then(|api| api.parse::<u32>().ok())
40 })
41 .collect();
42 if platforms.is_empty() {
43 return Err(AndroidError::NoPlatformsFound.into());
44 };
45 Ok(Self {
46 sdk_path,
47 build_deps_path,
48 build_deps_version,
49 platforms_path,
50 platforms,
51 })
52 }
53
54 pub fn sdk_path(&self) -> &Path {
55 &self.sdk_path
56 }
57
58 pub fn build_deps_path(&self) -> &Path {
59 &self.build_deps_path
60 }
61
62 pub fn build_deps_version(&self) -> &str {
63 &self.build_deps_version
64 }
65
66 pub fn platforms_path(&self) -> &Path {
67 &self.platforms_path
68 }
69
70 pub fn platforms(&self) -> &[u32] {
71 &self.platforms
72 }
73
74 pub fn build_tool(&self, tool: &str, current_dir: Option<&Path>) -> Result<ProcessCommand> {
75 let path = self
76 .build_deps_path
77 .join(&self.build_deps_version)
78 .join(tool);
79 if !path.exists() {
80 return Err(Error::CmdNotFound(tool.to_string()));
81 }
82 let mut command = ProcessCommand::new(dunce::canonicalize(path)?);
83 if let Some(current_dir) = current_dir {
84 command.current_dir(current_dir);
85 };
86 Ok(command)
87 }
88
89 pub fn platform_tool(&self, tool: &str) -> Result<ProcessCommand> {
90 let path = self.sdk_path.join("platform-tools").join(tool);
91 if !path.exists() {
92 return Err(Error::CmdNotFound(tool.to_string()));
93 }
94 Ok(ProcessCommand::new(dunce::canonicalize(path)?))
95 }
96
97 pub fn default_platform(&self) -> u32 {
98 self.platforms().iter().max().cloned().unwrap()
99 }
100
101 pub fn platform_dir(&self, platform: u32) -> Result<PathBuf> {
102 let dir = self.platforms_path.join(format!("android-{}", platform));
103 if !dir.exists() {
104 return Err(AndroidError::PlatformNotFound(platform).into());
105 }
106 Ok(dir)
107 }
108
109 pub fn android_jar(&self, platform: u32) -> Result<PathBuf> {
110 let android_jar = self.platform_dir(platform)?.join("android.jar");
111 if !android_jar.exists() {
112 return Err(Error::PathNotFound(android_jar));
113 }
114 Ok(android_jar)
115 }
116}