// // Copyright (c) 2020-2022 science+computing ag and other contributors // // This program and the accompanying materials are made // available under the terms of the Eclipse Public License 2.0 // which is available at https://www.eclipse.org/legal/epl-2.0/ // // SPDX-License-Identifier: EPL-2.0 // use std::ops::Deref; use anyhow::Context; use anyhow::Error; use anyhow::Result; use pom::parser::Parser as PomParser; use serde::Deserialize; use serde::Serialize; use crate::util::parser::*; #[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct PackageVersionConstraint { constraint: String, version: PackageVersion, } impl PackageVersionConstraint { fn parser<'a>() -> PomParser<'a, u8, Self> { (pom::parser::sym(b'=') + PackageVersion::parser()) .convert(|(constraint, version)| { String::from_utf8(vec![constraint]).map(|c| (c, version)) }) .map(|(constraint, version)| PackageVersionConstraint { constraint, version, }) } pub fn matches(&self, v: &PackageVersion) -> bool { self.version == *v } #[cfg(test)] pub fn from_version(constraint: String, version: PackageVersion) -> Self { PackageVersionConstraint { constraint, version, } } } impl std::convert::TryFrom for PackageVersionConstraint { type Error = anyhow::Error; fn try_from(s: String) -> Result { Self::try_from(&s as &str) } } impl std::convert::TryFrom<&str> for PackageVersionConstraint { type Error = anyhow::Error; fn try_from(s: &str) -> Result { PackageVersionConstraint::parser() .parse(s.as_bytes()) .context("Failed to parse package version constraint") .context("A package version constraint must have a comparator and a version string, like so: =0.1.0") .map_err(Error::from) } } impl std::fmt::Display for PackageVersionConstraint { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}{}", self.constraint, self.version) } } #[derive( parse_display::Display, Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, )] #[serde(transparent)] #[display("{0}")] pub struct PackageVersion(String); impl Deref for PackageVersion { type Target = String; fn deref(&self) -> &Self::Target { &self.0 } } impl AsRef for PackageVersion { fn as_ref(&self) -> &str { &self.0 } } impl From for PackageVersion { fn from(s: String) -> Self { PackageVersion(s) } } impl PackageVersion { fn parser<'a>() -> PomParser<'a, u8, Self> { (numbers() + ((dash() | under() | dot() | letters() | numbers()).repeat(0..))) .collect() .convert(|b| String::from_utf8(b.to_vec()).map(Self::from)) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_parse_version_1() { assert!(PackageVersion::parser().parse(b"").is_err()); assert!(PackageVersion::parser().parse(b"=").is_err()); assert!(PackageVersion::parser().parse(b"*1").is_err()); assert!(PackageVersion::parser().parse(b">1").is_err()); assert!(PackageVersion::parser().parse(b"<1").is_err()); assert!(PackageVersion::parser().parse(b"=a").is_err()); assert!(PackageVersion::parser().parse(b"=.a").is_err()); assert!(PackageVersion::parser().parse(b"=.1").is_err()); assert!(PackageVersion::parser().parse(b"=a1").is_err()); assert!(PackageVersion::parser().parse(b"a").is_err()); assert!(PackageVersionConstraint::parser() .parse(b"") .is_err()); assert!(PackageVersionConstraint::parser() .parse(b"=") .is_err()); assert!(PackageVersionConstraint::parser() .parse(b"*1") .is_err()); assert!(PackageVersionConstraint::parser() .parse(b">1") .is_err()); assert!(PackageVersionConstraint::parser() .parse(b"<1") .is_err()); assert!(PackageVersionConstraint::parser() .parse(b"=a") .is_err()); assert!(PackageVersionConstraint::parser() .parse(b"=.a") .is_err()); assert!(PackageVersionConstraint::parser() .parse(b"=.1") .is_err()); assert!(PackageVersionConstraint::parser() .parse(b"=a1") .is_err()); assert!(PackageVersionConstraint::parser() .parse(b"1") .is_err()); assert!(PackageVersionConstraint::parser() .parse(b"a") .is_err()); } #[test] fn test_parse_version_2() { let s = "=1"; let c = PackageVersionConstraint::parser() .parse(s.as_bytes()) .unwrap(); assert_eq!(c.version, PackageVersion::from(String::from("1"))); } #[test] fn test_parse_version_3() { let s = "=1.0.17"; let c = PackageVersionConstraint::parser() .parse(s.as_bytes()) .unwrap(); assert_eq!(c.version, PackageVersion::from(String::from("1.0.17"))); } #[test] fn test_parse_version_4() { let s = "=1.0.17asejg"; let c = PackageVersionConstraint::parser() .parse(s.as_bytes()) .unwrap(); assert_eq!(c.version, PackageVersion::from(String::from("1.0.17asejg"))); } #[test] fn test_parse_version_5() { let s = "=1-0B17-beta1247_commit_12653hasd"; let c = PackageVersionConstraint::parser() .parse(s.as_bytes()) .unwrap(); assert_eq!( c.version, PackageVersion::from(String::from("1-0B17-beta1247_commit_12653hasd")) ); } }