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 futures::future::{Future, FutureExt};
82 use futures::stream::StreamExt;
83 #[cfg(feature = "fdomain")]
84 use std::sync::Arc;
85 use {flex_fuchsia_driver_framework as fdf, fuchsia_async as fasync};
86
87 async fn test_list<F, Fut>(
92 #[cfg(feature = "fdomain")] client: Arc<flex_client::Client>,
93 cmd: ListCommand,
94 on_driver_development_request: F,
95 ) -> Result<String>
96 where
97 F: Fn(fdd::ManagerRequest) -> Fut + Send + Sync + 'static,
98 Fut: Future<Output = Result<()>> + Send + Sync,
99 {
100 #[cfg(not(feature = "fdomain"))]
101 let client = flex_client::fidl::ZirconClient;
102 let (driver_development_proxy, mut driver_development_requests) =
103 client.create_proxy_and_stream::<fdd::ManagerMarker>();
104
105 let mut writer = Vec::new();
107 let request_handler_task = fasync::Task::spawn(async move {
108 while let Some(res) = driver_development_requests.next().await {
109 let request = res.unwrap();
110 on_driver_development_request(request).await.context("Failed to handle request")?;
111 }
112 anyhow::bail!("Driver development request stream unexpectedly closed");
113 });
114 futures::select! {
115 res = request_handler_task.fuse() => {
116 res?;
117 anyhow::bail!("Request handler task unexpectedly finished");
118 }
119 res = list(cmd, &mut writer, driver_development_proxy).fuse() => res.context("List command failed")?,
120 }
121
122 String::from_utf8(writer).context("Failed to convert list output to a string")
123 }
124
125 async fn run_driver_info_iterator_server(
126 mut driver_infos: Vec<fdf::DriverInfo>,
127 iterator: ServerEnd<fdd::DriverInfoIteratorMarker>,
128 ) -> Result<()> {
129 let mut iterator = iterator.into_stream();
130 while let Some(res) = iterator.next().await {
131 let request = res.unwrap();
132 match request {
133 fdd::DriverInfoIteratorRequest::GetNext { responder } => {
134 responder.send(&driver_infos).unwrap();
135 driver_infos.clear();
136 }
137 }
138 }
139 Ok(())
140 }
141
142 #[fasync::run_singlethreaded(test)]
143 async fn test_list_all() {
144 #[cfg(feature = "fdomain")]
145 let client = fdomain_local::local_client_empty();
146 let cmd = ListCommand::from_args(&["list"], &[]).unwrap();
147
148 let output = test_list(
149 #[cfg(feature = "fdomain")]
150 client,
151 cmd,
152 |request: fdd::ManagerRequest| async move {
153 match request {
154 fdd::ManagerRequest::GetDriverInfo {
155 driver_filter: _,
156 iterator,
157 control_handle: _,
158 } => run_driver_info_iterator_server(
159 vec![fdf::DriverInfo {
160 name: Some("foo".to_owned()),
161 url: Some(
162 "fuchsia-pkg://fuchsia.com/foo-package#meta/foo.cm".to_owned(),
163 ),
164 ..Default::default()
165 }],
166 iterator,
167 )
168 .await
169 .context("Failed to run driver info iterator server")?,
170 _ => {}
171 }
172 Ok(())
173 },
174 )
175 .await
176 .unwrap();
177
178 assert_eq!(
179 output,
180 "foo : fuchsia-pkg://fuchsia.com/foo-package#meta/foo.cm\n"
181 );
182 }
183
184 #[fasync::run_singlethreaded(test)]
185 async fn test_verbose_deprecated() {
186 #[cfg(feature = "fdomain")]
187 let client = fdomain_local::local_client_empty();
188 let cmd = ListCommand::from_args(&["list"], &["--verbose"]).unwrap();
189
190 let output = test_list(
191 #[cfg(feature = "fdomain")]
192 Arc::clone(&client),
193 cmd,
194 |request: fdd::ManagerRequest| async move {
195 match request {
196 fdd::ManagerRequest::GetDriverInfo {
197 driver_filter: _,
198 iterator,
199 control_handle: _,
200 } => run_driver_info_iterator_server(
201 vec![fdf::DriverInfo {
202 name: Some("foo".to_owned()),
203 url: Some(
204 "fuchsia-pkg://fuchsia.com/foo-package#meta/foo.cm".to_owned(),
205 ),
206 ..Default::default()
207 }],
208 iterator,
209 )
210 .await
211 .context("Failed to run driver info iterator server")?,
212 _ => {}
213 }
214 Ok(())
215 },
216 )
217 .await
218 .unwrap();
219
220 assert_eq!(
221 output,
222 "WARNING: The verbose flag is deprecated. Use `ffx driver show` instead.\n"
223 );
224 }
225}