nearly finished rewrite
This commit is contained in:
@@ -1 +1,150 @@
|
|||||||
pub mod asciidoctor;
|
pub mod asciidoctor;
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fs, io::Cursor, path::PathBuf
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::app::{
|
||||||
|
build::{asciidoctor::build_slide, asciidoctor::build_doc}, config::config::Config, fs_util::{self, create_dir_recursive}, log::display_status
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct DockiBuilder<'a> {
|
||||||
|
progress: usize,
|
||||||
|
goal: usize,
|
||||||
|
config: &'a Config
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a> DockiBuilder <'a> {
|
||||||
|
pub fn new(config: &'a Config) -> Self {
|
||||||
|
return Self {
|
||||||
|
progress: 0,
|
||||||
|
goal: 0,
|
||||||
|
config: config
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Prepares everything for building the documentation
|
||||||
|
///
|
||||||
|
/// 1. Checks if the input directory exists and if not, returns an error
|
||||||
|
/// 2. When offline_reveal is set to true, it downloads revealjs. When it fails, it returns an error
|
||||||
|
pub async fn prepare(&self) -> Result<(), String> {
|
||||||
|
if !fs_util::directory_exists(&self.config.input_dir) {
|
||||||
|
return Err(
|
||||||
|
"docs directory does not exist it. Create it or use the template".to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.config.offline_reveal {
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
let reveal_version = "5.2.1";
|
||||||
|
let target = format!("https://github.com/hakimel/reveal.js/archive/{reveal_version}.zip");
|
||||||
|
|
||||||
|
create_dir_recursive(format!("{}/slides", self.config.input_dir).as_str());
|
||||||
|
|
||||||
|
reqwest::get(target.clone()).await.unwrap();
|
||||||
|
let Ok(response) = reqwest::get(target).await else {
|
||||||
|
return Err("could not downlaod revealjs".to_string())
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(bytes) = response.bytes().await else {
|
||||||
|
return Err("could not extract bytes".to_string())
|
||||||
|
};
|
||||||
|
|
||||||
|
let out = PathBuf::from(format!("{}/slides/revealjs", self.config.input_dir));
|
||||||
|
|
||||||
|
if zip_extract::extract(Cursor::new(bytes), &out, true).is_err() {
|
||||||
|
return Err("could not write extracted archive to disk".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Builds all files in the input directory with a pretty output
|
||||||
|
pub fn build_docs(&mut self) -> Result<(), String> {
|
||||||
|
let result = fs_util::fetch_paths_recursive(&self.config.input_dir);
|
||||||
|
let Ok(paths) = result else {
|
||||||
|
return Err(result.unwrap_err())
|
||||||
|
};
|
||||||
|
|
||||||
|
let reveal_dir = format!("{}/slides/revealjs", self.config.input_dir);
|
||||||
|
let paths = paths.into_iter()
|
||||||
|
.filter(|path| self.config.offline_reveal || !path.starts_with(reveal_dir.as_str()))
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
self.goal = paths.len();
|
||||||
|
|
||||||
|
for (index, in_path) in paths.iter().enumerate() {
|
||||||
|
self.progress = index + 1;
|
||||||
|
let result = self.build_file(&in_path);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
DockiBuildResult::Err(err) => {
|
||||||
|
self.display_building_status("Error", &in_path, "");
|
||||||
|
println!("{}", err)
|
||||||
|
},
|
||||||
|
DockiBuildResult::Copy(out_path) => self.display_building_status("Copy", &in_path, &out_path),
|
||||||
|
DockiBuildResult::Slide(out_path) => self.display_building_status("Slide", &in_path, &out_path),
|
||||||
|
DockiBuildResult::Doc(out_path) => self.display_building_status("Doc", &in_path, &out_path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Builds a single file without a pretty output
|
||||||
|
pub fn build_file(&self, path: &str) -> DockiBuildResult {
|
||||||
|
let out_path = path.replace(&self.config.input_dir, "./dist");
|
||||||
|
let convert_out_path = out_path.replace(".adoc", ".html");
|
||||||
|
|
||||||
|
if path.starts_with(format!("{}/slides/", &self.config.input_dir).as_str()) && path.ends_with(".adoc") {
|
||||||
|
if let Err(err) = build_slide(&path, &convert_out_path, self.config.offline_reveal) {
|
||||||
|
return DockiBuildResult::Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
DockiBuildResult::Slide(convert_out_path)
|
||||||
|
} else if path.ends_with(".adoc") {
|
||||||
|
if let Err(err) = build_doc(&path, &convert_out_path) {
|
||||||
|
return DockiBuildResult::Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
DockiBuildResult::Doc(convert_out_path)
|
||||||
|
} else {
|
||||||
|
if let Err(err) = Self::copy(&path, &out_path) {
|
||||||
|
return DockiBuildResult::Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
DockiBuildResult::Copy(out_path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy(in_path: &str, out_path: &str) -> Result<(), String> {
|
||||||
|
fs_util::create_parent_dir_recursive(out_path);
|
||||||
|
|
||||||
|
if let Err(err) = fs::copy(in_path, out_path) {
|
||||||
|
return Err(err.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_building_status(&self, status_type: &str, in_path: &str, out_path: &str) -> () {
|
||||||
|
let progress_str = format!("{} / {}", self.progress, self.goal);
|
||||||
|
display_status(&progress_str, status_type, in_path, out_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Used for the Result of build_file. This way it is known what the builder did
|
||||||
|
pub enum DockiBuildResult {
|
||||||
|
Slide(String),
|
||||||
|
Doc(String),
|
||||||
|
Copy(String),
|
||||||
|
Err(String),
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::app::config::config::Config;
|
use crate::app::config::config::Config;
|
||||||
|
|
||||||
use super::executions::build_execution::BuildExecution;
|
use crate::app::build::DockiBuilder;
|
||||||
|
|
||||||
pub async fn build(config: &Config) -> () {
|
pub async fn build(config: &Config) -> () {
|
||||||
let mut build_execution = BuildExecution::new(config);
|
let mut builder = DockiBuilder::new(config);
|
||||||
|
|
||||||
build_execution.prepare().await.expect("could not prepare for build");
|
builder.prepare().await.expect("could not prepare for build");
|
||||||
build_execution.build_dir().expect("build failed")
|
builder.build_docs().expect("build failed")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
use std::{
|
|
||||||
fs, io::Cursor, path::PathBuf
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::app::{
|
|
||||||
build::{asciidoctor::build_slide, asciidoctor::build_doc}, config::config::Config, fs_util::{self, create_dir_recursive}, log::display_status
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct BuildExecution<'a> {
|
|
||||||
progress: usize,
|
|
||||||
goal: usize,
|
|
||||||
config: &'a Config
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <'a> BuildExecution <'a> {
|
|
||||||
pub fn new(config: &'a Config) -> Self {
|
|
||||||
return Self {
|
|
||||||
progress: 0,
|
|
||||||
goal: 0,
|
|
||||||
config: config
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn prepare(&self) -> Result<(), String> {
|
|
||||||
if !fs_util::directory_exists(&self.config.input_dir) {
|
|
||||||
return Err(
|
|
||||||
"docs directory does not exist it. Create it or use the template".to_string(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.config.offline_reveal {
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
let reveal_version = "5.2.1";
|
|
||||||
let target = format!("https://github.com/hakimel/reveal.js/archive/{reveal_version}.zip");
|
|
||||||
|
|
||||||
create_dir_recursive(format!("{}/slides", self.config.input_dir).as_str());
|
|
||||||
|
|
||||||
reqwest::get(target.clone()).await.unwrap();
|
|
||||||
let Ok(response) = reqwest::get(target).await else {
|
|
||||||
return Err("could not downlaod revealjs".to_string())
|
|
||||||
};
|
|
||||||
|
|
||||||
let Ok(bytes) = response.bytes().await else {
|
|
||||||
return Err("could not extract bytes".to_string())
|
|
||||||
};
|
|
||||||
|
|
||||||
let out = PathBuf::from(format!("{}/slides/revealjs", self.config.input_dir));
|
|
||||||
|
|
||||||
if zip_extract::extract(Cursor::new(bytes), &out, true).is_err() {
|
|
||||||
return Err("could not write extracted archive to disk".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_dir(&mut self) -> Result<(), String> {
|
|
||||||
let result = fs_util::fetch_paths_recursive(&self.config.input_dir);
|
|
||||||
let Ok(paths) = result else {
|
|
||||||
return Err(result.unwrap_err())
|
|
||||||
};
|
|
||||||
|
|
||||||
let reveal_dir = format!("{}/slides/revealjs", self.config.input_dir);
|
|
||||||
let paths = paths.into_iter()
|
|
||||||
.filter(|path| self.config.offline_reveal || !path.starts_with(reveal_dir.as_str()))
|
|
||||||
.collect::<Vec<String>>();
|
|
||||||
|
|
||||||
self.goal = paths.len();
|
|
||||||
|
|
||||||
for (index, in_path) in paths.iter().enumerate() {
|
|
||||||
self.progress = index + 1;
|
|
||||||
let result = self.build_file(&in_path);
|
|
||||||
|
|
||||||
match result {
|
|
||||||
DockiBuildResult::Err(err) => {
|
|
||||||
self.display_building_status("Error", &in_path, "");
|
|
||||||
println!("{}", err)
|
|
||||||
},
|
|
||||||
DockiBuildResult::Copy(out_path) => self.display_building_status("Copy", &in_path, &out_path),
|
|
||||||
DockiBuildResult::Slide(out_path) => self.display_building_status("Slide", &in_path, &out_path),
|
|
||||||
DockiBuildResult::Doc(out_path) => self.display_building_status("Doc", &in_path, &out_path),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_file(&mut self, path: &str) -> DockiBuildResult {
|
|
||||||
let out_path = path.replace(&self.config.input_dir, "./dist");
|
|
||||||
let convert_out_path = out_path.replace(".adoc", ".html");
|
|
||||||
|
|
||||||
if path.starts_with(format!("{}/slides/", &self.config.input_dir).as_str()) && path.ends_with(".adoc") {
|
|
||||||
if let Err(err) = build_slide(&path, &convert_out_path, self.config.offline_reveal) {
|
|
||||||
return DockiBuildResult::Err(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
DockiBuildResult::Slide(convert_out_path)
|
|
||||||
} else if path.ends_with(".adoc") {
|
|
||||||
if let Err(err) = build_doc(&path, &convert_out_path) {
|
|
||||||
return DockiBuildResult::Err(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
DockiBuildResult::Doc(convert_out_path)
|
|
||||||
} else {
|
|
||||||
if let Err(err) = Self::copy(&path, &out_path) {
|
|
||||||
return DockiBuildResult::Err(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
DockiBuildResult::Copy(out_path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn copy(in_path: &str, out_path: &str) -> Result<(), String> {
|
|
||||||
fs_util::create_parent_dir_recursive(out_path);
|
|
||||||
|
|
||||||
if let Err(err) = fs::copy(in_path, out_path) {
|
|
||||||
return Err(err.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn display_building_status(&self, status_type: &str, in_path: &str, out_path: &str) -> () {
|
|
||||||
let progress_str = format!("{} / {}", self.progress, self.goal);
|
|
||||||
display_status(&progress_str, status_type, in_path, out_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub enum DockiBuildResult {
|
|
||||||
Slide(String),
|
|
||||||
Doc(String),
|
|
||||||
Copy(String),
|
|
||||||
Err(String),
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
pub mod build_execution;
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
pub mod build;
|
pub mod build;
|
||||||
pub mod completions;
|
pub mod completions;
|
||||||
pub mod executions;
|
|
||||||
pub mod health;
|
pub mod health;
|
||||||
pub mod install_reveal;
|
pub mod install_reveal;
|
||||||
pub mod serve;
|
pub mod serve;
|
||||||
|
|||||||
@@ -7,30 +7,33 @@ use notify::{
|
|||||||
};
|
};
|
||||||
use std::{env, path::Path};
|
use std::{env, path::Path};
|
||||||
|
|
||||||
use crate::app::{ commands::executions::build_execution::{self, BuildExecution, DockiBuildResult}, config::config::Config, log::display_status, watcher::watcher};
|
use crate::app::watcher::watcher;
|
||||||
|
use crate::app::log::display_status;
|
||||||
|
use crate::app::config::config::Config;
|
||||||
|
use crate::app::build::{DockiBuildResult, DockiBuilder};
|
||||||
|
|
||||||
pub async fn serve(config: &Config) {
|
pub async fn serve(config: &Config) {
|
||||||
let build_execution = BuildExecution::new(config);
|
let builder = DockiBuilder::new(config);
|
||||||
let mut server = Server::new(build_execution, config);
|
let mut server = Server::new(builder, config);
|
||||||
server.serve().await;
|
server.serve().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Server<'a> {
|
struct Server<'a> {
|
||||||
build_execution: BuildExecution<'a>,
|
builder: DockiBuilder<'a>,
|
||||||
config: &'a Config,
|
config: &'a Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a> Server <'a> {
|
impl <'a> Server <'a> {
|
||||||
pub fn new(build_execution: BuildExecution<'a>, config: &'a Config) -> Self {
|
fn new(builder: DockiBuilder<'a>, config: &'a Config) -> Self {
|
||||||
return Self {
|
return Self {
|
||||||
build_execution: build_execution,
|
builder,
|
||||||
config: config
|
config: config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn serve(&mut self) {
|
async fn serve(&mut self) {
|
||||||
self.build_execution.prepare().await.expect("could not prepare for build");
|
self.builder.prepare().await.expect("could not prepare for build");
|
||||||
self.build_execution.build_dir().expect("build failed");
|
self.builder.build_docs().expect("build failed");
|
||||||
tokio::join!(self.start_server(), self.watch_and_build());
|
tokio::join!(self.start_server(), self.watch_and_build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,13 +51,13 @@ impl <'a> Server <'a> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn watch_and_build(&mut self) {
|
async fn watch_and_build(&self) {
|
||||||
self.watch()
|
self.watch()
|
||||||
.await
|
.await
|
||||||
.expect("something went wrong")
|
.expect("something went wrong")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn watch(&mut self) -> notify::Result<()> {
|
async fn watch(&self) -> notify::Result<()> {
|
||||||
let path = Path::new(&self.config.input_dir);
|
let path = Path::new(&self.config.input_dir);
|
||||||
let (mut watcher, mut rx) = watcher()?;
|
let (mut watcher, mut rx) = watcher()?;
|
||||||
|
|
||||||
@@ -69,54 +72,50 @@ impl <'a> Server <'a> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_change(&mut self, event: Event) {
|
fn file_change(&self, event: Event) {
|
||||||
match event.kind {
|
match event.kind {
|
||||||
EventKind::Modify(ModifyKind::Data(_)) => self.build_file(event.paths),
|
EventKind::Modify(ModifyKind::Data(_)) => self.build_valid_files(event.paths),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_file(&mut self, paths: Vec<std::path::PathBuf>) {
|
fn build_valid_files(&self, paths: Vec<std::path::PathBuf>) {
|
||||||
let invalid_path_message = "changed path is invalid";
|
let invalid_path_message = "changed path is invalid";
|
||||||
let in_path = paths
|
let in_path = paths
|
||||||
.first()
|
.first()
|
||||||
.expect(invalid_path_message)
|
.expect(invalid_path_message)
|
||||||
.strip_prefix(¤t_dir())
|
.strip_prefix(&Self::current_dir())
|
||||||
.expect(invalid_path_message)
|
.expect(invalid_path_message)
|
||||||
.to_str()
|
.to_str()
|
||||||
.expect(invalid_path_message);
|
.expect(invalid_path_message);
|
||||||
|
|
||||||
let in_path = format!("./{}", in_path);
|
let in_path = format!("./{}", in_path);
|
||||||
let result = self.build_execution.build_file(&in_path);
|
let result = self.builder.build_file(&in_path);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
DockiBuildResult::Slide(out_path) => display_rebuilding_status("Slide", &in_path, &out_path),
|
DockiBuildResult::Slide(out_path) => Self::display_rebuilding_status("Slide", &in_path, &out_path),
|
||||||
DockiBuildResult::Doc(out_path) => display_rebuilding_status("Doc", &in_path, &out_path),
|
DockiBuildResult::Doc(out_path) => Self::display_rebuilding_status("Doc", &in_path, &out_path),
|
||||||
DockiBuildResult::Copy(out_path) => display_rebuilding_status("Copy", &in_path, &out_path),
|
DockiBuildResult::Copy(out_path) => Self::display_rebuilding_status("Copy", &in_path, &out_path),
|
||||||
DockiBuildResult::Err(err) => {
|
DockiBuildResult::Err(err) => {
|
||||||
display_rebuilding_status("Error", &in_path, "");
|
Self::display_rebuilding_status("Error", &in_path, "");
|
||||||
println!("{}", err);
|
println!("{}", err);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn display_rebuilding_status(context: &str, in_path: &str, out_path: &str) {
|
||||||
|
display_status("Rebuildng", context, in_path, out_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_dir() -> String {
|
||||||
|
let err_message = "something went wrong";
|
||||||
|
return String::from(
|
||||||
|
env::current_dir()
|
||||||
|
.expect(err_message)
|
||||||
|
.to_str()
|
||||||
|
.expect(err_message),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn display_rebuilding_status(context: &str, in_path: &str, out_path: &str) {
|
|
||||||
display_status("Rebuildng", context, in_path, out_path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current_dir() -> String {
|
|
||||||
let err_message = "something went wrong";
|
|
||||||
return String::from(
|
|
||||||
env::current_dir()
|
|
||||||
.expect(err_message)
|
|
||||||
.to_str()
|
|
||||||
.expect(err_message),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ pub enum CommandArg {
|
|||||||
Build {
|
Build {
|
||||||
/// When set to true, docki will download revealjs before building the documentation.
|
/// When set to true, docki will download revealjs before building the documentation.
|
||||||
/// Otherwise it will use the cdn for revealjs
|
/// Otherwise it will use the cdn for revealjs
|
||||||
#[arg(short, long)]
|
#[arg(long)]
|
||||||
offline_reveal: bool,
|
offline_reveal: bool,
|
||||||
},
|
},
|
||||||
/// Checks if everything required for docki is installed
|
/// Checks if everything required for docki is installed
|
||||||
|
|||||||
Reference in New Issue
Block a user