1- use  std:: collections:: { HashMap , BTreeMap } ; 
1+ use  std:: collections:: HashMap ; 
22use  std:: convert:: AsRef ; 
33use  std:: env; 
44use  std:: fmt; 
55use  std:: fs:: File ; 
6- use  std:: io:: { stdout,  BufWriter ,  Read } ; 
6+ use  std:: io:: { stdout,  BufWriter ,  Write , Read } ; 
77use  std:: path:: { Path ,  PathBuf } ; 
88use  std:: process:: Command ; 
99
@@ -13,7 +13,7 @@ use toml::{Value, Parser};
1313use  semver; 
1414
1515use  git:: { Commits ,  Commit } ; 
16- use  writer :: { Writer , WriterResult ,  Markdown } ; 
16+ use  fmt :: { ChangelogFormat , FormatWriter , WriterResult ,  MarkdownWriter , JsonWriter } ; 
1717use  sectionmap:: SectionMap ; 
1818use  error:: Error ; 
1919
@@ -65,9 +65,9 @@ impl LinkStyle {
6565 ""  => format ! ( "(#{})" ,  issue. as_ref( ) ) , 
6666 link => { 
6767 match  * self  { 
68-  LinkStyle :: Github  => format ! ( "[#{}]({} /issues/{})"  ,  issue . as_ref ( ) ,  link,  issue. as_ref( ) ) , 
69-  LinkStyle :: Gitlab  => format ! ( "[#{}]({} /issues/{})"  ,  issue . as_ref ( ) ,  link,  issue. as_ref( ) ) , 
70-  LinkStyle :: Stash  => format ! ( "(#{}) " ,  issue. as_ref( ) )  // Stash doesn't support issue links 
68+  LinkStyle :: Github  => format ! ( "{} /issues/{}"  ,  link,  issue. as_ref( ) ) , 
69+  LinkStyle :: Gitlab  => format ! ( "{} /issues/{}"  ,  link,  issue. as_ref( ) ) , 
70+  LinkStyle :: Stash  => format ! ( "{} " ,  issue. as_ref( ) )  // Stash doesn't support issue links 
7171 } 
7272 } 
7373 } 
@@ -83,14 +83,13 @@ impl LinkStyle {
8383 /// assert_eq!("[#123abc89](https://github.com/thoughtram/clog/commit/123abc891234567890abcdefabc4567898724", commit); 
8484 /// ``` 
8585 pub  fn  commit_link < S :  AsRef < str > > ( & self ,  hash :  S ,  repo :  S )  -> String  { 
86-  let  short_hash = & hash. as_ref ( ) [ 0 ..8 ] ; 
8786 match  repo. as_ref ( )  { 
88-  ""  => format ! ( "({}) " ,  short_hash ) , 
87+  ""  => format ! ( "{} " ,  & hash . as_ref ( ) [ 0 .. 8 ] ) , 
8988 link => { 
9089 match  * self  { 
91-  LinkStyle :: Github  => format ! ( "[{}]({} /commit/{})"  ,  short_hash ,  link,  hash. as_ref( ) ) , 
92-  LinkStyle :: Gitlab  => format ! ( "[{}]({} /commit/{})"  ,  short_hash ,  link,  hash. as_ref( ) ) , 
93-  LinkStyle :: Stash  => format ! ( "[{}]({} /commits/{})"  ,  short_hash ,  link,  hash. as_ref( ) ) 
90+  LinkStyle :: Github  => format ! ( "{} /commit/{}"  ,  link,  hash. as_ref( ) ) , 
91+  LinkStyle :: Gitlab  => format ! ( "{} /commit/{}"  ,  link,  hash. as_ref( ) ) , 
92+  LinkStyle :: Stash  => format ! ( "{} /commits/{}"  ,  link,  hash. as_ref( ) ) 
9493 } 
9594 } 
9695 } 
@@ -135,6 +134,8 @@ pub struct Clog {
135134 pub  regex :  Regex , 
136135 /// The regex used to get closes issue links 
137136 pub  closes_regex :  Regex ,  
137+  /// The format to output the changelog in (Defaults to Markdown) 
138+  pub  out_format :  ChangelogFormat , 
138139} 
139140
140141impl  fmt:: Debug  for  Clog  { 
@@ -156,6 +157,7 @@ impl fmt::Debug for Clog {
156157 git_work_tree: {:?} 
157158 regex: {:?} 
158159 closes_regex: {:?} 
160+  out_format: {:?} 
159161 }}" , 
160162 self . grep, 
161163 self . format, 
@@ -173,6 +175,7 @@ impl fmt::Debug for Clog {
173175 self . git_work_tree, 
174176 self . regex, 
175177 self . closes_regex, 
178+  self . out_format, 
176179 )  
177180 } 
178181} 
@@ -208,6 +211,7 @@ impl Clog {
208211 infile :  None , 
209212 outfile :  None , 
210213 section_map :  sections, 
214+  out_format :  ChangelogFormat :: Markdown , 
211215 git_dir :  None , 
212216 git_work_tree :  None , 
213217 regex :  regex ! ( r"^([^:\(]+?)(?:\(([^:\)]*?)?\))?:(.*)" ) , 
@@ -382,6 +386,7 @@ impl Clog {
382386 let  mut  toml_outfile = None ; 
383387 let  mut  toml_infile = None ; 
384388 let  mut  toml_changelog = None ; 
389+  let  mut  toml_format= None ; 
385390
386391 if  let  Ok ( ref  mut  toml_f)  = File :: open ( cfg_file)  { 
387392 debugln ! ( "Found file" ) ; 
@@ -439,6 +444,10 @@ impl Clog {
439444 Some ( val)  => Some ( val. as_str ( ) . unwrap_or ( "" ) . to_owned ( ) ) , 
440445 None  => None 
441446 } ; 
447+  toml_format = match  clog_table. lookup ( "output-format" )  { 
448+  Some ( val)  => Some ( val. as_str ( ) . unwrap_or ( "" ) . to_owned ( ) ) , 
449+  None  => None 
450+  } ; 
442451 match  toml_table. get ( "sections" )  { 
443452 Some ( table)  => { 
444453 match  table. as_table ( )  { 
@@ -483,6 +492,13 @@ impl Clog {
483492 self . infile  = Some ( infile) ; 
484493 } 
485494
495+  if  let  Some ( format)  = toml_format { 
496+  match  format. parse :: < ChangelogFormat > ( )  { 
497+  Ok ( val)  => self . out_format  = val, 
498+  Err ( ..)  => return  Err ( Error :: ConfigFormatErr ) , 
499+  } 
500+  } 
501+ 486502 if  let  Some ( ref  cl)  = toml_changelog { 
487503 self . outfile  = Some ( cl. to_owned ( ) ) ; 
488504 self . infile  = Some ( cl. to_owned ( ) ) ; 
@@ -614,6 +630,10 @@ impl Clog {
614630 clog. outfile  = Some ( file. to_owned ( ) ) ; 
615631 } 
616632
633+  if  matches. is_present ( "format" )  { 
634+  clog. out_format  = value_t_or_exit ! ( matches. value_of( "format" ) ,  ChangelogFormat ) ; 
635+  } 
636+ 617637 debugln ! ( "Returning clog:\n {:?}" ,  clog) ; 
618638
619639 Ok ( clog) 
@@ -872,6 +892,23 @@ impl Clog {
872892 self 
873893 } 
874894
895+  /// The format of output for the changelog (Defaults to Markdown) 
896+  /// 
897+  /// # Example 
898+  /// ```no_run 
899+  /// # use clog::Clog; 
900+  /// # use clog::ChangelogFormat; 
901+  /// let mut clog = Clog::new().unwrap_or_else(|e| { 
902+  /// e.exit(); 
903+  /// }); 
904+  ///  
905+  /// clog.out_format(ChangelogFormat::Json); 
906+  /// ``` 
907+  pub  fn  output_format ( & mut  self ,  f :  ChangelogFormat )  -> & mut  Clog  { 
908+  self . out_format  = f; 
909+  self 
910+  } 
911+ 875912 /// Retrieves a `Vec<Commit>` of only commits we care about. 
876913 /// 
877914 /// # Example 
@@ -1084,9 +1121,16 @@ impl Clog {
10841121 debugln ! ( "outfile and infile not set using stdout" ) ; 
10851122 let  out = stdout ( ) ; 
10861123 let  mut  out_buf = BufWriter :: new ( out. lock ( ) ) ; 
1087-  let  mut  writer = Markdown :: new ( & mut  out_buf,  self ) ; 
1088- 1089-  self . _write_changelog_with ( & mut  writer,  None ) 
1124+  match  self . out_format  { 
1125+  ChangelogFormat :: Markdown  => { 
1126+  let  mut  writer = MarkdownWriter :: new ( & mut  out_buf) ; 
1127+  self . write_changelog_with ( & mut  writer) 
1128+  } , 
1129+  ChangelogFormat :: Json  => { 
1130+  let  mut  writer = JsonWriter :: new ( & mut  out_buf) ; 
1131+  self . write_changelog_with ( & mut  writer) 
1132+  } 
1133+  } 
10901134 } 
10911135 } 
10921136
@@ -1117,11 +1161,26 @@ impl Clog {
11171161 contents. shrink_to_fit ( ) ; 
11181162
11191163 if  let  Ok ( mut  file)  = File :: create ( cl. as_ref ( ) )  { 
1120-  let  mut  writer = Markdown :: new ( & mut  file,  self ) ; 
1121-  self . _write_changelog_with ( & mut  writer,  Some ( & * contents) ) 
1164+  { 
1165+  match  self . out_format  { 
1166+  ChangelogFormat :: Markdown  => { 
1167+  let  mut  writer = MarkdownWriter :: new ( & mut  file) ; 
1168+  try!( self . write_changelog_with ( & mut  writer) ) ; 
1169+  } , 
1170+  ChangelogFormat :: Json  => { 
1171+  let  mut  writer = JsonWriter :: new ( & mut  file) ; 
1172+  try!( self . write_changelog_with ( & mut  writer) ) ; 
1173+  } 
1174+  } 
1175+  } 
1176+  if  let  Err ( ..)  = file. write ( contents. as_bytes ( ) )  { 
1177+  return  Err ( Error :: WriteErr ) ; 
1178+  } 
11221179 }  else  { 
1123-  Err ( Error :: CreateFileErr ) 
1180+  return Err ( Error :: CreateFileErr ) ; 
11241181 } 
1182+ 1183+  Ok ( ( ) ) 
11251184 } 
11261185
11271186 /// Writes the changelog from a specified input file, and appends new commits  
@@ -1146,19 +1205,48 @@ impl Clog {
11461205 if  let  Some ( ref  ofile)  = self . outfile  { 
11471206 debugln ! ( "outfile set to: {:?}" ,  ofile) ; 
11481207 if  let  Ok ( mut  file)  = File :: create ( ofile)  { 
1149-  let  mut  writer = Markdown :: new ( & mut  file,  self ) ; 
1150-  self . _write_changelog_with ( & mut  writer,  Some ( & * contents) ) 
1208+  { 
1209+  match  self . out_format  { 
1210+  ChangelogFormat :: Markdown  => { 
1211+  let  mut  writer = MarkdownWriter :: new ( & mut  file) ; 
1212+  try!( self . write_changelog_with ( & mut  writer) ) ; 
1213+  } , 
1214+  ChangelogFormat :: Json  => { 
1215+  let  mut  writer = JsonWriter :: new ( & mut  file) ; 
1216+  try!( self . write_changelog_with ( & mut  writer) ) ; 
1217+  } 
1218+  } 
1219+  } 
1220+ 1221+  if  let  Err ( ..)  = file. write ( contents. as_bytes ( ) )  { 
1222+  return  Err ( Error :: WriteErr ) 
1223+  } 
11511224 }  else  { 
1152-  Err ( Error :: CreateFileErr ) 
1225+  return Err ( Error :: CreateFileErr ) 
11531226 } 
11541227 }  else  { 
11551228 debugln ! ( "outfile not set, using stdout" ) ; 
11561229 let  out = stdout ( ) ; 
11571230 let  mut  out_buf = BufWriter :: new ( out. lock ( ) ) ; 
1158-  let  mut  writer = Markdown :: new ( & mut  out_buf,  self ) ; 
1231+  { 
1232+  match  self . out_format  { 
1233+  ChangelogFormat :: Markdown  => { 
1234+  let  mut  writer = MarkdownWriter :: new ( & mut  out_buf) ; 
1235+  try!( self . write_changelog_with ( & mut  writer) ) ; 
1236+  } , 
1237+  ChangelogFormat :: Json  => { 
1238+  let  mut  writer = JsonWriter :: new ( & mut  out_buf) ; 
1239+  try!( self . write_changelog_with ( & mut  writer) ) ; 
1240+  } 
1241+  } 
1242+  } 
11591243
1160-  self . _write_changelog_with ( & mut  writer,  Some ( & * contents) ) 
1244+  if  let  Err ( ..)  = out_buf. write ( contents. as_bytes ( ) )  { 
1245+  return  Err ( Error :: WriteErr ) ; 
1246+  } 
11611247 } 
1248+ 1249+  Ok ( ( ) ) 
11621250 } 
11631251
11641252 /// Writes a changelog with a specified `Writer` format and optional contents to append after 
@@ -1184,41 +1272,11 @@ impl Clog {
11841272 /// }); 
11851273 /// ``` 
11861274 pub  fn  write_changelog_with < W > ( & self ,  writer :  & mut  W )  -> WriterResult 
1187-  where  W :  Writer  { 
1275+  where  W :  FormatWriter  { 
11881276 debugln ! ( "Writing changelog from writer" ) ; 
1189-  let  mut  contents = String :: with_capacity ( 256 ) ; 
1190-  if  let  Some ( ref  infile)  = self . infile  { 
1191-  debugln ! ( "infile set to: {:?}" ,  infile) ; 
1192-  File :: open ( infile) . map ( |mut  f| f. read_to_string ( & mut  contents) . ok ( ) ) . ok ( ) ; 
1193-  }  else  { 
1194-  debugln ! ( "infile not set" ) ; 
1195-  } 
1196-  contents. shrink_to_fit ( ) ; 
1197-  self . _write_changelog_with ( writer,  Some ( & * contents) ) 
1198-  } 
1199- 1200-  // Does the actual changelog writing 
1201-  fn  _write_changelog_with < W > ( & self ,  writer :  & mut  W ,  old :  Option < & str > )  -> WriterResult 
1202-  where  W :  Writer  { 
1203-  debugln ! ( "Actually writing changelog" ) ; 
1204-  if  let  Err ( ..)  = writer. write_header ( )  { 
1205-  return  Err ( Error :: WriteErr ) ; 
1206-  } 
1207- 12081277 let  sm = SectionMap :: from_commits ( self . get_commits ( ) ) ; 
12091278
1210-  for  ( sec,  secmap)  in  sm. sections  { 
1211-  try!( writer. write_section ( & sec[ ..] ,  & secmap. iter ( ) . collect :: < BTreeMap < _ , _ > > ( ) ) ) ; 
1212-  } 
1213- 1214-  if  let  Some ( s)  = old { 
1215-  debugln ! ( "There are old contents to append" ) ; 
1216-  if  let  Err ( ..)  = writer. write ( s)  { 
1217-  return  Err ( Error :: WriteErr ) ; 
1218-  } 
1219-  }  else  { 
1220-  debugln ! ( "No old contents to append" ) ; 
1221-  } 
1279+  try!( writer. write_changelog ( self ,  & sm) ) ; 
12221280
12231281 Ok ( ( ) ) 
12241282 } 
0 commit comments