Skip to content

Commit 9bc7a37

Browse files
committed
Auto merge of #9559 - tcmal:master, r=ehuss
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
2 parents d403db6 + 30ff842 commit 9bc7a37

7 files changed

Lines changed: 245 additions & 31 deletions

File tree

src/bin/cargo/commands/package.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,20 @@ pub fn cli() -> App {
2828
.arg_target_triple("Build for the target triple")
2929
.arg_target_dir()
3030
.arg_features()
31+
.arg_package_spec(
32+
"Package(s) to assemble",
33+
"Assemble all packages in the workspace",
34+
"Don't assemble specified packages",
35+
)
3136
.arg_manifest_path()
3237
.arg_jobs()
3338
.after_help("Run `cargo help package` for more detailed information.\n")
3439
}
3540

3641
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
3742
let ws = args.workspace(config)?;
43+
let specs = args.packages_from_flags()?;
44+
3845
ops::package(
3946
&ws,
4047
&PackageOpts {
@@ -43,10 +50,12 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
4350
list: args.is_present("list"),
4451
check_metadata: !args.is_present("no-metadata"),
4552
allow_dirty: args.is_present("allow-dirty"),
53+
to_package: specs,
4654
targets: args.targets(),
4755
jobs: args.jobs()?,
4856
cli_features: args.cli_features()?,
4957
},
5058
)?;
59+
5160
Ok(())
5261
}

src/bin/cargo/commands/publish.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub fn cli() -> App {
1818
))
1919
.arg_target_triple("Build for the target triple")
2020
.arg_target_dir()
21+
.arg_package("Package to publish")
2122
.arg_manifest_path()
2223
.arg_features()
2324
.arg_jobs()
@@ -41,6 +42,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
4142
index,
4243
verify: !args.is_present("no-verify"),
4344
allow_dirty: args.is_present("allow-dirty"),
45+
to_publish: args.packages_from_flags()?,
4446
targets: args.targets(),
4547
jobs: args.jobs()?,
4648
dry_run: args.is_present("dry-run"),

src/cargo/ops/cargo_package.rs

Lines changed: 70 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub struct PackageOpts<'cfg> {
2929
pub allow_dirty: bool,
3030
pub verify: bool,
3131
pub jobs: Option<u32>,
32+
pub to_package: ops::Packages,
3233
pub targets: Vec<String>,
3334
pub cli_features: CliFeatures,
3435
}
@@ -61,16 +62,12 @@ enum GeneratedFile {
6162
VcsInfo(String),
6263
}
6364

