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 flex_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 = provider.snapshot(self.accessor.as_deref(), selectors).await?;
65 for result in results.iter_mut() {
66 if let Some(hierarchy) = &mut result.payload {
67 hierarchy.sort();
68 }
69 }
70 Ok(SelectorsResult(inspect_to_selectors(results)))
71 }
72}
73
74pub struct SelectorsResult(Vec<fdiagnostics::Selector>);
75
76impl Serialize for SelectorsResult {
77 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
78 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
79 let mut stringified = self
80 .0
81 .iter()
82 .map(|item| {
83 selectors::selector_to_string(
84 item,
85 selectors::SelectorDisplayOptions::never_wrap_in_quotes(),
86 )
87 .map_err(|e| S::Error::custom(format!("failed to serialize: {e:#?}")))
88 })
89 .collect::<Result<Vec<_>, _>>()?;
90 stringified.sort();
91 for item in stringified {
92 seq.serialize_element(&item)?;
93 }
94
95 seq.end()
96 }
97}
98
99impl fmt::Display for SelectorsResult {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 let mut stringified = self
102 .0
103 .iter()
104 .map(|item| {
105 selectors::selector_to_string(item, selectors::SelectorDisplayOptions::default())
106 .map_err(|_| fmt::Error)
107 })
108 .collect::<Result<Vec<_>, _>>()?;
109 stringified.sort();
110 for item in stringified {
111 writeln!(f, "{item}")?;
112 }
113 Ok(())
114 }
115}
116
117fn get_selectors(
118 moniker: String,
119 hierarchy: DiagnosticsHierarchy,
120 name: InspectHandleName,
121) -> Vec<fdiagnostics::Selector> {
122 hierarchy
123 .property_iter()
124 .flat_map(|(node_path, maybe_property)| maybe_property.map(|prop| (node_path, prop)))
125 .map(|(node_path, property)| {
126 let node_path = node_path
127 .iter()
128 .map(|s| fdiagnostics::StringSelector::ExactMatch(s.to_string()))
129 .collect::<Vec<_>>();
130
131 let target_properties =
132 fdiagnostics::StringSelector::ExactMatch(property.name().to_string());
133
134 let tree_selector = Some(fdiagnostics::TreeSelector::PropertySelector(
135 fdiagnostics::PropertySelector { node_path, target_properties },
136 ));
137
138 let tree_names = Some(fdiagnostics::TreeNames::Some(vec![name.to_string()]));
139
140 let component_selector = Some(fdiagnostics::ComponentSelector {
141 moniker_segments: Some(
142 moniker
143 .split("/")
144 .map(|segment| {
145 fdiagnostics::StringSelector::ExactMatch(segment.to_string())
146 })
147 .collect(),
148 ),
149 ..Default::default()
150 });
151
152 fdiagnostics::Selector {
153 component_selector,
154 tree_selector,
155 tree_names,
156 ..Default::default()
157 }
158 })
159 .collect()
160}
161
162fn inspect_to_selectors(inspect_data: Vec<InspectData>) -> Vec<fdiagnostics::Selector> {
163 inspect_data
164 .into_iter()
165 .filter_map(|schema| {
166 let moniker = schema.moniker;
167 let name = schema.metadata.name;
168 schema.payload.map(|hierarchy| get_selectors(moniker.to_string(), hierarchy, name))
169 })
170 .flatten()
171 .collect()
172}