Use a Config struct across the code
This commit is contained in:
parent
5bcc37f32c
commit
50085e8ce2
22
README.md
Normal file
22
README.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# MD-DOCS
|
||||||
|
|
||||||
|
All configuration is done via the `md-docs.config.yaml` file.
|
||||||
|
|
||||||
|
## md-docs.config.yaml
|
||||||
|
|
||||||
|
Values:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
{
|
||||||
|
String input # Path to the input folder
|
||||||
|
String output # Path to the output folder
|
||||||
|
|
||||||
|
?content: {
|
||||||
|
String? h1 # Classes to add to h1 elements
|
||||||
|
String? h2 # Classes to add to h2 elements
|
||||||
|
String? h3 # Classes to add to h3 elements
|
||||||
|
String? h4 # Classes to add to h4 elements
|
||||||
|
String? h5 # Classes to add to h5 elements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
16
md-docs.md
16
md-docs.md
@ -1,16 +0,0 @@
|
|||||||
# MD-DOCS
|
|
||||||
|
|
||||||
All configuration is done via the `md-docs.config.yaml` file.
|
|
||||||
|
|
||||||
## md-docs.config.yaml
|
|
||||||
|
|
||||||
Values:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
{
|
|
||||||
String input # Path to the input folder
|
|
||||||
String output # Path to the output folder
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
124
src/config.rs
Normal file
124
src/config.rs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use yaml_rust::Yaml;
|
||||||
|
|
||||||
|
pub const CONFIG_NAME: &str = "md-docs.config.yaml";
|
||||||
|
pub const INPUT_KEY: &str = "input";
|
||||||
|
pub const OUTPUT_KEY: &str = "output";
|
||||||
|
const TEMPLATE_KEY: &str = "template";
|
||||||
|
|
||||||
|
pub struct Config {
|
||||||
|
pub input: String,
|
||||||
|
pub output: String,
|
||||||
|
pub template: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `YAML::String` from a `&str`
|
||||||
|
macro_rules! ystr {
|
||||||
|
($str:literal) => {
|
||||||
|
&Yaml::String(String::from($str))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(yaml_str: &String) -> Result<Config, String> {
|
||||||
|
let config_yaml = match yaml_rust::YamlLoader::load_from_str(yaml_str) {
|
||||||
|
Ok(y) => {
|
||||||
|
let document = &y[0];
|
||||||
|
let Yaml::Hash(hash) = document
|
||||||
|
else {
|
||||||
|
return Err(format!("{} doesn't contain a hash as first value.", CONFIG_NAME));
|
||||||
|
};
|
||||||
|
|
||||||
|
hash.clone()
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
return Err(format!(
|
||||||
|
"{} doesn't contain valid YAML.\n{:?}",
|
||||||
|
CONFIG_NAME, error
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let input_folder = match config_yaml.get(ystr!("input")) {
|
||||||
|
Some(Yaml::String(input)) => input,
|
||||||
|
Some(_) => {
|
||||||
|
return Err(format!(
|
||||||
|
"{}'s `{}` key MUST be a string",
|
||||||
|
CONFIG_NAME, INPUT_KEY
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(format!("{} MUST have a `{}` key", CONFIG_NAME, INPUT_KEY));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let output_folder = match config_yaml.get(ystr!("output")) {
|
||||||
|
Some(Yaml::String(input)) => input,
|
||||||
|
Some(_) => {
|
||||||
|
return Err(format!(
|
||||||
|
"{}'s `{}` key MUST be a string",
|
||||||
|
CONFIG_NAME, OUTPUT_KEY
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(format!("{} MUST have a `{}` key", CONFIG_NAME, OUTPUT_KEY));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check that input & output are valid folders
|
||||||
|
match (
|
||||||
|
Path::new(input_folder).is_dir(),
|
||||||
|
Path::new(output_folder).is_dir(),
|
||||||
|
) {
|
||||||
|
(true, true) => {}
|
||||||
|
(false, true) => {
|
||||||
|
return Err(format!(
|
||||||
|
"{}'s `{}` key is not a valid path to a folder",
|
||||||
|
CONFIG_NAME, INPUT_KEY
|
||||||
|
))
|
||||||
|
}
|
||||||
|
(true, false) => {
|
||||||
|
return Err(format!(
|
||||||
|
"{}'s `{}` key is not a valid path to a folder",
|
||||||
|
CONFIG_NAME, OUTPUT_KEY
|
||||||
|
))
|
||||||
|
}
|
||||||
|
(false, false) => {
|
||||||
|
return Err(format!(
|
||||||
|
"{}'s `{}` and `{}` keys are not valid paths to a folder",
|
||||||
|
CONFIG_NAME, INPUT_KEY, OUTPUT_KEY
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get template file
|
||||||
|
let template_file = match config_yaml.get(ystr!("template")) {
|
||||||
|
Some(Yaml::String(v)) => v,
|
||||||
|
Some(_) => {
|
||||||
|
return Err(format!(
|
||||||
|
"{}'s `{}` key MUST be a string",
|
||||||
|
CONFIG_NAME, TEMPLATE_KEY
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(format!(
|
||||||
|
"{} MUST have a `{}` key",
|
||||||
|
CONFIG_NAME, TEMPLATE_KEY
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check template file exists
|
||||||
|
if !(Path::new(template_file).is_file()) {
|
||||||
|
return Err(format!(
|
||||||
|
"{}'s `{}` key MUST point to a file ({})",
|
||||||
|
CONFIG_NAME, TEMPLATE_KEY, template_file
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Config {
|
||||||
|
input: input_folder.clone(),
|
||||||
|
output: output_folder.clone(),
|
||||||
|
template: template_file.clone(),
|
||||||
|
})
|
||||||
|
}
|
78
src/main.rs
78
src/main.rs
@ -1,16 +1,16 @@
|
|||||||
|
use config::CONFIG_NAME;
|
||||||
use std::{fs, path::Path};
|
use std::{fs, path::Path};
|
||||||
use yaml_rust::Yaml;
|
use yaml_rust::Yaml;
|
||||||
|
|
||||||
|
use crate::config::{INPUT_KEY, OUTPUT_KEY};
|
||||||
|
|
||||||
|
mod config;
|
||||||
mod generator;
|
mod generator;
|
||||||
mod pages;
|
mod pages;
|
||||||
mod processor;
|
mod processor;
|
||||||
mod sidebar;
|
mod sidebar;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
const CONFIG_NAME: &str = "md-docs.config.yaml";
|
|
||||||
const INPUT_KEY: &str = "input";
|
|
||||||
const OUTPUT_KEY: &str = "output";
|
|
||||||
|
|
||||||
/// Creates a `YAML::String` from a `&str`
|
/// Creates a `YAML::String` from a `&str`
|
||||||
macro_rules! ystr {
|
macro_rules! ystr {
|
||||||
($str:literal) => {
|
($str:literal) => {
|
||||||
@ -33,71 +33,13 @@ fn main() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let config_yaml = match yaml_rust::YamlLoader::load_from_str(&config_str) {
|
match config::parse(&config_str) {
|
||||||
Ok(y) => {
|
Ok(config) => {
|
||||||
let document = &y[0];
|
processor::search_config_file(&config);
|
||||||
let Yaml::Hash(hash) = document
|
}
|
||||||
else {
|
Err(reason) => {
|
||||||
eprintln!("{} doesn't contain a hash as first value.", CONFIG_NAME);
|
eprintln!("{}", reason);
|
||||||
return;
|
return;
|
||||||
};
|
|
||||||
|
|
||||||
hash.clone()
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
eprintln!("{} doesn't contain valid YAML.\n{:?}", CONFIG_NAME, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let input_folder = match config_yaml.get(ystr!("input")) {
|
|
||||||
Some(Yaml::String(input)) => input,
|
|
||||||
Some(_) => {
|
|
||||||
eprintln!("{}'s `{}` key MUST be a string", CONFIG_NAME, INPUT_KEY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
eprintln!("{} MUST have a `{}` key", CONFIG_NAME, INPUT_KEY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let output_folder = match config_yaml.get(ystr!("output")) {
|
|
||||||
Some(Yaml::String(input)) => input,
|
|
||||||
Some(_) => {
|
|
||||||
eprintln!("{}'s `{}` key MUST be a string", CONFIG_NAME, OUTPUT_KEY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
eprintln!("{} MUST have a `{}` key", CONFIG_NAME, OUTPUT_KEY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let input_folder = Path::new(input_folder);
|
|
||||||
let output_folder = Path::new(output_folder);
|
|
||||||
|
|
||||||
match (input_folder.is_dir(), output_folder.is_dir()) {
|
|
||||||
(true, true) => {
|
|
||||||
processor::search_config_file(&input_folder, input_folder, output_folder);
|
|
||||||
}
|
|
||||||
(false, true) => {
|
|
||||||
eprintln!(
|
|
||||||
"{}'s `{}` key is not a valid path to a folder",
|
|
||||||
CONFIG_NAME, INPUT_KEY
|
|
||||||
)
|
|
||||||
}
|
|
||||||
(true, false) => {
|
|
||||||
eprintln!(
|
|
||||||
"{}'s `{}` key is not a valid path to a folder",
|
|
||||||
CONFIG_NAME, OUTPUT_KEY
|
|
||||||
)
|
|
||||||
}
|
|
||||||
(false, false) => {
|
|
||||||
eprintln!(
|
|
||||||
"{}'s `{}` and `{}` keys are not valid paths to a folder",
|
|
||||||
CONFIG_NAME, INPUT_KEY, OUTPUT_KEY
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,17 @@ use std::{
|
|||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{generator::Printable, sidebar::SidebarGenerator};
|
use crate::{generator::Printable, sidebar::SidebarGenerator, config::Config};
|
||||||
|
|
||||||
/// ## Parameters
|
/// ## Parameters
|
||||||
///
|
///
|
||||||
|
/// - `config`: Config struct with the parsed values
|
||||||
/// - `file`: Path to the MD file to compile
|
/// - `file`: Path to the MD file to compile
|
||||||
/// - `input_folder`: Path to the input folder passed as parameter of the program
|
|
||||||
/// - `output_folder`: Path to the output folder passed as parameter of the program
|
|
||||||
/// - `file_tree_html`: HTML code of the file tree to be inserted into the generated HTML
|
/// - `file_tree_html`: HTML code of the file tree to be inserted into the generated HTML
|
||||||
pub fn compile(file: &PathBuf, input_folder: &Path, output_folder: &Path, file_tree_html: &String) {
|
pub fn compile(config: &Config,file: &PathBuf, file_tree_html: &String) {
|
||||||
|
let input_folder = Path::new(&config.input);
|
||||||
|
let output_folder = Path::new(&config.output);
|
||||||
|
|
||||||
// /home/fernando/misti/docs/markdown
|
// /home/fernando/misti/docs/markdown
|
||||||
let input_folder = input_folder.canonicalize().unwrap();
|
let input_folder = input_folder.canonicalize().unwrap();
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use std::path::Path;
|
|||||||
|
|
||||||
use yaml_rust::Yaml;
|
use yaml_rust::Yaml;
|
||||||
|
|
||||||
use crate::utils;
|
use crate::{utils, config::{self, Config}};
|
||||||
|
|
||||||
mod md_compiler;
|
mod md_compiler;
|
||||||
|
|
||||||
@ -133,10 +133,9 @@ pub fn generate_pages_html(file_tree: &Node, current_path: &Path) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_md_to_html(
|
pub fn compile_md_to_html(
|
||||||
|
config: &Config,
|
||||||
file_tree: &Node,
|
file_tree: &Node,
|
||||||
current_path: &Path,
|
current_path: &Path,
|
||||||
input_folder: &Path,
|
|
||||||
output_folder: &Path,
|
|
||||||
file_tree_html: &String,
|
file_tree_html: &String,
|
||||||
) {
|
) {
|
||||||
match file_tree {
|
match file_tree {
|
||||||
@ -144,7 +143,7 @@ pub fn compile_md_to_html(
|
|||||||
let mut file_path = current_path.canonicalize().unwrap();
|
let mut file_path = current_path.canonicalize().unwrap();
|
||||||
file_path.push(format!("{}.md", file.path));
|
file_path.push(format!("{}.md", file.path));
|
||||||
|
|
||||||
md_compiler::compile(&file_path, input_folder, output_folder, file_tree_html);
|
md_compiler::compile(config, &file_path, file_tree_html);
|
||||||
}
|
}
|
||||||
Node::File(_) => {
|
Node::File(_) => {
|
||||||
panic!("YAML: A file cannot have an empty `path` key")
|
panic!("YAML: A file cannot have an empty `path` key")
|
||||||
@ -152,20 +151,19 @@ pub fn compile_md_to_html(
|
|||||||
Node::Folder(folder) if folder.path != "" => {
|
Node::Folder(folder) if folder.path != "" => {
|
||||||
let mut new_path = current_path.canonicalize().unwrap();
|
let mut new_path = current_path.canonicalize().unwrap();
|
||||||
new_path.push(folder.path);
|
new_path.push(folder.path);
|
||||||
utils::ensure_folder_exists(&new_path, input_folder, output_folder)
|
utils::ensure_folder_exists(config, &new_path)
|
||||||
.expect("SHOULD be able to create folder");
|
.expect("SHOULD be able to create folder");
|
||||||
|
|
||||||
for node in folder.children.iter() {
|
for node in folder.children.iter() {
|
||||||
compile_md_to_html(node, &new_path, input_folder, output_folder, file_tree_html);
|
compile_md_to_html(config, node, &new_path, file_tree_html);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Node::Folder(folder) => {
|
Node::Folder(folder) => {
|
||||||
for node in folder.children.iter() {
|
for node in folder.children.iter() {
|
||||||
compile_md_to_html(
|
compile_md_to_html(
|
||||||
|
config,
|
||||||
node,
|
node,
|
||||||
¤t_path,
|
¤t_path,
|
||||||
input_folder,
|
|
||||||
output_folder,
|
|
||||||
file_tree_html,
|
file_tree_html,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::config::Config;
|
||||||
use crate::pages::{compile_md_to_html, generate_pages_html, parse_yaml};
|
use crate::pages::{compile_md_to_html, generate_pages_html, parse_yaml};
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use std::{fs, path::Path};
|
use std::{fs, path::Path};
|
||||||
@ -9,10 +10,16 @@ enum EntryFound {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traverses the current path searching for a YAML file
|
pub fn search_config_file(config: &Config) {
|
||||||
pub fn search_config_file(current_path: &Path, input_folder: &Path, output_folder: &Path) {
|
let current_folder = Path::new(&config.input);
|
||||||
|
|
||||||
|
search_config_file_impl(config, current_folder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively traverses the current folder searching a YAML file
|
||||||
|
pub fn search_config_file_impl(config: &Config, current_folder: &Path) {
|
||||||
// Iterate over all the files searching for a YAML file
|
// Iterate over all the files searching for a YAML file
|
||||||
let result = current_path
|
let result = current_folder
|
||||||
.read_dir()
|
.read_dir()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.fold(&EntryFound::None, |acc, next| {
|
.fold(&EntryFound::None, |acc, next| {
|
||||||
@ -22,7 +29,11 @@ pub fn search_config_file(current_path: &Path, input_folder: &Path, output_folde
|
|||||||
|
|
||||||
match (acc, is_file, ext) {
|
match (acc, is_file, ext) {
|
||||||
(EntryFound::YamlFile, true, Some(x)) if x == "yaml" => {
|
(EntryFound::YamlFile, true, Some(x)) if x == "yaml" => {
|
||||||
panic!("FOUND A SECOND YAML FILE!!!")
|
panic!(
|
||||||
|
"Inside the folder {} a second YAML file was found ({}).",
|
||||||
|
current_folder.to_str().unwrap(),
|
||||||
|
p.to_str().unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
(EntryFound::YamlFile, _, _) => acc,
|
(EntryFound::YamlFile, _, _) => acc,
|
||||||
(EntryFound::OtherFile, true, Some(x)) if x == "yaml" => &EntryFound::YamlFile,
|
(EntryFound::OtherFile, true, Some(x)) if x == "yaml" => &EntryFound::YamlFile,
|
||||||
@ -35,26 +46,29 @@ pub fn search_config_file(current_path: &Path, input_folder: &Path, output_folde
|
|||||||
match result {
|
match result {
|
||||||
// If a file other than a YAML file is found, panic
|
// If a file other than a YAML file is found, panic
|
||||||
EntryFound::OtherFile => panic!(
|
EntryFound::OtherFile => panic!(
|
||||||
"Found an orphan file without a YAML parent at {:?}",
|
"Found an orphan file without a YAML parent inside folder {}",
|
||||||
current_path
|
current_folder.to_str().unwrap()
|
||||||
),
|
),
|
||||||
// Process the YAML file
|
// Process the YAML file
|
||||||
EntryFound::YamlFile => process_yaml(current_path, input_folder, output_folder),
|
EntryFound::YamlFile => process_yaml(config, current_folder),
|
||||||
// No files found, recursively read children folders
|
// No files found, recursively read children folders
|
||||||
EntryFound::None => {
|
EntryFound::None => {
|
||||||
for entry in current_path.read_dir().unwrap() {
|
for entry in current_folder.read_dir().unwrap() {
|
||||||
// Should always succeed, and countain a folder
|
// Should always succeed, and contain a folder
|
||||||
let x = entry.unwrap();
|
let x = entry.unwrap();
|
||||||
let path = x.path();
|
let path = x.path();
|
||||||
|
|
||||||
utils::ensure_folder_exists(&path, input_folder, output_folder).unwrap();
|
utils::ensure_folder_exists(config, &path).unwrap();
|
||||||
search_config_file(&path, input_folder, output_folder);
|
search_config_file_impl(config, &path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_yaml(current_path: &Path, input_folder: &Path, output_folder: &Path) {
|
fn process_yaml(config: &Config, current_path: &Path) {
|
||||||
|
let input_folder = Path::new(&config.input);
|
||||||
|
let output_folder = Path::new(&config.output);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Read YAML file
|
// Read YAML file
|
||||||
//
|
//
|
||||||
@ -88,10 +102,9 @@ fn process_yaml(current_path: &Path, input_folder: &Path, output_folder: &Path)
|
|||||||
// Compile MD to HTML
|
// Compile MD to HTML
|
||||||
//
|
//
|
||||||
compile_md_to_html(
|
compile_md_to_html(
|
||||||
|
config,
|
||||||
&file_tree,
|
&file_tree,
|
||||||
current_path,
|
current_path,
|
||||||
input_folder,
|
|
||||||
output_folder,
|
|
||||||
&tree_html,
|
&tree_html,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use std::{fs, path::Path};
|
|||||||
|
|
||||||
use markdown::mdast::Node;
|
use markdown::mdast::Node;
|
||||||
|
|
||||||
use crate::generator::Printable;
|
use crate::{generator::Printable, config::{self, Config}};
|
||||||
|
|
||||||
pub fn to_html_fragment(text: &String) -> String {
|
pub fn to_html_fragment(text: &String) -> String {
|
||||||
text.clone().replace(" ", "-")
|
text.clone().replace(" ", "-")
|
||||||
@ -29,10 +29,12 @@ pub fn collect_children_text(vec: &Vec<Node>) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensure_folder_exists(
|
pub fn ensure_folder_exists(
|
||||||
|
config: &Config,
|
||||||
folder: &Path,
|
folder: &Path,
|
||||||
input_folder: &Path,
|
|
||||||
output_folder: &Path,
|
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
|
let input_folder = Path::new(&config.input);
|
||||||
|
let output_folder = Path::new(&config.output);
|
||||||
|
|
||||||
// /home/fernando/misti/docs/markdown
|
// /home/fernando/misti/docs/markdown
|
||||||
let input_folder = input_folder.canonicalize().unwrap();
|
let input_folder = input_folder.canonicalize().unwrap();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user