Skip to content

Commit

Permalink
Auto merge of #9559 - tcmal:master, r=ehuss
Browse files Browse the repository at this point in the history
Allow publishing from workspace root.

Adds -p, --workspace, and --exclude to package and publish commands.

Uses ephemeral workspaces to avoid changing the existing functions too much.
There might be more `Finished dev [unoptimized + debuginfo] target` messages when packaging than there should be, I couldn't figure out what was generating them.
The tests aren't super extensive, as all the specs from arguments code should already be tested elsewhere.

Closes #7345
  • Loading branch information
bors committed Jul 26, 2021
2 parents d403db6 + 30ff842 commit 9bc7a37
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 31 deletions.
9 changes: 9 additions & 0 deletions src/bin/cargo/commands/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,20 @@ pub fn cli() -> App {
.arg_target_triple("Build for the target triple")
.arg_target_dir()
.arg_features()
.arg_package_spec(
"Package(s) to assemble",
"Assemble all packages in the workspace",
"Don't assemble specified packages",
)
.arg_manifest_path()
.arg_jobs()
.after_help("Run `cargo help package` for more detailed information.\n")
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
let ws = args.workspace(config)?;
let specs = args.packages_from_flags()?;

ops::package(
&ws,
&PackageOpts {
Expand All @@ -43,10 +50,12 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
list: args.is_present("list"),
check_metadata: !args.is_present("no-metadata"),
allow_dirty: args.is_present("allow-dirty"),
to_package: specs,
targets: args.targets(),
jobs: args.jobs()?,
cli_features: args.cli_features()?,
},
)?;

Ok(())
}
2 changes: 2 additions & 0 deletions src/bin/cargo/commands/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub fn cli() -> App {
))
.arg_target_triple("Build for the target triple")
.arg_target_dir()
.arg_package("Package to publish")
.arg_manifest_path()
.arg_features()
.arg_jobs()
Expand All @@ -41,6 +42,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
index,
verify: !args.is_present("no-verify"),
allow_dirty: args.is_present("allow-dirty"),
to_publish: args.packages_from_flags()?,
targets: args.targets(),
jobs: args.jobs()?,
dry_run: args.is_present("dry-run"),
Expand Down
94 changes: 70 additions & 24 deletions src/cargo/ops/cargo_package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub struct PackageOpts<'cfg> {
pub allow_dirty: bool,
pub verify: bool,
pub jobs: Option<u32>,
pub to_package: ops::Packages,
pub targets: Vec<String>,
pub cli_features: CliFeatures,
}
Expand Down Expand Up @@ -61,16 +62,12 @@ enum GeneratedFile {
VcsInfo(String),
}

pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Option<FileLock>> {
if ws.root().join("Cargo.lock").exists() {
// Make sure the Cargo.lock is up-to-date and valid.
let _ = ops::resolve_ws(ws)?;
// If Cargo.lock does not exist, it will be generated by `build_lock`
// below, and will be validated during the verification step.
}
let pkg = ws.current()?;
pub fn package_one(
ws: &Workspace<'_>,
pkg: &Package,
opts: &PackageOpts<'_>,
) -> CargoResult<Option<FileLock>> {
let config = ws.config();

let mut src = PathSource::new(pkg.root(), pkg.package_id().source_id(), config);
src.update()?;

Expand All @@ -96,12 +93,13 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Option
None
};

let ar_files = build_ar_list(ws, pkg, src_files, vcs_info)?;
let ar_files = build_ar_list(&ws, pkg, src_files, vcs_info)?;

if opts.list {
for ar_file in ar_files {
drop_println!(config, "{}", ar_file.rel_str);
}

return Ok(None);
}

Expand All @@ -125,20 +123,65 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Option
.shell()
.status("Packaging", pkg.package_id().to_string())?;
dst.file().set_len(0)?;
tar(ws, ar_files, dst.file(), &filename)
tar(&ws, pkg, ar_files, dst.file(), &filename)
.with_context(|| "failed to prepare local package for uploading")?;
if opts.verify {
dst.seek(SeekFrom::Start(0))?;
run_verify(ws, &dst, opts).with_context(|| "failed to verify package tarball")?
run_verify(&ws, pkg, &dst, opts).with_context(|| "failed to verify package tarball")?
}

dst.seek(SeekFrom::Start(0))?;
{
let src_path = dst.path();
let dst_path = dst.parent().join(&filename);
fs::rename(&src_path, &dst_path)
.with_context(|| "failed to move temporary tarball into final location")?;
let src_path = dst.path();
let dst_path = dst.parent().join(&filename);
fs::rename(&src_path, &dst_path)
.with_context(|| "failed to move temporary tarball into final location")?;

return Ok(Some(dst));
}

pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Option<Vec<FileLock>>> {
let pkgs = ws.members_with_features(
&opts.to_package.to_package_id_specs(ws)?,
&opts.cli_features,
)?;

let mut dsts = Vec::with_capacity(pkgs.len());

if ws.root().join("Cargo.lock").exists() {
// Make sure the Cargo.lock is up-to-date and valid.
let _ = ops::resolve_ws(&ws)?;
// If Cargo.lock does not exist, it will be generated by `build_lock`
// below, and will be validated during the verification step.
}

for (pkg, cli_features) in pkgs {
let result = package_one(
ws,
pkg,
&PackageOpts {
config: opts.config,
list: opts.list,
check_metadata: opts.check_metadata,
allow_dirty: opts.allow_dirty,
verify: opts.verify,
jobs: opts.jobs,
to_package: ops::Packages::Default,
targets: opts.targets.clone(),
cli_features: cli_features,
},
)?;

if !opts.list {
dsts.push(result.unwrap());
}
}

if opts.list {
// We're just listing, so there's no file output
Ok(None)
} else {
Ok(Some(dsts))
}
Ok(Some(dst))
}

/// Builds list of files to archive.
Expand Down Expand Up @@ -265,12 +308,11 @@ fn build_ar_list(
}

/// Construct `Cargo.lock` for the package to be published.
fn build_lock(ws: &Workspace<'_>) -> CargoResult<String> {
fn build_lock(ws: &Workspace<'_>, orig_pkg: &Package) -> CargoResult<String> {
let config = ws.config();
let orig_resolve = ops::load_pkg_lockfile(ws)?;

// Convert Package -> TomlManifest -> Manifest -> Package
let orig_pkg = ws.current()?;
let toml_manifest = Rc::new(
orig_pkg
.manifest()
Expand Down Expand Up @@ -473,6 +515,7 @@ fn check_repo_state(

fn tar(
ws: &Workspace<'_>,
pkg: &Package,
ar_files: Vec<ArchiveFile>,
dst: &File,
filename: &str,
Expand All @@ -485,7 +528,6 @@ fn tar(

// Put all package files into a compressed archive.
let mut ar = Builder::new(encoder);
let pkg = ws.current()?;
let config = ws.config();

let base_name = format!("{}-{}", pkg.name(), pkg.version());
Expand Down Expand Up @@ -519,7 +561,7 @@ fn tar(
FileContents::Generated(generated_kind) => {
let contents = match generated_kind {
GeneratedFile::Manifest => pkg.to_registry_toml(ws)?,
GeneratedFile::Lockfile => build_lock(ws)?,
GeneratedFile::Lockfile => build_lock(ws, pkg)?,
GeneratedFile::VcsInfo(s) => s,
};
header.set_entry_type(EntryType::file());
Expand Down Expand Up @@ -647,9 +689,13 @@ fn check_yanked(config: &Config, pkg_set: &PackageSet<'_>, resolve: &Resolve) ->
Ok(())
}

fn run_verify(ws: &Workspace<'_>, tar: &FileLock, opts: &PackageOpts<'_>) -> CargoResult<()> {
fn run_verify(
ws: &Workspace<'_>,
pkg: &Package,
tar: &FileLock,
opts: &PackageOpts<'_>,
) -> CargoResult<()> {
let config = ws.config();
let pkg = ws.current()?;

config.shell().status("Verifying", pkg)?;

Expand Down
2 changes: 1 addition & 1 deletion src/cargo/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub use self::cargo_generate_lockfile::UpdateOptions;
pub use self::cargo_install::{install, install_list};
pub use self::cargo_new::{init, new, NewOptions, VersionControl};
pub use self::cargo_output_metadata::{output_metadata, ExportInfo, OutputMetadataOptions};
pub use self::cargo_package::{package, PackageOpts};
pub use self::cargo_package::{package, package_one, PackageOpts};
pub use self::cargo_pkgid::pkgid;
pub use self::cargo_read_manifest::{read_package, read_packages};
pub use self::cargo_run::run;
Expand Down
17 changes: 11 additions & 6 deletions src/cargo/ops/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,20 @@ pub struct PublishOpts<'cfg> {
pub verify: bool,
pub allow_dirty: bool,
pub jobs: Option<u32>,
pub to_publish: ops::Packages,
pub targets: Vec<String>,
pub dry_run: bool,
pub registry: Option<String>,
pub cli_features: CliFeatures,
}

pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
let pkg = ws.current()?;
let mut publish_registry = opts.registry.clone();
let specs = opts.to_publish.to_package_id_specs(ws)?;
let mut pkgs = ws.members_with_features(&specs, &opts.cli_features)?;

let (pkg, cli_features) = pkgs.pop().unwrap();

let mut publish_registry = opts.registry.clone();
if let Some(ref allowed_registries) = *pkg.publish() {
if publish_registry.is_none() && allowed_registries.len() == 1 {
// If there is only one allowed registry, push to that one directly,
Expand Down Expand Up @@ -101,22 +105,23 @@ pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {

// Prepare a tarball, with a non-suppressible warning if metadata
// is missing since this is being put online.
let tarball = ops::package(
ws,
let tarball = ops::package_one(
&ws,
pkg,
&ops::PackageOpts {
config: opts.config,
verify: opts.verify,
list: false,
check_metadata: true,
allow_dirty: opts.allow_dirty,
to_package: ops::Packages::Default,
targets: opts.targets.clone(),
jobs: opts.jobs,
cli_features: opts.cli_features.clone(),
cli_features: cli_features.clone(),
},
)?
.unwrap();

// Upload said tarball to the specified destination
opts.config
.shell()
.status("Uploading", pkg.package_id().to_string())?;
Expand Down
56 changes: 56 additions & 0 deletions tests/testsuite/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2105,3 +2105,59 @@ src/main.rs
.run();
p.cargo("package --allow-dirty").run();
}

#[cargo_test]
fn in_workspace() {
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
license = "MIT"
description = "foo"
[workspace]
members = ["bar"]
"#,
)
.file("src/main.rs", "fn main() {}")
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.0.1"
authors = []
license = "MIT"
description = "bar"
workspace = ".."
"#,
)
.file("bar/src/main.rs", "fn main() {}")
.build();

p.cargo("package --workspace")
.with_stderr(
"\
[WARNING] manifest has no documentation, [..]
See [..]
[PACKAGING] bar v0.0.1 ([CWD]/bar)
[VERIFYING] bar v0.0.1 ([CWD]/bar)
[COMPILING] bar v0.0.1 ([CWD][..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[WARNING] manifest has no documentation, [..]
See [..]
[PACKAGING] foo v0.0.1 ([CWD])
[VERIFYING] foo v0.0.1 ([CWD])
[COMPILING] foo v0.0.1 ([CWD][..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
)
.run();

assert!(p.root().join("target/package/foo-0.0.1.crate").is_file());
assert!(p.root().join("target/package/bar-0.0.1.crate").is_file());
}
Loading

0 comments on commit 9bc7a37

Please sign in to comment.