deb: cross uses new apt sources parser
This commit is contained in:
@@ -16,8 +16,8 @@ pub struct SourceEntry {
|
||||
pub architectures: Vec<String>,
|
||||
/// Source URI
|
||||
pub uri: String,
|
||||
/// Source suite (series-pocket)
|
||||
pub suite: String,
|
||||
/// Source suites (series-pocket)
|
||||
pub suite: Vec<String>,
|
||||
}
|
||||
|
||||
impl SourceEntry {
|
||||
@@ -28,7 +28,7 @@ impl SourceEntry {
|
||||
components: Vec::new(),
|
||||
architectures: Vec::new(),
|
||||
uri: String::new(),
|
||||
suite: String::new(),
|
||||
suite: Vec::new(),
|
||||
};
|
||||
|
||||
for line in data.lines() {
|
||||
@@ -55,7 +55,10 @@ impl SourceEntry {
|
||||
// We only care about deb types
|
||||
}
|
||||
"URIs" => current_entry.uri = value.to_string(),
|
||||
"Suites" => current_entry.suite = value.to_string(),
|
||||
"Suites" => {
|
||||
current_entry.suite =
|
||||
value.split_whitespace().map(|s| s.to_string()).collect();
|
||||
}
|
||||
"Components" => {
|
||||
current_entry.components =
|
||||
value.split_whitespace().map(|s| s.to_string()).collect();
|
||||
@@ -123,7 +126,7 @@ impl SourceEntry {
|
||||
}
|
||||
|
||||
let uri = parts[1].to_string();
|
||||
let suite = parts[2].to_string();
|
||||
let suite = vec![parts[2].to_string()];
|
||||
let components: Vec<String> = parts[3..].iter().map(|&s| s.to_string()).collect();
|
||||
|
||||
Some(SourceEntry {
|
||||
@@ -139,26 +142,31 @@ impl SourceEntry {
|
||||
pub fn to_legacy(&self) -> String {
|
||||
let mut result = String::new();
|
||||
|
||||
// Start with "deb" type
|
||||
result.push_str("deb");
|
||||
// Legacy entries contain one suite per line
|
||||
for suite in &self.suite {
|
||||
// Start with "deb" type
|
||||
result.push_str("deb");
|
||||
|
||||
// Add architectures if present
|
||||
if !self.architectures.is_empty() {
|
||||
result.push_str(" [arch=");
|
||||
result.push_str(&self.architectures.join(","));
|
||||
result.push(']');
|
||||
}
|
||||
// Add architectures if present
|
||||
if !self.architectures.is_empty() {
|
||||
result.push_str(" [arch=");
|
||||
result.push_str(&self.architectures.join(","));
|
||||
result.push(']');
|
||||
}
|
||||
|
||||
// Add URI and suite
|
||||
result.push(' ');
|
||||
result.push_str(&self.uri);
|
||||
result.push(' ');
|
||||
result.push_str(&self.suite);
|
||||
|
||||
// Add components
|
||||
if !self.components.is_empty() {
|
||||
// Add URI and suite
|
||||
result.push(' ');
|
||||
result.push_str(&self.components.join(" "));
|
||||
result.push_str(&self.uri);
|
||||
result.push(' ');
|
||||
result.push_str(suite);
|
||||
|
||||
// Add components
|
||||
if !self.components.is_empty() {
|
||||
result.push(' ');
|
||||
result.push_str(&self.components.join(" "));
|
||||
}
|
||||
|
||||
result.push('\n');
|
||||
}
|
||||
|
||||
result
|
||||
@@ -275,12 +283,17 @@ mod tests {
|
||||
assert_eq!(sources.len(), 3);
|
||||
assert_eq!(sources[0].uri, "http://fr.archive.ubuntu.com/ubuntu/");
|
||||
assert_eq!(sources[0].architectures, vec!["amd64"]);
|
||||
assert_eq!(
|
||||
sources[0].suite,
|
||||
vec!["questing", "questing-updates", "questing-backports"]
|
||||
);
|
||||
assert_eq!(
|
||||
sources[0].components,
|
||||
vec!["main", "restricted", "universe", "multiverse"]
|
||||
);
|
||||
assert_eq!(sources[1].uri, "http://security.ubuntu.com/ubuntu/");
|
||||
assert_eq!(sources[1].architectures, vec!["amd64"]);
|
||||
assert_eq!(sources[1].suite, vec!["questing-security"]);
|
||||
assert_eq!(
|
||||
sources[1].components,
|
||||
vec!["main", "restricted", "universe", "multiverse"]
|
||||
@@ -288,6 +301,10 @@ mod tests {
|
||||
assert_eq!(sources[2].uri, "http://ports.ubuntu.com/ubuntu-ports/");
|
||||
assert_eq!(sources[2].architectures.len(), 1);
|
||||
assert_eq!(sources[2].architectures, vec!["riscv64"]);
|
||||
assert_eq!(
|
||||
sources[2].suite,
|
||||
vec!["questing", "questing-updates", "questing-backports"]
|
||||
);
|
||||
assert_eq!(
|
||||
sources[2].components,
|
||||
vec!["main", "restricted", "universe", "multiverse"]
|
||||
@@ -305,15 +322,15 @@ mod tests {
|
||||
let sources = parse_legacy(legacy);
|
||||
assert_eq!(sources.len(), 3);
|
||||
assert_eq!(sources[0].uri, "http://archive.ubuntu.com/ubuntu");
|
||||
assert_eq!(sources[0].suite, "resolute");
|
||||
assert_eq!(sources[0].suite, vec!["resolute"]);
|
||||
assert_eq!(sources[0].components, vec!["main", "universe"]);
|
||||
assert_eq!(sources[0].architectures, vec!["amd64"]);
|
||||
assert_eq!(sources[1].uri, "http://archive.ubuntu.com/ubuntu");
|
||||
assert_eq!(sources[1].suite, "resolute-updates");
|
||||
assert_eq!(sources[1].suite, vec!["resolute-updates"]);
|
||||
assert_eq!(sources[1].components, vec!["main"]);
|
||||
assert_eq!(sources[1].architectures, vec!["amd64", "i386"]);
|
||||
assert_eq!(sources[2].uri, "http://security.ubuntu.com/ubuntu");
|
||||
assert_eq!(sources[2].suite, "resolute-security");
|
||||
assert_eq!(sources[2].suite, vec!["resolute-security"]);
|
||||
assert_eq!(sources[2].components, vec!["main"]);
|
||||
}
|
||||
}
|
||||
|
||||
218
src/deb/cross.rs
218
src/deb/cross.rs
@@ -51,145 +51,99 @@ pub fn ensure_repositories(arch: &str, series: &str) -> Result<(), Box<dyn Error
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Handle DEB822 format (Ubuntu 24.04+)
|
||||
// Load existing sources
|
||||
let mut sources = crate::apt::sources::load(Some(ctx.clone()))?;
|
||||
|
||||
// Ensure all components are enabled for the primary architecture
|
||||
for source in &mut sources {
|
||||
if source.uri.contains("archive.ubuntu.com") || source.uri.contains("security.ubuntu.com") {
|
||||
// Scope to local_arch if not already scoped
|
||||
if source.architectures.is_empty() {
|
||||
source.architectures.push(local_arch.clone());
|
||||
}
|
||||
|
||||
// Ensure all components are present
|
||||
let required_components = ["main", "restricted", "universe", "multiverse"];
|
||||
for &comp in &required_components {
|
||||
if !source.components.contains(&comp.to_string()) {
|
||||
source.components.push(comp.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure all suites (pockets) are enabled, excluding 'proposed'
|
||||
let required_suites = [
|
||||
series.to_string(),
|
||||
format!("{}-updates", series),
|
||||
format!("{}-backports", series),
|
||||
format!("{}-security", series),
|
||||
];
|
||||
for suite in required_suites {
|
||||
if !source.suite.contains(&suite) {
|
||||
source.suite.push(suite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if ports repository already exists for the target architecture
|
||||
let has_ports = sources
|
||||
.iter()
|
||||
.any(|s| s.uri.contains("ports.ubuntu.com") && s.architectures.contains(&arch.to_string()));
|
||||
|
||||
if !has_ports {
|
||||
// Add ports repository for the target architecture
|
||||
let ports_entry = crate::apt::sources::SourceEntry {
|
||||
enabled: true,
|
||||
components: vec![
|
||||
"main".to_string(),
|
||||
"restricted".to_string(),
|
||||
"universe".to_string(),
|
||||
"multiverse".to_string(),
|
||||
],
|
||||
architectures: vec![arch.to_string()],
|
||||
uri: "http://ports.ubuntu.com/ubuntu-ports".to_string(),
|
||||
suite: vec![
|
||||
format!("{series}"),
|
||||
format!("{series}-updates"),
|
||||
format!("{series}-backports"),
|
||||
format!("{series}-security"),
|
||||
],
|
||||
};
|
||||
sources.push(ports_entry);
|
||||
}
|
||||
|
||||
// Save the updated sources
|
||||
// Try to save in DEB822 format first, fall back to legacy format
|
||||
let deb822_path = "/etc/apt/sources.list.d/ubuntu.sources";
|
||||
let has_deb822 = ctx
|
||||
if ctx
|
||||
.command("test")
|
||||
.arg("-f")
|
||||
.arg(deb822_path)
|
||||
.status()?
|
||||
.success();
|
||||
|
||||
if has_deb822 {
|
||||
ensure_repositories_deb822(&ctx, arch, &local_arch, series, deb822_path)?;
|
||||
} else {
|
||||
ensure_repositories_legacy(&ctx, arch, &local_arch, series, "/etc/apt/sources.list")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ensure_repositories_deb822(
|
||||
ctx: &context::Context,
|
||||
arch: &str,
|
||||
local_arch: &str,
|
||||
series: &str,
|
||||
deb822_path: &str,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
// Scope existing to local_arch if not already scoped
|
||||
ctx.command("sed")
|
||||
.arg("-i")
|
||||
.arg(format!("/URIs:.*\\(archive\\|security\\)\\.ubuntu\\.com/ {{ n; /^Architectures:/ ! i Architectures: {} }}", local_arch))
|
||||
.arg(deb822_path)
|
||||
.status()?;
|
||||
|
||||
// Ensure all components are enabled for the primary architecture
|
||||
ctx.command("sed")
|
||||
.arg("-i")
|
||||
.arg("/URIs:.*\\(archive\\|security\\)\\.ubuntu\\.com/,/Components:/ s/^Components:.*/Components: main restricted universe multiverse/")
|
||||
.arg(deb822_path)
|
||||
.status()?;
|
||||
|
||||
// Ensure all suites (pockets) are enabled for the primary architecture
|
||||
// Excluding 'proposed' as it contains unstable software
|
||||
let suites = format!("{series} {series}-updates {series}-backports {series}-security");
|
||||
ctx.command("sed")
|
||||
.arg("-i")
|
||||
.arg(format!(
|
||||
"/URIs:.*\\(archive\\|security\\)\\.ubuntu\\.com/,/Suites:/ s/^Suites:.*/Suites: {}/",
|
||||
suites
|
||||
))
|
||||
.arg(deb822_path)
|
||||
.status()?;
|
||||
|
||||
// Add ports if not already present
|
||||
let has_ports = ctx
|
||||
.command("grep")
|
||||
.arg("-q")
|
||||
.arg("ports.ubuntu.com")
|
||||
.arg(deb822_path)
|
||||
.status()?
|
||||
.success();
|
||||
|
||||
if !has_ports {
|
||||
let ports_block = format!(
|
||||
"\nTypes: deb\nURIs: http://ports.ubuntu.com/ubuntu-ports\nSuites: {series} {series}-updates {series}-backports {series}-security\nComponents: main restricted universe multiverse\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\nArchitectures: {arch}\n"
|
||||
);
|
||||
ctx.command("sh")
|
||||
.arg("-c")
|
||||
.arg(format!("echo '{}' >> {}", ports_block, deb822_path))
|
||||
.status()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ensure_repositories_legacy(
|
||||
ctx: &context::Context,
|
||||
arch: &str,
|
||||
local_arch: &str,
|
||||
series: &str,
|
||||
sources_path: &str,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
// Scope archive.ubuntu.com and security.ubuntu.com to local_arch if not already scoped
|
||||
ctx.command("sed")
|
||||
.arg("-i")
|
||||
.arg(format!(
|
||||
r"/archive.ubuntu.com\|security.ubuntu.com/ {{ /arch=/ ! {{ /^deb \[/ ! s/^deb /deb [arch={}] /; /^deb \[/ s/^deb \[\([^]]*\)\]/deb [arch={} \1]/ }} }}",
|
||||
local_arch, local_arch
|
||||
))
|
||||
.arg(sources_path)
|
||||
.status()?;
|
||||
|
||||
// Ensure all components (main restricted universe multiverse) are present for all archive/security lines
|
||||
ctx.command("sed")
|
||||
.arg("-i")
|
||||
.arg(r"/archive.ubuntu.com\|security.ubuntu.com/ s/\( main\)\?\([ ]\+restricted\)\?\([ ]\+universe\)\?\([ ]\+multiverse\)\?$/ main restricted universe multiverse/")
|
||||
.arg(sources_path)
|
||||
.status()?;
|
||||
|
||||
// Ensure all pockets exist. If not, we append them.
|
||||
for pocket in ["", "-updates", "-backports", "-security"] {
|
||||
let suite = format!("{}{}", series, pocket);
|
||||
let has_suite = ctx
|
||||
.command("grep")
|
||||
.arg("-q")
|
||||
.arg(format!(" {}", suite))
|
||||
.arg(sources_path)
|
||||
.status()?
|
||||
.success();
|
||||
|
||||
if !has_suite {
|
||||
let line = format!(
|
||||
"deb [arch={}] http://archive.ubuntu.com/ubuntu/ {} main restricted universe multiverse",
|
||||
local_arch, suite
|
||||
);
|
||||
ctx.command("sh")
|
||||
.arg("-c")
|
||||
.arg(format!("echo '{}' >> {}", line, sources_path))
|
||||
.status()?;
|
||||
.success()
|
||||
{
|
||||
// For DEB822 format, we need to reconstruct the file content
|
||||
let mut content = String::new();
|
||||
for source in &sources {
|
||||
if !source.enabled {
|
||||
continue;
|
||||
}
|
||||
content.push_str("Types: deb\n");
|
||||
content.push_str(&format!("URIs: {}\n", source.uri));
|
||||
content.push_str(&format!("Suites: {}\n", source.suite.join(" ")));
|
||||
content.push_str(&format!("Components: {}\n", source.components.join(" ")));
|
||||
content.push_str("Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\n");
|
||||
content.push_str(&format!(
|
||||
"Architectures: {}\n",
|
||||
source.architectures.join(" ")
|
||||
));
|
||||
content.push('\n');
|
||||
}
|
||||
ctx.write_file(std::path::Path::new(deb822_path), &content)?;
|
||||
} else {
|
||||
// Fall back to legacy format
|
||||
crate::apt::sources::save_legacy(Some(ctx.clone()), sources, "/etc/apt/sources.list")?;
|
||||
}
|
||||
|
||||
// Add ports repository to sources.list if not already present
|
||||
let has_ports = ctx
|
||||
.command("grep")
|
||||
.arg("-q")
|
||||
.arg("ports.ubuntu.com")
|
||||
.arg(sources_path)
|
||||
.status()?
|
||||
.success();
|
||||
|
||||
if !has_ports {
|
||||
let ports_lines = format!(
|
||||
"deb [arch={arch}] http://ports.ubuntu.com/ubuntu-ports {series} main restricted universe multiverse\n\
|
||||
deb [arch={arch}] http://ports.ubuntu.com/ubuntu-ports {series}-updates main restricted universe multiverse\n\
|
||||
deb [arch={arch}] http://ports.ubuntu.com/ubuntu-ports {series}-backports main restricted universe multiverse\n\
|
||||
deb [arch={arch}] http://ports.ubuntu.com/ubuntu-ports {series}-security main restricted universe multiverse"
|
||||
);
|
||||
ctx.command("sh")
|
||||
.arg("-c")
|
||||
.arg(format!("echo '{}' >> {}", ports_lines, sources_path))
|
||||
.status()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user