Skip to content

Commit

Permalink
Eagerly resolve toolchains to canonical, fixed reference (#106)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kha authored Jun 13, 2024
1 parent 69fcc98 commit 4e413ea
Show file tree
Hide file tree
Showing 22 changed files with 213 additions and 490 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@ jobs:
release-target-name: aarch64-unknown-linux-gnu
binary-check: true
- name: macOS
os: macos-latest
os: macos-13
target: x86_64-apple-darwin
binary-check: otool -L
- name: macOS aarch64
os: macos-latest
os: macos-14
target: aarch64-apple-darwin
skip-tests: true
binary-check: otool -L
- name: Windows
os: windows-latest
Expand All @@ -61,10 +60,11 @@ jobs:
target
key: ${{ matrix.name }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Setup macOS
if: matrix.os == 'macos-latest'
if: startsWith(matrix.os, 'macos-')
shell: bash
run: |
brew install coreutils
echo $HOMEBREW_PREFIX/opt/gnu-tar/libexec/gnubin >> $GITHUB_PATH
# still necessary??
echo /usr/local/opt/gnu-tar/libexec/gnubin >> $GITHUB_PATH
- name: Build
run: |
Expand Down
4 changes: 2 additions & 2 deletions elan-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ FLAGS:
-V, --version Prints version information
OPTIONS:
--default-toolchain <default-toolchain> Choose a default toolchain to install
--default-toolchain none Do not install any toolchains
--default-toolchain <default-toolchain> Choose a default toolchain
--default-toolchain none Do not set a default toolchain
EOF
}

Expand Down
1 change: 1 addition & 0 deletions fetch_nixos_patch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nix build -o nixos.patch $(nix eval nixpkgs#elan.patches --apply "patches: (builtins.elemAt patches 0).outPath" --raw)
33 changes: 0 additions & 33 deletions src/elan-cli/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use elan_dist::dist::ToolchainDesc;
use elan_utils::notify::NotificationLevel;
use elan_utils::utils;
use errors::*;
use self_update;
use std;
use std::io::{BufRead, BufReader, Write};
use std::path::Path;
Expand Down Expand Up @@ -200,38 +199,6 @@ fn show_channel_updates(
Ok(())
}

pub fn update_all_channels(cfg: &Cfg, self_update: bool, force_update: bool) -> Result<()> {
let toolchains = cfg.update_all_channels(force_update)?;

if toolchains.is_empty() {
info!("no updatable toolchains installed.");
info!("use 'elan toolchain install' to install a toolchain.")
}

let setup_path = if self_update {
self_update::prepare_update()?
} else {
None
};

if !toolchains.is_empty() {
println!("");

show_channel_updates(cfg, toolchains)?;
}

if let Some(ref setup_path) = setup_path {
self_update::run_update(setup_path)?;

unreachable!(); // update exits on success
} else if self_update {
// Try again in case we emitted "tool `{}` is already installed" last time.
self_update::install_proxies()?;
}

Ok(())
}

pub fn lean_version(toolchain: &Toolchain) -> String {
if toolchain.exists() {
let lean_path = toolchain.binary_file("lean");
Expand Down
88 changes: 29 additions & 59 deletions src/elan-cli/elan_mode.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clap::{App, AppSettings, Arg, ArgMatches, Shell, SubCommand};
use common;
use elan::{command, Cfg, Toolchain};
use elan::{command, lookup_toolchain_desc, Cfg, Toolchain};
use elan_dist::dist::ToolchainDesc;
use elan_utils::utils;
use errors::*;
Expand All @@ -22,12 +22,11 @@ pub fn main() -> Result<()> {

match matches.subcommand() {
("show", Some(_)) => show(cfg)?,
("install", Some(m)) => update(cfg, m)?,
("update", Some(m)) => update(cfg, m)?,
("install", Some(m)) => install(cfg, m)?,
("uninstall", Some(m)) => toolchain_remove(cfg, m)?,
("default", Some(m)) => default_(cfg, m)?,
("toolchain", Some(c)) => match c.subcommand() {
("install", Some(m)) => update(cfg, m)?,
("install", Some(m)) => install(cfg, m)?,
("list", Some(_)) => common::list_toolchains(cfg)?,
("link", Some(m)) => toolchain_link(cfg, m)?,
("uninstall", Some(m)) => toolchain_remove(cfg, m)?,
Expand Down Expand Up @@ -79,7 +78,7 @@ pub fn cli() -> App<'static, 'static> {
.about("Show the active and installed toolchains")
.after_help(SHOW_HELP))
.subcommand(SubCommand::with_name("install")
.about("Update Lean toolchains")
.about("Install Lean toolchain")
.after_help(INSTALL_HELP)
.setting(AppSettings::Hidden) // synonym for 'toolchain install'
.arg(Arg::with_name("toolchain")
Expand All @@ -93,22 +92,6 @@ pub fn cli() -> App<'static, 'static> {
.help(TOOLCHAIN_ARG_HELP)
.required(true)
.multiple(true)))
.subcommand(SubCommand::with_name("update")
.about("Update Lean toolchains and elan")
.after_help(UPDATE_HELP)
.arg(Arg::with_name("toolchain")
.help(TOOLCHAIN_ARG_HELP)
.required(false)
.multiple(true))
.arg(Arg::with_name("no-self-update")
.help("Don't perform self update when running the `elan` command")
.long("no-self-update")
.takes_value(false)
.hidden(true))
.arg(Arg::with_name("force")
.help("Force an update, even if some components are missing")
.long("force")
.takes_value(false)))
.subcommand(SubCommand::with_name("default")
.about("Set the default toolchain")
.after_help(DEFAULT_HELP)
Expand All @@ -124,8 +107,7 @@ pub fn cli() -> App<'static, 'static> {
.subcommand(SubCommand::with_name("list")
.about("List installed toolchains"))
.subcommand(SubCommand::with_name("install")
.about("Install or update a given toolchain")
.aliases(&["update", "add"])
.about("Install a given toolchain")
.arg(Arg::with_name("toolchain")
.help(TOOLCHAIN_ARG_HELP)
.required(true)
Expand Down Expand Up @@ -249,8 +231,8 @@ pub fn cli() -> App<'static, 'static> {
}

fn default_(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
let ref toolchain = m.value_of("toolchain").expect("");
let toolchain = ToolchainDesc::from_str(toolchain)?;
let ref name = m.value_of("toolchain").expect("");
let toolchain = lookup_toolchain_desc(cfg, name)?;
let ref toolchain = cfg.get_toolchain(&toolchain, false)?;

let status = if !toolchain.exists() || !toolchain.is_custom() {
Expand All @@ -259,7 +241,7 @@ fn default_(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
None
};

toolchain.make_default()?;
cfg.set_default(name)?;

if let Some(status) = status {
println!("");
Expand All @@ -269,29 +251,22 @@ fn default_(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
Ok(())
}

fn update(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
if let Some(names) = m.values_of("toolchain") {
for name in names {
let desc = ToolchainDesc::from_str(name)?;
let toolchain = cfg.get_toolchain(&desc, false)?;

let status = if !toolchain.exists() || !toolchain.is_custom() {
Some(toolchain.install_from_dist(m.is_present("force"))?)
} else {
None
};

if let Some(status) = status {
println!("");
common::show_channel_update(cfg, &toolchain.desc, Ok(status))?;
}
fn install(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
let names = m.values_of("toolchain").expect("");
for name in names {
let desc = lookup_toolchain_desc(cfg, name)?;
let toolchain = cfg.get_toolchain(&desc, false)?;

let status = if !toolchain.exists() || !toolchain.is_custom() {
Some(toolchain.install_from_dist()?)
} else {
None
};

if let Some(status) = status {
println!("");
common::show_channel_update(cfg, &toolchain.desc, Ok(status))?;
}
} else {
common::update_all_channels(
cfg,
!m.is_present("no-self-update") && !elan::install::NEVER_SELF_UPDATE,
m.is_present("force"),
)?;
}

Ok(())
Expand All @@ -301,7 +276,7 @@ fn run(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
let ref toolchain = m.value_of("toolchain").expect("");
let args = m.values_of("command").unwrap();
let args: Vec<_> = args.collect();
let desc = ToolchainDesc::from_str(toolchain)?;
let desc = lookup_toolchain_desc(cfg, toolchain)?;
let cmd = cfg.create_command_for_toolchain(&desc, m.is_present("install"), args[0])?;

Ok(command::run_command_for_dir(
Expand Down Expand Up @@ -344,13 +319,8 @@ fn show(cfg: &Cfg) -> Result<()> {
if show_headers {
print_header("installed toolchains")
}
let default_name = cfg.get_default()?;
for t in installed_toolchains {
if default_name.as_ref() == Some(&t) {
println!("{} (default)", t);
} else {
println!("{}", t);
}
println!("{}", t);
}
if show_headers {
println!("")
Expand Down Expand Up @@ -405,7 +375,7 @@ fn show(cfg: &Cfg) -> Result<()> {
fn explicit_or_dir_toolchain<'a>(cfg: &'a Cfg, m: &ArgMatches) -> Result<Toolchain<'a>> {
let toolchain = m.value_of("toolchain");
if let Some(toolchain) = toolchain {
let desc = ToolchainDesc::from_str(toolchain)?;
let desc = lookup_toolchain_desc(cfg, toolchain)?;
let toolchain = cfg.get_toolchain(&desc, false)?;
return Ok(toolchain);
}
Expand All @@ -419,15 +389,15 @@ fn explicit_or_dir_toolchain<'a>(cfg: &'a Cfg, m: &ArgMatches) -> Result<Toolcha
fn toolchain_link(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
let ref toolchain = m.value_of("toolchain").expect("");
let ref path = m.value_of("path").expect("");
let desc = ToolchainDesc::from_str(toolchain)?;
let desc = ToolchainDesc::from_resolved_str(toolchain)?;
let toolchain = cfg.get_toolchain(&desc, true)?;

Ok(toolchain.install_from_dir(Path::new(path), true)?)
}

fn toolchain_remove(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
for toolchain in m.values_of("toolchain").expect("") {
let desc = ToolchainDesc::from_str(toolchain)?;
let desc = lookup_toolchain_desc(cfg, toolchain)?;
let toolchain = cfg.get_toolchain(&desc, false)?;
toolchain.remove()?;
}
Expand All @@ -436,7 +406,7 @@ fn toolchain_remove(cfg: &Cfg, m: &ArgMatches) -> Result<()> {

fn override_add(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
let ref toolchain = m.value_of("toolchain").expect("");
let desc = ToolchainDesc::from_str(toolchain)?;
let desc = lookup_toolchain_desc(cfg, toolchain)?;
let toolchain = cfg.get_toolchain(&desc, false)?;

let status = if !toolchain.exists() || !toolchain.is_custom() {
Expand Down
11 changes: 1 addition & 10 deletions src/elan-cli/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,13 @@ pub static SHOW_HELP: &'static str = r"DISCUSSION:
If there are multiple toolchains installed then all installed
toolchains are listed as well.";

pub static UPDATE_HELP: &'static str = r"DISCUSSION:
With no toolchain specified, the `update` command updates each of
the installed toolchains from the official release channels, then
updates elan itself.
If given a toolchain argument then `update` updates that
toolchain, the same as `elan toolchain install`.";

pub static INSTALL_HELP: &'static str = r"DISCUSSION:
Installs a specific lean toolchain.
The 'install' command is an alias for 'elan update <toolchain>'.";

pub static DEFAULT_HELP: &'static str = r"DISCUSSION:
Sets the default toolchain to the one specified. If the toolchain
is not already installed then it is installed first.";
Sets the default toolchain to the one specified.";

pub static TOOLCHAIN_HELP: &'static str = r"DISCUSSION:
Many `elan` commands deal with *toolchains*, a single
Expand Down
5 changes: 2 additions & 3 deletions src/elan-cli/proxy_mode.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use common::set_globals;
use elan::command::run_command_for_dir;
use elan::Cfg;
use elan::{lookup_toolchain_desc, Cfg};
use elan_utils::utils;
use elan_dist::dist::ToolchainDesc;
use errors::*;
use job;
use std::env;
Expand Down Expand Up @@ -50,7 +49,7 @@ fn direct_proxy(cfg: &Cfg, arg0: &str, toolchain: Option<&str>, args: &[OsString
let cmd = match toolchain {
None => cfg.create_command_for_dir(&utils::current_dir()?, arg0)?,
Some(tc) => {
let desc = ToolchainDesc::from_str(tc)?;
let desc = lookup_toolchain_desc(cfg, tc)?;
cfg.create_command_for_toolchain(&desc, true, arg0)?
}
};
Expand Down
34 changes: 7 additions & 27 deletions src/elan-cli/self_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
//! and racy on Windows.
use common::{self, Confirm};
use elan::lookup_toolchain_desc;
use elan_dist::dist;
use elan_dist::dist::ToolchainDesc;
use elan_utils::utils;
use errors::*;
use flate2;
Expand Down Expand Up @@ -232,7 +232,12 @@ pub fn install(no_prompt: bool, verbose: bool, mut opts: InstallOpts) -> Result<
if !opts.no_modify_path {
do_add_to_path(&get_add_path_methods())?;
}
maybe_install_lean(&opts.default_toolchain, verbose)?;
if opts.default_toolchain != "none" {
let ref cfg = common::set_globals(verbose)?;
// sanity-check reference
let _ = lookup_toolchain_desc(cfg, &opts.default_toolchain)?;
cfg.set_default(&opts.default_toolchain)?;
}

if cfg!(unix) {
let ref env_file = utils::elan_home()?.join("env");
Expand Down Expand Up @@ -533,31 +538,6 @@ pub fn install_proxies() -> Result<()> {
Ok(())
}

fn maybe_install_lean(toolchain_str: &str, verbose: bool) -> Result<()> {
let ref cfg = common::set_globals(verbose)?;

// If there is already an install, then `toolchain_str` may not be
// a toolchain the user actually wants. Don't do anything. FIXME:
// This logic should be part of InstallOpts so that it isn't
// possible to select a toolchain then have it not be installed.
if toolchain_str == "none" {
info!("skipping toolchain installation");
println!("");
} else if cfg.find_default()?.is_none() {
let desc = ToolchainDesc::from_str(toolchain_str)?;
let toolchain = cfg.get_toolchain(&desc, false)?;
let status = toolchain.install_from_dist(false)?;
cfg.set_default(&desc)?;
println!("");
common::show_channel_update(cfg, &desc, Ok(status))?;
} else {
info!("updating existing elan installation");
println!("");
}

Ok(())
}

pub fn uninstall(no_prompt: bool) -> Result<()> {
if elan::install::NEVER_SELF_UPDATE {
err!("self-uninstall is disabled for this build of elan");
Expand Down
2 changes: 1 addition & 1 deletion src/elan-cli/setup_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub fn main() -> Result<()> {
Arg::with_name("default-toolchain")
.long("default-toolchain")
.takes_value(true)
.help("Choose a default toolchain to install"),
.help("Choose a default toolchain"),
)
.arg(
Arg::with_name("no-modify-path")
Expand Down
Loading

0 comments on commit 4e413ea

Please sign in to comment.