diff --git a/.gitignore b/.gitignore index 1733ca8..c03ca78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /target dist -docs +/docs diff --git a/Cargo.lock b/Cargo.lock index 158cf5d..0c53655 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,5 +3,5 @@ version = 3 [[package]] -name = "docki-cli" +name = "docki" version = "0.1.0" diff --git a/res/test/docs/core/functions.adoc b/res/test/docs/core/functions.adoc new file mode 100644 index 0000000..e69de29 diff --git a/res/test/docs/core/index.adoc b/res/test/docs/core/index.adoc new file mode 100644 index 0000000..e69de29 diff --git a/res/test/docs/fail.txt b/res/test/docs/fail.txt new file mode 100644 index 0000000..e69de29 diff --git a/res/test/docs/functions.adoc b/res/test/docs/functions.adoc new file mode 100644 index 0000000..e69de29 diff --git a/res/test/docs/index.adoc b/res/test/docs/index.adoc new file mode 100644 index 0000000..e69de29 diff --git a/src/app/builder/asciidoctor.rs b/src/app/builder/asciidoctor.rs index 13b48b9..dd5d51a 100644 --- a/src/app/builder/asciidoctor.rs +++ b/src/app/builder/asciidoctor.rs @@ -2,28 +2,33 @@ use std::process; use super::Builder; -pub struct AsciiDoctorBuilder; +fn asciidoctor(postfix: &str, in_path: &str, out_path: &str) -> Result<(), String> { + let result = process::Command::new(format!("asciidoctor{postfix}")) + .arg(format!("{in_path}")) + .arg(format!("--out-file={out_path}")) + .output(); -impl Builder for AsciiDoctorBuilder { - fn build(&self, in_path: &str, out_path: &str) -> Result<(), String> { - let result = process::Command::new("asciidoctor") - .arg(format!("{in_path}")) - .arg(format!("--out-file={out_path}")) - .output(); - - if let Ok(success) = result { - if success.stderr.len() == 0 { - return Ok(()); - } else { - return Err(AsciiDoctorBuilder::from_utf8(success.stderr)); - } + if let Ok(success) = result { + if success.stderr.len() == 0 { + return Ok(()); } else { - return Err("command failed to execute".to_string()); + return Err(AsciiDoctorDocsBuilder::from_utf8(success.stderr)); } + } else { + println!("{}", result.unwrap_err()); + return Err("asciidoctor not installed. You may need to run docki setup!".to_string()); } } -impl AsciiDoctorBuilder { +pub struct AsciiDoctorDocsBuilder; + +impl Builder for AsciiDoctorDocsBuilder { + fn build(&self, in_path: &str, out_path: &str) -> Result<(), String> { + return asciidoctor("", in_path, out_path); + } +} + +impl AsciiDoctorDocsBuilder { fn from_utf8(input: Vec) -> String { return match String::from_utf8(input) { Ok(m) => m, @@ -31,3 +36,11 @@ impl AsciiDoctorBuilder { }; } } + +pub struct AsciiDoctorSlideBuilder; + +impl Builder for AsciiDoctorSlideBuilder { + fn build(&self, in_path: &str, out_path: &str) -> Result<(), String> { + return asciidoctor("-revealjs-linux", in_path, out_path); + } +} diff --git a/src/app/commands/build.rs b/src/app/commands/build.rs index b7ce21e..02866e6 100644 --- a/src/app/commands/build.rs +++ b/src/app/commands/build.rs @@ -1,88 +1,45 @@ -use std::{collections::HashMap, fs, path::Path}; +use std::{collections::HashMap, path::Path}; -use crate::app::builder::{asciidoctor::AsciiDoctorBuilder, Builder}; +use crate::app::{ + builder::{ + asciidoctor::{AsciiDoctorDocsBuilder, AsciiDoctorSlideBuilder}, + Builder, + }, + fs_util, +}; use super::traits::Command; pub struct Build { - builder: Box, -} - -impl Build { - fn build_dir(&self, path: &str) -> Vec> { - let mut results = vec![]; - let Ok(dirs) = fs::read_dir(path) else { - return vec![Err(format!("direcotry {path} was not found. The filesystem was maybe updated while build"))] - }; - - for result in dirs { - let Ok(entry) = result else { - return vec![Err("could not read entry".to_string())]; - }; - - let path = entry - .path() - .to_str() - .expect("could not get text path") - .to_string() - .clone(); - - if entry.path().is_dir() { - results = [results, self.build_dir(&path)].concat() - } else { - results.push(self.build_file(&path)); - } - } - - return results; - } - - fn build_file(&self, path: &str) -> Result<(), String> { - let out_path = path - .clone() - .replace("docs", "dist") - .replace(".adoc", ".html"); - - return self.builder.build(&path, &out_path); - } - - fn docs_directory_exists(&self, path: &String) -> bool { - Path::new(path).is_dir() - } + slides_builder: Box, + docs_builder: Box, } impl Command for Build { fn execute(&self, _args: &HashMap) -> Result<(), String> { - // let Ok(project_cwd_object) = env::current_dir() else { - // return Err("current dirctory does not seem to exist".to_string()) - // }; - // - // let Some(project_cwd) = project_cwd_object.to_str() else { - // return Err("invalid path".to_string()); - // }; + let path = "./docs/".to_string(); - let path = format!("./docs/"); - let mut error_count = 0; - - if !self.docs_directory_exists(&path) { - error_count += 1; - println!( - "docs directory does not exist. Either create it or clone the template from gitlab" - ) - } else { - for result in self.build_dir(&path) { - match result { - Err(e) => { - error_count += 1; - println!("{e}"); - } - Ok(()) => println!("success"), - }; - } + if !Self::docs_directory_exists(&path) { + return Self::docs_directory_missing(); } - if error_count > 0 { - return Err(format!("failed with {} errors", error_count)); + let result = fs_util::fetch_paths_recursive(&path, ".adoc"); + + let Ok(paths) = result else { + return Err(result.unwrap_err()) + }; + + for (index, path) in paths.iter().enumerate() { + let progress = index + 1; + if path.starts_with("./docs/slides") { + if self.build_slide(&path).is_ok() { + Self::display_status(paths.len(), progress, &path, "slide") + } + } else { + if self.build_doc(&path).is_ok() { + Self::display_status(paths.len(), progress, &path, "doc") + } + } } return Ok(()); @@ -93,7 +50,49 @@ impl Command for Build { Self: Sized, { return Build { - builder: Box::new(AsciiDoctorBuilder {}), + slides_builder: Box::new(AsciiDoctorSlideBuilder {}), + docs_builder: Box::new(AsciiDoctorDocsBuilder {}), }; } } + +impl Build { + fn build_file(&self, builder: &Box, path: &str) -> Result<(), String> { + let out_path = path + .clone() + .replace("docs", "dist") + .replace(".adoc", ".html"); + + return builder.build(&path, &out_path); + } + + fn display_status(goal: usize, progress: usize, path: &str, conversion_type: &str) -> () { + println!( + "({} / {}) [{}] {} -> {}", + progress, + goal, + conversion_type, + path, + path.replace(".adoc", ".html") + ); + } + + fn build_doc(&self, path: &str) -> Result<(), String> { + return self.build_file(&self.docs_builder, path); + } + + fn build_slide(&self, path: &str) -> Result<(), String> { + return self.build_file(&self.slides_builder, path); + } + + fn docs_directory_exists(path: &String) -> bool { + Path::new(path).is_dir() + } + + fn docs_directory_missing() -> Result<(), String> { + return Err( + "direcotry {path} was not found. The filesystem was maybe updated while build" + .to_string(), + ); + } +} diff --git a/src/app/fs_util/mod.rs b/src/app/fs_util/mod.rs new file mode 100644 index 0000000..6691f25 --- /dev/null +++ b/src/app/fs_util/mod.rs @@ -0,0 +1,66 @@ +use std::fs; + +struct RecursivePathFetch { + paths: Vec, + ends_with: String, + path: String +} + +impl RecursivePathFetch { + pub fn new_with_extension_filter(path: String, ends_with: String) -> Self { + return Self { + paths: vec![], + ends_with, + path + } + } + + pub fn fetch(&mut self) -> Result, String> { + if let Err(error) = self.read_dir(self.path.clone()) { + return Err(error); + } else { + return Ok(self.paths.clone()); + } + } + + fn read_dir(&mut self, path: String) -> Result<(), String> { + let Ok(entries) = fs::read_dir(path) else { + return self.dir_not_found(); + }; + + for result in entries { + let entry = result.unwrap(); + let path = entry.path(); + let str_path = path.to_str().unwrap(); + + if path.is_file() { + if str_path.ends_with(&self.ends_with) { + self.paths.push(str_path.to_string()) + } + } else if path.is_dir() { + let read_result = self.read_dir(str_path.to_string()); + if read_result.is_err() { + return read_result; + } + } + } + + return Ok(()) + } + + fn dir_not_found(&self) -> Result<(), String> { + return Err(format!( + "directory {} was not found or was changed while building", + self.path + )) + } +} + +pub fn fetch_paths_recursive(path: &str, ends_with: &str) -> Result, String> { + let mut path_fetch = RecursivePathFetch::new_with_extension_filter( + path.to_string(), + ends_with.to_string() + ); + + return path_fetch.fetch(); +} diff --git a/src/app/mod.rs b/src/app/mod.rs index c8212e7..88f70ff 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,5 +1,6 @@ mod commands; pub mod builder; +pub mod fs_util; use std::collections::HashMap; diff --git a/src/main.rs b/src/main.rs index 11311b0..a5101bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,8 @@ mod app; +#[cfg(test)] +mod test; + use std::env; use app::App; diff --git a/src/test/fs_util.rs b/src/test/fs_util.rs new file mode 100644 index 0000000..ef9e885 --- /dev/null +++ b/src/test/fs_util.rs @@ -0,0 +1,9 @@ +use crate::app::fs_util; + +#[test] +fn test_fetch_asciidoctor_paths_recursive() { + let paths = fs_util::fetch_paths_recursive("res/test/docs", ".adoc").unwrap(); + let len = paths.len(); + dbg!(paths); + assert_eq!(len, 4); +} diff --git a/src/test/mod.rs b/src/test/mod.rs new file mode 100644 index 0000000..758eddb --- /dev/null +++ b/src/test/mod.rs @@ -0,0 +1,2 @@ +mod rx; +mod fs_util; diff --git a/src/test/rx.rs b/src/test/rx.rs new file mode 100644 index 0000000..26d541e --- /dev/null +++ b/src/test/rx.rs @@ -0,0 +1,13 @@ +use crate::app::rx::Observable; + +#[test] +fn test_observable() { + let mut observable: Observable = Observable::new(); + + observable.subscribe(|value| { + assert_eq!(5, value); + }); + + observable.next(5); +} +