This commit is contained in:
2025-08-12 15:52:13 +02:00
parent 0e1450b5db
commit ffff44f347
23 changed files with 437 additions and 388 deletions

View File

@@ -13,13 +13,14 @@ pub struct DocSite {
pub mut:
name string
url string
path_src pathlib.Path
// path_src pathlib.Path
path_publish pathlib.Path
path_build pathlib.Path
errors []SiteError
config Configuration
website sitemodule.Site
}
importparams []ImportParams
}
pub fn (mut s DocSite) build() ! {
s.generate()!
@@ -81,104 +82,6 @@ pub fn (mut s DocSite) dev(args DevArgs) ! {
s.open()!
}
pub fn (mut s DocSite) dev_watch(args DevArgs) ! {
s.generate()!
// Create screen session for docusaurus development server
mut screen_name := 'docusaurus'
mut sf := screen.new()!
// Add and start a new screen session
mut scr := sf.add(
name: screen_name
cmd: '/bin/bash'
start: true
attach: false
reset: true
)!
// Send commands to the screen session
console.print_item('To view the server output:: cd ${s.path_build.path}')
scr.cmd_send('cd ${s.path_build.path}')!
// Start script recording in the screen session for log streaming
log_file := '/tmp/docusaurus_${screen_name}.log'
script_cmd := 'script -f ${log_file}'
scr.cmd_send(script_cmd)!
// Small delay to ensure script is ready
time.sleep(500 * time.millisecond)
// Start bun in the scripted session
bun_cmd := 'bun start -p ${args.port} -h ${args.host}'
scr.cmd_send(bun_cmd)!
// Stream the log output to current terminal
console.print_header(' Docusaurus Development Server')
console.print_item('Streaming server output... Press Ctrl+C to detach and leave server running')
console.print_item('Server will be available at: http://${args.host}:${args.port}')
console.print_item('To reattach later: screen -r ${screen_name}')
println('')
// Stream logs until user interrupts
s.stream_logs(log_file, screen_name)!
// After user interrupts, show final instructions
console.print_header(' Server Running in Background')
console.print_item(' Development server is running in background')
console.print_item('Server URL: http://${args.host}:${args.port}')
console.print_item('To reattach: screen -r ${screen_name}')
console.print_item('To stop server: screen -S ${screen_name} -X kill')
console.print_item('The site content is on: ${s.path_src.path}/docs')
// Start the watcher in a separate thread
// mut tf:=spawn watch_docs(docs_path, s.path_src.path, s.path_build.path)
// tf.wait()!
println('\n')
if args.open {
s.open()!
}
if args.watch_changes {
docs_path := '${s.path_src.path}/docs'
watch_docs(docs_path, s.path_src.path, s.path_build.path)!
}
}
// Stream logs from script file to current terminal until user interrupts
fn (mut s DocSite) stream_logs(log_file string, screen_name string) ! {
// Wait a moment for the log file to be created
mut attempts := 0
for !os.exists(log_file) && attempts < 10 {
time.sleep(200 * time.millisecond)
attempts++
}
if !os.exists(log_file) {
console.print_stderr('Warning: Log file not created, falling back to screen attach')
console.print_item('Attaching to screen session... Press Ctrl+A then D to detach')
// Fallback to direct screen attach
osal.execute_interactive('screen -r ${screen_name}')!
return
}
// Use tail -f to stream the log file
// The -f flag follows the file as it grows
tail_cmd := 'tail -f ${log_file}'
// Execute tail in interactive mode - this will stream until Ctrl+C
osal.execute_interactive(tail_cmd) or {
// If tail fails, try alternative approach
console.print_stderr('Log streaming failed, attaching to screen session...')
osal.execute_interactive('screen -r ${screen_name}')!
return
}
// Clean up the log file after streaming
os.rm(log_file) or {}
}
@[params]
pub struct ErrorArgs {
pub mut:

View File

@@ -66,39 +66,4 @@ pub fn (mut site DocSite) generate() ! {
site: website
)!
site.process_imports()!
}
pub fn (mut site DocSite) process_imports() ! {
mut gs := gittools.new()!
mut f := factory_get()!
for item in site.website.siteconfig.imports {
if true {
panic('not implemented import')
}
mypath := gs.get_path(
pull: false
reset: false
url: item.url
)!
mut mypatho := pathlib.get(mypath)
mypatho.copy(dest: '${f.path_build.path}/docs/${item.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',
]
)!
}
}

View File

@@ -0,0 +1,49 @@
module docusaurus
import freeflowuniverse.herolib.osal.screen
import freeflowuniverse.herolib.develop.gittools
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
@[params]
pub struct ImportParams {
path string
git_url string
git_reset bool
git_root string
git_pull bool
}
pub fn (mut site DocSite) import(args ImportParams) ! {
mypath := gittools.get_repo_path(
git_pull: args.git_pull
git_reset: args.git_reset
git_url: args.git_url
path: args.path
)!
println(site)
if true{panic("3456789")}
mut mypatho := pathlib.get(mypath)
// mypatho.copy(dest: '${f.path_build.path}/docs/${item.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',
// ]
// )!
}

