This commit is contained in:
2025-08-13 07:18:02 +02:00
parent 42fe7b0a0d
commit 5fa361256a
13 changed files with 228 additions and 292 deletions

View File

@@ -139,8 +139,6 @@ fn cmd_docusaurus_execute(cmd Command) ! {
console.print_header('Running Docusaurus for: ${docusaurus_path.path}')
// The `playcmds.run` helper expects a string path. Use the underlying
// filesystem path from the pathlib.Path value.
playcmds.run(
heroscript_path: docusaurus_path.path
reset: false

View File

@@ -15,6 +15,7 @@ pub mut:
git_url string
git_pull bool
git_reset bool
git_root string
}
// get_repo_path implements the GitUrlResolver interface
@@ -22,7 +23,7 @@ pub fn get_repo_path(args GetRepoArgs) !string {
if os.exists(args.path) {
return args.path
}
mut gs := get()!
mut gs := get(coderoot:args.git_root)!
mut repo := gs.get_repo(
url: args.git_url
pull: args.git_pull

View File

@@ -116,7 +116,7 @@ pub fn (mut gitstructure GitStructure) get_repo(args_ ReposGetArgs) !&GitRepo {
}
if repositories.len > 1 {
repos := repositories.map('- ${it} ${it.account}.${it.name}').join_lines()
repos := repositories.map('- ${it.account}.${it.name}').join_lines()
return error('Found more than one repository for \n${args}\n${repos}')
}

View File

@@ -0,0 +1,63 @@
module docusaurus
import os
import freeflowuniverse.herolib.core.pathlib
__global (
docusaurus_sites map[string]&DocSite
docusaurus_config ?DocusaurusConfigParams
docusaurus_last string //the last one we worked with
)
pub struct DocusaurusConfig {
pub mut:
path_build pathlib.Path
path_publish pathlib.Path
install bool
reset bool
template_update bool
coderoot string
}
@[params]
pub struct DocusaurusConfigParams {
pub mut:
path_build string
path_publish string
install bool
reset bool
template_update bool
coderoot string
}
//return the last know config
pub fn config() !DocusaurusConfig {
mut args:= docusaurus_config or {DocusaurusConfig{}}
if args.path_build == '' {
args.path_build = '${os.home_dir()}/hero/var/docusaurus/build'
}
if args.path_publish == '' {
args.path_publish = '${os.home_dir()}/hero/var/docusaurus/publish'
}
if !os.exists('${args.path_build}/node_modules') {
args.install = true
}
mut c := DocusaurusConfig{
path_publish: pathlib.get_dir(path: args.path_publish, create: true)!
path_build: pathlib.get_dir(path: args.path_build, create: true)!
coderoot: args.coderoot
install: args.install
reset: args.reset
template_update: args.template_update
}
if c.install {
install()!
c.install=false
}
return c
}
pub fn config_set(args_ DocusaurusConfigParams) ! {
docusaurus_config = args_
}

View File

@@ -1,12 +1,9 @@
module docusaurus
import freeflowuniverse.herolib.osal.screen
import os
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.web.site as sitemodule
import freeflowuniverse.herolib.osal.core as osal
import freeflowuniverse.herolib.ui.console
import time
@[heap]
pub struct DocSite {
@@ -19,7 +16,6 @@ pub mut:
errors []SiteError
config Configuration
website sitemodule.Site
importparams []ImportParams
}
pub fn (mut s DocSite) build() ! {

View File

@@ -1,54 +1,33 @@
module docusaurus
import freeflowuniverse.herolib.develop.gittools
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.core.playbook
import json
import os
import freeflowuniverse.herolib.osal.core as osal
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.core.texttools.regext
// import freeflowuniverse.herolib.data.doctree
import freeflowuniverse.herolib.web.site as sitegen
pub fn (mut site DocSite) generate() ! {
mut f := factory_get()!
pub fn (mut docsite DocSite) generate() ! {
mut c := config()!
console.print_header(' site generate: ${site.name} on ${f.path_build.path}')
console.print_header(' docsite generate: ${docsite.name} on ${c.path_build.path}')
// lets make sure we remove the cfg dir so we rebuild
cfg_path := os.join_path(f.path_build.path)
osal.rm('${c.path_build.path}/docs')!
cfg_path:="${c.path_build.path}/cfg"
osal.rm(cfg_path)!
mut gs := gittools.new()!
template_path := gs.get_path(
pull: false
reset: false
url: 'https://github.com/freeflowuniverse/docusaurus_template/src/branch/main/template/'
)!
osal.rm('${f.path_build.path}/docs')!
mut main_file := pathlib.get_file(path: '${cfg_path}/main.json', create: true)!
main_file.write(json.encode_pretty(site.config.main))!
main_file.write(json.encode_pretty(docsite.config.main))!
mut navbar_file := pathlib.get_file(path: '${cfg_path}/navbar.json', create: true)!
navbar_file.write(json.encode_pretty(site.config.navbar))!
navbar_file.write(json.encode_pretty(docsite.config.navbar))!
mut footer_file := pathlib.get_file(path: '${cfg_path}/footer.json', create: true)!
footer_file.write(json.encode_pretty(site.config.footer))!
footer_file.write(json.encode_pretty(docsite.config.footer))!
// Generate the actual docs content from the processed site configuration
docs_path := '${f.path_build.path}/docs'
docsite.generate_docs()!
// TODO: check site vs website
website := site.website
generate_docs(
path: docs_path
site: website
)!
site.import()!
docsite.import()!
}

View File

@@ -18,26 +18,19 @@ mut:
errors []string // collect errors here
}
@[params]
struct SiteGeneratorArgs {
mut:
path string
flat bool // if flat then won't use sitenames as subdir's
site Site // this is the generic website we are feeding
}
// Generate docs from site configuration
pub fn generate_docs(args SiteGeneratorArgs) ! {
mut path := args.path
if args.path == '' {
return error('Path must be provided to generate site')
}
pub fn (mut docsite DocSite) generate_docs() ! {
c := config()!
//we generate the docs in the build path
docs_path := '${c.path_build.path}/docs'
mut gen := SiteGenerator{
path: pathlib.get_dir(path: path, create: true)!
path: pathlib.get_dir(path: docs_path, create: true)!
client: doctreeclient.new()!
flat: args.flat
site: args.site
flat: true
site: docsite.website
}
for section in gen.site.sections {
@@ -53,26 +46,26 @@ pub fn generate_docs(args SiteGeneratorArgs) ! {
}
}
fn (mut mysite SiteGenerator) error(msg string) ! {
fn (mut generator SiteGenerator) error(msg string) ! {
console.print_stderr('Error: ${msg}')
mysite.errors << msg
generator.errors << msg
}
fn (mut mysite SiteGenerator) page_generate(args_ Page) ! {
fn (mut generator SiteGenerator) page_generate(args_ Page) ! {
mut args := args_
mut content := ['---']
mut parts := args.src.split(':')
if parts.len != 2 {
mysite.error("Invalid src format for page '${args.src}', expected format: collection:page_name, TODO: fix in ${args.path}, check the collection & page_name exists in the pagelist")!
generator.error("Invalid src format for page '${args.src}', expected format: collection:page_name, TODO: fix in ${args.path}, check the collection & page_name exists in the pagelist")!
return
}
collection_name := parts[0]
page_name := parts[1]
mut page_content := mysite.client.get_page_content(collection_name, page_name) or {
mysite.error("Couldn't find page '${collection_name}:${page_name}' is formatted as collectionname:pagename. TODO: fix in ${args.path}, check the collection & page_name exists in the pagelist. ")!
mut page_content := generator.client.get_page_content(collection_name, page_name) or {
generator.error("Couldn't find page '${collection_name}:${page_name}' is formatted as collectionname:pagename. TODO: fix in ${args.path}, check the collection & page_name exists in the pagelist. ")!
return
}
@@ -135,18 +128,18 @@ fn (mut mysite SiteGenerator) page_generate(args_ Page) ! {
args.path += '.md'
}
mut pagepath := '${mysite.path.path}/${args.path}'
mut pagepath := '${generator.path.path}/${args.path}'
mut pagefile := pathlib.get_file(path: pagepath, create: true)!
pagefile.write(c)!
mysite.client.copy_images(collection_name, page_name, pagefile.path_dir()) or {
mysite.error("Couldn't copy image ${pagefile} for '${page_name}' in collection '${collection_name}', try to find the image and fix the path is in ${args.path}.}\nError: ${err}")!
generator.client.copy_images(collection_name, page_name, pagefile.path_dir()) or {
generator.error("Couldn't copy image ${pagefile} for '${page_name}' in collection '${collection_name}', try to find the image and fix the path is in ${args.path}.}\nError: ${err}")!
return
}
}
fn (mut mysite SiteGenerator) section_generate(args_ Section) ! {
fn (mut generator SiteGenerator) section_generate(args_ Section) ! {
mut args := args_
mut c := '{
@@ -157,7 +150,7 @@ fn (mut mysite SiteGenerator) section_generate(args_ Section) ! {
}
}'
mut category_path := '${mysite.path.path}/${args.path}/_category_.json'
mut category_path := '${generator.path.path}/${args.path}/_category_.json'
mut catfile := pathlib.get_file(path: category_path, create: true)!
catfile.write(c)!

View File

@@ -4,59 +4,54 @@ import freeflowuniverse.herolib.develop.gittools
import os
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.core.texttools.regext
@[params]
pub struct ImportParams {
path string
git_url string
git_reset bool
git_root string
git_pull bool
dest string
}
pub fn (mut site DocSite) import() ! {
for importparams in site.importparams {
console.print_header('Importing: ${importparams.path} from ${importparams.git_url}')
mut f := factory_get()!
mut mypath := ''
mut target_path := if os.is_abs_path(importparams.path) {
importparams.path
} else {
os.abs_path(os.join_path(importparams.git_root, importparams.path))
}
// Use gittools to get/update the repo, then navigate to the specific path
repo_path := gittools.get_repo_path(
git_pull: importparams.git_pull
git_reset: importparams.git_reset
git_url: importparams.git_url
path: importparams.git_root
pub fn (mut docsite DocSite) import() ! {
for importparams in docsite.website.siteconfig.imports {
console.print_header('Importing: path:${importparams.path} or url:${importparams.url}')
// pub struct ImportItem {
// name string // will normally be empty
// url string // http git url can be to specific path
// path string
// dest string // location in the docs folder of the place where we will build the documentation site e.g. docusaurus
// replace map[string]string // will replace ${NAME} in the imported content
// visible bool = true
// }
c:=config()!
// Use gittools to get path of what we want to import
import_path := gittools.get_repo_path(
git_pull: c.reset
git_reset: c.reset
git_url: importparams.url
git_root: c.coderoot
path: importparams.path
)!
mut mypatho := pathlib.get(repo_path)
// TODO: We need to think about a better way to do it
mypatho.path = repo_path + '/' + importparams.path.all_after('/')
mut import_patho := pathlib.get(import_path)
mut static_dest := '${f.path_build.path}/static'
println('static_dest: ${static_dest}')
if importparams.dest.len > 0 {
static_dest = '${static_dest}/${importparams.dest}'
if importparams.dest.starts_with("/") {
return error("Import path ${importparams.dest} must be relative, will be relative in relation to the build dir.")
}
mypatho.copy(dest: static_dest, delete: false)!
// println(item)
// // replace: {'NAME': 'MyName', 'URGENCY': 'red'}
// mut ri := regext.regex_instructions_new()
// for key, val in item.replace {
// ri.add_item('\{${key}\}', val)!
// }
// ri.replace_in_dir(
// path: '${f.path_build.path}/docs/${item.dest}'
// extensions: [
// 'md',
// ]
// )!
import_patho.copy(dest: '${c.path_build.path}/${importparams.dest}', delete: false)!
// println(importparams)
// replace: {'NAME': 'MyName', 'URGENCY': 'red'}
mut ri := regext.regex_instructions_new()
for key, val in importparams.replace {
ri.add_item('\{${key}\}', val)!
}
ri.replace_in_dir(
path: '${c.path_build.path}/docs/${importparams.dest}'
extensions: [
'md',
]
)!
}
}

View File

@@ -1,66 +1,64 @@
module docusaurus
import os
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.develop.gittools
import freeflowuniverse.herolib.osal.core as osal
import freeflowuniverse.herolib.installers.web.bun
__global (
docusaurus_sites map[string]&DocSite
docusaurus_factory []DocSiteFactory
)
pub struct DocSiteFactory {
pub mut:
path_publish pathlib.Path
path_build pathlib.Path
}
import freeflowuniverse.herolib.web.site
import freeflowuniverse.herolib.ui.console
@[params]
pub struct DocSiteFactoryArgs {
pub struct AddArgs {
pub mut:
path_build string
path_publish string
install bool
reset bool
template_update bool
sitename string // needs to exist in web.site module
}
pub fn factory_get(args_ DocSiteFactoryArgs) !DocSiteFactory {
mut args := args_
if docusaurus_factory.len > 1 {
panic('multiple docusaurus factories found, please specify which one to use')
}
if docusaurus_factory.len > 0 {
return docusaurus_factory[0]
}
return factory_set(args)!
pub fn dsite_define(sitename string) ! {
console.print_header('Add Docusaurus Site: ${sitename}')
mut c := config()!
path_publish := '${c.path_publish.path}/${sitename}'
path_build_ := '${c.path_build.path}/${sitename}'
// Get the site object after processing, this is the website which is a generic definition of a site
mut website := site.get(name: sitename)!
// Create the DocSite instance
mut dsite := &DocSite{
name: sitename
path_publish: pathlib.get_dir(path: path_publish, create: true)!
path_build: pathlib.get_dir(path: path_build_, create: true)!
config: new_configuration(website.siteconfig)!
website: website
}
pub fn factory_set(args_ DocSiteFactoryArgs) !DocSiteFactory {
mut args := args_
if args.path_build == '' {
args.path_build = '${os.home_dir()}/hero/var/docusaurus/build'
}
if args.path_publish == '' {
args.path_publish = '${os.home_dir()}/hero/var/docusaurus/publish'
}
mut factory := DocSiteFactory{
path_publish: pathlib.get_dir(path: args.path_publish, create: true)!
path_build: pathlib.get_dir(path: args.path_build, create: true)!
docusaurus_sites[sitename] = dsite
docusaurus_last = sitename
}
if !os.exists('${args.path_build}/node_modules') {
args.install = true
pub fn dsite_get(name_ string) !&DocSite {
mut name := texttools.name_fix(name_)
if name=="" {
name = docusaurus_last
}
return docusaurus_sites[name] or {
return error('docusaurus site with name "${name}" does not exist')
}
}
if args.install {
factory.install(args.reset, args.template_update)!
pub fn dsite_exists(name_ string) !bool {
mut name := texttools.name_fix(name_)
if name=="" {
name = docusaurus_last
}
_ := docusaurus_sites[name] or { return false }
return true
}
docusaurus_factory << factory
return factory
// dsite_names returns the list of defined docusaurus site names.
pub fn dsite_names() []string {
mut names := []string{}
for k, _ in docusaurus_sites {
names << k
}
return names
}

View File

@@ -1,68 +0,0 @@
module docusaurus
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.web.site
import freeflowuniverse.herolib.ui.console
@[params]
pub struct AddArgs {
pub mut:
sitename string // needs to exist in web.site module
}
pub fn dsite_define(sitename string) ! {
console.print_header('Add Docusaurus Site: ${sitename}')
mut f := factory_get()!
path_publish := '${f.path_publish.path}/${sitename}'
path_build_ := '${f.path_build.path}/${sitename}'
// Get the site object after processing, this is the website which is a generic definition of a site
mut website := site.get(name: sitename)!
// Create the DocSite instance
mut dsite := &DocSite{
name: sitename
path_publish: pathlib.get_dir(path: path_publish, create: true)!
path_build: pathlib.get_dir(path: path_build_, create: true)!
config: new_configuration(website.siteconfig)!
website: website
}
docusaurus_sites[sitename] = dsite
}
pub fn dsite_get(name_ string) !&DocSite {
name := texttools.name_fix(name_)
return docusaurus_sites[name] or {
return error('docusaurus site with name "${name}" does not exist')
}
}
pub fn dsite_exists(name_ string) !bool {
name := texttools.name_fix(name_)
_ := docusaurus_sites[name] or { return false }
return true
}
// dsite_names returns the list of defined docusaurus site names.
pub fn dsite_names() []string {
mut names := []string{}
for k, _ in docusaurus_sites {
names << k
}
return names
}
// dsite_get_only returns the only defined site, or an error if there are none or more than one.
pub fn dsite_get_only() !&DocSite {
if docusaurus_sites.len != 1 {
return error('expected exactly one docusaurus site to be defined, found ${docusaurus_sites.len}')
}
for _, v in docusaurus_sites {
return v
}
return error('no docusaurus site found')
}

View File

@@ -6,24 +6,27 @@ import freeflowuniverse.herolib.develop.gittools
import freeflowuniverse.herolib.osal.core as osal
import freeflowuniverse.herolib.installers.web.bun
fn (mut f DocSiteFactory) install(reset bool, template_update bool) ! {
fn install() ! {
mut gs := gittools.new()!
if reset {
osal.rm(f.path_build.path)!
osal.dir_ensure(f.path_build.path)!
mut c:=config()!
if c.reset {
osal.rm(c.path_build.path)!
osal.dir_ensure(c.path_build.path)!
}
template_path := gs.get_path(
pull: template_update
reset: reset // Changed args.delete to args.reset
pull: c.template_update
reset: c.reset
url: 'https://github.com/freeflowuniverse/docusaurus_template/src/branch/main/template'
)!
mut template_path0 := pathlib.get_dir(path: template_path, create: false)!
template_path0.copy(dest: f.path_build.path, delete: reset)! // Changed args.delete to args.reset
template_path0.copy(dest: c.path_build.path, delete: false)! //the dir has already been deleted so no point to delete again
if c.install { //config.install is set in factory if there is missing bun
// install bun
mut installer := bun.get()!
installer.install()!
@@ -31,9 +34,10 @@ fn (mut f DocSiteFactory) install(reset bool, template_update bool) ! {
// always stay in the context of the build directory
cmd: '
${osal.profile_path_source_and()!}
export PATH=${f.path_build.path}/node_modules/.bin::${os.home_dir()}/.bun/bin/:\$PATH
cd ${f.path_build.path}
export PATH=${c.path_build.path}/node_modules/.bin::${os.home_dir()}/.bun/bin/:\$PATH
cd ${c.path_build.path}
bun install
'
)!
}
}

View File

@@ -9,16 +9,11 @@ pub fn play(mut plbook PlayBook) ! {
return
}
// 1. Process generic site configuration first.
// This populates the global `site.websites` map.
site.play(mut plbook)!
//there should be 1 define section
mut action_define := plbook.ensure_once(filter: 'docusaurus.define')!
// 3. Process `docusaurus.add` actions to create sites.
mut param_define := action_define.params
_ := factory_set(
config_set(
path_build: param_define.get_default('path_build', '')!
path_publish: param_define.get_default('path_publish', '')!
reset: param_define.get_default_false('reset')
@@ -34,25 +29,6 @@ pub fn play(mut plbook PlayBook) ! {
action_define.done = true
mut dsite := dsite_get(site_name)!
// imports
mut actions_import := plbook.find(filter: 'docusaurus.import')!
for mut action in actions_import {
mut p := action.params
// TODO: We need to get the repo path from the path
// Import paths like ../docusaurus are authored relative to the project root (docs_owh)
// project_root = dirname(dirname(plbook.path)) since plbook.path = ebooks/owh_investment_memo
mut project_root := os.abs_path(os.join_path(plbook.path, '..', '..'))
dsite.importparams << ImportParams{
path: p.get_default('path', '')!
git_url: p.get_default('git_url', '')!
git_reset: p.get_default_false('git_reset')
git_pull: p.get_default_false('git_pull')
git_root: project_root
dest: p.get_default('dest', '')!
}
action.done = true
}
mut actions_dev := plbook.find(filter: 'docusaurus.dev')!
if actions_dev.len > 1 {
return error('Multiple "docusaurus.dev" actions found. Only one is allowed.')
@@ -67,6 +43,7 @@ pub fn play(mut plbook PlayBook) ! {
action.done = true
}
mut actions_build := plbook.find(filter: 'docusaurus.build')!
if actions_build.len > 1 {
return error('Multiple "docusaurus.build" actions found. Only one is allowed.')
@@ -76,9 +53,9 @@ pub fn play(mut plbook PlayBook) ! {
action.done = true
}
mut actions_export := plbook.find(filter: 'docusaurus.export')!
mut actions_export := plbook.find(filter: 'docusaurus.publish')!
if actions_export.len > 1 {
return error('Multiple "docusaurus.export" actions found. Only one is allowed.')
return error('Multiple "docusaurus.publish" actions found. Only one is allowed.')
}
for mut action in actions_export {
dsite.build_publish()!

View File

@@ -49,9 +49,8 @@ pub fn play(mut plbook PlayBook) ! {
play_import(mut plbook, mut config)!
play_menu(mut plbook, mut config)!
play_footer(mut plbook, mut config)!
play_build_dest(mut plbook, mut config)!
play_build_dest_dev(mut plbook, mut config)!
play_publish(mut plbook, mut config)!
play_publish_dev(mut plbook, mut config)!
play_pages(mut plbook, mut website)!
}
@@ -170,12 +169,12 @@ fn play_footer(mut plbook PlayBook, mut config SiteConfig) ! {
}
}
fn play_build_dest(mut plbook PlayBook, mut config SiteConfig) ! {
mut build_dest_actions := plbook.find(filter: 'site.build_dest')!
fn play_publish(mut plbook PlayBook, mut config SiteConfig) ! {
mut build_dest_actions := plbook.find(filter: 'site.publish')!
for mut action in build_dest_actions {
mut p := action.params
mut dest := BuildDest{
path: p.get_default('path', '')!
path: p.get_default('path', '')! //can be url
ssh_name: p.get_default('ssh_name', '')!
}
config.build_dest << dest
@@ -183,15 +182,16 @@ fn play_build_dest(mut plbook PlayBook, mut config SiteConfig) ! {
}
}
fn play_build_dest_dev(mut plbook PlayBook, mut config SiteConfig) ! {
mut build_dest_dev_actions := plbook.find(filter: 'site.build_dest_dev')!
for mut action in build_dest_dev_actions {
fn play_publish_dev(mut plbook PlayBook, mut config SiteConfig) ! {
mut build_dest_actions := plbook.find(filter: 'site.publish_dev')!
for mut action in build_dest_actions {
mut p := action.params
mut dest_dev := BuildDest{
path: p.get('path')!
mut dest := BuildDest{
path: p.get_default('path', '')! //can be url
ssh_name: p.get_default('ssh_name', '')!
}
config.build_dest_dev << dest_dev
config.build_dest_dev << dest
action.done = true // Mark the action as done
}
}