summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2019-04-25 10:34:35 +0200
committerGitHub <noreply@github.com>2019-04-25 10:34:35 +0200
commit77f8ed46dc3511e354e42c23976097c87c707024 (patch)
tree7180d2cb0409805592e24b4415b12107a2c72584
parenta06d315386bcb5b1ed26dffa9da90947e278b536 (diff)
parent150aa2a70684c9a3069a1263306001e894305bce (diff)
Merge pull request #8 from matthiasbeyer/doc
Doc
-rw-r--r--librepology/src/v1/api.rs67
-rw-r--r--librepology/src/v1/mod.rs1
-rw-r--r--librepology/src/v1/restapi.rs27
-rw-r--r--librepology/src/v1/stdinapi.rs63
-rw-r--r--librepology/src/v1/types/mod.rs8
-rw-r--r--src/backend.rs5
-rw-r--r--src/frontend/json.rs28
-rw-r--r--src/frontend/list.rs3
-rw-r--r--src/frontend/mod.rs2
-rw-r--r--src/frontend/table.rs66
10 files changed, 135 insertions, 135 deletions
diff --git a/librepology/src/v1/api.rs b/librepology/src/v1/api.rs
index d740d44..e192022 100644
--- a/librepology/src/v1/api.rs
+++ b/librepology/src/v1/api.rs
@@ -1,14 +1,16 @@
-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;
+/// 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<N: AsRef<str>>(&self, name: N) -> Result<Vec<Package>>;
@@ -18,56 +20,3 @@ 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
-//
-
-pub struct StdinWrapper(RefCell<Stdin>);
-
-impl From<Stdin> for StdinWrapper {
- fn from(inner: Stdin) -> Self {
- StdinWrapper(RefCell::new(inner))
- }
-}
-
-impl Deref for StdinWrapper {
- type Target = RefCell<Stdin>;
-
- 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<N: AsRef<str>>(&self, _name: N) -> Result<Vec<Package>> {
- 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<R: AsRef<str>>(&self, _repo: R) -> Result<Vec<Problem>> {
- 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<M: AsRef<str>>(&self, _maintainer: M) -> Result<Vec<Problem>> {
- 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<String> {
- 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/restapi.rs b/librepology/src/v1/restapi.rs
index df26135..bc1a693 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<u8>);
impl curl::easy::Handler for Collector {
fn write(&mut self, data: &[u8]) -> RResult<usize, curl::easy::WriteError> {
@@ -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<U: AsRef<str>>(&self, request: U) -> Result<String> {
let mut easy = Easy2::new(Collector(Vec::new()));
easy.get(true)?;
@@ -38,30 +41,18 @@ impl RestApi {
impl Api for RestApi {
fn project<N: AsRef<str>>(&self, name: N) -> Result<Vec<Package>> {
- 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<R: AsRef<str>>(&self, repo: R) -> Result<Vec<Problem>> {
- 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<M: AsRef<str>>(&self, maintainer: M) -> Result<Vec<Problem>> {
- 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
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<Stdin>);
+
+impl From<Stdin> for StdinWrapper {
+ fn from(inner: Stdin) -> Self {
+ StdinWrapper(RefCell::new(inner))
+ }
+}
+
+impl Deref for StdinWrapper {
+ type Target = RefCell<Stdin>;
+
+ 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<N: AsRef<str>>(&self, _name: N) -> Result<Vec<Package>> {
+ 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<R: AsRef<str>>(&self, _repo: R) -> Result<Vec<Problem>> {
+ 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<M: AsRef<str>>(&self, _maintainer: M) -> Result<Vec<Problem>> {
+ 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<String> {
+ 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/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;
diff --git a/src/backend.rs b/src/backend.rs
index 57afd10..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;
@@ -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<N: AsRef<str>>(&self, name: N) -> Result<Vec<Package>> {
match self {
diff --git a/src/frontend/json.rs b/src/frontend/json.rs
index cd7e651..39e86f8 100644
--- a/src/frontend/json.rs
+++ b/src/frontend/json.rs
@@ -15,23 +15,34 @@ 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)
}
+
+ 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<Package>) -> 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<Problem>) -> 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<ComparePackage>, backend: &Backend, filter_repos: Vec<Repo>) -> Result<()> {
@@ -71,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)?)
}
}
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/mod.rs b/src/frontend/mod.rs
index 43e5b5e..3bb912c 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<Package>) -> Result<()>;
fn list_problems(&self, problems: Vec<Problem>) -> Result<()>;
@@ -20,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<Box<Frontend>> {
match app.value_of("output") {
None | Some("lines") => {
diff --git a/src/frontend/table.rs b/src/frontend/table.rs
index 6a30e9c..35c867c 100644
--- a/src/frontend/table.rs
+++ b/src/frontend/table.rs
@@ -13,16 +13,15 @@ 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 {
pub fn new(stdout: Stdout) -> Self {
TableFrontend(stdout)
}
-}
-impl Frontend for TableFrontend {
- fn list_packages(&self, packages: Vec<Package>) -> Result<()> {
+ fn mktable(&self) -> Table {
let mut table = Table::new();
let format = format::FormatBuilder::new()
.column_separator('|')
@@ -34,9 +33,20 @@ impl Frontend for TableFrontend {
.padding(1, 1)
.build();
table.set_format(format);
-
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 {
+ fn list_packages(&self, packages: Vec<Package>) -> Result<()> {
+ let mut table = self.mktable();
packages.iter().for_each(|package| {
let status = if let Some(stat) = package.status() {
format!("{}", stat)
@@ -56,28 +66,11 @@ 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<Problem>) -> 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![
@@ -88,28 +81,11 @@ 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<ComparePackage>, backend: &Backend, filter_repos: Vec<Repo>) -> 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())?
@@ -124,11 +100,7 @@ impl Frontend for TableFrontend {
]);
});
}
-
- let mut outlock = self.0.lock();
- table.print(&mut outlock)?;
-
- Ok(())
+ self.print(table)
}
}