Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 75 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ regex = "1"
serde = { version = "1", features = ["derive"] }
percent-encoding = "2"
lazy_static = "1"
cargo_toml = "0.17"

[dev-dependencies]
assert_cli = "0.6"
Expand Down
126 changes: 68 additions & 58 deletions src/config/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,24 @@

use serde::Deserialize;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};

use super::badges;

/// Try to get manifest info from Cargo.toml
pub fn get_manifest(project_root: &Path) -> Result<Manifest, String> {
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_path = project_root.join("Cargo.toml");

let cargo_toml: CargoToml = toml::from_str(&buf).map_err(|e| format!("{}", e))?;
// Use cargo_toml crate for workspace inheritance support
let manifest = cargo_toml::Manifest::from_path(&cargo_toml_path)
.map_err(|e| format!("{}", e))?;

let manifest = Manifest::new(cargo_toml);
// Also parse raw TOML for badges (cargo_toml crate doesn't support all badge types)
let raw_toml = std::fs::read_to_string(&cargo_toml_path)
.map_err(|e| format!("Could not read Cargo.toml: {}", e))?;
let raw: RawCargoToml = toml::from_str(&raw_toml).map_err(|e| format!("{}", e))?;

Ok(manifest)
Manifest::try_new(manifest, raw.badges)
}

#[derive(Debug)]
Expand All @@ -39,23 +33,48 @@ pub struct Manifest {
}

impl Manifest {
fn new(cargo_toml: CargoToml) -> Manifest {
Manifest {
name: cargo_toml.package.name,
license: cargo_toml.package.license,
lib: cargo_toml.lib.map(ManifestLib::from_cargo_toml),
bin: cargo_toml
.bin
.map(|bin_vec| {
bin_vec
.into_iter()
.map(ManifestLib::from_cargo_toml)
.collect()
})
.unwrap_or_default(),
badges: cargo_toml.badges.map(process_badges).unwrap_or_default(),
version: cargo_toml.package.version,
}
fn try_new(
manifest: cargo_toml::Manifest,
badges: Option<BTreeMap<String, BTreeMap<String, String>>>,
) -> Result<Manifest, String> {
let package = manifest
.package
.ok_or_else(|| "Missing [package] section in Cargo.toml".to_string())?;

let license = match package.license {
Some(license) => match license.get() {
Ok(license) => Some(license.to_owned()),
Err(_) => {
return Err(
"Could not resolve workspace-inherited license".to_string()
)
}
},
None => None,
};

let lib = ManifestLib::from_product(manifest.lib.as_ref());

let bin = manifest
.bin
.iter()
.filter_map(|bin| ManifestLib::from_product(Some(bin)))
.collect::<Vec<_>>();

let version = package
.version
.get()
.map_err(|_| "Could not resolve workspace-inherited version".to_string())?
.to_owned();

Ok(Manifest {
name: package.name,
license,
lib,
bin,
badges: badges.map(process_badges).unwrap_or_default(),
version,
})
}
}

Expand All @@ -66,10 +85,19 @@ pub struct ManifestLib {
}

impl ManifestLib {
fn from_cargo_toml(lib: CargoTomlLib) -> Self {
ManifestLib {
path: PathBuf::from(lib.path),
doc: lib.doc.unwrap_or(true),
fn from_product(product: Option<&cargo_toml::Product>) -> Option<Self> {
if let Some(cargo_toml::Product {
path: Some(path),
doc,
..
}) = product
{
Some(ManifestLib {
path: path.into(),
doc: *doc,
})
} else {
None
}
}
}
Expand Down Expand Up @@ -100,26 +128,8 @@ fn process_badges(badges: BTreeMap<String, BTreeMap<String, String>>) -> Vec<Str
b.into_iter().map(|(_, badge)| badge).collect()
}

/// Cargo.toml crate information
#[derive(Clone, Deserialize)]
struct CargoToml {
pub package: CargoTomlPackage,
pub lib: Option<CargoTomlLib>,
pub bin: Option<Vec<CargoTomlLib>>,
pub badges: Option<BTreeMap<String, BTreeMap<String, String>>>,
}

/// Cargo.toml crate package information
#[derive(Clone, Deserialize)]
struct CargoTomlPackage {
pub name: String,
pub license: Option<String>,
pub version: String,
}

/// Cargo.toml crate lib information
#[derive(Clone, Deserialize)]
struct CargoTomlLib {
pub path: String,
pub doc: Option<bool>,
/// Used for extracting badges from raw TOML (cargo_toml crate doesn't support all badge types)
#[derive(Deserialize)]
struct RawCargoToml {
badges: Option<BTreeMap<String, BTreeMap<String, String>>>,
}
39 changes: 39 additions & 0 deletions tests/workspace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use assert_cli::Assert;

const EXPECTED_CRATE1: &str = r#"
# crate1

Test crate for cargo-readme
"#;

const EXPECTED_CRATE2: &str = r#"
# crate2

Test crate for cargo-readme
"#;

#[test]
fn workspace_crate1() {
let args = ["readme", "--project-root", "tests/workspace/crate1"];

Assert::main_binary()
.with_args(&args)
.succeeds()
.and()
.stdout()
.is(EXPECTED_CRATE1)
.unwrap();
}

#[test]
fn workspace_crate2() {
let args = ["readme", "--project-root", "tests/workspace/crate2"];

Assert::main_binary()
.with_args(&args)
.succeeds()
.and()
.stdout()
.is(EXPECTED_CRATE2)
.unwrap();
}
11 changes: 11 additions & 0 deletions tests/workspace/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[workspace]
members = ["crate1", "crate2"]

[workspace.package]
edition = "2021"
version = "0.1.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[workspace.dependencies]
serde = "^1.0"
9 changes: 9 additions & 0 deletions tests/workspace/crate1/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "crate1"
version.workspace = true
edition.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { workspace = true }
1 change: 1 addition & 0 deletions tests/workspace/crate1/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//! Test crate for cargo-readme
9 changes: 9 additions & 0 deletions tests/workspace/crate2/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "crate2"
version.workspace = true
edition.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { workspace = true }
1 change: 1 addition & 0 deletions tests/workspace/crate2/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//! Test crate for cargo-readme
Loading