use std::convert::AsRef;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
pub fn env(var: &str) -> Option<PathBuf> {
std::env::var_os(var).map(|os| os.into())
}
pub fn platforms_android_nn(android_sdk_root: &impl AsRef<Path>) -> Result<PathBuf, io::Error> {
let android_sdk_root = android_sdk_root.as_ref();
if_exists_any(&android_sdk_root.join("platforms"), "android-*")
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, format!("No android-NN platform found in Android SDK root: {}/platforms/android-*", android_sdk_root.display())))
}
pub fn android_sdk_root() -> Result<PathBuf, io::Error> {
if let Some(android_home) = env("ANDROID_HOME") {
Some(android_home)
} else if let Some(android_sdk_root) = env("ANDROID_SDK_ROOT") {
Some(android_sdk_root)
} else if cfg!(windows) {
let WinPaths { program_files: _, program_files_x86, local_app_data } = WinPaths::get();
None.or_else(|| if_exists(program_files_x86.join(r"Android\android-sdk")))
.or_else(|| if_exists(local_app_data.join(r"Android\Sdk")))
} else if cfg!(unix) {
let home = env("HOME").expect("Expected ${HOME} to be set");
if_exists(home.join("android-sdk-tmp"))
} else {
None
}
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "ANDROID_HOME nor ANDROID_SDK_ROOT set and no Android SDK installation could be found"))
}
pub fn java_home() -> Result<PathBuf, io::Error> {
if let Some(java_home) = env("JAVA_HOME") {
Some(java_home)
} else if cfg!(windows) {
let WinPaths { program_files, program_files_x86, local_app_data: _ } = WinPaths::get();
let program_files_native = if cfg!(target_pointer_width = "64") { &program_files } else { &program_files_x86 };
None
.or_else(|| if_exists_any(&program_files_native.join(r"AdoptOpenJDK"), "jdk-*-hotspot")) .or_else(|| if_exists_any(&program_files_native.join(r"Java"), "jdk*")) .or_else(|| if_exists_any(&program_files.join(r"Android\jdk"), "microsoft_disk_openjdk_*")) .or_else(|| if_exists(program_files.join(r"Android\Android Studio\jre"))) } else if cfg!(unix) {
if cfg!(target_arch = "x86_64") { if_exists_any("/usr/lib/jvm", "java-*-openjdk-amd64" ) }
else if cfg!(target_arch = "x86") { if_exists_any("/usr/lib/jvm", "java-*-openjdk-i386" ) }
else if cfg!(target_arch = "aarch64") { if_exists_any("/usr/lib/jvm", "java-*-openjdk-arm64" ) }
else if cfg!(target_arch = "arm") {
None.or_else(|| if_exists_any("/usr/lib/jvm", "java-*-openjdk-armhf")) .or_else(|| if_exists_any("/usr/lib/jvm", "java-*-openjdk-armel")) }
else {
None
}
} else {
None
}
.ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "JAVA_HOME not set and no Java installation could be found"))
}
pub fn libjvm_name() -> &'static str {
if cfg!(windows) {
"jvm.dll"
} else if cfg!(target_os = "macos") {
"libjvm.dylib"
} else {
"libjvm.so"
}
}
pub fn libjvm_dir(java_home: &impl AsRef<Path>) -> Result<PathBuf, io::Error> {
let java_home = java_home.as_ref();
let libjvm = libjvm_name();
for path in [
#[cfg(target_arch = "x86_64" )] "jre/lib/amd64/client",
#[cfg(target_arch = "x86_64" )] "jre/lib/amd64/server",
#[cfg(target_arch = "x86" )] "jre/lib/i386/client",
#[cfg(target_arch = "x86" )] "jre/lib/i386/server",
#[cfg(target_arch = "aarch64")] "jre/lib/aarch64/client",
#[cfg(target_arch = "aarch64")] "jre/lib/aarch64/server",
#[cfg(target_arch = "arm" )] "jre/lib/arm/client",
#[cfg(target_arch = "arm" )] "jre/lib/arm/server",
"jre/bin/client",
"jre/bin/server",
"bin/client",
"bin/server",
"lib/client",
"lib/server",
].iter().copied().map(|s| Path::new(s)) {
let path = java_home.join(path);
if path.join(libjvm).exists() {
return Ok(path);
}
}
Err(io::Error::new(io::ErrorKind::NotFound, format!("Could not find {} in expected locations of JAVA_HOME: {}/jre/{{bin,lib/amd64}}/{{client,server}}/", libjvm, java_home.display())))
}
fn for_each_dir<T>(dir: &Path, pattern: &str, on_dir: &mut impl FnMut(PathBuf, &str) -> Option<T>) -> Option<T> {
if let Some(star) = pattern.find('*') {
let (pre, post) = pattern.split_at(star);
let post = &post[1..];
if let Ok(dir) = fs::read_dir(dir) { for entry in dir {
let entry = if let Ok(e) = entry { e } else { continue }; let name = entry.file_name();
let name = if let Some(n) = name.to_str() { n } else { continue };
if name.starts_with(pre) && name.ends_with(post) {
let ver = &name[pre.len()..name.len()-post.len()];
let ver = ver.trim_start_matches(|ch| ch == '-'); if let Some(r) = on_dir(entry.path(), ver) {
return Some(r);
}
}
}
}
None
} else {
let dir = dir.join(pattern);
if !dir.exists() { return None; }
on_dir(dir, "")
}
}
fn if_exists_any(dir: &(impl AsRef<Path> + ?Sized), pattern: &str) -> Option<PathBuf> {
for_each_dir(dir.as_ref(), pattern, &mut |p,_v| Some(p))
}
fn if_exists<P: AsRef<Path>>(path: P) -> Option<P> {
if path.as_ref().exists() {
Some(path)
} else {
None
}
}
struct WinPaths {
program_files: PathBuf,
program_files_x86: PathBuf,
local_app_data: PathBuf,
}
impl WinPaths {
pub fn get() -> Self {
Self {
program_files: env("ProgramW6432" ).or_else(|| env("ProgramFiles")) .expect("Expected %ProgramW6432% or %ProgramFiles% to be set"),
program_files_x86: env("ProgramFiles(x86)" ).or_else(|| env("ProgramFiles")) .expect("Expected %ProgramW6432% or %ProgramFiles% to be set"),
local_app_data: env("LOCALAPPDATA" ) .expect("Expected %LOCALAPPDATA% to be set"),
}
}
}