deb: cross uses new apt sources parser
This commit is contained in:
@@ -16,8 +16,8 @@ pub struct SourceEntry {
|
|||||||
pub architectures: Vec<String>,
|
pub architectures: Vec<String>,
|
||||||
/// Source URI
|
/// Source URI
|
||||||
pub uri: String,
|
pub uri: String,
|
||||||
/// Source suite (series-pocket)
|
/// Source suites (series-pocket)
|
||||||
pub suite: String,
|
pub suite: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SourceEntry {
|
impl SourceEntry {
|
||||||
@@ -28,7 +28,7 @@ impl SourceEntry {
|
|||||||
components: Vec::new(),
|
components: Vec::new(),
|
||||||
architectures: Vec::new(),
|
architectures: Vec::new(),
|
||||||
uri: String::new(),
|
uri: String::new(),
|
||||||
suite: String::new(),
|
suite: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for line in data.lines() {
|
for line in data.lines() {
|
||||||
@@ -55,7 +55,10 @@ impl SourceEntry {
|
|||||||
// We only care about deb types
|
// We only care about deb types
|
||||||
}
|
}
|
||||||
"URIs" => current_entry.uri = value.to_string(),
|
"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" => {
|
"Components" => {
|
||||||
current_entry.components =
|
current_entry.components =
|
||||||
value.split_whitespace().map(|s| s.to_string()).collect();
|
value.split_whitespace().map(|s| s.to_string()).collect();
|
||||||
@@ -123,7 +126,7 @@ impl SourceEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let uri = parts[1].to_string();
|
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();
|
let components: Vec<String> = parts[3..].iter().map(|&s| s.to_string()).collect();
|
||||||
|
|
||||||
Some(SourceEntry {
|
Some(SourceEntry {
|
||||||
@@ -139,6 +142,8 @@ impl SourceEntry {
|
|||||||
pub fn to_legacy(&self) -> String {
|
pub fn to_legacy(&self) -> String {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
|
|
||||||
|
// Legacy entries contain one suite per line
|
||||||
|
for suite in &self.suite {
|
||||||
// Start with "deb" type
|
// Start with "deb" type
|
||||||
result.push_str("deb");
|
result.push_str("deb");
|
||||||
|
|
||||||
@@ -153,7 +158,7 @@ impl SourceEntry {
|
|||||||
result.push(' ');
|
result.push(' ');
|
||||||
result.push_str(&self.uri);
|
result.push_str(&self.uri);
|
||||||
result.push(' ');
|
result.push(' ');
|
||||||
result.push_str(&self.suite);
|
result.push_str(suite);
|
||||||
|
|
||||||
// Add components
|
// Add components
|
||||||
if !self.components.is_empty() {
|
if !self.components.is_empty() {
|
||||||
@@ -161,6 +166,9 @@ impl SourceEntry {
|
|||||||
result.push_str(&self.components.join(" "));
|
result.push_str(&self.components.join(" "));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.push('\n');
|
||||||
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,12 +283,17 @@ mod tests {
|
|||||||
assert_eq!(sources.len(), 3);
|
assert_eq!(sources.len(), 3);
|
||||||
assert_eq!(sources[0].uri, "http://fr.archive.ubuntu.com/ubuntu/");
|
assert_eq!(sources[0].uri, "http://fr.archive.ubuntu.com/ubuntu/");
|
||||||
assert_eq!(sources[0].architectures, vec!["amd64"]);
|
assert_eq!(sources[0].architectures, vec!["amd64"]);
|
||||||
|
assert_eq!(
|
||||||
|
sources[0].suite,
|
||||||
|
vec!["questing", "questing-updates", "questing-backports"]
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sources[0].components,
|
sources[0].components,
|
||||||
vec!["main", "restricted", "universe", "multiverse"]
|
vec!["main", "restricted", "universe", "multiverse"]
|
||||||
);
|
);
|
||||||
assert_eq!(sources[1].uri, "http://security.ubuntu.com/ubuntu/");
|
assert_eq!(sources[1].uri, "http://security.ubuntu.com/ubuntu/");
|
||||||
assert_eq!(sources[1].architectures, vec!["amd64"]);
|
assert_eq!(sources[1].architectures, vec!["amd64"]);
|
||||||
|
assert_eq!(sources[1].suite, vec!["questing-security"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sources[1].components,
|
sources[1].components,
|
||||||
vec!["main", "restricted", "universe", "multiverse"]
|
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].uri, "http://ports.ubuntu.com/ubuntu-ports/");
|
||||||
assert_eq!(sources[2].architectures.len(), 1);
|
assert_eq!(sources[2].architectures.len(), 1);
|
||||||
assert_eq!(sources[2].architectures, vec!["riscv64"]);
|
assert_eq!(sources[2].architectures, vec!["riscv64"]);
|
||||||
|
assert_eq!(
|
||||||
|
sources[2].suite,
|
||||||
|
vec!["questing", "questing-updates", "questing-backports"]
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sources[2].components,
|
sources[2].components,
|
||||||
vec!["main", "restricted", "universe", "multiverse"]
|
vec!["main", "restricted", "universe", "multiverse"]
|
||||||
@@ -305,15 +322,15 @@ mod tests {
|
|||||||
let sources = parse_legacy(legacy);
|
let sources = parse_legacy(legacy);
|
||||||
assert_eq!(sources.len(), 3);
|
assert_eq!(sources.len(), 3);
|
||||||
assert_eq!(sources[0].uri, "http://archive.ubuntu.com/ubuntu");
|
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].components, vec!["main", "universe"]);
|
||||||
assert_eq!(sources[0].architectures, vec!["amd64"]);
|
assert_eq!(sources[0].architectures, vec!["amd64"]);
|
||||||
assert_eq!(sources[1].uri, "http://archive.ubuntu.com/ubuntu");
|
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].components, vec!["main"]);
|
||||||
assert_eq!(sources[1].architectures, vec!["amd64", "i386"]);
|
assert_eq!(sources[1].architectures, vec!["amd64", "i386"]);
|
||||||
assert_eq!(sources[2].uri, "http://security.ubuntu.com/ubuntu");
|
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"]);
|
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(());
|
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 deb822_path = "/etc/apt/sources.list.d/ubuntu.sources";
|
||||||
let has_deb822 = ctx
|
if ctx
|
||||||
.command("test")
|
.command("test")
|
||||||
.arg("-f")
|
.arg("-f")
|
||||||
.arg(deb822_path)
|
.arg(deb822_path)
|
||||||
.status()?
|
.status()?
|
||||||
.success();
|
.success()
|
||||||
|
{
|
||||||
if has_deb822 {
|
// For DEB822 format, we need to reconstruct the file content
|
||||||
ensure_repositories_deb822(&ctx, arch, &local_arch, series, deb822_path)?;
|
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 {
|
} else {
|
||||||
ensure_repositories_legacy(&ctx, arch, &local_arch, series, "/etc/apt/sources.list")?;
|
// Fall back to legacy format
|
||||||
|
crate::apt::sources::save_legacy(Some(ctx.clone()), sources, "/etc/apt/sources.list")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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()?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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