Skip to content

Commit 75563da

Browse files
committed
Auto merge of #3049 - Turbo87:semver-req, r=jtgeibel
Save original dependency requirement string in the database when publishing This PR should resolve #3047 by saving the original dependency requirement string in the database when publishing, and returning the original string too when calling the `GET /crates/:crate_id/:version/dependencies` endpoint. Before #2990 we were turning `1.2.3` into `^1.2.3` automatically. After that PR were turning it into `>=1.2.3, <2.0.0`, and now, with this PR, we would keep it at `1.2.3` and it would be up to the API client to prefix the `^`, if necessary. r? `@jtgeibel` /cc `@dtolnay`
2 parents cd979d1 + c50c536 commit 75563da

File tree

7 files changed

+137
-27
lines changed

7 files changed

+137
-27
lines changed

src/models/dependency.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub struct Dependency {
2020
pub id: i32,
2121
pub version_id: i32,
2222
pub crate_id: i32,
23-
pub req: semver::VersionReq,
23+
pub req: String,
2424
pub optional: bool,
2525
pub default_features: bool,
2626
pub features: Vec<String>,
@@ -56,7 +56,7 @@ impl Dependency {
5656
id: self.id,
5757
version_id: self.version_id,
5858
crate_id: crate_name.into(),
59-
req: self.req.to_string(),
59+
req: self.req,
6060
optional: self.optional,
6161
default_features: self.default_features,
6262
features: self.features,
@@ -95,7 +95,7 @@ pub fn add_dependencies(
9595
let krate:Crate = Crate::by_exact_name(&dep.name)
9696
.first(&*conn)
9797
.map_err(|_| cargo_err(&format_args!("no known crate named `{}`", &*dep.name)))?;
98-
if dep.version_req == semver::VersionReq::parse("*").unwrap() {
98+
if semver::VersionReq::parse(&dep.version_req.0) == semver::VersionReq::parse("*") {
9999
return Err(cargo_err(WILDCARD_ERROR_MESSAGE));
100100
}
101101

src/tests/builders/dependency.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ impl DependencyBuilder {
1515
explicit_name_in_toml: None,
1616
name: name.to_string(),
1717
registry: None,
18-
version_req: u::EncodableCrateVersionReq(semver::VersionReq::parse(">= 0").unwrap()),
18+
version_req: u::EncodableCrateVersionReq("> 0".to_string()),
1919
}
2020
}
2121

@@ -38,10 +38,7 @@ impl DependencyBuilder {
3838
/// Panics if the `version_req` string specified isn't a valid `semver::VersionReq`.
3939
#[track_caller]
4040
pub fn version_req(mut self, version_req: &str) -> Self {
41-
self.version_req = u::EncodableCrateVersionReq(
42-
semver::VersionReq::parse(version_req)
43-
.expect("version req isn't a valid semver::VersionReq"),
44-
);
41+
self.version_req = u::EncodableCrateVersionReq(version_req.to_string());
4542
self
4643
}
4744

src/tests/builders/publish.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,7 @@ impl PublishBuilder {
180180
self
181181
}
182182

183-
/// Consume this builder to make the Put request body
184-
pub fn body(self) -> Vec<u8> {
183+
pub fn build(self) -> (String, Vec<u8>) {
185184
let new_crate = u::EncodableCrateUpload {
186185
name: u::EncodableCrateName(self.krate_name.clone()),
187186
vers: u::EncodableCrateVersion(self.version),
@@ -209,7 +208,16 @@ impl PublishBuilder {
209208
links: None,
210209
};
211210

212-
let json = serde_json::to_string(&new_crate).unwrap();
211+
(serde_json::to_string(&new_crate).unwrap(), self.tarball)
212+
}
213+
214+
/// Consume this builder to make the Put request body
215+
pub fn body(self) -> Vec<u8> {
216+
let (json, tarball) = self.build();
217+
PublishBuilder::create_publish_body(&json, &tarball)
218+
}
219+
220+
pub fn create_publish_body(json: &str, tarball: &[u8]) -> Vec<u8> {
213221
let mut body = Vec::new();
214222
body.extend(
215223
[
@@ -223,7 +231,6 @@ impl PublishBuilder {
223231
);
224232
body.extend(json.as_bytes().iter().cloned());
225233

226-
let tarball = &self.tarball;
227234
body.extend(&[
228235
tarball.len() as u8,
229236
(tarball.len() >> 8) as u8,
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
[
2+
{
3+
"request": {
4+
"uri": "http://alexcrichton-test.s3.amazonaws.com/crates/new_dep/new_dep-1.0.0.crate",
5+
"method": "PUT",
6+
"headers": [
7+
[
8+
"host",
9+
"alexcrichton-test.s3.amazonaws.com"
10+
],
11+
[
12+
"authorization",
13+
"AWS AKIAICL5IWUZYWWKA7JA:lH91IZJxBDr21vB3eSZXwXTQelk="
14+
],
15+
[
16+
"date",
17+
"Fri, 15 Sep 2017 07:53:06 -0700"
18+
],
19+
[
20+
"content-type",
21+
"application/x-tar"
22+
],
23+
[
24+
"accept-encoding",
25+
"gzip"
26+
],
27+
[
28+
"content-length",
29+
"35"
30+
],
31+
[
32+
"accept",
33+
"*/*"
34+
]
35+
],
36+
"body": "H4sIAAAAAAAA/+3AAQEAAACCIP+vbkhQwKsBLq+17wAEAAA="
37+
},
38+
"response": {
39+
"status": 200,
40+
"headers": [
41+
[
42+
"Server",
43+
"AmazonS3"
44+
],
45+
[
46+
"content-length",
47+
"0"
48+
],
49+
[
50+
"x-amz-request-id",
51+
"8190F375F5651D47"
52+
],
53+
[
54+
"x-amz-id-2",
55+
"PQEXq2S9IgVfG/u0l2cjHuWU8EDPlRSwxqai2oNPCz8TyX/CEwn2ydL+A1qnNK3Ng+FpC9ukVl8="
56+
],
57+
[
58+
"date",
59+
"Fri, 15 Sep 2017 14:53:07 GMT"
60+
],
61+
[
62+
"ETag",
63+
"\"f9016ad360cebb4fe2e6e96e5949f022\""
64+
]
65+
],
66+
"body": ""
67+
}
68+
}
69+
]

src/tests/krate/dependencies.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use cargo_registry::views::EncodableDependency;
55
use http::StatusCode;
66

77
#[derive(Deserialize)]
8-
struct Deps {
9-
dependencies: Vec<EncodableDependency>,
8+
pub struct Deps {
9+
pub dependencies: Vec<EncodableDependency>,
1010
}
1111

1212
#[test]

src/tests/krate/publish.rs

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,9 @@ fn new_with_renamed_dependency() {
173173

174174
#[test]
175175
fn new_krate_with_dependency() {
176-
let (app, _, user, token) = TestApp::full().with_token();
176+
use super::dependencies::Deps;
177+
178+
let (app, anon, user, token) = TestApp::full().with_token();
177179

178180
app.db(|conn| {
179181
// Insert a crate directly into the database so that new_dep can depend on it
@@ -183,12 +185,56 @@ fn new_krate_with_dependency() {
183185
CrateBuilder::new("foo-dep", user.as_model().id).expect_build(conn);
184186
});
185187

186-
let dependency = DependencyBuilder::new("foo-dep");
188+
let dependency = DependencyBuilder::new("foo-dep").version_req("1.0.0");
187189

188190
let crate_to_publish = PublishBuilder::new("new_dep")
189191
.version("1.0.0")
190192
.dependency(dependency);
193+
191194
token.enqueue_publish(crate_to_publish).good();
195+
196+
let dependencies = anon
197+
.get::<Deps>("/api/v1/crates/new_dep/1.0.0/dependencies")
198+
.good()
199+
.dependencies;
200+
201+
assert_eq!(dependencies.len(), 1);
202+
assert_eq!(dependencies[0].crate_id, "foo-dep");
203+
assert_eq!(dependencies[0].req, "1.0.0");
204+
}
205+
206+
#[test]
207+
fn new_krate_with_broken_dependency_requirement() {
208+
let (app, _, user, token) = TestApp::full().with_token();
209+
210+
app.db(|conn| {
211+
// Insert a crate directly into the database so that new_dep can depend on it
212+
// The name choice of `foo-dep` is important! It has the property of
213+
// name != canon_crate_name(name) and is a regression test for
214+
// https://github.com/rust-lang/crates.io/issues/651
215+
CrateBuilder::new("foo-dep", user.as_model().id).expect_build(conn);
216+
});
217+
218+
let dependency = DependencyBuilder::new("foo-dep").version_req("1.2.3");
219+
220+
let crate_to_publish = PublishBuilder::new("new_dep")
221+
.version("1.0.0")
222+
.dependency(dependency);
223+
224+
// create a request body with `version_req: "broken"`
225+
let (json, tarball) = crate_to_publish.build();
226+
let new_json = json.replace("\"version_req\":\"1.2.3\"", "\"version_req\":\"broken\"");
227+
assert_ne!(json, new_json);
228+
let body = PublishBuilder::create_publish_body(&new_json, &tarball);
229+
230+
let response = token
231+
.put::<serde_json::Value>("/api/v1/crates/new", &body)
232+
.good();
233+
234+
assert_eq!(
235+
response,
236+
json!({"errors": [{"detail": "invalid upload request: invalid value: string \"broken\", expected a valid version req at line 1 column 136"}]})
237+
);
192238
}
193239

194240
#[test]

src/views/krate_publish.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub struct EncodableCrateName(pub String);
4141
#[derive(Debug, Deref)]
4242
pub struct EncodableCrateVersion(pub semver::Version);
4343
#[derive(Debug, Deref)]
44-
pub struct EncodableCrateVersionReq(pub semver::VersionReq);
44+
pub struct EncodableCrateVersionReq(pub String);
4545
#[derive(Serialize, Debug, Deref, Default)]
4646
pub struct EncodableKeywordList(pub Vec<EncodableKeyword>);
4747
#[derive(Serialize, Debug, Deref)]
@@ -152,7 +152,7 @@ impl<'de> Deserialize<'de> for EncodableCrateVersionReq {
152152
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<EncodableCrateVersionReq, D::Error> {
153153
let s = String::deserialize(d)?;
154154
match semver::VersionReq::parse(&s) {
155-
Ok(v) => Ok(EncodableCrateVersionReq(v)),
155+
Ok(_) => Ok(EncodableCrateVersionReq(s)),
156156
Err(..) => {
157157
let value = de::Unexpected::Str(&s);
158158
let expected = "a valid version req";
@@ -162,15 +162,6 @@ impl<'de> Deserialize<'de> for EncodableCrateVersionReq {
162162
}
163163
}
164164

165-
impl<T: ?Sized> PartialEq<T> for EncodableCrateVersionReq
166-
where
167-
semver::VersionReq: PartialEq<T>,
168-
{
169-
fn eq(&self, rhs: &T) -> bool {
170-
self.0 == *rhs
171-
}
172-
}
173-
174165
impl<'de> Deserialize<'de> for EncodableKeywordList {
175166
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<EncodableKeywordList, D::Error> {
176167
let inner = <Vec<EncodableKeyword> as Deserialize<'de>>::deserialize(d)?;

0 commit comments

Comments
 (0)