1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use std::path::PathBuf;

use error::Error;

/// On Windows adds `.exe` to given string.
macro_rules! bin {
    ($bin:expr) => {{
        #[cfg(not(target_os = "windows"))]
        let bin = $bin;
        #[cfg(target_os = "windows")]
        let bin = concat!($bin, ".exe");
        bin
    }};
}

pub mod error;

#[cfg(feature = "aapt2")]
pub mod aapt2;
pub mod adb;
#[cfg(feature = "bundletool")]
pub mod bundletool;
#[cfg(feature = "emulator")]
pub mod emulator;
#[cfg(feature = "java-tools")]
pub mod java_tools;

/// Return SDK path from found environment variable
pub fn sdk_path_from_env() -> crate::error::Result<PathBuf> {
    let sdk_path = {
        let sdk_path = std::env::var("ANDROID_SDK_ROOT")
            .ok()
            .or_else(|| std::env::var("ANDROID_SDK_PATH").ok())
            .or_else(|| std::env::var("ANDROID_HOME").ok());
        if let Some(path) = sdk_path {
            std::path::PathBuf::from(path)
        } else {
            sdk_install_path()?
        }
    };
    if !sdk_path.exists() {
        return Err(Error::AndroidSdkNotFound)?;
    }
    Ok(sdk_path)
}

/// Default installation path
pub fn sdk_install_path() -> crate::error::Result<PathBuf> {
    let home_dir_path = dirs::home_dir().ok_or(Error::UnableToAccessHomeDirectory)?;
    #[cfg(target_os = "windows")]
    let path = std::path::Path::new("Local").join("Android").join("Sdk");
    #[cfg(target_os = "macos")]
    let path = std::path::Path::new("Library").join("Android").join("sdk");
    #[cfg(target_os = "linux")]
    let path = std::path::Path::new("Android").join("sdk");

    #[cfg(target_os = "windows")]
    let app_data = std::path::Path::new("AppData");
    #[cfg(target_os = "windows")]
    let sdk_path = home_dir_path.join(app_data).join(path);

    #[cfg(not(target_os = "windows"))]
    let sdk_path = home_dir_path.join(path);

    Ok(sdk_path)
}

pub fn find_max_version(target_dir: &std::path::Path) -> crate::error::Result<String> {
    let max_version = std::fs::read_dir(&target_dir)?
        .filter_map(|path| path.ok())
        .filter(|path| path.path().is_dir())
        .filter_map(|path| path.file_name().into_string().ok())
        .filter(|name| name.chars().next().unwrap().is_ascii_digit())
        .max()
        .ok_or(Error::AndroidToolNotFound)?;
    Ok(max_version)
}