Skip to content

Commit 630c9f3

Browse files
authored
publish: Read features metadata from embedded Cargo.toml file (#7215)
... instead of the metadata JSON blob
1 parent 1ab8427 commit 630c9f3

File tree

5 files changed

+23
-45
lines changed

5 files changed

+23
-45
lines changed

src/controllers/krate/publish.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,16 +185,27 @@ pub async fn publish(app: AppState, req: BytesRequest) -> AppResult<Json<GoodCra
185185
return Err(cargo_err("expected at most 5 categories per crate"));
186186
}
187187

188+
let features = tarball_info.manifest.features.unwrap_or_default();
189+
for (key, values) in features.iter() {
190+
if !Crate::valid_feature_name(key) {
191+
return Err(cargo_err(&format!(
192+
"\"{key}\" is an invalid feature name (feature names must contain only letters, numbers, '-', '+', or '_')"
193+
)));
194+
}
195+
196+
for value in values.iter() {
197+
if !Crate::valid_feature(value) {
198+
return Err(cargo_err(&format!("\"{value}\" is an invalid feature name")));
199+
}
200+
}
201+
}
202+
203+
188204
// Create a transaction on the database, if there are no errors,
189205
// commit the transactions to record a new or updated crate.
190206
conn.transaction(|conn| {
191207
let name = metadata.name;
192208
let vers = &*metadata.vers;
193-
let features = metadata
194-
.features
195-
.into_iter()
196-
.map(|(k, v)| (k.0, v.into_iter().map(|v| v.0).collect()))
197-
.collect();
198209
let keywords = keywords.iter().map(|s| s.as_str()).collect::<Vec<_>>();
199210
let categories = categories.iter().map(|s| s.as_str()).collect::<Vec<_>>();
200211

src/tests/builders/publish.rs

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use bytes::{BufMut, Bytes, BytesMut};
2-
use cargo_manifest::{DependencyDetail, DepsSet, FeatureSet, MaybeInherited};
2+
use cargo_manifest::{DependencyDetail, DepsSet, MaybeInherited};
33
use crates_io::models::DependencyKind;
44
use crates_io::views::krate_publish as u;
55
use std::collections::BTreeMap;
@@ -24,7 +24,7 @@ pub struct PublishBuilder {
2424
manifest: Manifest,
2525
readme: Option<String>,
2626
version: semver::Version,
27-
features: BTreeMap<u::EncodableFeatureName, Vec<u::EncodableFeature>>,
27+
features: BTreeMap<String, Vec<String>>,
2828
}
2929

3030
enum Manifest {
@@ -112,12 +112,8 @@ impl PublishBuilder {
112112

113113
// Adds a feature.
114114
pub fn feature(mut self, name: &str, values: &[&str]) -> Self {
115-
let values = values
116-
.iter()
117-
.map(|s| u::EncodableFeature(s.to_string()))
118-
.collect();
119-
self.features
120-
.insert(u::EncodableFeatureName(name.to_string()), values);
115+
let values = values.iter().map(ToString::to_string).collect();
116+
self.features.insert(name.to_string(), values);
121117
self
122118
}
123119

@@ -140,7 +136,6 @@ impl PublishBuilder {
140136
let metadata = u::PublishMetadata {
141137
name: u::EncodableCrateName(self.krate_name.clone()),
142138
vers: u::EncodableCrateVersion(self.version.clone()),
143-
features: self.features.clone(),
144139
deps: self.deps.clone(),
145140
readme: self.readme,
146141
readme_file: None,
@@ -180,7 +175,7 @@ impl PublishBuilder {
180175
build_dependencies: build_deps.none_or_filled(),
181176
dependencies: deps.none_or_filled(),
182177
dev_dependencies: dev_deps.none_or_filled(),
183-
features: convert_features(self.features).none_or_filled(),
178+
features: self.features.none_or_filled(),
184179
..Default::default()
185180
};
186181

@@ -277,15 +272,6 @@ fn is_simple_dependency(dep: &u::EncodableCrateDependency) -> bool {
277272
&& dep.registry.is_none()
278273
}
279274

280-
fn convert_features(
281-
encoded: BTreeMap<u::EncodableFeatureName, Vec<u::EncodableFeature>>,
282-
) -> FeatureSet {
283-
encoded
284-
.into_iter()
285-
.map(|(key, value)| (key.0, value.into_iter().map(|f| f.0).collect()))
286-
.collect()
287-
}
288-
289275
trait NoneOrFilled: Sized {
290276
fn none_or_filled(self) -> Option<Self>;
291277
}

src/tests/krate/publish/snapshots/all__krate__publish__features__invalid_feature.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ expression: response.into_json()
55
{
66
"errors": [
77
{
8-
"detail": "invalid upload request: invalid value: string \"!bar\", expected a valid feature name at line 1 column 65"
8+
"detail": "\"!bar\" is an invalid feature name"
99
}
1010
]
1111
}

src/tests/krate/publish/snapshots/all__krate__publish__features__invalid_feature_name.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ expression: response.into_json()
55
{
66
"errors": [
77
{
8-
"detail": "invalid upload request: invalid value: string \"~foo\", expected a valid feature name containing only letters, numbers, '-', '+', or '_' at line 1 column 57"
8+
"detail": "\"~foo\" is an invalid feature name (feature names must contain only letters, numbers, '-', '+', or '_')"
99
}
1010
]
1111
}

src/views/krate_publish.rs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
//! and manages the serialising and deserializing of this information
33
//! to and from structs. The serializing is only utilised in
44
//! integration tests.
5-
use std::collections::BTreeMap;
65
76
use diesel::pg::Pg;
87
use diesel::serialize::{self, Output, ToSql};
@@ -19,7 +18,6 @@ pub struct PublishMetadata {
1918
pub name: EncodableCrateName,
2019
pub vers: EncodableCrateVersion,
2120
pub deps: Vec<EncodableCrateDependency>,
22-
pub features: BTreeMap<EncodableFeatureName, Vec<EncodableFeature>>,
2321
pub readme: Option<String>,
2422
pub readme_file: Option<String>,
2523
}
@@ -84,23 +82,6 @@ impl<'de> Deserialize<'de> for EncodableDependencyName {
8482
}
8583
}
8684

87-
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Clone, Debug, Deref)]
88-
pub struct EncodableFeatureName(pub String);
89-
90-
impl<'de> Deserialize<'de> for EncodableFeatureName {
91-
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
92-
let s = String::deserialize(d)?;
93-
if !Crate::valid_feature_name(&s) {
94-
let value = de::Unexpected::Str(&s);
95-
let expected = "a valid feature name containing only letters, \
96-
numbers, '-', '+', or '_'";
97-
Err(de::Error::invalid_value(value, &expected))
98-
} else {
99-
Ok(EncodableFeatureName(s))
100-
}
101-
}
102-
}
103-
10485
#[derive(Serialize, Clone, Debug, Deref)]
10586
pub struct EncodableFeature(pub String);
10687

0 commit comments

Comments
 (0)