From 288cd8b16b619dc7824467bbe3a09e9502b3bf5a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 25 Apr 2019 09:30:24 +0200 Subject: Add comment to helper type --- src/backend.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/backend.rs b/src/backend.rs index 57afd10..23a09d4 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -15,6 +15,9 @@ pub enum Backend { RepologyOrg(RestApi), } +/// Implement Api for Backend +/// +/// With this, we can use the `Backend` object and do not have to care whether we have a librepology:: impl Api for Backend { fn project>(&self, name: N) -> Result> { match self { -- cgit v1.2.3 From 9f8682bee94ee349aa5086bdab257f7ce5cfcdb1 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 25 Apr 2019 09:32:37 +0200 Subject: Add doc: v1::api::Api --- librepology/src/v1/api.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/librepology/src/v1/api.rs b/librepology/src/v1/api.rs index d740d44..796b10e 100644 --- a/librepology/src/v1/api.rs +++ b/librepology/src/v1/api.rs @@ -9,6 +9,14 @@ use failure::Error; use crate::v1::types::Problem; use crate::v1::types::Package; +/// The high-level functionality of the repology API is represented in this trait +/// +/// Each "functionality" is represented via one function. +/// +/// # Note +/// +/// This is implemented as a _trait_ rather than a _struct_ because this way we can reuse the +/// functionality for operating on a stream, for example on stdin as a source of data. pub trait Api { fn project>(&self, name: N) -> Result>; -- cgit v1.2.3 From 6850e90c5402873970c39726b74b6bef442aa4cb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 25 Apr 2019 09:33:42 +0200 Subject: Add doc: v1::api::StdinWrapper --- librepology/src/v1/api.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/librepology/src/v1/api.rs b/librepology/src/v1/api.rs index 796b10e..b493209 100644 --- a/librepology/src/v1/api.rs +++ b/librepology/src/v1/api.rs @@ -26,12 +26,10 @@ pub trait Api { } -// -// Api implemented for StdIn (via a Wrapper for interior mutability) -// -// This way we can read the data from stdin and process it -// - +/// Wrapper for "stdin" +/// +/// This way we can implement the `Api` trait for StdIn (via a Wrapper for interior mutability) +/// This way we can read the data from stdin and process it. pub struct StdinWrapper(RefCell); impl From for StdinWrapper { -- cgit v1.2.3 From 79d82cf3d349d7914de5e198d1e191171a8fcea6 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 25 Apr 2019 09:36:21 +0200 Subject: Refactor: Move StdinWrapper to own module --- librepology/src/v1/api.rs | 57 -------------------------------------- librepology/src/v1/mod.rs | 1 + librepology/src/v1/stdinapi.rs | 63 ++++++++++++++++++++++++++++++++++++++++++ src/backend.rs | 2 +- 4 files changed, 65 insertions(+), 58 deletions(-) create mode 100644 librepology/src/v1/stdinapi.rs diff --git a/librepology/src/v1/api.rs b/librepology/src/v1/api.rs index b493209..e192022 100644 --- a/librepology/src/v1/api.rs +++ b/librepology/src/v1/api.rs @@ -1,10 +1,4 @@ -use std::io::{Stdin, Read}; -use std::cell::RefCell; -use std::ops::Deref; -use std::ops::DerefMut; - use failure::Fallible as Result; -use failure::Error; use crate::v1::types::Problem; use crate::v1::types::Package; @@ -26,54 +20,3 @@ pub trait Api { } -/// Wrapper for "stdin" -/// -/// This way we can implement the `Api` trait for StdIn (via a Wrapper for interior mutability) -/// This way we can read the data from stdin and process it. -pub struct StdinWrapper(RefCell); - -impl From for StdinWrapper { - fn from(inner: Stdin) -> Self { - StdinWrapper(RefCell::new(inner)) - } -} - -impl Deref for StdinWrapper { - type Target = RefCell; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for StdinWrapper { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl Api for StdinWrapper { - - fn project>(&self, _name: N) -> Result> { - let s = read_to_string(self.0.try_borrow_mut()?.deref_mut())?; - serde_json::de::from_str(&s).map_err(Error::from) - } - - fn problems_for_repo>(&self, _repo: R) -> Result> { - let s = read_to_string(self.0.try_borrow_mut()?.deref_mut())?; - serde_json::de::from_str(&s).map_err(Error::from) - } - - fn problems_for_maintainer>(&self, _maintainer: M) -> Result> { - let s = read_to_string(self.0.try_borrow_mut()?.deref_mut())?; - serde_json::de::from_str(&s).map_err(Error::from) - } - -} - -fn read_to_string(input: &mut Read) -> Result { - let mut buffer = String::new(); - let read = input.read_to_string(&mut buffer)?; - trace!("Read {} bytes from stdin", read); - Ok(buffer) -} diff --git a/librepology/src/v1/mod.rs b/librepology/src/v1/mod.rs index cd4d2fe..1d5eed6 100644 --- a/librepology/src/v1/mod.rs +++ b/librepology/src/v1/mod.rs @@ -1,3 +1,4 @@ pub mod restapi; +pub mod stdinapi; pub mod api; pub mod types; diff --git a/librepology/src/v1/stdinapi.rs b/librepology/src/v1/stdinapi.rs new file mode 100644 index 0000000..8ee26a4 --- /dev/null +++ b/librepology/src/v1/stdinapi.rs @@ -0,0 +1,63 @@ +use std::io::{Stdin, Read}; +use std::cell::RefCell; +use std::ops::Deref; +use std::ops::DerefMut; + +use failure::Fallible as Result; +use failure::Error; + +use crate::v1::types::Problem; +use crate::v1::types::Package; +use crate::v1::api::Api; + +/// Wrapper for "stdin" +/// +/// This way we can implement the `Api` trait for StdIn (via a Wrapper for interior mutability) +/// This way we can read the data from stdin and process it. +pub struct StdinWrapper(RefCell); + +impl From for StdinWrapper { + fn from(inner: Stdin) -> Self { + StdinWrapper(RefCell::new(inner)) + } +} + +impl Deref for StdinWrapper { + type Target = RefCell; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for StdinWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Api for StdinWrapper { + + fn project>(&self, _name: N) -> Result> { + let s = read_to_string(self.0.try_borrow_mut()?.deref_mut())?; + serde_json::de::from_str(&s).map_err(Error::from) + } + + fn problems_for_repo>(&self, _repo: R) -> Result> { + let s = read_to_string(self.0.try_borrow_mut()?.deref_mut())?; + serde_json::de::from_str(&s).map_err(Error::from) + } + + fn problems_for_maintainer>(&self, _maintainer: M) -> Result> { + let s = read_to_string(self.0.try_borrow_mut()?.deref_mut())?; + serde_json::de::from_str(&s).map_err(Error::from) + } + +} + +fn read_to_string(input: &mut Read) -> Result { + let mut buffer = String::new(); + let read = input.read_to_string(&mut buffer)?; + trace!("Read {} bytes from stdin", read); + Ok(buffer) +} diff --git a/src/backend.rs b/src/backend.rs index 23a09d4..fe1fa7e 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -3,8 +3,8 @@ use failure::Fallible as Result; use librepology::v1::api::Api; use librepology::v1::restapi::RestApi; +use librepology::v1::stdinapi::StdinWrapper; use librepology::v1::types::*; -use librepology::v1::api::StdinWrapper; use crate::config::Configuration; -- cgit v1.2.3 From 5d9fd8fc5a01dec571e35d6d84ca0636ddbf4517 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 25 Apr 2019 09:37:55 +0200 Subject: Add doc: REST Api type --- librepology/src/v1/restapi.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/librepology/src/v1/restapi.rs b/librepology/src/v1/restapi.rs index df26135..2ac593d 100644 --- a/librepology/src/v1/restapi.rs +++ b/librepology/src/v1/restapi.rs @@ -7,6 +7,7 @@ use curl::easy::Easy2; use crate::v1::types::{Package, Problem}; use crate::v1::api::Api; +/// Private helper type for collecting data from the curl library struct Collector(Vec); impl curl::easy::Handler for Collector { fn write(&mut self, data: &[u8]) -> RResult { @@ -15,6 +16,7 @@ impl curl::easy::Handler for Collector { } } +/// Representational object for the REST Api of repology pub struct RestApi { /// Base url repology: String, @@ -25,6 +27,7 @@ impl RestApi { Self { repology } } + /// Helper function for sending a request via the curl library fn send_request>(&self, request: U) -> Result { let mut easy = Easy2::new(Collector(Vec::new())); easy.get(true)?; -- cgit v1.2.3 From d5e5230dea1ca10483b29189f7a0633663ee4413 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 25 Apr 2019 09:40:51 +0200 Subject: Refactor: Impl of Api for RestApi to be less code --- librepology/src/v1/restapi.rs | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/librepology/src/v1/restapi.rs b/librepology/src/v1/restapi.rs index 2ac593d..bc1a693 100644 --- a/librepology/src/v1/restapi.rs +++ b/librepology/src/v1/restapi.rs @@ -41,30 +41,18 @@ impl RestApi { impl Api for RestApi { fn project>(&self, name: N) -> Result> { - let request_url = format!("{}api/v1/project/{}", self.repology, name.as_ref()); - - self.send_request(request_url) - .and_then(|r| { - serde_json::from_str(&r).map_err(Error::from) - }) + let url = format!("{}api/v1/project/{}", self.repology, name.as_ref()); + serde_json::from_str(&self.send_request(url)?).map_err(Error::from) } fn problems_for_repo>(&self, repo: R) -> Result> { - let request_url = format!("{}api/v1/repository/{}/problems", self.repology, repo.as_ref()); - - self.send_request(request_url) - .and_then(|r| { - serde_json::from_str(&r).map_err(Error::from) - }) + let url = format!("{}api/v1/repository/{}/problems", self.repology, repo.as_ref()); + serde_json::from_str(&self.send_request(url)?).map_err(Error::from) } fn problems_for_maintainer>(&self, maintainer: M) -> Result> { - let request_url = format!("{}api/v1/maintainer/{}/problems", self.repology, maintainer.as_ref()); - - self.send_request(request_url) - .and_then(|r| { - serde_json::from_str(&r).map_err(Error::from) - }) + let url = format!("{}api/v1/maintainer/{}/problems", self.repology, maintainer.as_ref()); + serde_json::from_str(&self.send_request(url)?).map_err(Error::from) } } \ No newline at end of file -- cgit v1.2.3 From 1e7c006d75298252118493f5001a2b81713ba9fb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 25 Apr 2019 09:42:40 +0200 Subject: Add doc: v1::types module --- librepology/src/v1/types/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/librepology/src/v1/types/mod.rs b/librepology/src/v1/types/mod.rs index 4e97b44..f192c49 100644 --- a/librepology/src/v1/types/mod.rs +++ b/librepology/src/v1/types/mod.rs @@ -1,3 +1,11 @@ +//! Module containing all _types_ of data for the API implementation +//! +//! Tne types have no functionality themselves but only represent objects which are returned by theĀ“ +//! repology API. +//! +//! This top-level module exports all types of the submodules publicly. +//! + mod category; mod download; mod effname; -- cgit v1.2.3 From e4134272791fbaa42c8bd3e99e7653d2b1c1d38d Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 25 Apr 2019 09:45:22 +0200 Subject: Add doc: Frontend trait --- src/frontend/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index 43e5b5e..93d2a09 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -10,6 +10,7 @@ use crate::frontend::table::TableFrontend; use crate::compare::ComparePackage; use crate::backend::Backend; +/// A Frontend represents a way to show the data to the user pub trait Frontend { fn list_packages(&self, packages: Vec) -> Result<()>; fn list_problems(&self, problems: Vec) -> Result<()>; -- cgit v1.2.3 From 23571d048e9f05b2bdef9e80bb5d8ef1673ca7d8 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 25 Apr 2019 09:46:03 +0200 Subject: Add doc: fn new_frontend() --- src/frontend/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index 93d2a09..3bb912c 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -21,6 +21,7 @@ pub mod list; pub mod json; pub mod table; +/// Helper function for building a new Frontend object based on the commandline parameters pub fn new_frontend(app: &ArgMatches, _config: &Configuration) -> Result> { match app.value_of("output") { None | Some("lines") => { -- cgit v1.2.3 From 524336a3335aaf49274a3bc4a177990c791a75c7 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 25 Apr 2019 09:48:52 +0200 Subject: Add doc: All Frontend implementations --- src/frontend/json.rs | 9 +++++++++ src/frontend/list.rs | 3 +++ src/frontend/table.rs | 1 + 3 files changed, 13 insertions(+) diff --git a/src/frontend/json.rs b/src/frontend/json.rs index cd7e651..b9d2007 100644 --- a/src/frontend/json.rs +++ b/src/frontend/json.rs @@ -15,6 +15,15 @@ use librepology::v1::api::Api; pub struct JsonFrontend(Stdout); +/// A Frontend that serializes the data to JSON +/// +/// Useful for piping the data as structured data to another program. +/// +/// # Warning +/// +/// This frontend does _not_ maintain compatibility with repolocli itself. That means that piping +/// output from repolocli to repolocli is _NOT_ supported by this frontend. +/// impl JsonFrontend { pub fn new(stdout: Stdout) -> Self { JsonFrontend(stdout) diff --git a/src/frontend/list.rs b/src/frontend/list.rs index e870ab0..e4ed7d7 100644 --- a/src/frontend/list.rs +++ b/src/frontend/list.rs @@ -15,6 +15,9 @@ use librepology::v1::api::Api; pub struct ListFrontend(Stdout); +/// A Frontend that prints the data in a human-readable way but without ASCII-art. +/// +/// It seperates the values with dashes ("-") for a slightly better reading experience. impl ListFrontend { pub fn new(stdout: Stdout) -> Self { ListFrontend(stdout) diff --git a/src/frontend/table.rs b/src/frontend/table.rs index 6a30e9c..ba5c21d 100644 --- a/src/frontend/table.rs +++ b/src/frontend/table.rs @@ -13,6 +13,7 @@ use crate::backend::Backend; use crate::compare::ComparePackage; use librepology::v1::api::Api; +/// A Frontend that formats the output in a nice ASCII-art table pub struct TableFrontend(Stdout); impl TableFrontend { -- cgit v1.2.3 From 66c91849ebd5e4b1161704a79527f3145b03208f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 25 Apr 2019 09:52:53 +0200 Subject: Refactor: Add helper function for constructing table object --- src/frontend/table.rs | 41 +++++++++-------------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/src/frontend/table.rs b/src/frontend/table.rs index ba5c21d..2440161 100644 --- a/src/frontend/table.rs +++ b/src/frontend/table.rs @@ -20,10 +20,8 @@ impl TableFrontend { pub fn new(stdout: Stdout) -> Self { TableFrontend(stdout) } -} -impl Frontend for TableFrontend { - fn list_packages(&self, packages: Vec) -> Result<()> { + fn mktable(&self) -> Table { let mut table = Table::new(); let format = format::FormatBuilder::new() .column_separator('|') @@ -35,9 +33,14 @@ impl Frontend for TableFrontend { .padding(1, 1) .build(); table.set_format(format); - table.set_titles(row!["Name", "Version", "Repo", "Status", "URL"]); + table + } +} +impl Frontend for TableFrontend { + fn list_packages(&self, packages: Vec) -> Result<()> { + let mut table = self.mktable(); packages.iter().for_each(|package| { let status = if let Some(stat) = package.status() { format!("{}", stat) @@ -65,20 +68,7 @@ impl Frontend for TableFrontend { } fn list_problems(&self, problems: Vec) -> Result<()> { - let mut table = Table::new(); - let format = format::FormatBuilder::new() - .column_separator('|') - .borders('|') - .separators( - &[format::LinePosition::Title, format::LinePosition::Top, format::LinePosition::Bottom], - format::LineSeparator::new('-', '+', '+', '+') - ) - .padding(1, 1) - .build(); - table.set_format(format); - - table.set_titles(row!["Repo", "Name", "EffName", "Maintainer", "Description"]); - + let mut table = self.mktable(); problems.iter().for_each(|problem| { trace!("Adding row for: {:?}", problem); table.add_row(row![ @@ -97,20 +87,7 @@ impl Frontend for TableFrontend { } fn compare_packages(&self, packages: Vec, backend: &Backend, filter_repos: Vec) -> Result<()> { - let mut table = Table::new(); - let format = format::FormatBuilder::new() - .column_separator('|') - .borders('|') - .separators( - &[format::LinePosition::Title, format::LinePosition::Top, format::LinePosition::Bottom], - format::LineSeparator::new('-', '+', '+', '+') - ) - .padding(1, 1) - .build(); - table.set_format(format); - - table.set_titles(row!["Name", "Local Version", "Repo", "Upstream Version"]); - + let mut table = self.mktable(); for package in packages { backend .project(package.name().deref())? -- cgit v1.2.3 From 430705439de90327be98d2cc3ae658cdce9edf9f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 25 Apr 2019 09:54:00 +0200 Subject: Refactor: Add helper for printing table --- src/frontend/table.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/frontend/table.rs b/src/frontend/table.rs index 2440161..35c867c 100644 --- a/src/frontend/table.rs +++ b/src/frontend/table.rs @@ -36,6 +36,12 @@ impl TableFrontend { table.set_titles(row!["Name", "Version", "Repo", "Status", "URL"]); table } + + fn print(&self, table: Table) -> Result<()> { + let mut outlock = self.0.lock(); + table.print(&mut outlock)?; + Ok(()) + } } impl Frontend for TableFrontend { @@ -60,11 +66,7 @@ impl Frontend for TableFrontend { table.add_row(row![package.name(), package.version(), package.repo(), status, url]); }); - - let mut outlock = self.0.lock(); - table.print(&mut outlock)?; - - Ok(()) + self.print(table) } fn list_problems(&self, problems: Vec) -> Result<()> { @@ -79,11 +81,7 @@ impl Frontend for TableFrontend { problem.problem_description() ]); }); - - let mut outlock = self.0.lock(); - table.print(&mut outlock)?; - - Ok(()) + self.print(table) } fn compare_packages(&self, packages: Vec, backend: &Backend, filter_repos: Vec) -> Result<()> { @@ -102,11 +100,7 @@ impl Frontend for TableFrontend { ]); }); } - - let mut outlock = self.0.lock(); - table.print(&mut outlock)?; - - Ok(()) + self.print(table) } } -- cgit v1.2.3 From 150aa2a70684c9a3069a1263306001e894305bce Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 25 Apr 2019 09:55:50 +0200 Subject: Refactor: Add helper for writing output --- src/frontend/json.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/frontend/json.rs b/src/frontend/json.rs index b9d2007..39e86f8 100644 --- a/src/frontend/json.rs +++ b/src/frontend/json.rs @@ -28,19 +28,21 @@ impl JsonFrontend { pub fn new(stdout: Stdout) -> Self { JsonFrontend(stdout) } + + fn write(&self, output: String) -> Result<()> { + let mut outlock = self.0.lock(); + writeln!(outlock, "{}", output).map_err(Error::from) + } } impl Frontend for JsonFrontend { fn list_packages(&self, packages: Vec) -> Result<()> { - let output = serde_json::ser::to_string_pretty(&packages).map_err(Error::from)?; - let mut outlock = self.0.lock(); - writeln!(outlock, "{}", output).map_err(Error::from) + self.write(serde_json::ser::to_string_pretty(&packages).map_err(Error::from)?) + } fn list_problems(&self, problems: Vec) -> Result<()> { - let output = serde_json::ser::to_string_pretty(&problems).map_err(Error::from)?; - let mut outlock = self.0.lock(); - writeln!(outlock, "{}", output).map_err(Error::from) + self.write(serde_json::ser::to_string_pretty(&problems).map_err(Error::from)?) } fn compare_packages(&self, packages: Vec, backend: &Backend, filter_repos: Vec) -> Result<()> { @@ -80,10 +82,7 @@ impl Frontend for JsonFrontend { }); } - let output = serde_json::ser::to_string_pretty(&output)?; - - let mut outlock = self.0.lock(); - writeln!(outlock, "{}", output).map_err(Error::from) + self.write(serde_json::ser::to_string_pretty(&output)?) } } -- cgit v1.2.3