From c05848cd751d6249ae1dea38f85713a33c357538 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Fri, 25 Feb 2022 16:55:09 +0100 Subject: [PATCH] Read environment variables from `.cargo/config.toml`'s `[env]` section --- Cargo.toml | 4 ++++ cargo-apk/CHANGELOG.md | 1 + cargo-apk/src/apk.rs | 23 +++++++++++++++++---- ndk-build/CHANGELOG.md | 1 + ndk-build/src/cargo.rs | 4 ++++ ndk-build/src/ndk.rs | 46 ++++++++++++++++++++++++++++-------------- 6 files changed, 60 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b189f3e0..37b3d543 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,7 @@ members = [ "ndk-sys", "cargo-apk", ] + +[patch.crates-io] +# https://github.com/dvc94ch/cargo-subcommand/pull/12 +cargo-subcommand = { git = "https://github.com/dvc94ch/cargo-subcommand", rev = "55269e6" } diff --git a/cargo-apk/CHANGELOG.md b/cargo-apk/CHANGELOG.md index 8ddace4e..b67621e4 100644 --- a/cargo-apk/CHANGELOG.md +++ b/cargo-apk/CHANGELOG.md @@ -5,6 +5,7 @@ - Default `target_sdk_version` to `30` or lower (instead of the highest supported SDK version by the detected NDK toolchain) for more consistent interaction with Android backwards compatibility handling and its increasingly strict usage rules: https://developer.android.com/distribute/best-practices/develop/target-sdk +- Read environment variables from `.cargo/config.toml`'s `[env]` section. # 0.8.2 (2021-11-22) diff --git a/cargo-apk/src/apk.rs b/cargo-apk/src/apk.rs index a864d5e4..9b2914c2 100644 --- a/cargo-apk/src/apk.rs +++ b/cargo-apk/src/apk.rs @@ -1,8 +1,8 @@ use crate::error::Error; use crate::manifest::Manifest; -use cargo_subcommand::{Artifact, CrateType, Profile, Subcommand}; +use cargo_subcommand::{Artifact, CrateType, LocalizedConfig, Profile, Subcommand}; use ndk_build::apk::{Apk, ApkConfig}; -use ndk_build::cargo::{cargo_ndk, VersionCode}; +use ndk_build::cargo::{cargo_ndk, Env, VersionCode}; use ndk_build::dylibs::get_libs_search_paths; use ndk_build::error::NdkError; use ndk_build::manifest::MetaData; @@ -10,6 +10,7 @@ use ndk_build::ndk::Ndk; use ndk_build::target::Target; use std::path::PathBuf; use std::process::Command; +use std::sync::Arc; pub struct ApkBuilder<'a> { cmd: &'a Subcommand, @@ -19,9 +20,23 @@ pub struct ApkBuilder<'a> { build_targets: Vec, } +struct ConfigEnv(Option); +impl Env for ConfigEnv { + fn var(&self, key: &str) -> std::result::Result, std::env::VarError> { + match &self.0 { + Some(config) => config + .resolve_env(key) + // IO error is currently only returned when path canonicalization fails + .expect("Failed to resolve environment variable") + .ok_or(std::env::VarError::NotPresent), + None => std::env::var(key).map(|s| s.into()), + } + } +} + impl<'a> ApkBuilder<'a> { pub fn from_subcommand(cmd: &'a Subcommand) -> Result { - let ndk = Ndk::from_env()?; + let ndk = Ndk::from_env(Arc::new(ConfigEnv(cmd.config().cloned())))?; let mut manifest = Manifest::parse_from_toml(cmd.manifest())?; let build_targets = if let Some(target) = cmd.target() { vec![Target::from_rust_triple(target)?] @@ -224,7 +239,7 @@ impl<'a> ApkBuilder<'a> { } pub fn default(&self) -> Result<(), Error> { - let ndk = Ndk::from_env()?; + let ndk = Ndk::from_env(Arc::new(ConfigEnv(None)))?; for target in &self.build_targets { let mut cargo = cargo_ndk(&ndk, *target, self.min_sdk_version())?; cargo.args(self.cmd.args()); diff --git a/ndk-build/CHANGELOG.md b/ndk-build/CHANGELOG.md index 1e0e812e..ffcb18ff 100644 --- a/ndk-build/CHANGELOG.md +++ b/ndk-build/CHANGELOG.md @@ -3,6 +3,7 @@ - Default `target_sdk_version` to `30` or lower (instead of the highest supported SDK version by the detected NDK toolchain) for more consistent interaction with Android backwards compatibility handling and its increasingly strict usage rules: https://developer.android.com/distribute/best-practices/develop/target-sdk +- **Breaking:** `Ndk` now requires a struct implementing `Env` to read environment variables from. # 0.4.3 (2021-11-22) diff --git a/ndk-build/src/cargo.rs b/ndk-build/src/cargo.rs index 65a07fc8..386cb739 100644 --- a/ndk-build/src/cargo.rs +++ b/ndk-build/src/cargo.rs @@ -3,6 +3,10 @@ use crate::ndk::Ndk; use crate::target::Target; use std::process::Command; +pub trait Env { + fn var(&self, key: &str) -> std::result::Result, std::env::VarError>; +} + pub fn cargo_ndk(ndk: &Ndk, target: Target, sdk_version: u32) -> Result { let triple = target.rust_triple(); let mut cargo = Command::new("cargo"); diff --git a/ndk-build/src/ndk.rs b/ndk-build/src/ndk.rs index 5035aecf..52f3a140 100644 --- a/ndk-build/src/ndk.rs +++ b/ndk-build/src/ndk.rs @@ -1,22 +1,25 @@ +use crate::cargo::Env; use crate::error::NdkError; use crate::target::Target; use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::process::Command; +use std::sync::Arc; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone)] pub struct Ndk { sdk_path: PathBuf, ndk_path: PathBuf, build_tools_version: String, build_tag: u32, platforms: Vec, + env: Arc, } impl Ndk { - pub fn from_env() -> Result { + pub fn from_env(env: Arc) -> Result { let sdk_path = { - let mut sdk_path = std::env::var("ANDROID_HOME").ok(); + let mut sdk_path = env.var("ANDROID_HOME").ok(); if sdk_path.is_some() { println!( "Warning: You use environment variable ANDROID_HOME that is deprecated. \ @@ -24,24 +27,25 @@ impl Ndk { ); } if sdk_path.is_none() { - sdk_path = std::env::var("ANDROID_SDK_ROOT").ok(); + sdk_path = env.var("ANDROID_SDK_ROOT").ok(); } - PathBuf::from(sdk_path.ok_or(NdkError::SdkNotFound)?) + PathBuf::from(sdk_path.ok_or(NdkError::SdkNotFound)?.as_ref()) }; let ndk_path = { - let ndk_path = std::env::var("ANDROID_NDK_ROOT") + let ndk_path = env + .var("ANDROID_NDK_ROOT") .ok() - .or_else(|| std::env::var("ANDROID_NDK_PATH").ok()) - .or_else(|| std::env::var("ANDROID_NDK_HOME").ok()) - .or_else(|| std::env::var("NDK_HOME").ok()); + .or_else(|| env.var("ANDROID_NDK_PATH").ok()) + .or_else(|| env.var("ANDROID_NDK_HOME").ok()) + .or_else(|| env.var("NDK_HOME").ok()); // default ndk installation path if ndk_path.is_none() && sdk_path.join("ndk-bundle").exists() { sdk_path.join("ndk-bundle") } else { - PathBuf::from(ndk_path.ok_or(NdkError::NdkNotFound)?) + PathBuf::from(ndk_path.ok_or(NdkError::NdkNotFound)?.as_ref()) } }; @@ -116,6 +120,7 @@ impl Ndk { build_tools_version, build_tag, platforms, + env, }) } @@ -191,7 +196,7 @@ impl Ndk { } pub fn toolchain_dir(&self) -> Result { - let host_os = std::env::var("HOST").ok(); + let host_os = self.env.var("HOST").ok(); let host_contains = |s| host_os.as_ref().map(|h| h.contains(s)).unwrap_or(false); let arch = if host_contains("linux") { @@ -208,7 +213,7 @@ impl Ndk { "windows" } else { return match host_os { - Some(host_os) => Err(NdkError::UnsupportedHost(host_os)), + Some(host_os) => Err(NdkError::UnsupportedHost(host_os.into())), _ => Err(NdkError::UnsupportedTarget), }; }; @@ -293,8 +298,10 @@ impl Ndk { if let Ok(keytool) = which::which(bin!("keytool")) { return Ok(Command::new(keytool)); } - if let Ok(java) = std::env::var("JAVA_HOME") { - let keytool = PathBuf::from(java).join("bin").join(bin!("keytool")); + if let Ok(java) = self.env.var("JAVA_HOME") { + let keytool = PathBuf::from(java.as_ref()) + .join("bin") + .join(bin!("keytool")); if keytool.exists() { return Ok(Command::new(keytool)); } @@ -401,7 +408,16 @@ mod tests { #[test] #[ignore] fn test_detect() { - let ndk = Ndk::from_env().unwrap(); + struct GlobalEnv; + impl Env for GlobalEnv { + fn var( + &self, + key: &str, + ) -> std::result::Result, std::env::VarError> { + std::env::var(key).map(|s| s.into()) + } + } + let ndk = Ndk::from_env(Arc::new(GlobalEnv)).unwrap(); assert_eq!(ndk.build_tools_version(), "29.0.2"); assert_eq!(ndk.platforms(), &[29, 28]); }