mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-12-26 00:11:49 +02:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b9479071c | ||
|
|
3d9b03c52b | ||
|
|
a03d9655a8 | ||
|
|
1e2fd9c92f | ||
|
|
7e8530b21f | ||
|
|
98358597a9 | ||
|
|
8064facbb8 | ||
|
|
f981dcfde4 | ||
|
|
bbf8922ef7 | ||
|
|
43dc31193a |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,3 +2,6 @@
|
||||
target/
|
||||
**/*.rs.bk
|
||||
.DS_Store
|
||||
*.pdb
|
||||
exercises/clippy/Cargo.toml
|
||||
exercises/clippy/Cargo.lock
|
||||
|
||||
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,3 +1,14 @@
|
||||
<a name="2.2.1"></a>
|
||||
### 2.2.1 (2020-02-27)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Re-add cloning the repo to install scripts ([3d9b03c5](https://github.com/rust-lang/rustlings/commit/3d9b03c52b8dc51b140757f6fd25ad87b5782ef5))
|
||||
|
||||
#### Features
|
||||
|
||||
* Add clippy lints (#269) ([1e2fd9c9](https://github.com/rust-lang/rustlings/commit/1e2fd9c92f8cd6e389525ca1a999fca4c90b5921))
|
||||
|
||||
<a name="2.2.0"></a>
|
||||
## 2.2.0 (2020-02-25)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustlings"
|
||||
version = "2.2.0"
|
||||
version = "2.2.1"
|
||||
authors = ["Marisa <mokou@posteo.de>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ Basically: Clone the repository, checkout to the latest tag, run `cargo install`
|
||||
```bash
|
||||
git clone https://github.com/rust-lang/rustlings
|
||||
cd rustlings
|
||||
git checkout tags/2.2.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
|
||||
git checkout tags/2.2.1 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
|
||||
cargo install --force --path .
|
||||
```
|
||||
|
||||
|
||||
8
exercises/clippy/README.md
Normal file
8
exercises/clippy/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
### Clippy
|
||||
|
||||
The Clippy tool is a collection of lints to analyze your code so you can catch common mistakes and improve your Rust code.
|
||||
|
||||
If you used the installation script for Rustlings, Clippy should be already installed.
|
||||
If not you can install it manually via `rustup component add clippy`.
|
||||
|
||||
For more information about Clippy lints, please see [their documentation page](https://rust-lang.github.io/rust-clippy/master/).
|
||||
15
exercises/clippy/clippy1.rs
Normal file
15
exercises/clippy/clippy1.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
// clippy1.rs
|
||||
// The Clippy tool is a collection of lints to analyze your code
|
||||
// so you can catch common mistakes and improve your Rust code.
|
||||
//
|
||||
// Execute `rustlings hint clippy1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let x = 1.2331f64;
|
||||
let y = 1.2332f64;
|
||||
if y != x {
|
||||
println!("Success!");
|
||||
}
|
||||
}
|
||||
13
exercises/clippy/clippy2.rs
Normal file
13
exercises/clippy/clippy2.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
// clippy2.rs
|
||||
// Make me compile! Execute `rustlings hint clippy2` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let mut res = 42;
|
||||
let option = Some(12);
|
||||
for x in option {
|
||||
res += x;
|
||||
}
|
||||
println!("{}", res);
|
||||
}
|
||||
16
info.toml
16
info.toml
@@ -529,6 +529,22 @@ hint = """
|
||||
It should be doing some checking, returning an `Err` result if those checks fail, and only
|
||||
returning an `Ok` result if those checks determine that everything is... okay :)"""
|
||||
|
||||
# CLIPPY
|
||||
|
||||
[[exercises]]
|
||||
name = "clippy1"
|
||||
path = "exercises/clippy/clippy1.rs"
|
||||
mode = "clippy"
|
||||
hint = """
|
||||
Floating point calculations are usually imprecise, so asking if two values are exactly equal is asking for trouble"""
|
||||
|
||||
[[exercises]]
|
||||
name = "clippy2"
|
||||
path = "exercises/clippy/clippy2.rs"
|
||||
mode = "clippy"
|
||||
hint = """
|
||||
`for` loops over Option values are more clearly expressed as an `if let`"""
|
||||
|
||||
# STANDARD LIBRARY TYPES
|
||||
|
||||
[[exercises]]
|
||||
|
||||
@@ -72,6 +72,7 @@ if (!($LASTEXITCODE -eq 0)) {
|
||||
# but anyone running pwsh 5 will have to pass the argument.
|
||||
$version = Invoke-WebRequest -UseBasicParsing https://api.github.com/repos/rust-lang/rustlings/releases/latest `
|
||||
| ConvertFrom-Json | Select-Object -ExpandProperty tag_name
|
||||
|
||||
Write-Host "Checking out version $version..."
|
||||
Set-Location $path
|
||||
git checkout -q tags/$version
|
||||
@@ -82,4 +83,12 @@ if (!(Get-Command rustlings -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "WARNING: Please check that you have '~/.cargo/bin' in your PATH environment variable!"
|
||||
}
|
||||
|
||||
# Checking whether Clippy is installed.
|
||||
# Due to a bug in Cargo, this must be done with Rustup: https://github.com/rust-lang/rustup/issues/1514
|
||||
$clippy = (rustup component list | Select-String "clippy" | Select-String "installed") | Out-String
|
||||
if (!$clippy) {
|
||||
Write-Host "Installing the 'cargo-clippy' executable..."
|
||||
rustup component add clippy
|
||||
}
|
||||
|
||||
Write-Host "All done! Run 'rustlings' to get started."
|
||||
|
||||
13
install.sh
13
install.sh
@@ -87,6 +87,8 @@ echo "Cloning Rustlings at $Path..."
|
||||
git clone -q https://github.com/rust-lang/rustlings $Path
|
||||
|
||||
Version=$(curl -s https://api.github.com/repos/rust-lang/rustlings/releases/latest | python -c "import json,sys;obj=json.load(sys.stdin);print(obj['tag_name']);")
|
||||
CargoBin="${CARGO_HOME:-$HOME/.cargo}/bin"
|
||||
|
||||
echo "Checking out version $Version..."
|
||||
cd $Path
|
||||
git checkout -q tags/$Version
|
||||
@@ -96,7 +98,16 @@ cargo install --force --path .
|
||||
|
||||
if ! [ -x "$(command -v rustlings)" ]
|
||||
then
|
||||
echo "WARNING: Please check that you have '~/.cargo/bin' in your PATH environment variable!"
|
||||
echo "WARNING: Please check that you have '$CargoBin' in your PATH environment variable!"
|
||||
fi
|
||||
|
||||
# Checking whether Clippy is installed.
|
||||
# Due to a bug in Cargo, this must be done with Rustup: https://github.com/rust-lang/rustup/issues/1514
|
||||
Clippy=$(rustup component list | grep "clippy" | grep "installed")
|
||||
if [ -z "$Clippy" ]
|
||||
then
|
||||
echo "Installing the 'cargo-clippy' executable..."
|
||||
rustup component add clippy
|
||||
fi
|
||||
|
||||
echo "All done! Run 'rustlings' to get started."
|
||||
|
||||
108
src/exercise.rs
108
src/exercise.rs
@@ -1,14 +1,15 @@
|
||||
use regex::Regex;
|
||||
use serde::Deserialize;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::fs::{remove_file, File};
|
||||
use std::fs::{self, remove_file, File};
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{self, Command, Output};
|
||||
use std::process::{self, Command};
|
||||
|
||||
const RUSTC_COLOR_ARGS: &[&str] = &["--color", "always"];
|
||||
const I_AM_DONE_REGEX: &str = r"(?m)^\s*///?\s*I\s+AM\s+NOT\s+DONE";
|
||||
const CONTEXT: usize = 2;
|
||||
const CLIPPY_CARGO_TOML_PATH: &str = "./exercises/clippy/Cargo.toml";
|
||||
|
||||
fn temp_file() -> String {
|
||||
format!("./temp_{}", process::id())
|
||||
@@ -19,6 +20,7 @@ fn temp_file() -> String {
|
||||
pub enum Mode {
|
||||
Compile,
|
||||
Test,
|
||||
Clippy,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -47,9 +49,34 @@ pub struct ContextLine {
|
||||
pub important: bool,
|
||||
}
|
||||
|
||||
pub struct CompiledExercise<'a> {
|
||||
exercise: &'a Exercise,
|
||||
_handle: FileHandle,
|
||||
}
|
||||
|
||||
impl<'a> CompiledExercise<'a> {
|
||||
pub fn run(&self) -> Result<ExerciseOutput, ExerciseOutput> {
|
||||
self.exercise.run()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ExerciseOutput {
|
||||
pub stdout: String,
|
||||
pub stderr: String,
|
||||
}
|
||||
|
||||
struct FileHandle;
|
||||
|
||||
impl Drop for FileHandle {
|
||||
fn drop(&mut self) {
|
||||
clean();
|
||||
}
|
||||
}
|
||||
|
||||
impl Exercise {
|
||||
pub fn compile(&self) -> Output {
|
||||
match self.mode {
|
||||
pub fn compile(&self) -> Result<CompiledExercise, ExerciseOutput> {
|
||||
let cmd = match self.mode {
|
||||
Mode::Compile => Command::new("rustc")
|
||||
.args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
@@ -58,18 +85,66 @@ impl Exercise {
|
||||
.args(&["--test", self.path.to_str().unwrap(), "-o", &temp_file()])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
.output(),
|
||||
Mode::Clippy => {
|
||||
let cargo_toml = format!(
|
||||
r#"[package]
|
||||
name = "{}"
|
||||
version = "0.0.1"
|
||||
edition = "2018"
|
||||
[[bin]]
|
||||
name = "{}"
|
||||
path = "{}.rs""#,
|
||||
self.name, self.name, self.name
|
||||
);
|
||||
fs::write(CLIPPY_CARGO_TOML_PATH, cargo_toml)
|
||||
.expect("Failed to write 📎 Clippy 📎 Cargo.toml file.");
|
||||
// Due to an issue with Clippy, a cargo clean is required to catch all lints.
|
||||
// See https://github.com/rust-lang/rust-clippy/issues/2604
|
||||
// This is already fixed on master branch. See this issue to track merging into Cargo:
|
||||
// https://github.com/rust-lang/rust-clippy/issues/3837
|
||||
Command::new("cargo")
|
||||
.args(&["clean", "--manifest-path", CLIPPY_CARGO_TOML_PATH])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
.output()
|
||||
.expect("Failed to run 'cargo clean'");
|
||||
Command::new("cargo")
|
||||
.args(&["clippy", "--manifest-path", CLIPPY_CARGO_TOML_PATH])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
.args(&["--", "-D", "warnings"])
|
||||
.output()
|
||||
}
|
||||
}
|
||||
.expect("Failed to run 'compile' command.");
|
||||
|
||||
if cmd.status.success() {
|
||||
Ok(CompiledExercise {
|
||||
exercise: &self,
|
||||
_handle: FileHandle,
|
||||
})
|
||||
} else {
|
||||
clean();
|
||||
Err(ExerciseOutput {
|
||||
stdout: String::from_utf8_lossy(&cmd.stdout).to_string(),
|
||||
stderr: String::from_utf8_lossy(&cmd.stderr).to_string(),
|
||||
})
|
||||
}
|
||||
.expect("Failed to run 'compile' command.")
|
||||
}
|
||||
|
||||
pub fn run(&self) -> Output {
|
||||
Command::new(&temp_file())
|
||||
fn run(&self) -> Result<ExerciseOutput, ExerciseOutput> {
|
||||
let cmd = Command::new(&temp_file())
|
||||
.output()
|
||||
.expect("Failed to run 'run' command")
|
||||
}
|
||||
.expect("Failed to run 'run' command");
|
||||
|
||||
pub fn clean(&self) {
|
||||
let _ignored = remove_file(&temp_file());
|
||||
let output = ExerciseOutput {
|
||||
stdout: String::from_utf8_lossy(&cmd.stdout).to_string(),
|
||||
stderr: String::from_utf8_lossy(&cmd.stderr).to_string(),
|
||||
};
|
||||
|
||||
if cmd.status.success() {
|
||||
Ok(output)
|
||||
} else {
|
||||
Err(output)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn state(&self) -> State {
|
||||
@@ -121,6 +196,10 @@ impl Display for Exercise {
|
||||
}
|
||||
}
|
||||
|
||||
fn clean() {
|
||||
let _ignored = remove_file(&temp_file());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
@@ -131,11 +210,12 @@ mod test {
|
||||
File::create(&temp_file()).unwrap();
|
||||
let exercise = Exercise {
|
||||
name: String::from("example"),
|
||||
path: PathBuf::from("example.rs"),
|
||||
mode: Mode::Test,
|
||||
path: PathBuf::from("tests/fixture/state/pending_exercise.rs"),
|
||||
mode: Mode::Compile,
|
||||
hint: String::from(""),
|
||||
};
|
||||
exercise.clean();
|
||||
let compiled = exercise.compile().unwrap();
|
||||
drop(compiled);
|
||||
assert!(!Path::new(&temp_file()).exists());
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@ use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
#[macro_use]
|
||||
mod ui;
|
||||
|
||||
mod exercise;
|
||||
mod run;
|
||||
mod verify;
|
||||
|
||||
55
src/run.rs
55
src/run.rs
@@ -1,52 +1,51 @@
|
||||
use crate::exercise::{Exercise, Mode};
|
||||
use crate::verify::test;
|
||||
use console::{style, Emoji};
|
||||
use indicatif::ProgressBar;
|
||||
|
||||
pub fn run(exercise: &Exercise) -> Result<(), ()> {
|
||||
match exercise.mode {
|
||||
Mode::Test => test(exercise)?,
|
||||
Mode::Compile => compile_and_run(exercise)?,
|
||||
Mode::Clippy => compile_and_run(exercise)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
|
||||
fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
|
||||
let compilecmd = exercise.compile();
|
||||
let compilation_result = exercise.compile();
|
||||
let compilation = match compilation_result {
|
||||
Ok(compilation) => compilation,
|
||||
Err(output) => {
|
||||
progress_bar.finish_and_clear();
|
||||
warn!(
|
||||
"Compilation of {} failed!, Compiler error message:\n",
|
||||
exercise
|
||||
);
|
||||
println!("{}", output.stderr);
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
progress_bar.set_message(format!("Running {}...", exercise).as_str());
|
||||
if compilecmd.status.success() {
|
||||
let runcmd = exercise.run();
|
||||
progress_bar.finish_and_clear();
|
||||
let result = compilation.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
if runcmd.status.success() {
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
let formatstr = format!("{} Successfully ran {}", Emoji("✅", "✓"), exercise);
|
||||
println!("{}", style(formatstr).green());
|
||||
exercise.clean();
|
||||
match result {
|
||||
Ok(output) => {
|
||||
println!("{}", output.stdout);
|
||||
success!("Successfully ran {}", exercise);
|
||||
Ok(())
|
||||
} else {
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stderr));
|
||||
}
|
||||
Err(output) => {
|
||||
println!("{}", output.stdout);
|
||||
println!("{}", output.stderr);
|
||||
|
||||
let formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), exercise);
|
||||
println!("{}", style(formatstr).red());
|
||||
exercise.clean();
|
||||
warn!("Ran {} with errors", exercise);
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
progress_bar.finish_and_clear();
|
||||
let formatstr = format!(
|
||||
"{} Compilation of {} failed! Compiler error message:\n",
|
||||
Emoji("⚠️ ", "!"),
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
23
src/ui.rs
Normal file
23
src/ui.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
macro_rules! warn {
|
||||
($fmt:literal, $ex:expr) => {{
|
||||
use console::{style, Emoji};
|
||||
let formatstr = format!($fmt, $ex);
|
||||
println!(
|
||||
"{} {}",
|
||||
style(Emoji("⚠️ ", "!")).red(),
|
||||
style(formatstr).red()
|
||||
);
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! success {
|
||||
($fmt:literal, $ex:expr) => {{
|
||||
use console::{style, Emoji};
|
||||
let formatstr = format!($fmt, $ex);
|
||||
println!(
|
||||
"{} {}",
|
||||
style(Emoji("✅", "✓")).green(),
|
||||
style(formatstr).green()
|
||||
);
|
||||
}};
|
||||
}
|
||||
108
src/verify.rs
108
src/verify.rs
@@ -1,12 +1,13 @@
|
||||
use crate::exercise::{Exercise, Mode, State};
|
||||
use console::{style, Emoji};
|
||||
use console::style;
|
||||
use indicatif::ProgressBar;
|
||||
|
||||
pub fn verify<'a>(start_at: impl IntoIterator<Item = &'a Exercise>) -> Result<(), &'a Exercise> {
|
||||
for exercise in start_at {
|
||||
let compile_result = match exercise.mode {
|
||||
Mode::Test => compile_and_test_interactively(&exercise),
|
||||
Mode::Test => compile_and_test(&exercise, RunMode::Interactive),
|
||||
Mode::Compile => compile_only(&exercise),
|
||||
Mode::Clippy => compile_only(&exercise),
|
||||
};
|
||||
if !compile_result.unwrap_or(false) {
|
||||
return Err(exercise);
|
||||
@@ -15,8 +16,13 @@ pub fn verify<'a>(start_at: impl IntoIterator<Item = &'a Exercise>) -> Result<()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
enum RunMode {
|
||||
Interactive,
|
||||
NonInteractive,
|
||||
}
|
||||
|
||||
pub fn test(exercise: &Exercise) -> Result<(), ()> {
|
||||
compile_and_test(exercise, true)?;
|
||||
compile_and_test(exercise, RunMode::NonInteractive)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -24,69 +30,64 @@ fn compile_only(exercise: &Exercise) -> Result<bool, ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
let compile_output = exercise.compile();
|
||||
let compilation_result = exercise.compile();
|
||||
progress_bar.finish_and_clear();
|
||||
if compile_output.status.success() {
|
||||
let formatstr = format!("{} Successfully compiled {}!", Emoji("✅", "✓"), exercise);
|
||||
println!("{}", style(formatstr).green());
|
||||
exercise.clean();
|
||||
Ok(prompt_for_completion(&exercise))
|
||||
} else {
|
||||
let formatstr = format!(
|
||||
"{} Compilation of {} failed! Compiler error message:\n",
|
||||
Emoji("⚠️ ", "!"),
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
|
||||
exercise.clean();
|
||||
Err(())
|
||||
|
||||
match compilation_result {
|
||||
Ok(_) => {
|
||||
success!("Successfully compiled {}!", exercise);
|
||||
Ok(prompt_for_completion(&exercise))
|
||||
}
|
||||
Err(output) => {
|
||||
warn!(
|
||||
"Compilation of {} failed! Compiler error message:\n",
|
||||
exercise
|
||||
);
|
||||
println!("{}", output.stderr);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_and_test_interactively(exercise: &Exercise) -> Result<bool, ()> {
|
||||
compile_and_test(exercise, false)
|
||||
}
|
||||
|
||||
fn compile_and_test(exercise: &Exercise, skip_prompt: bool) -> Result<bool, ()> {
|
||||
fn compile_and_test(exercise: &Exercise, run_mode: RunMode) -> Result<bool, ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Testing {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
|
||||
let compile_output = exercise.compile();
|
||||
if compile_output.status.success() {
|
||||
progress_bar.set_message(format!("Running {}...", exercise).as_str());
|
||||
let compilation_result = exercise.compile();
|
||||
|
||||
let runcmd = exercise.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
if runcmd.status.success() {
|
||||
let formatstr = format!("{} Successfully tested {}!", Emoji("✅", "✓"), exercise);
|
||||
println!("{}", style(formatstr).green());
|
||||
exercise.clean();
|
||||
Ok(skip_prompt || prompt_for_completion(exercise))
|
||||
} else {
|
||||
let formatstr = format!(
|
||||
"{} Testing of {} failed! Please try again. Here's the output:",
|
||||
Emoji("⚠️ ", "!"),
|
||||
let compilation = match compilation_result {
|
||||
Ok(compilation) => compilation,
|
||||
Err(output) => {
|
||||
progress_bar.finish_and_clear();
|
||||
warn!(
|
||||
"Compiling of {} failed! Please try again. Here's the output:",
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
exercise.clean();
|
||||
println!("{}", output.stderr);
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
let result = compilation.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
match result {
|
||||
Ok(_) => {
|
||||
if let RunMode::Interactive = run_mode {
|
||||
Ok(prompt_for_completion(&exercise))
|
||||
} else {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
Err(output) => {
|
||||
warn!(
|
||||
"Testing of {} failed! Please try again. Here's the output:",
|
||||
exercise
|
||||
);
|
||||
println!("{}", output.stdout);
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
progress_bar.finish_and_clear();
|
||||
let formatstr = format!(
|
||||
"{} Compiling of {} failed! Please try again. Here's the output:",
|
||||
Emoji("⚠️ ", "!"),
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +100,7 @@ fn prompt_for_completion(exercise: &Exercise) -> bool {
|
||||
let success_msg = match exercise.mode {
|
||||
Mode::Compile => "The code is compiling!",
|
||||
Mode::Test => "The code is compiling, and the tests pass!",
|
||||
Mode::Clippy => "The code is compiling, and 📎 Clippy 📎 is happy!",
|
||||
};
|
||||
|
||||
println!("");
|
||||
|
||||
Reference in New Issue
Block a user