64-
pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Option<FileLock>> {
65-
if ws.root().join("Cargo.lock").exists() {
66-
// Make sure the Cargo.lock is up-to-date and valid.
67-
let _ = ops::resolve_ws(ws)?;
68-
// If Cargo.lock does not exist, it will be generated by `build_lock`
69-
// below, and will be validated during the verification step.
70-
}
71-
let pkg = ws.current()?;
65+
pub fn package_one(
66+
ws: &Workspace<'_>,
67+
pkg: &Package,
68+
opts: &PackageOpts<'_>,
69+
) -> CargoResult<Option<FileLock>> {
7270
let config = ws.config();
73-
7471
let mut src = PathSource::new(pkg.root(), pkg.package_id().source_id(), config);
7572
src.update()?;
7673

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

99-
let ar_files = build_ar_list(ws, pkg, src_files, vcs_info)?;
96+
let ar_files = build_ar_list(&ws, pkg, src_files, vcs_info)?;
10097

10198
if opts.list {
10299
for ar_file in ar_files {
103100
drop_println!(config, "{}", ar_file.rel_str);
104101
}
102+
105103
return Ok(None);
106104
}
107105

@@ -125,20 +123,65 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Option
125123
.shell()
126124
.status("Packaging", pkg.package_id().to_string())?;
127125
dst.file().set_len(0)?;
128-
tar(ws, ar_files, dst.file(), &filename)
126+
tar(&ws, pkg, ar_files, dst.file(), &filename)
129127
.with_context(|| "failed to prepare local package for uploading")?;
130128
if opts.verify {
131129
dst.seek(SeekFrom::Start(0))?;
132-
run_verify(ws, &dst, opts).with_context(|| "failed to verify package tarball")?
130+
run_verify(&ws, pkg, &dst, opts).with_context(|| "failed to verify package tarball")?
133131
}
132+
134133
dst.seek(SeekFrom::Start(0))?;
135-
{
136-
let src_path = dst.path();
137-
let dst_path = dst.parent().join(&filename);
138-
fs::rename(&src_path, &dst_path)
139-
.with_context(|| "failed to move temporary tarball into final location")?;
134+
let src_path = dst.path();
135+
let dst_path = dst.parent().join(&filename);
136+
fs::rename(&src_path, &dst_path)
137+
.with_context(|| "failed to move temporary tarball into final location")?;
138+
139+
return Ok(Some(dst));
140+
}
141+
142+
pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Option<Vec<FileLock>>> {
143+
let pkgs = ws.members_with_features(
144+
&opts.to_package.to_package_id_specs(ws)?,
145+
&opts.cli_features,
146+
)?;
147+
148+
let mut dsts = Vec::with_capacity(pkgs.len());
149+
150+
if ws.root().join("Cargo.lock").exists() {
151+
// Make sure the Cargo.lock is up-to-date and valid.
152+
let _ = ops::resolve_ws(&ws)?;
153+
// If Cargo.lock does not exist, it will be generated by `build_lock`
154+
// below, and will be validated during the verification step.
155+
}
156+
157+
for (pkg, cli_features) in pkgs {
158+
let result = package_one(
159+
ws,
160+
pkg,
161+
&PackageOpts {
162+
config: opts.config,
163+
list: opts.list,
164+
check_metadata: opts.check_metadata,
165+
allow_dirty: opts.allow_dirty,
166+
verify: opts.verify,
167+
jobs: opts.jobs,
168+
to_package: ops::Packages::Default,
169+
targets: opts.targets.clone(),
170+
cli_features: cli_features,
171+
},
172+
)?;
173+
174+
if !opts.list {
175+
dsts.push(result.unwrap());
176+
}
177+
}
178+
179+
if opts.list {
180+
// We're just listing, so there's no file output
181+
Ok(None)
182+
} else {
183+
Ok(Some(dsts))
140184
}
141-
Ok(Some(dst))
142185
}
143186

144187
/// Builds list of files to archive.
@@ -265,12 +308,11 @@ fn build_ar_list(
265308
}
266309

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

272315
// Convert Package -> TomlManifest -> Manifest -> Package
273-
let orig_pkg = ws.current()?;
274316
let toml_manifest = Rc::new(
275317
orig_pkg
276318
.manifest()
@@ -473,6 +515,7 @@ fn check_repo_state(
473515

474516
fn tar(
475517
ws: &Workspace<'_>,
518+
pkg: &Package,
476519
ar_files: Vec<ArchiveFile>,
477520
dst: &File,
478521
filename: &str,
@@ -485,7 +528,6 @@ fn tar(
485528

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

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

650-
fn run_verify(ws: &Workspace<'_>, tar: &FileLock, opts: &PackageOpts<'_>) -> CargoResult<()> {
692+
fn run_verify(
693+
ws: &Workspace<'_>,
694+
pkg: &Package,
695+
tar: &FileLock,
696+
opts: &PackageOpts<'_>,
697+
) -> CargoResult<()> {
651698
let config = ws.config();
652-
let pkg = ws.current()?;
653699

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

src/cargo/ops/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub use self::cargo_generate_lockfile::UpdateOptions;
1313
pub use self::cargo_install::{install, install_list};
1414
pub use self::cargo_new::{init, new, NewOptions, VersionControl};
1515
pub use self::cargo_output_metadata::{output_metadata, ExportInfo, OutputMetadataOptions};
16-
pub use self::cargo_package::{package, PackageOpts};
16+
pub use self::cargo_package::{package, package_one, PackageOpts};
1717
pub use self::cargo_pkgid::pkgid;
1818
pub use self::cargo_read_manifest::{read_package, read_packages};
1919
pub use self::cargo_run::run;

src/cargo/ops/registry.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,20 @@ pub struct PublishOpts<'cfg> {
5050
pub verify: bool,
5151
pub allow_dirty: bool,
5252
pub jobs: Option<u32>,
53+
pub to_publish: ops::Packages,
5354
pub targets: Vec<String>,
5455
pub dry_run: bool,
5556
pub registry: Option<String>,
5657
pub cli_features: CliFeatures,
5758
}
5859

5960
pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
60-
let pkg = ws.current()?;
61-
let mut publish_registry = opts.registry.clone();
61+
let specs = opts.to_publish.to_package_id_specs(ws)?;
62+
let mut pkgs = ws.members_with_features(&specs, &opts.cli_features)?;
63+
64+
let (pkg, cli_features) = pkgs.pop().unwrap();
6265

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

102106
// Prepare a tarball, with a non-suppressible warning if metadata
103107
// is missing since this is being put online.
104-
let tarball = ops::package(
105-
ws,
108+
let tarball = ops::package_one(
109+
&ws,
110+
pkg,
106111
&ops::PackageOpts {
107112
config: opts.config,
108113
verify: opts.verify,
109114
list: false,
110115
check_metadata: true,
111116
allow_dirty: opts.allow_dirty,
117+
to_package: ops::Packages::Default,
112118
targets: opts.targets.clone(),
113119
jobs: opts.jobs,
114-
cli_features: opts.cli_features.clone(),
120+
cli_features: cli_features.clone(),
115121
},
116122
)?
117123
.unwrap();
118124

119-
// Upload said tarball to the specified destination
120125
opts.config
121126
.shell()
122127
.status("Uploading", pkg.package_id().to_string())?;

tests/testsuite/package.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2105,3 +2105,59 @@ src/main.rs
21052105
.run();
21062106
p.cargo("package --allow-dirty").run();
21072107
}
2108+
2109+
#[cargo_test]
2110+
fn in_workspace() {
2111+
let p = project()
2112+
.file(
2113+
"Cargo.toml",
2114+
r#"
2115+
[project]
2116+
name = "foo"
2117+
version = "0.0.1"
2118+
authors = []
2119+
license = "MIT"
2120+
description = "foo"
2121+
2122+
[workspace]
2123+
members = ["bar"]
2124+
"#,
2125+
)
2126+
.file("src/main.rs", "fn main() {}")
2127+
.file(
2128+
"bar/Cargo.toml",
2129+
r#"
2130+
[project]
2131+
name = "bar"
2132+
version = "0.0.1"
2133+
authors = []
2134+
license = "MIT"
2135+
description = "bar"
2136+
workspace = ".."
2137+
"#,
2138+
)
2139+
.file("bar/src/main.rs", "fn main() {}")
2140+
.build();
2141+
2142+
p.cargo("package --workspace")
2143+
.with_stderr(
2144+
"\
2145+
[WARNING] manifest has no documentation, [..]
2146+
See [..]
2147+
[PACKAGING] bar v0.0.1 ([CWD]/bar)
2148+
[VERIFYING] bar v0.0.1 ([CWD]/bar)
2149+
[COMPILING] bar v0.0.1 ([CWD][..])
2150+
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2151+
[WARNING] manifest has no documentation, [..]
2152+
See [..]
2153+
[PACKAGING] foo v0.0.1 ([CWD])
2154+
[VERIFYING] foo v0.0.1 ([CWD])
2155+
[COMPILING] foo v0.0.1 ([CWD][..])
2156+
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2157+
",
2158+
)
2159+
.run();
2160+
2161+
assert!(p.root().join("target/package/foo-0.0.1.crate").is_file());
2162+
assert!(p.root().join("target/package/bar-0.0.1.crate").is_file());
2163+
}

0 commit comments

Comments
 (0)