Browse Source

implement `get` command

master
Schneider 5 years ago
parent
commit
d51a4c911a
  1. 17
      src/app.rs
  2. 7
      src/errors.rs
  3. 62
      src/template.rs

17
src/app.rs

@ -96,24 +96,21 @@ fn run_add(glob: &str) -> Result<()> {
/// Runs the command `get` /// Runs the command `get`
fn run_get(lang: &str) -> Result<()> { fn run_get(lang: &str) -> Result<()> {
trace!("Run command `get` with lang {}", &lang); trace!("Run command `get` with lang {}", &lang);
let root = match git_dir()? {
let mut root = match git_dir()? {
Some(r) => r, Some(r) => r,
None => return Err(ErrorKind::NoGitRootFound.into()), None => return Err(ErrorKind::NoGitRootFound.into()),
}; };
info!("Working with git root in {:?}", root); info!("Working with git root in {:?}", root);
let tmpls = helpers::get_templates()?;
let tmpl: &Template =
let mut tmpls = helpers::get_templates()?;
let tmpl: &mut Template =
tmpls.get(lang).ok_or_else(|| ErrorKind::TemplateNotFound(lang.to_string()))?; tmpls.get(lang).ok_or_else(|| ErrorKind::TemplateNotFound(lang.to_string()))?;
debug!("Found a template for {}", lang); debug!("Found a template for {}", lang);
let url = tmpl
.download_url
.as_ref()
.ok_or_else(|| ErrorKind::TemplateNoDownloadUrl(lang.to_string()))?;
trace!("Getting template for {} from {}", tmpl.pretty_name(), url);
todo!();
tmpl.load_content()?;
root.push(".gitignore");
tmpl.write_to(&root)?;
trace!("Wrote template to file");
Ok(()) Ok(())
} }

7
src/errors.rs

@ -3,6 +3,9 @@
// Create the Error, ErrorKind, ResultExt, and Result types // Create the Error, ErrorKind, ResultExt, and Result types
error_chain! { error_chain! {
foreign_links{
Io(::std::io::Error) #[doc = "Link to a `std::io::Error` type."];
}
errors{ errors{
NoGitRootFound { NoGitRootFound {
description("no git root found"), description("no git root found"),
@ -15,5 +18,9 @@ error_chain! {
description("template has no download url"), description("template has no download url"),
display("template {} has no download url", name) display("template {} has no download url", name)
} }
TemplateNoContent {
description("template contains no content that could be used or written. try to `load_content` first.")
}
} }
} }

62
src/template.rs

@ -4,6 +4,10 @@ use log::{debug, trace};
use reqwest::blocking::Client; use reqwest::blocking::Client;
use reqwest::header::{ACCEPT, CONTENT_TYPE, USER_AGENT}; use reqwest::header::{ACCEPT, CONTENT_TYPE, USER_AGENT};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::PathBuf;
use crate::errors::*; use crate::errors::*;
@ -30,6 +34,7 @@ pub struct Template {
pub type_field: String, pub type_field: String,
#[serde(rename = "_links")] #[serde(rename = "_links")]
pub links: Links, pub links: Links,
pub content: Option<String>,
} }
/// Part of github api response /// Part of github api response
@ -56,6 +61,59 @@ impl Template {
} }
self.name.as_str() self.name.as_str()
} }
/// Loads the template content from github
pub fn load_content(&mut self) -> Result<()> {
let url = self
.download_url
.as_ref()
.ok_or_else(|| ErrorKind::TemplateNoDownloadUrl(self.pretty_name().into()))?;
debug!("Loading template content for {} from {}", self.pretty_name(), url);
let client = Client::new();
let res = client
.get(url)
.header(ACCEPT, "text/html")
.header(USER_AGENT, format!("{} {}", DEFAULT_USER_AGENT, env!("CARGO_PKG_VERSION")))
.send()
.chain_err(|| {
format!("Error while getting content of template {}", self.pretty_name())
})?;
debug!(
"Got a response from the server ({} B)",
res.content_length().map_or_else(|| "?".to_string(), |v| v.to_string())
);
let body: String =
res.text().chain_err(|| "Error while parsing body from template response")?;
self.content = Some(body);
debug!("Set content for template {}", self.pretty_name());
Ok(())
}
/// Writes the content of this template to the given path
///
/// Creates the file if it does not exist or trunceates an already existing one.
///
/// # Errors
///
/// Returns `ErrorKind::TemplateNoContent` if this templates has no content (i.e.
/// `load_content` has not yet been called.
/// Other reasons for `Err` can be io related errors.
#[allow(clippy::option_expect_used)]
pub fn write_to(&self, path: &PathBuf) -> Result<()> {
debug!("Writing contents of {} to {}", self.pretty_name(), path.to_string_lossy());
if self.content.is_none() {
return Err(ErrorKind::TemplateNoContent.into());
}
let file = File::create(path)?;
let mut writer = BufWriter::new(file);
writer.write_all(self.content.as_ref().expect("checked before to be some").as_bytes())?;
trace!("Wrote all content");
Ok(())
}
} }
/// This struct holds the information about the templates available at github /// This struct holds the information about the templates available at github
@ -97,9 +155,9 @@ impl GithubTemplates {
} }
/// Returns the template for the given name, if found /// Returns the template for the given name, if found
pub fn get(&self, name: &str) -> Option<&Template> {
pub fn get(&mut self, name: &str) -> Option<&mut Template> {
// names have all a .gitignore suffix // names have all a .gitignore suffix
let name = format!("{}.gitignore", name); let name = format!("{}.gitignore", name);
self.templates.iter().find(|t| t.name.eq_ignore_ascii_case(&name))
self.templates.iter_mut().find(|t| t.name.eq_ignore_ascii_case(&name))
} }
} }
Loading…
Cancel
Save