blob: a08182212569af493cae8af0745d17012a5095a9 [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::*,
location::{InspectLocation, InspectObject},
text_formatter,
types::{Error, ToText},
},
argh::FromArgs,
async_trait::async_trait,
derivative::Derivative,
diagnostics_hierarchy::DiagnosticsHierarchy,
serde::Serialize,
std::str::FromStr,
};
/// Given a path, prints the inspect contained in it. At the moment this command only
/// works for v1 components as we only have a v1 hub.
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "show-file")]
pub struct ShowFileCommand {
#[argh(positional)]
/// paths to query relative to the current directory. Minimum: 1
pub paths: Vec<String>,
}
#[derive(Derivative, Serialize, PartialEq)]
#[derivative(Ord, PartialOrd, Eq)]
pub struct ShowFileResultItem {
path: String,
#[derivative(Ord = "ignore", PartialOrd = "ignore")]
pub payload: DiagnosticsHierarchy,
}
impl ToText for Vec<ShowFileResultItem> {
fn to_text(self) -> String {
self.into_iter()
.map(|item| text_formatter::format(&item.path, item.payload))
.collect::<Vec<_>>()
.join("\n")
}
}
#[async_trait]
impl Command for ShowFileCommand {
type Result = Vec<ShowFileResultItem>;
async fn execute(&self) -> Result<Self::Result, Error> {
if self.paths.is_empty() {
return Err(Error::invalid_arguments("Expected 1 or more paths. Got zero."));
}
let mut results = Vec::new();
for path in expand_paths(&self.paths)? {
let location = match InspectLocation::from_str(&path) {
Err(_) => continue,
Ok(location) => location,
};
let path = location.path.to_string_lossy().to_string();
match location.load().await {
Err(e) => {
return Err(Error::ReadLocation(path.to_string(), e));
}
Ok(InspectObject { location, hierarchy: Some(mut hierarchy) }) => {
hierarchy.sort();
results.push(ShowFileResultItem {
payload: hierarchy,
path: location.absolute_path().unwrap_or(path),
});
}
Ok(_) => {}
}
}
Ok(results)
}
}
pub fn expand_paths(query_paths: &[String]) -> Result<Vec<String>, Error> {
let mut result = Vec::new();
for query_path in query_paths {
if query_path.ends_with(".inspect") {
if query_path.contains("*") {
println!(concat!(
"WARNING: you might no results when pointing directly to a *.inspect ",
"vmo file. This is due to http://fxbug.dev/40888. As a workaround use `*` ",
"instead of `root.inspect`."
));
} else {
// Just push this query path. For example, if the command was called with
// /hub/c/kcounter_inspect.cmx/\*/out/diagnostics/\* and the shell matched a single
// file then at least we'll get it here. Otherwise due to http://fxbug.dev/40888,
// glob will return an empty list for vmo files.
// TODO(fxbug.dev/40888): remove this
result.push(query_path.clone());
continue;
}
}
let path_results = glob::glob(&query_path)
.map_err(|e| Error::ParsePath(query_path.clone(), e.into()))?
.collect::<Vec<_>>();
for path_result in path_results {
let path = path_result.map_err(|e| Error::ParsePath(query_path.clone(), e.into()))?;
result.push(path.to_string_lossy().to_string());
}
}
Ok(result)
}