All checks were successful
CI / build (push) Successful in 2m2s
sbuild options: unshare, build directory context: retrieve files
158 lines
4.9 KiB
Rust
158 lines
4.9 KiB
Rust
use crate::context::{Context, current_context};
|
|
use std::error::Error;
|
|
use std::path::{Path, PathBuf};
|
|
|
|
pub fn build_binary_package(
|
|
arch: Option<&str>,
|
|
series: Option<&str>,
|
|
cwd: Option<&Path>,
|
|
) -> Result<(), Box<dyn Error>> {
|
|
let cwd = cwd.unwrap_or_else(|| Path::new("."));
|
|
|
|
// Parse changelog to get package name and version
|
|
let changelog_path = cwd.join("debian/changelog");
|
|
let (package, version, _series) = crate::changelog::parse_changelog_header(&changelog_path)?;
|
|
|
|
// Find .dsc file
|
|
let dsc_path = find_dsc_file(cwd, &package, &version)?;
|
|
println!("Building {} using sbuild...", dsc_path.display());
|
|
|
|
// Identify all related files from .dsc
|
|
let mut files_to_ensure = get_dsc_related_files(&dsc_path)?;
|
|
// Ensure dsc itself is included (usually first)
|
|
if !files_to_ensure.contains(&dsc_path) {
|
|
files_to_ensure.insert(0, dsc_path.clone());
|
|
}
|
|
|
|
// Prepare Environment
|
|
let ctx = current_context();
|
|
let build_root = ctx.prepare_work_dir()?;
|
|
|
|
// Ensure availability of all needed files for the build
|
|
let remote_dsc_path = upload_package_files(&ctx, &files_to_ensure, &build_root, &dsc_path)?;
|
|
println!(
|
|
"Building {} on {}...",
|
|
remote_dsc_path.display(),
|
|
build_root
|
|
);
|
|
|
|
// Run sbuild
|
|
run_sbuild(&ctx, &remote_dsc_path, arch, series, &build_root)?;
|
|
|
|
// Retrieve artifacts
|
|
// Always retrieve to the directory containing the .dsc file
|
|
let local_output_dir = dsc_path
|
|
.parent()
|
|
.ok_or("Could not determine parent directory of dsc file")?;
|
|
println!("Retrieving artifacts to {}...", local_output_dir.display());
|
|
|
|
// Only retrieve .deb files
|
|
let remote_files = ctx.list_files(Path::new(&build_root))?;
|
|
for remote_file in remote_files {
|
|
if remote_file.extension().is_some_and(|ext| ext == "deb") {
|
|
let file_name = remote_file.file_name().ok_or("Invalid remote filename")?;
|
|
let local_dest = local_output_dir.join(file_name);
|
|
ctx.retrieve_path(&remote_file, &local_dest)?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn find_dsc_file(cwd: &Path, package: &str, version: &str) -> Result<PathBuf, Box<dyn Error>> {
|
|
let parent = cwd.parent().ok_or("Cannot find parent directory")?;
|
|
let dsc_name = format!("{}_{}.dsc", package, version);
|
|
let dsc_path = parent.join(&dsc_name);
|
|
|
|
if !dsc_path.exists() {
|
|
return Err(format!("Could not find .dsc file at {}", dsc_path.display()).into());
|
|
}
|
|
Ok(dsc_path)
|
|
}
|
|
|
|
fn get_dsc_related_files(dsc_path: &Path) -> Result<Vec<PathBuf>, Box<dyn Error>> {
|
|
let content = std::fs::read_to_string(dsc_path)?;
|
|
let parent = dsc_path.parent().unwrap(); // dsc_path exists so parent exists
|
|
let mut files = Vec::new();
|
|
|
|
let mut in_files = false;
|
|
for line in content.lines() {
|
|
if line.starts_with("Files:") {
|
|
in_files = true;
|
|
continue;
|
|
}
|
|
if in_files {
|
|
if line.starts_with(' ') {
|
|
let parts: Vec<&str> = line.split_whitespace().collect();
|
|
if parts.len() >= 3 {
|
|
let filename = parts[2];
|
|
let filepath = parent.join(filename);
|
|
if filepath.exists() {
|
|
files.push(filepath);
|
|
} else {
|
|
return Err(
|
|
format!("Referenced file {} not found", filepath.display()).into()
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
in_files = false;
|
|
}
|
|
}
|
|
}
|
|
Ok(files)
|
|
}
|
|
|
|
fn upload_package_files(
|
|
ctx: &Context,
|
|
files: &[PathBuf],
|
|
dest_root: &str,
|
|
local_dsc_path: &Path,
|
|
) -> Result<PathBuf, Box<dyn Error>> {
|
|
let mut remote_dsc_path = PathBuf::new();
|
|
|
|
for file in files {
|
|
let remote_path = ctx.ensure_available(file, dest_root)?;
|
|
// Check if this is the dsc file by comparing file names
|
|
if let (Some(f_name), Some(dsc_name)) = (file.file_name(), local_dsc_path.file_name())
|
|
&& f_name == dsc_name
|
|
{
|
|
remote_dsc_path = remote_path;
|
|
}
|
|
}
|
|
|
|
if remote_dsc_path.as_os_str().is_empty() {
|
|
return Err("Failed to determine remote path for .dsc file".into());
|
|
}
|
|
|
|
Ok(remote_dsc_path)
|
|
}
|
|
|
|
fn run_sbuild(
|
|
ctx: &Context,
|
|
dsc_path: &Path,
|
|
arch: Option<&str>,
|
|
series: Option<&str>,
|
|
output_dir: &str,
|
|
) -> Result<(), Box<dyn Error>> {
|
|
let mut cmd = ctx.command("sbuild");
|
|
cmd.arg("--chroot-mode=unshare");
|
|
|
|
if let Some(a) = arch {
|
|
cmd.arg(format!("--arch={}", a));
|
|
}
|
|
if let Some(s) = series {
|
|
cmd.arg(format!("--dist={}", s));
|
|
}
|
|
|
|
// Add output directory argument
|
|
cmd.arg(format!("--build-dir={}", output_dir));
|
|
|
|
let status = cmd.arg(dsc_path).status()?;
|
|
|
|
if !status.success() {
|
|
return Err(format!("sbuild failed with status: {}", status).into());
|
|
}
|
|
Ok(())
|
|
}
|