View File

@@ -12,76 +12,30 @@ import freeflowuniverse.herolib.osal.core as osal
pub struct AddArgs {
pub mut:
sitename string // needs to exist in web.site module
path string // site of the docusaurus site with the config as is needed to populate the docusaurus site
git_url string
git_reset bool
git_root string
git_pull bool
path_publish string
}
pub fn dsite_add(args_ AddArgs) !&DocSite {
mut args := args_
args.sitename = texttools.name_fix(args_.sitename)
console.print_header('Add Docusaurus Site: ${args.sitename}')
if args.sitename in docusaurus_sites {
return error('Docusaurus site ${args.sitename} already exists, no need to add again.')
}
mut path := gittools.path(
path: args.path
git_url: args.git_url
git_reset: args.git_reset
git_root: args.git_root
git_pull: args.git_pull
currentdir: false
)!
args.path = path.path
if !path.is_dir() {
return error('path is not a directory')
}
if !os.exists('${args.path}/cfg') {
return error('config directory for docusaurus does not exist in ${args.path}/cfg.\n${args}')
}
configpath := '${args.path}/cfg'
if !os.exists(configpath) {
return error("can't find config file for docusaurus in ${configpath}")
}
osal.rm('${args.path}/cfg/main.json')!
osal.rm('${args.path}/cfg/footer.json')!
osal.rm('${args.path}/cfg/navbar.json')!
osal.rm('${args.path}/build.sh')!
osal.rm('${args.path}/develop.sh')!
osal.rm('${args.path}/sync.sh')!
osal.rm('${args.path}/.DS_Store')!
pub fn dsite_define(sitename string) ! {
console.print_header('Add Docusaurus Site: ${sitename}')
mut f := factory_get()!
if args.path_publish == '' {
args.path_publish = '${f.path_publish.path}/${args.sitename}'
}
path_build_ := '${f.path_build.path}/${args.sitename}'
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: args.sitename)!
mut website := site.get(name: sitename)!
// Create the DocSite instance
mut dsite := &DocSite{
name: args.sitename
path_src: pathlib.get_dir(path: args.path, create: false)!
path_publish: pathlib.get_dir(path: args.path_publish, create: true)!
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[args.sitename] = dsite
return dsite
docusaurus_sites[sitename] = dsite
}
pub fn dsite_get(name_ string) !&DocSite {

View File

@@ -1,6 +1,6 @@
module docusaurus
import freeflowuniverse.herolib.core.playbook { PlayBook }
import freeflowuniverse.herolib.core.playbook { PlayBook, Action }
import freeflowuniverse.herolib.web.site
pub fn play(mut plbook PlayBook) ! {
@@ -12,37 +12,39 @@ pub fn play(mut plbook PlayBook) ! {
// This populates the global `site.websites` map.
site.play(mut plbook)!
mut a := plbook.ensure_once(filter: 'docusaurus.define')!
// check if docusaurus.define exists, if not, we create a default factory
mut p2 := a.params
mut f := factory_set(
path_build: p2.get_default('path_build', '')!
path_publish: p2.get_default('path_publish', '')!
reset: p2.get_default_false('reset')
template_update: p2.get_default_false('template_update')
install: p2.get_default_false('install')
)!
a.done = true
mut action_define := plbook.ensure_once(filter: 'docusaurus.define')!
// 3. Process `docusaurus.add` actions to create sites.
for mut action in plbook.find(filter: 'docusaurus.add')! {
mut p := action.params
site_name := p.get('sitename') or {
return error('In docusaurus.add, param "sitename" is required.')
}
mut param_define := action_define.params
dsite_add(
sitename: site_name
mut f := factory_set(
path_build: param_define.get_default('path_build', '')!
path_publish: param_define.get_default('path_publish', '')!
reset: param_define.get_default_false('reset')
template_update: param_define.get_default_false('template_update')
install: param_define.get_default_false('install')
)!
site_name := param_define.get('name') or {
return error('In docusaurus.add, param "name" is required.')
}
dsite_define(site_name)!
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
dsite.importparams << ImportParams{
path: p.get_default('path', '')!
git_url: p.get_default('git_url', '')!
git_reset: p.get_default_false('git_reset')
git_root: p.get_default('git_root', '')!
git_pull: p.get_default_false('git_pull')
path_publish: p.get_default('path_publish', f.path_publish.path)!
)!
}
action.done = true
}
}
mut actions_dev := plbook.find(filter: 'docusaurus.dev')!
if actions_dev.len > 1 {
@@ -50,13 +52,10 @@ pub fn play(mut plbook PlayBook) ! {
}
for mut action in actions_dev {
mut p := action.params
site_name := p.get('site')!
mut dsite := dsite_get(site_name)!
dsite.dev(
host: p.get_default('host', 'localhost')!
port: p.get_int_default('port', 3000)!
open: p.get_default_false('open')
watch_changes: p.get_default_false('watch_changes')
)!
action.done = true
}
@@ -67,8 +66,6 @@ pub fn play(mut plbook PlayBook) ! {
}
for mut action in actions_build {
mut p := action.params
site_name := p.get('site')!
mut dsite := dsite_get(site_name)!
dsite.build()!
action.done = true
}

View File

@@ -1,96 +1,195 @@
module docusaurus
import freeflowuniverse.herolib.osal.notifier
import os
//not longer working because is coming from doctree
fn watch_docs(docs_path string, path_src string, path_build string) ! {
mut n := notifier.new('docsite_watcher') or {
eprintln('Failed to create watcher: ${err}')
return
}
// import freeflowuniverse.herolib.osal.notifier
// import os
n.args['path_src'] = path_src
n.args['path_build'] = path_build
// fn watch_docs(docs_path string, path_src string, path_build string) ! {
// mut n := notifier.new('docsite_watcher') or {
// eprintln('Failed to create watcher: ${err}')
// return
// }
// Add watch with captured args
n.add_watch(docs_path, fn (event notifier.NotifyEvent, path string, args map[string]string) {
handle_file_change(event, path, args) or { eprintln('Error handling file change: ${err}') }
})!
// n.args['path_src'] = path_src
// n.args['path_build'] = path_build
n.start()!
}
// // Add watch with captured args
// n.add_watch(docs_path, fn (event notifier.NotifyEvent, path string, args map[string]string) {
// handle_file_change(event, path, args) or { eprintln('Error handling file change: ${err}') }
// })!
// handle_file_change processes file system events
fn handle_file_change(event notifier.NotifyEvent, path string, args map[string]string) ! {
file_base := os.base(path)
is_dir := os.is_dir(path)
// n.start()!
// }
// Skip files starting with #
if file_base.starts_with('#') {
return
}
// // handle_file_change processes file system events
// fn handle_file_change(event notifier.NotifyEvent, path string, args map[string]string) ! {
// file_base := os.base(path)
// is_dir := os.is_dir(path)
// For files (not directories), check extensions
if !is_dir {
ext := os.file_ext(path).to_lower()
if ext !in ['.md', '.png', '.jpeg', '.jpg'] {
return
}
}
// // Skip files starting with #
// if file_base.starts_with('#') {
// return
// }
// Get relative path from docs directory
rel_path := path.replace('${args['path_src']}/docs/', '')
dest_path := '${args['path_build']}/docs/${rel_path}'
// // For files (not directories), check extensions
// if !is_dir {
// ext := os.file_ext(path).to_lower()
// if ext !in ['.md', '.png', '.jpeg', '.jpg'] {
// return
// }
// }
match event {
.create, .modify {
if is_dir {
// For directories, just ensure they exist
os.mkdir_all(dest_path) or {
return error('Failed to create directory ${dest_path}: ${err}')
}
println('Created directory: ${rel_path}')
} else {
// For files, ensure parent directory exists and copy
os.mkdir_all(os.dir(dest_path)) or {
return error('Failed to create directory ${os.dir(dest_path)}: ${err}')
}
os.cp(path, dest_path) or {
return error('Failed to copy ${path} to ${dest_path}: ${err}')
}
println('Updated: ${rel_path}')
}
}
.delete {
if os.exists(dest_path) {
if is_dir {
os.rmdir_all(dest_path) or {
return error('Failed to delete directory ${dest_path}: ${err}')
}
println('Deleted directory: ${rel_path}')
} else {
os.rm(dest_path) or { return error('Failed to delete ${dest_path}: ${err}') }
println('Deleted: ${rel_path}')
}
}
}
.rename {
// For rename events, fswatch provides the new path in the event
// The old path is already removed, so we just need to handle the new path
if is_dir {
os.mkdir_all(dest_path) or {
return error('Failed to create directory ${dest_path}: ${err}')
}
println('Renamed directory to: ${rel_path}')
} else {
os.mkdir_all(os.dir(dest_path)) or {
return error('Failed to create directory ${os.dir(dest_path)}: ${err}')
}
os.cp(path, dest_path) or {
return error('Failed to copy ${path} to ${dest_path}: ${err}')
}
println('Renamed to: ${rel_path}')
}
}
}
}
// // Get relative path from docs directory
// rel_path := path.replace('${args['path_src']}/docs/', '')
// dest_path := '${args['path_build']}/docs/${rel_path}'
// match event {
// .create, .modify {
// if is_dir {
// // For directories, just ensure they exist
// os.mkdir_all(dest_path) or {
// return error('Failed to create directory ${dest_path}: ${err}')
// }
// println('Created directory: ${rel_path}')
// } else {
// // For files, ensure parent directory exists and copy
// os.mkdir_all(os.dir(dest_path)) or {
// return error('Failed to create directory ${os.dir(dest_path)}: ${err}')
// }
// os.cp(path, dest_path) or {
// return error('Failed to copy ${path} to ${dest_path}: ${err}')
// }
// println('Updated: ${rel_path}')
// }
// }
// .delete {
// if os.exists(dest_path) {
// if is_dir {
// os.rmdir_all(dest_path) or {
// return error('Failed to delete directory ${dest_path}: ${err}')
// }
// println('Deleted directory: ${rel_path}')
// } else {
// os.rm(dest_path) or { return error('Failed to delete ${dest_path}: ${err}') }
// println('Deleted: ${rel_path}')
// }
// }
// }
// .rename {
// // For rename events, fswatch provides the new path in the event
// // The old path is already removed, so we just need to handle the new path
// if is_dir {
// os.mkdir_all(dest_path) or {
// return error('Failed to create directory ${dest_path}: ${err}')
// }
// println('Renamed directory to: ${rel_path}')
// } else {
// os.mkdir_all(os.dir(dest_path)) or {
// return error('Failed to create directory ${os.dir(dest_path)}: ${err}')
// }
// os.cp(path, dest_path) or {
// return error('Failed to copy ${path} to ${dest_path}: ${err}')
// }
// println('Renamed to: ${rel_path}')
// }
// }
// }
// }
// pub fn (mut s DocSite) dev_watch(args DevArgs) ! {
// s.generate()!
// // Create screen session for docusaurus development server
// mut screen_name := 'docusaurus'
// mut sf := screen.new()!
// // Add and start a new screen session
// mut scr := sf.add(
// name: screen_name
// cmd: '/bin/bash'
// start: true
// attach: false
// reset: true
// )!
// // Send commands to the screen session
// console.print_item('To view the server output:: cd ${s.path_build.path}')
// scr.cmd_send('cd ${s.path_build.path}')!
// // Start script recording in the screen session for log streaming
// log_file := '/tmp/docusaurus_${screen_name}.log'
// script_cmd := 'script -f ${log_file}'
// scr.cmd_send(script_cmd)!
// // Small delay to ensure script is ready
// time.sleep(500 * time.millisecond)
// // Start bun in the scripted session
// bun_cmd := 'bun start -p ${args.port} -h ${args.host}'
// scr.cmd_send(bun_cmd)!
// // Stream the log output to current terminal
// console.print_header(' Docusaurus Development Server')
// console.print_item('Streaming server output... Press Ctrl+C to detach and leave server running')
// console.print_item('Server will be available at: http://${args.host}:${args.port}')
// console.print_item('To reattach later: screen -r ${screen_name}')
// println('')
// // Stream logs until user interrupts
// s.stream_logs(log_file, screen_name)!
// // After user interrupts, show final instructions
// console.print_header(' Server Running in Background')
// console.print_item(' Development server is running in background')
// console.print_item('Server URL: http://${args.host}:${args.port}')
// console.print_item('To reattach: screen -r ${screen_name}')
// console.print_item('To stop server: screen -S ${screen_name} -X kill')
// // console.print_item('The site content is on: ${s.path_src.path}/docs')
// // Start the watcher in a separate thread
// // mut tf:=spawn watch_docs(docs_path, s.path_src.path, s.path_build.path)
// // tf.wait()!
// println('\n')
// if args.open {
// s.open()!
// }
// }
// // Stream logs from script file to current terminal until user interrupts
// fn (mut s DocSite) stream_logs(log_file string, screen_name string) ! {
// // Wait a moment for the log file to be created
// mut attempts := 0
// for !os.exists(log_file) && attempts < 10 {
// time.sleep(200 * time.millisecond)
// attempts++
// }
// if !os.exists(log_file) {
// console.print_stderr('Warning: Log file not created, falling back to screen attach')
// console.print_item('Attaching to screen session... Press Ctrl+A then D to detach')
// // Fallback to direct screen attach
// osal.execute_interactive('screen -r ${screen_name}')!
// return
// }
// // Use tail -f to stream the log file
// // The -f flag follows the file as it grows
// tail_cmd := 'tail -f ${log_file}'
// // Execute tail in interactive mode - this will stream until Ctrl+C
// osal.execute_interactive(tail_cmd) or {
// // If tail fails, try alternative approach
// console.print_stderr('Log streaming failed, attaching to screen session...')
// osal.execute_interactive('screen -r ${screen_name}')!
// return
// }
// // Clean up the log file after streaming
// os.rm(log_file) or {}
// }