diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs index b32f2ed20d0..b33383422cd 100644 --- a/src/cargo/ops/cargo_package.rs +++ b/src/cargo/ops/cargo_package.rs @@ -732,7 +732,7 @@ fn tar( .iter() .map(|ar_file| ar_file.rel_path.clone()) .collect::>(); - let publish_pkg = prepare_for_publish(pkg, ws, &included)?; + let publish_pkg = prepare_for_publish(pkg, ws, Some(&included))?; let mut uncompressed_size = 0; for ar_file in ar_files { diff --git a/src/cargo/ops/registry/publish.rs b/src/cargo/ops/registry/publish.rs index 4ce5e36a50a..d00485355ca 100644 --- a/src/cargo/ops/registry/publish.rs +++ b/src/cargo/ops/registry/publish.rs @@ -3,7 +3,6 @@ //! [1]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html#publish use std::collections::BTreeMap; -use std::collections::BTreeSet; use std::collections::HashSet; use std::fs::File; use std::time::Duration; @@ -21,7 +20,6 @@ use crate::core::dependency::DepKind; use crate::core::manifest::ManifestMetadata; use crate::core::resolver::CliFeatures; use crate::core::Dependency; -use crate::core::FeatureValue; use crate::core::Package; use crate::core::PackageIdSpecQuery; use crate::core::SourceId; @@ -35,7 +33,7 @@ use crate::sources::CRATES_IO_REGISTRY; use crate::util::auth; use crate::util::cache_lock::CacheLockMode; use crate::util::context::JobsConfig; -use crate::util::interning::InternedString; +use crate::util::toml::prepare_for_publish; use crate::util::Progress; use crate::util::ProgressStyle; use crate::CargoResult; @@ -184,6 +182,7 @@ pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> { .status("Uploading", pkg.package_id().to_string())?; transmit( opts.gctx, + ws, pkg, tarball.file(), &mut registry, @@ -323,19 +322,19 @@ fn verify_dependencies( fn transmit( gctx: &GlobalContext, - pkg: &Package, + ws: &Workspace<'_>, + local_pkg: &Package, tarball: &File, registry: &mut Registry, registry_id: SourceId, dry_run: bool, ) -> CargoResult<()> { - let deps = pkg + let included = None; // don't filter build-targets + let publish_pkg = prepare_for_publish(local_pkg, ws, included)?; + + let deps = publish_pkg .dependencies() .iter() - .filter(|dep| { - // Skip dev-dependency without version. - dep.is_transitive() || dep.specified_req() - }) .map(|dep| { // If the dependency is from a different registry, then include the // registry in the dependency. @@ -380,7 +379,7 @@ fn transmit( }) }) .collect::>>()?; - let manifest = pkg.manifest(); + let manifest = publish_pkg.manifest(); let ManifestMetadata { ref authors, ref description, @@ -397,15 +396,19 @@ fn transmit( ref rust_version, } = *manifest.metadata(); let rust_version = rust_version.as_ref().map(ToString::to_string); - let readme_content = readme + let readme_content = local_pkg + .manifest() + .metadata() + .readme .as_ref() .map(|readme| { - paths::read(&pkg.root().join(readme)) - .with_context(|| format!("failed to read `readme` file for package `{}`", pkg)) + paths::read(&local_pkg.root().join(readme)).with_context(|| { + format!("failed to read `readme` file for package `{}`", local_pkg) + }) }) .transpose()?; - if let Some(ref file) = *license_file { - if !pkg.root().join(file).exists() { + if let Some(ref file) = local_pkg.manifest().metadata().license_file { + if !local_pkg.root().join(file).exists() { bail!("the license file `{}` does not exist", file) } } @@ -416,31 +419,13 @@ fn transmit( return Ok(()); } - let deps_set = deps - .iter() - .map(|dep| dep.name.clone()) - .collect::>(); - let string_features = match manifest.resolved_toml().features() { Some(features) => features .iter() .map(|(feat, values)| { ( feat.to_string(), - values - .iter() - .filter(|fv| { - let feature_value = FeatureValue::new(InternedString::new(fv)); - match feature_value { - FeatureValue::Dep { dep_name } - | FeatureValue::DepFeature { dep_name, .. } => { - deps_set.contains(&dep_name.to_string()) - } - _ => true, - } - }) - .map(|fv| fv.to_string()) - .collect(), + values.iter().map(|fv| fv.to_string()).collect(), ) }) .collect::>>(), @@ -450,8 +435,8 @@ fn transmit( let warnings = registry .publish( &NewCrate { - name: pkg.name().to_string(), - vers: pkg.version().to_string(), + name: local_pkg.name().to_string(), + vers: local_pkg.version().to_string(), deps, features: string_features, authors: authors.clone(), diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 5bd6f79fe48..ef66abf24d5 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -2575,7 +2575,7 @@ fn unused_dep_keys( pub fn prepare_for_publish( me: &Package, ws: &Workspace<'_>, - included: &[PathBuf], + included: Option<&[PathBuf]>, ) -> CargoResult { let contents = me.manifest().contents(); let document = me.manifest().document(); @@ -2612,7 +2612,7 @@ fn prepare_toml_for_publish( me: &manifest::TomlManifest, ws: &Workspace<'_>, package_root: &Path, - included: &[PathBuf], + included: Option<&[PathBuf]>, ) -> CargoResult { let gctx = ws.gctx(); @@ -2629,7 +2629,8 @@ fn prepare_toml_for_publish( package.workspace = None; if let Some(StringOrBool::String(path)) = &package.build { let path = paths::normalize_path(Path::new(path)); - let build = if included.contains(&path) { + let included = included.map(|i| i.contains(&path)).unwrap_or(true); + let build = if included { let path = path .into_os_string() .into_string() @@ -2898,7 +2899,7 @@ fn prepare_toml_for_publish( fn prepare_targets_for_publish( targets: Option<&Vec>, - included: &[PathBuf], + included: Option<&[PathBuf]>, context: &str, gctx: &GlobalContext, ) -> CargoResult>> { @@ -2923,19 +2924,21 @@ fn prepare_targets_for_publish( fn prepare_target_for_publish( target: &manifest::TomlTarget, - included: &[PathBuf], + included: Option<&[PathBuf]>, context: &str, gctx: &GlobalContext, ) -> CargoResult> { let path = target.path.as_ref().expect("previously resolved"); let path = normalize_path(&path.0); - if !included.contains(&path) { - let name = target.name.as_ref().expect("previously resolved"); - gctx.shell().warn(format!( - "ignoring {context} `{name}` as `{}` is not included in the published package", - path.display() - ))?; - return Ok(None); + if let Some(included) = included { + if !included.contains(&path) { + let name = target.name.as_ref().expect("previously resolved"); + gctx.shell().warn(format!( + "ignoring {context} `{name}` as `{}` is not included in the published package", + path.display() + ))?; + return Ok(None); + } } let mut target = target.clone(); diff --git a/tests/testsuite/inheritable_workspace_fields.rs b/tests/testsuite/inheritable_workspace_fields.rs index 70fb61197f8..664e25602c1 100644 --- a/tests/testsuite/inheritable_workspace_fields.rs +++ b/tests/testsuite/inheritable_workspace_fields.rs @@ -752,11 +752,11 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "homepage": "https://www.rust-lang.org", "keywords": ["cli"], "license": "MIT", - "license_file": "../LICENSE", + "license_file": "LICENSE", "links": null, "name": "bar", "readme": "README.md", - "readme_file": "../README.md", + "readme_file": "README.md", "repository": "https://github.com/example/example", "rust_version": "1.60", "vers": "1.2.3" diff --git a/tests/testsuite/lints/implicit_features.rs b/tests/testsuite/lints/implicit_features.rs index 37a12ba69d9..174bc1d4a94 100644 --- a/tests/testsuite/lints/implicit_features.rs +++ b/tests/testsuite/lints/implicit_features.rs @@ -127,7 +127,7 @@ unused_optional_dependency = "allow" .masquerade_as_nightly_cargo(&["cargo-lints", "edition2024"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index -[LOCKING] 2 packages to latest Rust 1.81.0-nightly compatible versions +[LOCKING] 2 packages to latest Rust [..] compatible versions [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s diff --git a/tests/testsuite/publish.rs b/tests/testsuite/publish.rs index c03e726d6da..cb97657040d 100644 --- a/tests/testsuite/publish.rs +++ b/tests/testsuite/publish.rs @@ -1598,112 +1598,20 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. } #[cargo_test] -fn publish_dev_dep_no_version() { - let registry = RegistryBuilder::new().http_api().http_index().build(); - - let p = project() - .file( - "Cargo.toml", - r#" - [package] - name = "foo" - version = "0.1.0" - edition = "2015" - authors = [] - license = "MIT" - description = "foo" - documentation = "foo" - homepage = "foo" - repository = "foo" - - [dev-dependencies] - bar = { path = "bar" } - "#, - ) - .file("src/lib.rs", "") - .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) - .file("bar/src/lib.rs", "") - .build(); - - p.cargo("publish --no-verify") - .replace_crates_io(registry.index_url()) - .with_stderr_data(str![[r#" -[UPDATING] crates.io index -[PACKAGING] foo v0.1.0 ([ROOT]/foo) -[PACKAGED] 3 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) -[UPLOADING] foo v0.1.0 ([ROOT]/foo) -[UPLOADED] foo v0.1.0 to registry `crates-io` -[NOTE] waiting for `foo v0.1.0` to be available at registry `crates-io`. -You may press ctrl-c to skip waiting; the crate should be available shortly. -[PUBLISHED] foo v0.1.0 at registry `crates-io` - -"#]]) - .run(); - - publish::validate_upload_with_contents( - r#" - { - "authors": [], - "badges": {}, - "categories": [], - "deps": [], - "description": "foo", - "documentation": "foo", - "features": {}, - "homepage": "foo", - "keywords": [], - "license": "MIT", - "license_file": null, - "links": null, - "name": "foo", - "readme": null, - "readme_file": null, - "repository": "foo", - "rust_version": null, - "vers": "0.1.0" - } - "#, - "foo-0.1.0.crate", - &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs"], - &[( - "Cargo.toml", - &format!( - r#"{} -[package] -edition = "2015" -name = "foo" -version = "0.1.0" -authors = [] -build = false -autobins = false -autoexamples = false -autotests = false -autobenches = false -description = "foo" -homepage = "foo" -documentation = "foo" -readme = false -license = "MIT" -repository = "foo" - -[lib] -name = "foo" -path = "src/lib.rs" - -[dev-dependencies] -"#, - cargo::core::manifest::MANIFEST_PREAMBLE - ), - )], - ); -} - -#[cargo_test] -fn publish_with_feature_point_diff_kinds_dep() { +fn publish_dev_dep_stripping() { let registry = RegistryBuilder::new().http_api().http_index().build(); Package::new("normal-only", "1.0.0") .feature("cat", &[]) .publish(); + Package::new("optional-dep-feature", "1.0.0") + .feature("cat", &[]) + .publish(); + Package::new("optional-namespaced", "1.0.0") + .feature("cat", &[]) + .publish(); + Package::new("optional-renamed-namespaced", "1.0.0") + .feature("cat", &[]) + .publish(); Package::new("build-only", "1.0.0") .feature("cat", &[]) .publish(); @@ -1745,11 +1653,17 @@ fn publish_with_feature_point_diff_kinds_dep() { "target-build-only/cat", "target-dev-only/cat", "target-normal-and-dev/cat", + "optional-dep-feature/cat", + "dep:optional-namespaced", + "dep:optional-renamed-namespaced10", ] [dependencies] normal-only = { version = "1.0", features = ["cat"] } normal-and-dev = { version = "1.0", features = ["cat"] } + optional-dep-feature = { version = "1.0", features = ["cat"], optional = true } + optional-namespaced = { version = "1.0", features = ["cat"], optional = true } + optional-renamed-namespaced10 = { version = "1.0", features = ["cat"], optional = true, package = "optional-renamed-namespaced" } [build-dependencies] build-only = { version = "1.0", features = ["cat"] } @@ -1839,6 +1753,40 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "target": null, "version_req": "^1.0" }, + { + "default_features": true, + "features": [ + "cat" + ], + "kind": "normal", + "name": "optional-dep-feature", + "optional": true, + "target": null, + "version_req": "^1.0" + }, + { + "default_features": true, + "features": [ + "cat" + ], + "kind": "normal", + "name": "optional-namespaced", + "optional": true, + "target": null, + "version_req": "^1.0" + }, + { + "default_features": true, + "explicit_name_in_toml": "optional-renamed-namespaced10", + "features": [ + "cat" + ], + "kind": "normal", + "name": "optional-renamed-namespaced", + "optional": true, + "target": null, + "version_req": "^1.0" + }, { "default_features": true, "features": [ @@ -1915,7 +1863,10 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "normal-and-dev/cat", "target-normal-only/cat", "target-build-only/cat", - "target-normal-and-dev/cat" + "target-normal-and-dev/cat", + "optional-dep-feature/cat", + "dep:optional-namespaced", + "dep:optional-renamed-namespaced10" ] }, "homepage": "foo", @@ -1966,6 +1917,22 @@ features = ["cat"] version = "1.0" features = ["cat"] +[dependencies.optional-dep-feature] +version = "1.0" +features = ["cat"] +optional = true + +[dependencies.optional-namespaced] +version = "1.0" +features = ["cat"] +optional = true + +[dependencies.optional-renamed-namespaced10] +version = "1.0" +features = ["cat"] +optional = true +package = "optional-renamed-namespaced" + [dev-dependencies.normal-and-dev] version = "1.0" features = ["cat"] @@ -1982,6 +1949,9 @@ foo_feature = [ "target-normal-only/cat", "target-build-only/cat", "target-normal-and-dev/cat", + "optional-dep-feature/cat", + "dep:optional-namespaced", + "dep:optional-renamed-namespaced10", ] [target."cfg(unix)".dependencies.target-normal-and-dev] @@ -2005,6 +1975,7 @@ features = ["cat"] )], ); } + #[cargo_test] fn credentials_ambiguous_filename() { // `publish` generally requires a remote registry