Skip to content

Commit

Permalink
Prompt user to install toolchain if missing (#652)
Browse files Browse the repository at this point in the history
  • Loading branch information
alfiedotwtf committed Sep 2, 2024
1 parent b4d9116 commit 69176e8
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 39 deletions.
10 changes: 10 additions & 0 deletions src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,14 @@ pub fn ask_user_yes_no_question(question: &str) -> io::Result<bool> {
return Ok(result);
}
}

// This is the dialoguer version of the prompter, but it's not testable
// as dialoguer requires an interactive terminal to work without failing.
//
// use dialoguer::{theme::ColorfulTheme, Confirm};
//
// Confirm::with_theme(&ColorfulTheme::default())
// .with_prompt(question)
// .interact()
// .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))
}
44 changes: 42 additions & 2 deletions src/fuelup_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ use crate::commands::{
toolchain::{self, ToolchainCommand},
upgrade::{self, UpgradeCommand},
};
use crate::ops::{fuelup_show, fuelup_update};
use anyhow::Result;
use anyhow::{bail, Context, Result};
use clap::Parser;
use crate::fmt::ask_user_yes_no_question;
use crate::ops::{fuelup_show, fuelup_toolchain, fuelup_update};
use crate::toolchain::{DistToolchainDescription, Toolchain};
use crate::toolchain_override::ToolchainOverride;
use std::str::FromStr;
use tracing::info;

