1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! Read crate information from `Cargo.toml`

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

use toml;

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: CargoToml = toml::from_str(&buf)
        .map_err(|e| format!("{}", e))?;

    let manifest = Manifest::new(cargo_toml);

    Ok(manifest)
}

#[derive(Debug)]
pub struct Manifest {
    pub name: String,
    pub license: Option<String>,
    pub lib: Option<ManifestLib>,
    pub bin: Vec<ManifestLib>,
    pub badges: Vec<String>,
}

impl Manifest {
    fn new(cargo_toml: CargoToml) -> 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: cargo_toml.badges
                .map(|b| process_badges(b))
                .unwrap_or_default()
        }
    }
}

#[derive(Debug)]
pub struct ManifestLib {
    pub path: PathBuf,
    pub doc: bool,
}

impl ManifestLib {
    fn from_cargo_toml(lib: CargoTomlLib) -> Self {
        ManifestLib {
            path: PathBuf::from(lib.path),
            doc: lib.doc.unwrap_or(true)
        }
    }
}

fn process_badges(badges: BTreeMap<String, BTreeMap<String, String>>) -> Vec<String> {
    let mut b: Vec<(u16, _)> = badges.into_iter()
        .filter_map(|(name, attrs)| {
            match name.as_ref() {
                "appveyor" => Some((0, badges::appveyor(attrs))),
                "circle-ci" => Some((1, badges::circle_ci(attrs))),
                "gitlab" => Some((2, badges::gitlab(attrs))),
                "travis-ci" => Some((3, badges::travis_ci(attrs))),
                "codecov" => Some((4, badges::codecov(attrs))),
                "coveralls" => Some((5, badges::coveralls(attrs))),
                "is-it-maintained-issue-resolution" => Some((6, badges::is_it_maintained_issue_resolution(attrs))),
                "is-it-maintained-open-issues" => Some((7, badges::is_it_maintained_open_issues(attrs))),
                _ => return None,
            }
        }).collect();

    b.sort_unstable_by(|a, b| a.0.cmp(&b.0));
    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>,
}

/// Cargo.toml crate lib information
#[derive(Clone, Deserialize)]
struct CargoTomlLib {
    pub path: String,
    pub doc: Option<bool>,
}