driver_tools/subcommands/list_composites/
mod.rs1pub mod args;
6
7use anyhow::{Context, Result};
8use args::ListCompositesCommand;
9use flex_client::ProxyHasDomain;
10use flex_fuchsia_driver_development as fdd;
11use flex_fuchsia_driver_framework as fdf;
12use std::io::Write;
13
14pub async fn list_composites(
15 cmd: ListCompositesCommand,
16 writer: &mut dyn Write,
17 proxy: fdd::ManagerProxy,
18) -> Result<()> {
19 writeln!(
20 writer,
21 "WARNING: This command is deprecated. Use `ffx driver composite list` instead."
22 )?;
23
24 let (iterator, iterator_server) =
25 proxy.domain().create_proxy::<fdd::CompositeInfoIteratorMarker>();
26 proxy.get_composite_info(iterator_server).context("GetCompositeInfo() failed")?;
27
28 loop {
29 let composite_list =
30 iterator.get_next().await.context("CompositeInfoIterator GetNext() failed")?;
31
32 if composite_list.is_empty() {
33 break;
34 }
35
36 for composite_node in composite_list {
37 match composite_node.composite {
38 Some(fdd::CompositeInfo::Composite(info)) => {
39 write_composite(
40 writer,
41 info,
42 composite_node.parent_topological_paths.unwrap(),
43 composite_node.topological_path,
44 cmd.verbose,
45 )?;
46 }
47 _ => {}
48 }
49 }
50 }
51
52 Ok(())
53}
54
55fn write_composite(
56 writer: &mut dyn Write,
57 composite: fdf::CompositeInfo,
58 parent_topological_paths: Vec<Option<String>>,
59 topological_path: Option<String>,
60 verbose: bool,
61) -> Result<()> {
62 let spec = composite.spec.unwrap_or_default();
63 let driver_match = composite.matched_driver.unwrap_or_default();
64 if !verbose {
65 writeln!(writer, "{}", spec.name.unwrap_or_else(|| "".to_string()))?;
66 return Ok(());
67 }
68
69 writeln!(writer, "{0: <9}: {1}", "Name", spec.name.unwrap_or_else(|| "".to_string()))?;
70 writeln!(
71 writer,
72 "{0: <9}: {1}",
73 "Driver",
74 driver_match
75 .composite_driver
76 .and_then(|composite_driver| composite_driver.driver_info)
77 .and_then(|driver_info| driver_info.url)
78 .unwrap_or_else(|| "N/A".to_string())
79 )?;
80 writeln!(
81 writer,
82 "{0: <9}: {1}",
83 "Device",
84 topological_path.unwrap_or_else(|| "N/A".to_string())
85 )?;
86
87 write_parent_nodes_info(
88 writer,
89 driver_match.primary_parent_index,
90 driver_match.parent_names.unwrap_or_default(),
91 parent_topological_paths,
92 )?;
93
94 writeln!(writer)?;
95 Ok(())
96}
97
98fn write_parent_nodes_info(
99 writer: &mut dyn Write,
100 primary_index: Option<u32>,
101 parent_names: Vec<String>,
102 parent_paths: Vec<Option<String>>,
103) -> Result<()> {
104 writeln!(writer, "{0: <9}: {1}", "Parents", parent_names.len())?;
105 for (i, parent_name) in parent_names.into_iter().enumerate() {
106 let primary_tag = if primary_index == Some(i as u32) { "(Primary)" } else { "" };
107 writeln!(writer, "{0: <1} {1} : {2} {3}", "Parent", i, parent_name, primary_tag)?;
108
109 writeln!(
110 writer,
111 " {0: <1} : {1}",
112 "Device",
113 parent_paths[i].clone().unwrap_or_else(|| "Unbound".to_string())
114 )?;
115 }
116 Ok(())
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
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 #[fuchsia::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 #[fuchsia::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}