Skip to content

Commit

Permalink
wip: implementing clog-tool#58 and better errors
Browse files Browse the repository at this point in the history
  • Loading branch information
kbknapp committed Jul 13, 2015
1 parent 12e69bb commit ca5960c
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 44 deletions.
28 changes: 11 additions & 17 deletions src/bin/clog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,18 @@ project directory (i.e. /myproject/.clog.toml) you do not need to use --work-tre

let start_nsec = time::get_time().nsec;

let clog = Clog::from_matches(&matches).unwrap_or_else(|e| { println!("{}",e); std::process::exit(1); });
let clog = Clog::from_matches(&matches).unwrap_or_else(|e| { wlnerr!("{}",e); ::std::process::exit(1); });

let sm = SectionMap::from_commits(clog.get_commits());
if let Some(file) = clog.changelog {
let mut contents = String::new();
clog.write_changelog_to(file).unwrap_or_else(|e| { wlnerr!("{}",e); ::std::process::exit(1); });

let mut contents = String::new();

File::open(&Path::new(&clog.changelog[..])).map(|mut f| f.read_to_string(&mut contents).ok()).ok();

let mut file = File::create(&Path::new(&clog.changelog[..])).ok().unwrap();
let mut writer = LogWriter::new(&mut file, &clog);

writer.write_header().ok().expect("failed to write header");
for (sec, secmap) in sm.sections {
writer.write_section(&sec[..], &secmap.iter().collect::<BTreeMap<_,_>>()).ok().expect(&format!("failed to write {}", sec)[..]);
let end_nsec = time::get_time().nsec;
let elapsed_mssec = (end_nsec - start_nsec) / 1000000;
println!("changelog written. (took {} ms)", elapsed_mssec);
} else {
let out = stdout();
let out_buf = BufWriter::new(out.lock());
clog.write_changelog_to(out_buf).unwrap_or_else(|e| { wlnerr!("{}",e); ::std::process::exit(1); });
}
writer.write(&contents[..]).ok().expect("failed to write contents");

let end_nsec = time::get_time().nsec;
let elapsed_mssec = (end_nsec - start_nsec) / 1000000;
println!("changelog updated. (took {} ms)", elapsed_mssec);
}
105 changes: 78 additions & 27 deletions src/clog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,40 @@ use semver;
use git::{Commits, Commit};
use log_writer::LogWriter;
use sectionmap::SectionMap;
use error::Error;

use CLOG_CONFIG_FILE;

/// Convienience type for returning results of building a `Clog` struct
///
/// # Example
///
/// ```no_run
/// # use clog::Clog;
/// let clog = Clog::new().unwrap_or_else(|e| {
/// // Prints the error and exits appropriately
/// e.exit();
/// });
/// ```
pub type BuilderResult = Result<Clog, Error>;

/// Convienience type for returning results of writing a changelog with a `Clog`
/// struct
///
/// # Example
///
/// ```no_run
/// # use clog::Clog;
/// # use std::io;
/// let out = io::stdout();
/// let clog = Clog::new();
/// clog.write_changelog_with(out.lock()).unwrap_or_else(|e| {
/// // Prints the error and exits appropriately
/// e.exit();
/// });
/// ```
pub type WriterResult = Result<(), Error>;

/// Determines the link style used in commit links. Defaults to `LinksStyle::Github`
///
/// # Example
Expand Down Expand Up @@ -105,7 +136,7 @@ pub struct Clog {
/// Where to stop looking for commits using a hash (or short hash). (Defaults to `HEAD`)
pub to: String,
/// The file to use as the changelog. (Defaults to `changelog.md`)
pub changelog: String,
pub changelog: Option<String>,
/// Maps out the sections and aliases used to trigger those sections. The keys are the section
/// name, and the values are an array of aliases.
pub section_map: HashMap<String, Vec<String>>,
Expand Down Expand Up @@ -158,17 +189,6 @@ impl fmt::Debug for Clog {
}
}

/// Convienience type for returning results of building a `Clog` struct
///
/// # Example
/// ```no_run
/// # use clog::Clog;
/// let clog = Clog::new().unwrap_or_else(|e| {
/// println!("Error initializing: {}", e);
/// std::process::exit(1);
/// });
/// ```
pub type ClogResult = Result<Clog, Box<Display>>;

