2024-03-28 16:06:36 -04:00
|
|
|
use std::{
|
|
|
|
fs::{create_dir, File, OpenOptions},
|
|
|
|
io::{self, Write},
|
|
|
|
path::Path,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub static EMBEDDED_FILES: EmbeddedFiles = rustlings_macros::include_files!();
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub enum WriteStrategy {
|
|
|
|
IfNotExists,
|
|
|
|
Overwrite,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl WriteStrategy {
|
|
|
|
fn open<P: AsRef<Path>>(self, path: P) -> io::Result<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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct EmbeddedFile {
|
|
|
|
path: &'static str,
|
|
|
|
content: &'static [u8],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EmbeddedFile {
|
|
|
|
fn write_to_disk(&self, strategy: WriteStrategy) -> io::Result<()> {
|
|
|
|
strategy.open(self.path)?.write_all(self.content)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct EmbeddedFlatDir {
|
|
|
|
path: &'static str,
|
|
|
|
readme: EmbeddedFile,
|
|
|
|
content: &'static [EmbeddedFile],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EmbeddedFlatDir {
|
|
|
|
fn init_on_disk(&self) -> io::Result<()> {
|
|
|
|
let path = Path::new(self.path);
|
|
|
|
|
|
|
|
if let Err(e) = create_dir(path) {
|
|
|
|
if !path.is_dir() {
|
|
|
|
return Err(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-28 17:11:16 -04:00
|
|
|
self.readme.write_to_disk(WriteStrategy::Overwrite)?;
|
|
|
|
|
|
|
|
Ok(())
|
2024-03-28 16:06:36 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ExercisesDir {
|
|
|
|
readme: EmbeddedFile,
|
|
|
|
files: &'static [EmbeddedFile],
|
|
|
|
dirs: &'static [EmbeddedFlatDir],
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct EmbeddedFiles {
|
|
|
|
exercises_dir: ExercisesDir,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EmbeddedFiles {
|
|
|
|
pub fn init_exercises_dir(&self) -> io::Result<()> {
|
|
|
|
create_dir("exercises")?;
|
2024-03-28 17:11:16 -04:00
|
|
|
|
2024-03-28 16:06:36 -04:00
|
|
|
self.exercises_dir
|
|
|
|
.readme
|
2024-03-28 17:11:16 -04:00
|
|
|
.write_to_disk(WriteStrategy::IfNotExists)?;
|
|
|
|
|
|
|
|
for file in self.exercises_dir.files {
|
|
|
|
file.write_to_disk(WriteStrategy::IfNotExists)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
for dir in self.exercises_dir.dirs {
|
|
|
|
dir.init_on_disk()?;
|
|
|
|
|
|
|
|
for file in dir.content {
|
|
|
|
file.write_to_disk(WriteStrategy::IfNotExists)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
2024-03-28 16:06:36 -04:00
|
|
|
}
|
|
|
|
|
2024-04-13 20:41:19 -04:00
|
|
|
pub fn write_exercise_to_disk<P>(&self, path: P, strategy: WriteStrategy) -> io::Result<()>
|
|
|
|
where
|
|
|
|
P: AsRef<Path>,
|
|
|
|
{
|
|
|
|
let path = path.as_ref();
|
|
|
|
|
2024-03-28 16:06:36 -04:00
|
|
|
if let Some(file) = self
|
|
|
|
.exercises_dir
|
|
|
|
.files
|
|
|
|
.iter()
|
2024-03-30 19:49:19 -04:00
|
|
|
.find(|file| Path::new(file.path) == path)
|
2024-03-28 16:06:36 -04:00
|
|
|
{
|
|
|
|
return file.write_to_disk(strategy);
|
|
|
|
}
|
|
|
|
|
|
|
|
for dir in self.exercises_dir.dirs {
|
2024-03-30 19:49:19 -04:00
|
|
|
if let Some(file) = dir.content.iter().find(|file| Path::new(file.path) == path) {
|
2024-03-28 16:06:36 -04:00
|
|
|
dir.init_on_disk()?;
|
|
|
|
return file.write_to_disk(strategy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-30 16:15:11 -04:00
|
|
|
Err(io::Error::new(
|
|
|
|
io::ErrorKind::NotFound,
|
|
|
|
format!("{} not found in the embedded files", path.display()),
|
|
|
|
))
|
2024-03-28 16:06:36 -04:00
|
|
|
}
|
|
|
|
}
|