Skip to content

Commit c87376e

Browse files
committed
fix: strip feature dep when dep is dev dep
1 parent e68cbd8 commit c87376e

File tree

3 files changed

+152
-17
lines changed

3 files changed

+152
-17
lines changed

src/cargo/ops/registry/publish.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::core::dependency::DepKind;
2020
use crate::core::manifest::ManifestMetadata;
2121
use crate::core::resolver::CliFeatures;
2222
use crate::core::Dependency;
23+
use crate::core::FeatureValue;
2324
use crate::core::Package;
2425
use crate::core::PackageIdSpecQuery;
2526
use crate::core::SourceId;
@@ -33,6 +34,7 @@ use crate::sources::CRATES_IO_REGISTRY;
3334
use crate::util::auth;
3435
use crate::util::cache_lock::CacheLockMode;
3536
use crate::util::context::JobsConfig;
37+
use crate::util::interning::InternedString;
3638
use crate::util::Progress;
3739
use crate::util::ProgressStyle;
3840
use crate::CargoResult;
@@ -411,14 +413,31 @@ fn transmit(
411413
gctx.shell().warn("aborting upload due to dry run")?;
412414
return Ok(());
413415
}
416+
let deps_map = deps
417+
.iter()
418+
.map(|dep| (InternedString::new(dep.name.as_str()), dep))
419+
.collect::<BTreeMap<InternedString, &NewCrateDependency>>();
414420

