iquery/commands/
selectors.rs1use crate::commands::types::*;
6use crate::commands::utils;
7use crate::types::Error;
8use argh::{ArgsInfo, FromArgs};
9use diagnostics_data::{InspectData, InspectHandleName};
10use diagnostics_hierarchy::DiagnosticsHierarchy;
11use fidl_fuchsia_diagnostics as fdiagnostics;
12use serde::ser::{Error as _, SerializeSeq};
13use serde::{Serialize, Serializer};
14use std::fmt;
15
16#[derive(ArgsInfo, FromArgs, PartialEq, Debug)]
18#[argh(subcommand, name = "selectors")]
19pub struct SelectorsCommand {
20 #[argh(positional)]
21 pub selectors: Vec<String>,
26
27 #[argh(option)]
28 pub data: Vec<String>,
32
33 #[argh(option)]
34 pub accessor: Option<String>,
39}
40
41impl Command for SelectorsCommand {
42 type Result = SelectorsResult;
43
44 async fn execute<P: DiagnosticsProvider>(self, provider: &P) -> Result<Self::Result, Error> {
45 if self.selectors.is_empty() && self.data.is_empty() {
46 return Err(Error::invalid_arguments("Expected 1 or more selectors. Got zero."));
47 }
48
49 let mut selectors = if self.data.is_empty() {
50 utils::process_fuzzy_inputs(self.selectors, provider).await?
51 } else {
52 if self.selectors.len() != 1 {
53 return Err(Error::WrongNumberOfSearchQueriesForDataFlag);
54 }
55 utils::process_component_query_with_partial_selectors(
56 &self.selectors[0],
57 self.data.into_iter(),
58 provider,
59 )
60 .await?
61 };
62
63 utils::ensure_tree_field_is_set(&mut selectors, None)?;
64 let mut results =
65 provider.snapshot(self.accessor.as_deref(), selectors.into_iter()).await?;
66 for result in results.iter_mut() {
67 if let Some(hierarchy) = &mut result.payload {
68 hierarchy.sort();
69 }
70 }
71 Ok(SelectorsResult(inspect_to_selectors(results)))
72 }
73}
74
75pub struct SelectorsResult(Vec<fdiagnostics::Selector>);
76
77impl Serialize for SelectorsResult {
78 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
79 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
80 let mut stringified = self
81 .0
82 .iter()
83 .map(|item| {
84 selectors::selector_to_string(
85 item,
86 selectors::SelectorDisplayOptions::never_wrap_in_quotes(),
87 )
88 .map_err(|e| S::Error::custom(format!("failed to serialize: {:#?}", e)))
89 })
90 .collect::<Result<Vec<_>, _>>()?;
91 stringified.sort();
92 for item in stringified {
93 seq.serialize_element(&item)?;
94 }
95
96 seq.end()
97 }
98}
99
100impl fmt::Display for SelectorsResult {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 let mut stringified = self
103 .0
104 .iter()
105 .map(|item| {
106 selectors::selector_to_string(item, selectors::SelectorDisplayOptions::default())
107 .map_err(|_| fmt::Error)
108 })
109 .collect::<Result<Vec<_>, _>>()?;
110 stringified.sort();
111 for item in stringified {
112 writeln!(f, "{item}")?;
113 }
114 Ok(())
115 }
116}
117
118fn get_selectors(
119 moniker: String,
120 hierarchy: DiagnosticsHierarchy,
121 name: InspectHandleName,
122) -> Vec<fdiagnostics::Selector> {
123 hierarchy
124 .property_iter()
125 .flat_map(|(node_path, maybe_property)| maybe_property.map(|prop| (node_path, prop)))
126 .map(|(node_path, property)| {
127 let node_path = node_path
128 .iter()
129 .map(|s| fdiagnostics::StringSelector::ExactMatch(s.to_string()))
130 .collect::<Vec<_>>();
131
132 let target_properties =
133 fdiagnostics::StringSelector::ExactMatch(property.name().to_string());
134
135 let tree_selector = Some(fdiagnostics::TreeSelector::PropertySelector(
136 fdiagnostics::PropertySelector { node_path, target_properties },
137 ));
138
139 let tree_names = Some(fdiagnostics::TreeNames::Some(vec![name.to_string()]));
140
141 let component_selector = Some(fdiagnostics::ComponentSelector {
142 moniker_segments: Some(
143 moniker
144 .split("/")
145 .map(|segment| {
146 fdiagnostics::StringSelector::ExactMatch(segment.to_string())
147 })
148 .collect(),
149 ),
150 ..Default::default()
151 });
152
153 fdiagnostics::Selector {
154 component_selector,
155 tree_selector,
156 tree_names,
157 ..Default::default()
158 }
159 })
160 .collect()
161}
162
163fn inspect_to_selectors(inspect_data: Vec<InspectData>) -> Vec<fdiagnostics::Selector> {
164 inspect_data
165 .into_iter()
166 .filter_map(|schema| {
167 let moniker = schema.moniker;
168 let name = schema.metadata.name;
169 schema.payload.map(|hierarchy| get_selectors(moniker.to_string(), hierarchy, name))
170 })
171 .flatten()
172 .collect()
173}