use crate::architecture::{self, Architecture};
use std::borrow::Cow;
#[derive(Clone, Debug, PartialEq)]
pub struct Release {
pub name: Cow<'static, str>,
pub version: Cow<'static, str>,
pub architectures: Cow<'static, [Architecture]>,
released_on: Option<NaiveDate>,
eol_on: Option<NaiveDate>,
}
macro_rules! cow {
( $str:expr ) => {
Cow::Borrowed($str)
};
}
#[cfg(feature = "chrono")]
use ::chrono::NaiveDate;
#[cfg(feature = "chrono")]
macro_rules! date {
($y:literal/$m:literal/$d:literal) => {
NaiveDate::from_ymd_opt($y, $m, $d)
};
}
#[cfg(not(feature = "chrono"))]
type NaiveDate = ();
#[cfg(not(feature = "chrono"))]
macro_rules! date {
($_:expr) => {
None
};
}
pub const BUZZ: Release = Release {
name: cow!("buzz"),
version: cow!("1.1"),
released_on: date!(1996 / 6 / 16),
eol_on: date!(1996 / 12 / 12),
architectures: cow!(&[architecture::I386]),
};
pub const REX: Release = Release {
name: cow!("rex"),
version: cow!("1.2"),
released_on: date!(1996 / 12 / 12),
eol_on: date!(1997 / 7 / 2),
architectures: cow!(&[architecture::I386]),
};
pub const BO: Release = Release {
name: cow!("bo"),
version: cow!("1.3"),
released_on: date!(1997 / 7 / 2),
eol_on: date!(1998 / 7 / 24),
architectures: cow!(&[
architecture::I386,
architecture::M68K,
architecture::ALPHA,
architecture::SPARC
]),
};
pub const HAMM: Release = Release {
name: cow!("hamm"),
version: cow!("2.0"),
released_on: date!(1998 / 6 / 24),
eol_on: date!(1999 / 3 / 9),
architectures: cow!(&[architecture::I386, architecture::M68K]),
};
pub const SLINK: Release = Release {
name: cow!("slink"),
version: cow!("2.1"),
released_on: date!(1999 / 3 / 9),
eol_on: date!(2000 / 9 / 30),
architectures: cow!(&[
architecture::ALPHA,
architecture::I386,
architecture::M68K,
architecture::SPARC,
]),
};
pub const POTATO: Release = Release {
name: cow!("potato"),
version: cow!("2.2"),
released_on: date!(2000 / 8 / 15),
eol_on: date!(2003 / 6 / 30),
architectures: cow!(&[
architecture::ALPHA,
architecture::ARM,
architecture::I386,
architecture::M68K,
architecture::POWERPC,
architecture::SPARC,
]),
};
pub const WOODY: Release = Release {
name: cow!("woody"),
version: cow!("3.0"),
released_on: date!(2002 / 7 / 19),
eol_on: date!(2006 / 6 / 30),
architectures: cow!(&[
architecture::ALPHA,
architecture::ARM,
architecture::HPPA,
architecture::I386,
architecture::IA64,
architecture::M68K,
architecture::MIPS,
architecture::MIPSEL,
architecture::POWERPC,
architecture::S390,
architecture::SPARC,
]),
};
pub const SARGE: Release = Release {
name: cow!("sarge"),
version: cow!("3.1"),
released_on: date!(2005 / 6 / 6),
eol_on: date!(2008 / 3 / 31),
architectures: cow!(&[
architecture::ALPHA,
architecture::ARM,
architecture::HPPA,
architecture::I386,
architecture::IA64,
architecture::M68K,
architecture::MIPS,
architecture::MIPSEL,
architecture::POWERPC,
architecture::S390,
architecture::SPARC,
]),
};
pub const ETCH: Release = Release {
name: cow!("etch"),
version: cow!("4.0"),
released_on: date!(2007 / 4 / 8),
eol_on: date!(2012 / 2 / 6),
architectures: cow!(&[
architecture::ALPHA,
architecture::AMD64,
architecture::ARM,
architecture::HPPA,
architecture::I386,
architecture::IA64,
architecture::MIPS,
architecture::MIPSEL,
architecture::POWERPC,
architecture::S390,
architecture::SPARC,
]),
};
pub const LENNY: Release = Release {
name: cow!("lenny"),
version: cow!("5.0"),
released_on: date!(2009 / 2 / 14),
eol_on: date!(2012 / 2 / 6),
architectures: cow!(&[
architecture::ALPHA,
architecture::AMD64,
architecture::ARMEL,
architecture::HPPA,
architecture::I386,
architecture::IA64,
architecture::MIPS,
architecture::MIPSEL,
architecture::POWERPC,
architecture::S390,
architecture::SPARC,
]),
};
pub const SQUEEZE: Release = Release {
name: cow!("squeeze"),
version: cow!("6.0"),
released_on: date!(2011 / 2 / 6),
eol_on: date!(2014 / 5 / 31),
architectures: cow!(&[
architecture::AMD64,
architecture::ARMEL,
architecture::I386,
architecture::IA64,
architecture::MIPS,
architecture::MIPSEL,
architecture::POWERPC,
architecture::S390,
architecture::SPARC,
]),
};
pub const WHEEZY: Release = Release {
name: cow!("wheezy"),
version: cow!("7"),
released_on: date!(2013 / 5 / 4),
eol_on: date!(2016 / 4 / 25),
architectures: cow!(&[
architecture::AMD64,
architecture::ARMEL,
architecture::ARMHF,
architecture::I386,
architecture::IA64,
architecture::MIPS,
architecture::MIPSEL,
architecture::POWERPC,
architecture::S390,
architecture::S390X,
architecture::SPARC,
]),
};
pub const JESSIE: Release = Release {
name: cow!("jessie"),
version: cow!("8"),
released_on: date!(2015 / 4 / 25),
eol_on: date!(2018 / 6 / 17),
architectures: cow!(&[
architecture::AMD64,
architecture::ARM64,
architecture::ARMEL,
architecture::ARMHF,
architecture::I386,
architecture::MIPS,
architecture::MIPSEL,
architecture::POWERPC,
architecture::PPC64EL,
architecture::S390X,
]),
};
pub const STRETCH: Release = Release {
name: cow!("stretch"),
version: cow!("9"),
released_on: date!(2017 / 6 / 17),
eol_on: date!(2020 / 7 / 18),
architectures: cow!(&[
architecture::AMD64,
architecture::ARM64,
architecture::ARMEL,
architecture::ARMHF,
architecture::I386,
architecture::MIPS,
architecture::MIPS64EL,
architecture::MIPSEL,
architecture::PPC64EL,
architecture::S390X,
]),
};
pub const BUSTER: Release = Release {
name: cow!("buster"),
version: cow!("10"),
released_on: date!(2019 / 7 / 6),
eol_on: date!(2022 / 9 / 10),
architectures: cow!(&[
architecture::AMD64,
architecture::ARM64,
architecture::ARMEL,
architecture::ARMHF,
architecture::I386,
architecture::MIPS,
architecture::MIPS64EL,
architecture::MIPSEL,
architecture::PPC64EL,
architecture::S390X,
]),
};
pub const BULLSEYE: Release = Release {
name: cow!("bullseye"),
version: cow!("11"),
released_on: date!(2021 / 8 / 14),
eol_on: date!(2024 / 8 / 14),
architectures: cow!(&[
architecture::AMD64,
architecture::ARM64,
architecture::ARMEL,
architecture::ARMHF,
architecture::I386,
architecture::MIPS64EL,
architecture::MIPSEL,
architecture::PPC64EL,
architecture::S390X,
]),
};
pub const BOOKWORM: Release = Release {
name: cow!("bookworm"),
version: cow!("12"),
released_on: date!(2023 / 6 / 10),
eol_on: date!(2026 / 6 / 10),
architectures: cow!(&[
architecture::AMD64,
architecture::ARM64,
architecture::ARMEL,
architecture::ARMHF,
architecture::I386,
architecture::MIPS64EL,
architecture::MIPSEL,
architecture::PPC64EL,
architecture::S390X,
]),
};
pub const TRIXIE: Release = Release {
name: cow!("trixie"),
version: cow!("13"),
released_on: date!(2025 / 8 / 9),
eol_on: date!(2028 / 8 / 9),
architectures: cow!(&[
architecture::AMD64,
architecture::ARM64,
architecture::ARMHF,
architecture::PPC64EL,
architecture::RISCV64,
architecture::S390X,
]),
};
pub const FORKY: Release = Release {
name: cow!("forky"),
version: cow!("14"),
released_on: None,
eol_on: None,
architectures: cow!(&[]),
};
pub const DUKE: Release = Release {
name: cow!("duke"),
version: cow!("15"),
released_on: None,
eol_on: None,
architectures: cow!(&[]),
};
pub const RELEASES: [Release; 20] = [
DUKE, FORKY, TRIXIE, BOOKWORM, BULLSEYE, BUSTER, STRETCH, JESSIE, WHEEZY, SQUEEZE, LENNY, ETCH,
SARGE, WOODY, POTATO, SLINK, HAMM, BO, REX, BUZZ,
];
#[cfg(feature = "chrono")]
mod chrono {
#![cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
const RELEASE_HORIZON: NaiveDate = date!(2025 / 6 / 1).unwrap();
use super::*;
use ::chrono::{NaiveDate, Utc};
impl Release {
pub fn released_on(&self) -> Option<&NaiveDate> {
self.released_on.as_ref()
}
pub fn eol_on(&self) -> Option<&NaiveDate> {
self.eol_on.as_ref()
}
}
pub fn supported_on(date: &NaiveDate) -> Vec<Release> {
RELEASES
.iter()
.filter(|rel| rel.released_on.is_some())
.filter(|rel| match &rel.released_on {
Some(release_date) => release_date < date,
None => true,
})
.filter(|rel| match &rel.eol_on {
Some(eol_date) => date < eol_date,
None => true,
})
.cloned()
.collect()
}
pub fn guess_release_suites_on(date: &NaiveDate) -> Option<[Release; 2]> {
if *date > RELEASE_HORIZON {
return None;
}
let releases = supported_on(date);
let stable = releases.first()?;
let stable_idx = RELEASES.iter().position(|e| e == stable).unwrap();
if stable_idx <= 1 {
return None;
}
let [testing, stable] = RELEASES
.into_iter()
.skip(stable_idx - 1)
.take(2)
.collect::<Vec<_>>()
.try_into()
.ok()?;
Some([testing, stable])
}
pub fn supported() -> Vec<Release> {
let today = Utc::now().naive_utc().date();
supported_on(&today)
}
pub fn supported_architectures_on(date: &NaiveDate) -> Vec<Architecture> {
let mut ret = vec![];
for arch in supported_on(date)
.iter()
.flat_map(|rel| &rel.architectures[..])
{
if ret.contains(arch) {
continue;
}
ret.push(arch.clone());
}
ret
}
pub fn supported_architectures() -> Vec<Architecture> {
let today = Utc::now().naive_utc().date();
supported_architectures_on(&today)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_supported_on() {
let supported_releases = supported_on(&NaiveDate::from_ymd_opt(2023, 7, 1).unwrap());
assert_eq!(2, supported_releases.len());
assert_eq!(vec![BOOKWORM, BULLSEYE], supported_releases);
let supported_releases = supported_on(&NaiveDate::from_ymd_opt(2012, 6, 26).unwrap());
assert_eq!(1, supported_releases.len());
assert_eq!(vec![SQUEEZE], supported_releases);
}
#[test]
fn test_supported_architectures_on() {
let supported_architectures =
supported_architectures_on(&NaiveDate::from_ymd_opt(2023, 7, 1).unwrap());
let mut supported_architectures = supported_architectures
.into_iter()
.map(|arch| arch.to_string())
.collect::<Vec<String>>();
supported_architectures.sort();
assert_eq!(
vec![
"amd64", "arm64", "armel", "armhf", "i386", "mips64el", "mipsel", "ppc64el",
"s390x"
],
supported_architectures
);
}
#[test]
fn test_releases_on() {
assert_eq!(
Some([TRIXIE, BOOKWORM]),
guess_release_suites_on(&NaiveDate::from_ymd_opt(2023, 7, 1).unwrap())
);
assert_eq!(
Some([WHEEZY, SQUEEZE]),
guess_release_suites_on(&NaiveDate::from_ymd_opt(2012, 6, 26).unwrap())
);
assert_eq!(
None,
guess_release_suites_on(&NaiveDate::from_ymd_opt(1980, 6, 26).unwrap())
);
let date_past_horizon = NaiveDate::from_ymd_opt(2025, 6, 2).unwrap();
assert!(
date_past_horizon > RELEASE_HORIZON,
"update this test case after updating RELEASE_HORIZON"
);
assert!(guess_release_suites_on(&date_past_horizon).is_none());
}
}
}
#[cfg(feature = "chrono")]
pub use chrono::{
guess_release_suites_on, supported, supported_architectures, supported_architectures_on,
supported_on,
};