415421
let string_features = match manifest.original().features() {
416422
Some(features) => features
417423
.iter()
418424
.map(|(feat, values)| {
419425
(
420426
feat.to_string(),
421-
values.iter().map(|fv| fv.to_string()).collect(),
427+
values
428+
.iter()
429+
.filter(|fv| {
430+
let feature_value = FeatureValue::new(InternedString::new(fv));
431+
match feature_value {
432+
FeatureValue::Dep { dep_name }
433+
| FeatureValue::DepFeature { dep_name, .. } => {
434+
deps_map.contains_key(&dep_name)
435+
}
436+
_ => true,
437+
}
438+
})
439+
.map(|fv| fv.to_string())
440+
.collect(),
422441
)
423442
})
424443
.collect::<BTreeMap<String, Vec<String>>>(),

src/cargo/util/toml/mod.rs

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::core::compiler::{CompileKind, CompileTarget};
2222
use crate::core::dependency::{Artifact, ArtifactTarget, DepKind};
2323
use crate::core::manifest::{ManifestMetadata, TargetSourcePath, Warnings};
2424
use crate::core::resolver::ResolveBehavior;
25-
use crate::core::{find_workspace_root, resolve_relative_path, CliUnstable};
25+
use crate::core::{find_workspace_root, resolve_relative_path, CliUnstable, FeatureValue};
2626
use crate::core::{Dependency, Manifest, PackageId, Summary, Target};
2727
use crate::core::{Edition, EitherManifest, Feature, Features, VirtualManifest, Workspace};
2828
use crate::core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, WorkspaceRootConfig};
@@ -316,6 +316,12 @@ pub fn prepare_for_publish(
316316
}
317317
}
318318
let all = |_d: &manifest::TomlDependency| true;
319+
let dependencies = map_deps(gctx, me.dependencies.as_ref(), all)?;
320+
let dev_dependencies = map_deps(
321+
gctx,
322+
me.dev_dependencies(),
323+
manifest::TomlDependency::is_version_specified,
324+
)?;
319325
return Ok(manifest::TomlManifest {
320326
package: Some(package),
321327
project: None,
@@ -325,16 +331,16 @@ pub fn prepare_for_publish(
325331
example: me.example.clone(),
326332
test: me.test.clone(),
327333
bench: me.bench.clone(),
328-
dependencies: map_deps(gctx, me.dependencies.as_ref(), all)?,
329-
dev_dependencies: map_deps(
330-
gctx,
331-
me.dev_dependencies(),
332-
manifest::TomlDependency::is_version_specified,
333-
)?,
334+
dependencies: dependencies.clone(),
335+
dev_dependencies: dev_dependencies.clone(),
334336
dev_dependencies2: None,
335337
build_dependencies: map_deps(gctx, me.build_dependencies(), all)?,
336338
build_dependencies2: None,
337-
features: me.features.clone(),
339+
features: map_feature(
340+
me.features.as_ref(),
341+
dependencies.as_ref(),
342+
dev_dependencies.as_ref(),
343+
)?,
338344
target: match me.target.as_ref().map(|target_map| {
339345
target_map
340346
.iter()
@@ -368,6 +374,46 @@ pub fn prepare_for_publish(
368374
lints: me.lints.clone(),
369375
});
370376

377+
fn map_feature(
378+
features: Option<&BTreeMap<manifest::FeatureName, Vec<String>>>,
379+
deps: Option<&BTreeMap<manifest::PackageName, manifest::InheritableDependency>>,
380+
dev_deps: Option<&BTreeMap<manifest::PackageName, manifest::InheritableDependency>>,
381+
) -> CargoResult<Option<BTreeMap<manifest::FeatureName, Vec<String>>>> {
382+
let Some(features) = features else {
383+
return Ok(None);
384+
};
385+
let features = features
386+
.iter()
387+
.map(|(name, feature_deps)| {
388+
let feature_deps = feature_deps
389+
.iter()
390+
.filter(|feature_dep| {
391+
let feature_value = FeatureValue::new(InternedString::new(feature_dep));
392+
match feature_value {
393+
FeatureValue::Dep { dep_name }
394+
| FeatureValue::DepFeature { dep_name, .. } => {
395+
let k = &manifest::PackageName::new(dep_name.to_string()).unwrap();
396+
397+
if let Some(deps_map) = deps {
398+
return deps_map.contains_key(k);
399+
}
400+
if let Some(dev_deps_map) = dev_deps {
401+
return dev_deps_map.contains_key(k);
402+
}
403+
false
404+
}
405+
_ => true,
406+
}
407+
})
408+
.map(|feature_dep| feature_dep.to_string())
409+
.collect::<Vec<String>>();
410+
(name, feature_deps)
411+
})
412+
.map(|(name, feature_deps)| Ok((name.clone(), feature_deps)))
413+
.collect::<CargoResult<BTreeMap<_, _>>>()?;
414+
Ok(Some(features))
415+
}
416+
371417
fn map_deps(
372418
gctx: &GlobalContext,
373419
deps: Option<&BTreeMap<manifest::PackageName, manifest::InheritableDependency>>,
@@ -936,17 +982,34 @@ pub fn to_real_manifest(
936982
.unwrap_or_default();
937983
let empty_features = BTreeMap::new();
938984

985+
let deps_map = deps
986+
.iter()
987+
.filter(|dep| dep.is_transitive() || dep.specified_req())
988+
.map(|dep| (dep.name_in_toml(), dep))
989+
.collect::<BTreeMap<InternedString, &Dependency>>();
939990
let summary = Summary::new(
940991
pkgid,
941-
deps,
992+
deps.clone(),
942993
&me.features
943994
.as_ref()
944995
.unwrap_or(&empty_features)
945996
.iter()
946997
.map(|(k, v)| {
947998
(
948999
InternedString::new(k),
949-
v.iter().map(InternedString::from).collect(),
1000+
v.iter()
1001+
.filter(|feature_dep| {
1002+
let feature_value = FeatureValue::new(InternedString::new(feature_dep));
1003+
match feature_value {
1004+
FeatureValue::Dep { dep_name }
1005+
| FeatureValue::DepFeature { dep_name, .. } => {
1006+
deps_map.contains_key(&dep_name)
1007+
}
1008+
_ => true,
1009+
}
1010+
})
1011+
.map(InternedString::from)
1012+
.collect(),
9501013
)
9511014
})
9521015
.collect(),

tests/testsuite/publish.rs

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,7 +1687,7 @@ repository = "foo"
16871687
}
16881688

16891689
#[cargo_test]
1690-
fn invalid_publish_feature_point_to_stripped_dep() {
1690+
fn publish_feature_point_to_stripped_dep() {
16911691
let registry = RegistryBuilder::new().http_api().http_index().build();
16921692

16931693
let p = project()
@@ -1739,18 +1739,71 @@ fn invalid_publish_feature_point_to_stripped_dep() {
17391739

17401740
p.cargo("publish --no-verify")
17411741
.replace_crates_io(registry.index_url())
1742-
.with_status(101)
17431742
.with_stderr(
17441743
"\
17451744
[UPDATING] [..]
17461745
[PACKAGING] foo v0.1.0 [..]
1747-
[ERROR] failed to prepare local package for uploading
1748-
1749-
Caused by:
1750-
feature `foo_feature` includes `bar/cat`, but `bar` is not a dependency
1746+
[PACKAGED] [..] files, [..] ([..] compressed)
1747+
[UPLOADING] foo v0.1.0 [..]
1748+
[UPLOADED] foo v0.1.0 [..]
1749+
[NOTE] waiting [..]
1750+
You may press ctrl-c [..]
1751+
[PUBLISHED] foo v0.1.0 [..]
17511752
",
17521753
)
17531754
.run();
1755+
1756+
publish::validate_upload_with_contents(
1757+
r#"
1758+
{
1759+
"authors": [],
1760+
"badges": {},
1761+
"categories": [],
1762+
"deps": [],
1763+
"description": "foo",
1764+
"documentation": "foo",
1765+
"features": {
1766+
"foo_feature": []
1767+
},
1768+
"homepage": "foo",
1769+
"keywords": [],
1770+
"license": "MIT",
1771+
"license_file": null,
1772+
"links": null,
1773+
"name": "foo",
1774+
"readme": null,
1775+
"readme_file": null,
1776+
"repository": "foo",
1777+
"rust_version": null,
1778+
"vers": "0.1.0"
1779+
}
1780+
"#,
1781+
"foo-0.1.0.crate",
1782+
&["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"],
1783+
&[(
1784+
"Cargo.toml",
1785+
&format!(
1786+
r#"{}
1787+
[package]
1788+
edition = "2015"
1789+
name = "foo"
1790+
version = "0.1.0"
1791+
authors = []
1792+
description = "foo"
1793+
homepage = "foo"
1794+
documentation = "foo"
1795+
license = "MIT"
1796+
repository = "foo"
1797+
1798+
[dev-dependencies]
1799+
1800+
[features]
1801+
foo_feature = []
1802+
"#,
1803+
cargo::core::package::MANIFEST_PREAMBLE
1804+
),
1805+
)],
1806+
);
17541807
}
17551808
#[cargo_test]
17561809
fn credentials_ambiguous_filename() {

0 commit comments

Comments
 (0)