creator_tools/tools/
android_sdk.rs

1use 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}