diff --git a/solutions/00_intro/intro1.rs b/solutions/00_intro/intro1.rs index 07d4e4fd..4fe84549 100644 --- a/solutions/00_intro/intro1.rs +++ b/solutions/00_intro/intro1.rs @@ -1,2 +1,5 @@ -// The exercise `intro1` only requires entering `n` in the terminal to go to the next exercise. -// It is just an introduction to how Rustlings works. +fn main() { + // Congratulations, you finished the first exercise 🎉 + // As an introduction to Rustlings, the first exercise only required + // entering `n` in the terminal to go to the next exercise. +} diff --git a/src/cargo_toml.rs b/src/cargo_toml.rs index b7951f6b..cf17acd4 100644 --- a/src/cargo_toml.rs +++ b/src/cargo_toml.rs @@ -1,4 +1,5 @@ use anyhow::{Context, Result}; +use std::path::Path; use crate::info_file::ExerciseInfo; @@ -40,6 +41,24 @@ pub fn append_bins( } buf.extend_from_slice(exercise_info.name.as_bytes()); buf.extend_from_slice(b".rs\" },\n"); + + let sol_path = exercise_info.sol_path(); + if !Path::new(&sol_path).exists() { + continue; + } + + buf.extend_from_slice(b" { name = \""); + buf.extend_from_slice(exercise_info.name.as_bytes()); + buf.extend_from_slice(b"_sol"); + buf.extend_from_slice(b"\", path = \""); + buf.extend_from_slice(exercise_path_prefix); + buf.extend_from_slice(b"solutions/"); + if let Some(dir) = &exercise_info.dir { + buf.extend_from_slice(dir.as_bytes()); + buf.push(b'/'); + } + buf.extend_from_slice(exercise_info.name.as_bytes()); + buf.extend_from_slice(b".rs\" },\n"); } } diff --git a/src/embedded.rs b/src/embedded.rs index e710a4e5..1dce46c5 100644 --- a/src/embedded.rs +++ b/src/embedded.rs @@ -1,6 +1,6 @@ use anyhow::{Context, Error, Result}; use std::{ - fs::{create_dir, create_dir_all, OpenOptions}, + fs::{create_dir, OpenOptions}, io::{self, Write}, }; @@ -43,8 +43,8 @@ struct ExerciseFiles { } // A directory in the `exercises/` directory. -struct ExerciseDir { - name: &'static str, +pub struct ExerciseDir { + pub name: &'static str, readme: &'static [u8], } @@ -78,7 +78,7 @@ pub struct EmbeddedFiles { /// The content of the `info.toml` file. pub info_file: &'static str, exercise_files: &'static [ExerciseFiles], - exercise_dirs: &'static [ExerciseDir], + pub exercise_dirs: &'static [ExerciseDir], } impl EmbeddedFiles { @@ -121,13 +121,9 @@ impl EmbeddedFiles { // 14 = 10 + 1 + 3 // solutions/ + / + .rs - 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_all(&dir_path) - .with_context(|| format!("Failed to create the directory {dir_path}"))?; - - let mut solution_path = dir_path; + 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); solution_path.push('/'); solution_path.push_str(exercise_name); solution_path.push_str(".rs"); diff --git a/src/info_file.rs b/src/info_file.rs index 0c459284..5ea487fc 100644 --- a/src/info_file.rs +++ b/src/info_file.rs @@ -49,6 +49,30 @@ impl ExerciseInfo { path } + + /// Path to the solution file starting with the `solutions/` directory. + pub fn sol_path(&self) -> String { + let mut path = if let Some(dir) = &self.dir { + // 14 = 10 + 1 + 3 + // solutions/ + / + .rs + let mut path = String::with_capacity(14 + dir.len() + self.name.len()); + path.push_str("solutions/"); + path.push_str(dir); + path.push('/'); + path + } else { + // 13 = 10 + 3 + // solutions/ + .rs + let mut path = String::with_capacity(13 + self.name.len()); + path.push_str("solutions/"); + path + }; + + path.push_str(&self.name); + path.push_str(".rs"); + + path + } } /// The deserialized `info.toml` file. diff --git a/src/init.rs b/src/init.rs index 67d8a243..4063ca75 100644 --- a/src/init.rs +++ b/src/init.rs @@ -34,6 +34,20 @@ pub fn init() -> Result<()> { .init_exercises_dir(&info_file.exercises) .context("Failed to initialize the `rustlings/exercises` directory")?; + create_dir("solutions").context("Failed to create the `solutions/` directory")?; + for dir in EMBEDDED_FILES.exercise_dirs { + let mut dir_path = String::with_capacity(10 + dir.name.len()); + dir_path.push_str("solutions/"); + dir_path.push_str(dir.name); + create_dir(&dir_path) + .with_context(|| format!("Failed to create the directory {dir_path}"))?; + } + for exercise_info in &info_file.exercises { + let solution_path = exercise_info.sol_path(); + fs::write(&solution_path, INIT_SOLUTION_FILE) + .with_context(|| format!("Failed to create the file {solution_path}"))?; + } + let current_cargo_toml = include_str!("../dev-Cargo.toml"); // Skip the first line (comment). let newline_ind = current_cargo_toml @@ -72,6 +86,12 @@ pub fn init() -> Result<()> { Ok(()) } +const INIT_SOLUTION_FILE: &[u8] = b"fn main() { + // DON'T EDIT THIS SOLUTION FILE! + // It will be automatically filled after you finish the exercise. +} +"; + const GITIGNORE: &[u8] = b".rustlings-state.txt solutions Cargo.lock