use std::collections::BTreeMap;
use std::io;
use time;
use clog::Clog;
use git::Commit;
use error::Error;
use fmt::{FormatWriter, WriterResult};
use sectionmap::SectionMap;
pub struct JsonWriter<'a>(&'a mut io::Write);
impl<'a> JsonWriter<'a> {
pub fn new<T: io::Write>(writer: &'a mut T) -> JsonWriter<'a> {
JsonWriter(writer)
}
}
impl<'a> JsonWriter<'a> {
fn write_header(&mut self, options: &Clog) -> io::Result<()> {
try!(write!(self.0, "\"header\":{{\"version\":{:?},\"patch_version\":{:?},\"subtitle\":{},",
options.version,
options.patch_ver,
match options.subtitle.len() {
0 => "null".to_owned(),
_ => format!("{:?}", &*options.subtitle)
}
));
let date = time::now_utc();
match date.strftime("%Y-%m-%d") {
Ok(date) => {
write!(
self.0,
"\"date\":\"{}\"}},",
date
)
}
Err(_) => {
write!(
self.0,
"\"date\":null}},",
)
}
}
}
fn write_section(&mut self,
options: &Clog,
section: &BTreeMap<&String, &Vec<Commit>>)
-> WriterResult {
if section.len() == 0 {
write!(self.0, "\"commits\":null").unwrap();
return Ok(())
}
write!(self.0, "\"commits\":[").unwrap();
let mut s_it = section.iter().peekable();
while let Some((component, entries)) = s_it.next() {
let mut e_it = entries.iter().peekable();
debugln!("Writing component: {}", &*component);
while let Some(entry) = e_it.next() {
debugln!("Writing commit: {}", &*entry.subject);
write!(self.0, "{{\"component\":").unwrap();
if component.is_empty() {
write!(self.0, "null,").unwrap();
} else {
write!(self.0, "{:?},", component).unwrap();
}
write!(
self.0 , "\"subject\":{:?},\"commit_link\":{:?},\"closes\":",
entry.subject,
options.link_style
.commit_link(&*entry.hash, &*options.repo)
).unwrap();
if !entry.closes.is_empty() {
write!(self.0, "[").unwrap();
let mut c_it = entry.closes.iter().peekable();
while let Some(issue) = c_it.next() {
write!(self.0,
"{{\"issue\":{},\"issue_link\":{:?}}}",
issue,
options.link_style.issue_link(issue, &options.repo)
).unwrap();
if c_it.peek().is_some() {
debugln!("There are more close commits, adding comma");
write!(self.0, ",").unwrap();
} else {
debugln!("There are no more close commits, no comma required");
}
}
write!(self.0,
"],").unwrap();
} else {
write!(self.0, "null,").unwrap();
}
write!(self.0 , "\"breaks\":").unwrap();
if !entry.breaks.is_empty() {
write!(self.0, "[").unwrap();
let mut c_it = entry.closes.iter().peekable();
while let Some(issue) = c_it.next() {
write!(self.0,
"{{\"issue\":{},\"issue_link\":{:?}}}",
issue,
options.link_style.issue_link(issue, &options.repo)
).unwrap();
if c_it.peek().is_some() {
debugln!("There are more breaks commits, adding comma");
write!(self.0, ",").unwrap();
} else {
debugln!("There are no more breaks commits, no comma required");
}
}
write!(self.0,
"]}}").unwrap();
} else {
write!(self.0, "null}}").unwrap();
}
if e_it.peek().is_some() {
debugln!("There are more commits, adding comma");
write!(self.0, ",").unwrap();
} else {
debugln!("There are no more commits, no comma required");
}
}
if s_it.peek().is_some() {
debugln!("There are more sections, adding comma");
write!(self.0, ",").unwrap();
} else {
debugln!("There are no more commits, no comma required");
}
}
write!(self.0, "]").unwrap();
Ok(())
}
#[allow(dead_code)]
fn write(&mut self, content: &str) -> io::Result<()> {
write!(self.0, "{}", content)
}
}
impl<'a> FormatWriter for JsonWriter<'a> {
fn write_changelog(&mut self, options: &Clog, sm: &SectionMap) -> WriterResult {
debugln!("Writing JSON changelog");
write!(self.0, "{{").unwrap();
if let Some(..) = self.write_header(options).err() {
debugln!("Error writing JSON header");
return Err(Error::WriteErr);
}
write!(self.0, "\"sections\":").unwrap();
let mut s_it = sm.sections.iter().peekable();
if s_it.peek().is_some() {
debugln!("There are sections to write");
write!(self.0, "[").unwrap();
while let Some((sec, compmap)) = s_it.next() {
debugln!("Writing section: {}", &*sec);
write!(self.0, "{{\"title\":{:?},", &*sec).unwrap();
try!(self.write_section(options, &compmap.iter().collect::<BTreeMap<_,_>>()));
write!(self.0, "}}").unwrap();
if s_it.peek().is_some() { debugln!("There are more sections, adding comma");
write!(self.0, ",").unwrap();
} else {
debugln!("There are no more sections, no comma required");
}
}
write!(self.0, "]").unwrap();
} else {
debugln!("There are no sections to write");
write!(self.0, "null").unwrap();
}
write!(self.0, "}}").unwrap();
debugln!("Finished writing sections, flushing");
self.0.flush().unwrap();
Ok(())
}
}