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