diff --git a/src/bin/cargo/commands/package.rs b/src/bin/cargo/commands/package.rs index 27b48097c6a..d938e0a3244 100644 --- a/src/bin/cargo/commands/package.rs +++ b/src/bin/cargo/commands/package.rs @@ -1,16 +1,22 @@ use crate::command_prelude::*; -use cargo::ops::{self, PackageOpts}; +use cargo::ops::{self, ListMode, PackageOpts}; +use clap::builder::PossibleValuesParser; pub fn cli() -> Command { subcommand("package") .about("Assemble the local package into a distributable tarball") .arg( - flag( + opt( "list", "Print files included in a package without making one", ) - .short('l'), + .short('l') + .default_missing_value("basic") + .num_args(0..=1) + .require_equals(true) + .value_name("MODE") + .value_parser(PossibleValuesParser::new(["basic", "json"])), ) .arg(flag( "no-verify", @@ -56,7 +62,11 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { &PackageOpts { gctx, verify: !args.flag("no-verify"), - list: args.flag("list"), + list: match args.get_one::("list").map(String::as_str) { + Some("json") => ListMode::Json, + Some(_) => ListMode::Basic, + None => ListMode::Disabled, + }, check_metadata: !args.flag("no-metadata"), allow_dirty: args.flag("allow-dirty"), to_package: specs, diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs index b32f2ed20d0..40944e8233b 100644 --- a/src/cargo/ops/cargo_package.rs +++ b/src/cargo/ops/cargo_package.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeSet, HashMap}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::fs::{self, File}; use std::io::prelude::*; use std::io::SeekFrom; @@ -31,7 +31,7 @@ use unicase::Ascii as UncasedAscii; #[derive(Clone)] pub struct PackageOpts<'gctx> { pub gctx: &'gctx GlobalContext, - pub list: bool, + pub list: ListMode, pub check_metadata: bool, pub allow_dirty: bool, pub verify: bool, @@ -42,6 +42,25 @@ pub struct PackageOpts<'gctx> { pub cli_features: CliFeatures, } +/// Possible values for the --list flag. +#[derive(Clone, Copy)] +pub enum ListMode { + /// Basic mode: just output the paths that would be included in the package file. + Basic, + + /// JSON mode: output the paths that would be included and their sources. + Json, + + /// Listing disabled; normal package operation. + Disabled, +} + +impl ListMode { + fn is_disabled(&self) -> bool { + matches!(self, &ListMode::Disabled) + } +} + const ORIGINAL_MANIFEST_FILE: &str = "Cargo.toml.orig"; const VCS_INFO_FILE: &str = ".cargo_vcs_info.json"; @@ -55,6 +74,7 @@ struct ArchiveFile { contents: FileContents, } +#[derive(Serialize)] enum FileContents { /// Absolute path to the file on disk to add to the archive. OnDisk(PathBuf), @@ -62,6 +82,7 @@ enum FileContents { Generated(GeneratedFile), } +#[derive(Serialize)] enum GeneratedFile { /// Generates `Cargo.toml` by rewriting the original. Manifest, @@ -98,7 +119,7 @@ pub fn package_one( pkg: &Package, opts: &PackageOpts<'_>, ) -> CargoResult { - assert!(!opts.list); + assert!(opts.list.is_disabled()); let ar_files = prepare_archive(ws, pkg, opts)?; let tarball = create_package(ws, pkg, ar_files)?; @@ -194,25 +215,36 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult