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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
use std::collections::HashMap;
use bstr::BString;
use smartstring::alias::String as SmolString;
use std::hash::Hash;
use std::{fmt, slice};
/// A wrapper for a repository of the crates.io index.
pub struct Index {
/// The name and path of the reference used to keep track of the last seen state of the
/// crates.io repository. The default value is `refs/heads/crates-index-diff_last-seen`.
pub seen_ref_name: &'static str,
/// The name of the branch to fetch. This value also affects the tracking branch.
pub branch_name: &'static str,
/// The name of the symbolic name of the remote to fetch from.
/// If `None`, obtain the remote name from the configuration of the currently checked-out branch.
pub remote_name: Option<BString>,
/// The git repository to use for diffing
pub(crate) repo: gix::Repository,
}
/// Identify a kind of change that occurred to a crate
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Change {
/// A crate version was added.
Added(CrateVersion),
/// A crate version was unyanked.
Unyanked(CrateVersion),
/// A crate version was added in a yanked state.
///
/// This can happen if we don't see the commit that added them, so it appears to pop into existence yanked.
/// Knowing this should help to trigger the correct action, as simply `Yanked` crates would be treated quite differently.
AddedAndYanked(CrateVersion),
/// A crate version was yanked.
Yanked(CrateVersion),
/// The name of the crate whose file was deleted, which implies all versions were deleted as well.
CrateDeleted {
/// The name of the deleted crate.
name: String,
/// All of its versions that were deleted along with the file.
versions: Vec<CrateVersion>,
},
/// A crate version was deleted.
///
/// Note that this is equivalent to deleting a line from a crates version file.
/// Should more than one lines be removed per commit, the order of these changes is nondeterministic.
VersionDeleted(CrateVersion),
}
impl Change {
/// Return the added crate, if this is this kind of change.
pub fn added(&self) -> Option<&CrateVersion> {
match self {
Change::Added(v) | Change::AddedAndYanked(v) => Some(v),
_ => None,
}
}
/// Return the yanked crate, if this is this kind of change.
pub fn yanked(&self) -> Option<&CrateVersion> {
match self {
Change::Yanked(v) | Change::AddedAndYanked(v) => Some(v),
_ => None,
}
}
/// Return the unyanked crate, if this is this kind of change.
pub fn unyanked(&self) -> Option<&CrateVersion> {
match self {
Change::Unyanked(v) => Some(v),
_ => None,
}
}
/// Return the deleted crate, if this is this kind of change.
pub fn crate_deleted(&self) -> Option<(&str, &[CrateVersion])> {
match self {
Change::CrateDeleted { name, versions } => Some((name.as_str(), versions)),
_ => None,
}
}
/// Return the deleted version crate, if this is this kind of change.
pub fn version_deleted(&self) -> Option<&CrateVersion> {
match self {
Change::VersionDeleted(v) => Some(v),
_ => None,
}
}
/// Returns all versions affected by this change.
///
/// The returned slice usually has length 1.
/// However, if a crate was purged from the index by an admin,
/// all versions of the purged crate are returned.
pub fn versions(&self) -> &[CrateVersion] {
match self {
Change::Added(v)
| Change::Unyanked(v)
| Change::AddedAndYanked(v)
| Change::Yanked(v)
| Change::VersionDeleted(v) => slice::from_ref(v),
Change::CrateDeleted { versions, .. } => versions,
}
}
}
impl fmt::Display for Change {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match *self {
Change::Added(_) => "added",
Change::Yanked(_) => "yanked",
Change::CrateDeleted { .. } => "crate deleted",
Change::VersionDeleted(_) => "version deleted",
Change::Unyanked(_) => "unyanked",
Change::AddedAndYanked(_) => "added and yanked",
}
)
}
}
/// Section in which a dependency was defined in.
#[derive(
Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash, Ord, PartialOrd,
)]
#[serde(rename_all = "lowercase")]
pub enum DependencyKind {
/// Used for production builds.
Normal,
/// Used only for tests and examples.
Dev,
/// Used in build scripts.
Build,
}
/// Pack all information we know about a change made to a version of a crate.
#[derive(Default, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Debug)]
pub struct CrateVersion {
/// The crate name, i.e. `clap`.
pub name: SmolString,
/// is the release yanked?
pub yanked: bool,
/// The semantic version of the crate.
#[serde(rename = "vers")]
pub version: SmolString,
/// The checksum over the crate archive
#[serde(rename = "cksum", with = "hex")]
pub checksum: [u8; 32],
/// All cargo features
pub features: HashMap<String, Vec<String>>,
/// All crate dependencies
#[serde(rename = "deps")]
pub dependencies: Vec<Dependency>,
}
/// A single dependency of a specific crate version
#[derive(
Clone, serde::Serialize, serde::Deserialize, Ord, PartialOrd, Eq, PartialEq, Debug, Hash,
)]
pub struct Dependency {
/// The crate name
pub name: SmolString,
/// The version the parent crate requires of this dependency
#[serde(rename = "req")]
pub required_version: SmolString,
/// All cargo features configured by the parent crate
pub features: Vec<String>,
/// True if this is an optional dependency
pub optional: bool,
/// True if default features are enabled
pub default_features: bool,
/// The name of the build target
#[serde(skip_serializing_if = "Option::is_none")]
pub target: Option<SmolString>,
/// The kind of dependency, usually 'normal' or 'dev'
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<DependencyKind>,
/// The package this crate is contained in
#[serde(skip_serializing_if = "Option::is_none")]
pub package: Option<SmolString>,
}