driver_tools/subcommands/list_composites/
mod.rs1pub mod args;
6
7use anyhow::{Context, Result};
8use args::ListCompositesCommand;
9use flex_client::ProxyHasDomain;
10use std::io::Write;
11use {flex_fuchsia_driver_development as fdd, flex_fuchsia_driver_framework as fdf};
12
13pub async fn list_composites(
14 cmd: ListCompositesCommand,
15 writer: &mut dyn Write,
16 proxy: fdd::ManagerProxy,
17) -> Result<()> {
18 writeln!(
19 writer,
20 "WARNING: This command is deprecated. Use `ffx driver composite list` instead."
21 )?;
22
23 let (iterator, iterator_server) =
24 proxy.domain().create_proxy::<fdd::CompositeInfoIteratorMarker>();
25 proxy.get_composite_info(iterator_server).context("GetCompositeInfo() failed")?;
26
27 loop {
28 let composite_list =
29 iterator.get_next().await.context("CompositeInfoIterator GetNext() failed")?;
30
31 if composite_list.is_empty() {
32 break;
33 }
34
35 for composite_node in composite_list {
36 match composite_node.composite {
37 Some(fdd::CompositeInfo::Composite(info)) => {
38 write_composite(
39 writer,
40 info,
41 composite_node.parent_topological_paths.unwrap(),
42 composite_node.topological_path,
43 cmd.verbose,
44 )?;
45 }
46 _ => {}
47 }
48 }
49 }
50
51 Ok(())
52}
53
54fn write_composite(
55 writer: &mut dyn Write,
56 composite: fdf::CompositeInfo,
57 parent_topological_paths: Vec<Option<String>>,
58 topological_path: Option<String>,
59 verbose: bool,
60) -> Result<()> {
61 let spec = composite.spec.unwrap_or_default();
62 let driver_match = composite.matched_driver.unwrap_or_default();
63 if !verbose {
64 writeln!(writer, "{}", spec.name.unwrap_or_else(|| "".to_string()))?;
65 return Ok(());
66 }
67
68 writeln!(writer, "{0: <9}: {1}", "Name", spec.name.unwrap_or_else(|| "".to_string()))?;
69 writeln!(
70 writer,
71 "{0: <9}: {1}",
72 "Driver",
73 driver_match
74 .composite_driver
75 .and_then(|composite_driver| composite_driver.driver_info)
76 .and_then(|driver_info| driver_info.url)
77 .unwrap_or_else(|| "N/A".to_string())
78 )?;
79 writeln!(
80 writer,
81 "{0: <9}: {1}",
82 "Device",
83 topological_path.unwrap_or_else(|| "N/A".to_string())
84 )?;
85
86 write_parent_nodes_info(
87 writer,
88 driver_match.primary_parent_index,
89 driver_match.parent_names.unwrap_or_default(),
90 parent_topological_paths,
91 )?;
92
93 writeln!(writer)?;
94 Ok(())
95}
96
97fn write_parent_nodes_info(
98 writer: &mut dyn Write,
99 primary_index: Option<u32>,
100 parent_names: Vec<String>,
101 parent_paths: Vec<Option<String>>,
102) -> Result<()> {
103 writeln!(writer, "{0: <9}: {1}", "Parents", parent_names.len())?;
104 for (i, parent_name) in parent_names.into_iter().enumerate() {
105 let primary_tag = if primary_index == Some(i as u32) { "(Primary)" } else { "" };
106 writeln!(writer, "{0: <1} {1} : {2} {3}", "Parent", i, parent_name, primary_tag)?;
107
108 writeln!(
109 writer,
110 " {0: <1} : {1}",
111 "Device",
112 parent_paths[i].clone().unwrap_or_else(|| "Unbound".to_string())
113 )?;
114 }
115 Ok(())
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use fuchsia_async as fasync;
122 use std::io::Error;
123
124 pub struct TestWriteBuffer {
125 pub content: String,
126 }
127
128 impl Write for TestWriteBuffer {
129 fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
130 self.content.push_str(std::str::from_utf8(buf).unwrap());
131 Ok(buf.len())
132 }
133
134 fn flush(&mut self) -> Result<(), Error> {
135 Ok(())
136 }
137 }
138
139 #[fasync::run_singlethreaded(test)]
140 async fn test_composite_verbose() {
141 let test_composite = fdf::CompositeInfo {
142 spec: Some(fdf::CompositeNodeSpec {
143 name: Some("composite_dev".to_string()),
144 ..Default::default()
145 }),
146 matched_driver: Some(fdf::CompositeDriverMatch {
147 composite_driver: Some(fdf::CompositeDriverInfo {
148 driver_info: Some(fdf::DriverInfo {
149 url: Some("fuchsia-boot:///#meta/waxwing.cm".to_string()),
150 ..Default::default()
151 }),
152 ..Default::default()
153 }),
154 parent_names: Some(vec!["sysmem".to_string(), "acpi".to_string()]),
155 primary_parent_index: Some(1),
156 ..Default::default()
157 }),
158 ..Default::default()
159 };
160
161 let mut test_write_buffer = TestWriteBuffer { content: "".to_string() };
162 writeln!(
163 &mut test_write_buffer,
164 "WARNING: This command is deprecated. Use `ffx driver composite list` instead."
165 )
166 .unwrap();
167 write_composite(
168 &mut test_write_buffer,
169 test_composite,
170 vec![Some("path/sysmem_dev".to_string()), Some("path/acpi_dev".to_string())],
171 Some("dev/sys/composite_dev".to_string()),
172 true,
173 )
174 .unwrap();
175 assert_eq!(
176 format!(
177 "WARNING: This command is deprecated. Use `ffx driver composite list` instead.\n{}",
178 include_str!("../../../tests/golden/list_composites_verbose")
179 ),
180 test_write_buffer.content
181 );
182 }
183
184 #[fasync::run_singlethreaded(test)]
185 async fn test_composite_verbose_empty_fields() {
186 let test_composite = fdf::CompositeInfo {
187 spec: Some(fdf::CompositeNodeSpec {
188 name: Some("composite_dev".to_string()),
189 ..Default::default()
190 }),
191 matched_driver: Some(fdf::CompositeDriverMatch {
192 composite_driver: Some(fdf::CompositeDriverInfo {
193 composite_name: Some("composite_name".to_string()),
194 driver_info: Some(fdf::DriverInfo {
195 url: Some("fuchsia-boot:///#meta/waxwing.cm".to_string()),
196 ..Default::default()
197 }),
198 ..Default::default()
199 }),
200 parent_names: Some(vec!["sysmem".to_string(), "acpi".to_string()]),
201 primary_parent_index: Some(1),
202 ..Default::default()
203 }),
204 ..Default::default()
205 };
206
207 let mut test_write_buffer = TestWriteBuffer { content: "".to_string() };
208 writeln!(
209 &mut test_write_buffer,
210 "WARNING: This command is deprecated. Use `ffx driver composite list` instead."
211 )
212 .unwrap();
213 write_composite(
214 &mut test_write_buffer,
215 test_composite,
216 vec![None, None],
217 Some("dev/sys/composite_dev".to_string()),
218 true,
219 )
220 .unwrap();
221 println!("{}", test_write_buffer.content);
222
223 assert_eq!(
224 format!(
225 "WARNING: This command is deprecated. Use `ffx driver composite list` instead.\n{}",
226 include_str!("../../../tests/golden/list_composites_verbose_empty_fields")
227 ),
228 test_write_buffer.content
229 );
230 }
231}