blob: 3e0bcbdff330abee5fa5a4fea803108028adc9db [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},
text_formatter,
types::Error,
},
argh::{ArgsInfo, FromArgs},
async_trait::async_trait,
derivative::Derivative,
diagnostics_data::{Inspect, InspectData, InspectHandleName},
serde::Serialize,
std::{cmp::Ordering, fmt, ops::Deref},
};
#[derive(Derivative, Serialize, PartialEq)]
#[derivative(Eq)]
pub struct ShowResultItem(InspectData);
impl Deref for ShowResultItem {
type Target = InspectData;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl PartialOrd for ShowResultItem {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ShowResultItem {
fn cmp(&self, other: &Self) -> Ordering {
self.moniker.cmp(&other.moniker).then_with(|| {
let this_name = self.metadata.name.as_ref().map(InspectHandleName::as_ref);
let other_name = other.metadata.name.as_ref().map(InspectHandleName::as_ref);
this_name.cmp(&other_name)
})
}
}
#[derive(Serialize)]
pub struct ShowResult(Vec<ShowResultItem>);
impl fmt::Display for ShowResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for item in self.0.iter() {
text_formatter::output_schema(f, &item.0)?;
}
Ok(())
}
}
/// Prints the inspect hierarchies that match the given selectors.
#[derive(ArgsInfo, FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "show")]
pub struct ShowCommand {
#[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 representing the Inspect data that should be queried.
///
/// If no selectors are provided, Inspect data for the whole system will be returned.
///
/// This command accepts the following as a selector:
///
/// - A component moniker, for example, `core/network/netstack`. Doesn't work if
/// `--manifest` is passed.
/// - A component selector, for example, `core/network/*`. Doesn't work if `--manifest`
/// is passed.
/// - A tree selector, for example, `core/network/netstack:root/path/to/*:property`
///
/// To learn more about selectors see
/// https://fuchsia.dev/fuchsia-src/reference/diagnostics/selectors.
///
/// The following characters in a selector must be escaped with `\`: `*`, `:`, `\`, `/` and
/// whitespace.
///
/// When `*` or other characters cause ambiguity with your shell, make sure to wrap the
/// selector in single or double quotes. For example:
/// `ffx inspect show "bootstrap/boot-drivers:*:root/path/to\:some:prop"`
pub selectors: Vec<String>,
#[argh(option)]
/// A string 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 ShowCommand {
type Result = ShowResult;
async fn execute<P: DiagnosticsProvider>(&self, provider: &P) -> Result<Self::Result, Error> {
let selectors = utils::get_selectors_for_manifest(
&self.manifest,
&self.selectors,
&self.accessor,
provider,
)
.await?;
let selectors = utils::expand_selectors(selectors)?;
let inspect_data_iter =
provider.snapshot::<Inspect>(&self.accessor, &selectors).await?.into_iter();
let mut results = inspect_data_iter
.map(|mut d: InspectData| {
if let Some(hierarchy) = &mut d.payload {
hierarchy.sort();
}
ShowResultItem(d)
})
.collect::<Vec<_>>();
results.sort();
Ok(ShowResult(results))
}
}