mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
Auto merge of #13518 - baby230211:fix/strip-feature-dev-dep, r=epage
fix: strip feature dep when dep is dev dep ### What does this PR try to resolve? This change aims to strip features dependencies without a version key to be published. If a dev-dependency is missing the version, it will be stripped from the packaged manifest. The features table may contains the deps in following places. - Target - normal - dev - build - normal-and-dev - normal - dev - build - normal-and-dev ### How should we test and review this PR? See the initial commit, it shows current behavior that will cause error when feature has deps that point to dev_dep and doesn't have a version specified. Title | orignal toml | published toml | ---- | ---- | ---- | Before | feature = ["dev-dep/feature"] <br/> [dev-dependencies] <br/> dev-dep = { .., features: ["feature"] } | feature = ["dev-dep/feature"] <br/> [dev-dependencies] <br/> dev-dep = { .., features: ["feature"] } | After | feature = ["dev-dep/feature"] <br/> [dev-dependencies] <br/> dev-dep = { .., features: ["feature"] } | feature = [] <br/> [dev-dependencies] ``` Fix: #12225
This commit is contained in:
commit
403fbe2b49
@ -3,6 +3,7 @@
|
|||||||
//! [1]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html#publish
|
//! [1]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html#publish
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -20,6 +21,7 @@ use crate::core::dependency::DepKind;
|
|||||||
use crate::core::manifest::ManifestMetadata;
|
use crate::core::manifest::ManifestMetadata;
|
||||||
use crate::core::resolver::CliFeatures;
|
use crate::core::resolver::CliFeatures;
|
||||||
use crate::core::Dependency;
|
use crate::core::Dependency;
|
||||||
|
use crate::core::FeatureValue;
|
||||||
use crate::core::Package;
|
use crate::core::Package;
|
||||||
use crate::core::PackageIdSpecQuery;
|
use crate::core::PackageIdSpecQuery;
|
||||||
use crate::core::SourceId;
|
use crate::core::SourceId;
|
||||||
@ -33,6 +35,7 @@ use crate::sources::CRATES_IO_REGISTRY;
|
|||||||
use crate::util::auth;
|
use crate::util::auth;
|
||||||
use crate::util::cache_lock::CacheLockMode;
|
use crate::util::cache_lock::CacheLockMode;
|
||||||
use crate::util::context::JobsConfig;
|
use crate::util::context::JobsConfig;
|
||||||
|
use crate::util::interning::InternedString;
|
||||||
use crate::util::Progress;
|
use crate::util::Progress;
|
||||||
use crate::util::ProgressStyle;
|
use crate::util::ProgressStyle;
|
||||||
use crate::CargoResult;
|
use crate::CargoResult;
|
||||||
@ -412,13 +415,31 @@ fn transmit(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let deps_set = deps
|
||||||
|
.iter()
|
||||||
|
.map(|dep| dep.name.clone())
|
||||||
|
.collect::<BTreeSet<String>>();
|
||||||
|
|
||||||
let string_features = match manifest.original().features() {
|
let string_features = match manifest.original().features() {
|
||||||
Some(features) => features
|
Some(features) => features
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(feat, values)| {
|
.map(|(feat, values)| {
|
||||||
(
|
(
|
||||||
feat.to_string(),
|
feat.to_string(),
|
||||||
values.iter().map(|fv| fv.to_string()).collect(),
|
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(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<BTreeMap<String, Vec<String>>>(),
|
.collect::<BTreeMap<String, Vec<String>>>(),
|
||||||
|
@ -9,8 +9,8 @@ use crate::AlreadyPrintedError;
|
|||||||
use anyhow::{anyhow, bail, Context as _};
|
use anyhow::{anyhow, bail, Context as _};
|
||||||
use cargo_platform::Platform;
|
use cargo_platform::Platform;
|
||||||
use cargo_util::paths;
|
use cargo_util::paths;
|
||||||
use cargo_util_schemas::manifest;
|
|
||||||
use cargo_util_schemas::manifest::RustVersion;
|
use cargo_util_schemas::manifest::RustVersion;
|
||||||
|
use cargo_util_schemas::manifest::{self, TomlManifest};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use lazycell::LazyCell;
|
use lazycell::LazyCell;
|
||||||
use pathdiff::diff_paths;
|
use pathdiff::diff_paths;
|
||||||
@ -21,7 +21,7 @@ use crate::core::compiler::{CompileKind, CompileTarget};
|
|||||||
use crate::core::dependency::{Artifact, ArtifactTarget, DepKind};
|
use crate::core::dependency::{Artifact, ArtifactTarget, DepKind};
|
||||||
use crate::core::manifest::{ManifestMetadata, TargetSourcePath, Warnings};
|
use crate::core::manifest::{ManifestMetadata, TargetSourcePath, Warnings};
|
||||||
use crate::core::resolver::ResolveBehavior;
|
use crate::core::resolver::ResolveBehavior;
|
||||||
use crate::core::{find_workspace_root, resolve_relative_path, CliUnstable};
|
use crate::core::{find_workspace_root, resolve_relative_path, CliUnstable, FeatureValue};
|
||||||
use crate::core::{Dependency, Manifest, PackageId, Summary, Target};
|
use crate::core::{Dependency, Manifest, PackageId, Summary, Target};
|
||||||
use crate::core::{Edition, EitherManifest, Feature, Features, VirtualManifest, Workspace};
|
use crate::core::{Edition, EitherManifest, Feature, Features, VirtualManifest, Workspace};
|
||||||
use crate::core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, WorkspaceRootConfig};
|
use crate::core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, WorkspaceRootConfig};
|
||||||
@ -316,7 +316,7 @@ pub fn prepare_for_publish(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let all = |_d: &manifest::TomlDependency| true;
|
let all = |_d: &manifest::TomlDependency| true;
|
||||||
return Ok(manifest::TomlManifest {
|
let mut manifest = manifest::TomlManifest {
|
||||||
package: Some(package),
|
package: Some(package),
|
||||||
project: None,
|
project: None,
|
||||||
profile: me.profile.clone(),
|
profile: me.profile.clone(),
|
||||||
@ -366,7 +366,52 @@ pub fn prepare_for_publish(
|
|||||||
badges: me.badges.clone(),
|
badges: me.badges.clone(),
|
||||||
cargo_features: me.cargo_features.clone(),
|
cargo_features: me.cargo_features.clone(),
|
||||||
lints: me.lints.clone(),
|
lints: me.lints.clone(),
|
||||||
});
|
};
|
||||||
|
strip_features(&mut manifest);
|
||||||
|
return Ok(manifest);
|
||||||
|
|
||||||
|
fn strip_features(manifest: &mut TomlManifest) {
|
||||||
|
fn insert_dep_name(
|
||||||
|
dep_name_set: &mut BTreeSet<manifest::PackageName>,
|
||||||
|
deps: Option<&BTreeMap<manifest::PackageName, manifest::InheritableDependency>>,
|
||||||
|
) {
|
||||||
|
let Some(deps) = deps else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
deps.iter().for_each(|(k, _v)| {
|
||||||
|
dep_name_set.insert(k.clone());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let mut dep_name_set = BTreeSet::new();
|
||||||
|
insert_dep_name(&mut dep_name_set, manifest.dependencies.as_ref());
|
||||||
|
insert_dep_name(&mut dep_name_set, manifest.dev_dependencies());
|
||||||
|
insert_dep_name(&mut dep_name_set, manifest.build_dependencies());
|
||||||
|
if let Some(target_map) = manifest.target.as_ref() {
|
||||||
|
target_map.iter().for_each(|(_k, v)| {
|
||||||
|
insert_dep_name(&mut dep_name_set, v.dependencies.as_ref());
|
||||||
|
insert_dep_name(&mut dep_name_set, v.dev_dependencies());
|
||||||
|
insert_dep_name(&mut dep_name_set, v.build_dependencies());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let features = manifest.features.as_mut();
|
||||||
|
|
||||||
|
let Some(features) = features else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
features.values_mut().for_each(|feature_deps| {
|
||||||
|
feature_deps.retain(|feature_dep| {
|
||||||
|
let feature_value = FeatureValue::new(InternedString::new(feature_dep));
|
||||||
|
match feature_value {
|
||||||
|
FeatureValue::Dep { dep_name } | FeatureValue::DepFeature { dep_name, .. } => {
|
||||||
|
let k = &manifest::PackageName::new(dep_name.to_string()).unwrap();
|
||||||
|
dep_name_set.contains(k)
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn map_deps(
|
fn map_deps(
|
||||||
gctx: &GlobalContext,
|
gctx: &GlobalContext,
|
||||||
|
@ -1686,6 +1686,304 @@ repository = "foo"
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn publish_with_feature_point_diff_kinds_dep() {
|
||||||
|
let registry = RegistryBuilder::new().http_api().http_index().build();
|
||||||
|
Package::new("normal-only", "1.0.0")
|
||||||
|
.feature("cat", &[])
|
||||||
|
.publish();
|
||||||
|
Package::new("build-only", "1.0.0")
|
||||||
|
.feature("cat", &[])
|
||||||
|
.publish();
|
||||||
|
Package::new("normal-and-dev", "1.0.0")
|
||||||
|
.feature("cat", &[])
|
||||||
|
.publish();
|
||||||
|
Package::new("target-normal-only", "1.0.0")
|
||||||
|
.feature("cat", &[])
|
||||||
|
.publish();
|
||||||
|
Package::new("target-build-only", "1.0.0")
|
||||||
|
.feature("cat", &[])
|
||||||
|
.publish();
|
||||||
|
Package::new("target-normal-and-dev", "1.0.0")
|
||||||
|
.feature("cat", &[])
|
||||||
|
.publish();
|
||||||
|
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"
|
||||||
|
|
||||||
|
|
||||||
|
[features]
|
||||||
|
foo_feature = [
|
||||||
|
"normal-only/cat",
|
||||||
|
"build-only/cat",
|
||||||
|
"dev-only/cat",
|
||||||
|
"normal-and-dev/cat",
|
||||||
|
"target-normal-only/cat",
|
||||||
|
"target-build-only/cat",
|
||||||
|
"target-dev-only/cat",
|
||||||
|
"target-normal-and-dev/cat",
|
||||||
|
]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
normal-only = { version = "1.0", features = ["cat"] }
|
||||||
|
normal-and-dev = { version = "1.0", features = ["cat"] }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
build-only = { version = "1.0", features = ["cat"] }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
dev-only = { path = "../dev-only", features = ["cat"] }
|
||||||
|
normal-and-dev = { version = "1.0", features = ["cat"] }
|
||||||
|
|
||||||
|
[target.'cfg(unix)'.dependencies]
|
||||||
|
target-normal-only = { version = "1.0", features = ["cat"] }
|
||||||
|
target-normal-and-dev = { version = "1.0", features = ["cat"] }
|
||||||
|
|
||||||
|
[target.'cfg(unix)'.build-dependencies]
|
||||||
|
target-build-only = { version = "1.0", features = ["cat"] }
|
||||||
|
|
||||||
|
[target.'cfg(unix)'.dev-dependencies]
|
||||||
|
target-dev-only = { path = "../dev-only", features = ["cat"] }
|
||||||
|
target-normal-and-dev = { version = "1.0", features = ["cat"] }
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/main.rs", "")
|
||||||
|
.file(
|
||||||
|
"dev-only/Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "dev-only"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2015"
|
||||||
|
authors = []
|
||||||
|
|
||||||
|
[features]
|
||||||
|
cat = []
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file(
|
||||||
|
"dev-only/src/lib.rs",
|
||||||
|
r#"
|
||||||
|
#[cfg(feature = "cat")]
|
||||||
|
pub fn cat() {}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
p.cargo("publish --no-verify")
|
||||||
|
.env("RUSTFLAGS", "--cfg unix")
|
||||||
|
.replace_crates_io(registry.index_url())
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[UPDATING] [..]
|
||||||
|
[PACKAGING] foo v0.1.0 [..]
|
||||||
|
[UPDATING] [..]
|
||||||
|
[PACKAGED] [..] files, [..] ([..] compressed)
|
||||||
|
[UPLOADING] foo v0.1.0 [..]
|
||||||
|
[UPLOADED] foo v0.1.0 [..]
|
||||||
|
[NOTE] waiting [..]
|
||||||
|
You may press ctrl-c [..]
|
||||||
|
[PUBLISHED] foo v0.1.0 [..]
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
publish::validate_upload_with_contents(
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
"authors": [],
|
||||||
|
"badges": {},
|
||||||
|
"categories": [],
|
||||||
|
"deps": [
|
||||||
|
{
|
||||||
|
"default_features": true,
|
||||||
|
"features": [
|
||||||
|
"cat"
|
||||||
|
],
|
||||||
|
"kind": "normal",
|
||||||
|
"name": "normal-and-dev",
|
||||||
|
"optional": false,
|
||||||
|
"target": null,
|
||||||
|
"version_req": "^1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default_features": true,
|
||||||
|
"features": [
|
||||||
|
"cat"
|
||||||
|
],
|
||||||
|
"kind": "normal",
|
||||||
|
"name": "normal-only",
|
||||||
|
"optional": false,
|
||||||
|
"target": null,
|
||||||
|
"version_req": "^1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default_features": true,
|
||||||
|
"features": [
|
||||||
|
"cat"
|
||||||
|
],
|
||||||
|
"kind": "dev",
|
||||||
|
"name": "normal-and-dev",
|
||||||
|
"optional": false,
|
||||||
|
"target": null,
|
||||||
|
"version_req": "^1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default_features": true,
|
||||||
|
"features": [
|
||||||
|
"cat"
|
||||||
|
],
|
||||||
|
"kind": "build",
|
||||||
|
"name": "build-only",
|
||||||
|
"optional": false,
|
||||||
|
"target": null,
|
||||||
|
"version_req": "^1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default_features": true,
|
||||||
|
"features": [
|
||||||
|
"cat"
|
||||||
|
],
|
||||||
|
"kind": "normal",
|
||||||
|
"name": "target-normal-and-dev",
|
||||||
|
"optional": false,
|
||||||
|
"target": "cfg(unix)",
|
||||||
|
"version_req": "^1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default_features": true,
|
||||||
|
"features": [
|
||||||
|
"cat"
|
||||||
|
],
|
||||||
|
"kind": "normal",
|
||||||
|
"name": "target-normal-only",
|
||||||
|
"optional": false,
|
||||||
|
"target": "cfg(unix)",
|
||||||
|
"version_req": "^1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default_features": true,
|
||||||
|
"features": [
|
||||||
|
"cat"
|
||||||
|
],
|
||||||
|
"kind": "build",
|
||||||
|
"name": "target-build-only",
|
||||||
|
"optional": false,
|
||||||
|
"target": "cfg(unix)",
|
||||||
|
"version_req": "^1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default_features": true,
|
||||||
|
"features": [
|
||||||
|
"cat"
|
||||||
|
],
|
||||||
|
"kind": "dev",
|
||||||
|
"name": "target-normal-and-dev",
|
||||||
|
"optional": false,
|
||||||
|
"target": "cfg(unix)",
|
||||||
|
"version_req": "^1.0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "foo",
|
||||||
|
"documentation": "foo",
|
||||||
|
"features": {
|
||||||
|
"foo_feature": [
|
||||||
|
"normal-only/cat",
|
||||||
|
"build-only/cat",
|
||||||
|
"normal-and-dev/cat",
|
||||||
|
"target-normal-only/cat",
|
||||||
|
"target-build-only/cat",
|
||||||
|
"target-normal-and-dev/cat"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"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.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"],
|
||||||
|
&[(
|
||||||
|
"Cargo.toml",
|
||||||
|
&format!(
|
||||||
|
r#"{}
|
||||||
|
[package]
|
||||||
|
edition = "2015"
|
||||||
|
name = "foo"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = []
|
||||||
|
description = "foo"
|
||||||
|
homepage = "foo"
|
||||||
|
documentation = "foo"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "foo"
|
||||||
|
|
||||||
|
[dependencies.normal-and-dev]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["cat"]
|
||||||
|
|
||||||
|
[dependencies.normal-only]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["cat"]
|
||||||
|
|
||||||
|
[dev-dependencies.normal-and-dev]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["cat"]
|
||||||
|
|
||||||
|
[build-dependencies.build-only]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["cat"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
foo_feature = [
|
||||||
|
"normal-only/cat",
|
||||||
|
"build-only/cat",
|
||||||
|
"normal-and-dev/cat",
|
||||||
|
"target-normal-only/cat",
|
||||||
|
"target-build-only/cat",
|
||||||
|
"target-normal-and-dev/cat",
|
||||||
|
]
|
||||||
|
|
||||||
|
[target."cfg(unix)".dependencies.target-normal-and-dev]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["cat"]
|
||||||
|
|
||||||
|
[target."cfg(unix)".dependencies.target-normal-only]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["cat"]
|
||||||
|
|
||||||
|
[target."cfg(unix)".build-dependencies.target-build-only]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["cat"]
|
||||||
|
|
||||||
|
[target."cfg(unix)".dev-dependencies.target-normal-and-dev]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["cat"]
|
||||||
|
"#,
|
||||||
|
cargo::core::package::MANIFEST_PREAMBLE
|
||||||
|
),
|
||||||
|
)],
|
||||||
|
);
|
||||||
|
}
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
fn credentials_ambiguous_filename() {
|
fn credentials_ambiguous_filename() {
|
||||||
// `publish` generally requires a remote registry
|
// `publish` generally requires a remote registry
|
||||||
|
Loading…
x
Reference in New Issue
Block a user