blob: 6141255f5784cf5415bcaa25956a82a52b660a6d [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::{
commands::{types::*, utils},
types::Error,
},
argh::{ArgsInfo, FromArgs},
async_trait::async_trait,
diagnostics_data::{Inspect, InspectData},
diagnostics_hierarchy::DiagnosticsHierarchy,
serde::Serialize,
std::fmt,
};
/// Lists all available full selectors (component selector + tree selector).
/// If a selector is provided, it’ll only print selectors for that component.
/// If a full selector (component + tree) is provided, it lists all selectors under the given node.
#[derive(ArgsInfo, FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "selectors")]
pub struct SelectorsCommand {
#[argh(option)]
/// the name of the manifest file that we are interested in. If this is provided, the output
/// will only contain monikers for components whose url contains the provided name.
pub manifest: Option<String>,
#[argh(positional)]
/// selectors for which the selectors should be queried. Minimum: 1 unless `--manifest` is set.
/// When `--manifest` is provided then the selectors should be tree selectors, otherwise
/// they can be component selectors or full selectors.
pub selectors: Vec<String>,
#[argh(option)]
/// A selector specifying what `fuchsia.diagnostics.ArchiveAccessor` to connect to.
/// The selector will be in the form of:
/// <moniker>:<directory>:fuchsia.diagnostics.ArchiveAccessorName
///
/// Typically this is the output of `iquery list-accessors`.
///
/// For example: `bootstrap/archivist:expose:fuchsia.diagnostics.FeedbackArchiveAccessor`
/// means that the command will connect to the `FeedbackArchiveAccecssor`
/// exposed by `bootstrap/archivist`.
pub accessor: Option<String>,
}
#[async_trait]
impl Command for SelectorsCommand {
type Result = SelectorsResult;
async fn execute<P: DiagnosticsProvider>(&self, provider: &P) -> Result<Self::Result, Error> {
if self.selectors.is_empty() && self.manifest.is_none() {
return Err(Error::invalid_arguments("Expected 1 or more selectors. Got zero."));
}
let selectors = utils::get_selectors_for_manifest(
&self.manifest,
&self.selectors,
&self.accessor,
provider,
)
.await?;
let selectors = utils::expand_selectors(selectors)?;
let mut results = provider.snapshot::<Inspect>(&self.accessor, &selectors).await?;
for result in results.iter_mut() {
if let Some(hierarchy) = &mut result.payload {
hierarchy.sort();
}
}
Ok(SelectorsResult(inspect_to_selectors(results)))
}
}
#[derive(Serialize)]
pub struct SelectorsResult(Vec<String>);
impl fmt::Display for SelectorsResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for item in self.0.iter() {
writeln!(f, "{}", item)?;
}
Ok(())
}
}
fn get_selectors(moniker: String, hierarchy: DiagnosticsHierarchy) -> Vec<String> {
let component_selector = selectors::sanitize_moniker_for_selectors(&moniker);
hierarchy
.property_iter()
.flat_map(|(node_path, maybe_property)| maybe_property.map(|prop| (node_path, prop)))
.map(|(node_path, property)| {
let node_selector = node_path
.iter()
.map(|s| selectors::sanitize_string_for_selectors(s))
.collect::<Vec<_>>()
.join("/");
let property_selector = selectors::sanitize_string_for_selectors(property.name());
format!("{}:{}:{}", component_selector, node_selector, property_selector)
})
.collect()
}
fn inspect_to_selectors(inspect_data: Vec<InspectData>) -> Vec<String> {
let mut result = inspect_data
.into_iter()
.filter_map(|schema| {
let moniker = schema.moniker;
schema.payload.map(|hierarchy| get_selectors(moniker, hierarchy))
})
.flat_map(|results| results)
.collect::<Vec<_>>();
result.sort();
result
}