Skip to content

Commit

Permalink
Add interactive advanced installation
Browse files Browse the repository at this point in the history
This allows users to change --no-modify-path and --default-toolchain
from the interactive cli installer.

A typical session looks like

```
... snip ...

To cancel installation, type "n", or for more options type "a",
then press the Enter key to continue.

Press the Enter key to install Rust.
a

Selected installation options:

     default toolchain: stable
  modify PATH variable: yes

I'm going to ask you the value of each these installation options.
You may simply press the Enter key to accept the default.

Default toolchain? (stable/beta/nightly)
nightly

Modify PATH variable? (y/n)
n

That's it! We're ready to install Rust.

Selected installation options:

     default toolchain: nightly
  modify PATH variable: no

To cancel installation, type "n", or for more options type "a",
then press the Enter key to continue.

Press the Enter key to install Rust.

info: syncing channel updates for 'nightly-x86_64-unknown-linux-gnu'
info: default toolchain set to 'nightly'

  nightly unchanged - rustc 1.9.0-nightly (177905703 2016-04-08)

Rust is installed now. Great!

To get started you need Cargo's bin directory in your `PATH`
environment variable.

To configure your current shell run `source /home/brian/dev/.cargo/env`.
```
  • Loading branch information
brson committed Apr 13, 2016
1 parent 9fc97dc commit 14cbd2f
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 28 deletions.
43 changes: 38 additions & 5 deletions src/multirust-cli/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,14 @@ pub enum Confirm {
Yes, No, Advanced
}

pub fn confirm_advanced(question: &str, default: Confirm) -> Result<Confirm> {
print!("{} ", question);
pub fn confirm_advanced(default: Confirm) -> Result<Confirm> {
let _ = std::io::stdout().flush();
let input = try!(read_line());

let r = match &*input {
"y" | "Y" => Confirm::Yes,
"n" | "N" => Confirm::No,
"a" | "A" => Confirm::Advanced,
"y" | "Y" | "yes" => Confirm::Yes,
"n" | "N" | "no" => Confirm::No,
"a" | "A" | "advanced" => Confirm::Advanced,
"" => default,
_ => Confirm::No,
};
Expand All @@ -51,6 +50,40 @@ pub fn confirm_advanced(question: &str, default: Confirm) -> Result<Confirm> {
Ok(r)
}

pub fn question_str(question: &str, default: &str) -> Result<String> {
println!("{}", question);
let _ = std::io::stdout().flush();
let input = try!(read_line());

println!("");

if input.is_empty() {
Ok(default.to_string())
} else {
Ok(input)
}
}

pub fn question_bool(question: &str, default: bool) -> Result<bool> {
println!("{}", question);

let _ = std::io::stdout().flush();
let input = try!(read_line());

println!("");

if input.is_empty() {
Ok(default)
} else {
match &*input {
"y" | "Y" | "yes" => Ok(true),
"n" | "N" | "no" => Ok(false),
_ => Ok(default)
}
}

}

pub fn read_line() -> Result<String> {
let stdin = std::io::stdin();
let stdin = stdin.lock();
Expand Down
121 changes: 107 additions & 14 deletions src/multirust-cli/self_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ these changes will be reverted.
WARNING: This is an early beta. Expect breakage.
To cancel installation, type "n" (for "nah, I don't want to install Rust"),
or for more options type "a" (for "awesome advanced options"),
To cancel installation, type "n", or for more options type "a",
then press the Enter key to continue.
Press the Enter key to install Rust."#
Expand Down Expand Up @@ -116,8 +115,9 @@ r"Rust is installed now. Great!
To get started you need Cargo's bin directory in your `PATH`
environment variable. Next time you log in this will be done
automatically. To configure your current shell without logging out
run `source {cargo_home}/env`.
automatically.
To configure your current shell run `source {cargo_home}/env`.
"
};
}
Expand All @@ -129,7 +129,31 @@ r"Rust is installed now. Great!
To get started you need Cargo's bin directory in your `PATH`
environment variable. Future applications will automatically have the
correct environment, but you may need to restart your current shell.
" }; }
"
};
}

macro_rules! post_install_msg_unix_no_modify_path {
() => {
r"Rust is installed now. Great!
To get started you need Cargo's bin directory in your `PATH`
environment variable.
To configure your current shell run `source {cargo_home}/env`.
"
};
}

macro_rules! post_install_msg_win_no_modify_path {
() => {
r"Rust is installed now. Great!
To get started you need Cargo's bin directory in your `PATH`
environment variable. This has not been done automatically.
"
};
}

