From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id DAF1569FED for ; Thu, 29 Jul 2021 14:26:59 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 37CA72EE41 for ; Thu, 29 Jul 2021 14:26:04 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id 016842EE2C for ; Thu, 29 Jul 2021 14:26:03 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id CFA004101F for ; Thu, 29 Jul 2021 14:26:02 +0200 (CEST) From: Fabian Ebner To: pve-devel@lists.proxmox.com Date: Thu, 29 Jul 2021 14:25:52 +0200 Message-Id: <20210729122554.148980-6-f.ebner@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210729122554.148980-1-f.ebner@proxmox.com> References: <20210729122554.148980-1-f.ebner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.456 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [PATCH proxmox-apt 5/5] add type DebianCodename X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 29 Jul 2021 12:26:59 -0000 which allows to get rid of an possible error with check_suites, and easily detect unexpected values with get_current_release_codename. The check_repos function needs to be adapted, since the type does not include suite names like oldstable,experimental,etc. Signed-off-by: Fabian Ebner --- src/repositories/file.rs | 73 ++++++++++++------------- src/repositories/mod.rs | 18 +++---- src/repositories/release.rs | 103 ++++++++++++++++++++++++++++-------- tests/repositories.rs | 18 +++---- 4 files changed, 133 insertions(+), 79 deletions(-) diff --git a/src/repositories/file.rs b/src/repositories/file.rs index fe994f7..3df59db 100644 --- a/src/repositories/file.rs +++ b/src/repositories/file.rs @@ -1,11 +1,11 @@ -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::fmt::Display; use std::path::{Path, PathBuf}; -use anyhow::{bail, format_err, Error}; +use anyhow::{format_err, Error}; use serde::{Deserialize, Serialize}; -use crate::repositories::release::DEBIAN_SUITES; +use crate::repositories::release::DebianCodename; use crate::repositories::repository::{ APTRepository, APTRepositoryFileType, APTRepositoryPackageType, }; @@ -300,7 +300,7 @@ impl APTRepositoryFile { /// Checks if old or unstable suites are configured and also that the /// `stable` keyword is not used. - pub fn check_suites(&self, current_suite: &str) -> Result, Error> { + pub fn check_suites(&self, current_codename: DebianCodename) -> Vec { let mut infos = vec![]; for (n, repo) in self.repositories.iter().enumerate() { @@ -308,60 +308,55 @@ impl APTRepositoryFile { continue; } - let mut add_info = |kind, message| { + let mut add_info = |kind: &str, message| { infos.push(APTRepositoryInfo { path: self.path.clone(), index: n, property: Some("Suites".to_string()), - kind, + kind: kind.to_string(), message, }) }; - let current_index = match DEBIAN_SUITES - .iter() - .position(|&suite| suite == current_suite) - { - Some(index) => index, - None => bail!("unknown release {}", current_suite), - }; + let message_old = |suite| format!("old suite '{}' configured!", suite); + let message_new = + |suite| format!("suite '{}' should not be used in production!", suite); + let message_stable = "use the name of the stable distribution instead of 'stable'!"; for suite in repo.suites.iter() { let base_suite = suite_variant(suite).0; - if base_suite == "stable" { - add_info( - "warning".to_string(), - "use the name of the stable distribution instead of 'stable'!".to_string(), - ); - } - - if let Some(n) = DEBIAN_SUITES.iter().position(|&suite| suite == base_suite) { - if n < current_index { - add_info( - "warning".to_string(), - format!("old suite '{}' configured!", base_suite), - ); + match base_suite { + "oldoldstable" | "oldstable" => { + add_info("warning", message_old(base_suite)); } - - if n == current_index + 1 { - add_info( - "ignore-pre-upgrade-warning".to_string(), - format!("suite '{}' should not be used in production!", base_suite), - ); + "testing" | "unstable" | "experimental" | "sid" => { + add_info("warning", message_new(base_suite)); } - - if n > current_index + 1 { - add_info( - "warning".to_string(), - format!("suite '{}' should not be used in production!", base_suite), - ); + "stable" => { + add_info("warning", message_stable.to_string()); } + _ => (), + }; + + let codename: DebianCodename = match base_suite.try_into() { + Ok(codename) => codename, + Err(_) => continue, + }; + + if codename < current_codename { + add_info("warning", message_old(base_suite)); + } + + if Some(codename) == current_codename.next() { + add_info("ignore-pre-upgrade-warning", message_new(base_suite)); + } else if codename > current_codename { + add_info("warning", message_new(base_suite)); } } } - Ok(infos) + infos } /// Checks for official URIs. diff --git a/src/repositories/mod.rs b/src/repositories/mod.rs index 8f5500e..88b515d 100644 --- a/src/repositories/mod.rs +++ b/src/repositories/mod.rs @@ -12,7 +12,7 @@ mod file; pub use file::{APTRepositoryFile, APTRepositoryFileError, APTRepositoryInfo}; mod release; -pub use release::get_current_release_codename; +pub use release::{get_current_release_codename, DebianCodename}; mod standard; pub use standard::{APTRepositoryHandle, APTStandardRepository}; @@ -51,25 +51,25 @@ fn common_digest(files: &[APTRepositoryFile]) -> [u8; 32] { /// `badge` for official URIs. pub fn check_repositories( files: &[APTRepositoryFile], - current_suite: &str, -) -> Result, Error> { + current_suite: DebianCodename, +) -> Vec { let mut infos = vec![]; for file in files.iter() { - infos.append(&mut file.check_suites(current_suite)?); + infos.append(&mut file.check_suites(current_suite)); infos.append(&mut file.check_uris()); } - Ok(infos) + infos } /// Get the repository associated to the handle and the path where it is usually configured. pub fn get_standard_repository( handle: APTRepositoryHandle, product: &str, - suite: &str, + suite: DebianCodename, ) -> (APTRepository, String) { - let repo = handle.to_repository(product, &suite); + let repo = handle.to_repository(product, &suite.to_string()); let path = handle.path(product); (repo, path) @@ -80,7 +80,7 @@ pub fn get_standard_repository( pub fn standard_repositories( files: &[APTRepositoryFile], product: &str, - suite: &str, + suite: DebianCodename, ) -> Vec { let mut result = vec![ APTStandardRepository::from(APTRepositoryHandle::Enterprise), @@ -104,7 +104,7 @@ pub fn standard_repositories( continue; } - if repo.is_referenced_repository(entry.handle, product, suite) { + if repo.is_referenced_repository(entry.handle, product, &suite.to_string()) { entry.status = Some(repo.enabled); } } diff --git a/src/repositories/release.rs b/src/repositories/release.rs index 688f038..dbbc699 100644 --- a/src/repositories/release.rs +++ b/src/repositories/release.rs @@ -1,29 +1,88 @@ +use std::convert::{TryFrom, TryInto}; +use std::fmt::Display; +use std::io::{BufRead, BufReader}; + use anyhow::{bail, format_err, Error}; -use std::io::{BufRead, BufReader}; +/// The code names of Debian releases. Does not include `sid`. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum DebianCodename { + Lenny = 5, + Squeeze, + Wheezy, + Jessie, + Stretch, + Buster, + Bullseye, + Bookworm, + Trixie, +} -/// The suites of Debian releases, ordered chronologically, with variable releases -/// like 'oldstable' and 'testing' ordered at the extremes. Does not include 'stable'. -pub const DEBIAN_SUITES: [&str; 15] = [ - "oldoldstable", - "oldstable", - "lenny", - "squeeze", - "wheezy", - "jessie", - "stretch", - "buster", - "bullseye", - "bookworm", - "trixie", - "sid", - "testing", - "unstable", - "experimental", -]; +impl DebianCodename { + pub fn next(&self) -> Option { + match (*self as u8 + 1).try_into() { + Ok(codename) => Some(codename), + Err(_) => None, + } + } +} + +impl TryFrom<&str> for DebianCodename { + type Error = Error; + + fn try_from(string: &str) -> Result { + match string { + "lenny" => Ok(DebianCodename::Lenny), + "squeeze" => Ok(DebianCodename::Squeeze), + "wheezy" => Ok(DebianCodename::Wheezy), + "jessie" => Ok(DebianCodename::Jessie), + "stretch" => Ok(DebianCodename::Stretch), + "buster" => Ok(DebianCodename::Buster), + "bullseye" => Ok(DebianCodename::Bullseye), + "bookworm" => Ok(DebianCodename::Bookworm), + "trixie" => Ok(DebianCodename::Trixie), + _ => bail!("unknown Debian code name '{}'", string), + } + } +} + +impl TryFrom for DebianCodename { + type Error = Error; + + fn try_from(number: u8) -> Result { + match number { + 5 => Ok(DebianCodename::Lenny), + 6 => Ok(DebianCodename::Squeeze), + 7 => Ok(DebianCodename::Wheezy), + 8 => Ok(DebianCodename::Jessie), + 9 => Ok(DebianCodename::Stretch), + 10 => Ok(DebianCodename::Buster), + 11 => Ok(DebianCodename::Bullseye), + 12 => Ok(DebianCodename::Bookworm), + 13 => Ok(DebianCodename::Trixie), + _ => bail!("unknown Debian release number '{}'", number), + } + } +} + +impl Display for DebianCodename { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DebianCodename::Lenny => write!(f, "lenny"), + DebianCodename::Squeeze => write!(f, "squeeze"), + DebianCodename::Wheezy => write!(f, "wheezy"), + DebianCodename::Jessie => write!(f, "jessie"), + DebianCodename::Stretch => write!(f, "stretch"), + DebianCodename::Buster => write!(f, "buster"), + DebianCodename::Bullseye => write!(f, "bullseye"), + DebianCodename::Bookworm => write!(f, "bookworm"), + DebianCodename::Trixie => write!(f, "trixie"), + } + } +} /// Read the `VERSION_CODENAME` from `/etc/os-release`. -pub fn get_current_release_codename() -> Result { +pub fn get_current_release_codename() -> Result { let raw = std::fs::read("/etc/os-release") .map_err(|err| format_err!("unable to read '/etc/os-release' - {}", err))?; @@ -34,7 +93,7 @@ pub fn get_current_release_codename() -> Result { if let Some(codename) = line.strip_prefix("VERSION_CODENAME=") { let codename = codename.trim_matches(&['"', '\''][..]); - return Ok(codename.to_string()); + return codename.try_into(); } } diff --git a/tests/repositories.rs b/tests/repositories.rs index a9a7b96..d79ea72 100644 --- a/tests/repositories.rs +++ b/tests/repositories.rs @@ -6,7 +6,7 @@ use proxmox_apt::config::APTConfig; use proxmox_apt::repositories::{ check_repositories, get_current_release_codename, standard_repositories, APTRepositoryFile, - APTRepositoryHandle, APTRepositoryInfo, APTStandardRepository, + APTRepositoryHandle, APTRepositoryInfo, APTStandardRepository, DebianCodename, }; #[test] @@ -187,7 +187,7 @@ fn test_check_repositories() -> Result<(), Error> { let mut file = APTRepositoryFile::new(&absolute_suite_list)?.unwrap(); file.parse()?; - let infos = check_repositories(&vec![file], "bullseye")?; + let infos = check_repositories(&vec![file], DebianCodename::Bullseye); assert_eq!(infos.is_empty(), true); let pve_list = read_dir.join("pve.list"); @@ -212,7 +212,7 @@ fn test_check_repositories() -> Result<(), Error> { } expected_infos.sort(); - let mut infos = check_repositories(&vec![file], "bullseye")?; + let mut infos = check_repositories(&vec![file], DebianCodename::Bullseye); infos.sort(); assert_eq!(infos, expected_infos); @@ -278,7 +278,7 @@ fn test_check_repositories() -> Result<(), Error> { } expected_infos.sort(); - let mut infos = check_repositories(&vec![file], "bullseye")?; + let mut infos = check_repositories(&vec![file], DebianCodename::Bullseye); infos.sort(); assert_eq!(infos, expected_infos); @@ -337,7 +337,7 @@ fn test_standard_repositories() -> Result<(), Error> { let mut file = APTRepositoryFile::new(&absolute_suite_list)?.unwrap(); file.parse()?; - let std_repos = standard_repositories(&vec![file], "pve", "bullseye"); + let std_repos = standard_repositories(&vec![file], "pve", DebianCodename::Bullseye); assert_eq!(std_repos, expected); @@ -347,14 +347,14 @@ fn test_standard_repositories() -> Result<(), Error> { let file_vec = vec![file]; - let std_repos = standard_repositories(&file_vec, "pbs", "bullseye"); + let std_repos = standard_repositories(&file_vec, "pbs", DebianCodename::Bullseye); assert_eq!(&std_repos, &expected[0..=2]); expected[0].status = Some(false); expected[1].status = Some(true); - let std_repos = standard_repositories(&file_vec, "pve", "bullseye"); + let std_repos = standard_repositories(&file_vec, "pve", DebianCodename::Bullseye); assert_eq!(std_repos, expected); @@ -368,7 +368,7 @@ fn test_standard_repositories() -> Result<(), Error> { expected[1].status = Some(true); expected[2].status = Some(false); - let std_repos = standard_repositories(&file_vec, "pve", "bullseye"); + let std_repos = standard_repositories(&file_vec, "pve", DebianCodename::Bullseye); assert_eq!(std_repos, expected); @@ -379,7 +379,7 @@ fn test_standard_repositories() -> Result<(), Error> { fn test_get_current_release_codename() -> Result<(), Error> { let codename = get_current_release_codename()?; - assert_eq!(&codename, "bullseye"); + assert!(codename == DebianCodename::Bullseye); Ok(()) } -- 2.30.2