feat: add package identifiers

This commit is contained in:
Strix 2023-10-14 22:39:40 +02:00
parent 6e30a8bed7
commit a0416cf6a9
No known key found for this signature in database
GPG key ID: 49B2E37B8915B774
5 changed files with 185 additions and 1 deletions

View file

@ -0,0 +1,114 @@
use std::str::FromStr;
use regex::Regex;
#[derive(Debug)]
pub enum PackageIdentifierError {
InvalidPackageLocator(String),
InvalidURI(String),
}
impl std::fmt::Display for PackageIdentifierError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
PackageIdentifierError::InvalidPackageLocator(s) => write!(f, "Invalid package locator: {}", s),
PackageIdentifierError::InvalidURI(s) => write!(f, "Invalid URI: {}", s),
}
}
}
#[derive(Debug)]
pub enum PackageIdentifier {
PackageLocator(PackageLocator),
URI(String),
}
impl std::fmt::Display for PackageIdentifier {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
PackageIdentifier::PackageLocator(pl) => write!(f, "{}", pl),
PackageIdentifier::URI(uri) => write!(f, "{}", uri),
}
}
}
#[derive(Debug)]
pub struct PackageLocator {
pub name: String,
pub version: Option<u32>,
pub tags: Option<Vec<String>>,
}
impl std::fmt::Display for PackageLocator {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut s = self.name.clone();
if let Some(version) = self.version {
s += &*format!("@{}", version);
}
if let Some(tags) = &self.tags {
s += &*format!(":{}", tags.join(","));
}
write!(f, "{}", s)
}
}
impl FromStr for PackageIdentifier {
type Err = PackageIdentifierError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let uri_re = regex::Regex::new(r"^[a-zA-Z0-9]+://").unwrap();
if uri_re.is_match(s) {
// there needs to be stuff after the protocol
let split = s.split("://").collect::<Vec<&str>>();
if split.len() != 2 || split[1].is_empty() {
return Err(PackageIdentifierError::InvalidURI(s.to_string()));
}
Ok(PackageIdentifier::URI(s.to_string()))
} else {
let pl = match PackageLocator::from_str(s) {
Ok(pl) => pl,
Err(e) => return Err(PackageIdentifierError::InvalidPackageLocator(e.to_string())),
};
Ok(PackageIdentifier::PackageLocator(pl))
}
}
}
impl FromStr for PackageLocator {
type Err = PackageIdentifierError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
#[allow(unused_assignments)] // false positive
let mut name = None;
let mut version = None;
let mut tags = None;
if s.is_empty() {
return Err(PackageIdentifierError::InvalidPackageLocator(s.to_string()));
}
let name_re = Regex::new("^([A-Za-z][A-Za-z0-9_.]+)").unwrap();
let version_re = Regex::new("@([0-9]+)").unwrap();
let tags_re = Regex::new(":([a-zA-Z0-9,._]+)").unwrap();
if let Some(caps) = name_re.captures(s) {
name = Some(caps.get(1).unwrap().as_str().to_string());
} else {
return Err(PackageIdentifierError::InvalidPackageLocator(s.to_string()));
}
if let Some(caps) = version_re.captures(s) {
version = Some(caps.get(1).unwrap().as_str().parse::<u32>().unwrap());
}
if let Some(caps) = tags_re.captures(s) {
tags = Some(caps.get(1).unwrap().as_str().split(",").map(|s| s.to_string()).collect());
}
Ok(PackageLocator {
name: name.unwrap(),
version,
tags,
})
}
}

1
pkgr/src/package/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod identifier;