macro_rules! pre_uninstall_msg {
() => {
Expand Down Expand Up @@ -172,7 +196,8 @@ pub fn install(no_prompt: bool, verbose: bool,

if !no_prompt {
let ref msg = try!(pre_install_msg(opts.no_modify_path));
match try!(common::confirm_advanced(msg, Confirm::Yes)) {
println!("{}", msg);
match try!(common::confirm_advanced(Confirm::Yes)) {
Confirm::No => {
info!("aborting installation");
return Ok(());
Expand Down Expand Up @@ -203,7 +228,11 @@ pub fn install(no_prompt: bool, verbose: bool,

if cfg!(unix) {
let ref env_file = try!(utils::cargo_home()).join("env");
let ref env_str = try!(shell_export_string());
let ref env_str = format!(
"{}\n\
printf \"PATH environment variable set.\\n\"
printf \"You're ready to Rust!\\n\\n\"",
try!(shell_export_string()));
try!(utils::write_file("env", env_file, env_str));
}

Expand All @@ -228,12 +257,22 @@ pub fn install(no_prompt: bool, verbose: bool,

// More helpful advice, skip if -y
if !no_prompt {
if cfg!(unix) {
let cargo_home = try!(canonical_cargo_home());
println!(post_install_msg_unix!(),
cargo_home = cargo_home);
if !selected_opts.no_modify_path {
if cfg!(unix) {
let cargo_home = try!(canonical_cargo_home());
println!(post_install_msg_unix!(),
cargo_home = cargo_home);
} else {
println!(post_install_msg_win!());
}
} else {
println!(post_install_msg_win!());
if cfg!(unix) {
let cargo_home = try!(canonical_cargo_home());
println!(post_install_msg_unix_no_modify_path!(),
cargo_home = cargo_home);
} else {
println!(post_install_msg_win_no_modify_path!());
}
}

// On windows, where installation happens in a console
Expand Down Expand Up @@ -279,8 +318,62 @@ fn pre_install_msg(no_modify_path: bool) -> Result<String> {
}

// Interactive editing of the install options
fn advanced_install(opts: InstallOpts) -> Result<Option<InstallOpts>> {
unimplemented!()
fn advanced_install(mut opts: InstallOpts) -> Result<Option<InstallOpts>> {

fn print_opts(opts: &InstallOpts) {
println!(
r"Selected installation options:
default toolchain: {}
modify PATH variable: {}
",
opts.default_toolchain,
if !opts.no_modify_path { "yes" } else { "no" }
);
}

loop {

print_opts(&opts);

println!(
"I'm going to ask you the value of each these installation options.\n\
You may simply press the Enter key to accept the default.");

println!("");

opts.default_toolchain = try!(common::question_str(
"Default toolchain? (stable/beta/nightly)",
&opts.default_toolchain));

opts.no_modify_path = !try!(common::question_bool(
"Modify PATH variable? (y/n)",
!opts.no_modify_path));

println!("That's it! We're ready to install Rust.");
println!("");

print_opts(&opts);

println!(
r#"To cancel installation, type "n", or for more options type "a",
then press the Enter key to continue.
Press the Enter key to install Rust. "#);

match try!(common::confirm_advanced(Confirm::Yes)) {
Confirm::No => {
info!("aborting installation");
return Ok(None);
}
Confirm::Yes => {
return Ok(Some(opts));
}
Confirm::Advanced => {
continue;
}
}
}
}

// Before multirust-rs installed bins to $CARGO_HOME/bin it installed
Expand Down
67 changes: 58 additions & 9 deletions tests/cli-install-interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use std::sync::Mutex;
use std::process::Stdio;
use std::io::Write;
use multirust_mock::clitools::{self, Config, Scenario,
SanitizedOutput};
SanitizedOutput,
expect_stdout_ok};
use multirust_mock::{get_path, restore_path};

pub fn setup(f: &Fn(&Config)) {
Expand Down Expand Up @@ -73,12 +74,14 @@ fn blank_lines_around_stderr_log_output_install() {
setup(&|config| {
let out = run_input(config, &["rustup-setup"], "\n\n");

// During an interactive session, after "Continue?"
// there is a blank line that comes from the user pressing enter,
// then log output on stderr, then an explicit blank line on stdout
// During an interactive session, after "Press the Enter
// key..." the UI emits a blank line, then there is a blank
// line that comes from the user pressing enter, then log
// output on stderr, then an explicit blank line on stdout
// before printing $toolchain installed
assert!(out.stdout.contains(r"
Press the Enter key to install Rust.
Press the Enter key to install Rust.
stable installed - 1.1.0 (hash-s-2)
Expand All @@ -93,10 +96,9 @@ fn blank_lines_around_stderr_log_output_update() {
run_input(config, &["rustup-setup"], "\n\n");
let out = run_input(config, &["rustup-setup"], "\n\n");

// Here again the user generates one blank line, then there
// are lines of stderr logs, then one blank line on stdout.
assert!(out.stdout.contains(r"
Press the Enter key to install Rust.
Press the Enter key to install Rust.
stable unchanged - 1.1.0 (hash-s-2)
Expand Down Expand Up @@ -129,8 +131,55 @@ fn with_no_modify_path() {

#[test]
fn with_non_default_toolchain() {
setup(&|config| {
let out = run_input(config, &["rustup-setup", "--default-toolchain=nightly"], "\n\n");
assert!(out.ok);

expect_stdout_ok(config, &["rustup", "show"], "nightly");
});
}

#[test]
fn set_nightly_toolchain() {
setup(&|config| {
let out = run_input(config, &["rustup-setup"],
"a\nnightly\n\n\n\n");
assert!(out.ok);

expect_stdout_ok(config, &["rustup", "show"], "nightly");
});
}

#[test]
fn set_no_modify_path() {
setup(&|config| {
let out = run_input(config, &["rustup-setup"],
"a\n\nno\n\n\n");
assert!(out.ok);

if cfg!(unix) {
assert!(!config.homedir.join(".profile").exists());
}
});
}

#[test]
fn with_no_modify_path_and_non_default_toolchain() {
fn set_nightly_toolchain_and_unset() {
setup(&|config| {
let out = run_input(config, &["rustup-setup"],
"a\nnightly\n\na\nbeta\n\n\n\n");
assert!(out.ok);

expect_stdout_ok(config, &["rustup", "show"], "beta");
});
}

#[test]
fn user_says_nope_after_advanced_install() {
setup(&|config| {
let out = run_input(config, &["rustup-setup"],
"a\n\n\nn\n\n");
assert!(out.ok);
assert!(!config.cargodir.join("bin").exists());
});
}

0 comments on commit 14cbd2f

Please sign in to comment.