Skip to content

Commit 7af951a

Browse files
authored
Merge pull request #2551 from integer32llc/short-version
Allow installing `major.minor` channels
2 parents 5674652 + 7efa731 commit 7af951a

File tree

3 files changed

+148
-15
lines changed

3 files changed

+148
-15
lines changed

doc/src/concepts/toolchains.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ Standard release channel toolchain names have the following form:
1515
```
1616
<channel>[-<date>][-<host>]
1717
18-
<channel> = stable|beta|nightly|<version>
18+
<channel> = stable|beta|nightly|<major.minor>|<major.minor.patch>
1919
<date> = YYYY-MM-DD
2020
<host> = <target-triple>
2121
```
2222

23-
'channel' is either a named release channel or an explicit version number,
24-
such as `1.42.0`. Channel names can be optionally appended with an archive
25-
date, as in `nightly-2014-12-18`, in which case the toolchain is downloaded
26-
from the archive for that date.
23+
'channel' is a named release channel, a major and minor version number such as
24+
`1.42`, or a fully specified version number, such as `1.42.0`. Channel names
25+
can be optionally appended with an archive date, as in `nightly-2014-12-18`, in
26+
which case the toolchain is downloaded from the archive for that date.
2727

2828
Finally, the host may be specified as a target triple. This is most useful for
2929
installing a 32-bit compiler on a 64-bit platform, or for installing the

src/cli/help.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,15 @@ pub static TOOLCHAIN_HELP: &str = r"DISCUSSION:
5555
5656
<channel>[-<date>][-<host>]
5757
58-
<channel> = stable|beta|nightly|<version>
58+
<channel> = stable|beta|nightly|<major.minor>|<major.minor.patch>
5959
<date> = YYYY-MM-DD
6060
<host> = <target-triple>
6161
62-
'channel' is either a named release channel or an explicit version
63-
number, such as '1.42.0'. Channel names can be optionally appended
64-
with an archive date, as in 'nightly-2017-05-09', in which case
65-
the toolchain is downloaded from the archive for that date.
62+
'channel' is a named release channel, a major and minor version
63+
number such as `1.42`, or a fully specified version number, such
64+
as `1.42.0`. Channel names can be optionally appended with an
65+
archive date, as in `nightly-2014-12-18`, in which case the
66+
toolchain is downloaded from the archive for that date.
6667
6768
The host may be specified as a target triple. This is most useful
6869
for installing a 32-bit compiler on a 64-bit platform, or for

src/dist/dist.rs

Lines changed: 137 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ static TOOLCHAIN_CHANNELS: &[&str] = &[
2828
"nightly",
2929
"beta",
3030
"stable",
31-
// Allow from 1.0.0 through to 9.999.99
32-
r"\d{1}\.\d{1,3}\.\d{1,2}",
31+
// Allow from 1.0.0 through to 9.999.99 with optional patch version
32+
r"\d{1}\.\d{1,3}(?:\.\d{1,2})?",
3333
];
3434

