mirror of https://github.com/rust-lang/cargo
feat(package+publish): package arguments
adds -p, --workspace, and --exclude to package command, and -p to publish command, as well as tests for both. closes #7345
This commit is contained in:
parent
9535dc3dfd
commit
8f1f0e40fd
|
@ -28,6 +28,11 @@ 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")
|
||||
|
@ -35,6 +40,8 @@ pub fn cli() -> App {
|
|||
|
||||
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||
let ws = args.workspace(config)?;
|
||||
let specs = args.packages_from_flags()?;
|
||||
|
||||
ops::package(
|
||||
&ws,
|
||||
&PackageOpts {
|
||||
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
@ -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"),
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
@ -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()?;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
|
@ -473,6 +515,7 @@ fn check_repo_state(
|
|||
|
||||
fn tar(
|
||||
ws: &Workspace<'_>,
|
||||
pkg: &Package,
|
||||
ar_files: Vec<ArchiveFile>,
|
||||
dst: &File,
|
||||
filename: &str,
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
@ -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)?;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -50,6 +50,7 @@ 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>,
|
||||
|
@ -57,9 +58,12 @@ pub struct PublishOpts<'cfg> {
|
|||
}
|
||||
|
||||
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,
|
||||
|
@ -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())?;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -56,6 +56,34 @@ fn validate_upload_foo() {
|
|||
);
|
||||
}
|
||||
|
||||
fn validate_upload_bar() {
|
||||
publish::validate_upload(
|
||||
r#"
|
||||
{
|
||||
"authors": [],
|
||||
"badges": {},
|
||||
"categories": [],
|
||||
"deps": [],
|
||||
"description": "bar",
|
||||
"documentation": null,
|
||||
"features": {},
|
||||
"homepage": null,
|
||||
"keywords": [],
|
||||
"license": "MIT",
|
||||
"license_file": null,
|
||||
"links": null,
|
||||
"name": "bar",
|
||||
"readme": null,
|
||||
"readme_file": null,
|
||||
"repository": null,
|
||||
"vers": "0.0.1"
|
||||
}
|
||||
"#,
|
||||
"bar-0.0.1.crate",
|
||||
&["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"],
|
||||
);
|
||||
}
|
||||
|
||||
fn validate_upload_foo_clean() {
|
||||
publish::validate_upload(
|
||||
CLEAN_FOO_JSON,
|
||||
|
@ -1704,3 +1732,71 @@ Caused by:
|
|||
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn in_workspace() {
|
||||
registry::init();
|
||||
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[workspace]
|
||||
members = ["foo", "bar"]
|
||||
"#,
|
||||
)
|
||||
.file(
|
||||
"foo/Cargo.toml",
|
||||
r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
license = "MIT"
|
||||
description = "foo"
|
||||
"#,
|
||||
)
|
||||
.file("foo/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("publish --no-verify --token sekrit -p foo")
|
||||
.with_stderr(&format!(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
[WARNING] manifest has no documentation, [..]
|
||||
See [..]
|
||||
[PACKAGING] foo v0.0.1 ([CWD]/foo)
|
||||
[UPLOADING] foo v0.0.1 ([CWD]/foo)
|
||||
"
|
||||
))
|
||||
.run();
|
||||
|
||||
validate_upload_foo();
|
||||
|
||||
p.cargo("publish --no-verify --token sekrit -p bar")
|
||||
.with_stderr(&format!(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
[WARNING] manifest has no documentation, [..]
|
||||
See [..]
|
||||
[PACKAGING] bar v0.0.1 ([CWD]/bar)
|
||||
[UPLOADING] bar v0.0.1 ([CWD]/bar)
|
||||
"
|
||||
))
|
||||
.run();
|
||||
|
||||
validate_upload_bar();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue