blob: 90ce8cfdeff71bff33a6a7d20f3689e18176ac8d [file] [log] [blame]
// Copyright 2019 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.
#![feature(async_await, await_macro)]
use failure::{err_msg, format_err, Error, ResultExt};
use fidl_fuchsia_sys_index::{ComponentIndexMarker, FuzzySearchError};
use fuchsia_async as fasync;
use fuchsia_component::client::{launch, launcher};
use std::convert::{TryFrom, TryInto};
use std::env;
#[fasync::run_singlethreaded]
async fn main() {
match await!(run_locate()) {
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
Ok(()) => {}
}
}
async fn run_locate() -> Result<(), Error> {
let cfg: LocateConfig = env::args().try_into()?;
let launcher = launcher().context("Failed to open launcher service.")?;
let app = launch(
&launcher,
"fuchsia-pkg://fuchsia.com/component_index#meta/component_index.cmx".to_string(),
None,
)
.context("Failed to launch component_index service.")?;
let component_index = app
.connect_to_service::<ComponentIndexMarker>()
.context("Failed to connect to component_index service.")?;
match await!(component_index.fuzzy_search(&cfg.search_keyword))? {
Ok(res_vec) => fuzzy_search_result(res_vec, cfg),
Err(e) => fuzzy_search_error(e, cfg),
}
}
fn fuzzy_search_result(res_vec: Vec<String>, cfg: LocateConfig) -> Result<(), Error> {
if res_vec.is_empty() {
return Err(format_err!("\"{}\" did not match any components.", cfg.search_keyword));
}
if cfg.list {
for res in &res_vec {
println!("{}", res);
}
} else {
if res_vec.len() == 1 {
println!("{}", res_vec[0]);
} else {
for res in &res_vec {
eprintln!("{}", res);
}
return Err(format_err!(
"\"{}\" matched more than one component. Try `locate --list` instead.",
cfg.search_keyword
));
}
}
Ok(())
}
fn fuzzy_search_error(e: FuzzySearchError, cfg: LocateConfig) -> Result<(), Error> {
if e == FuzzySearchError::MalformedInput {
return Err(format_err!(
"\"{}\" contains unsupported characters. Valid characters are [A-Z a-z 0-9 / _ - .].",
cfg.search_keyword
));
}
Err(err_msg("fuchsia.sys.index.FuzzySearch could not serve the input query."))
}
struct LocateConfig {
list: bool,
search_keyword: String,
}
impl TryFrom<env::Args> for LocateConfig {
type Error = Error;
fn try_from(args: env::Args) -> Result<LocateConfig, Error> {
let mut args = args.peekable();
// Ignore arg[0]
let _ = args.next();
// Consume arg[1] if it is --list
let list = args.peek() == Some(&"--list".to_string());
if list {
let _ = args.next();
}
// Ensure nothing beyond current arg.
if let (Some(search_keyword), None) = (args.next(), args.next()) {
return Ok(LocateConfig { list, search_keyword });
} else {
help();
return Err(err_msg("Unable to parse args."));
}
}
}
fn help() {
println!(
r"Usage: locate [--list] <search_keyword>
Locates the fuchsia-pkg URL of <search_keyword>.
Options:
--list Allows matching of more than one component."
)
}