#[derive(Debug, Parser)]
#[clap(name = "fuelup", about = "Fuel Toolchain Manager", version)]
Expand Down Expand Up @@ -46,6 +51,41 @@ enum Commands {
pub fn fuelup_cli() -> Result<()> {
let cli = Cli::parse();

if let Some(toolchain_override) = ToolchainOverride::from_project_root() {
let override_path = toolchain_override.cfg.toolchain.channel.to_string();
let toolchain = match DistToolchainDescription::from_str(&override_path) {
Ok(desc) => Toolchain::from_path(&desc.to_string()),
Err(_) => Toolchain::from_path(&override_path),
};

info!("Using override toolchain '{}'", &toolchain.name);

if !toolchain.exists() {
match cli.command {
Commands::Toolchain(_) => {
// User is managing their toolchains, so we fall through
}
_ => {
let should_install = ask_user_yes_no_question(
"Override toolchain is not installed. Do you want to install it now?",
)
.context("Console I/O")?;

if should_install {
fuelup_toolchain::install::install(toolchain::InstallCommand {
name: toolchain.name,
})?;
} else {
bail!(
"Override toolchain is not installed. Please run: 'fuelup toolchain install {}'",
&toolchain.name,
)
}
}
}
}
}

match cli.command {
Commands::Check(command) => check::exec(command),
Commands::Completions(command) => completions::exec(command),
Expand Down
43 changes: 40 additions & 3 deletions tests/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,50 @@ fn fuelup_default_nightly_and_nightly_date() -> Result<()> {
Ok(())
}

#[test]
fn fuelup_default_override_skip_install() -> Result<()> {
testcfg::setup(FuelupState::LatestWithBetaOverride, &|cfg| {
let output = cfg.fuelup_with_input(&["default"], b"N\n");
let triple = TargetTriple::from_host().unwrap();

assert!(output
.stdout
.starts_with(&format!("Using override toolchain 'beta-1-{triple}'")));

assert!(output
.stdout
.contains("Override toolchain is not installed. Do you want to install it now?"));

assert!(output
.stdout
.contains(&format!("Override toolchain is not installed. Please run: 'fuelup toolchain install beta-1-{triple}'")));
})?;
Ok(())
}

#[test]
fn fuelup_default_override() -> Result<()> {
testcfg::setup(FuelupState::LatestWithBetaOverride, &|cfg| {
let output = cfg.fuelup(&["default"]);
let output = cfg.fuelup_with_input(&["default"], b"Y\n");
let triple = TargetTriple::from_host().unwrap();
let expected_stdout = format!("beta-1-{triple} (override), latest-{triple} (default)\n");
assert_eq!(output.stdout, expected_stdout);

assert!(output
.stdout
.starts_with(&format!("Using override toolchain 'beta-1-{triple}'")));

assert!(output
.stdout
.contains("Override toolchain is not installed. Do you want to install it now?"));

assert!(output.stdout.contains("Downloading:"));

assert!(output
.stdout
.contains("The Fuel toolchain is installed and up to date"));

assert!(output
.stdout
.contains(&format!("beta-1-{triple} (override)")));
})?;
Ok(())
}
Expand Down
50 changes: 20 additions & 30 deletions tests/show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,39 +173,28 @@ fn fuelup_show_custom() -> Result<()> {
#[test]
fn fuelup_show_override() -> Result<()> {
testcfg::setup(FuelupState::LatestWithBetaOverride, &|cfg| {
let stripped = strip_ansi_escapes::strip(cfg.fuelup(&["show"]).stdout);
let stripped = strip_ansi_escapes::strip(cfg.fuelup_with_input(&["show"], b"y\n").stdout);
let stdout = String::from_utf8_lossy(&stripped);
let target = TargetTriple::from_host().unwrap();
let fuelup_home = cfg.fuelup_dir();
let fuelup_home_str = fuelup_home.to_string_lossy();
let expected_stdout = formatdoc! {
r#"Default host: {target}
fuelup home: {fuelup_home_str}

Installed toolchains
--------------------
latest-{target} (default)
assert!(stdout
.starts_with(&format!("Using override toolchain 'beta-1-{target}'")));

active toolchain
----------------
beta-1-{target} (override), path: {}
forc : not found
- forc-client
- forc-deploy : not found
- forc-run : not found
- forc-crypto : not found
- forc-debug : not found
- forc-doc : not found
- forc-fmt : not found
- forc-lsp : not found
- forc-tx : not found
- forc-wallet : not found
fuel-core : not found
fuel-core-keygen : not found
"#, cfg.home.join(FUEL_TOOLCHAIN_TOML_FILE).display()
};
assert_eq!(stdout, expected_stdout);
})?;
assert!(stdout
.contains("Override toolchain is not installed. Do you want to install it now?"));

assert!(stdout.contains("Downloading:"));

assert!(stdout.contains(&formatdoc! {"
Installed:
- forc 0.26.0
- forc-wallet 0.1.2
- fuel-core 0.10.1
"}));

assert!(stdout
.contains(&format!("beta-1-{target} (override)")));
})?;
Ok(())
}

Expand Down Expand Up @@ -267,7 +256,8 @@ fn fuelup_show_latest_then_override() -> Result<()> {
stdout = String::from_utf8_lossy(&stripped);

let expected_stdout = formatdoc! {
r#"Default host: {target}
r#"Using override toolchain 'nightly-2022-08-30-{target}'
Default host: {target}
fuelup home: {fuelup_home_str}
Installed toolchains
Expand Down
49 changes: 45 additions & 4 deletions tests/testcfg/mod.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use anyhow::Result;
use fuelup::channel::{BETA_1, LATEST, NIGHTLY};
use fuelup::constants::FUEL_TOOLCHAIN_TOML_FILE;
use fuelup::constants::{BETA_1, FUEL_TOOLCHAIN_TOML_FILE, LATEST, NIGHTLY};
use fuelup::file::hard_or_symlink_file;
use fuelup::settings::SettingsFile;
use fuelup::target_triple::TargetTriple;
use fuelup::toolchain_override::{self, OverrideCfg, ToolchainCfg, ToolchainOverride};
use semver::Version;
use std::io::Write;
use std::os::unix::fs::OpenOptionsExt;
use std::str::FromStr;
use std::{
env, fs,
path::{Path, PathBuf},
process::{Command, ExitStatus},
process::{Command, ExitStatus, Stdio},
};
use tempfile::tempdir;

Expand Down Expand Up @@ -130,7 +130,7 @@ impl TestCfg {
.args(args)
.current_dir(&self.home)
.env("HOME", &self.home)
.env("CARGO_HOME", &self.home.join(".cargo"))
.env("CARGO_HOME", self.home.join(".cargo"))
.env(
"PATH",
format!(
Expand Down Expand Up @@ -163,6 +163,47 @@ impl TestCfg {
pub fn fuelup(&mut self, args: &[&str]) -> TestOutput {
self.exec("fuelup", args)
}

/// A convenience wrapper for executing 'fuelup' within the fuelup test configuration.
/// It takes an array ref of bytes to write into stdin.
pub fn fuelup_with_input(&mut self, args: &[&str], input: &[u8]) -> TestOutput {
let path = self.fuelup_bin_dirpath.join("fuelup");
let mut child = Command::new(path)
.args(args)
.current_dir(&self.home)
.env("HOME", &self.home)
.env("CARGO_HOME", self.home.join(".cargo"))
.env(
"PATH",
format!(
"{}:{}:{}",
&self.home.join(".local/bin").display(),
&self.home.join(".cargo/bin").display(),
&self.home.join(".fuelup/bin").display(),
),
)
.env("TERM", "dumb")
.stdin(Stdio::piped())
.stdout(Stdio::piped()) // Inherit so we can see it install
.spawn()
.expect("Failed to execute command");

let stdin = child.stdin.as_mut().expect("Failed to open stdin");

for byte in input {
stdin.write_all(&[*byte]).expect("Failed to write to stdin");
}

let output = child.wait_with_output().expect("Failed to read output");
let stdout = String::from_utf8(output.stdout).unwrap();
let stderr = String::from_utf8(output.stderr).unwrap();

TestOutput {
stdout,
stderr,
status: output.status,
}
}
}

#[cfg(unix)]
Expand Down

0 comments on commit 69176e8

Please sign in to comment.