summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2021-04-07 20:28:23 +0200
committerMatthias Beyer <mail@beyermatthias.de>2021-04-07 20:28:23 +0200
commit0351f3f9c3ddb1545f324f6902848e3abf6c3ce3 (patch)
treeb1f5a10e48943898bfac7f07a1cfaccbfab9feeb
parent96d5a42bf96b9dc74b2f2dbc55c71b74230047a6 (diff)
Add CLI interface for project(s)
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--src/cli.rs110
-rw-r--r--src/main.rs83
2 files changed, 193 insertions, 0 deletions
diff --git a/src/cli.rs b/src/cli.rs
index 6fa6a23..e3a21c4 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -21,5 +21,115 @@ pub fn app<'a, 'b>() -> App<'a, 'b> {
.help("Get problems for a repo REPO")
)
)
+
+ .subcommand(App::new("project")
+ .version(crate_version!())
+ .about("Query repology for a project")
+
+ .arg(Arg::with_name("name")
+ .index(1)
+ .required(true)
+ .multiple(false)
+ .value_name("NAME")
+ .help("Get the project NAME")
+ )
+ )
+
+ .subcommand(App::new("projects")
+ .version(crate_version!())
+ .about("Query repology for a project by a certain filter")
+
+ .arg(Arg::with_name("search")
+ .long("search")
+ .required(false)
+ .multiple(false)
+ .value_name("SEARCH")
+ .help("project name substring to look for")
+ )
+ .arg(Arg::with_name("maintainer")
+ .long("maintainer")
+ .required(false)
+ .multiple(false)
+ .takes_value(true)
+ .value_name("MAINTAINER")
+ .help("return projects maintainer by specified person")
+ )
+ .arg(Arg::with_name("category")
+ .long("category")
+ .required(false)
+ .multiple(false)
+ .takes_value(true)
+ .value_name("CATEGORY")
+ .help("return projects with specified category")
+ )
+ .arg(Arg::with_name("in_repo_filter")
+ .long("in-repo")
+ .required(false)
+ .multiple(false)
+ .takes_value(true)
+ .value_name("REPO")
+ .help("return projects present in specified repository")
+ )
+ .arg(Arg::with_name("not_in_repo_filter")
+ .long("not-in-repo")
+ .required(false)
+ .multiple(false)
+ .takes_value(true)
+ .value_name("REPO")
+ .help("return projects absent in specified repository")
+ )
+ .arg(Arg::with_name("repos_filter")
+ .long("repos")
+ .required(false)
+ .multiple(false)
+ .takes_value(true)
+ .value_name("N")
+ .help("return projects present in specified number of repositories (exact values and open/closed ranges are allowed, e.g. 1, 5-, -5, 2-7")
+ )
+ .arg(Arg::with_name("families_filter")
+ .long("families")
+ .required(false)
+ .multiple(false)
+ .takes_value(true)
+ .value_name("FAMS")
+ .help("return projects present in specified number of repository families (for instance, use 1 to get unique projects)")
+ )
+ .arg(Arg::with_name("repos_newest")
+ .long("newest-repos")
+ .required(false)
+ .multiple(false)
+ .takes_value(false)
+ .help("return projects which are up to date in specified number of repositories")
+ )
+ .arg(Arg::with_name("families_newest")
+ .long("newest-families")
+ .required(false)
+ .multiple(false)
+ .value_name("")
+ .takes_value(false)
+ .help("return projects which are up to date in specified number of repository families")
+ )
+ .arg(Arg::with_name("newest")
+ .long("newest")
+ .required(false)
+ .multiple(false)
+ .takes_value(false)
+ .help("return newest projects only")
+ )
+ .arg(Arg::with_name("outdated")
+ .long("outdated")
+ .required(false)
+ .multiple(false)
+ .takes_value(false)
+ .help("return outdated projects only")
+ )
+ .arg(Arg::with_name("problematic")
+ .long("problematic")
+ .required(false)
+ .multiple(false)
+ .takes_value(false)
+ .help("return problematic projects only")
+ )
+ )
}
diff --git a/src/main.rs b/src/main.rs
index e0455ca..84a60a9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
use anyhow::anyhow;
+use anyhow::Error;
use anyhow::Result;
use clap::ArgMatches;
use result_inspect::*;
@@ -16,6 +17,9 @@ async fn main() -> Result<()> {
match app.get_matches().subcommand() {
("problems", Some(mtch)) => problems(mtch).await,
+ ("projects", Some(mtch)) => projects(mtch).await,
+ ("project", Some(mtch)) => project(mtch).await,
+ ("repo", Some(mtch)) => problems(mtch).await,
(other, _) => Err(anyhow!("No such subcommand: {}", other)),
}
}
@@ -36,3 +40,82 @@ async fn problems<'a>(matches: &ArgMatches<'a>) -> Result<()> {
Ok(())
}
+
+async fn projects<'a>(matches: &ArgMatches<'a>) -> Result<()> {
+ trait FromCliArg: Sized {
+ fn from_cli_arg(arg: &str) -> Result<Self>;
+ }
+
+ impl FromCliArg for String {
+ fn from_cli_arg(arg: &str) -> Result<Self> {
+ Ok(String::from(arg))
+ }
+ }
+
+ impl FromCliArg for usize {
+ fn from_cli_arg(arg: &str) -> Result<Self> {
+ use std::str::FromStr;
+ usize::from_str(arg).map_err(Error::from)
+ }
+ }
+
+ impl FromCliArg for bool {
+ fn from_cli_arg(arg: &str) -> Result<Self> {
+ use std::str::FromStr;
+ bool::from_str(arg).map_err(Error::from)
+ }
+ }
+
+ impl FromCliArg for librepology::v1::api::NumberOrRange {
+ fn from_cli_arg(arg: &str) -> Result<Self> {
+ // TODO: Parse arg to NumberOrRange
+ unimplemented!()
+ }
+ }
+
+ fn cliarg<'a, T: FromCliArg>(matches: &ArgMatches<'a>, s: &'static str) -> Result<Option<T>> {
+ matches.value_of(s).map(FromCliArg::from_cli_arg).transpose()
+ }
+
+ ApiClient::new::<DefaultEndpoint>()?
+ .projects()
+ .filtered()
+ .with_search(cliarg(matches, "search")?)
+ .with_maintainer(cliarg(matches, "maintainer")?)
+ .with_category(cliarg(matches, "category")?)
+ .with_in_repo_filter(cliarg(matches, "in_repo_filter")?)
+ .with_not_in_repo_filter(cliarg(matches, "not_in_repo_filter")?)
+ .with_repos_filter(cliarg(matches, "repos_filter")?)
+ .with_families_filter(cliarg(matches, "families_filter")?)
+ .with_repos_newest(cliarg(matches, "repos_newest")?)
+ .with_families_newest(cliarg(matches, "families_newest")?)
+ .with_newest(cliarg(matches, "newest")?)
+ .with_outdated(cliarg(matches, "outdated")?)
+ .with_problematic(cliarg(matches, "problematic")?)
+ .to_request()
+ .perform()
+ .await?
+ .into_iter()
+ .for_each(|project| {
+ println!("Project: {:?}", project);
+ });
+
+ Ok(())
+}
+
+async fn project<'a>(matches: &ArgMatches<'a>) -> Result<()> {
+ let name = matches.value_of("name").map(String::from).unwrap(); // safe by clap
+ let client = ApiClient::new::<DefaultEndpoint>()?;
+ client.projects()
+ .with_name(name)
+ .to_request()
+ .perform()
+ .await
+ .inspect(|response| log::debug!("Response: {:?}", response))?
+ .into_iter()
+ .for_each(|project| {
+ println!("Project: {:?}", project);
+ });
+
+ Ok(())
+}