From 9d0b52a535f8f87611dbb8ce38726397c63f51d3 Mon Sep 17 00:00:00 2001 From: Bloxx12 Date: Thu, 8 May 2025 15:27:34 +0200 Subject: [PATCH] main, util: move get_version to util.rs --- src/main.rs | 62 ++----------------------------------------------- src/util.rs | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 60 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0da38d0..084e440 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,11 +3,8 @@ mod util; use clap::Parser; use core::str; use log::{debug, error}; -use regex::Regex; use std::{ collections::{HashMap, HashSet}, - string::ToString, - sync::OnceLock, thread, }; use yansi::Paint; @@ -153,7 +150,7 @@ fn main() { let mut post = HashMap::<&str, HashSet<&str>>::new(); for p in &package_list_pre { - match get_version(&**p) { + match util::get_version(&**p) { Ok((name, version)) => { pre.entry(name).or_default().insert(version); } @@ -164,7 +161,7 @@ fn main() { } for p in &package_list_post { - match get_version(&**p) { + match util::get_version(&**p) { Ok((name, version)) => { post.entry(name).or_default().insert(version); } @@ -247,58 +244,3 @@ fn main() { } } } - -// Returns a reference to the compiled regex pattern. -// The regex is compiled only once. -fn store_path_regex() -> &'static Regex { - static REGEX: OnceLock = OnceLock::new(); - REGEX.get_or_init(|| { - Regex::new(r"(.+?)(-([0-9].*?))?$") - .expect("Failed to compile regex pattern for nix store paths") - }) -} - -/// Parses a nix store path to extract the packages name and version -/// -/// This function first drops the inputs first 44 chars, since that is exactly the length of the /nix/store/... prefix. Then it matches that against our store path regex. -/// -/// # Returns -/// -/// * Result<(&'a str, &'a str)> - The Package's name and version, or an error if -/// one or both cannot be retrieved. -fn get_version<'a>(pack: impl Into<&'a str>) -> Result<(&'a str, &'a str)> { - let path = pack.into(); - - // We can strip the path since it _always_ follows the format - // /nix/store/<...>--...... - // This part is exactly 44 chars long, so we just remove it. - let stripped_path = &path[44..]; - debug!("Stripped path: {stripped_path}"); - - // Match the regex against the input - if let Some(cap) = store_path_regex().captures(stripped_path) { - // Handle potential missing captures safely - let name = cap.get(1).map_or("", |m| m.as_str()); - let mut version = cap.get(2).map_or("", |m| m.as_str()); - - if version.starts_with('-') { - version = &version[1..]; - } - - if name.is_empty() { - return Err(AppError::ParseError { - message: format!("Failed to extract name from path: {path}"), - context: "get_version".to_string(), - source: None, - }); - } - - return Ok((name, version)); - } - - Err(AppError::ParseError { - message: format!("Path does not match expected nix store format: {path}"), - context: "get_version".to_string(), - source: None, - }) -} diff --git a/src/util.rs b/src/util.rs index cec4503..a0a57f9 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,18 @@ +use crate::error::AppError; +use log::{debug, error}; +use regex::Regex; use std::cmp::Ordering; +use std::{ + collections::{HashMap, HashSet}, + string::ToString, + sync::OnceLock, + thread, +}; + +// Use type alias for Result with our custom error type +type Result = std::result::Result; + #[derive(Eq, PartialEq, Debug)] enum VersionComponent { Number(u64), @@ -114,3 +127,57 @@ mod test { ); } } +/// Parses a nix store path to extract the packages name and version +/// +/// This function first drops the inputs first 44 chars, since that is exactly the length of the /nix/store/... prefix. Then it matches that against our store path regex. +/// +/// # Returns +/// +/// * Result<(&'a str, &'a str)> - The Package's name and version, or an error if +/// one or both cannot be retrieved. +pub fn get_version<'a>(pack: impl Into<&'a str>) -> Result<(&'a str, &'a str)> { + let path = pack.into(); + + // We can strip the path since it _always_ follows the format + // /nix/store/<...>--...... + // This part is exactly 44 chars long, so we just remove it. + let stripped_path = &path[44..]; + debug!("Stripped path: {stripped_path}"); + + // Match the regex against the input + if let Some(cap) = store_path_regex().captures(stripped_path) { + // Handle potential missing captures safely + let name = cap.get(1).map_or("", |m| m.as_str()); + let mut version = cap.get(2).map_or("", |m| m.as_str()); + + if version.starts_with('-') { + version = &version[1..]; + } + + if name.is_empty() { + return Err(AppError::ParseError { + message: format!("Failed to extract name from path: {path}"), + context: "get_version".to_string(), + source: None, + }); + } + + return Ok((name, version)); + } + + Err(AppError::ParseError { + message: format!("Path does not match expected nix store format: {path}"), + context: "get_version".to_string(), + source: None, + }) +} + +// Returns a reference to the compiled regex pattern. +// The regex is compiled only once. +fn store_path_regex() -> &'static Regex { + static REGEX: OnceLock = OnceLock::new(); + REGEX.get_or_init(|| { + Regex::new(r"(.+?)(-([0-9].*?))?$") + .expect("Failed to compile regex pattern for nix store paths") + }) +}