You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

495 lines
12 KiB

package main
import (
"bytes"
"fmt"
"math"
"os"
"os/exec"
"runtime"
"sort"
"text/template"
"time"
)
type Outter struct {
MetaData map[string]interface{} // 记录source/data下的所有文件
Posts []Post // 记录文章
Pages []Page // 记录页面
Theme Theme // 记录主题模板文件
Config Config // 全局配置
Paginate bool // 是否开启了分页
PageTotal int // 页面总数
PageCurrent int // 当前分页
}
type PostOutter struct {
Post Post
Config Config
}
type PageOutter struct {
Page Page
Config Config
PostData []PostData
}
type PostData struct {
Key string
Posts []Post
}
// check 检测目标
func (o *Outter) check() {
o.Config.SourceVersion = Md5(time.Now().String())[:10]
var args []string
switch runtime.GOOS {
case "windows":
args = []string{"cmd.exe", "/C", "rmdir", "/S", "/Q", "dist"}
default:
args = []string{"rm", "-rf", "./dist"}
}
var cmd = exec.Command(args[0], args[1:]...)
if err := cmd.Run(); err != nil {
sout(cmd.String())
serr("clear dist directory failed: %v", err)
}
if !isExist("./dist") {
if err := mkdir("./dist"); err != nil {
sfault("create dist directory failed: %v", err)
}
}
if err := mkdir("./dist/" + o.Config.SourceVersion); err != nil {
sfault("create source directory failed: %v", err)
}
}
func (o *Outter) createDir(fp string) error {
if !isExist(fp) {
if err := mkdir(fp); err != nil {
sfault("create %s directory failed: %v", fp, err)
}
}
return nil
}
// sourceCopy 资源拷贝 将主题的资源拷贝到目标文件夹中
func (o *Outter) sourceCopy() {
var args []string
switch runtime.GOOS {
case "windows":
args = []string{"cmd.exe", "/C", "xcopy", "/e", "/y"}
default:
args = []string{"cp", "-r"}
}
themePath := slash(fmt.Sprintf("./themes/%s/", o.Config.Theme))
destPath := slash(fmt.Sprintf("./dist/%s/", o.Config.SourceVersion))
cmd := exec.Command(args[0], append(args[1:], themePath+"css", slash(destPath+"css/"))...)
if err := cmd.Run(); err != nil {
sout(cmd.String())
sfault("copy theme css source failed: %v", err)
}
cmd = exec.Command(args[0], append(args[1:], themePath+"js", slash(destPath+"js/"))...)
if err := cmd.Run(); err != nil {
sout(cmd.String())
sfault("copy theme js source failed: %v", err)
}
cmd = exec.Command(args[0], append(args[1:], themePath+"images", slash(destPath+"images/"))...)
if err := cmd.Run(); err != nil {
sout(cmd.String())
sfault("copy theme images source failed: %v", err)
}
}
// generate 文件生成
func (o *Outter) generate() {
o.check()
o.sourceCopy()
o.generateIndex()
o.generatePost()
o.generatePage()
o.generateArchives()
o.generateTags()
o.generateCategory()
}
var funcMap = template.FuncMap{
"getSource": getSource,
"add": add,
"sum": sum,
}
// generateIndex 首页生成
func (o *Outter) generateIndex() {
indexTemplate := template.New("index")
funcMap["title"] = func() string {
return o.Config.Title
}
indexTemplate.Funcs(funcMap)
indexTemplate, err := indexTemplate.Parse(string(o.Theme.IndexLayout))
if err != nil {
sfault("parse index layout failed: %v", err)
}
// 首页文件
var buffer = bytes.Buffer{}
// 没开分页
if !o.Config.Site.Paginate {
err = indexTemplate.Execute(&buffer, o)
if err != nil {
sfault("generate index page failed: %v", err)
}
var filename = "./dist/index.html"
if err := os.WriteFile(filename, buffer.Bytes(), os.ModePerm); err != nil {
sfault("write index file failed: %v", err)
}
sout("index generate success...")
return
}
// 分页数据不规范
if o.Config.Site.PageSize < 1 {
sfault("page size must > 1")
}
var pageSize = int(math.Ceil(float64(len(o.Posts)) / float64(o.Config.Site.PageSize)))
o.PageTotal = pageSize
o.Paginate = true
var posts = make([]Post, len(o.Posts))
copy(posts, o.Posts)
for i := 0; i < pageSize; i++ {
rightBorder := int(o.Config.Site.PageSize) * (i + 1)
if rightBorder > len(posts) {
rightBorder = len(posts)
}
leftBorder := int(o.Config.Site.PageSize) * (i)
o.Posts = make([]Post, rightBorder-leftBorder)
copy(o.Posts, posts[leftBorder:rightBorder])
o.PageCurrent = i + 1
err = indexTemplate.Execute(&buffer, o)
if err != nil {
sfault("generate index page failed: %v", err)
}
// 第一页 主页
if i == 0 {
// 第一次的时候创建目录
dir := "./dist/page"
if err := o.createDir(dir); err != nil {
sfault("create index page failed: %v", err)
return
}
var filename = "./dist/index.html"
if err := os.WriteFile(filename, buffer.Bytes(), os.ModePerm); err != nil {
sfault("write index file failed: %v", err)
}
}
fPage := fmt.Sprintf("./dist/page/%d.html", i+1)
if err := os.WriteFile(fPage, buffer.Bytes(), os.ModePerm); err != nil {
sfault("write index file failed: %v", err)
}
buffer.Reset()
}
o.Posts = make([]Post, len(posts))
copy(o.Posts, posts)
}
func (o *Outter) generatePost() {
postTemplate := template.New("post")
var postBuffer = new(bytes.Buffer)
for _, post := range o.Posts {
instance := PostOutter{
Post: post,
Config: o.Config,
}
funcMap["title"] = func() string {
return instance.Post.Title
}
funcMap["post_name"] = func() string {
return o.Config.Title
}
postTemplate.Funcs(funcMap)
postTemplate, err := postTemplate.Parse(string(o.Theme.PostLayout))
if err != nil {
sfault("generate post page failed: %v", err)
}
// 入buffer
if err := postTemplate.Execute(postBuffer, instance); err != nil {
sfault("generate post page failed: %v", err)
}
// buffer写文件
var catDir = fmt.Sprintf("./dist/%s", post.Category)
if !isExist(catDir) {
if err := mkdir(catDir); err != nil {
sfault("create directory failed: %v", err)
}
}
var filename = fmt.Sprintf("%s/%s.html", catDir, post.FileBasename)
if err := os.WriteFile(filename, postBuffer.Bytes(), os.ModePerm); err != nil {
sfault("write file failed: %v", err)
}
postBuffer.Reset()
}
}
func (o *Outter) generatePage() {
pageTemplate := template.New("page")
var pageBuffer = new(bytes.Buffer)
for _, page := range o.Pages {
instance := PageOutter{
Page: page,
Config: o.Config,
}
funcMap["title"] = func() string {
return page.Title
}
funcMap["page_name"] = func() string {
return o.Config.Title
}
pageTemplate.Funcs(funcMap)
pageTemplate, err := pageTemplate.Parse(string(o.Theme.PageLayout))
if err != nil {
sfault("generate page page failed: %v", err)
}
// 入buffer
if err := pageTemplate.Execute(pageBuffer, instance); err != nil {
sfault("generate page page failed: %v", err)
}
// buffer写文件
var filename = fmt.Sprintf("./dist/%s.html", page.Link)
if err := os.WriteFile(filename, pageBuffer.Bytes(), os.ModePerm); err != nil {
sfault("write page content failed: %v", err)
}
pageBuffer.Reset()
}
}
func (o *Outter) generateArchives() {
archiveTemplate := template.New("archive")
var archiveBuffer = new(bytes.Buffer)
// 按时间归档
var m = make(map[string][]Post)
for _, post := range o.Posts {
newPost := post
newPost.MD = ""
m[int2String(post.CreatedAt.Year())] = append(m[int2String(post.CreatedAt.Year())], newPost)
}
var postData []PostData
for year, posts := range m {
postData = append(postData, PostData{
Key: year,
Posts: posts,
})
}
sort.Slice(postData, func(i, j int) bool {
return postData[i].Key > postData[j].Key
})
var instance = PageOutter{
Page: Page{
Title: "Archives",
Link: "archives",
},
Config: o.Config,
PostData: postData,
}
funcMap["title"] = func() string {
return instance.Page.Title
}
funcMap["page_name"] = func() string {
return o.Config.Title
}
archiveTemplate.Funcs(funcMap)
archiveTemplate, err := archiveTemplate.Parse(string(o.Theme.ArchiveLayout))
if err != nil {
sfault("generate archive page failed: %v", err)
}
// 入buffer
if err := archiveTemplate.Execute(archiveBuffer, instance); err != nil {
sfault("generate archive page failed: %v", err)
}
// buffer写文件
var filename = fmt.Sprintf("./dist/%s.html", instance.Page.Link)
if err := os.WriteFile(filename, archiveBuffer.Bytes(), os.ModePerm); err != nil {
sfault("write archive page failed: %v", err)
}
archiveBuffer.Reset()
}
func (o *Outter) generateTags() {
tagsTemplate := template.New("tags")
var tagsBuffer = new(bytes.Buffer)
// 按标签归档
var mTag = make(map[string][]Post)
for _, post := range o.Posts {
for _, tag := range post.Tags {
newPost := post
newPost.MD = ""
mTag[tag] = append(mTag[tag], newPost)
}
}
for tag, posts := range mTag {
// 按时间归档
var m = make(map[string][]Post)
for _, post := range posts {
newPost := post
newPost.MD = ""
m[int2String(post.CreatedAt.Year())] = append(m[int2String(post.CreatedAt.Year())], newPost)
}
var postData []PostData
for year, _posts := range m {
postData = append(postData, PostData{
Key: year,
Posts: _posts,
})
}
sort.Slice(postData, func(i, j int) bool {
return postData[i].Key > postData[j].Key
})
var instance = PageOutter{
Page: Page{
Title: tag,
Link: tag,
},
Config: o.Config,
PostData: postData,
}
funcMap["title"] = func() string {
return "Tag: " + instance.Page.Title
}
funcMap["page_name"] = func() string {
return o.Config.Title
}
tagsTemplate.Funcs(funcMap)
tagsTemplate, err := tagsTemplate.Parse(string(o.Theme.TagLayout))
if err != nil {
sfault("generate tags page failed: %v", err)
}
// 入buffer
if err := tagsTemplate.Execute(tagsBuffer, instance); err != nil {
sfault("generate tags page failed: %v", err)
}
// 创建tag文件夹
var tagDir = "./dist/tags"
if !isExist(tagDir) {
if err := mkdir(tagDir); err != nil {
sfault("create tag directory failed: %v", err)
}
}
// buffer写文件
var filename = fmt.Sprintf("%s/%s.html", tagDir, instance.Page.Link)
if err := os.WriteFile(filename, tagsBuffer.Bytes(), os.ModePerm); err != nil {
sfault("write tag content failed: %v", err)
}
tagsBuffer.Reset()
}
}
func (o *Outter) generateCategory() {
tagsTemplate := template.New("category")
var catBuffer = new(bytes.Buffer)
// 按标签归档
var mCats = make(map[string][]Post)
for _, post := range o.Posts {
newPost := post
newPost.MD = ""
mCats[post.Category] = append(mCats[post.Category], newPost)
}
for cat, posts := range mCats {
// 按时间归档
var m = make(map[string][]Post)
for _, post := range posts {
newPost := post
newPost.MD = ""
m[int2String(post.CreatedAt.Year())] = append(m[int2String(post.CreatedAt.Year())], newPost)
}
var postData []PostData
for year, _posts := range m {
postData = append(postData, PostData{
Key: year,
Posts: _posts,
})
}
sort.Slice(postData, func(i, j int) bool {
return postData[i].Key > postData[j].Key
})
var instance = PageOutter{
Page: Page{
Title: cat,
Link: cat,
},
Config: o.Config,
PostData: postData,
}
funcMap["title"] = func() string {
return "Category: " + instance.Page.Title
}
funcMap["page_name"] = func() string {
return o.Config.Title
}
tagsTemplate.Funcs(funcMap)
tagsTemplate, err := tagsTemplate.Parse(string(o.Theme.TagLayout))
if err != nil {
sfault("generate category page failed: %v", err)
}
// 入buffer
if err := tagsTemplate.Execute(catBuffer, instance); err != nil {
sfault("generate category page failed: %v", err)
}
// 创建tag文件夹
var tagDir = "./dist/category"
if !isExist(tagDir) {
if err := mkdir(tagDir); err != nil {
sfault("create category directory failed: %v", err)
}
}
// buffer写文件
var filename = fmt.Sprintf("%s/%s.html", tagDir, instance.Page.Link)
if err := os.WriteFile(filename, catBuffer.Bytes(), os.ModePerm); err != nil {
sfault("write category content failed: %v", err)
}
catBuffer.Reset()
}
}
func getSource(data interface{}, key string) interface{} {
meta, ok := data.(map[string]interface{})
if !ok {
return nil
}
return meta[key]
}
func add(a, b int) int {
return a + b
}
func sum(a, b int) int {
return a - b
}