Skip to content

Commit 8fd72e5

Browse files
committed
devices/adb: Find adb executable in $ANDROID_HOME/$ANDROID_SDK_ROOT
`adb` is not always available on `PATH`, sometimes it is installed only via the SDK. Make sure we find it there too - after checking `PATH` - via well-known SDK variables.
1 parent 05f23f9 commit 8fd72e5

File tree

3 files changed

+83
-19
lines changed

3 files changed

+83
-19
lines changed

xbuild/src/command/doctor.rs

+39-11
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
use anyhow::Result;
1+
use anyhow::{bail, Result};
22
use std::path::PathBuf;
33
use std::process::Command;
44

5-
#[derive(Clone, Debug)]
5+
use crate::devices::adb::Adb;
6+
7+
#[derive(Debug)]
68
pub struct Doctor {
79
groups: Vec<Group>,
810
}
@@ -35,7 +37,11 @@ impl Default for Doctor {
3537
Group {
3638
name: "android",
3739
checks: vec![
38-
Check::new("adb", Some(VersionCheck::new("--version", 0, 4))),
40+
Check::with_path(
41+
"adb",
42+
Adb::which(),
43+
Some(VersionCheck::new("--version", 0, 4)),
44+
),
3945
Check::new("javac", Some(VersionCheck::new("--version", 0, 1))),
4046
Check::new("java", Some(VersionCheck::new("--version", 0, 1))),
4147
Check::new("kotlin", Some(VersionCheck::new("-version", 0, 2))),
@@ -77,7 +83,7 @@ impl std::fmt::Display for Doctor {
7783
}
7884
}
7985

80-
#[derive(Clone, Debug)]
86+
#[derive(Debug)]
8187
struct Group {
8288
name: &'static str,
8389
checks: Vec<Check>,
@@ -105,15 +111,32 @@ impl std::fmt::Display for Group {
105111
}
106112
}
107113

108-
#[derive(Clone, Copy, Debug)]
114+
#[derive(Debug)]
109115
struct Check {
110116
name: &'static str,
117+
location: Option<Result<PathBuf>>,
111118
version: Option<VersionCheck>,
112119
}
113120

114121
impl Check {
115122
pub const fn new(name: &'static str, version: Option<VersionCheck>) -> Self {
116-
Self { name, version }
123+
Self {
124+
name,
125+
location: None,
126+
version,
127+
}
128+
}
129+
130+
pub const fn with_path(
131+
name: &'static str,
132+
path: Result<PathBuf>,
133+
version: Option<VersionCheck>,
134+
) -> Self {
135+
Self {
136+
name,
137+
location: Some(path),
138+
version,
139+
}
117140
}
118141
}
119142

@@ -131,17 +154,22 @@ impl VersionCheck {
131154
}
132155

133156
impl Check {
134-
fn name(self) -> &'static str {
157+
fn name(&self) -> &'static str {
135158
self.name
136159
}
137160

138-
fn path(self) -> Result<PathBuf> {
139-
Ok(which::which(self.name)?)
161+
fn path(&self) -> Result<PathBuf> {
162+
Ok(match &self.location {
163+
Some(Ok(path)) => path.clone(),
164+
// Cannot clone the error:
165+
Some(Err(e)) => bail!("{:?}", e),
166+
None => which::which(self.name)?,
167+
})
140168
}
141169

142-
fn version(self) -> Result<Option<String>> {
170+
fn version(&self) -> Result<Option<String>> {
143171
if let Some(version) = self.version {
144-
let output = Command::new(self.name)
172+
let output = Command::new(self.path()?)
145173
.args(version.arg.split(' '))
146174
.output()?;
147175
anyhow::ensure!(output.status.success(), "failed to run {}", self.name);

xbuild/src/devices/adb.rs

+39-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::config::AndroidDebugConfig;
22
use crate::devices::{Backend, Device};
33
use crate::{Arch, Platform};
4-
use anyhow::Result;
4+
use anyhow::{Context, Result};
55
use apk::Apk;
66
use std::io::{BufRead, BufReader};
77
use std::path::{Path, PathBuf};
@@ -12,8 +12,44 @@ use std::time::Duration;
1212
pub(crate) struct Adb(PathBuf);
1313

1414
impl Adb {
15-
pub fn which() -> Result<Self> {
16-
Ok(Self(which::which(exe!("adb"))?))
15+
pub fn which() -> Result<PathBuf> {
16+
const ADB: &str = exe!("adb");
17+
18+
match which::which(ADB) {
19+
Err(which::Error::CannotFindBinaryPath) => {
20+
let sdk_path = {
21+
let sdk_path = std::env::var("ANDROID_SDK_ROOT").ok();
22+
if sdk_path.is_some() {
23+
eprintln!(
24+
"Warning: Environment variable ANDROID_SDK_ROOT is deprecated \
25+
(https://developer.android.com/studio/command-line/variables#envar). \
26+
It will be used until it is unset and replaced by ANDROID_HOME."
27+
);
28+
}
29+
30+
PathBuf::from(
31+
sdk_path
32+
.or_else(|| std::env::var("ANDROID_HOME").ok())
33+
.context(
34+
"Cannot find `adb` on in PATH nor is ANDROID_HOME/ANDROID_SDK_ROOT set",
35+
)?,
36+
)
37+
};
38+
39+
let adb_path = sdk_path.join("platform-tools").join(ADB);
40+
anyhow::ensure!(
41+
adb_path.exists(),
42+
"Expected `adb` at `{}`",
43+
adb_path.display()
44+
);
45+
Ok(adb_path)
46+
}
47+
r => r.context("Could not find `adb` in PATH"),
48+
}
49+
}
50+
51+
pub fn new() -> Result<Self> {
52+
Ok(Self(Self::which()?))
1753
}
1854

1955
fn adb(&self, device: &str) -> Command {

xbuild/src/devices/mod.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use crate::{Arch, BuildEnv, Platform};
55
use anyhow::Result;
66
use std::path::Path;
77

8-
mod adb;
9-
mod host;
10-
mod imd;
8+
pub(crate) mod adb;
9+
pub(crate) mod host;
10+
pub(crate) mod imd;
1111

1212
#[derive(Clone, Debug)]
1313
enum Backend {
@@ -31,7 +31,7 @@ impl std::str::FromStr for Device {
3131
}
3232
if let Some((backend, id)) = device.split_once(':') {
3333
let backend = match backend {
34-
"adb" => Backend::Adb(Adb::which()?),
34+
"adb" => Backend::Adb(Adb::new()?),
3535
"imd" => Backend::Imd(IMobileDevice::which()?),
3636
_ => anyhow::bail!("unsupported backend {}", backend),
3737
};
@@ -58,7 +58,7 @@ impl std::fmt::Display for Device {
5858
impl Device {
5959
pub fn list() -> Result<Vec<Self>> {
6060
let mut devices = vec![Self::host()];
61-
if let Ok(adb) = Adb::which() {
61+
if let Ok(adb) = Adb::new() {
6262
adb.devices(&mut devices)?;
6363
}
6464
if let Ok(imd) = IMobileDevice::which() {

0 commit comments

Comments
 (0)