context: copy symlinks as symlinks and improve error messages

This commit is contained in:
2026-07-17 10:12:46 +02:00
parent 2b27b7b06e
commit c4b59a4376
11 changed files with 382 additions and 54 deletions
+67 -10
View File
@@ -110,11 +110,30 @@ fn parse_series_csv(content: &str) -> Result<Vec<SeriesInformation>, Box<dyn Err
Ok(series_info_list)
}
/// List the distributions known to pkh (e.g. "debian", "ubuntu")
pub fn supported_dists() -> Vec<String> {
DATA.dist.keys().cloned().collect()
}
/// Get time-ordered list of series information for a distribution, development series first
pub async fn get_ordered_series(dist: &str) -> Result<Vec<SeriesInformation>, Box<dyn Error>> {
let series_info = &DATA.dist.get(dist).unwrap().series;
let dist_data = DATA.dist.get(dist).ok_or_else(|| {
format!(
"Unknown distribution '{}'. Supported distributions are: {}.",
dist,
supported_dists().join(", ")
)
})?;
let series_info = &dist_data.series;
let content = if Path::new(series_info.local.as_str()).exists() {
std::fs::read_to_string(format!("/usr/share/distro-info/{dist}.csv"))?
std::fs::read_to_string(format!("/usr/share/distro-info/{dist}.csv"))
.map_err(|e| {
format!(
"Failed to read distribution series data for '{dist}' \
from '{}': {}. The 'distro-info' package provides these CSV files.",
series_info.local, e
)
})?
} else {
reqwest::get(series_info.network.as_str())
.await?
@@ -188,13 +207,20 @@ pub async fn get_dist_from_series(series: &str) -> Result<String, Box<dyn Error>
/// Get the package pockets available for a given distribution
///
/// Example: get_dist_pockets(ubuntu) => ["proposed", "updates", ""]
pub fn get_dist_pockets(dist: &str) -> Vec<String> {
let mut pockets = DATA.dist.get(dist).unwrap().pockets.clone();
pub fn get_dist_pockets(dist: &str) -> Result<Vec<String>, Box<dyn Error>> {
let dist_data = DATA.dist.get(dist).ok_or_else(|| {
format!(
"Unknown distribution '{}'. Supported distributions are: {}.",
dist,
supported_dists().join(", ")
)
})?;
let mut pockets = dist_data.pockets.clone();
// Explicitely add 'main' pocket, which is just the empty string
pockets.push("".to_string());
pockets
Ok(pockets)
}
/// Get the sources URL for a distribution, series, pocket, and component
@@ -210,8 +236,17 @@ pub fn get_sources_url(base_url: &str, series: &str, pocket: &str, component: &s
/// Get the archive base URL for a distribution
///
/// Example: ubuntu => http://archive.ubuntu.com/ubuntu
pub fn get_base_url(dist: &str) -> String {
DATA.dist.get(dist).unwrap().base_url.clone()
pub fn get_base_url(dist: &str) -> Result<String, Box<dyn Error>> {
DATA.dist.get(dist)
.map(|d| d.base_url.clone())
.ok_or_else(|| {
format!(
"Unknown distribution '{}'. Supported distributions are: {}.",
dist,
supported_dists().join(", ")
)
.into()
})
}
/// Obtain the URLs for the archive keyrings of a distribution series
@@ -246,7 +281,15 @@ pub async fn get_keyring_urls(series: &str) -> Result<Vec<String>, Box<dyn Error
Ok(urls)
}
} else {
let series_num = get_debian_series_number(series).await?.unwrap();
let series_num = get_debian_series_number(series)
.await?
.ok_or_else(|| {
format!(
"Could not determine the version number for Debian series '{series}'. \
Make sure the 'distro-info' package is installed, which provides the \
series CSV data used to map series names to version numbers."
)
})?;
// Replace {series_num} placeholder with the actual series number
Ok(vec![
dist_data
@@ -297,9 +340,23 @@ pub async fn get_components(
/// Map a Debian series name to its version number
pub async fn get_debian_series_number(series: &str) -> Result<Option<String>, Box<dyn Error>> {
let series_info = &DATA.dist.get("debian").unwrap().series;
let dist_data = DATA.dist.get("debian").ok_or_else(|| {
format!(
"Debian distribution data is missing from the built-in configuration. \
This is a bug; supported distributions are: {}.",
supported_dists().join(", ")
)
})?;
let series_info = &dist_data.series;
let content = if Path::new(series_info.local.as_str()).exists() {
std::fs::read_to_string(series_info.local.as_str())?
std::fs::read_to_string(series_info.local.as_str())
.map_err(|e| {
format!(
"Failed to read Debian series data from '{}': {}. \
The 'distro-info' package provides this file.",
series_info.local, e
)
})?
} else {
reqwest::get(series_info.network.as_str())
.await?