diff --git a/src/embedded.rs b/src/embedded.rs index 1dce46c5..51a14b6a 100644 --- a/src/embedded.rs +++ b/src/embedded.rs @@ -1,7 +1,7 @@ use anyhow::{Context, Error, Result}; use std::{ - fs::{create_dir, OpenOptions}, - io::{self, Write}, + fs::{self, create_dir}, + io, }; use crate::info_file::ExerciseInfo; @@ -9,29 +9,6 @@ use crate::info_file::ExerciseInfo; /// Contains all embedded files. pub static EMBEDDED_FILES: EmbeddedFiles = rustlings_macros::include_files!(); -#[derive(Clone, Copy)] -pub enum WriteStrategy { - IfNotExists, - Overwrite, -} - -impl WriteStrategy { - fn write(self, path: &str, content: &[u8]) -> Result<()> { - let file = match self { - Self::IfNotExists => OpenOptions::new().create_new(true).write(true).open(path), - Self::Overwrite => OpenOptions::new() - .create(true) - .write(true) - .truncate(true) - .open(path), - }; - - file.with_context(|| format!("Failed to open the file `{path}` in write mode"))? - .write_all(content) - .with_context(|| format!("Failed to write the file {path}")) - } -} - // Files related to one exercise. struct ExerciseFiles { // The content of the exercise file. @@ -42,6 +19,16 @@ struct ExerciseFiles { dir_ind: usize, } +fn create_dir_if_not_exists(path: &str) -> Result<()> { + if let Err(e) = create_dir(path) { + if e.kind() != io::ErrorKind::AlreadyExists { + return Err(Error::from(e).context(format!("Failed to create the directory {path}"))); + } + } + + Ok(()) +} + // A directory in the `exercises/` directory. pub struct ExerciseDir { pub name: &'static str, @@ -55,21 +42,13 @@ impl ExerciseDir { let mut dir_path = String::with_capacity(20 + self.name.len()); dir_path.push_str("exercises/"); dir_path.push_str(self.name); - - if let Err(e) = create_dir(&dir_path) { - if e.kind() == io::ErrorKind::AlreadyExists { - return Ok(()); - } - - return Err( - Error::from(e).context(format!("Failed to create the directory {dir_path}")) - ); - } + create_dir_if_not_exists(&dir_path)?; let mut readme_path = dir_path; readme_path.push_str("/README.md"); - WriteStrategy::Overwrite.write(&readme_path, self.readme) + fs::write(&readme_path, self.readme) + .with_context(|| format!("Failed to write the file {readme_path}")) } } @@ -86,17 +65,31 @@ impl EmbeddedFiles { pub fn init_exercises_dir(&self, exercise_infos: &[ExerciseInfo]) -> Result<()> { create_dir("exercises").context("Failed to create the directory `exercises`")?; - WriteStrategy::IfNotExists.write( + fs::write( "exercises/README.md", include_bytes!("../exercises/README.md"), - )?; + ) + .context("Failed to write the file exercises/README.md")?; for dir in self.exercise_dirs { dir.init_on_disk()?; } + let mut exercise_path = String::with_capacity(64); + let prefix = "exercises/"; + exercise_path.push_str(prefix); + for (exercise_info, exercise_files) in exercise_infos.iter().zip(self.exercise_files) { - WriteStrategy::IfNotExists.write(&exercise_info.path(), exercise_files.exercise)?; + let dir = &self.exercise_dirs[exercise_files.dir_ind]; + + exercise_path.truncate(prefix.len()); + exercise_path.push_str(dir.name); + exercise_path.push('/'); + exercise_path.push_str(&exercise_info.name); + exercise_path.push_str(".rs"); + + fs::write(&exercise_path, exercise_files.exercise) + .with_context(|| format!("Failed to write the exercise file {exercise_path}"))?; } Ok(()) @@ -107,7 +100,8 @@ impl EmbeddedFiles { let dir = &self.exercise_dirs[exercise_files.dir_ind]; dir.init_on_disk()?; - WriteStrategy::Overwrite.write(path, exercise_files.exercise) + fs::write(path, exercise_files.exercise) + .with_context(|| format!("Failed to write the exercise file {path}")) } /// Write the solution file to disk and return its path. @@ -116,19 +110,25 @@ impl EmbeddedFiles { exercise_ind: usize, exercise_name: &str, ) -> Result { + create_dir_if_not_exists("solutions")?; + let exercise_files = &self.exercise_files[exercise_ind]; let dir = &self.exercise_dirs[exercise_files.dir_ind]; // 14 = 10 + 1 + 3 // solutions/ + / + .rs - let mut solution_path = String::with_capacity(14 + dir.name.len() + exercise_name.len()); - solution_path.push_str("solutions/"); - solution_path.push_str(dir.name); + let mut dir_path = String::with_capacity(14 + dir.name.len() + exercise_name.len()); + dir_path.push_str("solutions/"); + dir_path.push_str(dir.name); + create_dir_if_not_exists(&dir_path)?; + + let mut solution_path = dir_path; solution_path.push('/'); solution_path.push_str(exercise_name); solution_path.push_str(".rs"); - WriteStrategy::Overwrite.write(&solution_path, exercise_files.solution)?; + fs::write(&solution_path, exercise_files.solution) + .with_context(|| format!("Failed to write the solution file {solution_path}"))?; Ok(solution_path) }