use std::path::{Path, PathBuf};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Pinned {
pub tuple: &'static str,
pub url: &'static str,
pub sha256: &'static str,
}
impl Pinned {
#[must_use]
pub fn file_name(&self) -> &'static str {
self.url.rsplit('/').next().unwrap_or(self.url)
}
#[must_use]
pub fn archive_in(&self, cache: &Path) -> PathBuf {
cache.join("downloads").join(self.file_name())
}
}
pub const PINNED: &[Pinned] = &[];
#[must_use]
pub fn pinned_for(tuple: &str) -> Option<&'static Pinned> {
look(PINNED, tuple)
}
#[must_use]
pub fn pinned_targets() -> Vec<&'static str> {
PINNED.iter().map(|what| what.tuple).collect()
}
fn look<'a>(table: &'a [Pinned], tuple: &str) -> Option<&'a Pinned> {
table.iter().find(|what| what.tuple == tuple)
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use rucc_tuple::TargetTuple;
use super::*;
const TABLE: &[Pinned] = &[
Pinned {
tuple: "aarch64-linux-musl",
url: "https://example.invalid/rucc-sysroot-aarch64-linux-musl.tar.gz",
sha256: "1111111111111111111111111111111111111111111111111111111111111111",
},
Pinned {
tuple: "x86_64-linux-musl",
url: "https://example.invalid/rucc-sysroot-x86_64-linux-musl.tar.gz",
sha256: "2222222222222222222222222222222222222222222222222222222222222222",
},
];
#[test]
fn a_target_the_table_names_is_found_and_one_it_does_not_is_not() {
let found = look(TABLE, "x86_64-linux-musl").expect("the table has that one");
assert_eq!(found.sha256, TABLE[1].sha256);
assert_eq!(look(TABLE, "riscv64-linux-gnu"), None);
}
#[test]
fn a_longer_tuple_is_not_the_row_it_begins_with() {
assert_eq!(look(TABLE, "x86_64-linux-musl.1.2.5"), None);
assert_eq!(look(TABLE, "x86_64-linux"), None);
}
#[test]
fn the_archive_is_named_by_the_url_and_kept_under_the_cache() {
let what = TABLE[0];
assert_eq!(what.file_name(), "rucc-sysroot-aarch64-linux-musl.tar.gz");
assert_eq!(
what.archive_in(&PathBuf::from("/tmp/cache")),
PathBuf::from("/tmp/cache/downloads/rucc-sysroot-aarch64-linux-musl.tar.gz")
);
}
#[test]
fn every_row_is_a_target_a_url_and_a_hash() {
for what in PINNED {
let tuple: TargetTuple =
what.tuple.parse().unwrap_or_else(|why| panic!("{}: {why}", what.tuple));
assert_eq!(
tuple.to_canonical_string(),
what.tuple,
"a row is named by the canonical spelling, because that is what names the \
directory the tree is installed at"
);
assert!(what.url.starts_with("https://"), "{}: {}", what.tuple, what.url);
assert!(!what.url.contains('?') && !what.url.contains('#'), "{}", what.url);
assert!(!what.file_name().is_empty(), "{} ends with a separator", what.url);
assert_eq!(what.sha256.len(), 64, "{}: {}", what.tuple, what.sha256);
assert!(
what.sha256.bytes().all(|b| b.is_ascii_digit() || (b'a'..=b'f').contains(&b)),
"{}: {} is not lowercase hex, and the check compares text",
what.tuple,
what.sha256
);
}
let mut sorted: Vec<&str> = pinned_targets();
sorted.sort_unstable();
sorted.dedup();
assert_eq!(sorted, pinned_targets(), "the rows are in tuple order and each target once");
}
}