waterui_cli/android/
adb.rs1use std::path::{Path, PathBuf};
13
14use crate::{android::toolchain::AndroidSdk, toolchain::Host, utils::CommandError};
15
16#[derive(Debug, thiserror::Error)]
18pub enum AdbError {
19 #[error("Android SDK not found or adb not installed")]
21 NotFound,
22 #[error("failed to start the adb server: {0}")]
24 ServerLauncher(#[from] CommandError),
25 #[error("`{adb} start-server` failed with status {status}", adb = .adb.display())]
27 ServerStart {
28 adb: PathBuf,
30 status: std::process::ExitStatus,
32 },
33}
34
35#[derive(Debug, Clone)]
37pub struct Adb {
38 path: PathBuf,
39}
40
41impl Adb {
42 pub async fn locate(host: &Host) -> Result<Self, AdbError> {
48 let path = AndroidSdk::adb_path(host).ok_or(AdbError::NotFound)?;
49 let status = host.run_detached(&path, ["start-server"]).await?;
50 if !status.success() {
51 return Err(AdbError::ServerStart { adb: path, status });
52 }
53 Ok(Self { path })
54 }
55
56 #[must_use]
58 pub fn path(&self) -> &Path {
59 &self.path
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use std::ffi::OsString;
66
67 use super::{Adb, AdbError};
68 use crate::toolchain::testing::TestMachine;
69
70 #[test]
71 fn without_platform_tools_there_is_no_adb() {
72 let machine = TestMachine::new();
73 let sdk = machine.install_android_sdk();
74 let host = machine.host([(
75 OsString::from("ANDROID_SDK_ROOT"),
76 sdk.as_os_str().to_os_string(),
77 )]);
78 let error = smol::block_on(Adb::locate(&host)).expect_err("no adb staged");
79 assert!(matches!(error, AdbError::NotFound), "{error:?}");
80 }
81
82 #[test]
85 #[cfg(unix)]
86 fn locating_adb_starts_its_server_first() {
87 let machine = TestMachine::new();
88 let sdk = machine.install_android_sdk();
89 let staged = machine.install_adb();
90 let host = machine.host([(
91 OsString::from("ANDROID_SDK_ROOT"),
92 sdk.as_os_str().to_os_string(),
93 )]);
94 let adb = smol::block_on(Adb::locate(&host)).expect("the fake adb starts its server");
95 assert_eq!(adb.path(), staged);
96 }
97
98 #[test]
99 #[cfg(unix)]
100 fn a_failing_server_launch_is_an_error() {
101 let machine = TestMachine::new();
102 let sdk = machine.install_android_sdk();
103 machine.install_adb();
104 let host = machine.host([
105 (
106 OsString::from("ANDROID_SDK_ROOT"),
107 sdk.as_os_str().to_os_string(),
108 ),
109 (
110 OsString::from("WATERUI_FAKE_ADB_START_SERVER_STATUS"),
111 OsString::from("3"),
112 ),
113 ]);
114 let error = smol::block_on(Adb::locate(&host)).expect_err("the launcher exits 3");
115 match error {
116 AdbError::ServerStart { status, .. } => assert_eq!(status.code(), Some(3)),
117 other => panic!("expected ServerStart, got {other:?}"),
118 }
119 }
120}