Skip to content

Commit 64f5b0c

Browse files
committed
feat(spec): Track git ref
1 parent 9b9c683 commit 64f5b0c

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

src/cargo/core/package_id_spec.rs

+42-5
Original file line numberDiff line numberDiff line change
@@ -115,20 +115,30 @@ impl PackageIdSpec {
115115
if let Some((kind_str, scheme)) = url.scheme().split_once('+') {
116116
match kind_str {
117117
"git" => {
118-
let git_ref = GitReference::DefaultBranch;
118+
let git_ref = GitReference::from_query(url.query_pairs());
119+
url.set_query(None);
119120
kind = Some(SourceKind::Git(git_ref));
120121
url = strip_url_protocol(&url);
121122
}
122123
"registry" => {
124+
if url.query().is_some() {
125+
bail!("cannot have a query string in a pkgid: {url}")
126+
}
123127
kind = Some(SourceKind::Registry);
124128
url = strip_url_protocol(&url);
125129
}
126130
"sparse" => {
131+
if url.query().is_some() {
132+
bail!("cannot have a query string in a pkgid: {url}")
133+
}
127134
kind = Some(SourceKind::SparseRegistry);
128135
// Leave `sparse` as part of URL, see `SourceId::new`
129136
// url = strip_url_protocol(&url);
130137
}
131138
"path" => {
139+
if url.query().is_some() {
140+
bail!("cannot have a query string in a pkgid: {url}")
141+
}
132142
if scheme != "file" {
133143
anyhow::bail!("`path+{scheme}` is unsupported; `path+file` and `file` schemes are supported");
134144
}
@@ -137,10 +147,10 @@ impl PackageIdSpec {
137147
}
138148
kind => anyhow::bail!("unsupported source protocol: {kind}"),
139149
}
140-
}
141-
142-
if url.query().is_some() {
143-
bail!("cannot have a query string in a pkgid: {}", url)
150+
} else {
151+
if url.query().is_some() {
152+
bail!("cannot have a query string in a pkgid: {url}")
153+
}
144154
}
145155

146156
let frag = url.fragment().map(|s| s.to_owned());
@@ -347,6 +357,11 @@ impl fmt::Display for PackageIdSpec {
347357
write!(f, "{protocol}+")?;
348358
}
349359
write!(f, "{}", url)?;
360+
if let Some(SourceKind::Git(git_ref)) = self.kind.as_ref() {
361+
if let Some(pretty) = git_ref.pretty_ref(true) {
362+
write!(f, "?{}", pretty)?;
363+
}
364+
}
350365
if url.path_segments().unwrap().next_back().unwrap() != &*self.name {
351366
printed_name = true;
352367
write!(f, "#{}", self.name)?;
@@ -625,6 +640,16 @@ mod tests {
625640
},
626641
"git+ssh://[email protected]/rust-lang/regex.git#[email protected]",
627642
);
643+
ok(
644+
"git+ssh://[email protected]/rust-lang/regex.git?branch=dev#[email protected]",
645+
PackageIdSpec {
646+
name: String::from("regex"),
647+
version: Some("1.4.3".parse().unwrap()),
648+
url: Some(Url::parse("ssh://[email protected]/rust-lang/regex.git").unwrap()),
649+
kind: Some(SourceKind::Git(GitReference::Branch("dev".to_owned()))),
650+
},
651+
"git+ssh://[email protected]/rust-lang/regex.git?branch=dev#[email protected]",
652+
);
628653
ok(
629654
"file:///path/to/my/project/foo",
630655
PackageIdSpec {
@@ -670,6 +695,18 @@ mod tests {
670695
PackageIdSpec::parse("foobar+https://github.com/rust-lang/crates.io-index").is_err()
671696
);
672697
assert!(PackageIdSpec::parse("path+https://github.com/rust-lang/crates.io-index").is_err());
698+
699+
// Only `git+` can use `?`
700+
assert!(PackageIdSpec::parse("file:///path/to/my/project/foo?branch=dev").is_err());
701+
assert!(PackageIdSpec::parse("path+file:///path/to/my/project/foo?branch=dev").is_err());
702+
assert!(PackageIdSpec::parse(
703+
"registry+https://github.com/rust-lang/cargo#0.52.0?branch=dev"
704+
)
705+
.is_err());
706+
assert!(PackageIdSpec::parse(
707+
"sparse+https://github.com/rust-lang/cargo#0.52.0?branch=dev"
708+
)
709+
.is_err());
673710
}
674711

675712
#[test]

src/doc/src/reference/pkgid-spec.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ The formal grammar for a Package Id Specification is:
2222

2323
```notrust
2424
spec := pkgname |
25-
[ kind "+" ] proto "://" hostname-and-path [ "#" ( pkgname | semver ) ]
25+
[ kind "+" ] proto "://" hostname-and-path [ "?" query] [ "#" ( pkgname | semver ) ]
26+
query = ( "branch" | "tag" | "rev" ) "=" ref
2627
pkgname := name [ ("@" | ":" ) semver ]
2728
semver := digits [ "." digits [ "." digits [ "-" prerelease ] [ "+" build ]]]
2829
@@ -56,6 +57,7 @@ The following are some examples of specs for several different git dependencies:
5657
| `https://github.com/rust-lang/cargo#[email protected]` | <nobr>`cargo-platform`</nobr> | `0.1.2` |
5758
| `ssh://[email protected]/rust-lang/regex.git#[email protected]` | `regex` | `1.4.3` |
5859
| `git+ssh://[email protected]/rust-lang/regex.git#[email protected]` | `regex` | `1.4.3` |
60+
| `git+ssh://[email protected]/rust-lang/regex.git?branch=dev#[email protected]` | `regex` | `1.4.3` |
5961

6062
Local packages on the filesystem can use `file://` URLs to reference them:
6163

tests/testsuite/pkgid.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,8 @@ foo v0.1.0 ([..]/foo)
277277
"\
278278
error: There are multiple `xyz` packages in your project, and the specification `xyz` is ambiguous.
279279
Please re-run this command with one of the following specifications:
280-
git+file://[..]/xyz#0.5.0
281-
git+file://[..]/xyz#0.5.0
280+
git+file://[..]/xyz?rev=[..]#0.5.0
281+
git+file://[..]/xyz?rev=[..]#0.5.0
282282
",
283283
)
284284
.run();

0 commit comments

Comments
 (0)