diff options
-rw-r--r-- | fatcat-cli/src/commands.rs | 34 | ||||
-rw-r--r-- | fatcat-cli/src/lib.rs | 23 | ||||
-rw-r--r-- | fatcat-cli/src/main.rs | 68 | ||||
-rw-r--r-- | fatcat-cli/src/search.rs | 18 |
4 files changed, 104 insertions, 39 deletions
diff --git a/fatcat-cli/src/commands.rs b/fatcat-cli/src/commands.rs index 15bfc81..3074937 100644 --- a/fatcat-cli/src/commands.rs +++ b/fatcat-cli/src/commands.rs @@ -12,7 +12,7 @@ use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; use crate::{ entity_model_from_json_str, read_entity_file, ApiModelSer, EntityType, FatcatApiClient, - Mutation, Specifier, + Mutation, Specifier, SearchEntityType, SearchResults, }; // Want to show: @@ -274,6 +274,38 @@ pub fn print_entity_histories( Ok(()) } +pub fn print_search_table(results: SearchResults, entity_type: SearchEntityType) -> Result<()> { + let mut tw = TabWriter::new(std::io::stdout()); + match entity_type { + SearchEntityType::Release => { + writeln!( + tw, + "release_ident\ttype\tstage\tyear\tcontainer_name\ttitle" + )?; + } + //"ident\tissnl\tname" + } + for hit in results { + let hit = hit?; + match entity_type { + SearchEntityType::Release => { + writeln!( + tw, + "{}\t{}\t{}\t{}\t{}\t{}", + hit["ident"].as_str().unwrap_or("-"), + hit["release_type"].as_str().unwrap_or("-"), + hit["release_stage"].as_str().unwrap_or("-"), + hit["release_year"].as_u64().map_or("-".to_string(), |v| v.to_string()), + hit["container_name"].as_str().unwrap_or("-"), + hit["title"].as_str().unwrap_or("-"), + )?; + } + } + } + tw.flush()?; + Ok(()) +} + pub fn edit_entity_locally( api_client: &mut FatcatApiClient, specifier: Specifier, diff --git a/fatcat-cli/src/lib.rs b/fatcat-cli/src/lib.rs index d648c1c..8706774 100644 --- a/fatcat-cli/src/lib.rs +++ b/fatcat-cli/src/lib.rs @@ -14,6 +14,7 @@ mod specifier; pub use api::FatcatApiClient; pub use commands::{ edit_entity_locally, print_changelog_entries, print_editgroups, print_entity_histories, + print_search_table, BatchGrouper, BatchOp, ClientStatus, }; pub use download::{download_batch, download_file, download_release}; @@ -21,7 +22,7 @@ pub use entities::{ entity_model_from_json_str, read_entity_file, ApiEntityModel, ApiModelIdent, ApiModelSer, Mutation, }; -pub use search::crude_search; +pub use search::{crude_search, SearchResults}; pub use specifier::Specifier; #[derive(Debug, PartialEq, Clone, Copy)] @@ -52,6 +53,26 @@ impl FromStr for EntityType { } } +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum SearchEntityType { + Release, + // TODO: Container, + // TODO: Fulltext, +} + +impl FromStr for SearchEntityType { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "release" | "releases" => Ok(SearchEntityType::Release), + //"container" | "containers" => Ok(SearchEntityType::Container), + //"fulltext" | "scholar" => Ok(SearchEntityType::Fulltext), + _ => Err(anyhow!("invalid entity type : {}", s)), + } + } +} + /// Takes a macaroon token (as base64-encoded string) and tries to parse out an editor id pub fn parse_macaroon_editor_id(s: &str) -> Result<String> { let raw = BASE64 diff --git a/fatcat-cli/src/main.rs b/fatcat-cli/src/main.rs index 6e3f2c7..72cb169 100644 --- a/fatcat-cli/src/main.rs +++ b/fatcat-cli/src/main.rs @@ -224,9 +224,9 @@ enum Command { json: bool, }, Search { - entity_type: EntityType, + entity_type: SearchEntityType, - terms: Vec<String>, + query: Vec<String>, #[structopt(long = "--expand")] expand: Option<String>, @@ -234,11 +234,17 @@ enum Command { #[structopt(long = "--hide")] hide: Option<String>, + #[structopt(long = "--count")] + count: bool, + #[structopt(long, short = "-n", default_value = "20")] limit: i64, - #[structopt(long = "--search-schema")] - search_schema: bool, + #[structopt(long = "--entity-json")] + entity_json: bool, + + #[structopt(long = "--index-json")] + index_json: bool, }, Editgroup { #[structopt(subcommand)] @@ -509,34 +515,46 @@ fn run(opt: Opt) -> Result<()> { } Command::Search { entity_type, - terms, + query, limit, - search_schema, + count, + entity_json, + index_json, expand, hide, } => { - let limit: Option<u64> = match limit { - l if l <= 0 => None, - l => Some(l as u64), + // TODO: ensure that we don't try print more than ~1000 hits with tabwriter? + let limit: Option<u64> = match (count, limit) { + (true, _) => Some(0), + (false, l) if l <= 0 => None, + (false, l) => Some(l as u64), }; - let results = fatcat_cli::crude_search(&opt.search_host, entity_type, limit, terms) + let results = fatcat_cli::crude_search(&opt.search_host, entity_type, limit, query) .with_context(|| format!("searching for {:?}", entity_type))?; - eprintln!("Got {} hits in {}ms", results.count, results.took_ms); - for hit in results { - let hit = hit?; - match (search_schema, entity_type) { - (true, _) => writeln!(&mut std::io::stdout(), "{}", hit.to_string())?, - (false, EntityType::Release) => { - let specifier = - Specifier::Release(hit["ident"].as_str().unwrap().to_string()); - let entity = specifier.get_from_api( - &mut api_client, - expand.clone(), - hide.clone(), - )?; - writeln!(&mut std::io::stdout(), "{}", entity.to_json_string()?)? + if count { + println!("{}", results.count); + } else { + eprintln!("Got {} hits in {}ms", results.count, results.took_ms); + if !(index_json || entity_json) { + print_search_table(results, entity_type)?; + } else { + for hit in results { + let hit = hit?; + match (index_json, entity_json, entity_type) { + (false, false, _) => unreachable!("case handled above"), + (true, _, _) => writeln!(&mut std::io::stdout(), "{}", hit.to_string())?, + (false, true, SearchEntityType::Release) => { + let specifier = + Specifier::Release(hit["ident"].as_str().unwrap().to_string()); + let entity = specifier.get_from_api( + &mut api_client, + expand.clone(), + hide.clone(), + )?; + writeln!(&mut std::io::stdout(), "{}", entity.to_json_string()?)? + } + } } - (false, _) => unimplemented!("searching other entity types"), } } } diff --git a/fatcat-cli/src/search.rs b/fatcat-cli/src/search.rs index f778477..f328ee9 100644 --- a/fatcat-cli/src/search.rs +++ b/fatcat-cli/src/search.rs @@ -1,11 +1,11 @@ -use crate::EntityType; +use crate::SearchEntityType; use anyhow::{anyhow, Result}; use log::{self, info}; use serde_json::json; use std::time::Duration; pub struct SearchResults { - pub entity_type: EntityType, + pub entity_type: SearchEntityType, pub limit: Option<u64>, pub count: u64, pub took_ms: u64, @@ -71,20 +71,14 @@ impl Iterator for SearchResults { pub fn crude_search( api_host: &str, - entity_type: EntityType, + entity_type: SearchEntityType, limit: Option<u64>, terms: Vec<String>, ) -> Result<SearchResults> { let index = match entity_type { - EntityType::Release => "fatcat_release", - EntityType::File => "fatcat_file", - EntityType::Container => "fatcat_container", - _ => { - return Err(anyhow!( - "No search index for entity type: {:?}", - entity_type - )) - } + SearchEntityType::Release => "fatcat_release", + //SearchEntityType::File => "fatcat_file", + //SearchEntityType::Container => "fatcat_container", }; let http_client = reqwest::blocking::Client::builder() .timeout(Duration::from_secs(10)) |