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
//! Support for interacting with the local crates.io registry index

use crate::{
    error::{Error, ErrorKind},
    package,
};

/// Crates.io registry index (local copy)
pub struct Index(crates_index::Index);

impl Index {
    /// Open the local crates.io index, fetching it if it doesn't exist, and
    /// updating it if it does.
    pub fn fetch() -> Result<Self, Error> {
        let index = crates_index::Index::new_cargo_default();

        if index.exists() {
            index.update()?;
        } else {
            index.retrieve()?;
        }

        Ok(Index(index))
    }

    /// Open the local crates.io index, erroring if it hasn't been fetched yet
    pub fn open() -> Result<Self, Error> {
        let index = crates_index::Index::new_cargo_default();

        if !index.exists() {
            fail!(
                ErrorKind::Registry,
                "crates.io registry has not been fetched yet"
            );
        }

        Ok(Index(index))
    }

    /// Find an entry for a particular package in the index
    pub fn find(
        &self,
        package: &package::Name,
        version: &package::Version,
    ) -> Result<IndexPackage, Error> {
        let crate_releases = self.0.crate_(package.as_str()).ok_or_else(|| {
            format_err!(
                ErrorKind::NotFound,
                "no results for: {} {}",
                &package,
                &version
            )
        })?;

        let crate_release = crate_releases
            .versions()
            .iter()
            .find(|crate_version| crate_version.version() == version.to_string())
            .ok_or_else(|| {
                format_err!(
                    ErrorKind::NotFound,
                    "no results for: {} {}",
                    &package,
                    &version
                )
            })?;

        Ok(IndexPackage::from(crate_release))
    }
}

/// Release of the package in the crates.io registry
pub struct IndexPackage {
    /// Name of this package
    pub package: package::Name,

    /// Version of this package
    pub version: package::Version,

    /// Is this package yanked?
    pub is_yanked: bool,
}

impl From<&crates_index::Version> for IndexPackage {
    fn from(crate_release: &crates_index::Version) -> IndexPackage {
        IndexPackage {
            package: crate_release.name().parse().unwrap(),
            version: crate_release.version().parse().unwrap(),
            is_yanked: crate_release.is_yanked(),
        }
    }
}