From 3465e36de529cfab78b1207763e81d7dcd06db36 Mon Sep 17 00:00:00 2001 From: despiegk Date: Mon, 13 Oct 2025 09:07:40 +0400 Subject: [PATCH] ... --- lib/core/generator/generic/generate.v | 53 ++++---- .../generic/generate_installer_client.v | 16 +-- lib/core/generator/generic/model.v | 88 ------------- lib/core/generator/generic/model_meta.v | 120 ++++++++++++++++++ lib/core/generator/generic/scanner.v | 36 ++++-- lib/core/herocmds/generator.v | 23 +--- lib/web/ui/heroprompt_api.v | 44 +++---- 7 files changed, 208 insertions(+), 172 deletions(-) delete mode 100644 lib/core/generator/generic/model.v create mode 100644 lib/core/generator/generic/model_meta.v diff --git a/lib/core/generator/generic/generate.v b/lib/core/generator/generic/generate.v index bc4c052c..02fa98de 100644 --- a/lib/core/generator/generic/generate.v +++ b/lib/core/generator/generic/generate.v @@ -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)! diff --git a/lib/core/generator/generic/generate_installer_client.v b/lib/core/generator/generic/generate_installer_client.v index faf3f4de..7b57c4d5 100644 --- a/lib/core/generator/generic/generate_installer_client.v +++ b/lib/core/generator/generic/generate_installer_client.v @@ -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 { diff --git a/lib/core/generator/generic/model.v b/lib/core/generator/generic/model.v deleted file mode 100644 index 23b82292..00000000 --- a/lib/core/generator/generic/model.v +++ /dev/null @@ -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}") -} diff --git a/lib/core/generator/generic/model_meta.v b/lib/core/generator/generic/model_meta.v new file mode 100644 index 00000000..66c17e77 --- /dev/null +++ b/lib/core/generator/generic/model_meta.v @@ -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()}' +} diff --git a/lib/core/generator/generic/scanner.v b/lib/core/generator/generic/scanner.v index 6985aa18..6c24a30b 100644 --- a/lib/core/generator/generic/scanner.v +++ b/lib/core/generator/generic/scanner.v @@ -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)! diff --git a/lib/core/herocmds/generator.v b/lib/core/herocmds/generator.v index 5cb82b2d..c6befa1f 100644 --- a/lib/core/herocmds/generator.v +++ b/lib/core/herocmds/generator.v @@ -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)! } } diff --git a/lib/web/ui/heroprompt_api.v b/lib/web/ui/heroprompt_api.v index be059f90..438b7462 100644 --- a/lib/web/ui/heroprompt_api.v +++ b/lib/web/ui/heroprompt_api.v @@ -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 {