This commit is contained in:
2025-10-13 09:07:40 +04:00
parent b154a91867
commit 3465e36de5
7 changed files with 208 additions and 172 deletions

View File

@@ -4,13 +4,21 @@ import incubaid.herolib.ui.console
import os
import incubaid.herolib.core.pathlib
pub struct GenerateArgs {
pub mut:
path string
reset bool
force bool
name string
}
// will ask questions when not in force mode
// & generate the module
pub fn generate(args_ GeneratorArgs) ! {
pub fn generate(args_ GenerateArgs) ! {
mut myconsole := console.new()
mut args := args_
console.print_header('Generate code for path: ${args.path} (reset:${args.force}, force:${args.force})')
console.print_header('Generate code for path: ${args.path} (reset:${args.reset}, force:${args.force})')
console.print_debug(args)
if args.path == '' {
return error('no path provided')
@@ -73,10 +81,12 @@ pub fn generate(args_ GeneratorArgs) ! {
warning: 'Please select a category'
)!
mut meta := ModuleMeta{}
if mycat == 'installer' {
args.cat = .installer
meta.cat = .installer
} else {
args.cat = .client
meta.cat = .client
}
// if args.name==""{
@@ -86,28 +96,28 @@ pub fn generate(args_ GeneratorArgs) ! {
// }
// }
args.classname = myconsole.ask_question(
meta.classname = myconsole.ask_question(
description: 'Class name of the ${mycat}'
question: 'What is the class name of the generator e.g. MyClass ?'
warning: 'Please provide a valid class name for the generator'
minlen: 4
)!
args.title = myconsole.ask_question(
meta.title = myconsole.ask_question(
description: 'Title of the ${mycat} (optional)'
)!
if args.cat == .installer {
args.hasconfig = myconsole.ask_yesno(
if meta.cat == .installer {
meta.hasconfig = myconsole.ask_yesno(
description: 'Does your installer have a config (normally yes)?'
)!
}
if args.hasconfig {
args.default = myconsole.ask_yesno(
if meta.hasconfig {
meta.default = myconsole.ask_yesno(
description: 'Is it ok when doing new() that a default is created (normally yes)?'
)!
args.singleton = !myconsole.ask_yesno(
meta.singleton = !myconsole.ask_yesno(
description: 'Can there be multiple instances (normally yes)?'
)!
}
@@ -123,16 +133,16 @@ pub fn generate(args_ GeneratorArgs) ! {
// warning: 'Please select one or more platforms'
// )!
if args.cat == .installer {
args.templates = myconsole.ask_yesno(
if meta.cat == .installer {
meta.templates = myconsole.ask_yesno(
description: 'Will there be templates available for your installer?'
)!
args.startupmanager = myconsole.ask_yesno(
meta.startupmanager = myconsole.ask_yesno(
description: 'Is this an installer which will be managed by a startup mananger?'
)!
args.build = myconsole.ask_yesno(
meta.build = myconsole.ask_yesno(
description: 'Are there builders for the installers (compilation)'
)!
}
@@ -141,11 +151,11 @@ pub fn generate(args_ GeneratorArgs) ! {
// description: 'Reset, overwrite code.'
// question: 'This will overwrite all files in your existing dir, be carefule?'
// )!
create_heroscript(args)!
create_heroscript(meta)!
generate_exec(args.path, true)!
}
pub fn create_heroscript(args GeneratorArgs) ! {
pub fn create_heroscript(args ModuleMeta) ! {
mut script := ''
if args.cat == .installer {
script = "
@@ -165,12 +175,11 @@ pub fn create_heroscript(args GeneratorArgs) ! {
}}
title:'${args.title}'
supported_platforms:''
reset:${if args.reset {
startupmanager:${if args.startupmanager {
'1'
} else {
'0'
}}
startupmanager:${if args.startupmanager { '1' } else { '0' }}
hasconfig:${if args.hasconfig {
'1'
} else {
@@ -197,11 +206,7 @@ pub fn create_heroscript(args GeneratorArgs) ! {
} else {
'0'
}}
reset:${if args.reset {
'1'
} else {
'0'
}}"
}"
}
if !os.exists(args.path) {
os.mkdir(args.path)!

View File

@@ -8,12 +8,8 @@ fn generate_exec(path string, reset bool) ! {
mut args := args_get(path)!
console.print_debug('generate code for path: ${path}')
if reset {
args.reset = true
}
mut path_actions := pathlib.get(args.path + '/${args.name}_actions.v')
if args.reset {
if reset {
path_actions.delete()!
}
if !path_actions.exists() && args.cat == .installer {
@@ -27,7 +23,7 @@ fn generate_exec(path string, reset bool) ! {
pathlib.template_write(templ_2, '${args.path}/${args.name}_factory_.v', true)!
mut path_model := pathlib.get(args.path + '/${args.name}_model.v')
if args.reset || !path_model.exists() {
if reset || !path_model.exists() {
console.print_debug('write model.')
mut templ_3 := $tmpl('templates/objname_model.vtemplate')
pathlib.template_write(templ_3, '${args.path}/${args.name}_model.v', true)!
@@ -35,13 +31,13 @@ fn generate_exec(path string, reset bool) ! {
// TODO: check case sensistivity for delete
mut path_readme := pathlib.get(args.path + '/readme.md')
if args.reset || !path_readme.exists() {
if reset || !path_readme.exists() {
mut templ_readme := $tmpl('templates/readme.md')
pathlib.template_write(templ_readme, '${args.path}/readme.md', true)!
}
mut path_templ_dir := pathlib.get_dir(path: args.path + '/templates', create: false)!
if args.reset {
if reset {
path_templ_dir.delete()!
}
@@ -55,7 +51,7 @@ fn generate_exec(path string, reset bool) ! {
osal.execute_silent('v fmt -w ${args.path}')!
}
fn platform_check(args GeneratorArgs) ! {
fn platform_check(args ModuleMeta) ! {
ok := 'osx,ubuntu,arch'
ok2 := ok.split(',')
for i in args.supported_platforms {
@@ -65,7 +61,7 @@ fn platform_check(args GeneratorArgs) ! {
}
}
pub fn (args GeneratorArgs) platform_check_str() string {
pub fn (args ModuleMeta) platform_check_str() string {
mut out := ''
if 'osx' in args.supported_platforms {

View File

@@ -1,88 +0,0 @@
module generic
import incubaid.herolib.core.pathlib
import incubaid.herolib.core.playbook
import incubaid.herolib.ui.console
pub struct GeneratorArgs {
pub mut:
name string
classname string
default bool = true // means user can just get the object and a default will be created
title string
supported_platforms []string // only relevant for installers for now
singleton bool // means there can only be one
templates bool // means we will use templates in the installer, client doesn't do this'
reset bool // regenerate all, dangerous !!!
startupmanager bool = true
build bool
cat Cat
path string
force bool
hasconfig bool = true
playonly bool
play_name string // e.g. docusaurus is what we look for
module_path string // e.g.incubaid.herolib.web.docusaurus
}
pub enum Cat {
installer
client
}
fn args_get(path string) !GeneratorArgs {
console.print_debug('generate code for path: ${path}')
mut config_path := pathlib.get_file(path: '${path}/.heroscript', create: false)!
if !config_path.exists() {
return error("can't find path with .heroscript in ${path}, is a bug")
}
mut plbook := playbook.new(text: config_path.read()!) or {
return error('failed to create playbook: ${err}')
}
mut install_actions := plbook.find(filter: 'hero_code.generate_installer')!
if install_actions.len > 0 {
for install_action in install_actions {
mut p := install_action.params
mut args := GeneratorArgs{
name: p.get('name')!
classname: p.get('classname')!
title: p.get_default('title', '')!
default: p.get_default_true('default')
supported_platforms: p.get_list_default('supported_platforms', [])!
singleton: p.get_default_false('singleton')
templates: p.get_default_false('templates')
reset: p.get_default_false('reset')
startupmanager: p.get_default_true('startupmanager')
hasconfig: p.get_default_true('hasconfig')
build: p.get_default_false('build')
force: p.get_default_false('force')
cat: .installer
path: path
}
return args
}
}
mut client_actions := plbook.find(filter: 'hero_code.generate_client')!
if client_actions.len > 0 {
for client_action in client_actions {
mut p := client_action.params
args := GeneratorArgs{
name: p.get('name')!
classname: p.get('classname')!
title: p.get_default('title', '')!
default: p.get_default_true('default')
singleton: p.get_default_false('singleton')
reset: p.get_default_false('reset')
cat: .client
path: path
}
return args
}
}
return error("can't find hero_code.generate_client or hero_code.generate_installer in ${path}")
}

View File

@@ -0,0 +1,120 @@
module generic
import incubaid.herolib.core.pathlib
import incubaid.herolib.core.playbook
import incubaid.herolib.ui.console
import os
pub struct ModuleMeta {
pub mut:
name string
classname string
default bool = true // means user can just get the object and a default will be created
title string
supported_platforms []string // only relevant for installers for now
singleton bool // means there can only be one
templates bool // means we will use templates in the installer, client doesn't do this'
startupmanager bool = true
build bool
cat Cat
path string
hasconfig bool = true
play_name string // e.g. docusaurus is what we look for
module_path string // e.g.incubaid.herolib.web.docusaurus
}
pub enum Cat {
installer
client
}
fn args_get(path string) !ModuleMeta {
console.print_debug('generate code for path: ${path}')
mut config_path := pathlib.get_file(path: '${path}/.heroscript', create: false)!
if !config_path.exists() {
return error("can't find path with .heroscript in ${path}, is a bug")
}
mut plbook := playbook.new(text: config_path.read()!) or {
return error('failed to create playbook: ${err}')
}
mut install_actions := plbook.find(filter: 'hero_code.generate_installer')!
mut client_actions := plbook.find(filter: 'hero_code.generate_client')!
if install_actions.len > 1 {
return error("found more than one 'hero_code.generate_installer' action in ${path}")
}
if client_actions.len > 1 {
return error("found more than one 'hero_code.generate_client' action in ${path}")
}
if install_actions.len == 1 && client_actions.len == 1 {
return error("found both 'hero_code.generate_installer' and 'hero_code.generate_client' actions in ${path}, can only be one or the other")
}
if install_actions.len == 1 {
mut p := install_actions[0].params
mut name := p.get('name')!
if name == '' {
name = os.base(path)
}
mut args := ModuleMeta{
name: name
classname: p.get('classname')!
title: p.get_default('title', '')!
play_name: p.get_default('play_name', name)!
default: p.get_default_true('default')
supported_platforms: p.get_list_default('supported_platforms', [])!
singleton: p.get_default_false('singleton')
templates: p.get_default_false('templates')
startupmanager: p.get_default_true('startupmanager')
hasconfig: p.get_default_true('hasconfig')
build: p.get_default_false('build')
cat: .installer
path: path
}
args.check()!
return args
}
if client_actions.len == 1 {
mut p := client_actions[0].params
mut name := p.get('name')!
if name == '' {
name = os.base(path)
}
mut args := ModuleMeta{
name: name
classname: p.get('classname')!
title: p.get_default('title', '')!
default: p.get_default_true('default')
singleton: p.get_default_false('singleton')
cat: .client
path: path
play_name: p.get_default('play_name', name)!
}
args.check()!
return args
}
return error("can't find hero_code.generate_client or hero_code.generate_installer in ${path}")
}
fn (mut m ModuleMeta) check() ! {
if m.name == '' {
return error('name cannot be empty')
}
if m.classname == '' {
return error('classname cannot be empty')
}
mut module_path := m.path.replace('/', '.')
if module_path.contains('incubaid.herolib.lib.') {
module_path = module_path.split('incubaid.herolib.lib.')[1]
} else {
return error('path should be inside incubaid.herolib, so that module_path can be determined, now is: ${m.path}')
}
m.module_path = 'incubaid.herolib.${module_path.trim_space()}'
}

View File

@@ -4,15 +4,25 @@ import os
import incubaid.herolib.core.pathlib
import incubaid.herolib.ui.console
// scan over a set of directories call the play where
pub fn scan(args_ GeneratorArgs) ! {
mut args := args_
console.print_header('Scan for generation of code for path: ${args.path} (reset:${args.force}, force:${args.force})')
pub struct ScannerArgs {
pub mut:
path string
generate bool
}
if args.path.len == 0 {
// scan over a set of directories call the play where
pub fn scan(args_ ScannerArgs) ! {
mut args := args_
console.print_header('Scan for generation of code for path: ${args.path} (generate:${args.generate})')
if args.path == '.' {
args.path = os.getwd()
}
if args.path == '' {
args.path = '${os.home_dir()}/code/github/incubaid/herolib/lib'
}
// now walk over all directories, find .heroscript
mut pathroot := pathlib.get_dir(path: args.path, create: false)!
mut plist := pathroot.list(
@@ -22,13 +32,17 @@ pub fn scan(args_ GeneratorArgs) ! {
)!
console.print_debug('Found ${plist.paths.len} directories with .heroscript file.')
for mut p in plist.paths {
pparent := p.parent()!
args.force = true
args.path = pparent.path
generate(args)!
if args.generate && args.path != '' {
return error('when scanning without generation then we always need to start from the root path, so no . or path provided.')
}
mut res := []GeneratorArgs{}
if args.generate {
console.print_debug('Now generating code for all found .heroscript files.')
for mut p in plist.paths {
pparent := p.parent()!
generate(path: pparent.path, force: true)!
}
}
mut res := []ModuleMeta{}
for mut p in plist.paths {
pparent := p.parent()!
res << args_get(pparent.path)!

View File

@@ -31,8 +31,8 @@ pub fn cmd_generator(mut cmdroot Command) {
cmd_run.add_flag(Flag{
flag: .bool
required: false
name: 'playonly'
description: 'generate the play script.'
name: 'generate'
description: 'generate the code only relevant for scanning.'
})
cmd_run.add_flag(Flag{
@@ -58,8 +58,7 @@ fn cmd_generator_execute(cmd Command) ! {
mut force := cmd.flags.get_bool('force') or { false }
mut reset := cmd.flags.get_bool('reset') or { false }
mut scan := cmd.flags.get_bool('scan') or { false }
mut playonly := cmd.flags.get_bool('playonly') or { false }
mut installer := cmd.flags.get_bool('installer') or { false }
mut generate := cmd.flags.get_bool('generate') or { false }
// Get path from required argument
mut path := ''
@@ -68,10 +67,6 @@ fn cmd_generator_execute(cmd Command) ! {
path = cmd.args[0]
}
if playonly {
force = true
}
// Handle "." as current working directory
if path == '.' {
path = os.getwd()
@@ -80,19 +75,13 @@ fn cmd_generator_execute(cmd Command) ! {
path = path.replace('~', os.home_dir())
// Validate that path exists
if !os.exists(path) {
if path != '' && !os.exists(path) {
return error('Path does not exist: ${path}')
}
}
mut cat := generic.Cat.client
if installer {
cat = generic.Cat.installer
}
if scan {
generic.scan(path: path, reset: reset, force: force, cat: cat, playonly: playonly)!
generic.scan(path: path, generate: generate)!
} else {
generic.generate(path: path, reset: reset, force: force, cat: cat)!
generic.generate(path: path, reset: reset, force: force)!
}
}

View File

@@ -79,31 +79,31 @@ pub fn (app &App) api_heroprompt_list(mut ctx Context) veb.Result {
return ctx.text(json.encode(names))
}
@['/api/heroprompt/workspaces'; post]
pub fn (app &App) api_heroprompt_create(mut ctx Context) veb.Result {
name_input := ctx.form['name'] or { '' }
base_path_in := ctx.form['base_path'] or { '' }
if base_path_in.len == 0 {
return ctx.text(json_error('base_path required'))
}
// @['/api/heroprompt/workspaces'; post]
// pub fn (app &App) api_heroprompt_create(mut ctx Context) veb.Result {
// name_input := ctx.form['name'] or { '' }
// base_path_in := ctx.form['base_path'] or { '' }
// if base_path_in.len == 0 {
// return ctx.text(json_error('base_path required'))
// }
base_path := expand_home_path(base_path_in)
// base_path := expand_home_path(base_path_in)
// If no name provided, generate a random name
mut name := name_input.trim(' \t\n\r')
if name.len == 0 {
name = hp.generate_random_workspace_name()
}
// // If no name provided, generate a random name
// mut name := name_input.trim(' \t\n\r')
// if name.len == 0 {
// name = hp.generate_random_workspace_name()
// }
wsp := hp.get(name: name, create: true, path: base_path) or {
return ctx.text(json_error('create failed'))
}
ctx.set_content_type('application/json')
return ctx.text(json.encode({
'name': wsp.name
'base_path': wsp.base_path
}))
}
// wsp := hp.get(name: name, create: true, path: base_path) or {
// return ctx.text(json_error('create failed'))
// }
// ctx.set_content_type('application/json')
// return ctx.text(json.encode({
// 'name': wsp.name
// 'base_path': wsp.base_path
// }))
// }
@['/api/heroprompt/workspaces/:name'; get]
pub fn (app &App) api_heroprompt_get(mut ctx Context, name string) veb.Result {