driver_tools/subcommands/list/
mod.rs1pub mod args;
6
7use anyhow::{Context, Result};
8use args::ListCommand;
9use flex_fuchsia_driver_development as fdd;
10#[cfg(feature = "fdomain")]
11use fuchsia_driver_dev_fdomain as fuchsia_driver_dev;
12use futures::join;
13use std::collections::HashSet;
14use std::io::Write;
15
16pub async fn list(
17 cmd: ListCommand,
18 writer: &mut dyn Write,
19 driver_development_proxy: fdd::ManagerProxy,
20) -> Result<()> {
21 if cmd.verbose {
22 writeln!(
23 writer,
24 "WARNING: The verbose flag is deprecated. Use `ffx driver show` instead."
25 )?;
26 return Ok(());
27 }
28
29 let empty: [String; 0] = [];
30 let driver_info = fuchsia_driver_dev::get_driver_info(&driver_development_proxy, &empty);
31
32 let driver_info = if cmd.loaded {
33 let device_info = fuchsia_driver_dev::get_device_info(
35 &driver_development_proxy,
36 &empty,
37 false,
38 );
39
40 let (driver_info, device_info) = join!(driver_info, device_info);
42
43 let loaded_driver_set: HashSet<String> = HashSet::from_iter(
44 device_info?.into_iter().filter_map(|device_info| device_info.bound_driver_url),
45 );
46
47 driver_info?
49 .into_iter()
50 .filter(|driver| {
51 let mut loaded = false;
52 if let Some(ref url) = driver.url {
53 if loaded_driver_set.contains(url) {
54 loaded = true
55 }
56 }
57 loaded
58 })
59 .collect()
60 } else {
61 driver_info.await.context("Failed to get driver info")?
62 };
63
64 for driver in driver_info {
65 if let Some(name) = driver.name {
66 let url = driver.url.unwrap_or_default();
67 writeln!(writer, "{:<20}: {}", name, url)?;
68 } else {
69 let url = driver.url.unwrap_or_default();
70 writeln!(writer, "{}", url)?;
71 }
72 }
73 Ok(())
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use argh::FromArgs;
80 use flex_client::fidl::ServerEnd;
81 use flex_fuchsia_driver_framework as fdf;
82 use fuchsia_async as fasync;
83 use futures::future::{Future, FutureExt};
84 use futures::stream::StreamExt;
85 #[cfg(feature = "fdomain")]
86 use std::sync::Arc;
87
88 async fn test_list<F, Fut>(
93 #[cfg(feature = "fdomain")] client: Arc<flex_client::Client>,
94 cmd: ListCommand,
95 on_driver_development_request: F,
96 ) -> Result<String>
97 where
98 F: Fn(fdd::ManagerRequest) -> Fut + Send + Sync + 'static,
99 Fut: Future<Output = Result<()>> + Send + Sync,
100 {
101 #[cfg(not(feature = "fdomain"))]
102 let client = flex_client::fidl::ZirconClient;
103 let (driver_development_proxy, mut driver_development_requests) =
104 client.create_proxy_and_stream::<fdd::ManagerMarker>();
105
106 let mut writer = Vec::new();
108 let request_handler_task = fasync::Task::spawn(async move {
109 while let Some(res) = driver_development_requests.next().await {
110 let request = res.unwrap();
111 on_driver_development_request(request).await.context("Failed to handle request")?;
112 }
113 anyhow::bail!("Driver development request stream unexpectedly closed");
114 });
115 futures::select! {
116 res = request_handler_task.fuse() => {
117 res?;
118 anyhow::bail!("Request handler task unexpectedly finished");
119 }
120 res = list(cmd, &mut writer, driver_development_proxy).fuse() => res.context("List command failed")?,
121 }
122
123 String::from_utf8(writer).context("Failed to convert list output to a string")
124 }
125
126 async fn run_driver_info_iterator_server(
127 mut driver_infos: Vec<fdf::DriverInfo>,
128 iterator: ServerEnd<fdd::DriverInfoIteratorMarker>,
129 ) -> Result<()> {
130 let mut iterator = iterator.into_stream();
131 while let Some(res) = iterator.next().await {
132 let request = res.unwrap();
133 match request {
134 fdd::DriverInfoIteratorRequest::GetNext { responder } => {
135 responder.send(&driver_infos).unwrap();
136 driver_infos.clear();
137 }
138 }
139 }
140 Ok(())
141 }
142
143 #[fuchsia::test]
144 async fn test_list_all() {
145 #[cfg(feature = "fdomain")]
146 let client = fdomain_local::local_client_empty();
147 let cmd = ListCommand::from_args(&["list"], &[]).unwrap();
148
149 let output = test_list(
150 #[cfg(feature = "fdomain")]
151 client,
152 cmd,
153 |request: fdd::ManagerRequest| async move {
154 match request {
155 fdd::ManagerRequest::GetDriverInfo {
156 driver_filter: _,
157 iterator,
158 control_handle: _,
159 } => run_driver_info_iterator_server(
160 vec![fdf::DriverInfo {
161 name: Some("foo".to_owned()),
162 url: Some(
163 "fuchsia-pkg://fuchsia.com/foo-package#meta/foo.cm".to_owned(),
164 ),
165 ..Default::default()
166 }],
167 iterator,
168 )
169 .await
170 .context("Failed to run driver info iterator server")?,
171 _ => {}
172 }
173 Ok(())
174 },
175 )
176 .await
177 .unwrap();
178
179 assert_eq!(
180 output,
181 "foo : fuchsia-pkg://fuchsia.com/foo-package#meta/foo.cm\n"
182 );
183 }
184
185 #[fuchsia::test]
186 async fn test_verbose_deprecated() {
187 #[cfg(feature = "fdomain")]
188 let client = fdomain_local::local_client_empty();
189 let cmd = ListCommand::from_args(&["list"], &["--verbose"]).unwrap();
190
191 let output = test_list(
192 #[cfg(feature = "fdomain")]
193 Arc::clone(&client),
194 cmd,
195 |request: fdd::ManagerRequest| async move {
196 match request {
197 fdd::ManagerRequest::GetDriverInfo {
198 driver_filter: _,
199 iterator,
200 control_handle: _,
201 } => run_driver_info_iterator_server(
202 vec![fdf::DriverInfo {
203 name: Some("foo".to_owned()),
204 url: Some(
205 "fuchsia-pkg://fuchsia.com/foo-package#meta/foo.cm".to_owned(),
206 ),
207 ..Default::default()
208 }],
209 iterator,
210 )
211 .await
212 .context("Failed to run driver info iterator server")?,
213 _ => {}
214 }
215 Ok(())
216 },
217 )
218 .await
219 .unwrap();
220
221 assert_eq!(
222 output,
223 "WARNING: The verbose flag is deprecated. Use `ffx driver show` instead.\n"
224 );
225 }
226}