mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-06-07 19:26:36 +00:00
Rename lib to binstalk (#361)
This commit is contained in:
parent
a94d83f0d5
commit
e25aa50ec9
49 changed files with 25 additions and 25 deletions
112
crates/binstalk/src/ops/resolve/crate_name.rs
Normal file
112
crates/binstalk/src/ops/resolve/crate_name.rs
Normal file
|
@ -0,0 +1,112 @@
|
|||
use std::{fmt, str::FromStr};
|
||||
|
||||
use compact_str::CompactString;
|
||||
use itertools::Itertools;
|
||||
use semver::{Error, VersionReq};
|
||||
|
||||
use super::version_ext::VersionReqExt;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct CrateName {
|
||||
pub name: CompactString,
|
||||
pub version_req: Option<VersionReq>,
|
||||
}
|
||||
|
||||
impl fmt::Display for CrateName {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.name)?;
|
||||
|
||||
if let Some(version) = &self.version_req {
|
||||
write!(f, "@{version}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for CrateName {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(if let Some((name, version)) = s.split_once('@') {
|
||||
CrateName {
|
||||
name: name.into(),
|
||||
version_req: Some(VersionReq::parse_from_cli(version)?),
|
||||
}
|
||||
} else {
|
||||
CrateName {
|
||||
name: s.into(),
|
||||
version_req: None,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl CrateName {
|
||||
pub fn dedup(crate_names: &[Self]) -> impl Iterator<Item = Self> {
|
||||
let mut crate_names = crate_names.to_vec();
|
||||
crate_names.sort_by(|x, y| x.name.cmp(&y.name));
|
||||
crate_names.into_iter().coalesce(|previous, current| {
|
||||
if previous.name == current.name {
|
||||
Ok(current)
|
||||
} else {
|
||||
Err((previous, current))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
macro_rules! assert_dedup {
|
||||
([ $( ( $input_name:expr, $input_version:expr ) ),* ], [ $( ( $output_name:expr, $output_version:expr ) ),* ]) => {
|
||||
let input_crate_names = [$( CrateName {
|
||||
name: $input_name.into(),
|
||||
version_req: Some($input_version.parse().unwrap())
|
||||
}, )*];
|
||||
|
||||
let mut output_crate_names: Vec<CrateName> = vec![$( CrateName {
|
||||
name: $output_name.into(), version_req: Some($output_version.parse().unwrap())
|
||||
}, )*];
|
||||
output_crate_names.sort_by(|x, y| x.name.cmp(&y.name));
|
||||
|
||||
let crate_names: Vec<_> = CrateName::dedup(&input_crate_names).collect();
|
||||
assert_eq!(crate_names, output_crate_names);
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dedup() {
|
||||
// Base case 0: Empty input
|
||||
assert_dedup!([], []);
|
||||
|
||||
// Base case 1: With only one input
|
||||
assert_dedup!([("a", "1")], [("a", "1")]);
|
||||
|
||||
// Base Case 2: Only has duplicate names
|
||||
assert_dedup!([("a", "1"), ("a", "2")], [("a", "2")]);
|
||||
|
||||
// Complex Case 0: Having two crates
|
||||
assert_dedup!(
|
||||
[("a", "10"), ("b", "3"), ("a", "0"), ("b", "0"), ("a", "1")],
|
||||
[("a", "1"), ("b", "0")]
|
||||
);
|
||||
|
||||
// Complex Case 1: Having three crates
|
||||
assert_dedup!(
|
||||
[
|
||||
("d", "1.1"),
|
||||
("a", "10"),
|
||||
("b", "3"),
|
||||
("d", "230"),
|
||||
("a", "0"),
|
||||
("b", "0"),
|
||||
("a", "1"),
|
||||
("d", "23")
|
||||
],
|
||||
[("a", "1"), ("b", "0"), ("d", "23")]
|
||||
);
|
||||
}
|
||||
}
|
99
crates/binstalk/src/ops/resolve/version_ext.rs
Normal file
99
crates/binstalk/src/ops/resolve/version_ext.rs
Normal file
|
@ -0,0 +1,99 @@
|
|||
use compact_str::format_compact;
|
||||
use semver::{Prerelease, Version, VersionReq};
|
||||
|
||||
/// Extension trait for [`VersionReq`].
|
||||
pub trait VersionReqExt {
|
||||
/// Return `true` if `self.matches(version)` returns `true`
|
||||
/// and the `version` is the latest one acceptable by `self`.
|
||||
fn is_latest_compatible(&self, version: &Version) -> bool;
|
||||
|
||||
/// Parse from CLI option.
|
||||
///
|
||||
/// Notably, a bare version is treated as if preceded by `=`, not by `^` as in Cargo.toml
|
||||
/// dependencies.
|
||||
fn parse_from_cli(str: &str) -> Result<Self, semver::Error>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl VersionReqExt for VersionReq {
|
||||
fn is_latest_compatible(&self, version: &Version) -> bool {
|
||||
if !self.matches(version) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test if bumping patch will be accepted
|
||||
let bumped_version = Version::new(version.major, version.minor, version.patch + 1);
|
||||
|
||||
if self.matches(&bumped_version) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test if bumping prerelease will be accepted if version has one.
|
||||
let pre = &version.pre;
|
||||
if !pre.is_empty() {
|
||||
// Bump pre by appending random number to the end.
|
||||
let bumped_pre = format_compact!("{}.1", pre.as_str());
|
||||
|
||||
let bumped_version = Version {
|
||||
major: version.major,
|
||||
minor: version.minor,
|
||||
patch: version.patch,
|
||||
pre: Prerelease::new(&bumped_pre).unwrap(),
|
||||
build: Default::default(),
|
||||
};
|
||||
|
||||
if self.matches(&bumped_version) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn parse_from_cli(version: &str) -> Result<Self, semver::Error> {
|
||||
if version
|
||||
.chars()
|
||||
.next()
|
||||
.map(|ch| ch.is_ascii_digit())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
format_compact!("={version}").parse()
|
||||
} else {
|
||||
version.parse()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
// Test star
|
||||
assert!(!VersionReq::STAR.is_latest_compatible(&Version::parse("0.0.1").unwrap()));
|
||||
assert!(!VersionReq::STAR.is_latest_compatible(&Version::parse("0.1.1").unwrap()));
|
||||
assert!(!VersionReq::STAR.is_latest_compatible(&Version::parse("0.1.1-alpha").unwrap()));
|
||||
|
||||
// Test ^x.y.z
|
||||
assert!(!VersionReq::parse("^0.1")
|
||||
.unwrap()
|
||||
.is_latest_compatible(&Version::parse("0.1.99").unwrap()));
|
||||
|
||||
// Test =x.y.z
|
||||
assert!(VersionReq::parse("=0.1.0")
|
||||
.unwrap()
|
||||
.is_latest_compatible(&Version::parse("0.1.0").unwrap()));
|
||||
|
||||
// Test =x.y.z-alpha
|
||||
assert!(VersionReq::parse("=0.1.0-alpha")
|
||||
.unwrap()
|
||||
.is_latest_compatible(&Version::parse("0.1.0-alpha").unwrap()));
|
||||
|
||||
// Test >=x.y.z-alpha
|
||||
assert!(!VersionReq::parse(">=0.1.0-alpha")
|
||||
.unwrap()
|
||||
.is_latest_compatible(&Version::parse("0.1.0-alpha").unwrap()));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue