diff --git a/src/build/buildinfo.rs b/src/build/buildinfo.rs index 853b387..c892093 100644 --- a/src/build/buildinfo.rs +++ b/src/build/buildinfo.rs @@ -6,7 +6,7 @@ use std::collections::{HashMap, HashSet, VecDeque}; use std::path::Path; use crate::debian::checksums::FileChecksums; -use crate::debian::control::{parse_paragraphs, write_paragraph, Paragraph}; +use crate::debian::control::{Paragraph, parse_paragraphs, write_paragraph}; /// One installed package relevant for dependency resolution. #[derive(Debug, Clone)] @@ -52,13 +52,20 @@ impl StatusDb { }; let arch = para.get("Architecture").unwrap_or("").to_string(); if let (Some(version), false) = (para.get("Version"), arch.is_empty()) { - db.pkgs.entry(package.to_string()).or_default().push(InstalledPkg { - version: version.to_string(), - arch: arch.clone(), - }); + db.pkgs + .entry(package.to_string()) + .or_default() + .push(InstalledPkg { + version: version.to_string(), + arch: arch.clone(), + }); } - if para.get("Essential").map(|v| v.eq_ignore_ascii_case("yes")).unwrap_or(false) { + if para + .get("Essential") + .map(|v| v.eq_ignore_ascii_case("yes")) + .unwrap_or(false) + { db.essential.push(package.to_string()); } @@ -291,7 +298,10 @@ pub fn render_buildinfo(input: &BuildInfoInput) -> Paragraph { } /// Serialize and atomically write a `.buildinfo` file. -pub fn save_buildinfo(path: &Path, paragraph: &Paragraph) -> Result<(), Box> { +pub fn save_buildinfo( + path: &Path, + paragraph: &Paragraph, +) -> Result<(), Box> { let tmp = path.with_extension("new"); std::fs::write(&tmp, write_paragraph(paragraph)) .map_err(|e| format!("cannot write '{}': {}", tmp.display(), e))?; @@ -366,7 +376,10 @@ Architecture: amd64 #[test] fn wrap_binary_field() { assert_eq!(wrap_long("abc"), "abc"); - let long = (0..500).map(|i| i.to_string()).collect::>().join(" "); + let long = (0..500) + .map(|i| i.to_string()) + .collect::>() + .join(" "); let wrapped = wrap_long(&long); assert!(wrapped.contains('\n')); for line in wrapped.lines() { diff --git a/src/build/buildtype.rs b/src/build/buildtype.rs index a2240f4..e3c205d 100644 --- a/src/build/buildtype.rs +++ b/src/build/buildtype.rs @@ -114,7 +114,7 @@ impl BuildType { /// The architecture suffix used in artifact file names: /// host arch, `all` or `source`. - pub fn arch_suffix<'a>(self, host_arch: &'a str) -> &'a str { + pub fn arch_suffix(self, host_arch: &str) -> &str { if self.has_any(ARCH_DEP) { host_arch } else if self.has_any(ARCH_INDEP) { @@ -133,7 +133,10 @@ mod tests { 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("source,any").unwrap(), + SOURCE_ARCH_DEP + ); assert_eq!(BuildType::from_options("any,all").unwrap(), BINARY); assert!(BuildType::from_options("bogus").is_err()); } diff --git a/src/build/changes.rs b/src/build/changes.rs index c066c88..3038967 100644 --- a/src/build/changes.rs +++ b/src/build/changes.rs @@ -5,7 +5,7 @@ use std::path::Path; use crate::debian::checksums::FileChecksums; -use crate::debian::control::{write_paragraph, Paragraph}; +use crate::debian::control::{Paragraph, write_paragraph}; use crate::debian::files::FilesList; /// Everything needed to render a `.changes` file. @@ -165,7 +165,10 @@ mod tests { "verylongpkgname - short (udeb)" ); let long_summary = "x".repeat(100); - assert_eq!(format_description("p", "deb", &long_summary).len(), 10 + 3 + 65); + assert_eq!( + format_description("p", "deb", &long_summary).len(), + 10 + 3 + 65 + ); } #[test] @@ -230,7 +233,7 @@ mod tests { assert_eq!( files_value, "\n 8 utils optional pkg_1.0.dsc" - .replace("", &files_value.split_whitespace().next().unwrap_or("")) + .replace("", files_value.split_whitespace().next().unwrap_or("")) ); } } diff --git a/src/build/env.rs b/src/build/env.rs index 380b58f..ef6c3ae 100644 --- a/src/build/env.rs +++ b/src/build/env.rs @@ -54,14 +54,12 @@ pub fn arch_env(host_arch: Option<&str>) -> Result, Str cmd.args(["--host-arch", arch]); } - let output = cmd - .output() - .map_err(|e| { - format!( - "failed to run 'dpkg-architecture': {}. Is 'dpkg-dev' installed?", - e - ) - })?; + let output = cmd.output().map_err(|e| { + format!( + "failed to run 'dpkg-architecture': {}. Is 'dpkg-dev' installed?", + e + ) + })?; if !output.status.success() { return Err(format!( @@ -83,8 +81,7 @@ pub fn arch_env(host_arch: Option<&str>) -> Result, Str /// Read the current vendor name from `/etc/dpkg/origins/default` /// (its `Vendor:` or `Origin:` field), defaulting to `"debian"`. pub fn current_vendor() -> String { - read_vendor_from(Path::new("/etc/dpkg/origins/default")) - .unwrap_or_else(|| "debian".to_string()) + read_vendor_from(Path::new("/etc/dpkg/origins/default")).unwrap_or_else(|| "debian".to_string()) } fn read_vendor_from(path: &Path) -> Option { @@ -289,7 +286,7 @@ mod tests { let env = build_env(1787392800, 16, &[]); assert_eq!(env.get("SOURCE_DATE_EPOCH").unwrap(), "1787392800"); assert_eq!(env.get("DEB_BUILD_OPTIONS").unwrap(), "parallel=16"); - assert!(env.get("DEB_BUILD_PROFILES").is_none()); + assert!(!env.contains_key("DEB_BUILD_PROFILES")); let env = build_env(1, 4, &["nodoc".to_string(), "cross".to_string()]); assert_eq!(env.get("DEB_BUILD_PROFILES").unwrap(), "nodoc,cross"); diff --git a/src/build/mod.rs b/src/build/mod.rs index 9189f90..0f8b82b 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -17,7 +17,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use crate::debian::{ - parse_paragraphs, ChecksumEntry, ControlInfo, FileChecksums, FilesEntry, FilesList, + ChecksumEntry, ControlInfo, FileChecksums, FilesEntry, FilesList, parse_paragraphs, }; /// Options for a native source-package build. @@ -151,7 +151,10 @@ pub fn run_source_build( ); } Err(e) => { - log::warn!("failed to check for GPG key: {}, building without signing", e); + log::warn!( + "failed to check for GPG key: {}, building without signing", + e + ); } } } @@ -167,7 +170,12 @@ pub fn run_source_build( // ------------------------------------------------------------------ // 5. dpkg-source lifecycle: before-build + source build // ------------------------------------------------------------------ - run_command(cwd, "dpkg-source", &["-I", "-i", "--before-build", "."], &pipeline_env)?; + run_command( + cwd, + "dpkg-source", + &["-I", "-i", "--before-build", "."], + &pipeline_env, + )?; run_command(cwd, "dpkg-source", &["-I", "-i", "-b", "."], &pipeline_env)?; if !dsc_path.exists() { @@ -333,7 +341,12 @@ pub fn run_source_build( // ------------------------------------------------------------------ // 8. dpkg-source after-build (unapplies quilt patches it applied) // ------------------------------------------------------------------ - run_command(cwd, "dpkg-source", &["-I", "-i", "--after-build", "."], &pipeline_env)?; + run_command( + cwd, + "dpkg-source", + &["-I", "-i", "--after-build", "."], + &pipeline_env, + )?; // ------------------------------------------------------------------ // 9. Signing cascade: dsc -> buildinfo -> changes diff --git a/src/debian/changelog.rs b/src/debian/changelog.rs index e8ef4c7..3b2fac8 100644 --- a/src/debian/changelog.rs +++ b/src/debian/changelog.rs @@ -56,9 +56,13 @@ pub fn parse_changelog_entry(path: &Path) -> Result Vec { // Continuation line if line.starts_with(' ') || line.starts_with('\t') { let content = line.strip_prefix(' ').unwrap_or(line); - if let Some(field) = &last_field { - if let Some((_, v)) = current + if let Some(field) = &last_field + && let Some((_, v)) = current .fields .iter_mut() .rev() .find(|(k, _)| k.eq_ignore_ascii_case(field)) - { - v.push('\n'); - v.push_str(content); - continue; - } + { + v.push('\n'); + v.push_str(content); + continue; } // Continuation without a preceding field line: skip it (malformed) continue; @@ -174,7 +173,7 @@ mod tests { #[test] fn parse_multiline_and_comments() { let input = "# a comment\nDescription: short\n long description\n" // - .to_string() // + .to_string() + " spanning lines\n\nPackage: x\n"; let paras = parse_paragraphs(&input); assert_eq!(paras.len(), 2); @@ -190,7 +189,10 @@ mod tests { let mut p = Paragraph::new(); p.set("Description", value); let text = write_paragraph(&p); - assert_eq!(text, "Description: short\n long description\n spanning lines\n"); + assert_eq!( + text, + "Description: short\n long description\n spanning lines\n" + ); let reparsed = parse_paragraphs(&text); assert_eq!(reparsed[0].get("Description"), Some(value)); } @@ -228,12 +230,15 @@ impl ControlInfo { pub fn parse(path: &Path) -> Result> { let content = std::fs::read_to_string(path) .map_err(|e| format!("failed to read control file '{}': {}", path.display(), e))?; - Self::from_str(&content) + content + .parse::() .map_err(|e| format!("invalid control file '{}': {}", path.display(), e).into()) } /// Parse control content from a string. - pub fn from_str(content: &str) -> Result { + /// + /// Prefer [`std::str::FromStr`] (`"...".parse::()`). + pub fn parse_content(content: &str) -> Result { let paragraphs = parse_paragraphs(content); let mut iter = paragraphs.into_iter(); let source = iter @@ -267,9 +272,18 @@ impl ControlInfo { } } +impl std::str::FromStr for ControlInfo { + type Err = String; + + fn from_str(content: &str) -> Result { + ControlInfo::parse_content(content) + } +} + #[cfg(test)] mod control_info_tests { use super::*; + use std::str::FromStr; #[test] fn control_parsing() { diff --git a/src/debian/files.rs b/src/debian/files.rs index 77c4a4f..2f69469 100644 --- a/src/debian/files.rs +++ b/src/debian/files.rs @@ -61,8 +61,11 @@ pub fn parse_filename(name: &str) -> Option { if let Some(dot) = rest.rfind('.') { let arch = &rest[..dot]; let ptype = &rest[dot + 1..]; - let valid = |s: &str| !s.is_empty() - && s.chars().all(|c| c.is_ascii_alphanumeric() || "-+.:~".contains(c)); + let valid = |s: &str| { + !s.is_empty() + && s.chars() + .all(|c| c.is_ascii_alphanumeric() || "-+.:~".contains(c)) + }; if valid(pkg) && valid(version) && valid(arch) && valid(ptype) { return Some(FilesEntry { filename: name.to_string(), @@ -128,7 +131,11 @@ impl FilesList { return Err(format!("badly formed line in '{}': {}", path.display(), line).into()); } let mut entry = parse_filename(tokens[0]).ok_or_else(|| { - format!("badly formed file name in '{}': {}", path.display(), tokens[0]) + format!( + "badly formed file name in '{}': {}", + path.display(), + tokens[0] + ) })?; entry.section = tokens[1].to_string(); entry.priority = tokens[2].to_string(); diff --git a/src/debian/mod.rs b/src/debian/mod.rs index 2214d81..dee66a5 100644 --- a/src/debian/mod.rs +++ b/src/debian/mod.rs @@ -15,8 +15,8 @@ pub mod control; pub mod files; pub mod version; -pub use changelog::{parse_changelog_entry, ChangelogEntry}; +pub use changelog::{ChangelogEntry, parse_changelog_entry}; pub use checksums::{Entry as ChecksumEntry, FileChecksums}; -pub use control::{parse_paragraphs, write_paragraph, ControlInfo, Paragraph}; +pub use control::{ControlInfo, Paragraph, parse_paragraphs, write_paragraph}; pub use files::{FilesEntry, FilesList}; pub use version::DebianVersion; diff --git a/src/lib.rs b/src/lib.rs index 596a8b5..d27cf71 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,11 +9,11 @@ pub mod apt; pub mod build; /// Parse or edit a Debian changelog of a source package pub mod changelog; +/// Build a Debian package into a binary (.deb) +pub mod deb; /// Reusable Debian format primitives (control/deb822, checksums, versions, /// changelog entries, artifact registries) pub mod debian; -/// Build a Debian package into a binary (.deb) -pub mod deb; /// Obtain general information about distribution, series, etc pub mod distro_info; /// Obtain information about one or multiple packages diff --git a/src/utils/gpg.rs b/src/utils/gpg.rs index 2de9be3..4599999 100644 --- a/src/utils/gpg.rs +++ b/src/utils/gpg.rs @@ -46,9 +46,7 @@ pub fn find_signing_key_for_email( pub fn validate_key_id(keyid: &str) -> Result<(), Box> { let len = keyid.len(); if len <= 8 { - return Err( - "short OpenPGP key IDs are broken; use a key fingerprint instead".into(), - ); + return Err("short OpenPGP key IDs are broken; use a key fingerprint instead".into()); } else if len <= 16 { log::warn!( "long OpenPGP key IDs are strongly discouraged; \ @@ -65,10 +63,10 @@ pub fn validate_key_id(keyid: &str) -> Result<(), Box> { fn find_secret_key(ctx: &mut Context, keyid: &str) -> Result, Box> { for key_result in ctx.secret_keys()? { let key = key_result?; - if let Ok(fingerprint) = key.fingerprint() { - if fingerprint.ends_with(keyid) { - return Ok(Some(key)); - } + if let Ok(fingerprint) = key.fingerprint() + && fingerprint.ends_with(keyid) + { + return Ok(Some(key)); } } Ok(None)