summaryrefslogtreecommitdiffstats
path: root/rich_crate/src/lib.rs
blob: dbd04d9e90324d57de533874cc7301427b9b03e6 (plain)
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
#[macro_use]
extern crate serde_derive;

pub use cargo_author::*;
mod rich_crate;
pub use crate::rich_crate::*;
mod rich_crate_version;
pub use crate::rich_crate_version::*;

pub use render_readme::Markup;
pub use render_readme::Readme;
pub use repo_url::Repo;
pub use repo_url::RepoHost;
pub use repo_url::SimpleRepo;

/// URL-like identifier of location where crate has been published + normalized crate name
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Origin {
    CratesIo(Box<str>),
    GitHub {repo: SimpleRepo, package: Box<str>},
}

impl Origin {
    pub fn from_crates_io_name(name: &str) -> Self {
        Origin::CratesIo(name.to_ascii_lowercase().into())
    }

    pub fn from_github(repo: SimpleRepo, package: impl Into<Box<str>>) -> Self {
        Origin::GitHub {repo, package: package.into()}
    }

    pub fn from_repo(r: &Repo, package: &str) -> Option<Self> {
        match r.host() {
            RepoHost::GitHub(r) => Some(Self::from_github(r.clone(), package)),
            _ => None,
        }
    }

    pub fn from_str(s: impl AsRef<str>) -> Self {
        let s = s.as_ref();
        let mut n = s.splitn(2, ':');
        let host = n.next().unwrap();
        match host {
            "crates.io" => Self::from_crates_io_name(n.next().expect("parse")),
            "github" => {
                let mut n = n.next().expect("parse").splitn(3, "/");
                let owner = n.next().expect("parse").into();
                let repo = n.next().expect("parse").into();
                let package = n.next().expect("parse");
                Self::from_github(SimpleRepo {owner, repo}, package)
            },
            _ => panic!("bad str {}", s),
        }
    }

    pub fn to_str(&self) -> String {
        match *self {
            Origin::CratesIo(ref s) => format!("crates.io:{}", s),
            Origin::GitHub {ref repo, ref package} => format!("github:{}/{}/{}", repo.owner, repo.repo, package),
        }
    }

    pub fn short_crate_name(&self) -> &str {
        match *self {
            Origin::CratesIo(ref s) => s,
            Origin::GitHub {ref package, ..} => package,
        }
    }
}

#[test]
fn roundtrip() {
    let o1 = Origin::from_crates_io_name("hello");
    let o2 = Origin::from_str(o1.to_str());
    assert_eq!(o1, o2);
    assert_eq!("hello", o2.short_crate_name());
}

#[test]
fn roundtrip_gh() {
    let o1 = Origin::from_github(SimpleRepo {owner: "foo".into(), repo: "bar".into()}, "baz");
    let o3 = Origin::from_github(SimpleRepo {owner: "foo".into(), repo: "bar".into()}, "other_package");
    let o2 = Origin::from_str(o1.to_str());
    assert_eq!(o1, o2);
    assert_ne!(o1, o3);
    assert_eq!("baz", o2.short_crate_name());
}