use std::path::PathBuf;
use anyhow::Context;
use clap::{crate_version, Parser};
use crate::config::{Config, PackageKey};
use crate::crates::{AutoPatches, CrateInfo};
use crate::debian::{self, DebInfo};
use crate::errors::Result;
use crate::util;
pub struct PackageProcess {
pub crate_info: CrateInfo,
pub deb_info: DebInfo,
pub config_path: Option<PathBuf>,
pub config: Config,
pub output_dir: Option<PathBuf>,
pub source_modified: bool,
pub auto_patches: AutoPatches,
pub temp_output_dir: Option<tempfile::TempDir>,
pub orig_tarball: Option<PathBuf>,
}
#[derive(Debug, Clone, Parser)]
pub struct PackageInitArgs {
pub crate_name: String,
pub version: Option<String>,
#[arg(long)]
pub config: Option<PathBuf>,
}
#[derive(Debug, Clone, Parser)]
pub struct PackageExtractArgs {
#[arg(long)]
pub directory: Option<PathBuf>,
}
#[derive(Debug, Clone, Parser)]
pub struct PackageExecuteArgs {
#[arg(long)]
pub changelog_ready: bool,
#[arg(long)]
pub copyright_guess_harder: bool,
#[arg(long)]
pub no_overlay_write_back: bool,
}
impl PackageProcess {
pub fn new(
mut crate_info: CrateInfo,
config_path: Option<PathBuf>,
config: Config,
) -> Result<Self> {
crate_info.set_includes_excludes(config.orig_tar_excludes(), config.orig_tar_whitelist());
let deb_info = DebInfo::new(
&crate_info,
crate_version!(),
config.semver_suffix,
config.repack_suffix(),
);
Ok(Self {
crate_info,
deb_info,
config_path,
config,
output_dir: None,
source_modified: false,
auto_patches: AutoPatches::new(),
temp_output_dir: None,
orig_tarball: None,
})
}
pub fn init(init_args: PackageInitArgs) -> Result<Self> {
let crate_name = &init_args.crate_name;
let version = init_args.version.as_deref();
let config = init_args.config;
let (config_path, config) = match config {
Some(path) => {
let config = Config::parse(&path).context("failed to parse debcargo.toml")?;
(Some(path), config)
}
None => (None, Config::default()),
};
let crate_path = config.crate_src_path(config_path.as_deref());
let crate_info = match crate_path {
Some(p) => CrateInfo::new_with_local_crate(crate_name, version, &p)?,
None => CrateInfo::new(crate_name, version)?,
};
Self::new(crate_info, config_path, config)
}
pub fn extract(&mut self, extract: PackageExtractArgs) -> Result<()> {
assert!(self.output_dir.is_none());
let Self {
crate_info,
deb_info,
config,
..
} = self;
let output_dir = extract
.directory
.unwrap_or_else(|| deb_info.package_source_dir().to_path_buf());
let (source_modified, manifest_normalization_patch) =
crate_info.extract_crate(&output_dir)?;
if source_modified && config.repack_suffix().is_none() {
debcargo_bail!("orig tarball has been modified, but no repack_suffix set -> please set repack_suffix in debcargo.toml!");
}
let mut auto_patches = AutoPatches::new();
if let Some(patch) = manifest_normalization_patch {
auto_patches.insert(
"auto-cargo-toml-normalization.patch".to_string(),
patch.into_bytes(),
);
}
if let Some(targets) = &config.filter_targets.as_ref() {
if !targets.is_empty() {
let toml_path = output_dir.join("Cargo.toml");
crate::crates::remove_targets_patch(&toml_path, targets, &mut auto_patches)?;
}
}
if let Some(target_types) = &config.remove_target_types.as_ref() {
if !target_types.is_empty() {
let toml_path = output_dir.join("Cargo.toml");
crate::crates::remove_target_types_patch(
&toml_path,
target_types,
&mut auto_patches,
)?;
}
}
if let Some(disabled) = config.remove_features.as_deref() {
if !disabled.is_empty() {
let toml_path = output_dir.join("Cargo.toml");
crate::crates::remove_features_patch(&toml_path, disabled, &mut auto_patches)?;
}
}
self.output_dir = Some(output_dir);
self.source_modified = source_modified;
self.auto_patches = auto_patches;
Ok(())
}
pub fn apply_overrides(&mut self) -> Result<()> {
assert!(self.temp_output_dir.is_none());
let Self {
crate_info,
config_path,
config,
output_dir,
auto_patches,
..
} = self;
let output_dir = output_dir.as_ref().unwrap();
let temp_output_dir = debian::apply_overlay_and_patches(
crate_info,
config_path.as_deref(),
config,
output_dir,
auto_patches,
)?;
self.temp_output_dir = Some(temp_output_dir);
Ok(())
}
pub fn prepare_orig_tarball(&mut self) -> Result<()> {
assert!(self.orig_tarball.is_none());
let Self {
crate_info,
deb_info,
output_dir,
source_modified,
..
} = self;
let output_dir = output_dir.as_ref().unwrap();
let orig_tarball = output_dir
.parent()
.unwrap()
.join(deb_info.orig_tarball_path());
debian::prepare_orig_tarball(crate_info, &orig_tarball, *source_modified)?;
self.orig_tarball = Some(orig_tarball);
Ok(())
}
pub fn prepare_debian_folder(&mut self, args: &PackageExecuteArgs) -> Result<()> {
let Self {
crate_info,
deb_info,
config_path,
config,
output_dir,
temp_output_dir,
auto_patches,
..
} = self;
let output_dir = output_dir.as_ref().unwrap();
let temp_output_dir = temp_output_dir.as_ref().unwrap();
debian::prepare_debian_folder(
crate_info,
deb_info,
config_path.as_deref(),
config,
output_dir,
temp_output_dir,
auto_patches,
args.changelog_ready,
args.copyright_guess_harder,
!args.no_overlay_write_back,
)?;
Ok(())
}
pub fn post_package_checks(&self) -> Result<()> {
let Self {
config_path,
config,
output_dir,
orig_tarball,
..
} = self;
let output_dir = output_dir.as_ref().unwrap();
let orig_tarball = orig_tarball.as_ref().unwrap();
let curdir = std::env::current_dir()?;
debcargo_info!(
concat!("Package Source: {}\n", "Original Tarball for package: {}\n"),
util::rel_p(output_dir, &curdir),
util::rel_p(orig_tarball, &curdir)
);
let fixmes = util::lookup_fixmes(output_dir)?;
if !fixmes.is_empty() {
debcargo_warn!("FIXME found in the following files.");
for f in fixmes {
if util::hint_file_for(&f).is_some() {
debcargo_warn!("\t(•) {}", util::rel_p(&f, &curdir));
} else {
debcargo_warn!("\t • {}", util::rel_p(&f, &curdir));
}
}
debcargo_warn!("");
debcargo_warn!("To fix, try combinations of the following: ");
match config_path.as_deref() {
None => debcargo_warn!("\t • Write a config file and use it with --config"),
Some(c) => {
debcargo_warn!("\t • Add or edit overrides in your config file:");
debcargo_warn!("\t {}", util::rel_p(c, &curdir));
}
}
match config.overlay_dir(config_path.as_deref()) {
None => debcargo_warn!("\t • Create an overlay directory and add it to your config file with overlay = \"/path/to/overlay\""),
Some(p) => {
debcargo_warn!("\t • Add or edit files in your overlay directory:");
debcargo_warn!("\t {}", util::rel_p(&p, &curdir));
}
}
}
if let Some(architecture) = self.config.package_architecture(PackageKey::BareLib) {
if architecture == &vec!["all"] {
debcargo_warn!("");
debcargo_warn!(
"'Architecture: all' override found for library package. This potentially breaks Multi-Arch,"
);
debcargo_warn!(
"see https://rust-team.pages.debian.net/book/policy.html#why-architecture-any."
);
}
}
Ok(())
}
}