(ALT) Proper default repo's checks and creation

This commit is contained in:
2025-02-22 23:49:18 +03:00
parent 6339b60fc6
commit 93dd6ea520
7 changed files with 162 additions and 80 deletions

View File

@ -392,15 +392,19 @@ pub enum APTRepositoryHandle {
CephSquidNoSubscription,
/// Ceph Squid test repository.
CephSquidTest,
/// Debug info
#[serde(rename = "debuginfo")]
DebugInfo,
/// Classic
#[serde(rename = "classic")]
Classic,
/// GOST crypto
#[serde(rename = "gostcrypto")]
GostCrypto,
/// Classic (for host's architecture)
#[serde(rename = "classic_arch_specific")]
ClassicArchSpecific,
/// Classic (for any architecture)
#[serde(rename = "classic_noarch")]
ClassicNoArch,
/// GOST crypto (for host's architecture)
#[serde(rename = "gostcrypto_arch_specific")]
GostCryptoArchSpecific,
/// GOST crypto (for any architecture)
#[serde(rename = "gostcrypto_noarch")]
GostCryptoNoArch
}
serde_plain::derive_display_from_serialize!(APTRepositoryHandle);

View File

@ -2,10 +2,10 @@ use std::path::{Path, PathBuf};
use anyhow::{format_err, Error};
#[cfg(feature = "alt-linux")]
use crate::repositories::release::ALTBranchID;
#[cfg(not(feature = "alt-linux"))]
use crate::repositories::release::DebianCodename;
#[cfg(feature = "alt-linux")]
use crate::repositories::release::{get_rpm_arch_name, ALTBranchID};
use proxmox_apt_api_types::{
APTRepository, APTRepositoryFile, APTRepositoryFileError, APTRepositoryFileType,
APTRepositoryInfo, APTRepositoryPackageType,
@ -301,11 +301,24 @@ impl APTRepositoryFileImpl for APTRepositoryFile {
if !repo.types.contains(&APTRepositoryPackageType::Deb) {
continue;
}
let mut add_info = |kind: &str, message| {
infos.push(APTRepositoryInfo {
path: path.clone(),
index: n,
property: Some("Suites".to_string()),
kind: kind.to_string(),
message,
})
};
#[cfg(feature = "alt-linux")]
if !repo.types.contains(&APTRepositoryPackageType::Rpm) {
add_info(
"warning",
"Unsupported repo packages type. Alt only have RPMs!".to_string(),
);
continue;
}
#[cfg(not(feature = "alt-linux"))]
let is_security_repo = repo.uris.iter().any(|uri| {
let uri = uri.trim_end_matches('/');
@ -316,7 +329,7 @@ impl APTRepositoryFileImpl for APTRepositoryFile {
"http://security.debian.org" | "https://security.debian.org",
)
});
#[cfg(not(feature = "alt-linux"))]
let require_suffix = match is_security_repo {
#[cfg(not(feature = "alt-linux"))]
@ -325,16 +338,6 @@ impl APTRepositoryFileImpl for APTRepositoryFile {
false => None,
};
let mut add_info = |kind: &str, message| {
infos.push(APTRepositoryInfo {
path: path.clone(),
index: n,
property: Some("Suites".to_string()),
kind: kind.to_string(),
message,
})
};
let message_old = |suite| format!("old suite '{}' configured!", suite);
let message_new =
|suite| format!("suite '{}' should not be used in production!", suite);
@ -344,16 +347,10 @@ impl APTRepositoryFileImpl for APTRepositoryFile {
for suite in repo.suites.iter() {
#[cfg(not(feature = "alt-linux"))]
let (base_suite, suffix) = suite_variant(suite);
#[cfg(feature = "alt-linux")]
let (base_suite, arch) = suite_arch(suite);
#[cfg(feature = "alt-linux")]
if base_suite.to_lowercase().contains("sisyphus") {
add_info("warning", message_new("Sisyphus"))
}
#[cfg(not(feature = "alt-linux"))]
match base_suite {
"oldoldstable" | "oldstable" => {
@ -373,14 +370,13 @@ impl APTRepositoryFileImpl for APTRepositoryFile {
Ok(codename) => codename,
Err(_) => continue,
};
#[cfg(feature = "alt-linux")]
let codename: ALTBranchID = match base_suite.try_into() {
let codename: ALTBranchID = match base_suite.to_lowercase()[..].try_into() {
Ok(codename) => codename,
Err(_) => continue,
};
if codename < current_codename {
add_info("warning", message_old(base_suite));
}
@ -389,10 +385,20 @@ impl APTRepositoryFileImpl for APTRepositoryFile {
if codename > current_codename {
add_info("warning", message_new(base_suite));
}
#[cfg(feature = "alt-linux")]
if arch.is_empty() {
add_info("warning", "repo suite should contain architecture".to_string())
add_info(
"warning",
"repo suite should contain architecture!".to_string(),
)
} else if let Ok(proper_arch) = get_rpm_arch_name() {
if !arch.contains(&proper_arch) && arch != "noarch" {
add_info(
"warning",
"Incorrent architecture name in repo suite!".to_string(),
)
}
}
#[cfg(not(feature = "alt-linux"))]
@ -447,7 +453,6 @@ impl APTRepositoryFileImpl for APTRepositoryFile {
}
}
#[cfg(not(feature = "alt-linux"))]
/// Splits the suite into its base part and variant.
/// Does not expect the base part to contain either `-` or `/`.
@ -462,7 +467,7 @@ fn suite_variant(suite: &str) -> (&str, &str) {
/// Splits the suite into its branch part and arch.
/// Does not expect the base part to contain either `-` or `/`.
fn suite_arch(mut suite: &str) -> (&str, &str) {
if suite.starts_with("ports/") {
if suite.starts_with("ports/") {
// Alt's suites approach is unsystematic :(
suite = suite.strip_prefix("ports/").unwrap();
@ -470,7 +475,7 @@ fn suite_arch(mut suite: &str) -> (&str, &str) {
// Cut off needless part
Some(index) => &suite[index + 1..],
None => suite,
};
};
}
match suite.rfind('/') {
@ -480,10 +485,10 @@ fn suite_arch(mut suite: &str) -> (&str, &str) {
// Cut off needless '/branch' part
Some(index) => &branch_part[0..index],
None => branch_part,
};
};
let arch_part = &suite[n + 1..];
return (branch_part, arch_part)
},
None => (suite, "")
return (branch_part, arch_part);
}
None => (suite, ""),
}
}
}

View File

@ -106,9 +106,10 @@ pub fn standard_repositories(
];
#[cfg(feature = "alt-linux")]
let mut result = vec![
APTStandardRepository::from_handle(APTRepositoryHandle::Classic),
APTStandardRepository::from_handle(APTRepositoryHandle::DebugInfo),
APTStandardRepository::from_handle(APTRepositoryHandle::GostCrypto),
APTStandardRepository::from_handle(APTRepositoryHandle::ClassicArchSpecific),
APTStandardRepository::from_handle(APTRepositoryHandle::ClassicNoArch),
APTStandardRepository::from_handle(APTRepositoryHandle::GostCryptoArchSpecific),
APTStandardRepository::from_handle(APTRepositoryHandle::GostCryptoNoArch),
];
#[cfg(not(feature = "alt-linux"))]

View File

@ -1,7 +1,11 @@
use std::fmt::Display;
use std::io::{BufRead, BufReader};
use anyhow::{bail, format_err, Error};
use anyhow::{anyhow, bail, format_err, Error};
#[cfg(feature = "alt-linux")]
use std::process::Command;
#[cfg(feature = "alt-linux")]
use std::sync::OnceLock;
/// The code names of Debian releases. Does not include `sid`.
#[cfg(not(feature = "alt-linux"))]
@ -193,4 +197,28 @@ pub fn get_current_release_branch_id() -> Result<ALTBranchID, Error> {
}
bail!("unable to parse ALT branch ID from '/etc/os-release'");
}
}
// This static value is computed only once.
#[cfg(feature = "alt-linux")]
static RPM_ARCH: OnceLock<Option<String>> = OnceLock::new();
/// Read the architecture name
#[cfg(feature = "alt-linux")]
pub fn get_rpm_arch_name() -> Result<String, Error> {
RPM_ARCH
.get_or_init(|| {
let output = Command::new("rpm")
.args(&["--eval", "%{_arch}"])
.output()
.ok()?;
if output.status.success() {
let arch = String::from_utf8(output.stdout).ok()?;
Some(arch.trim().to_string())
} else {
None
}
})
.clone()
.ok_or(anyhow!("Failed to execute rpm command"))
}

View File

@ -157,11 +157,14 @@ impl APTRepositoryImpl for APTRepository {
#[cfg(feature = "alt-linux")]
{
// ALT's suites looks like `Sisyphus/noarch` or `p11/branch/x86_64`
let proper_suite = handle.proper_suite(suite);
self.types.contains(&package_type)
&& found_uri
// ALT's suites looks like `Sisyphus/noarch`
&& self.suites.iter().any(|self_suite| self_suite.to_lowercase().starts_with(suite))
&& found_component
&& self
.suites
.iter()
.any(|self_suite| *self_suite == proper_suite)
&& found_component
}
}
@ -172,13 +175,14 @@ impl APTRepositoryImpl for APTRepository {
if host == "proxmox.com" || host.ends_with(".proxmox.com") {
return Some("Proxmox".to_string());
}
#[cfg(not(feature = "alt-linux"))]
if host == "debian.org" || host.ends_with(".debian.org") {
return Some("Debian".to_string());
}
#[cfg(feature = "alt-linux")]
// In ALT we mark everything with 'badge' for now
if !host.is_empty() {
return Some("ALT Linux Team".to_string());
}

View File

@ -1,8 +1,9 @@
#[cfg(feature = "alt-linux")]
use crate::repositories::release::{get_rpm_arch_name, ALTBranchID};
use proxmox_apt_api_types::{
APTRepository, APTRepositoryFileType, APTRepositoryHandle, APTRepositoryPackageType,
APTStandardRepository,
};
pub trait APTStandardRepositoryImpl {
fn from_handle(handle: APTRepositoryHandle) -> APTStandardRepository;
}
@ -25,6 +26,13 @@ pub trait APTRepositoryHandleImpl {
fn name(self) -> String;
/// Get the standard file path for the repository referenced by the handle.
fn path(self, product: &str) -> String;
/// Get the arch-suffix for the repository referenced by the handle.
#[cfg(feature = "alt-linux")]
fn arch_suite_suffix(self) -> String;
/// Get proper suite for given branch
#[cfg(feature = "alt-linux")]
fn proper_suite(self, branch: &str) -> String;
/// Get package type, possible URIs and the component associated with the handle.
///
/// The first URI is the preferred one.
@ -86,15 +94,21 @@ impl APTRepositoryHandleImpl for APTRepositoryHandle {
"This repository contains the Ceph Squid packages before they are moved to the \
main repository."
}
APTRepositoryHandle::Classic => {
"The repository contains binary executables and libraries."
APTRepositoryHandle::ClassicArchSpecific => {
"The repository contains binary executables and libraries, \
specific for node's architecture."
}
APTRepositoryHandle::DebugInfo => {
"The repository contains debugging information for binary \
executables and libraries."
}
APTRepositoryHandle::GostCrypto => {
APTRepositoryHandle::ClassicNoArch => {
"The repository contains binary executables and libraries \
that are architecture-independent."
}
APTRepositoryHandle::GostCryptoArchSpecific => {
"The repository contains binary executables and libraries \
with GOST cryptography, specific for node's architecture."
}
APTRepositoryHandle::GostCryptoNoArch => {
"The repository contains architecture-independent executables and libraries \
with GOST cryptography."
}
}
@ -116,9 +130,10 @@ impl APTRepositoryHandleImpl for APTRepositoryHandle {
APTRepositoryHandle::CephSquidNoSubscription => "Ceph Squid No-Subscription",
APTRepositoryHandle::CephSquidTest => "Ceph Squid Test",
APTRepositoryHandle::Classic => "classic",
APTRepositoryHandle::DebugInfo => "debuginfo",
APTRepositoryHandle::GostCrypto => "gostcrypto",
APTRepositoryHandle::ClassicArchSpecific => "Classic (architecture-dependent)",
APTRepositoryHandle::ClassicNoArch => "Classic (architecture-independent)",
APTRepositoryHandle::GostCryptoArchSpecific => "GostCrypto (architecture-dependent)",
APTRepositoryHandle::GostCryptoNoArch => "GostCrypto (architecture-independent)",
}
.to_string()
}
@ -139,9 +154,10 @@ impl APTRepositoryHandleImpl for APTRepositoryHandle {
| APTRepositoryHandle::CephSquidEnterprise
| APTRepositoryHandle::CephSquidNoSubscription
| APTRepositoryHandle::CephSquidTest => "/etc/apt/sources.list.d/ceph.list".to_string(),
APTRepositoryHandle::Classic
| APTRepositoryHandle::DebugInfo
| APTRepositoryHandle::GostCrypto => "/etc/apt/sources.list".to_string(),
APTRepositoryHandle::ClassicArchSpecific
| APTRepositoryHandle::ClassicNoArch
| APTRepositoryHandle::GostCryptoArchSpecific
| APTRepositoryHandle::GostCryptoNoArch => "/etc/apt/sources.list".to_string(),
}
}
@ -225,7 +241,7 @@ impl APTRepositoryHandleImpl for APTRepositoryHandle {
vec!["http://download.proxmox.com/debian/ceph-squid".to_string()],
"test".to_string(),
),
APTRepositoryHandle::Classic => (
APTRepositoryHandle::ClassicArchSpecific | APTRepositoryHandle::ClassicNoArch => (
APTRepositoryPackageType::Rpm,
vec![
"http://ftp.altlinux.org/pub/distributions/ALTLinux".to_string(),
@ -234,16 +250,13 @@ impl APTRepositoryHandleImpl for APTRepositoryHandle {
],
"classic".to_string(),
),
APTRepositoryHandle::DebugInfo => (
APTRepositoryPackageType::Rpm,
vec!["http://ftp.altlinux.org/pub/distributions/ALTLinux".to_string()],
"debuginfo".to_string(),
),
APTRepositoryHandle::GostCrypto => (
APTRepositoryPackageType::Rpm,
vec!["http://ftp.altlinux.org/pub/distributions/ALTLinux".to_string()],
"gostcrypto".to_string(),
),
APTRepositoryHandle::GostCryptoArchSpecific | APTRepositoryHandle::GostCryptoNoArch => {
(
APTRepositoryPackageType::Rpm,
vec!["http://ftp.altlinux.org/pub/distributions/ALTLinux".to_string()],
"gostcrypto".to_string(),
)
}
}
}
@ -253,7 +266,10 @@ impl APTRepositoryHandleImpl for APTRepositoryHandle {
APTRepository {
types: vec![package_type],
uris: vec![uris.into_iter().next().unwrap()],
#[cfg(not(feature = "alt-linux"))]
suites: vec![suite.to_string()],
#[cfg(feature = "alt-linux")]
suites: vec![self.proper_suite(suite)],
components: vec![component],
options: vec![],
comment: String::new(),
@ -261,4 +277,29 @@ impl APTRepositoryHandleImpl for APTRepositoryHandle {
enabled: true,
}
}
#[cfg(feature = "alt-linux")]
fn arch_suite_suffix(self) -> String {
match self {
APTRepositoryHandle::ClassicArchSpecific
| APTRepositoryHandle::GostCryptoArchSpecific => {
get_rpm_arch_name().unwrap_or("noarch".to_string())
}
APTRepositoryHandle::ClassicNoArch | APTRepositoryHandle::GostCryptoNoArch => {
"noarch".to_string()
}
_ => unreachable!(),
}
}
#[cfg(feature = "alt-linux")]
fn proper_suite(self, branch: &str) -> String {
let branch_id: ALTBranchID = branch.try_into().unwrap_or(ALTBranchID::Sisyphus);
match branch_id {
ALTBranchID::Sisyphus => {
format!("Sisyphus/{}", self.arch_suite_suffix())
}
_ => format!("{}/branch/{}", branch, self.arch_suite_suffix()),
}
}
}

View File

@ -770,7 +770,6 @@ fn test_standard_repositories() -> Result<(), Error> {
let mut expected = vec![
APTStandardRepository::from_handle(APTRepositoryHandle::Classic),
APTStandardRepository::from_handle(APTRepositoryHandle::DebugInfo),
APTStandardRepository::from_handle(APTRepositoryHandle::GostCrypto),
];