Skip to content

Commit

Permalink
add: book builder output.
Browse files Browse the repository at this point in the history
  • Loading branch information
auula committed Jul 2, 2024
1 parent aa1849b commit 4cc7106
Show file tree
Hide file tree
Showing 18 changed files with 290 additions and 231 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.DS_Store
*.log
/target

docs
cobertura.xml
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
# Typikon

**Typikon lets you use markdown to write your online books.**
Typikon lets you use markdown to write your online books.

---

![https://img.shields.io/badge/Typikon-Rust%20CLI-brightgreen](https://img.shields.io/badge/📖%20Typikon-Rust%20🦀️-yellow)
[![codecov](https://codecov.io/github/auula/typikon/branch/main/graph/badge.svg?token=FaR2OdNYeB)](https://codecov.io/github/auula/typikon)
[![License](https://img.shields.io/badge/license-Apache-db5149.svg)](https://github.com/auula/typikon/blob/master/LICENSE)
![https://img.shields.io/github/repo-size/auula/typikon](https://img.shields.io/github/repo-size/auula/typikon)
[![action](https://github.com/auula/typikon/actions/workflows/rust.yml/badge.svg?event=push)](https://github.com/auula/typikon/actions/workflows/rust.yml)
[![Twitter URL](https://img.shields.io/twitter/follow/auula_?style=social)](https://twitter.com/auula_)


---

A static website rendering tool similar to mdbook and hugo, but it focuses only on rendering markdown into an online book, and is easier to use than the other tools.
## Introduce

Typikon name derived from [Typikon](https://en.wikipedia.org/wiki/Typikon) Book, the a static website rendering tool similar to mdbook and hugo, but it focuses only on rendering markdown into an online book, and is easier to use than the other tools.

---

## Preview

<div style="display: flex; justify-content: space-around;">
<img src="https://img.ibyte.me/a0mt96.png" alt="Alt text" style="width: 400px; height: 300px;">
<img src="https://img.ibyte.me/e68k6e.png" alt="Alt text" style="width: 400px; height: 300px;">
</div>

---
4 changes: 2 additions & 2 deletions book/chapter_1.1.0.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
### MySQL 8.x 安装和配置
### /book/chapter_1.1.0.md

MySQL 8.x 中引入了许多新特性和改进,包括 JSONJavaScript 作为数据库查询语言,以及更好的性能和安全性。例如,在连接过程中出现的 `Public Key Retrieval is not allowed` 错误提示,这些都是新版本的特性。本文将记录在最新版本的 Ubuntu 中安装 MySQL 8.x 的完整过程。

Expand Down Expand Up @@ -64,7 +64,7 @@ flush privileges;
- 子项目1
- 子项目2

这是一个 [超链接测试]() 对文本内容。
这是一个 [超链接测试](https://www.ibyte.me/) 对文本内容。

## 插入普通图片

Expand Down
83 changes: 83 additions & 0 deletions book/chapter_1.1.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
### /book/chapter_1.1.1.md

MySQL 8.x 中引入了许多新特性和改进,包括 JSONJavaScript 作为数据库查询语言,以及更好的性能和安全性。例如,在连接过程中出现的 `Public Key Retrieval is not allowed` 错误提示,这些都是新版本的特性。本文将记录在最新版本的 Ubuntu 中安装 MySQL 8.x 的完整过程。

---

### 安装和配置

在安装 MySQL 8.x 之前,可以先更新操作系统和软件包:

```sh
sudo apt update && apt upgrade -y
```

更新完成后,可以执行以下命令来查找和安装 MySQL 8.x 软件包:

```sh
sudo apt search mysql
sudo apt install mysql-*
```

安装完成后,使用 `sudo mysql_secure_installation` 初始化 root 用户的密码:

```sh
sudo mysql_secure_installation
```

如果需要允许远程用户访问 MySQL 服务器,可以修改配置文件 `/etc/mysql/mysql.conf.d/mysqld.cnf` 中的 `bind-address`,设置为 `0.0.0.0`:

```ini
bind-address = 0.0.0.0
mysqlx-bind-address = 127.0.0.1
```

然后可以为远程用户授予访问权限:

```sql
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED WITH mysql_native_password BY '新密码' WITH GRANT OPTION;
```

---

### 解决安全连接问题

MySQL 8.x 中,如果出现 `Public Key Retrieval is not allowed` 错误提示,可以执行以下命令来解决:

```sql
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '新密码';
```

执行后,刷新授权表:

```sql
flush privileges;
```

最后,请确保允许服务器上的 `3306` 端口连接。


## 列表示例

- 项目1
- 项目2
- 子项目1
- 子项目2

这是一个 [超链接测试](https://www.ibyte.me/) 对文本内容。

## 插入普通图片

![java](https://img.ibyte.me/470eor.jpg)

## 引用示例

> 这是一个引用示例,可以包含多行文本和**加粗**文字。

## 表格示例

| 姓名 | 年龄 | 城市 |
|--------|------|--------|
| Alice | 25 | 北京 |
| Bob | 30 | 上海 |
| Carol | 28 | 广州 |
10 changes: 4 additions & 6 deletions root.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@ root:
index: "index.md"
chapters:
- title: "Chapter 1"
path: "/chapter1"
index: "/chapter1/chapter1.md"
sub_chapters:
- title: "Section 1.1"
path: "/chapter1/chapter1-section1.1.md"
path: "book/chapter_1.1.0.md"
- title: "Section 1.2"
path: "/chapter1/chapter1-section1.2.md"
path: "book/chapter_1.1.1.md"
- title: "Chapter 2"
path: "/chapter2"
index: "/chapter2/chapter2.md"
sub_chapters:
- title: "Section 2.1"
path: "/chapter2/chapter2-section2.1.md"
path: "book/chapter_1.1.0.md"
- title: "Section 2.2"
path: "/chapter2/chapter2-section2.2.md"
path: "book/chapter_1.1.1.md"
5 changes: 3 additions & 2 deletions settings.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
settings:
about:
title: 现代 Java 编程指南
title: Typikon Book
author: Leon Ding
description: 一本基于 JDK21 版本讲解 Java21 新特性编程实践书籍,采用 WSL + VSCode 作为基础开发环境。
description: Typikon name derived from Typikon Book, the a static website rendering tool similar to mdbook and hugo, but it focuses only on rendering markdown into an online book, and is easier to use than the other tools.
language: zh-cn
keywords: typikon,book,website,generator,static,html,css,js,theme,rust

directory:
theme: theme
Expand Down
159 changes: 124 additions & 35 deletions src/book/builder.rs
Original file line number Diff line number Diff line change
@@ -1,76 +1,140 @@
use std::io;
use std::{collections::HashMap, fs, io, path::Path};

use tera::Tera;

use crate::{
book,
html::{
self,
template::{self, Template},
},
html::{self, template::Template, Hypertext, Markdown},
utils::Logger,
};

use super::{get_settings, Root, Settings};
use super::{Root, Settings};

#[derive(Debug)]
pub struct Builder {
root: Root,
pub templates: Template,
pub engine: Tera,
settings: Settings,
pub templates: Vec<Template>,
}

impl Builder {
// 渲染整本书
pub fn render(&self) -> io::Result<()> {
println!("Builder.render() {:?}", self);
unimplemented!()
pub fn render(&mut self) -> io::Result<()> {
self.create_directory()?;
self.get_chapters_hypertext();
self.copy_theme_assets()?;
Ok(())
}

pub fn get_hypertext() -> Vec<html::Hypertext> {
// 1. 通过 root 目录先创建目录
// 2. 通过 root 目录读取 md 内容
// 3. 通过 md 内容构建 Hypertext
// 4. 通过 Hypertext 落盘
unimplemented!()
pub fn get_chapters_hypertext(&mut self) -> HashMap<String, Vec<html::Hypertext>> {
let mut result: HashMap<String, Vec<html::Hypertext>> = HashMap::new();
let mut log = Logger::console_log();

if let Some(chapters) = self.get_chapter() {
// 开始遍历所有文章,找出同一子篇章的
for chapter in chapters {
let base_chapter = Path::new(&chapter.title);
let mut chapter_hypertexts: Vec<html::Hypertext> = Vec::new();

// 遍历子文章目录,并且将所有的子文章放到同父类中
for sub_chapter in &chapter.sub_chapters {
let sub_chapter_path = &sub_chapter.path;

// 开始读取 markdown 文件的内容
match fs::read_to_string(sub_chapter_path) {
Ok(markdown_content) => {
let hypertext =
Hypertext::new(sub_chapter_path, Markdown::new(&markdown_content));
chapter_hypertexts.push(hypertext);

log.info(format_args!(
"Loading markdown file {:?} successful",
sub_chapter_path
));
}
Err(err) => {
log.error(format_args!("Loading markdown file fail : {:?}", err))
}
}
}

// 转换小写名字
let chapter_key = base_chapter
.file_name()
.and_then(|os_str| os_str.to_str())
.map_or_else(|| chapter.title.clone(), |s| s.to_string());

result.insert(chapter_key.to_lowercase(), chapter_hypertexts);
}
}

result
}

pub fn get_chapter(&self) -> Option<Vec<book::Chapter>> {
fn get_chapter(&self) -> Option<Vec<book::Chapter>> {
if self.root.root.chapters.is_empty() {
None
} else {
Some(self.root.root.chapters.clone())
}
}

pub fn get_sub_chapter(&self) -> Option<Vec<book::SubChapter>> {
if self.root.root.chapters.is_empty() {
None
} else {
Some(
self.root
.root
.chapters
.iter()
.flat_map(|chapter| chapter.sub_chapters.clone())
.collect(),
)
}
fn copy_theme_assets(&self) -> std::io::Result<()> {
let mut log = Logger::console_log();
let from = format!(
"{}/{}/assets",
self.settings.settings.directory.theme, self.settings.settings.theme
);
let to = format!("{}/assets", self.settings.settings.directory.output);

copy_dir_recursive(Path::new(&from), Path::new(&to))?;

log.info(format_args!(
"Building theme assets directory {:?} successful",
&to
));

Ok(())
}

// 先把目录创建好
pub fn create_directory() -> io::Result<()> {
unimplemented!()
}
pub fn create_directory(&mut self) -> io::Result<()> {
let base_path = Path::new(&self.settings.settings.directory.output);
let mut log = Logger::console_log();
// 如果文件存在就删除并重建
if base_path.exists() {
fs::remove_dir_all(base_path)?;
log.info(format_args!(
"Clean up output diretory {:?} successful",
base_path
));
}

fs::create_dir(base_path)?;
log.info(format_args!(
"New create output diretory {:?} successful",
base_path
));

// 创建存放静态 html 文件的二级目录
self.root.root.chapters.iter().try_for_each(|chapter| {
fs::create_dir(base_path.join(&chapter.title.replace(" ", "_").to_lowercase()))
})
}
}

pub fn new_builder() -> Result<Builder, Box<dyn std::error::Error>> {
let root = book::get_root()?;
let templates = html::Template::empty();
let templates = html::get_templates().unwrap();
let settings = book::get_settings()?;
let engine = Tera::new(format!("theme/{}/**/*.html", &settings.settings.theme).as_str())?;
let engine = Tera::new(
format!(
"{}/{}/**/*.html",
&settings.settings.directory.theme, &settings.settings.theme
)
.as_str(),
)?;
// 返回 Builder 实例
Ok(Builder {
root,
Expand All @@ -79,3 +143,28 @@ pub fn new_builder() -> Result<Builder, Box<dyn std::error::Error>> {
settings,
})
}

fn copy_dir_recursive(from: &Path, to: &Path) -> io::Result<()> {
// 创建目标目录如果它不存在
if !to.exists() {
fs::create_dir_all(to)?;
}

// 遍历源目录
for entry in fs::read_dir(from)? {
let entry = entry?;
let path = entry.path();
let relative_path = path.strip_prefix(from).unwrap();
let target_path = to.join(relative_path);

if path.is_dir() {
// 递归地复制子目录
copy_dir_recursive(&path, &target_path)?;
} else if path.is_file() {
// 复制文件
fs::copy(&path, &target_path)?;
}
}

Ok(())
}
7 changes: 0 additions & 7 deletions src/book/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ pub struct InnerRoot {
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Chapter {
pub title: String,
pub path: String,
pub index: String,
pub sub_chapters: Vec<SubChapter>,
}
Expand All @@ -34,9 +33,3 @@ pub fn get_root() -> Result<Root, Box<dyn Error>> {
let root: Root = serde_yaml::from_str(&content)?;
Ok(root)
}

impl Chapter {
pub fn get_sub_chapters(&self) -> &[SubChapter] {
&self.sub_chapters
}
}
Loading

0 comments on commit 4cc7106

Please sign in to comment.