mirror of
https://github.com/rust-lang/rustlings.git
synced 2026-08-14 14:26:56 +00:00
write input files to disk before running exercise
This commit is contained in:
parent
343e21b3bd
commit
c114fb3bbb
@ -81,9 +81,11 @@ impl AppState {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let dir_canonical_path = term::canonicalize("exercises");
|
let dir_canonical_path = term::canonicalize("exercises");
|
||||||
|
let official_exercises = !Path::new("info.toml").exists();
|
||||||
let mut exercises = exercise_infos
|
let mut exercises = exercise_infos
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|exercise_info| {
|
.enumerate()
|
||||||
|
.map(|(i, exercise_info)| {
|
||||||
let canonical_path = dir_canonical_path.as_deref().map(|dir_canonical_path| {
|
let canonical_path = dir_canonical_path.as_deref().map(|dir_canonical_path| {
|
||||||
let mut canonical_path;
|
let mut canonical_path;
|
||||||
if let Some(dir) = exercise_info.dir {
|
if let Some(dir) = exercise_info.dir {
|
||||||
@ -105,10 +107,16 @@ impl AppState {
|
|||||||
canonical_path.push_str(".rs");
|
canonical_path.push_str(".rs");
|
||||||
canonical_path
|
canonical_path
|
||||||
});
|
});
|
||||||
|
let embedded_input_files = if official_exercises {
|
||||||
|
EMBEDDED_FILES.exercise_files[i].input_files
|
||||||
|
} else {
|
||||||
|
&[]
|
||||||
|
};
|
||||||
|
|
||||||
Exercise {
|
Exercise {
|
||||||
name: exercise_info.name,
|
name: exercise_info.name,
|
||||||
dir: exercise_info.dir,
|
dir: exercise_info.dir,
|
||||||
|
embedded_input_files,
|
||||||
// LEAKING: For `Editor::open`. The app state is used until the end of the program.
|
// LEAKING: For `Editor::open`. The app state is used until the end of the program.
|
||||||
path: exercise_info.path().leak(),
|
path: exercise_info.path().leak(),
|
||||||
canonical_path,
|
canonical_path,
|
||||||
@ -173,7 +181,7 @@ impl AppState {
|
|||||||
final_message,
|
final_message,
|
||||||
state_file,
|
state_file,
|
||||||
file_buf,
|
file_buf,
|
||||||
official_exercises: !Path::new("info.toml").exists(),
|
official_exercises,
|
||||||
cmd_runner,
|
cmd_runner,
|
||||||
// VS Code has its own file link handling
|
// VS Code has its own file link handling
|
||||||
emit_file_links: !vs_code_term,
|
emit_file_links: !vs_code_term,
|
||||||
@ -597,6 +605,7 @@ mod tests {
|
|||||||
Exercise {
|
Exercise {
|
||||||
name: "0",
|
name: "0",
|
||||||
dir: None,
|
dir: None,
|
||||||
|
embedded_input_files: &[],
|
||||||
path: "exercises/0.rs",
|
path: "exercises/0.rs",
|
||||||
canonical_path: None,
|
canonical_path: None,
|
||||||
test: false,
|
test: false,
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use crate::info_file::ExerciseInfo;
|
|||||||
pub static EMBEDDED_FILES: EmbeddedFiles = rustlings_macros::include_files!();
|
pub static EMBEDDED_FILES: EmbeddedFiles = rustlings_macros::include_files!();
|
||||||
|
|
||||||
// Files related to one exercise.
|
// Files related to one exercise.
|
||||||
struct ExerciseFiles {
|
pub struct ExerciseFiles {
|
||||||
// The content of the exercise file.
|
// The content of the exercise file.
|
||||||
exercise: &'static [u8],
|
exercise: &'static [u8],
|
||||||
// The content of the solution file.
|
// The content of the solution file.
|
||||||
@ -18,7 +18,7 @@ struct ExerciseFiles {
|
|||||||
// Index of the related `ExerciseDir` in `EmbeddedFiles::exercise_dirs`.
|
// Index of the related `ExerciseDir` in `EmbeddedFiles::exercise_dirs`.
|
||||||
dir_ind: usize,
|
dir_ind: usize,
|
||||||
// Files that are read by the exercise.
|
// Files that are read by the exercise.
|
||||||
input_files: &'static [InputFile],
|
pub input_files: &'static [InputFile],
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input files that may be read by exercises.
|
// Input files that may be read by exercises.
|
||||||
@ -64,7 +64,7 @@ impl ExerciseDir {
|
|||||||
pub struct EmbeddedFiles {
|
pub struct EmbeddedFiles {
|
||||||
/// The content of the `info.toml` file.
|
/// The content of the `info.toml` file.
|
||||||
pub info_file: &'static str,
|
pub info_file: &'static str,
|
||||||
exercise_files: &'static [ExerciseFiles],
|
pub exercise_files: &'static [ExerciseFiles],
|
||||||
pub exercise_dirs: &'static [ExerciseDir],
|
pub exercise_dirs: &'static [ExerciseDir],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
QueueableCommand,
|
QueueableCommand,
|
||||||
style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
|
style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
|
||||||
@ -7,6 +7,7 @@ use std::io::{self, StdoutLock, Write};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cmd::CmdRunner,
|
cmd::CmdRunner,
|
||||||
|
embedded::InputFile,
|
||||||
term::{self, CountedWrite, file_path, terminal_file_link, write_ansi},
|
term::{self, CountedWrite, file_path, terminal_file_link, write_ansi},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -69,6 +70,7 @@ fn run_bin(
|
|||||||
pub struct Exercise {
|
pub struct Exercise {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub dir: Option<&'static str>,
|
pub dir: Option<&'static str>,
|
||||||
|
pub embedded_input_files: &'static [InputFile],
|
||||||
/// Path of the exercise file starting with the `exercises/` directory.
|
/// Path of the exercise file starting with the `exercises/` directory.
|
||||||
pub path: &'static str,
|
pub path: &'static str,
|
||||||
pub canonical_path: Option<String>,
|
pub canonical_path: Option<String>,
|
||||||
@ -99,6 +101,7 @@ pub trait RunnableExercise {
|
|||||||
fn dir(&self) -> Option<&str>;
|
fn dir(&self) -> Option<&str>;
|
||||||
fn strict_clippy(&self) -> bool;
|
fn strict_clippy(&self) -> bool;
|
||||||
fn test(&self) -> bool;
|
fn test(&self) -> bool;
|
||||||
|
fn embedded_input_files(&self) -> &[InputFile];
|
||||||
|
|
||||||
// Compile, check and run the exercise or its solution (depending on `bin_name´).
|
// Compile, check and run the exercise or its solution (depending on `bin_name´).
|
||||||
// The output is written to the `output` buffer after clearing it.
|
// The output is written to the `output` buffer after clearing it.
|
||||||
@ -112,6 +115,19 @@ pub trait RunnableExercise {
|
|||||||
output.clear();
|
output.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Input files are already written to disk during `rustlings init`.
|
||||||
|
// We repeat it here to ensure an exercise doesn't fail because the
|
||||||
|
// input files were deleted or modified in the meantime. Note that
|
||||||
|
// `self.embedded_input_files()` is empty for community exercises.
|
||||||
|
for input_file in self.embedded_input_files() {
|
||||||
|
let name = input_file.name;
|
||||||
|
let path = match self.dir() {
|
||||||
|
Some(dir) => format!("exercises/{dir}/{name}"),
|
||||||
|
None => format!("exercises/{name}"),
|
||||||
|
};
|
||||||
|
std::fs::write(path, input_file.content).context("failed to write input file")?;
|
||||||
|
}
|
||||||
|
|
||||||
let build_success = cmd_runner
|
let build_success = cmd_runner
|
||||||
.cargo("build", bin_name, output.as_deref_mut())
|
.cargo("build", bin_name, output.as_deref_mut())
|
||||||
.run("cargo build …")?;
|
.run("cargo build …")?;
|
||||||
@ -224,4 +240,8 @@ impl RunnableExercise for Exercise {
|
|||||||
fn test(&self) -> bool {
|
fn test(&self) -> bool {
|
||||||
self.test
|
self.test
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn embedded_input_files(&self) -> &[InputFile] {
|
||||||
|
self.embedded_input_files
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,10 @@ use anyhow::{Context, Error, Result, bail};
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{fs, io::ErrorKind};
|
use std::{fs, io::ErrorKind};
|
||||||
|
|
||||||
use crate::{embedded::EMBEDDED_FILES, exercise::RunnableExercise};
|
use crate::{
|
||||||
|
embedded::{EMBEDDED_FILES, InputFile},
|
||||||
|
exercise::RunnableExercise,
|
||||||
|
};
|
||||||
|
|
||||||
/// Deserialized from the `info.toml` file.
|
/// Deserialized from the `info.toml` file.
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@ -72,6 +75,11 @@ impl RunnableExercise for ExerciseInfo<'_> {
|
|||||||
fn test(&self) -> bool {
|
fn test(&self) -> bool {
|
||||||
self.test
|
self.test
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn embedded_input_files(&self) -> &[InputFile] {
|
||||||
|
// We don't have the input files embedded for communtiy exercises.
|
||||||
|
&[]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The deserialized `info.toml` file.
|
/// The deserialized `info.toml` file.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user