exp: cross #5
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
/// Schroot context: execute commands in a schroot session
|
||||||
|
/// Not tested, will need more work!
|
||||||
use super::api::ContextDriver;
|
use super::api::ContextDriver;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
@@ -9,25 +11,104 @@ pub struct SchrootDriver {
|
|||||||
pub parent: Option<Arc<super::api::Context>>,
|
pub parent: Option<Arc<super::api::Context>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use super::api::{Context, ContextConfig};
|
||||||
|
|
||||||
|
impl SchrootDriver {
|
||||||
|
fn parent(&self) -> Arc<Context> {
|
||||||
|
self.parent
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| Arc::new(Context::new(ContextConfig::Local)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ensure_session(&self) -> io::Result<String> {
|
||||||
|
let mut session_lock = self.session.lock().unwrap();
|
||||||
|
if let Some(id) = session_lock.as_ref() {
|
||||||
|
return Ok(id.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new session
|
||||||
|
let output = self
|
||||||
|
.parent()
|
||||||
|
.command("schroot")
|
||||||
|
.arg("-b")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(&self.name)
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
return Err(io::Error::other(format!(
|
||||||
|
"Failed to create schroot session: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let session_id = String::from_utf8(output.stdout)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?
|
||||||
|
.trim()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
*session_lock = Some(session_id.clone());
|
||||||
|
Ok(session_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_session_location(&self, session_id: &str) -> io::Result<String> {
|
||||||
|
let output = self
|
||||||
|
.parent()
|
||||||
|
.command("schroot")
|
||||||
|
.arg("--location")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(session_id)
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
return Err(io::Error::other(format!(
|
||||||
|
"Failed to get schroot location: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(String::from_utf8(output.stdout)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?
|
||||||
|
.trim()
|
||||||
|
.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ContextDriver for SchrootDriver {
|
impl ContextDriver for SchrootDriver {
|
||||||
fn ensure_available(&self, src: &Path, _dest_root: &str) -> io::Result<PathBuf> {
|
fn ensure_available(&self, src: &Path, _dest_root: &str) -> io::Result<PathBuf> {
|
||||||
src.canonicalize()
|
src.canonicalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retrieve_path(&self, _src: &Path, _dest: &Path) -> io::Result<()> {
|
fn retrieve_path(&self, src: &Path, dest: &Path) -> io::Result<()> {
|
||||||
// TODO: Implement schroot file retrieval logic
|
let session_id = self.ensure_session()?;
|
||||||
Err(io::Error::new(
|
let location = self.get_session_location(&session_id)?;
|
||||||
io::ErrorKind::Unsupported,
|
|
||||||
"retrieve_path not yet implemented for schroot",
|
let path_in_chroot = src.strip_prefix("/").unwrap_or(src);
|
||||||
))
|
let host_src = Path::new(&location).join(path_in_chroot);
|
||||||
|
|
||||||
|
self.parent().retrieve_path(&host_src, dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_files(&self, _path: &Path) -> io::Result<Vec<PathBuf>> {
|
fn list_files(&self, path: &Path) -> io::Result<Vec<PathBuf>> {
|
||||||
// TODO: Implement schroot file listing logic
|
let session_id = self.ensure_session()?;
|
||||||
Err(io::Error::new(
|
let location = self.get_session_location(&session_id)?;
|
||||||
io::ErrorKind::Unsupported,
|
|
||||||
"list_files not yet implemented for schroot",
|
let path_in_chroot = path.strip_prefix("/").unwrap_or(path);
|
||||||
))
|
let host_path = Path::new(&location).join(path_in_chroot);
|
||||||
|
|
||||||
|
let files = self.parent().list_files(&host_path)?;
|
||||||
|
let mut chroot_files = Vec::new();
|
||||||
|
|
||||||
|
// TODO: Check if we *need* to strip the prefix.
|
||||||
|
// If we don't, we can just return `files`.
|
||||||
|
for file in files {
|
||||||
|
if let Ok(rel) = file.strip_prefix(&location) {
|
||||||
|
chroot_files.push(Path::new("/").join(rel));
|
||||||
|
} else {
|
||||||
|
chroot_files.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(chroot_files)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@@ -37,94 +118,48 @@ impl ContextDriver for SchrootDriver {
|
|||||||
env: &[(String, String)],
|
env: &[(String, String)],
|
||||||
cwd: Option<&str>,
|
cwd: Option<&str>,
|
||||||
) -> io::Result<std::process::ExitStatus> {
|
) -> io::Result<std::process::ExitStatus> {
|
||||||
// Initialize session on first run
|
let session_id = self.ensure_session()?;
|
||||||
let mut session_lock = self.session.lock().unwrap();
|
|
||||||
if session_lock.is_none() {
|
|
||||||
let session_output = if let Some(parent) = &self.parent {
|
|
||||||
parent
|
|
||||||
.command("schroot")
|
|
||||||
.arg("-b")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(&self.name)
|
|
||||||
.output()?
|
|
||||||
} else {
|
|
||||||
std::process::Command::new("schroot")
|
|
||||||
.arg("-b")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(&self.name)
|
|
||||||
.output()?
|
|
||||||
};
|
|
||||||
|
|
||||||
if !session_output.status.success() {
|
// Construct the schroot command
|
||||||
return Err(io::Error::other(format!(
|
// schroot -p -r -c session_id -- program args...
|
||||||
"Failed to create schroot session: {}",
|
// If cwd is specified, we wrap in sh -c "cd cwd && ..."
|
||||||
String::from_utf8_lossy(&session_output.stderr)
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let session_id = String::from_utf8(session_output.stdout)
|
let mut command_args = vec![
|
||||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?
|
"-p".to_string(),
|
||||||
.trim()
|
"-r".to_string(),
|
||||||
.to_string();
|
"-c".to_string(),
|
||||||
|
session_id,
|
||||||
|
"--".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
*session_lock = Some(session_id);
|
let mut actual_program = program.to_string();
|
||||||
}
|
let mut actual_args = args.to_vec();
|
||||||
drop(session_lock);
|
|
||||||
|
|
||||||
let session_lock = self.session.lock().unwrap();
|
// Simplest: Wrap everything in `sh -c` if CWD or ENV is needed.
|
||||||
let session_id = session_lock.as_ref().unwrap();
|
if cwd.is_some() || !env.is_empty() {
|
||||||
|
let mut shell_cmd = String::new();
|
||||||
if let Some(parent) = &self.parent {
|
|
||||||
let mut cmd = parent.command("sudo");
|
|
||||||
cmd.envs(env.iter().cloned());
|
|
||||||
|
|
||||||
if let Some(dir) = cwd {
|
if let Some(dir) = cwd {
|
||||||
cmd.arg("schroot")
|
shell_cmd.push_str(&format!("cd {} && ", dir));
|
||||||
.arg("-p")
|
|
||||||
.arg("-r")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(session_id)
|
|
||||||
.arg("--")
|
|
||||||
.arg("sh")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(format!("cd {} && {} {}", dir, program, args.join(" ")));
|
|
||||||
} else {
|
|
||||||
cmd.arg("schroot")
|
|
||||||
.arg("-p")
|
|
||||||
.arg("-r")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(session_id)
|
|
||||||
.arg("--")
|
|
||||||
.arg(program)
|
|
||||||
.args(args);
|
|
||||||
}
|
}
|
||||||
cmd.status()
|
|
||||||
} else {
|
|
||||||
let mut cmd = std::process::Command::new("sudo");
|
|
||||||
cmd.args(env.iter().map(|(k, v)| format!("{k}={v}")));
|
|
||||||
|
|
||||||
if let Some(dir) = cwd {
|
if !env.is_empty() {
|
||||||
cmd.arg("schroot")
|
shell_cmd.push_str("env ");
|
||||||
.arg("-p")
|
for (k, v) in env {
|
||||||
.arg("-r")
|
shell_cmd.push_str(&format!("{}={} ", k, v));
|
||||||
.arg("-c")
|
}
|
||||||
.arg(session_id)
|
|
||||||
.arg("--")
|
|
||||||
.arg("sh")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(format!("cd {} && {} {}", dir, program, args.join(" ")));
|
|
||||||
} else {
|
|
||||||
cmd.arg("schroot")
|
|
||||||
.arg("-p")
|
|
||||||
.arg("-r")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(session_id)
|
|
||||||
.arg("--")
|
|
||||||
.arg(program)
|
|
||||||
.args(args);
|
|
||||||
}
|
}
|
||||||
cmd.status()
|
|
||||||
|
shell_cmd.push_str(&format!("{} {}", program, args.join(" ")));
|
||||||
|
|
||||||
|
actual_program = "sh".to_string();
|
||||||
|
actual_args = vec!["-c".to_string(), shell_cmd];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
command_args.push(actual_program);
|
||||||
|
command_args.extend(actual_args);
|
||||||
|
|
||||||
|
self.parent().command("schroot").args(command_args).status()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_output(
|
fn run_output(
|
||||||
@@ -134,66 +169,42 @@ impl ContextDriver for SchrootDriver {
|
|||||||
env: &[(String, String)],
|
env: &[(String, String)],
|
||||||
cwd: Option<&str>,
|
cwd: Option<&str>,
|
||||||
) -> io::Result<std::process::Output> {
|
) -> io::Result<std::process::Output> {
|
||||||
if let Some(parent) = &self.parent {
|
let session_id = self.ensure_session()?;
|
||||||
let mut cmd = parent.command("sudo");
|
|
||||||
cmd.envs(env.iter().cloned());
|
let mut command_args = vec![
|
||||||
|
"-r".to_string(),
|
||||||
|
"-c".to_string(),
|
||||||
|
session_id,
|
||||||
|
"--".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut actual_program = program.to_string();
|
||||||
|
let mut actual_args = args.to_vec();
|
||||||
|
|
||||||
|
if cwd.is_some() || !env.is_empty() {
|
||||||
|
let mut shell_cmd = String::new();
|
||||||
|
|
||||||
if let Some(dir) = cwd {
|
if let Some(dir) = cwd {
|
||||||
cmd.arg("schroot")
|
shell_cmd.push_str(&format!("cd {} && ", dir));
|
||||||
.arg("-r")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(&self.name)
|
|
||||||
.arg("--")
|
|
||||||
.arg("sh")
|
|
||||||
.arg("-c");
|
|
||||||
|
|
||||||
let mut cmd_str = String::new();
|
|
||||||
cmd_str.push_str(&format!("cd {} && {} {}", dir, program, args.join(" ")));
|
|
||||||
cmd.arg(cmd_str);
|
|
||||||
} else {
|
|
||||||
cmd.arg("schroot")
|
|
||||||
.arg("-r")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(&self.name)
|
|
||||||
.arg("--");
|
|
||||||
|
|
||||||
cmd.arg(program).args(args);
|
|
||||||
}
|
}
|
||||||
cmd.output()
|
|
||||||
} else {
|
|
||||||
let mut cmd = std::process::Command::new("sudo");
|
|
||||||
if let Some(dir) = cwd {
|
|
||||||
cmd.arg("schroot")
|
|
||||||
.arg("-r")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(&self.name)
|
|
||||||
.arg("--")
|
|
||||||
.arg("sh")
|
|
||||||
.arg("-c");
|
|
||||||
|
|
||||||
let mut cmd_str = String::new();
|
if !env.is_empty() {
|
||||||
|
shell_cmd.push_str("env ");
|
||||||
for (k, v) in env {
|
for (k, v) in env {
|
||||||
cmd_str.push_str(&format!("{}={} ", k, v));
|
shell_cmd.push_str(&format!("{}={} ", k, v));
|
||||||
}
|
}
|
||||||
cmd_str.push_str(&format!("cd {} && {} {}", dir, program, args.join(" ")));
|
|
||||||
cmd.arg(cmd_str);
|
|
||||||
} else {
|
|
||||||
cmd.arg("schroot")
|
|
||||||
.arg("-r")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(&self.name)
|
|
||||||
.arg("--");
|
|
||||||
|
|
||||||
if !env.is_empty() {
|
|
||||||
cmd.arg("env");
|
|
||||||
for (k, v) in env {
|
|
||||||
cmd.arg(format!("{}={}", k, v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmd.arg(program).args(args);
|
|
||||||
}
|
}
|
||||||
cmd.output()
|
|
||||||
|
shell_cmd.push_str(&format!("{} {}", program, args.join(" ")));
|
||||||
|
|
||||||
|
actual_program = "sh".to_string();
|
||||||
|
actual_args = vec!["-c".to_string(), shell_cmd];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
command_args.push(actual_program);
|
||||||
|
command_args.extend(actual_args);
|
||||||
|
|
||||||
|
self.parent().command("schroot").args(command_args).output()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_temp_dir(&self) -> io::Result<String> {
|
fn create_temp_dir(&self) -> io::Result<String> {
|
||||||
@@ -233,7 +244,6 @@ impl ContextDriver for SchrootDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_file(&self, path: &Path, content: &str) -> io::Result<()> {
|
fn write_file(&self, path: &Path, content: &str) -> io::Result<()> {
|
||||||
// TODO: change that command, it's not safe
|
|
||||||
let status = self.run(
|
let status = self.run(
|
||||||
"sh",
|
"sh",
|
||||||
&[
|
&[
|
||||||
|
|||||||
@@ -70,12 +70,9 @@ impl ContextDriver for UnshareDriver {
|
|||||||
Ok(Path::new(dest_root).join(filename))
|
Ok(Path::new(dest_root).join(filename))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retrieve_path(&self, _src: &Path, _dest: &Path) -> io::Result<()> {
|
fn retrieve_path(&self, src: &Path, dest: &Path) -> io::Result<()> {
|
||||||
// TODO: Implement chroot file retrieval logic
|
let host_src = Path::new(&self.path).join(src.to_string_lossy().trim_start_matches('/'));
|
||||||
Err(io::Error::new(
|
self.parent().retrieve_path(&host_src, dest)
|
||||||
io::ErrorKind::Unsupported,
|
|
||||||
"retrieve_path not yet implemented for chroot",
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_files(&self, path: &Path) -> io::Result<Vec<PathBuf>> {
|
fn list_files(&self, path: &Path) -> io::Result<Vec<PathBuf>> {
|
||||||
|
|||||||
348
src/deb/cross.rs
348
src/deb/cross.rs
@@ -3,59 +3,89 @@ use crate::context::{Context, ContextConfig};
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
/// Setup a specific chroot context for native cross builds
|
use std::path::PathBuf;
|
||||||
pub fn setup_native_context(series: &str) -> Result<(), Box<dyn Error>> {
|
|
||||||
// Create a temporary directory for the chroot
|
|
||||||
let chroot_path_str = context::current().create_temp_dir()?;
|
|
||||||
let chroot_path = std::path::PathBuf::from(chroot_path_str);
|
|
||||||
|
|
||||||
log::debug!(
|
pub struct EphemeralContextGuard {
|
||||||
"Creating new chroot for {} at {}...",
|
previous_context: String,
|
||||||
series,
|
chroot_path: PathBuf,
|
||||||
chroot_path.display()
|
|
||||||
);
|
|
||||||
|
|
||||||
let status = context::current()
|
|
||||||
.command("sudo")
|
|
||||||
.arg("mmdebstrap")
|
|
||||||
.arg("--variant=buildd")
|
|
||||||
.arg(series)
|
|
||||||
.arg(chroot_path.to_string_lossy().to_string())
|
|
||||||
.status()?;
|
|
||||||
|
|
||||||
if !status.success() {
|
|
||||||
// Clean up on failure
|
|
||||||
let _ = std::fs::remove_dir_all(&chroot_path);
|
|
||||||
return Err(format!("mmdebstrap failed for series {}", series).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Switch to an ephemeral context to build the package in the chroot
|
|
||||||
context::manager().set_current_ephemeral(Context::new(ContextConfig::Unshare {
|
|
||||||
path: chroot_path.to_string_lossy().to_string(),
|
|
||||||
parent: Some(context::manager().current_name()),
|
|
||||||
}));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clean_native_context() -> Result<(), Box<dyn Error>> {
|
impl EphemeralContextGuard {
|
||||||
let ctx = context::current();
|
pub fn new(series: &str) -> Result<Self, Box<dyn Error>> {
|
||||||
if let ContextConfig::Unshare { path, .. } = &ctx.config {
|
let current_context_name = context::manager().current_name();
|
||||||
let chroot_path = path.clone();
|
|
||||||
|
|
||||||
|
// Create a temporary directory for the chroot
|
||||||
|
let chroot_path_str = context::current().create_temp_dir()?;
|
||||||
|
let chroot_path = PathBuf::from(chroot_path_str);
|
||||||
|
|
||||||
|
log::debug!(
|
||||||
|
"Creating new chroot for {} at {}...",
|
||||||
|
series,
|
||||||
|
chroot_path.display()
|
||||||
|
);
|
||||||
|
|
||||||
|
let status = context::current()
|
||||||
|
.command("sudo")
|
||||||
|
.arg("mmdebstrap")
|
||||||
|
.arg("--variant=buildd")
|
||||||
|
.arg(series)
|
||||||
|
.arg(chroot_path.to_string_lossy().to_string())
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
// Clean up on failure
|
||||||
|
let _ = std::fs::remove_dir_all(&chroot_path);
|
||||||
|
return Err(format!("mmdebstrap failed for series {}", series).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch to an ephemeral context to build the package in the chroot
|
||||||
|
context::manager().set_current_ephemeral(Context::new(ContextConfig::Unshare {
|
||||||
|
path: chroot_path.to_string_lossy().to_string(),
|
||||||
|
parent: Some(current_context_name.clone()),
|
||||||
|
}));
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
previous_context: current_context_name,
|
||||||
|
chroot_path,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for EphemeralContextGuard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
log::debug!("Cleaning up ephemeral context...");
|
||||||
// Reset to normal context
|
// Reset to normal context
|
||||||
context::manager().set_current(&context::manager().current_name())?;
|
if let Err(e) = context::manager().set_current(&self.previous_context) {
|
||||||
|
log::error!("Failed to restore context {}: {}", self.previous_context, e);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove chroot directory
|
// Remove chroot directory
|
||||||
context::current()
|
// We use the restored context to execute the cleanup command
|
||||||
|
let result = context::current()
|
||||||
.command("sudo")
|
.command("sudo")
|
||||||
.arg("rm")
|
.arg("rm")
|
||||||
.arg("-rf")
|
.arg("-rf")
|
||||||
.arg(chroot_path)
|
.arg(&self.chroot_path)
|
||||||
.status()?;
|
.status();
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
match result {
|
||||||
|
Ok(status) => {
|
||||||
|
if !status.success() {
|
||||||
|
log::error!(
|
||||||
|
"Failed to remove chroot directory {}",
|
||||||
|
self.chroot_path.display()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!(
|
||||||
|
"Failed to execute cleanup command for {}: {}",
|
||||||
|
self.chroot_path.display(),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set environment variables for cross-compilation
|
/// Set environment variables for cross-compilation
|
||||||
@@ -92,6 +122,7 @@ pub fn setup_environment(
|
|||||||
/// This also handles the 'ports.ubuntu.com' vs 'archive.ubuntu.com' on Ubuntu
|
/// This also handles the 'ports.ubuntu.com' vs 'archive.ubuntu.com' on Ubuntu
|
||||||
pub fn ensure_repositories(arch: &str, series: &str) -> Result<(), Box<dyn Error>> {
|
pub fn ensure_repositories(arch: &str, series: &str) -> Result<(), Box<dyn Error>> {
|
||||||
let ctx = context::current();
|
let ctx = context::current();
|
||||||
|
let local_arch = crate::get_current_arch();
|
||||||
|
|
||||||
// Add target ('host') architecture
|
// Add target ('host') architecture
|
||||||
ctx.command("dpkg")
|
ctx.command("dpkg")
|
||||||
@@ -115,114 +146,135 @@ pub fn ensure_repositories(arch: &str, series: &str) -> Result<(), Box<dyn Error
|
|||||||
.success();
|
.success();
|
||||||
|
|
||||||
if has_deb822 {
|
if has_deb822 {
|
||||||
// Scope existing to amd64 if not already scoped
|
ensure_repositories_deb822(&ctx, arch, &local_arch, series, deb822_path)?;
|
||||||
// This looks for URIs lines for archive/security and adds Architectures: amd64 on the next line if missing
|
|
||||||
ctx.command("sed")
|
|
||||||
.arg("-i")
|
|
||||||
.arg("/URIs:.*\\(archive\\|security\\)\\.ubuntu\\.com/ { n; /^Architectures:/ ! i Architectures: amd64 }")
|
|
||||||
.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
|
|
||||||
let suites = format!(
|
|
||||||
"{series} {series}-updates {series}-backports {series}-security {series}-proposed"
|
|
||||||
);
|
|
||||||
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 {series}-proposed\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()?;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Traditional sources.list
|
ensure_repositories_legacy(&ctx, arch, &local_arch, series, "/etc/apt/sources.list")?;
|
||||||
let sources_path = "/etc/apt/sources.list";
|
|
||||||
|
|
||||||
// Scope archive.ubuntu.com and security.ubuntu.com to amd64 if not already scoped
|
|
||||||
ctx.command("sed")
|
|
||||||
.arg("-i")
|
|
||||||
.arg(r"/archive.ubuntu.com\|security.ubuntu.com/ { /arch=/ ! { /^deb \[/ ! s/^deb /deb [arch=amd64] /; /^deb \[/ s/^deb \[\([^]]*\)\]/deb [arch=amd64 \1]/ } }")
|
|
||||||
.arg(sources_path)
|
|
||||||
.status()?;
|
|
||||||
|
|
||||||
// Ensure all components (main restricted universe multiverse) are present for all archive/security lines
|
|
||||||
// We match any combination of components at the end and replace with the full set
|
|
||||||
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.
|
|
||||||
// We ignore 'proposed' as it contains unstable software
|
|
||||||
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=amd64] http://archive.ubuntu.com/ubuntu/ {} main restricted universe multiverse",
|
|
||||||
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(())
|
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(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,9 +51,11 @@ pub fn build_binary_package(
|
|||||||
// Specific case: native cross-compilation, we don't allow that
|
// Specific case: native cross-compilation, we don't allow that
|
||||||
// instead this wraps to an automatic unshare chroot
|
// instead this wraps to an automatic unshare chroot
|
||||||
// using an ephemeral context
|
// using an ephemeral context
|
||||||
if cross && mode == BuildMode::Local {
|
let _guard = if cross && mode == BuildMode::Local {
|
||||||
cross::setup_native_context(series)?;
|
Some(cross::EphemeralContextGuard::new(series)?)
|
||||||
}
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Prepare build directory
|
// Prepare build directory
|
||||||
let ctx = context::current();
|
let ctx = context::current();
|
||||||
@@ -83,10 +85,6 @@ pub fn build_binary_package(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cross && mode == BuildMode::Local {
|
|
||||||
cross::clean_native_context()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user