impl Clog {
fn _new() -> Clog {
Expand Down Expand Up @@ -196,7 +216,7 @@ impl Clog {
subtitle: "".to_owned(),
from: "".to_owned(),
to: "HEAD".to_owned(),
changelog: "changelog.md".to_owned(),
changelog: None,
section_map: sections,
git_dir: None,
git_work_tree: None,
Expand All @@ -216,7 +236,7 @@ impl Clog {
/// std::process::exit(1);
/// });
/// ```
pub fn new() -> ClogResult {
pub fn new() -> BuilderResult {
debugln!("Creating public default clog");
Clog::from_file(CLOG_CONFIG_FILE)
}
Expand All @@ -234,7 +254,7 @@ impl Clog {
/// std::process::exit(1);
/// });
/// ```
pub fn with_all<P: AsRef<Path>>(git_dir: P, work_tree: P, cfg_file: P) -> ClogResult {
pub fn with_all<P: AsRef<Path>>(git_dir: P, work_tree: P, cfg_file: P) -> BuilderResult {
debugln!("Creating clog with \n\tgit_dir: {:?}\n\twork_tree: {:?}\n\tcfg_file: {:?}",
git_dir.as_ref(),
work_tree.as_ref(),
Expand All @@ -259,7 +279,7 @@ impl Clog {
/// std::process::exit(1);
/// });
/// ```
pub fn with_dir_and_file<P: AsRef<Path>>(dir: P, cfg_file: P) -> ClogResult {
pub fn with_dir_and_file<P: AsRef<Path>>(dir: P, cfg_file: P) -> BuilderResult {
debugln!("Creating clog with \n\tdir: {:?}\n\tcfg_file: {:?}",
dir.as_ref(),
cfg_file.as_ref());
Expand Down Expand Up @@ -302,7 +322,7 @@ impl Clog {
/// std::process::exit(1);
/// });
/// ```
pub fn with_dir<P: AsRef<Path>>(dir: P) -> ClogResult {
pub fn with_dir<P: AsRef<Path>>(dir: P) -> BuilderResult {
debugln!("Creating clog with \n\tdir: {:?}", dir.as_ref());
let clog = try!(Clog::_with_dir(dir));
clog.try_config_file(Path::new(CLOG_CONFIG_FILE))
Expand All @@ -322,7 +342,7 @@ impl Clog {
/// std::process::exit(1);
/// });
/// ```
pub fn with_dirs<P: AsRef<Path>>(git_dir: P, work_tree: P) -> ClogResult {
pub fn with_dirs<P: AsRef<Path>>(git_dir: P, work_tree: P) -> BuilderResult {
debugln!("Creating clog with \n\tgit_dir: {:?}\n\twork_tree: {:?}",
git_dir.as_ref(),
work_tree.as_ref());
Expand All @@ -347,14 +367,14 @@ impl Clog {
/// std::process::exit(1);
/// });
/// ```
pub fn from_file<P: AsRef<Path>>(file: P) -> ClogResult {
pub fn from_file<P: AsRef<Path>>(file: P) -> BuilderResult {
debugln!("Creating clog with \n\tfile: {:?}", file.as_ref());
// Determine if the cfg_file was relative or not
let cfg_file = if file.as_ref().is_relative() {
debugln!("file is relative");
let cwd = match env::current_dir() {
Ok(d) => d,
Err(e) => return Err(Box::new(e)),
Err(e) => return Err(Error::CurrentDirErr(e)),
};
Path::new(&cwd).join(file.as_ref())
} else {
Expand All @@ -368,7 +388,7 @@ impl Clog {
Clog::with_dir_and_file(dir, cfg_file)
}

fn try_config_file(mut self, cfg_file: &Path) -> ClogResult {
fn try_config_file(mut self, cfg_file: &Path) -> BuilderResult {
debugln!("Trying to use config file: {:?}", cfg_file);
let mut toml_from_latest = None;
let mut toml_repo = None;
Expand All @@ -381,7 +401,7 @@ impl Clog {
let mut toml_s = String::with_capacity(100);

if let Err(e) = toml_f.read_to_string(&mut toml_s) {
return Err(Box::new(e))
return Err(Error::TomlReadErr(e));
}

toml_s.shrink_to_fit();
Expand All @@ -391,14 +411,14 @@ impl Clog {
let toml_table = match toml.parse() {
Some(table) => table,
None => {
return Err(Box::new(format!("Error parsing file: {}\n\nPlease check the format or specify the options manually", cfg_file.to_str().unwrap_or("UNABLE TO DISPLAY"))))
return Err(Error::ConfigParseErr(cfg_file.to_str().unwrap_or("UNABLE TO DISPLAY")));
}
};

let clog_table = match toml_table.get("clog") {
Some(table) => table,
None => {
return Err(Box::new(format!("Error parsing file {}\n\nPlease check the format or specify the options manually", cfg_file.to_str().unwrap_or("UNABLE TO DISPLAY"))))
return Err(Error::ConfigFormatErr(cfg_file.to_str().unwrap_or("UNABLE TO DISPLAY")));
}
};

Expand Down Expand Up @@ -459,7 +479,7 @@ impl Clog {
}

if let Some(outfile) = toml_outfile {
self.changelog = outfile;
self.changelog = Some(outfile);
}

debugln!("Returning clog:\n{:?}", self);
Expand Down Expand Up @@ -577,7 +597,7 @@ impl Clog {
}

if let Some(file) = matches.value_of("outfile") {
clog.changelog = file.to_owned();
clog.changelog = Some(file.to_owned());
}

debugln!("Returning clog:\n{:?}", clog);
Expand Down Expand Up @@ -746,7 +766,7 @@ impl Clog {
/// clog.changelog("/myproject/my_changelog.md");
/// ```
pub fn changelog<S: Into<String>>(&mut self, c: S) -> &mut Clog {
self.changelog = c.into();
self.changelog = Some(c.into());
self
}

Expand Down Expand Up @@ -1021,6 +1041,37 @@ impl Clog {
writer.write(&contents[..]).ok().expect("failed to write contents");
}

/// Writes the changelog to a specified file, and prepends new commits if file exists, or
/// creates the file if it doesn't
///
/// # Example
/// ```no_run
/// # use clog::Clog;
/// let mut clog = Clog::new().unwrap_or_else(|e| {
/// println!("Error initializing: {}", e);
/// std::process::exit(1);
/// });
///
/// clog.write_changelog_to("/myproject/new_changelog.md");
/// ```
pub fn write_changelog_with<T, W>(&self, w: W) -> Result<(),Box<Display>>
where W: BufWriter<T> {
let sm = SectionMap::from_commits(self.get_commits());

let mut contents = String::new();

File::open(cl.as_ref()).map(|mut f| f.read_to_string(&mut contents).ok()).ok();

// let mut file = File::create(cl.as_ref()).ok().unwrap();
let mut writer = LogWriter::new(&mut w, self);

writer.write_header().ok().expect("failed to write header");
for (sec, secmap) in sm.sections {
writer.write_section(&sec[..], &secmap.iter().collect::<BTreeMap<_,_>>()).ok().expect(&format!("failed to write {}", sec)[..]);
}
writer.write(&contents[..]).ok().expect("failed to write contents");
}

/// Writes the changelog to the default location and file or wherever was specified by the TOML
/// or configuration options. `Clog` prepends new commits if file exists, or
/// creates the file if it doesn't.
Expand Down
59 changes: 59 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use std::error::Error as StdError;
use std::fmt;

#[derive(Debug)]
pub enum Error {
ConfigParseErr(String),
ConfigFormatErr(String),
CurrentDirErr(StdError),
TomlReadErr(StdError),

}


// Shamelessly taken and adopted from https://github.com/BurntSushi :)
impl Error {
/// Return whether this was a fatal error or not.
pub fn fatal(&self) -> bool {
match *self {

}
}

/// Print this error and immediately exit the program.
///
/// If the error is non-fatal then the error is printed to stdout and the
/// exit status will be `0`. Otherwise, when the error is fatal, the error
/// is printed to stderr and the exit status will be `1`.
pub fn exit(&self) -> ! {
if self.fatal() {
wlnerr!("{}\n", self);
::std::process::exit(1)
} else {
println!("{}", self);
::std::process::exit(0)
}
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {

}
}
}

impl StdError for Error {
fn description(&self) -> &str {
match *self {

}
}

fn cause(&self) -> Option<&StdError> {
match *self {

}
}
}

0 comments on commit ca5960c

Please sign in to comment.