Skip to content

Commit

Permalink
more pep440 impl; remove manifest in favor of function param
Browse files Browse the repository at this point in the history
  • Loading branch information
msarahan committed Oct 15, 2019
1 parent d3f3df0 commit ed56713
Show file tree
Hide file tree
Showing 9 changed files with 236 additions and 733 deletions.
1 change: 1 addition & 0 deletions src/custom_parts/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod pep440;
96 changes: 96 additions & 0 deletions src/custom_parts/pep440.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use std::cmp::Ordering;
use std::fmt;
use regex::Regex;

#[derive(Debug, Copy, Clone)]
pub struct PEP440String<'a> {
pre: i16,
alpha: &'a str,
post: i16,
}

impl<'a> PEP440String<'a> {
fn new(input: &'a str) -> PEP440String {
lazy_static! {
static ref RE: Regex = Regex::new(r"^(\d*)([a-zA-Z]*)(\d*)").unwrap();
}

let caps = RE.captures(input).unwrap();
let pre: i16 = caps.get(1).map_or(0, |m| m.as_str().parse().unwrap());
let alpha = caps.get(2).map_or("", |m| m.as_str());
let post: i16 = caps.get(3).map_or(0, |m| m.as_str().parse().unwrap());

PEP440String{pre, alpha, post }
}

pub fn empty() -> PEP440String<'a> {
PEP440String {pre: 0, alpha: "", post: 0}
}
}

fn compare_pep440_str<'a>(left: &'a str, right: &'a str) -> Option<Ordering> {
lazy_static! { static ref DEV_RE: Regex = Regex::new("dev").unwrap(); }
lazy_static! { static ref POST_RE: Regex = Regex::new("post").unwrap(); }

let is_dev = (DEV_RE.is_match(left), DEV_RE.is_match(right));
let is_post = (POST_RE.is_match(left), POST_RE.is_match(right));

let str_match = left.partial_cmp(right);
match str_match {
Some(Ordering::Equal) => Some(Ordering::Equal),
_ => match is_dev {
(false, true) => Some(Ordering::Greater),
(true, false) => Some(Ordering::Less),
_ => match is_post {
(true, true) => Some(Ordering::Equal),
(false, true) => Some(Ordering::Less),
(true, false) => Some(Ordering::Greater),
// this is the final fallback to lexicographic sorting, if neither
// dev nor post are in effect
(false, false) => left.partial_cmp(right),
}
}
}
}

impl<'a> PartialOrd for PEP440String<'a> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match self.pre.partial_cmp(&other.pre) {
Some(Ordering::Greater) => Some(Ordering::Greater),
Some(Ordering::Less) => Some(Ordering::Less),
Some(Ordering::Equal) => match compare_pep440_str(self.alpha, &other.alpha) {
Some(Ordering::Equal) => self.post.partial_cmp(&other.post),
Some(Ordering::Greater) => Some(Ordering::Greater),
Some(Ordering::Less) => Some(Ordering::Less),
_ => panic!()
}
_ => panic!()
}
}
}

impl<'a> PartialEq for PEP440String<'a> {
fn eq(&self, other: &Self) -> bool {
self.partial_cmp(&other).unwrap() == Ordering::Equal
}
}

impl<'a> fmt::Display for PEP440String<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}{}", self.pre, self.alpha, self.post)
}
}

#[cfg_attr(tarpaulin, skip)]
#[cfg(test)]
mod tests {
use super::PEP440String;

#[test]
fn compare_implict_leading_zero() {
assert_eq!(PEP440String::new("0dev"), PEP440String::new("dev"));
// epoch of any value trumps integer (priority)
// assert!(VersionPart::Epoch(value: 0) > VersionPart::Integer(value: 1);
// assert!(Version::Epoch{0} > Version::String{"abc"});
}
}
14 changes: 9 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,19 @@
#[macro_use] extern crate lazy_static;

pub mod comp_op;
//pub mod version;
pub mod version_manifest;
pub mod version_part;
pub mod version;
pub mod version_compare;
pub mod parsers;
// Ideally no one interacts directly with the parts
mod version_part;
mod custom_parts;

#[cfg(test)]
mod test;

// Reexports
pub use crate::comp_op::CompOp;
//pub use crate::version::Version;
pub use crate::version_manifest::VersionManifest;
pub use crate::version::Version;
pub use crate::version_part::VersionPart;
pub use crate::version_compare::VersionCompare;
pub use crate::parsers::default::default_parser;
Empty file added src/parsers/conda.rs
Empty file.
44 changes: 44 additions & 0 deletions src/parsers/default.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use crate::version_part::VersionPart;

/// Split the given version string, in it's version parts.
/// TODO: Move this method to some sort of helper class, maybe as part of `VersionPart`.
pub fn default_parser(
version: &str,
) -> Option<Vec<VersionPart>> {
// Split the version string, and create a vector to put the parts in
// TODO: split at specific separators instead
let split = version.split(|c| !char::is_alphanumeric(c));
let mut parts = Vec::new();

// Flag to determine whether this version number contains any number part
let mut has_number = false;

// Loop over the parts, and parse them
for part in split {
// Skip empty parts
if part.is_empty() {
continue;
}

// Try to parse the value as an number
match part.parse::<i32>() {
Ok(number) => {
// Push the number part to the vector, and set the has number flag
parts.push(VersionPart::Integer(number));
has_number = true;
}
Err(_) => {
// Push the text part to the vector
parts.push(VersionPart::LexicographicString(part));
}
}
}

// The version must contain a number part, if any part was parsed
if !has_number && !parts.is_empty() {
return None;
}

// Return the list of parts
Some(parts)
}
2 changes: 2 additions & 0 deletions src/parsers/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod conda;
pub mod default;
Loading

0 comments on commit ed56713

Please sign in to comment.