Skip to content

Commit 77bfca2

Browse files
committed
WIP: Thoughts on #2458
Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
1 parent 5674652 commit 77bfca2

File tree

3 files changed

+70
-10
lines changed

3 files changed

+70
-10
lines changed

src/config.rs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ impl OverrideFile {
3333
#[derive(Debug, Default, Deserialize, PartialEq, Eq)]
3434
struct ToolchainSection {
3535
channel: Option<String>,
36+
path: Option<String>,
3637
components: Option<Vec<String>>,
3738
targets: Option<Vec<String>>,
3839
}
@@ -45,11 +46,21 @@ impl ToolchainSection {
4546

4647
impl<T: Into<String>> From<T> for OverrideFile {
4748
fn from(channel: T) -> Self {
48-
Self {
49-
toolchain: ToolchainSection {
50-
channel: Some(channel.into()),
51-
..Default::default()
52-
},
49+
let channel = channel.into();
50+
if channel.contains('/') || channel.contains('\\') {
51+
Self {
52+
toolchain: ToolchainSection {
53+
path: Some(channel),
54+
..Default::default()
55+
},
56+
}
57+
} else {
58+
Self {
59+
toolchain: ToolchainSection {
60+
channel: Some(channel),
61+
..Default::default()
62+
},
63+
}
5364
}
5465
}
5566
}
@@ -73,7 +84,7 @@ impl Display for OverrideReason {
7384
}
7485
}
7586

76-
#[derive(Default)]
87+
#[derive(Default, Debug)]
7788
struct OverrideCfg<'a> {
7889
toolchain: Option<Toolchain<'a>>,
7990
components: Vec<String>,
@@ -83,9 +94,13 @@ struct OverrideCfg<'a> {
8394
impl<'a> OverrideCfg<'a> {
8495
fn from_file(cfg: &'a Cfg, file: OverrideFile) -> Result<Self> {
8596
Ok(Self {
86-
toolchain: match file.toolchain.channel {
87-
Some(name) => Some(Toolchain::from(cfg, &name)?),
88-
None => None,
97+
toolchain: match (file.toolchain.channel, file.toolchain.path) {
98+
(Some(name), None) => Some(Toolchain::from(cfg, &name)?),
99+
(None, Some(path)) => Some(Toolchain::from_path(cfg, &path)?),
100+
(Some(channel), Some(path)) => {
101+
return Err(ErrorKind::CannotSpecifyChannelAndPath(channel, path.into()).into())
102+
}
103+
(None, None) => None,
89104
},
90105
components: file.toolchain.components.unwrap_or_default(),
91106
targets: file.toolchain.targets.unwrap_or_default(),
@@ -521,7 +536,6 @@ impl Cfg {
521536
path.display()
522537
),
523538
};
524-
525539
let override_cfg = OverrideCfg::from_file(self, file)?;
526540
if let Some(toolchain) = &override_cfg.toolchain {
527541
// Overridden toolchains can be literally any string, but only
@@ -889,6 +903,7 @@ mod tests {
889903
OverrideFile {
890904
toolchain: ToolchainSection {
891905
channel: Some(contents.into()),
906+
path: None,
892907
components: None,
893908
targets: None,
894909
}
@@ -910,6 +925,7 @@ targets = [ "wasm32-unknown-unknown", "thumbv2-none-eabi" ]
910925
OverrideFile {
911926
toolchain: ToolchainSection {
912927
channel: Some("nightly-2020-07-10".into()),
928+
path: None,
913929
components: Some(vec!["rustfmt".into(), "rustc-dev".into()]),
914930
targets: Some(vec![
915931
"wasm32-unknown-unknown".into(),
@@ -932,6 +948,7 @@ channel = "nightly-2020-07-10"
932948
OverrideFile {
933949
toolchain: ToolchainSection {
934950
channel: Some("nightly-2020-07-10".into()),
951+
path: None,
935952
components: None,
936953
targets: None,
937954
}
@@ -952,6 +969,7 @@ components = []
952969
OverrideFile {
953970
toolchain: ToolchainSection {
954971
channel: Some("nightly-2020-07-10".into()),
972+
path: None,
955973
components: Some(vec![]),
956974
targets: None,
957975
}
@@ -972,6 +990,7 @@ targets = []
972990
OverrideFile {
973991
toolchain: ToolchainSection {
974992
channel: Some("nightly-2020-07-10".into()),
993+
path: None,
975994
components: None,
976995
targets: Some(vec![]),
977996
}
@@ -991,6 +1010,7 @@ components = [ "rustfmt" ]
9911010
OverrideFile {
9921011
toolchain: ToolchainSection {
9931012
channel: None,
1013+
path: None,
9941014
components: Some(vec!["rustfmt".into()]),
9951015
targets: None,
9961016
}

src/errors.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,14 @@ error_chain! {
188188
description("invalid toolchain name")
189189
display("invalid toolchain name: '{}'", t)
190190
}
191+
InvalidToolchainPath(p: PathBuf) {
192+
description("invalid toolchain path"),
193+
display("invalid toolchain path: '{}'", p.display())
194+
}
195+
CannotSpecifyChannelAndPath(channel: String, path: PathBuf) {
196+
description("cannot specify channel and path simultaneously"),
197+
display("cannot specify both channel ({}) and path ({}) simultaneously", channel, path.display())
198+
}
191199
InvalidProfile(t: String) {
192200
description("invalid profile name")
193201
display("invalid profile name: '{}'; valid names are: {}", t, valid_profile_names())

src/toolchain.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ pub enum UpdateStatus {
6363

6464
impl<'a> Toolchain<'a> {
6565
pub fn from(cfg: &'a Cfg, name: &str) -> Result<Self> {
66+
if name.contains('/') || name.contains('\\') {
67+
return Self::from_path(cfg, name);
68+
}
6669
let resolved_name = cfg.resolve_toolchain(name)?;
6770
let path = cfg.toolchains_dir.join(&resolved_name);
6871
Ok(Toolchain {
@@ -73,6 +76,26 @@ impl<'a> Toolchain<'a> {
7376
})
7477
}
7578

79+
pub fn from_path(cfg: &'a Cfg, path: impl AsRef<Path>) -> Result<Self> {
80+
let path = path.as_ref();
81+
let base = path
82+
.components()
83+
.last()
84+
.ok_or_else(|| ErrorKind::InvalidToolchainPath(path.into()))?
85+
.as_os_str()
86+
.to_string_lossy();
87+
// Perform minimal validation - that there's a `bin/` which might contain things for us to run
88+
if !path.join("bin").is_dir() {
89+
return Err(ErrorKind::InvalidToolchainPath(path.into()).into());
90+
}
91+
Ok(Toolchain {
92+
cfg,
93+
name: base.into(),
94+
path: path.to_path_buf(),
95+
dist_handler: Box::new(move |n| (cfg.notify_handler)(n.into())),
96+
})
97+
}
98+
7699
pub fn as_installed_common(&'a self) -> Result<InstalledCommonToolchain<'a>> {
77100
if !self.exists() {
78101
// Should be verify perhaps?
@@ -255,6 +278,15 @@ impl<'a> Toolchain<'a> {
255278
}
256279
}
257280

281+
impl<'a> std::fmt::Debug for Toolchain<'a> {
282+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
283+
f.debug_struct("Toolchain")
284+
.field("name", &self.name)
285+
.field("path", &self.path)
286+
.finish()
287+
}
288+
}
289+
258290
/// Newtype hosting functions that apply to both custom and distributable toolchains that are installed.
259291
pub struct InstalledCommonToolchain<'a>(&'a Toolchain<'a>);
260292

0 commit comments

Comments
 (0)