diff --git a/src/config/manifest.rs b/src/config/manifest.rs index 218df44..02b4628 100644 --- a/src/config/manifest.rs +++ b/src/config/manifest.rs @@ -22,6 +22,34 @@ const BADGE_PROVIDERS: [&str; 8] = [ "is-it-maintained-open-issues", ]; +/// Try to get manifest info from Cargo.toml +pub fn get_manifest(project_root: &Path) -> Result { + let mut cargo_toml = File::open(project_root.join("Cargo.toml")) + .map_err(|e| format!("Could not read Cargo.toml: {}", e))?; + + let buf = { + let mut buf = String::new(); + cargo_toml.read_to_string(&mut buf) + .map_err(|e| format!("{}", e))?; + buf + }; + + let cargo_toml: CargoToml = toml::from_str(&buf) + .map_err(|e| format!("{}", e))?; + + let manifest = Manifest { + name: cargo_toml.package.name, + license: cargo_toml.package.license, + lib: cargo_toml.lib.map(|lib| ManifestLib::from_cargo_toml(lib)), + bin: cargo_toml.bin.map(|bin_vec| { + bin_vec.into_iter().map(|bin| ManifestLib::from_cargo_toml(bin)).collect() + }).unwrap_or_default(), + badges: process_badges(cargo_toml.badges) + }; + + Ok(manifest) +} + pub struct Manifest { pub name: String, pub license: Option, @@ -174,21 +202,3 @@ struct CargoTomlLib { pub path: String, pub doc: Option, } - -/// Try to get crate info from Cargo.toml -pub fn get_crate_info(project_root: &Path) -> Result { - let mut cargo_toml = File::open(project_root.join("Cargo.toml")) - .map_err(|e| format!("Could not read Cargo.toml: {}", e))?; - - let buf = { - let mut buf = String::new(); - cargo_toml.read_to_string(&mut buf) - .map_err(|e| format!("{}", e))?; - buf - }; - - let cargo_toml = toml::from_str(&buf) - .map_err(|e| format!("{}", e))?; - - Ok(Manifest::new(cargo_toml)) -} diff --git a/src/config/mod.rs b/src/config/mod.rs index 49c7906..092a873 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -3,7 +3,8 @@ use std::path::{Path, PathBuf}; mod manifest; mod project; -use self::manifest::Manifest; +pub(crate) use self::manifest::Manifest; +pub(crate) use self::manifest::get_manifest; pub struct ReadmeConfig { pub root: PathBuf, diff --git a/src/lib.rs b/src/lib.rs index af5c0a5..cb94edd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,6 @@ extern crate percent_encoding; #[macro_use] mod test_macros; mod readme; -// pub mod manifest; mod config; pub use readme::generate_readme; diff --git a/src/readme/extract.rs b/src/readme/extract.rs index 5f78206..f9a175f 100644 --- a/src/readme/extract.rs +++ b/src/readme/extract.rs @@ -5,24 +5,34 @@ use std::io::{self, Read, BufRead, BufReader}; use ::readme::process::DocProcess; /// Read the given `Read`er and return a `Vec` of the rustdoc lines found -pub fn extract_docs(reader: R, indent_headings: bool) -> io::Result> { +pub fn extract_docs(reader: R, indent_headings: bool) -> io::Result { let mut reader = BufReader::new(reader); let mut line = String::new(); + let mut lines = Vec::new(); + while reader.read_line(&mut line)? > 0 { if line.starts_with("//!") { - return extract_docs_singleline_style(line, reader) - .map(|i| i.process_doc(indent_headings)); + lines = extract_docs_singleline_style(line, reader)?; + break } + if line.starts_with("/*!") { - return extract_docs_multiline_style(line, reader) - .map(|i| i.process_doc(indent_headings)); + lines = extract_docs_multiline_style(line, reader)?; + break } line.clear(); } - Ok(Vec::new()) + let readme = lines.process_doc(indent_headings).into_iter() + .fold(String::new(), |mut acc, x| { + if !acc.is_empty() { acc.push('\n'); } + acc.push_str(&x); + acc + }); + + Ok(readme) } fn extract_docs_singleline_style(first_line: String, reader: BufReader) -> io::Result> { diff --git a/src/readme/mod.rs b/src/readme/mod.rs index 9fdd959..cac6bcc 100644 --- a/src/readme/mod.rs +++ b/src/readme/mod.rs @@ -5,8 +5,7 @@ mod extract; mod process; mod template; -use self::transform::DocTransform; -use cargo_info; +use ::config; /// Generates readme data from `source` file /// @@ -17,20 +16,12 @@ pub fn generate_readme( template: Option<&mut T>, add_title: bool, add_license: bool, + add_badges: bool, indent_headings: bool, ) -> Result { - let readme = extract::extract_docs(source) - .map_err(|e| format!("{}", e))? - .into_iter() - .transform_doc(indent_headings) - .fold(String::new(), |mut acc, x| { - if !acc.is_empty() { - acc.push('\n'); - } - acc.push_str(&x); - acc - }); + let readme = extract::extract_docs(source, indent_headings) + .map_err(|e| format!("{}", e))?; // get template from file let template = if let Some(template) = template { @@ -39,13 +30,18 @@ pub fn generate_readme( None }; - // get cargo info from Cargo.toml - let cargo = cargo_info::get_cargo_info(project_root)?; - if add_license && cargo.package.license.is_none() { + // get manifest from Cargo.toml + let cargo = config::get_manifest(project_root)?; + + if add_license && cargo.license.is_none() { return Err("License not found in Cargo.toml".to_owned()); } - template::render(template, readme, cargo, add_title, add_license) + if add_badges && cargo.badges.is_empty() { + return Err("No badges found in Cargo.toml".to_owned()); + } + + template::render(template, readme, cargo, add_title, add_badges, add_license) } /// Load a template String from a file diff --git a/src/readme/template.rs b/src/readme/template.rs index b6dce49..6308901 100644 --- a/src/readme/template.rs +++ b/src/readme/template.rs @@ -1,4 +1,4 @@ -use cargo_info::Cargo; +use ::config::Manifest; /// Renders the template /// @@ -6,37 +6,59 @@ use cargo_info::Cargo; pub fn render( template: Option, mut readme: String, - cargo: Cargo, + cargo: Manifest, add_title: bool, + add_badges: bool, add_license: bool, ) -> Result { - let title = cargo.package.name.as_ref(); - let license = cargo.package.license.as_ref(); + let title = cargo.name.as_ref(); + let badges = cargo.badges.as_ref(); + let license = cargo.license.as_ref(); match template { Some(template) => { if template.contains("{{license}}") && !add_license { return Err( - "`{{license}}` was found in template but should not be rendered".to_owned(), + "`{{license}}` was found in template but license should not be rendered".to_owned() + ); + } + + if template.contains("{{badges}}") && !add_badges { + return Err( + "`{{badges}}` was found in template but badges should not be rendered".to_owned() ); } if template.contains("{{crate}}") && !add_title { return Err( - "`{{crate}}` was found in template but title should not be rendered" - .to_owned(), + "`{{crate}}` was found in template but title should not be rendered".to_owned() ); } - let title = if add_title { Some(title) } else { None }; + let title = if add_title { + Some(title) + } else { + None + }; + + let badges = if add_badges { + Some(badges) + } else { + None + }; + let license = if add_license { - Some(license.unwrap().as_ref()) + license.map(|l| l.as_ref()) } else { None }; + process_template(template, readme, title, license) } None => { + if add_badges { + readme = prepend_badges(readme, &badges); + } if add_title { readme = prepend_title(readme, &title); } @@ -96,6 +118,12 @@ fn process_template( Ok(result) } +/// Prepend badges to output string +fn prepend_badges(readme: String, badges: &Vec) -> String { + let badges = badges.iter().fold(String::new(), |acc, x| format!("{}\n{}", acc, x)); + format!("{}\n\n{}", badges, readme) +} + /// Prepend title (crate name) to output string fn prepend_title(readme: String, crate_name: &str) -> String { let title = format!("# {}", crate_name);