Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Thoughts on #2458 #2471

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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