35-
#[derive(Debug)]
35+
#[derive(Debug, PartialEq)]
3636
struct ParsedToolchainDesc {
3737
channel: String,
3838
date: Option<String>,
@@ -52,7 +52,7 @@ pub struct PartialToolchainDesc {
5252
pub target: PartialTargetTriple,
5353
}
5454

55-
#[derive(Debug, Clone)]
55+
#[derive(Debug, Clone, PartialEq)]
5656
pub struct PartialTargetTriple {
5757
pub arch: Option<String>,
5858
pub os: Option<String>,
@@ -147,7 +147,7 @@ impl FromStr for ParsedToolchainDesc {
147147
fn from_str(desc: &str) -> Result<Self> {
148148
lazy_static! {
149149
static ref TOOLCHAIN_CHANNEL_PATTERN: String = format!(
150-
r"^({})(?:-(\d{{4}}-\d{{2}}-\d{{2}}))?(?:-(.*))?$",
150+
r"^({})(?:-(\d{{4}}-\d{{2}}-\d{{2}}))?(?:-(.+))?$",
151151
TOOLCHAIN_CHANNELS.join("|")
152152
);
153153
// Note this regex gives you a guaranteed match of the channel (1)
@@ -948,3 +948,135 @@ fn utc_from_manifest_date(date_str: &str) -> Option<Date<Utc>> {
948948
.ok()
949949
.map(|date| Utc.from_utc_date(&date))
950950
}
951+
952+
#[cfg(test)]
953+
mod tests {
954+
use super::*;
955+
956+
#[test]
957+
fn test_parsed_toolchain_desc_parse() {
958+
let success_cases = vec![
959+
("nightly", ("nightly", None, None)),
960+
("beta", ("beta", None, None)),
961+
("stable", ("stable", None, None)),
962+
("0.0", ("0.0", None, None)),
963+
("0.0.0", ("0.0.0", None, None)),
964+
("0.0.0--", ("0.0.0", None, Some("-"))), // possibly a bug?
965+
("9.999.99", ("9.999.99", None, None)),
966+
("0.0.0-anything", ("0.0.0", None, Some("anything"))),
967+
("0.0.0-0000-00-00", ("0.0.0", Some("0000-00-00"), None)),
968+
// possibly unexpected behavior, if someone typos a date?
969+
(
970+
"0.0.0-00000-000-000",
971+
("0.0.0", None, Some("00000-000-000")),
972+
),
973+
// possibly unexpected behavior, if someone forgets to add target after the hyphen?
974+
("0.0.0-0000-00-00-", ("0.0.0", None, Some("0000-00-00-"))),
975+
(
976+
"0.0.0-0000-00-00-any-other-thing",
977+
("0.0.0", Some("0000-00-00"), Some("any-other-thing")),
978+
),
979+
];
980+
981+
for (input, (channel, date, target)) in success_cases {
982+
let parsed = input.parse::<ParsedToolchainDesc>();
983+
assert!(
984+
parsed.is_ok(),
985+
"expected parsing of `{}` to succeed: {:?}",
986+
input,
987+
parsed
988+
);
989+
990+
let expected = ParsedToolchainDesc {
991+
channel: channel.into(),
992+
date: date.map(String::from),
993+
target: target.map(String::from),
994+
};
995+
assert_eq!(parsed.unwrap(), expected, "input: `{}`", input);
996+
}
997+
998+
let failure_cases = vec!["anything", "00.0000.000", "3", "", "--", "0.0.0-"];
999+
1000+
for input in failure_cases {
1001+
let parsed = input.parse::<ParsedToolchainDesc>();
1002+
assert!(
1003+
parsed.is_err(),
1004+
"expected parsing of `{}` to fail: {:?}",
1005+
input,
1006+
parsed
1007+
);
1008+
1009+
let error_message = format!("invalid toolchain name: '{}'", input);
1010+
1011+
assert_eq!(
1012+
parsed.unwrap_err().to_string(),
1013+
error_message,
1014+
"input: `{}`",
1015+
input
1016+
);
1017+
}
1018+
}
1019+
1020+
#[test]
1021+
fn test_partial_target_triple_new() {
1022+
let success_cases = vec![
1023+
("", (None, None, None)),
1024+
("i386", (Some("i386"), None, None)),
1025+
("pc-windows", (None, Some("pc-windows"), None)),
1026+
("gnu", (None, None, Some("gnu"))),
1027+
("i386-gnu", (Some("i386"), None, Some("gnu"))),
1028+
("pc-windows-gnu", (None, Some("pc-windows"), Some("gnu"))),
1029+
("i386-pc-windows", (Some("i386"), Some("pc-windows"), None)),
1030+
(
1031+
"i386-pc-windows-gnu",
1032+
(Some("i386"), Some("pc-windows"), Some("gnu")),
1033+
),
1034+
];
1035+
1036+
for (input, (arch, os, env)) in success_cases {
1037+
let partial_target_triple = PartialTargetTriple::new(input);
1038+
assert!(
1039+
partial_target_triple.is_some(),
1040+
"expected `{}` to create some partial target triple; got None",
1041+
input
1042+
);
1043+
1044+
let expected = PartialTargetTriple {
1045+
arch: arch.map(String::from),
1046+
os: os.map(String::from),
1047+
env: env.map(String::from),
1048+
};
1049+
1050+
assert_eq!(
1051+
partial_target_triple.unwrap(),
1052+
expected,
1053+
"input: `{}`",
1054+
input
1055+
);
1056+
}
1057+
1058+
let failure_cases = vec![
1059+
"anything",
1060+
"any-other-thing",
1061+
"-",
1062+
"--",
1063+
"i386-",
1064+
"i386-pc-",
1065+
"i386-pc-windows-",
1066+
"-pc-windows",
1067+
"i386-pc-windows-anything",
1068+
"0000-00-00-",
1069+
"00000-000-000",
1070+
];
1071+
1072+
for input in failure_cases {
1073+
let partial_target_triple = PartialTargetTriple::new(input);
1074+
assert!(
1075+
partial_target_triple.is_none(),
1076+
"expected `{}` to be `None`, was: `{:?}`",
1077+
input,
1078+
partial_target_triple
1079+
);
1080+
}
1081+
}
1082+
}

0 commit comments

Comments
 (0)