Files
herolib/lib/web/mdbook/mdbook.v
Mahmoud Emad 4c01c88b85 WIP: Building hero
- The work is still in progress

Co-authored-by: supermario <mariobassem12@gmail.com>
2025-01-02 19:01:37 +02:00

297 lines
8.4 KiB
V

module mdbook
import freeflowuniverse.herolib.osal
import os
import freeflowuniverse.herolib.data.doctree.collection
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.core.base
import freeflowuniverse.herolib.develop.gittools
@[heap]
pub struct MDBook {
pub mut:
name string
books &MDBooks @[skip; str: skip]
path_build pathlib.Path
path_publish pathlib.Path
args MDBookArgs
errors []collection.CollectionError
}
@[params]
pub struct MDBookArgs {
pub mut:
name string @[required]
title string
foldlevel int
printbook bool
// summary_url string // url of the summary.md file
summary_path string // can also give the path to the summary file (can be the dir or the summary itself)
// doctree_url string
// doctree_path string
publish_path string
build_path string
production bool
collections []string
description string
export bool // whether mdbook should be built
}
pub fn (mut books MDBooks) generate(args_ MDBookArgs) !&MDBook {
console.print_header(' mdbook: ${args_.name}')
mut args := args_
if args.title == '' {
args.title = args.name
}
if args.build_path.len == 0 {
args.build_path = '${books.path_build}/${args.name}'
}
if args.publish_path.len == 0 {
args.publish_path = '${books.path_publish}/${args.name}'
}
mut mycontext := base.context()!
mut r := mycontext.redis()!
r.set('mdbook:${args.name}:build', args.build_path)!
r.set('mdbook:${args.name}:publish', args.publish_path)!
r.expire('mdbook:${args.name}:build', 3600 * 12)! // expire after 12h
r.expire('mdbook:${args.name}:publish', 3600 * 12)!
_ := gittools.get()!
mut src_path := pathlib.get_dir(path: '${args.build_path}/src', create: true)!
_ := pathlib.get_dir(path: '${args.build_path}/.edit', create: true)!
mut collection_set := map[string]bool{}
for col_path in args.collections {
// link collections from col_path to src
mut p := pathlib.get_dir(path: col_path)!
_ := p.list(dirs_only: true, recursive: false)!
if _ := collection_set[p.name()] {
return error('collection with name ${p.name()} already exists')
}
p.link('${src_path.path}/${p.name()}', true)!
// QUESTION: why was this ever implemented per entry?
// for mut entry in entries.paths {
// if _ := collection_set[entry.name()] {
// println('collection with name ${entry.name()} already exists')
// // return error('collection with name ${entry.name()} already exists')
// }
// collection_set[entry.name()] = true
// entry.link('${src_path.path}/${entry.name()}', true)!
// }
}
mut book := MDBook{
args: args
path_build: pathlib.get_dir(path: args.build_path, create: true)!
path_publish: pathlib.get_dir(path: args.publish_path, create: true)!
books: &books
}
mut summary := book.summary(args_.production)!
mut dir_list := src_path.list(dirs_only: true, include_links: true, recursive: false)!
for mut collection_dir_path in dir_list.paths {
collectionname := collection_dir_path.path.all_after_last('/')
// should always work because done in summary
// check if there are errors, if yes add to summary
if os.exists('${collection_dir_path.path}/errors.md') {
summary.add_error_page(collectionname, 'errors.md')
}
// now link the exported collection into the build dir
collection_dirbuild_str := '${book.path_build.path}/src/${collectionname}'.replace('~',
os.home_dir())
if !pathlib.path_equal(collection_dirbuild_str, collection_dir_path.path) {
collection_dir_path.link(collection_dirbuild_str, true)!
}
if !os.exists('${collection_dir_path.path}/.linkedpages') {
continue
}
mut linked_pages := pathlib.get_file(path: '${collection_dir_path.path}/.linkedpages')!
lpagescontent := linked_pages.read()!
for lpagestr in lpagescontent.split_into_lines().filter(it.trim_space() != '') {
// console.print_green('find linked page: ${lpagestr}')
// format $collection:$pagename.md
splitted := lpagestr.split(':')
assert splitted.len == 2
summary.add_page_additional(splitted[0], splitted[1])
}
// if collection_dir_path.file_exists('.linkedpages') {
// mut lpages := collection_dir_path.file_get('.linkedpages')!
// lpagescontent := lpages.read()!
// for lpagestr in lpagescontent.split_into_lines().filter(it.trim_space() != '') {
// // console.print_green('find linked page: ${lpagestr}')
// // format $collection:$pagename.md
// splitted := lpagestr.split(':')
// assert splitted.len == 2
// summary.add_page_additional(splitted[0], splitted[1])
// }
// }
}
// create the additional collection (is a system collection)
addpath := '${book.path_build.path}/src/additional'
mut a := pathlib.get_file(path: '${addpath}/additional.md', create: true)!
mut b := pathlib.get_file(path: '${addpath}/errors.md', create: true)!
mut c := pathlib.get_file(path: '${addpath}/pages.md', create: true)!
a.write('
# Additional pages
A normal user can ignore these pages, they are for the authors to see e.g. errors
')!
b.write('
# Errors
Be the mother for our errors.
')!
c.write('
# Additional pages
You can ignore these pages, they are just to get links to work.
')!
if book.errors.len > 0 {
book.errors_report()!
summary.errors << SummaryItem{
level: 2
description: 'errors mdbook'
pagename: 'errors_mdbook.md'
collection: 'additional'
}
}
path_summary_str := '${book.path_build.path}/src/SUMMARY.md'
mut path_summary := pathlib.get_file(path: path_summary_str, create: true)!
path_summary.write(summary.str())!
book.template_install()!
if args.export {
book.generate()!
}
console.print_header(' mdbook prepared: ${book.path_build.path}')
return &book
}
// write errors.md in the collection, this allows us to see what the errors are
fn (book MDBook) errors_report() ! {
errors_path_str := '${book.path_build.path}/src/additional/errors_mdbook.md'
mut dest := pathlib.get_file(path: errors_path_str, create: true)!
if book.errors.len == 0 {
dest.delete()!
return
}
c := $tmpl('template/errors.md')
dest.write(c)!
}
@[params]
pub struct ErrorArgs {
pub mut:
path string
msg string
cat collection.CollectionErrorCat
}
pub fn (mut book MDBook) error(args ErrorArgs) {
path2 := pathlib.get(args.path)
e := collection.CollectionError{
path: path2
msg: args.msg
cat: args.cat
}
book.errors << e
console.print_stderr(args.msg)
}
pub fn (mut book MDBook) open() ! {
console.print_header('open book: ${book.name}')
cmd := 'open \'${book.path_publish.path}/index.html\''
// console.print_debug(cmd)
// cmd:='bash ${book.path_build.path}/develop.sh'
osal.exec(cmd: cmd)!
}
pub fn (mut book MDBook) generate() ! {
console.print_header(' book generate: ${book.name} on ${book.path_build.path}')
book.summary_image_set()!
osal.exec(
cmd: '
cd ${book.path_build.path}
mdbook build --dest-dir ${book.path_publish.path}
'
retry: 0
)!
}
fn (mut book MDBook) template_install() ! {
// get embedded files to the mdbook dir
// console.print_debug(book.str())
mut l := loader()!
l.load()!
for item in l.embedded_files {
dpath := '${book.path_build.path}/${item.path.all_after_first('/')}'
// console.print_debug(' embed: ${dpath}')
mut dpatho := pathlib.get_file(path: dpath, create: true)!
dpatho.write(item.to_string())!
}
c := $tmpl('template/book.toml')
mut tomlfile := book.path_build.file_get_new('book.toml')!
tomlfile.write(c)!
c1 := $tmpl('template/build.sh')
mut file1 := book.path_build.file_get_new('build.sh')!
file1.write(c1)!
file1.chmod(0o770)!
c2 := $tmpl('template/develop.sh')
mut file2 := book.path_build.file_get_new('develop.sh')!
file2.write(c2)!
file2.chmod(0o770)!
}
fn (mut book MDBook) summary_image_set() ! {
// this is needed to link the first image dir in the summary to the src, otherwise empty home image
summaryfile := '${book.path_build.path}/src/SUMMARY.md'
mut p := pathlib.get_file(path: summaryfile)!
c := p.read()!
mut first := true
for line in c.split_into_lines() {
if !(line.trim_space().starts_with('-')) {
continue
}
if line.contains('](') && first {
folder_first := line.all_after('](').all_before_last(')')
folder_first_dir_img := '${book.path_build.path}/src/${folder_first.all_before_last('/')}/img'
// console.print_debug(folder_first_dir_img)
// if true{panic("s")}
if os.exists(folder_first_dir_img) {
mut image_dir := pathlib.get_dir(path: folder_first_dir_img)!
image_dir.link('${book.path_build.path}/src/img', true)!
}
first = false
}
}
}