Browse Source

add cache read methods

master
Schneider 4 years ago
parent
commit
7eae18a837
Signed by: schneider GPG Key ID: 3F50B02A50039F3B
  1. 18
      src/app.rs
  2. 15
      src/helpers.rs
  3. 2
      src/main.rs
  4. 80
      src/template.rs

18
src/app.rs

@ -5,8 +5,6 @@
use std::path::PathBuf;
// 3rd-party crate imports
use reqwest::blocking::Client;
use reqwest::header::{ACCEPT, CONTENT_TYPE, USER_AGENT};
use structopt::StructOpt;
use log::{debug, error, info, trace, warn};
@ -19,7 +17,6 @@ use crate::template::*;
/// The verbosity level when no `-q` or `-v` arguments are given, with `0` being `-q`
pub const DEFAULT_VERBOSITY: u64 = 1;
pub const DEFAULT_USER_AGENT: &str = "gitig";
/// Command-line argument schema
///
@ -99,18 +96,11 @@ fn run_get(lang: &str) -> Result<()> {
}
/// Runs the command `list-templates`
#[allow(clippy::print_stdout)]
fn run_list_templates() -> Result<()> {
let client = Client::new();
let res = client
.get("https://api.github.com/repos/github/gitignore/contents//")
.header(ACCEPT, "application/jsonapplication/vnd.github.v3+json")
.header(CONTENT_TYPE, "application/json")
.header(USER_AGENT, format!("{} {}", DEFAULT_USER_AGENT, env!("CARGO_PKG_VERSION")))
.send()
.chain_err(|| "Error while sending request to query all templates")?;
let body: Vec<Template> = res.json().chain_err(|| "json")?;
body.iter().filter(|t| t.is_gitignore_template()).for_each(|t| println!("{}", t.pretty_name()));
let tmpl = GithubTemplates::new().chain_err(|| "Error while getting Templates")?;
let names = tmpl.list_names();
println!("{}", names.join("\n"));
Ok(())
}

15
src/helpers.rs

@ -100,3 +100,18 @@ pub fn git_dir() -> Result<Option<PathBuf>> {
info!("Arrived at filesystem root while checking for git folder");
Ok(None)
}
/// Returns the path to the cache dir
///
/// If env `XDG_CACHE_HOME` is not set it uses `$HOME/.cache` and appends `gitig`. If dir does not
/// exists it will be created
pub fn cache_dir() -> PathBuf {
let root = std::env::var("XDG_CACHE_HOME").unwrap_or_else(|_| "$HOME/.cache/".to_string());
let mut root = PathBuf::from(root);
root.push("gitig");
if !root.exists() && std::fs::create_dir_all(&root).is_err() {
// should not happen, but as a fallback we can use /tmp/
root = PathBuf::from("/tmp");
}
root
}

2
src/main.rs

@ -20,7 +20,7 @@ This project used [rust-cli-boilerplate](https://github.com/ssokolow/rust-cli-bo
clippy::restriction
)]
// Opt out of the lints I've seen and don't want
#![allow(clippy::float_arithmetic, clippy::implicit_return)]
#![allow(clippy::float_arithmetic, clippy::implicit_return, clippy::filter_map)]
#[macro_use]
extern crate error_chain;

80
src/template.rs

@ -1,6 +1,17 @@
//! This module contains structs for working with the github templates
use log::{debug, trace};
use reqwest::blocking::Client;
use reqwest::header::{ACCEPT, CONTENT_TYPE, USER_AGENT};
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::PathBuf;
use crate::errors::*;
pub const DEFAULT_USER_AGENT: &str = "gitig";
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
@ -39,9 +50,72 @@ impl Template {
///
/// if `!self.is_gitignore_template()` the whole `self.name` is returned
pub fn pretty_name(&self) -> &str {
if let Some(dot_index) = self.name.rfind(".") {
return &self.name[0..dot_index];
if let Some(dot_index) = self.name.rfind('.') {
return &self.name.get(0..dot_index).unwrap_or_else(|| self.name.as_str());
}
return self.name.as_str();
self.name.as_str()
}
}
/// This struct holds the information about the templates available at github
pub struct GithubTemplates {
/// The templates
templates: Vec<Template>,
}
impl GithubTemplates {
/// Loads the templates from the github api
fn from_server() -> Result<GithubTemplates> {
trace!("Loading templates from github api");
let client = Client::new();
let res = client
.get("https://api.github.com/repos/github/gitignore/contents//")
.header(ACCEPT, "application/jsonapplication/vnd.github.v3+json")
.header(CONTENT_TYPE, "application/json")
.header(USER_AGENT, format!("{} {}", DEFAULT_USER_AGENT, env!("CARGO_PKG_VERSION")))
.send()
.chain_err(|| "Error while sending request to query all templates")?;
let body: Vec<Template> = res.json().chain_err(|| "json")?;
Ok(GithubTemplates { templates: body })
}
/// Returns whether there is an cached json version
fn is_cached() -> bool { Self::cache_path().exists() }
/// Returns the path of the file cache
fn cache_path() -> PathBuf {
let mut cache: PathBuf = crate::helpers::cache_dir();
cache.push("templates.json");
debug!("Using cache path for templates: {}", cache.to_str().unwrap_or("err"));
cache
}
/// Reads the templates from the file cache
fn from_cache() -> Result<GithubTemplates> {
trace!("Reading templates from file cache");
let f = File::open(Self::cache_path())
.chain_err(|| "Error while opening cache file for templates")?;
let reader = BufReader::new(f);
let tpls = serde_json::from_reader(reader)
.chain_err(|| "Error while reading templates from file cache")?;
Ok(GithubTemplates { templates: tpls })
}
/// Creates a new struct with templates
pub fn new() -> Result<GithubTemplates> {
if Self::is_cached() {
Self::from_cache()
} else {
Self::from_server()
}
}
/// Returns a list of the template names
pub fn list_names(&self) -> Vec<&str> {
self.templates
.iter()
.filter(|t| t.is_gitignore_template())
.map(Template::pretty_name)
.collect()
}
}
Loading…
Cancel
Save