Files
pkh/src/build/buildtype.rs
T
2026-08-23 01:46:04 +02:00

164 lines
5.3 KiB
Rust

//! Debian build types (`dpkg-buildpackage -b/-B/-A/-S/-g/-G/--build=...`)
//! and their mapping to `debian/rules` targets.
/// Build type bit flags, mirroring `Dpkg::BuildTypes`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BuildType(u8);
/// Source build component (`-S`, `--build=source`).
pub const SOURCE: BuildType = BuildType(0x1);
/// Arch-dependent binary build component (`-B`, `--build=any`).
pub const ARCH_DEP: BuildType = BuildType(0x2);
/// Arch-independent binary build component (`-A`, `--build=all`).
pub const ARCH_INDEP: BuildType = BuildType(0x4);
/// Any binary component.
pub const BINARY: BuildType = BuildType(ARCH_DEP.0 | ARCH_INDEP.0);
/// Normal full build: source + binaries (`-F`, default).
pub const FULL: BuildType = BuildType(SOURCE.0 | BINARY.0);
/// Source + arch-dependent (`-G`).
pub const SOURCE_ARCH_DEP: BuildType = BuildType(SOURCE.0 | ARCH_DEP.0);
/// Source + arch-indep (`-g`).
pub const SOURCE_ARCH_INDEP: BuildType = BuildType(SOURCE.0 | ARCH_INDEP.0);
impl BuildType {
/// Construct from raw bits.
pub const fn from_bits(bits: u8) -> Self {
BuildType(bits)
}
/// Raw bits.
pub const fn bits(self) -> u8 {
self.0
}
/// True if any of `other`'s components are set.
pub fn has_any(self, other: BuildType) -> bool {
self.0 & other.0 != 0
}
/// True if all of `other`'s components are set.
pub fn has_all(self, other: BuildType) -> bool {
self.0 & other.0 == other.0
}
/// True if none of `other`'s components are set.
pub fn has_none(self, other: BuildType) -> bool {
self.0 & other.0 == 0
}
/// Parse a comma-separated `--build=<type>[,...]` option value.
///
/// Valid components: `full`, `source`, `binary`, `any`, `all`.
pub fn from_options(value: &str) -> Result<BuildType, String> {
let mut result = BuildType(0);
for part in value.split(',') {
match part.trim() {
"full" => result = FULL,
"source" => result = BuildType(result.0 | SOURCE.0),
"binary" => result = BuildType(result.0 | BINARY.0),
"any" => result = BuildType(result.0 | ARCH_DEP.0),
"all" => result = BuildType(result.0 | ARCH_INDEP.0),
other => return Err(format!("unknown build type component '{}'", other)),
}
}
if result.0 == 0 {
return Err("empty build type".to_string());
}
Ok(result)
}
/// Canonical comma-separated representation (as passed to
/// `dpkg-genchanges --build=` / `dpkg-genbuildinfo --build=`).
pub fn to_options(self) -> String {
let mut parts = Vec::new();
if self.has_any(SOURCE) {
parts.push("source");
}
if self.has_all(BINARY) {
parts.push("binary");
} else {
if self.has_any(ARCH_DEP) {
parts.push("any");
}
if self.has_any(ARCH_INDEP) {
parts.push("all");
}
}
parts.join(",")
}
/// The `debian/rules` build target for this type:
/// `build`, `build-arch` or `build-indep`.
pub fn build_target(self) -> &'static str {
if self.has_all(BINARY) || self.has_none(BINARY) {
"build"
} else if self.has_any(ARCH_DEP) {
"build-arch"
} else {
"build-indep"
}
}
/// The `debian/rules` binary target for this type:
/// `binary`, `binary-arch` or `binary-indep`.
pub fn binary_target(self) -> &'static str {
if self.has_all(BINARY) || self.has_none(BINARY) {
"binary"
} else if self.has_any(ARCH_DEP) {
"binary-arch"
} else {
"binary-indep"
}
}
/// The architecture suffix used in artifact file names:
/// host arch, `all` or `source`.
pub fn arch_suffix(self, host_arch: &str) -> &str {
if self.has_any(ARCH_DEP) {
host_arch
} else if self.has_any(ARCH_INDEP) {
"all"
} else {
"source"
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_options() {
assert_eq!(BuildType::from_options("full").unwrap(), FULL);
assert_eq!(BuildType::from_options("source").unwrap(), SOURCE);
assert_eq!(
BuildType::from_options("source,any").unwrap(),
SOURCE_ARCH_DEP
);
assert_eq!(BuildType::from_options("any,all").unwrap(), BINARY);
assert!(BuildType::from_options("bogus").is_err());
}
#[test]
fn roundtrip_options() {
for t in [FULL, SOURCE, BINARY, SOURCE_ARCH_DEP, SOURCE_ARCH_INDEP] {
assert_eq!(BuildType::from_options(&t.to_options()).unwrap(), t);
}
}
#[test]
fn targets() {
assert_eq!(FULL.build_target(), "build");
assert_eq!(FULL.binary_target(), "binary");
assert_eq!(ARCH_DEP.build_target(), "build-arch");
assert_eq!(ARCH_DEP.binary_target(), "binary-arch");
assert_eq!(ARCH_INDEP.build_target(), "build-indep");
assert_eq!(ARCH_INDEP.binary_target(), "binary-indep");
assert_eq!(SOURCE.arch_suffix("amd64"), "source");
assert_eq!(ARCH_DEP.arch_suffix("amd64"), "amd64");
assert_eq!(ARCH_INDEP.arch_suffix("amd64"), "all");
}
}