summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormo8it <mo8it@proton.me>2024-03-31 18:25:54 +0200
committermo8it <mo8it@proton.me>2024-03-31 18:25:54 +0200
commitc1de4d46aad38d315e061b7262f773f48c6aab63 (patch)
treef4dd2c27e9dca918d0ae24391f4f079fda715b30 /src
parent82b563f1654860ba3590d91ec3c0f321e3130ae2 (diff)
Some improvements to error handling
Diffstat (limited to 'src')
-rw-r--r--src/exercise.rs23
-rw-r--r--src/main.rs84
-rw-r--r--src/verify.rs14
3 files changed, 55 insertions, 66 deletions
diff --git a/src/exercise.rs b/src/exercise.rs
index 83d444f..48aaedd 100644
--- a/src/exercise.rs
+++ b/src/exercise.rs
@@ -114,14 +114,9 @@ impl Exercise {
}
}
- pub fn state(&self) -> State {
- let source_file = File::open(&self.path).unwrap_or_else(|e| {
- println!(
- "Failed to open the exercise file {}: {e}",
- self.path.display(),
- );
- exit(1);
- });
+ pub fn state(&self) -> Result<State> {
+ let source_file = File::open(&self.path)
+ .with_context(|| format!("Failed to open the exercise file {}", self.path.display()))?;
let mut source_reader = BufReader::new(source_file);
// Read the next line into `buf` without the newline at the end.
@@ -152,7 +147,7 @@ impl Exercise {
// Reached the end of the file and didn't find the comment.
if n == 0 {
- return State::Done;
+ return Ok(State::Done);
}
if contains_not_done_comment(&line) {
@@ -198,7 +193,7 @@ impl Exercise {
});
}
- return State::Pending(context);
+ return Ok(State::Pending(context));
}
current_line_number += 1;
@@ -218,8 +213,8 @@ impl Exercise {
// without actually having solved anything.
// The only other way to truly check this would to compile and run
// the exercise; which would be both costly and counterintuitive
- pub fn looks_done(&self) -> bool {
- self.state() == State::Done
+ pub fn looks_done(&self) -> Result<bool> {
+ self.state().map(|state| state == State::Done)
}
}
@@ -271,7 +266,7 @@ mod test {
},
];
- assert_eq!(state, State::Pending(expected));
+ assert_eq!(state.unwrap(), State::Pending(expected));
}
#[test]
@@ -283,7 +278,7 @@ mod test {
hint: String::new(),
};
- assert_eq!(exercise.state(), State::Done);
+ assert_eq!(exercise.state().unwrap(), State::Done);
}
#[test]
diff --git a/src/main.rs b/src/main.rs
index 1c736f3..72bff4d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -92,14 +92,11 @@ fn main() -> Result<()> {
println!("\n{WELCOME}\n");
}
- if which::which("cargo").is_err() {
- println!(
- "Failed to find `cargo`.
+ which::which("cargo").context(
+ "Failed to find `cargo`.
Did you already install Rust?
-Try running `cargo --version` to diagnose the problem."
- );
- std::process::exit(1);
- }
+Try running `cargo --version` to diagnose the problem.",
+ )?;
let exercises = ExerciseList::parse()?.exercises;
@@ -122,7 +119,7 @@ If you are just starting with Rustlings, run the command `rustlings init` to ini
let verbose = args.nocapture;
let command = args.command.unwrap_or_else(|| {
println!("{DEFAULT_OUT}\n");
- std::process::exit(0);
+ exit(0);
});
match command {
@@ -160,7 +157,7 @@ If you are just starting with Rustlings, run the command `rustlings init` to ini
let filter_cond = filters
.iter()
.any(|f| exercise.name.contains(f) || fname.contains(f));
- let looks_done = exercise.looks_done();
+ let looks_done = exercise.looks_done()?;
let status = if looks_done {
exercises_done += 1;
"Done"
@@ -185,8 +182,8 @@ If you are just starting with Rustlings, run the command `rustlings init` to ini
let mut handle = stdout.lock();
handle.write_all(line.as_bytes()).unwrap_or_else(|e| {
match e.kind() {
- std::io::ErrorKind::BrokenPipe => std::process::exit(0),
- _ => std::process::exit(1),
+ std::io::ErrorKind::BrokenPipe => exit(0),
+ _ => exit(1),
};
});
}
@@ -200,35 +197,34 @@ If you are just starting with Rustlings, run the command `rustlings init` to ini
exercises.len(),
percentage_progress
);
- std::process::exit(0);
+ exit(0);
}
Subcommands::Run { name } => {
- let exercise = find_exercise(&name, &exercises);
- run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1));
+ let exercise = find_exercise(&name, &exercises)?;
+ run(exercise, verbose).unwrap_or_else(|_| exit(1));
}
Subcommands::Reset { name } => {
- let exercise = find_exercise(&name, &exercises);
+ let exercise = find_exercise(&name, &exercises)?;
reset(exercise)?;
println!("The file {} has been reset!", exercise.path.display());
}
Subcommands::Hint { name } => {
- let exercise = find_exercise(&name, &exercises);
+ let exercise = find_exercise(&name, &exercises)?;
println!("{}", exercise.hint);
}
Subcommands::Verify => {
- verify(&exercises, (0, exercises.len()), verbose, false)
- .unwrap_or_else(|_| std::process::exit(1));
+ verify(&exercises, (0, exercises.len()), verbose, false).unwrap_or_else(|_| exit(1));
}
Subcommands::Watch { success_hints } => match watch(&exercises, verbose, success_hints) {
Err(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);
+ exit(1);
}
Ok(WatchStatus::Finished) => {
println!(
@@ -295,25 +291,23 @@ fn spawn_watch_shell(
});
}
-fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
+fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> Result<&'a Exercise> {
if name == "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)
- })
- } else {
- exercises
- .iter()
- .find(|e| e.name == name)
- .unwrap_or_else(|| {
- println!("No exercise found for '{name}'!");
- std::process::exit(1)
- })
+ for exercise in exercises {
+ if !exercise.looks_done()? {
+ return Ok(exercise);
+ }
+ }
+
+ println!("🎉 Congratulations! You have done all the exercises!");
+ println!("🔚 There are no more exercises to do next!");
+ exit(0);
}
+
+ exercises
+ .iter()
+ .find(|e| e.name == name)
+ .with_context(|| format!("No exercise found for '{name}'!"))
}
enum WatchStatus {
@@ -363,17 +357,17 @@ fn watch(
&& event_path.exists()
{
let filepath = event_path.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)
- }));
+ // TODO: Remove unwrap
+ let pending_exercises = exercises
+ .iter()
+ .find(|e| filepath.ends_with(&e.path))
+ .into_iter()
+ .chain(exercises.iter().filter(|e| {
+ !e.looks_done().unwrap() && !filepath.ends_with(&e.path)
+ }));
let num_done = exercises
.iter()
- .filter(|e| e.looks_done() && !filepath.ends_with(&e.path))
+ .filter(|e| e.looks_done().unwrap() && !filepath.ends_with(&e.path))
.count();
clear_screen();
match verify(
diff --git a/src/verify.rs b/src/verify.rs
index 56c6779..adfd3b2 100644
--- a/src/verify.rs
+++ b/src/verify.rs
@@ -79,7 +79,7 @@ fn compile_only(exercise: &Exercise, success_hints: bool) -> Result<bool> {
let _ = exercise.run()?;
progress_bar.finish_and_clear();
- Ok(prompt_for_completion(exercise, None, success_hints))
+ prompt_for_completion(exercise, None, success_hints)
}
// Compile the given Exercise and run the resulting binary in an interactive mode
@@ -102,7 +102,7 @@ fn compile_and_run_interactively(exercise: &Exercise, success_hints: bool) -> Re
bail!("TODO");
}
- Ok(prompt_for_completion(exercise, Some(output), success_hints))
+ prompt_for_completion(exercise, Some(output), success_hints)
}
// Compile the given Exercise as a test harness and display
@@ -139,7 +139,7 @@ fn compile_and_test(
}
if run_mode == RunMode::Interactive {
- Ok(prompt_for_completion(exercise, None, success_hints))
+ prompt_for_completion(exercise, None, success_hints)
} else {
Ok(true)
}
@@ -149,9 +149,9 @@ fn prompt_for_completion(
exercise: &Exercise,
prompt_output: Option<Output>,
success_hints: bool,
-) -> bool {
- let context = match exercise.state() {
- State::Done => return true,
+) -> Result<bool> {
+ let context = match exercise.state()? {
+ State::Done => return Ok(true),
State::Pending(context) => context,
};
match exercise.mode {
@@ -215,7 +215,7 @@ fn prompt_for_completion(
);
}
- false
+ Ok(false)
}
fn separator() -> console::StyledObject<&'static str> {