blob: 84d0923515da2c924c37112a82138b89ec587b6a [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::FromArgs,
async_trait::async_trait,
diagnostics_hierarchy::DiagnosticsHierarchy,
selectors,
};
/// 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(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)]
/// the path from where to get the ArchiveAccessor connection. If the given path is a
/// directory, the command will look for a `fuchsia.diagnostics.ArchiveAccessor` service file.
/// If the given path is a service file, the command will attempt to connect to it as an
/// ArchiveAccessor.
pub accessor_path: Option<String>,
}
#[async_trait]
impl Command for SelectorsCommand {
type Result = Vec<String>;
async fn execute(&self) -> 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_path)
.await?;
let mut result = utils::fetch_data(&selectors, &self.accessor_path)
.await?
.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();
Ok(result)
}
}
fn get_selectors(component_selector: String, hierarchy: DiagnosticsHierarchy) -> Vec<String> {
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<String>>()
.join("/");
let property_selector = selectors::sanitize_string_for_selectors(property.name());
format!("{}:{}:{}", component_selector, node_selector, property_selector)
})
.collect()
}