Skip to content

Commit

Permalink
Merge pull request rust-lang#1151 from magnusrodseth/1031-reset-exercise
Browse files Browse the repository at this point in the history
Add reset command for a given filename
  • Loading branch information
shadows-withal authored Aug 18, 2022
2 parents fb7d3bf + d59dde3 commit 96098d2
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 20 deletions.
75 changes: 56 additions & 19 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::exercise::{Exercise, ExerciseList};
use crate::project::RustAnalyzerProject;
use crate::run::run;
use crate::run::{reset, run};
use crate::verify::verify;
use argh::FromArgs;
use console::Emoji;
Expand Down Expand Up @@ -47,6 +47,7 @@ enum Subcommands {
Verify(VerifyArgs),
Watch(WatchArgs),
Run(RunArgs),
Reset(ResetArgs),
Hint(HintArgs),
List(ListArgs),
Lsp(LspArgs),
Expand All @@ -71,6 +72,15 @@ struct RunArgs {
name: String,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "reset")]
/// Resets a single exercise using "git stash -- <filename>"
struct ResetArgs {
#[argh(positional)]
/// the name of the exercise
name: String,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "hint")]
/// Returns a hint for the given exercise
Expand All @@ -85,7 +95,6 @@ struct HintArgs {
/// Enable rust-analyzer for exercises
struct LspArgs {}


#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "list")]
/// Lists the exercises available in Rustlings
Expand Down Expand Up @@ -164,7 +173,9 @@ fn main() {
"Pending"
};
let solve_cond = {
(e.looks_done() && subargs.solved) || (!e.looks_done() && subargs.unsolved) || (!subargs.solved && !subargs.unsolved)
(e.looks_done() && subargs.solved)
|| (!e.looks_done() && subargs.unsolved)
|| (!subargs.solved && !subargs.unsolved)
};
if solve_cond && (filter_cond || subargs.filter.is_none()) {
let line = if subargs.paths {
Expand Down Expand Up @@ -205,14 +216,21 @@ fn main() {
run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1));
}

Subcommands::Reset(subargs) => {
let exercise = find_exercise(&subargs.name, &exercises);

reset(exercise).unwrap_or_else(|_| std::process::exit(1));
}

Subcommands::Hint(subargs) => {
let exercise = find_exercise(&subargs.name, &exercises);

println!("{}", exercise.hint);
}

Subcommands::Verify(_subargs) => {
verify(&exercises, (0, exercises.len()), verbose).unwrap_or_else(|_| std::process::exit(1));
verify(&exercises, (0, exercises.len()), verbose)
.unwrap_or_else(|_| std::process::exit(1));
}

Subcommands::Lsp(_subargs) => {
Expand All @@ -236,12 +254,18 @@ fn main() {

Subcommands::Watch(_subargs) => match watch(&exercises, verbose) {
Err(e) => {
println!("Error: Could not watch your progress. Error message was {:?}.", e);
println!(
"Error: Could not watch your progress. Error message was {:?}.",
e
);
println!("Most likely you've run out of disk space or your 'inotify limit' has been reached.");
std::process::exit(1);
}
Ok(WatchStatus::Finished) => {
println!("{emoji} All exercises completed! {emoji}", emoji = Emoji("🎉", "★"));
println!(
"{emoji} All exercises completed! {emoji}",
emoji = Emoji("🎉", "★")
);
println!("\n{}\n", FENISH_LINE);
}
Ok(WatchStatus::Unfinished) => {
Expand All @@ -252,8 +276,10 @@ fn main() {
}
}


fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>, should_quit: Arc<AtomicBool>) {
fn spawn_watch_shell(
failed_exercise_hint: &Arc<Mutex<Option<String>>>,
should_quit: Arc<AtomicBool>,
) {
let failed_exercise_hint = Arc::clone(failed_exercise_hint);
println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.");
thread::spawn(move || loop {
Expand Down Expand Up @@ -290,16 +316,22 @@ fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>, should_q

fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
if name.eq("next") {
exercises.iter().find(|e| !e.looks_done()).unwrap_or_else(|| {
println!("🎉 Congratulations! You have done all the exercises!");
println!("🔚 There are no more exercises to do next!");
std::process::exit(1)
})
exercises
.iter()
.find(|e| !e.looks_done())
.unwrap_or_else(|| {
println!("🎉 Congratulations! You have done all the exercises!");
println!("🔚 There are no more exercises to do next!");
std::process::exit(1)
})
} else {
exercises.iter().find(|e| e.name == name).unwrap_or_else(|| {
println!("No exercise found for '{}'!", name);
std::process::exit(1)
})
exercises
.iter()
.find(|e| e.name == name)
.unwrap_or_else(|| {
println!("No exercise found for '{}'!", name);
std::process::exit(1)
})
}
}

Expand Down Expand Up @@ -337,8 +369,13 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<WatchStatus> {
let filepath = b.as_path().canonicalize().unwrap();
let pending_exercises = exercises
.iter()
.find(|e| filepath.ends_with(&e.path)).into_iter()
.chain(exercises.iter().filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)));
.find(|e| filepath.ends_with(&e.path))
.into_iter()
.chain(
exercises
.iter()
.filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)),
);
let num_done = exercises.iter().filter(|e| e.looks_done()).count();
clear_screen();
match verify(pending_exercises, (num_done, exercises.len()), verbose) {
Expand Down
15 changes: 15 additions & 0 deletions src/run.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::process::Command;

use crate::exercise::{Exercise, Mode};
use crate::verify::test;
use indicatif::ProgressBar;
Expand All @@ -15,6 +17,19 @@ pub fn run(exercise: &Exercise, verbose: bool) -> Result<(), ()> {
Ok(())
}

// Resets the exercise by stashing the changes.
pub fn reset(exercise: &Exercise) -> Result<(), ()> {
let command = Command::new("git")
.args(["stash", "--"])
.arg(&exercise.path)
.spawn();

match command {
Ok(_) => Ok(()),
Err(_) => Err(()),
}
}

// Invoke the rust compiler on the path of the given exercise
// and run the ensuing binary.
// This is strictly for non-test binaries, so output is displayed
Expand Down
23 changes: 22 additions & 1 deletion tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,27 @@ fn run_single_test_no_exercise() {
.code(1);
}

#[test]
fn reset_single_exercise() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["reset", "intro1"])
.assert()
.code(0);
}

#[test]
fn reset_no_exercise() {
Command::cargo_bin("rustlings")
.unwrap()
.arg("reset")
.assert()
.code(1)
.stderr(predicates::str::contains(
"positional arguments not provided",
));
}

#[test]
fn get_hint_for_single_test() {
Command::cargo_bin("rustlings")
Expand All @@ -126,7 +147,7 @@ fn all_exercises_require_confirmation() {
for exercise in glob("exercises/**/*.rs").unwrap() {
let path = exercise.unwrap();
if path.file_name().unwrap() == "mod.rs" {
continue
continue;
}
let source = {
let mut file = File::open(&path).unwrap();
Expand Down

0 comments on commit 96098d2

Please sign in to comment.