From 367059fa9c75a4ea10025ad6d1cba06c71258d98 Mon Sep 17 00:00:00 2001 From: Aria Beingessner Date: Mon, 18 Mar 2024 16:00:11 -0400 Subject: [PATCH] chore: remove duplicate linkage type --- cargo-dist-schema/src/lib.rs | 17 ++ cargo-dist/src/build/mod.rs | 2 +- cargo-dist/src/linkage.rs | 409 ++++++++++++++--------------------- cargo-dist/src/main.rs | 4 +- 4 files changed, 179 insertions(+), 253 deletions(-) diff --git a/cargo-dist-schema/src/lib.rs b/cargo-dist-schema/src/lib.rs index f67c43f4e..c1df5c1e7 100644 --- a/cargo-dist-schema/src/lib.rs +++ b/cargo-dist-schema/src/lib.rs @@ -651,6 +651,23 @@ impl Linkage { } } +impl Library { + /// Make a new Library with the given path and no source + pub fn new(path: String) -> Self { + Self { path, source: None } + } +} + +impl std::fmt::Display for Library { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if let Some(package) = &self.source { + write!(f, "{} ({package})", self.path) + } else { + write!(f, "{}", self.path) + } + } +} + /// Helper to read the raw version from serialized json fn dist_version(input: &str) -> Option { #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] diff --git a/cargo-dist/src/build/mod.rs b/cargo-dist/src/build/mod.rs index cf62555dd..08b6d22f0 100644 --- a/cargo-dist/src/build/mod.rs +++ b/cargo-dist/src/build/mod.rs @@ -187,7 +187,7 @@ impl BuildExpectations { }); linkage } else { - determine_linkage(src_path, target)?.to_schema() + determine_linkage(src_path, target)? }; let bin = dist.binary(src.idx); manifest.assets.insert( diff --git a/cargo-dist/src/linkage.rs b/cargo-dist/src/linkage.rs index 5fc05df9a..a6ddcc668 100644 --- a/cargo-dist/src/linkage.rs +++ b/cargo-dist/src/linkage.rs @@ -8,11 +8,10 @@ use std::{ use axoasset::SourceFile; use axoprocess::Cmd; use camino::Utf8PathBuf; -use cargo_dist_schema::DistManifest; +use cargo_dist_schema::{DistManifest, Library, Linkage}; use comfy_table::{presets::UTF8_FULL, Table}; use goblin::Object; use mach_object::{LoadCommand, OFile}; -use serde::{Deserialize, Serialize}; use crate::{config::Config, errors::*, gather_work, Artifact, DistGraph}; @@ -40,7 +39,7 @@ pub fn do_linkage(cfg: &Config, args: &LinkageArgs) -> Result<()> { if args.print_output { for report in &reports { - eprintln!("{}", report.report()); + eprintln!("{}", report_linkage(report)); } } if args.print_json { @@ -63,9 +62,7 @@ pub fn add_linkage_to_manifest( dist.dist_dir.clone(), )?; - manifest - .linkage - .extend(linkage.iter().map(|l| l.to_schema())); + manifest.linkage.extend(linkage); Ok(()) } @@ -105,253 +102,163 @@ fn fetch_linkage( Ok(reports) } -/// Information about dynamic libraries used by a binary -#[derive(Debug, Deserialize, Serialize)] -pub struct Linkage { - /// The filename of the binary - pub binary: String, - /// The target triple for which the binary was built - pub target: String, - /// Libraries included with the operating system - pub system: Vec, - /// Libraries provided by the Homebrew package manager - pub homebrew: Vec, - /// Public libraries not provided by the system and not managed by any package manager - pub public_unmanaged: Vec, - /// Libraries which don't fall into any other categories - pub other: Vec, - /// Frameworks, only used on macOS - pub frameworks: Vec, -} - -impl Linkage { - /// Formatted human-readable output - pub fn report(&self) -> String { - let mut table = Table::new(); - table - .load_preset(UTF8_FULL) - .set_header(vec!["Category", "Libraries"]) - .add_row(vec![ - "System", - self.system - .clone() - .into_iter() - .map(|l| l.to_string_pretty()) - .collect::>() - .join("\n") - .as_str(), - ]) - .add_row(vec![ - "Homebrew", - self.homebrew - .clone() - .into_iter() - .map(|l| l.to_string_pretty()) - .collect::>() - .join("\n") - .as_str(), - ]) - .add_row(vec![ - "Public (unmanaged)", - self.public_unmanaged - .clone() - .into_iter() - .map(|l| l.path) - .collect::>() - .join("\n") - .as_str(), - ]) - .add_row(vec![ - "Frameworks", - self.frameworks - .clone() - .into_iter() - .map(|l| l.path) - .collect::>() - .join("\n") - .as_str(), - ]) - .add_row(vec![ - "Other", - self.other - .clone() - .into_iter() - .map(|l| l.to_string_pretty()) - .collect::>() - .join("\n") - .as_str(), - ]); - - let s = format!( - r#"{} ({}): - -{table}"#, - self.binary, self.target, - ); - - s.to_owned() - } - - /// Construct a cargo_dist_schema::Linkage from a Linkage - pub fn to_schema(&self) -> cargo_dist_schema::Linkage { - cargo_dist_schema::Linkage { - binary: None, - target: None, - system: self.system.iter().map(|s| s.to_schema()).collect(), - homebrew: self.homebrew.iter().map(|s| s.to_schema()).collect(), - public_unmanaged: self - .public_unmanaged - .iter() - .map(|s| s.to_schema()) - .collect(), - other: self.other.iter().map(|s| s.to_schema()).collect(), - frameworks: self.frameworks.iter().map(|s| s.to_schema()).collect(), - } - } - - /// Constructs a Linkage from a cargo_dist_schema::Linkage - pub fn from_schema(other: &cargo_dist_schema::Linkage) -> Self { - Self { - binary: other.binary.clone().unwrap_or_default(), - target: other.target.clone().unwrap_or_default(), - system: other.system.iter().map(Library::from_schema).collect(), - homebrew: other.homebrew.iter().map(Library::from_schema).collect(), - public_unmanaged: other +/// Formatted human-readable output +pub fn report_linkage(linkage: &Linkage) -> String { + let mut table = Table::new(); + table + .load_preset(UTF8_FULL) + .set_header(vec!["Category", "Libraries"]) + .add_row(vec![ + "System", + linkage + .system + .clone() + .into_iter() + .map(|l| l.to_string()) + .collect::>() + .join("\n") + .as_str(), + ]) + .add_row(vec![ + "Homebrew", + linkage + .homebrew + .clone() + .into_iter() + .map(|l| l.to_string()) + .collect::>() + .join("\n") + .as_str(), + ]) + .add_row(vec![ + "Public (unmanaged)", + linkage .public_unmanaged - .iter() - .map(Library::from_schema) - .collect(), - other: other.other.iter().map(Library::from_schema).collect(), - frameworks: other.frameworks.iter().map(Library::from_schema).collect(), - } + .clone() + .into_iter() + .map(|l| l.path) + .collect::>() + .join("\n") + .as_str(), + ]) + .add_row(vec![ + "Frameworks", + linkage + .frameworks + .clone() + .into_iter() + .map(|l| l.path) + .collect::>() + .join("\n") + .as_str(), + ]) + .add_row(vec![ + "Other", + linkage + .other + .clone() + .into_iter() + .map(|l| l.to_string()) + .collect::>() + .join("\n") + .as_str(), + ]); + + use std::fmt::Write; + let mut output = String::new(); + if let (Some(bin), Some(target)) = (&linkage.binary, &linkage.target) { + writeln!(&mut output, "{} ({}):\n", bin, target).unwrap(); } + write!(&mut output, "{table}").unwrap(); + output } -/// Represents a dynamic library located somewhere on the system -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct Library { - /// The path to the library; on platforms without that information, it will be a basename instead - pub path: String, - /// The package from which a library comes, if relevant - #[serde(skip_serializing_if = "Option::is_none")] - pub source: Option, -} +/// Create a homebrew library for the given path +pub fn library_from_homebrew(library: String) -> Library { + // Doesn't currently support Homebrew installations in + // non-default locations + let brew_prefix = if library.starts_with("/opt/homebrew/opt/") { + Some("/opt/homebrew/opt/") + } else if library.starts_with("/usr/local/opt/") { + Some("/usr/local/opt/") + } else { + None + }; -impl Library { - fn new(library: String) -> Self { - Self { - path: library, - source: None, + if let Some(prefix) = brew_prefix { + let cloned = library.clone(); + let stripped = cloned.strip_prefix(prefix).unwrap(); + let mut package = stripped.split('/').next().unwrap().to_owned(); + + // The path alone isn't enough to determine the tap the formula + // came from. If the install receipt exists, we can use it to + // get the name of the source tap. + let receipt = Utf8PathBuf::from(&prefix) + .join(&package) + .join("INSTALL_RECEIPT.json"); + + // If the receipt doesn't exist or can't be loaded, that's not an + // error; we can fall back to the package basename we parsed out + // of the path. + if receipt.exists() { + let _ = SourceFile::load_local(&receipt) + .and_then(|file| file.deserialize_json()) + .map(|parsed: serde_json::Value| { + if let Some(tap) = parsed["source"]["tap"].as_str() { + if tap != "homebrew/core" { + package = format!("{tap}/{package}"); + } + } + }); } - } - fn to_schema(&self) -> cargo_dist_schema::Library { - cargo_dist_schema::Library { - path: self.path.clone(), - source: self.source.clone(), + Library { + path: library, + source: Some(package.to_owned()), } - } - - fn from_schema(other: &cargo_dist_schema::Library) -> Self { - Self { - path: other.path.clone(), - source: other.source.clone(), + } else { + Library { + path: library, + source: None, } } +} - fn from_homebrew(library: String) -> Self { - // Doesn't currently support Homebrew installations in - // non-default locations - let brew_prefix = if library.starts_with("/opt/homebrew/opt/") { - Some("/opt/homebrew/opt/") - } else if library.starts_with("/usr/local/opt/") { - Some("/usr/local/opt/") - } else { - None - }; - - if let Some(prefix) = brew_prefix { - let cloned = library.clone(); - let stripped = cloned.strip_prefix(prefix).unwrap(); - let mut package = stripped.split('/').nth(0).unwrap().to_owned(); - - // The path alone isn't enough to determine the tap the formula - // came from. If the install receipt exists, we can use it to - // get the name of the source tap. - let receipt = Utf8PathBuf::from(&prefix) - .join(&package) - .join("INSTALL_RECEIPT.json"); - - // If the receipt doesn't exist or can't be loaded, that's not an - // error; we can fall back to the package basename we parsed out - // of the path. - if receipt.exists() { - let _ = SourceFile::load_local(&receipt) - .and_then(|file| file.deserialize_json()) - .map(|parsed: serde_json::Value| { - if let Some(tap) = parsed["source"]["tap"].as_str() { - if tap != "homebrew/core" { - package = format!("{tap}/{package}"); - } - } - }); - } - - Self { - path: library, - source: Some(package.to_owned()), - } - } else { - Self { - path: library, - source: None, - } - } +/// Create an apt library for the given path +pub fn library_from_apt(library: String) -> DistResult { + // We can't get this information on other OSs + if std::env::consts::OS != "linux" { + return Ok(Library { + path: library, + source: None, + }); } - fn maybe_apt(library: String) -> DistResult { - // We can't get this information on other OSs - if std::env::consts::OS != "linux" { - return Ok(Self { - path: library, - source: None, - }); - } - - let process = Cmd::new("dpkg", "get linkage info from dpkg") - .arg("--search") - .arg(&library) - .output(); - match process { - Ok(output) => { - let output = String::from_utf8(output.stdout)?; - - let package = output.split(':').nth(0).unwrap(); - let source = if package.is_empty() { - None - } else { - Some(package.to_owned()) - }; + let process = Cmd::new("dpkg", "get linkage info from dpkg") + .arg("--search") + .arg(&library) + .output(); + match process { + Ok(output) => { + let output = String::from_utf8(output.stdout)?; + + let package = output.split(':').next().unwrap(); + let source = if package.is_empty() { + None + } else { + Some(package.to_owned()) + }; - Ok(Self { - path: library, - source, - }) - } - // Couldn't find a package for this file - Err(_) => Ok(Self { + Ok(Library { path: library, - source: None, - }), - } - } - - fn to_string_pretty(&self) -> String { - if let Some(package) = &self.source { - format!("{} ({package})", self.path).to_owned() - } else { - self.path.clone() + source, + }) } + // Couldn't find a package for this file + Err(_) => Ok(Library { + path: library, + source: None, + }), } } @@ -472,35 +379,37 @@ pub fn determine_linkage(path: &Utf8PathBuf, target: &str) -> DistResult Result<(), std::io::Erro fn print_human_linkage(out: &mut Term, report: &DistManifest) -> Result<(), std::io::Error> { for linkage in &report.linkage { - writeln!(out, "{}", Linkage::from_schema(linkage).report())?; + writeln!(out, "{}", linkage::report_linkage(linkage))?; } Ok(())