use std::process::Command;
use super::super::config::TelarConfig;
use super::{
create_dir_or_exit, desktop_entry_file, dist_dir, run_bundler_tool, run_release_build,
stage_binary, write_or_exit,
};
fn deb_architecture(arch: &str) -> &str {
match arch {
"x86_64" => "amd64",
"aarch64" => "arm64",
other => other,
}
}
fn deb_control_file(name: &str, version: &str, arch: &str, description: &str) -> String {
format!(
"Package: {name}\nVersion: {version}\nArchitecture: {arch}\nMaintainer: {name} maintainers <maintainer@example.invalid>\nDescription: {description}\n"
)
}
pub(crate) fn build_deb(cargo_args: Vec<String>, config: TelarConfig) -> ! {
let (bin_path, resolved) = run_release_build(cargo_args, config);
let package_name = resolved.name();
let version = resolved.version();
let description = resolved
.package
.as_ref()
.and_then(|p| p.description.clone())
.unwrap_or_else(|| format!("{package_name} (built with rsx)"));
let arch = deb_architecture(std::env::consts::ARCH);
let dist_dir = dist_dir(&resolved.workspace_root);
let staging = dist_dir.join("deb-staging").join(&package_name);
let _ = std::fs::remove_dir_all(&staging);
let debian_dir = staging.join("DEBIAN");
let bin_dir = staging.join("usr").join("bin");
let apps_dir = staging.join("usr").join("share").join("applications");
create_dir_or_exit(&debian_dir);
create_dir_or_exit(&bin_dir);
create_dir_or_exit(&apps_dir);
write_or_exit(
&debian_dir.join("control"),
deb_control_file(&package_name, &version, arch, &description),
);
stage_binary(&bin_path, &bin_dir.join(&package_name));
write_or_exit(
&apps_dir.join(format!("{package_name}.desktop")),
desktop_entry_file(&package_name, false),
);
let deb_path = dist_dir.join(format!("{package_name}_{version}_{arch}.deb"));
let mut cmd = Command::new("dpkg-deb");
cmd.arg("--build")
.arg("--root-owner-group")
.arg(&staging)
.arg(&deb_path);
run_bundler_tool(
&mut cmd,
"deb",
&deb_path,
Some(
"[cargo-telar] `dpkg-deb` is required for --format deb but was not found on PATH. On NixOS: `nix shell nixpkgs#dpkg`.",
),
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deb_architecture_maps_known_arches_and_passes_through_others() {
assert_eq!(deb_architecture("x86_64"), "amd64");
assert_eq!(deb_architecture("aarch64"), "arm64");
assert_eq!(deb_architecture("riscv64"), "riscv64");
}
#[test]
fn deb_control_file_has_required_fields_and_trailing_newline() {
let control = deb_control_file("myapp", "1.2.3", "amd64", "A neat app");
assert!(control.contains("Package: myapp\n"));
assert!(control.contains("Version: 1.2.3\n"));
assert!(control.contains("Architecture: amd64\n"));
assert!(control.contains("Maintainer: myapp maintainers <maintainer@example.invalid>\n"));
assert!(control.contains("Description: A neat app\n"));
assert!(control.ends_with('\n'));
}
}