Skip to content

Commit

Permalink
WIP: Thoughts on #2458
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Silverstone <[email protected]>
  • Loading branch information
kinnison committed Nov 17, 2020
1 parent 5674652 commit 77bfca2
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 10 deletions.
40 changes: 30 additions & 10 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ impl OverrideFile {
#[derive(Debug, Default, Deserialize, PartialEq, Eq)]
struct ToolchainSection {
channel: Option<String>,
path: Option<String>,
components: Option<Vec<String>>,
targets: Option<Vec<String>>,
}
Expand All @@ -45,11 +46,21 @@ impl ToolchainSection {

impl<T: Into<String>> From<T> for OverrideFile {
fn from(channel: T) -> Self {
Self {
toolchain: ToolchainSection {
channel: Some(channel.into()),
..Default::default()
},
let channel = channel.into();
if channel.contains('/') || channel.contains('\\') {
Self {
toolchain: ToolchainSection {
path: Some(channel),
..Default::default()
},
}
} else {
Self {
toolchain: ToolchainSection {
channel: Some(channel),
..Default::default()
},
}
}
}
}
Expand All @@ -73,7 +84,7 @@ impl Display for OverrideReason {
}
}

#[derive(Default)]
#[derive(Default, Debug)]
struct OverrideCfg<'a> {
toolchain: Option<Toolchain<'a>>,
components: Vec<String>,
Expand All @@ -83,9 +94,13 @@ struct OverrideCfg<'a> {
impl<'a> OverrideCfg<'a> {
fn from_file(cfg: &'a Cfg, file: OverrideFile) -> Result<Self> {
Ok(Self {
toolchain: match file.toolchain.channel {
Some(name) => Some(Toolchain::from(cfg, &name)?),
None => None,
toolchain: match (file.toolchain.channel, file.toolchain.path) {
(Some(name), None) => Some(Toolchain::from(cfg, &name)?),
(None, Some(path)) => Some(Toolchain::from_path(cfg, &path)?),
(Some(channel), Some(path)) => {
return Err(ErrorKind::CannotSpecifyChannelAndPath(channel, path.into()).into())
}
(None, None) => None,
},
components: file.toolchain.components.unwrap_or_default(),
targets: file.toolchain.targets.unwrap_or_default(),
Expand Down Expand Up @@ -521,7 +536,6 @@ impl Cfg {
path.display()
),
};

let override_cfg = OverrideCfg::from_file(self, file)?;
if let Some(toolchain) = &override_cfg.toolchain {
// Overridden toolchains can be literally any string, but only
Expand Down Expand Up @@ -889,6 +903,7 @@ mod tests {
OverrideFile {
toolchain: ToolchainSection {
channel: Some(contents.into()),
path: None,
components: None,
targets: None,
}
Expand All @@ -910,6 +925,7 @@ targets = [ "wasm32-unknown-unknown", "thumbv2-none-eabi" ]
OverrideFile {
toolchain: ToolchainSection {
channel: Some("nightly-2020-07-10".into()),
path: None,
components: Some(vec!["rustfmt".into(), "rustc-dev".into()]),
targets: Some(vec![
"wasm32-unknown-unknown".into(),
Expand All @@ -932,6 +948,7 @@ channel = "nightly-2020-07-10"
OverrideFile {
toolchain: ToolchainSection {
channel: Some("nightly-2020-07-10".into()),
path: None,
components: None,
targets: None,
}
Expand All @@ -952,6 +969,7 @@ components = []
OverrideFile {
toolchain: ToolchainSection {
channel: Some("nightly-2020-07-10".into()),
path: None,
components: Some(vec![]),
targets: None,
}
Expand All @@ -972,6 +990,7 @@ targets = []
OverrideFile {
toolchain: ToolchainSection {
channel: Some("nightly-2020-07-10".into()),
path: None,
components: None,
targets: Some(vec![]),
}
Expand All @@ -991,6 +1010,7 @@ components = [ "rustfmt" ]
OverrideFile {
toolchain: ToolchainSection {
channel: None,
path: None,
components: Some(vec!["rustfmt".into()]),
targets: None,
}
Expand Down
8 changes: 8 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,14 @@ error_chain! {
description("invalid toolchain name")
display("invalid toolchain name: '{}'", t)
}
InvalidToolchainPath(p: PathBuf) {
description("invalid toolchain path"),
display("invalid toolchain path: '{}'", p.display())
}
CannotSpecifyChannelAndPath(channel: String, path: PathBuf) {
description("cannot specify channel and path simultaneously"),
display("cannot specify both channel ({}) and path ({}) simultaneously", channel, path.display())
}
InvalidProfile(t: String) {
description("invalid profile name")
display("invalid profile name: '{}'; valid names are: {}", t, valid_profile_names())
Expand Down
32 changes: 32 additions & 0 deletions src/toolchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ pub enum UpdateStatus {

impl<'a> Toolchain<'a> {
pub fn from(cfg: &'a Cfg, name: &str) -> Result<Self> {
if name.contains('/') || name.contains('\\') {
return Self::from_path(cfg, name);
}
let resolved_name = cfg.resolve_toolchain(name)?;
let path = cfg.toolchains_dir.join(&resolved_name);
Ok(Toolchain {
Expand All @@ -73,6 +76,26 @@ impl<'a> Toolchain<'a> {
})
}

pub fn from_path(cfg: &'a Cfg, path: impl AsRef<Path>) -> Result<Self> {
let path = path.as_ref();
let base = path
.components()
.last()
.ok_or_else(|| ErrorKind::InvalidToolchainPath(path.into()))?
.as_os_str()
.to_string_lossy();
// Perform minimal validation - that there's a `bin/` which might contain things for us to run
if !path.join("bin").is_dir() {
return Err(ErrorKind::InvalidToolchainPath(path.into()).into());
}
Ok(Toolchain {
cfg,
name: base.into(),
path: path.to_path_buf(),
dist_handler: Box::new(move |n| (cfg.notify_handler)(n.into())),
})
}

pub fn as_installed_common(&'a self) -> Result<InstalledCommonToolchain<'a>> {
if !self.exists() {
// Should be verify perhaps?
Expand Down Expand Up @@ -255,6 +278,15 @@ impl<'a> Toolchain<'a> {
}
}

impl<'a> std::fmt::Debug for Toolchain<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Toolchain")
.field("name", &self.name)
.field("path", &self.path)
.finish()
}
}

/// Newtype hosting functions that apply to both custom and distributable toolchains that are installed.
pub struct InstalledCommonToolchain<'a>(&'a Toolchain<'a>);

Expand Down

0 comments on commit 77bfca2

Please sign in to comment.