#![forbid(unsafe_code)]
#[derive(Debug, Clone, PartialEq)]
pub struct ArtifactDesc {
pub url: String,
pub archive: String,
pub sha256: String,
pub bin: Vec<String>,
pub strip: u32,
}
pub trait ToolProvider {
fn list_versions(&self) -> Vec<String>;
fn resolve(&self, version: &str, os: &str, arch: &str) -> Option<ArtifactDesc>;
}
pub fn render_url(template: &str, version: &str, os: &str, arch: &str, ext: &str) -> String {
template
.replace("{version}", version)
.replace("{os}", os)
.replace("{arch}", arch)
.replace("{ext}", ext)
}
#[cfg(test)]
mod tests {
use super::*;
struct Demo;
impl ToolProvider for Demo {
fn list_versions(&self) -> Vec<String> {
vec!["1.0.0".into(), "1.1.0".into()]
}
fn resolve(&self, version: &str, os: &str, arch: &str) -> Option<ArtifactDesc> {
Some(ArtifactDesc {
url: render_url(
"https://x.test/demo-{version}-{os}-{arch}.{ext}",
version,
os,
arch,
"tar.gz",
),
archive: "tar.gz".into(),
sha256: "abc".into(),
bin: vec!["bin/demo".into()],
strip: 1,
})
}
}
#[test]
fn render_substitutes_all_placeholders() {
assert_eq!(
render_url(
"a/{version}/{os}-{arch}.{ext}",
"1.2.3",
"macos",
"arm64",
"tar.gz"
),
"a/1.2.3/macos-arm64.tar.gz"
);
}
#[test]
fn author_trait_roundtrip() {
let p = Demo;
assert_eq!(p.list_versions().len(), 2);
let a = p.resolve("1.1.0", "linux", "x64").unwrap();
assert_eq!(a.url, "https://x.test/demo-1.1.0-linux-x64.tar.gz");
assert_eq!(a.strip, 1);
}
}