///|
pub(all) suberror SpecError {
MissingOwner
MissingRepo
MissingVersion
MissingPackagePath
InvalidFormat(String)
} derive(Eq, Show)
///|
pub struct Spec {
owner : String
repo : String
version : String?
package_path : String
package_name : String
} derive(Eq, Show)
///|
pub fn parse_spec(input : String) -> Result[Spec, SpecError] {
let parts : Array[String] = input
.split("/")
.map(part => part.to_string())
.to_array()
if parts.length() == 0 || parts[0].length() == 0 {
return Err(SpecError::MissingOwner)
}
if parts.length() < 2 || parts[1].length() == 0 {
return Err(SpecError::MissingRepo)
}
if parts.length() < 3 {
return Err(SpecError::MissingPackagePath)
}
let owner = parts[0]
let repo_with_version = parts[1]
let (repo, version) = match split_once(repo_with_version, "@") {
Some(pair) => {
let (repo, version) = pair
if repo.length() == 0 {
return Err(SpecError::InvalidFormat(input))
}
if version.length() == 0 {
return Err(SpecError::MissingVersion)
}
(repo, Some(version))
}
None => {
if repo_with_version.length() == 0 {
return Err(SpecError::InvalidFormat(input))
}
(repo_with_version, None)
}
}
let package_path = parts[2:].iter().join("/")
if package_path.length() == 0 {
return Err(SpecError::MissingPackagePath)
}
let package_name = parts[parts.length() - 1]
Ok({ owner, repo, version, package_path, package_name })
}
///|
fn split_once(s : String, sep : StringView) -> (String, String)? {
match s.find(sep) {
Some(i) => {
let sep_len = sep.length()
try s[:i] catch {
_ => None
} noraise {
left_view =>
try s[i + sep_len:] catch {
_ => None
} noraise {
right_view => Some((left_view.to_string(), right_view.to_string()))
}
}
}
None => None
}
}