diff --git a/cli/hero.v b/cli/hero.v index a11fdc57..903add9d 100644 --- a/cli/hero.v +++ b/cli/hero.v @@ -31,7 +31,7 @@ fn do() ! { mut cmd := Command{ name: 'hero' description: 'Your HERO toolset.' - version: '2.0.5' + version: '2.0.6' } // herocmds.cmd_run_add_flags(mut cmd) diff --git a/examples/clients/mail.vsh b/examples/clients/mail.vsh new file mode 100755 index 00000000..a61074d5 --- /dev/null +++ b/examples/clients/mail.vsh @@ -0,0 +1,24 @@ +#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run + + +import freeflowuniverse.herolib.clients. mailclient + + +//remove the previous one, otherwise the env variables are not read +mailclient.config_delete(name:"test")! + +// env variables which need to be set are: +// - MAIL_FROM=... +// - MAIL_PASSWORD=... +// - MAIL_PORT=465 +// - MAIL_SERVER=... +// - MAIL_USERNAME=... + + +mut client:= mailclient.get(name:"test")! + +println(client) + +client.send(subject:'this is a test',to:'kristof@incubaid.com',body:' + this is my email content + ')! \ No newline at end of file diff --git a/examples/builder/clients/psql.vsh b/examples/clients/psql.vsh similarity index 100% rename from examples/builder/clients/psql.vsh rename to examples/clients/psql.vsh diff --git a/examples/data/heroencoder_simple.vsh b/examples/data/heroencoder_simple.vsh new file mode 100755 index 00000000..c0db981a --- /dev/null +++ b/examples/data/heroencoder_simple.vsh @@ -0,0 +1,30 @@ +#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run + +import freeflowuniverse.herolib.data.encoderhero +import freeflowuniverse.herolib.core.base +import time + +struct Person { +mut: + name string + age int = 20 + birthday time.Time +} + +mut person := Person{ + name: 'Bob' + birthday: time.now() +} +heroscript := encoderhero.encode[Person](person)! + +println(heroscript) + +person2 := encoderhero.decode[Person](heroscript)! +println(person2) + +//show that it doesn't matter which action & method is used +heroscript2:="!!a.b name:Bob age:20 birthday:'2025-02-06 09:57:30'" +person3 := encoderhero.decode[Person](heroscript)! + +println(person3) + diff --git a/examples/data/location/location_example.vsh b/examples/data/location/location_example.vsh index 9e1731a7..94c3f1ba 100755 --- a/examples/data/location/location_example.vsh +++ b/examples/data/location/location_example.vsh @@ -1,9 +1,28 @@ #!/usr/bin/env -S v -n -w -cg -d use_openssl -enable-globals run +import freeflowuniverse.herolib.clients.postgresql_client import freeflowuniverse.herolib.data.location +// Configure PostgreSQL client +heroscript := " +!!postgresql_client.configure + name:'test' + user: 'postgres' + port: 5432 + host: 'localhost' + password: '1234' + dbname: 'postgres' +" + +// Process the heroscript configuration +postgresql_client.play(heroscript: heroscript)! + +// Get the configured client +mut db_client := postgresql_client.get(name: "test")! + + // Create a new location instance -mut loc := location.new(false) or { panic(err) } +mut loc := location.new(mut db_client, false) or { panic(err) } println('Location database initialized') // Initialize the database (downloads and imports data) diff --git a/examples/installers/gitea.vsh b/examples/installers/gitea.vsh index b2ea3eb5..d8df7013 100755 --- a/examples/installers/gitea.vsh +++ b/examples/installers/gitea.vsh @@ -2,33 +2,14 @@ import freeflowuniverse.herolib.installers.infra.gitea as gitea_installer -// First of all, we need to set the gitea configuration -// heroscript := " -// !!gitea.configure -// name:'default' -// version:'1.22.6' -// path: '/var/lib/git' -// passwd: '12345678' -// postgresql_name: 'default' -// mail_from: 'git@meet.tf' -// smtp_addr: 'smtp-relay.brevo.com' -// smtp_login: 'admin' -// smtp_port: 587 -// smtp_passwd: '12345678' -// domain: 'meet.tf' -// jwt_secret: '' -// lfs_jwt_secret: '' -// internal_token: '' -// secret_key: '' -// " -// gitea_installer.play( -// name: 'default' -// heroscript: heroscript -// )! +mut installer:= gitea_installer.get(name:'test')! -// Then we need to get an instace of the installer and call the install -mut gitea := gitea_installer.get()! -// println('gitea configs: ${gitea}') -gitea.install()! -gitea.start()! +//if you want to configure using heroscript +gitea_installer.play(heroscript:" + !!gitea.configure name:test + passwd:'something' + domain: 'docs.info.com' + ")! + +installer.start()! diff --git a/install_hero.sh b/install_hero.sh index d6171019..614434be 100755 --- a/install_hero.sh +++ b/install_hero.sh @@ -17,6 +17,20 @@ else exit 1 fi +# Check for existing hero installations +existing_hero=$(which hero 2>/dev/null || true) +if [ ! -z "$existing_hero" ]; then + echo "Found existing hero installation at: $existing_hero" + if [ -w "$(dirname "$existing_hero")" ]; then + echo "Removing existing hero installation..." + rm "$existing_hero" || { echo "Error: Failed to remove existing hero binary at $existing_hero"; exit 1; } + else + echo "Error: Cannot remove existing hero installation at $existing_hero (permission denied)" + echo "Please remove it manually with sudo and run this script again" + exit 1 + fi +fi + if [[ "${OSNAME}" == "darwin"* ]]; then # Check if /usr/local/bin/hero exists and remove it if [ -f /usr/local/bin/hero ]; then diff --git a/lib/clients/mailclient/mailclient_factory.v b/lib/clients/mailclient/mailclient_factory.v deleted file mode 100644 index 258b0c58..00000000 --- a/lib/clients/mailclient/mailclient_factory.v +++ /dev/null @@ -1,107 +0,0 @@ -module mailclient - -import freeflowuniverse.herolib.core.base -// import freeflowuniverse.herolib.core.playbook - -// __global ( -// mailclient_global map[string]&MailClient -// mailclient_default string -// ) - -// /////////FACTORY - -// @[params] -// pub struct ArgsGet { -// pub mut: -// name string = 'default' -// } - -// fn args_get(args_ ArgsGet) ArgsGet { -// mut args := args_ -// if args.name == '' { -// args.name = mailclient_default -// } -// if args.name == '' { -// args.name = 'default' -// } -// return args -// } - -// pub fn get(args_ ArgsGet) !&MailClient { -// mut args := args_get(args_) -// if args.name !in mailclient_global { -// if !config_exists() { -// if default { -// config_save()! -// } -// } -// config_load()! -// } -// return mailclient_global[args.name] or { panic('bug') } -// } - -// // switch instance to be used for mailclient -// pub fn switch(name string) { -// mailclient_default = name -// } - -fn config_exists(args_ ArgsGet) bool { - mut args := args_get(args_) - mut context := base.context() or { panic('bug') } - return context.hero_config_exists('mailclient', args.name) -} - -// fn config_load(args_ ArgsGet) ! { -// mut args := args_get(args_) -// mut context := base.context()! -// mut heroscript := context.hero_config_get('mailclient', args.name)! -// play(heroscript: heroscript)! -// } - -// fn config_save(args_ ArgsGet) ! { -// mut args := args_get(args_) -// mut context := base.context()! -// context.hero_config_set('mailclient', args.name, heroscript_default())! -// } - -// fn set(o MailClient) ! { -// mut o2 := obj_init(o)! -// mailclient_global['default'] = &o2 -// } - -// @[params] -// pub struct InstallPlayArgs { -// pub mut: -// name string = 'default' -// heroscript string // if filled in then plbook will be made out of it -// plbook ?playbook.PlayBook -// reset bool -// start bool -// stop bool -// restart bool -// delete bool -// configure bool // make sure there is at least one installed -// } - -// pub fn play(args_ InstallPlayArgs) ! { -// mut args := args_ -// println('debguzo1') -// mut plbook := args.plbook or { -// println('debguzo2') -// heroscript := if args.heroscript == '' { -// heroscript_default() -// } else { -// args.heroscript -// } -// playbook.new(text: heroscript)! -// } - -// mut install_actions := plbook.find(filter: 'mailclient.configure')! -// println('debguzo3 ${install_actions}') -// if install_actions.len > 0 { -// for install_action in install_actions { -// mut p := install_action.params -// cfg_play(p)! -// } -// } -// } diff --git a/lib/clients/mailclient/mailclient_factory_.v b/lib/clients/mailclient/mailclient_factory_.v index 489a45fd..c100f937 100644 --- a/lib/clients/mailclient/mailclient_factory_.v +++ b/lib/clients/mailclient/mailclient_factory_.v @@ -1,103 +1,127 @@ + module mailclient import freeflowuniverse.herolib.core.base import freeflowuniverse.herolib.core.playbook import freeflowuniverse.herolib.ui.console -import freeflowuniverse.herolib.data.encoderhero + __global ( - mailclient_global map[string]&MailClient - mailclient_default string + mailclient_global map[string]&MailClient + mailclient_default string ) /////////FACTORY @[params] -pub struct ArgsGet { +pub struct ArgsGet{ pub mut: - name string + name string } -fn args_get(args_ ArgsGet) ArgsGet { - mut model := args_ - if model.name == '' { - model.name = mailclient_default - } - if model.name == '' { - model.name = 'default' - } - return model +fn args_get (args_ ArgsGet) ArgsGet { + mut args:=args_ + if args.name == ""{ + args.name = mailclient_default + } + if args.name == ""{ + args.name = "default" + } + return args } -pub fn get(args_ ArgsGet) !&MailClient { - mut args := args_get(args_) - if args.name !in mailclient_global { - if args.name == 'default' { - if !config_exists(args) { - if default { - mut context := base.context() or { panic('bug') } - context.hero_config_set('mailclient', args.name, heroscript_default())! - } - } - load(args)! - } - } - return mailclient_global[args.name] or { - println(mailclient_global) - panic('could not get config for ${args.name} with name:${args.name}') - } +pub fn get(args_ ArgsGet) !&MailClient { + mut args := args_get(args_) + if !(args.name in mailclient_global) { + if ! config_exists(args){ + config_save(args)! + } + config_load(args)! + } + return mailclient_global[args.name] or { + println(mailclient_global) + //bug if we get here because should be in globals + panic("could not get config for mailclient with name, is bug:${args.name}") + } } -// set the model in mem and the config on the filesystem -pub fn set(o MailClient) ! { - mut o2 := obj_init(o)! - mailclient_global[o.name] = &o2 - mailclient_default = o.name + + +pub fn config_exists(args_ ArgsGet) bool { + mut args := args_get(args_) + mut context:=base.context() or { panic("bug") } + return context.hero_config_exists("mailclient",args.name) } -// check we find the config on the filesystem -pub fn exists(args_ ArgsGet) bool { - mut model := args_get(args_) - mut context := base.context() or { panic('bug') } - return context.hero_config_exists('mailclient', model.name) +pub fn config_load(args_ ArgsGet) ! { + mut args := args_get(args_) + mut context:=base.context()! + mut heroscript := context.hero_config_get("mailclient",args.name)! + play(heroscript:heroscript)! } -// load the config error if it doesn't exist -pub fn load(args_ ArgsGet) ! { - mut model := args_get(args_) - mut context := base.context()! - mut heroscript := context.hero_config_get('mailclient', model.name)! - play(heroscript: heroscript)! +pub fn config_save(args_ ArgsGet) ! { + mut args := args_get(args_) + mut context:=base.context()! + context.hero_config_set("mailclient",args.name,heroscript_default(instance:args.name)!)! +} + + +pub fn config_delete(args_ ArgsGet) ! { + mut args := args_get(args_) + mut context:=base.context()! + context.hero_config_delete("mailclient",args.name)! +} + +fn set(o MailClient)! { + mut o2:=obj_init(o)! + mailclient_global[o.name] = &o2 + mailclient_default = o.name } -// // save the config to the filesystem in the context -// pub fn save(o MailClient) ! { -// mut context := base.context()! -// heroscript := encoderhero.encode[MailClient](o)! -// context.hero_config_set('mailclient', model.name, heroscript)! -// } @[params] pub struct PlayArgs { pub mut: - heroscript string // if filled in then plbook will be made out of it - plbook ?playbook.PlayBook - reset bool + heroscript string //if filled in then plbook will be made out of it + plbook ?playbook.PlayBook + reset bool } pub fn play(args_ PlayArgs) ! { - mut model := args_ + + mut args:=args_ + + if args.heroscript == "" { + args.heroscript = heroscript_default()! + } + mut plbook := args.plbook or { + playbook.new(text: args.heroscript)! + } + + mut install_actions := plbook.find(filter: 'mailclient.configure')! + if install_actions.len > 0 { + for install_action in install_actions { + mut p := install_action.params + cfg_play(p)! + } + } - if model.heroscript == '' { - model.heroscript = heroscript_default() - } - mut plbook := model.plbook or { playbook.new(text: model.heroscript)! } - mut configure_actions := plbook.find(filter: 'mailclient.configure')! - if configure_actions.len > 0 { - for config_action in configure_actions { - mut p := config_action.params - cfg_play(p)! - } - } +} + + + + +//switch instance to be used for mailclient +pub fn switch(name string) { + mailclient_default = name +} + + +//helpers + +@[params] +pub struct DefaultConfigArgs{ + instance string = 'default' } diff --git a/lib/clients/mailclient/mailclient_model.v b/lib/clients/mailclient/mailclient_model.v index 79b4690a..85cde253 100644 --- a/lib/clients/mailclient/mailclient_model.v +++ b/lib/clients/mailclient/mailclient_model.v @@ -1,21 +1,21 @@ module mailclient - import freeflowuniverse.herolib.data.paramsparser import os -pub const version = '1.0.0' +pub const version = '0.0.0' const singleton = false const default = true -pub fn heroscript_default() string { + +pub fn heroscript_default(args DefaultConfigArgs) !string { mail_from := os.getenv_opt('MAIL_FROM') or { 'info@example.com' } mail_password := os.getenv_opt('MAIL_PASSWORD') or { 'secretpassword' } mail_port := (os.getenv_opt('MAIL_PORT') or { '465' }).int() mail_server := os.getenv_opt('MAIL_SERVER') or { 'smtp-relay.brevo.com' } - mail_username := os.getenv_opt('MAIL_USERNAME') or { 'kristof@incubaid.com' } + mail_username := os.getenv_opt('MAIL_USERNAME') or { 'mail@incubaid.com' } heroscript := " -!!mailclient.configure name:'default' +!!mailclient.configure name:'${args.instance}' mail_from: '${mail_from}' mail_password: '${mail_password}' mail_port: ${mail_port} @@ -23,9 +23,10 @@ pub fn heroscript_default() string { mail_username: '${mail_username}' " - return heroscript + return heroscript } +@[heap] pub struct MailClient { pub mut: name string = 'default' @@ -39,31 +40,22 @@ pub mut: } fn cfg_play(p paramsparser.Params) ! { - mut mycfg := MailClient{ + mut mycfg := MailClient{ name: p.get_default('name', 'default')! mail_from: p.get('mail_from')! mail_password: p.get('mail_password')! mail_port: p.get_int_default('mail_port', 465)! mail_server: p.get('mail_server')! mail_username: p.get('mail_username')! - } - set(mycfg)! + } + set(mycfg)! +} + + +fn obj_init(obj_ MailClient)!MailClient{ + mut obj:=obj_ + return obj } -fn obj_init(obj_ MailClient) !MailClient { - // never call get here, only thing we can do here is work on object itself - mut obj := obj_ - return obj -} -// user needs to us switch to make sure we get the right object -pub fn configure(config MailClient) !MailClient { - client := MailClient{ - ...config - } - set(client)! - return client - // THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED - // implement if steps need to be done for configuration -} diff --git a/lib/clients/mailclient/readme.md b/lib/clients/mailclient/readme.md index e98a40f2..b74b212d 100644 --- a/lib/clients/mailclient/readme.md +++ b/lib/clients/mailclient/readme.md @@ -1,16 +1,29 @@ # mailclient - To get started ```vlang -import freeflowuniverse.herolib.clients. mailclient +import freeflowuniverse.herolib.clients.mailclient -mut client:= mailclient.get()! -client.send(subject:'this is a test',to:'kds@something.com,kds2@else.com',body:' +//remove the previous one, otherwise the env variables are not read +mailclient.config_delete(name:"test")! + +// env variables which need to be set are: +// - MAIL_FROM=... +// - MAIL_PASSWORD=... +// - MAIL_PORT=465 +// - MAIL_SERVER=... +// - MAIL_USERNAME=... + + +mut client:= mailclient.get(name:"test")! + +println(client) + +client.send(subject:'this is a test',to:'kristof@incubaid.com',body:' this is my email content ')! diff --git a/lib/clients/postgresql_client/readme.md b/lib/clients/postgresql_client/readme.md index 11cbcc39..054fae0d 100644 --- a/lib/clients/postgresql_client/readme.md +++ b/lib/clients/postgresql_client/readme.md @@ -12,26 +12,49 @@ The PostgreSQL client can be configured using HeroScript. Configuration settings #!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run import freeflowuniverse.herolib.core -import os import freeflowuniverse.herolib.clients.postgresql_client + +// Configure PostgreSQL client heroscript := " !!postgresql_client.configure - name:'test' - user: 'root' - port: 5432 - host: 'localhost' - password: '1234' - dbname: 'postgres' + name:'test' + user: 'postgres' + port: 5432 + host: 'localhost' + password: '1234' + dbname: 'postgres' " -// Process the heroscript -postgresql_client.play(heroscript:heroscript)! +// Process the heroscript configuration +postgresql_client.play(heroscript: heroscript)! // Get the configured client -mut db_client := postgresql_client.get(name:"test")! +mut db_client := postgresql_client.get(name: "test")! + +// Check if test database exists, create if not +if !db_client.db_exists('test')! { + println('Creating database test...') + db_client.db_create('test')! +} + +// Switch to test database +db_client.dbname = 'test' + +// Create table if not exists +create_table_sql := "CREATE TABLE IF NOT EXISTS users ( + id SERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + email VARCHAR(255) UNIQUE NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +)" + +println('Creating table users if not exists...') +db_client.exec(create_table_sql)! + +println('Database and table setup completed successfully!') + -println(db_client) ``` ### Configuration Parameters @@ -94,20 +117,3 @@ db_client.backup(dest: '/path/to/backup/dir')! Backups are created in custom PostgreSQL format (.bak files) which can be restored using pg_restore. -## Default Configuration - -If no configuration is provided, the client uses these default settings: - -```v -heroscript := " -!!postgresql_client.configure - name:'default' - user: 'root' - port: 5432 - host: 'localhost' - password: '' - dbname: 'postgres' -" -``` - -You can override these defaults by providing your own configuration using the HeroScript configure command. diff --git a/lib/core/base/context.v b/lib/core/base/context.v index 8e174752..f0de79cc 100644 --- a/lib/core/base/context.v +++ b/lib/core/base/context.v @@ -138,6 +138,13 @@ pub fn (mut self Context) hero_config_set(cat string, name string, content_ stri config_file.write(content)! } +pub fn (mut self Context) hero_config_delete(cat string, name string) ! { + path := '${self.path()!.path}/${cat}__${name}.yaml' + mut config_file := pathlib.get_file(path: path)! + config_file.delete()! +} + + pub fn (mut self Context) hero_config_exists(cat string, name string) bool { path := '${os.home_dir()}/hero/context/${self.config.name}/${cat}__${name}.yaml' return os.exists(path) diff --git a/lib/core/generator/generic/templates/objname_factory_.vtemplate b/lib/core/generator/generic/templates/objname_factory_.vtemplate index 38c1684a..09f83fdc 100644 --- a/lib/core/generator/generic/templates/objname_factory_.vtemplate +++ b/lib/core/generator/generic/templates/objname_factory_.vtemplate @@ -1,9 +1,9 @@ - module ${args.name} import freeflowuniverse.herolib.core.base import freeflowuniverse.herolib.core.playbook import freeflowuniverse.herolib.ui.console +import freeflowuniverse.herolib.data.paramsparser @if args.cat == .installer import freeflowuniverse.herolib.sysadmin.startupmanager @@ -27,9 +27,6 @@ pub mut: @if args.hasconfig fn args_get (args_ ArgsGet) ArgsGet { mut args:=args_ - if args.name == ""{ - args.name = ${args.name}_default - } if args.name == ""{ args.name = "default" } @@ -37,23 +34,53 @@ fn args_get (args_ ArgsGet) ArgsGet { } pub fn get(args_ ArgsGet) !&${args.classname} { + mut context:=base.context()! mut args := args_get(args_) + mut obj := ${args.classname}{} if !(args.name in ${args.name}_global) { - if args.name=="default"{ - if ! config_exists(args){ - if default{ - config_save(args)! - } - } - config_load(args)! - } + if ! exists(args){ + set(obj)! + }else{ + heroscript := context.hero_config_get("${args.name}",args.name)! + mut obj:=heroscript_loads(heroscript)! + set_in_mem(obj)! + } } - return ${args.name}_global[args.name] or { + return ${args.name}_global[args.name] or { println(${args.name}_global) - panic("could not get config for ${args.name} with name:??{args.name}") + //bug if we get here because should be in globals + panic("could not get config for ${args.name} with name, is bug:??{args.name}") } } +//register the config for the future +pub fn set(o ${args.classname})! { + set_in_mem(o)! + heroscript:=heroscript_dumps(obj)! + context.hero_config_set(${args.name},args.name,heroscript)! +} + +//does the config exists? +pub fn exists(args_ ArgsGet)! { + mut context:=base.context() or { panic("bug") } + return context.hero_config_exists("${args.name}",args.name) +} + +pub fn delete(args_ ArgsGet)! { + mut args := args_get(args_) + mut context:=base.context()! + context.hero_config_delete("${args.name}",args.name)! + if args.name in ${args.name}_global { + //del ${args.name}_global[args.name] + } +} + +//only sets in mem, does not set as config +fn set_in_mem(o ${args.classname})! { + mut o2:=obj_init(o)! + ${args.name}_global[o.name] = &o2 + ${args.name}_default = o.name +} @else pub fn get(args_ ArgsGet) !&${args.classname} { @@ -61,34 +88,6 @@ pub fn get(args_ ArgsGet) !&${args.classname} { } @end -@if args.hasconfig -fn config_exists(args_ ArgsGet) bool { - mut args := args_get(args_) - mut context:=base.context() or { panic("bug") } - return context.hero_config_exists("${args.name}",args.name) -} - -fn config_load(args_ ArgsGet) ! { - mut args := args_get(args_) - mut context:=base.context()! - mut heroscript := context.hero_config_get("${args.name}",args.name)! - play(heroscript:heroscript)! -} - -fn config_save(args_ ArgsGet) ! { - mut args := args_get(args_) - mut context:=base.context()! - context.hero_config_set("${args.name}",args.name,heroscript_default()!)! -} - - -fn set(o ${args.classname})! { - mut o2:=obj_init(o)! - ${args.name}_global[o.name] = &o2 - ${args.name}_default = o.name -} - - ^^[params] pub struct PlayArgs { pub mut: @@ -102,9 +101,7 @@ pub fn play(args_ PlayArgs) ! { mut args:=args_ @if args.hasconfig - if args.heroscript == "" { - args.heroscript = heroscript_default()! - } + @end mut plbook := args.plbook or { playbook.new(text: args.heroscript)! @@ -114,8 +111,9 @@ pub fn play(args_ PlayArgs) ! { mut install_actions := plbook.find(filter: '${args.name}.configure')! if install_actions.len > 0 { for install_action in install_actions { - mut p := install_action.params - cfg_play(p)! + heroscript:=install_action.heroscript() + mut obj2:=heroscript_loads(heroscript)! + set(obj2)! } } @end @@ -161,8 +159,6 @@ pub fn play(args_ PlayArgs) ! { } -@end - @if args.cat == .installer //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -309,3 +305,11 @@ pub fn (mut self ${args.classname}) destroy() ! { pub fn switch(name string) { ${args.name}_default = name } + + +//helpers + +^^[params] +pub struct DefaultConfigArgs{ + instance string = 'default' +} \ No newline at end of file diff --git a/lib/core/generator/generic/templates/objname_model.vtemplate b/lib/core/generator/generic/templates/objname_model.vtemplate index b881274b..5e07144f 100644 --- a/lib/core/generator/generic/templates/objname_model.vtemplate +++ b/lib/core/generator/generic/templates/objname_model.vtemplate @@ -1,47 +1,12 @@ module ${args.name} import freeflowuniverse.herolib.data.paramsparser +import freeflowuniverse.herolib.data.encoderhero import os -pub const version = '1.14.3' +pub const version = '0.0.0' const singleton = ${args.singleton} const default = ${args.default} -@if args.hasconfig -//TODO: THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED IN LINE TO STRUCT BELOW, IS STRUCTURED AS HEROSCRIPT -pub fn heroscript_default() !string { -@if args.cat == .installer - heroscript:=" - !!${args.name}.configure - name:'${args.name}' - homedir: '{HOME}/hero/var/${args.name}' - configpath: '{HOME}/.config/${args.name}/admin.yaml' - username: 'admin' - password: 'secretpassword' - secret: '' - title: 'My Hero DAG' - host: 'localhost' - port: 8888 - - " -@else - heroscript:=" - !!${args.name}.configure - name:'${args.name}' - mail_from: 'info@@example.com' - mail_password: 'secretpassword' - mail_port: 587 - mail_server: 'smtp-relay.brevo.com' - mail_username: 'kristof@@incubaid.com' - - " - -@end - - return heroscript - -} -@end - //THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED @if args.cat == .installer ^^[heap] @@ -53,33 +18,11 @@ pub mut: configpath string username string password string @@[secret] - secret string @@[secret] title string host string port int @end } -@if args.hasconfig -fn cfg_play(p paramsparser.Params) !${args.classname} { - //THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED IN LINE WITH struct above - mut mycfg := ${args.classname}{ - name: p.get_default('name', 'default')! - homedir: p.get_default('homedir', '{HOME}/hero/var/${args.name}')! - configpath: p.get_default('configpath', '{HOME}/hero/var/${args.name}/admin.yaml')! - username: p.get_default('username', 'admin')! - password: p.get_default('password', '')! - secret: p.get_default('secret', '')! - title: p.get_default('title', 'HERO DAG')! - host: p.get_default('host', 'localhost')! - port: p.get_int_default('port', 8888)! - } - - if mycfg.password == '' && mycfg.secret == '' { - return error('password or secret needs to be filled in for ${args.name}') - } - return mycfg -} -@end @else @@ -94,27 +37,16 @@ pub mut: mail_username string } -@if args.hasconfig -fn cfg_play(p paramsparser.Params) ! { - //THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED IN LINE WITH struct above - mut mycfg := ${args.classname}{ - name: p.get_default('name', 'default')! - mail_from: p.get('mail_from')! - mail_password: p.get('mail_password')! - mail_port: p.get_int_default('mail_port', 8888)! - mail_server: p.get('mail_server')! - mail_username: p.get('mail_username')! - } - set(mycfg)! -} @end -@end -fn obj_init(obj_ ${args.classname})!${args.classname}{ - //never call get here, only thing we can do here is work on object itself - mut obj:=obj_ - return obj +//your checking & initialization code if needed +fn obj_init(mycfg_ ${args.classname})!${args.classname}{ + mut mycfg:=mycfg_ + if mycfg.password == '' && mycfg.secret == '' { + return error('password or secret needs to be filled in for ??{mycfg.name}') + } + return mycfg } @if args.cat == .installer @@ -135,3 +67,13 @@ fn configure() ! { @end +/////////////NORMALLY NO NEED TO TOUCH + +pub fn heroscript_dumps(obj ${args.classname}) !string { + return encoderhero.encode[${args.classname} ](obj)! +} + +pub fn heroscript_loads(heroscript string) !${args.classname} { + mut obj := encoderhero.decode[${args.classname}](heroscript)! + return obj +} diff --git a/lib/data/encoderhero/readme.md b/lib/data/encoderhero/readme.md index af10be2c..ffd7a6c7 100644 --- a/lib/data/encoderhero/readme.md +++ b/lib/data/encoderhero/readme.md @@ -1,23 +1,18 @@ # hero Encoder -> encoder hero is based on json2 from https://github.com/vlang/v/blob/master/vlib/x/json2/README.md - -## Usage - -#### encode[T] - ```v -#!/usr/bin/env -S v -n -cg -w -enable-globals run + +#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run import freeflowuniverse.herolib.data.encoderhero +import freeflowuniverse.herolib.core.base import time struct Person { mut: name string - age ?int = 20 + age int = 20 birthday time.Time - deathday ?time.Time } mut person := Person{ @@ -26,44 +21,11 @@ mut person := Person{ } heroscript := encoderhero.encode[Person](person)! -``` +println(heroscript) -#### decode[T] +person2 := encoderhero.decode[Person](heroscript)! -```v -import freeflowuniverse.herolib.data.encoderhero -import time - -struct Person { -mut: - name string - age ?int = 20 - birthday time.Time - deathday ?time.Time -} - -data := ' - -' - -person := encoderhero.decode[Person](data)! -/* -struct Person { - mut: - name "Bob" - age 20 - birthday "2022-03-11 13:54:25" - } -*/ +println(person2) ``` - -## License - -for all original code as used from Alexander: - -// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved. -// Use of this source code is governed by an MIT license -// that can be found in the LICENSE file. - diff --git a/lib/installers/infra/gitea/gitea_actions.v b/lib/installers/infra/gitea/gitea_actions.v index 854015ff..39d03cf8 100644 --- a/lib/installers/infra/gitea/gitea_actions.v +++ b/lib/installers/infra/gitea/gitea_actions.v @@ -2,106 +2,61 @@ module gitea import freeflowuniverse.herolib.osal import freeflowuniverse.herolib.core +import freeflowuniverse.herolib.core.texttools import freeflowuniverse.herolib.ui.console -import freeflowuniverse.herolib.installers.base import freeflowuniverse.herolib.installers.ulist -import freeflowuniverse.herolib.installers.db.postgresql as postgres_installer -import freeflowuniverse.herolib.installers.virt.podman as podman_installer import freeflowuniverse.herolib.osal.zinit import os -const postgres_container_name = 'herocontainer_postgresql' - -// checks if a certain version or above is installed fn installed() !bool { - mut podman := podman_installer.get()! - podman.install()! - - // We need to check also if postgres is installed - mut result := os.execute('podman healthcheck run ${postgres_container_name}') - - if result.exit_code != 0 { - return false - } - - result = os.execute('gitea -v') - - if result.exit_code != 0 { + res := os.execute('${osal.profile_path_source_and()!} gitea version') + if res.exit_code == 0 { + r := res.output.split_into_lines().filter(it.trim_space().len > 0) + if r.len != 1 { + return error("couldn't parse gitea version.\n${res.output}") + } + if texttools.version(version) > texttools.version(r[0]) { + return false + } + } else { return false } return true } -fn install_postgres(cfg GiteaServer) ! { - postgres_heroscript := " -!!postgresql.configure - name: '${cfg.database_name}' - user: '${cfg.database_user}' - password: '${cfg.database_passwd}' - host: '${cfg.database_host}' - port: ${cfg.database_port} - volume_path:'/var/lib/postgresql/data' - container_name: '${postgres_container_name}' -" - - postgres_installer.play(heroscript: postgres_heroscript)! - mut postgres := postgres_installer.get()! - postgres.install()! - postgres.start()! -} - fn install() ! { - if installed()! { - console.print_header('gitea binaraies already installed') - return - } console.print_header('install gitea') - server := get()! + baseurl:="https://github.com/go-gitea/gitea/releases/download/v${version}/gitea-${version}" - // make sure we install base on the node - base.install()! - install_postgres(server)! - - mut download_link := '' - - is_linux_intel := core.is_linux_intel()! - is_osx_arm := core.is_osx_arm()! - - if is_linux_intel { - download_link = 'https://dl.gitea.com/gitea/${server.version}/gitea-${server.version}-linux-amd64' + mut url := '' + if core.is_linux_arm()! { + //https://github.com/go-gitea/gitea/releases/download/v1.23.2/gitea-1.23.2-linux-arm64.xz + url = '${baseurl}-linux-arm64.xz' + } else if core.is_linux_intel()! { + // https://github.com/go-gitea/gitea/releases/download/v1.23.2/gitea-1.23.2-linux-amd64.xz + url = '${baseurl}-linux-amd64.xz' + } else if core.is_osx_arm()! { + //https://github.com/go-gitea/gitea/releases/download/v1.23.2/gitea-1.23.2-darwin-10.12-arm64.xz + url = '${baseurl}-darwin-10.12-arm64.xz' + } else if core.is_osx_intel()! { + //https://github.com/go-gitea/gitea/releases/download/v1.23.2/gitea-1.23.2-darwin-10.12-amd64.xz + url = '${baseurl}-darwin-10.12-amd64.xz' + } else { + return error('unsported platform') } - if is_osx_arm { - download_link = 'https://dl.gitea.com/gitea/${server.version}/gitea-${server.version}-darwin-10.12-amd64' - } + mut dest := osal.download( + url: url + minsize_kb: 9000 + expand_dir: '/tmp/gitea' + )! - if download_link.len == 0 { - return error('unsupported platform') - } - - binary := osal.download( - url: download_link - name: 'gitea' - dest: '/tmp/gitea' - ) or { return error('failed to download gitea due to: ${err}') } - - mut res := os.execute('sudo cp ${binary.path} /usr/local/bin/gitea') - if res.exit_code != 0 { - return error('failed to add gitea to the path due to: ${res.output}') - } - - res = os.execute('sudo chmod +x /usr/local/bin/gitea') - if res.exit_code != 0 { - return error('failed to make gitea executable due to: ${res.output}') - } - - // create config file - file_content := $tmpl('./templates/app.ini') - mut file := os.open_file('/etc/gitea_app.ini', 'w')! - file.write(file_content.bytes())! - - console.print_header('gitea installed properly.') + mut binpath := dest.file_get('gitea')! + osal.cmd_add( + cmdname: 'gitea' + source: binpath.path + )! } fn build() ! { @@ -137,65 +92,79 @@ fn ulist_get() !ulist.UList { fn upload() ! {} fn startupcmd() ![]zinit.ZProcessNewArgs { - mut res := []zinit.ZProcessNewArgs{} - cfg := get()! + + mut cfg := get()! res << zinit.ZProcessNewArgs{ name: 'gitea' - // cmd: 'GITEA_WORK_DIR=${cfg.path} sudo -u git /var/lib/git/gitea web -c /etc/gitea_app.ini' - cmd: ' - -# Variables -GITEA_USER="${cfg.run_user}" -GITEA_HOME="${cfg.path}" -GITEA_BINARY="/usr/local/bin/gitea" -GITEA_CONFIG="/etc/gitea_app.ini" -GITEA_DATA_PATH="\$GITEA_HOME/data" -GITEA_CUSTOM_PATH="\$GITEA_HOME/custom" -GITEA_LOG_PATH="\$GITEA_HOME/log" - -# Ensure the script is run as root -if [[ \$EUID -ne 0 ]]; then - echo "This script must be run as root." - exit 1 -fi - -echo "Setting up Gitea..." - -# Create Gitea user if it doesn\'t exist -if id -u "\$GITEA_USER" &>/dev/null; then - echo "User \$GITEA_USER already exists." -else - echo "Creating Gitea user..." - if ! sudo adduser --system --shell /bin/bash --group --disabled-password --home "/var/lib/\$GITEA_USER" "\$GITEA_USER"; then - echo "Failed to create user \$GITEA_USER." - exit 1 - fi -fi - -# Create necessary directories -echo "Creating directories..." -mkdir -p "\$GITEA_DATA_PATH" "\$GITEA_CUSTOM_PATH" "\$GITEA_LOG_PATH" -chown -R "\$GITEA_USER:\$GITEA_USER" "\$GITEA_HOME" -chmod -R 750 "\$GITEA_HOME" - -chown "\$GITEA_USER:\$GITEA_USER" "\$GITEA_CONFIG" -chmod 640 "\$GITEA_CONFIG" - -GITEA_WORK_DIR=\$GITEA_HOME sudo -u git gitea web -c \$GITEA_CONFIG -' - workdir: cfg.path + cmd: 'gitea server' + env: { + 'HOME ': os.home_dir() + 'GITEA_CONFIG ': cfg.config_path() + } } - res << zinit.ZProcessNewArgs{ - name: 'restart_gitea' - cmd: 'sleep 30 && zinit restart gitea && exit 1' - after: ['gitea'] - oneshot: true - workdir: cfg.path - } - return res + + + +// mut res := []zinit.ZProcessNewArgs{} +// cfg := get()! +// res << zinit.ZProcessNewArgs{ +// name: 'gitea' +// // cmd: 'GITEA_WORK_DIR=${cfg.path} sudo -u git /var/lib/git/gitea web -c /etc/gitea_app.ini' +// cmd: ' + +// # Variables +// GITEA_USER="${cfg.run_user}" +// GITEA_HOME="${cfg.path}" +// GITEA_BINARY="/usr/local/bin/gitea" +// GITEA_CONFIG="/etc/gitea_app.ini" +// GITEA_DATA_PATH="\$GITEA_HOME/data" +// GITEA_CUSTOM_PATH="\$GITEA_HOME/custom" +// GITEA_LOG_PATH="\$GITEA_HOME/log" + +// # Ensure the script is run as root +// if [[ \$EUID -ne 0 ]]; then +// echo "This script must be run as root." +// exit 1 +// fi + +// echo "Setting up Gitea..." + +// # Create Gitea user if it doesn\'t exist +// if id -u "\$GITEA_USER" &>/dev/null; then +// echo "User \$GITEA_USER already exists." +// else +// echo "Creating Gitea user..." +// if ! sudo adduser --system --shell /bin/bash --group --disabled-password --home "/var/lib/\$GITEA_USER" "\$GITEA_USER"; then +// echo "Failed to create user \$GITEA_USER." +// exit 1 +// fi +// fi + +// # Create necessary directories +// echo "Creating directories..." +// mkdir -p "\$GITEA_DATA_PATH" "\$GITEA_CUSTOM_PATH" "\$GITEA_LOG_PATH" +// chown -R "\$GITEA_USER:\$GITEA_USER" "\$GITEA_HOME" +// chmod -R 750 "\$GITEA_HOME" + +// chown "\$GITEA_USER:\$GITEA_USER" "\$GITEA_CONFIG" +// chmod 640 "\$GITEA_CONFIG" + +// GITEA_WORK_DIR=\$GITEA_HOME sudo -u git gitea web -c \$GITEA_CONFIG +// ' +// workdir: cfg.path +// } +// res << zinit.ZProcessNewArgs{ +// name: 'restart_gitea' +// cmd: 'sleep 30 && zinit restart gitea && exit 1' +// after: ['gitea'] +// oneshot: true +// workdir: cfg.path +// } +// return res } fn running() !bool { + //TODO: extend with proper gitea client res := os.execute('curl -fsSL http://localhost:3000 || exit 1') return res.exit_code == 0 } diff --git a/lib/installers/infra/gitea/gitea_factory_.v b/lib/installers/infra/gitea/gitea_factory_.v index 0c0e944b..f89abace 100644 --- a/lib/installers/infra/gitea/gitea_factory_.v +++ b/lib/installers/infra/gitea/gitea_factory_.v @@ -2,239 +2,287 @@ module gitea import freeflowuniverse.herolib.core.base import freeflowuniverse.herolib.core.playbook +import freeflowuniverse.herolib.ui.console +import freeflowuniverse.herolib.data.paramsparser + import freeflowuniverse.herolib.sysadmin.startupmanager import freeflowuniverse.herolib.osal.zinit -import freeflowuniverse.herolib.ui.console import time __global ( - gitea_global map[string]&GiteaServer - gitea_default string + gitea_global map[string]&GiteaServer + gitea_default string ) /////////FACTORY @[params] -pub struct ArgsGet { +pub struct ArgsGet{ pub mut: - name string = 'default' + name string } -fn args_get(args_ ArgsGet) ArgsGet { - mut args := args_ - if args.name == '' { - args.name = gitea_default - } - if args.name == '' { - args.name = 'default' - } - return args +fn args_get (args_ ArgsGet) ArgsGet { + mut args:=args_ + if args.name == ""{ + args.name = "default" + } + return args } -pub fn get(args_ ArgsGet) !&GiteaServer { - mut args := args_get(args_) - if args.name !in gitea_global { - if !config_exists() { - if default { - config_save()! - } - } - config_load()! - } - return gitea_global[args.name] or { - println(gitea_global) - panic('failed to get gitea server for ${args.name}') - } +pub fn get(args_ ArgsGet) !&GiteaServer { + mut context:=base.context()! + mut args := args_get(args_) + mut obj := GiteaServer{} + if !(args.name in gitea_global) { + if ! exists(args){ + set(obj)! + }else{ + heroscript := context.hero_config_get("gitea",args.name)! + mut obj2:=heroscript_loads(heroscript)! + set_in_mem(obj2)! + } + } + return gitea_global[args.name] or { + println(gitea_global) + //bug if we get here because should be in globals + panic("could not get config for gitea with name, is bug:${args.name}") + } } -fn config_exists(args_ ArgsGet) bool { - mut args := args_get(args_) - mut context := base.context() or { panic('bug') } - return context.hero_config_exists('gitea', args.name) +//register the config for the future +pub fn set(o GiteaServer)! { + set_in_mem(o)! + heroscript:=heroscript_dumps(obj)! + context.hero_config_set(gitea,args.name,heroscript)! } -fn config_load(args_ ArgsGet) ! { - mut args := args_get(args_) - mut context := base.context()! - mut heroscript := context.hero_config_get('gitea', args.name)! - play(heroscript: heroscript)! +//does the config exists? +pub fn exists(args_ ArgsGet)! { + mut context:=base.context() or { panic("bug") } + return context.hero_config_exists("gitea",args.name) } -fn config_save(args_ ArgsGet) ! { - mut args := args_get(args_) - mut context := base.context()! - context.hero_config_set('gitea', args.name, heroscript_default()!)! +pub fn delete(args_ ArgsGet)! { + mut args := args_get(args_) + mut context:=base.context()! + context.hero_config_delete("gitea",args.name)! + if args.name in gitea_global { + //del gitea_global[args.name] + } } -fn set(o GiteaServer) ! { - mut o2 := obj_init(o)! - gitea_global['default'] = &o2 +//only sets in mem, does not set as config +fn set_in_mem(o GiteaServer)! { + mut o2:=obj_init(o)! + gitea_global[o.name] = &o2 + gitea_default = o.name } + @[params] pub struct PlayArgs { pub mut: - name string = 'default' - heroscript string // if filled in then plbook will be made out of it - plbook ?playbook.PlayBook - reset bool - - start bool - stop bool - restart bool - delete bool - configure bool // make sure there is at least one installed + heroscript string //if filled in then plbook will be made out of it + plbook ?playbook.PlayBook + reset bool } pub fn play(args_ PlayArgs) ! { - mut args := args_ + + mut args:=args_ - if args.heroscript == '' { - args.heroscript = heroscript_default()! - } - mut plbook := args.plbook or { playbook.new(text: args.heroscript)! } + mut plbook := args.plbook or { + playbook.new(text: args.heroscript)! + } + + mut install_actions := plbook.find(filter: 'gitea.configure')! + if install_actions.len > 0 { + for install_action in install_actions { + heroscript:=install_action.heroscript() + mut obj:=heroscript_loads(heroscript)! + set(obj)! + } + } + + mut other_actions := plbook.find(filter: 'gitea.')! + for other_action in other_actions { + if other_action.name in ["destroy","install","build"]{ + mut p := other_action.params + reset:=p.get_default_false("reset") + if other_action.name == "destroy" || reset{ + console.print_debug("install action gitea.destroy") + destroy()! + } + if other_action.name == "install"{ + console.print_debug("install action gitea.install") + install()! + } + } + if other_action.name in ["start","stop","restart"]{ + mut p := other_action.params + name := p.get('name')! + mut gitea_obj:=get(name:name)! + console.print_debug("action object:\n${gitea_obj}") + if other_action.name == "start"{ + console.print_debug("install action gitea.${other_action.name}") + gitea_obj.start()! + } + + if other_action.name == "stop"{ + console.print_debug("install action gitea.${other_action.name}") + gitea_obj.stop()! + } + if other_action.name == "restart"{ + console.print_debug("install action gitea.${other_action.name}") + gitea_obj.restart()! + } + } + } - mut install_actions := plbook.find(filter: 'gitea.configure')! - if install_actions.len > 0 { - for install_action in install_actions { - mut p := install_action.params - cfg := cfg_play(p)! - set(cfg)! - } - } } + //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////# LIVE CYCLE MANAGEMENT FOR INSTALLERS /////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// fn startupmanager_get(cat zinit.StartupManagerType) !startupmanager.StartupManager { - // unknown - // screen - // zinit - // tmux - // systemd - match cat { - .zinit { - console.print_debug('startupmanager: zinit') - return startupmanager.get(cat: .zinit)! - } - .systemd { - console.print_debug('startupmanager: systemd') - return startupmanager.get(cat: .systemd)! - } - else { - console.print_debug('startupmanager: auto') - return startupmanager.get()! - } - } + // unknown + // screen + // zinit + // tmux + // systemd + match cat{ + .zinit{ + console.print_debug("startupmanager: zinit") + return startupmanager.get(cat:.zinit)! + } + .systemd{ + console.print_debug("startupmanager: systemd") + return startupmanager.get(cat:.systemd)! + }else{ + console.print_debug("startupmanager: auto") + return startupmanager.get()! + } + } } -// load from disk and make sure is properly intialized +//load from disk and make sure is properly intialized pub fn (mut self GiteaServer) reload() ! { - switch(self.name) - self = obj_init(self)! + switch(self.name) + self=obj_init(self)! } pub fn (mut self GiteaServer) start() ! { - switch(self.name) - if self.running()! { - return - } + switch(self.name) + if self.running()!{ + return + } - console.print_header('gitea start') + console.print_header('gitea start') - if !installed()! { - install()! - } + if ! installed()!{ + install()! + } - configure()! + configure()! - start_pre()! + start_pre()! - for zprocess in startupcmd()! { - mut sm := startupmanager_get(zprocess.startuptype)! + for zprocess in startupcmd()!{ + mut sm:=startupmanager_get(zprocess.startuptype)! - console.print_debug('starting gitea with ${zprocess.startuptype}...') + console.print_debug('starting gitea with ${zprocess.startuptype}...') - sm.new(zprocess)! + sm.new(zprocess)! - sm.start(zprocess.name)! - } + sm.start(zprocess.name)! + } - start_post()! + start_post()! + + for _ in 0 .. 50 { + if self.running()! { + return + } + time.sleep(100 * time.millisecond) + } + return error('gitea did not install properly.') - for _ in 0 .. 50 { - if self.running()! { - return - } - time.sleep(100 * time.millisecond) - } - return error('cannot start gitea') } pub fn (mut self GiteaServer) install_start(args InstallArgs) ! { - switch(self.name) - self.install(args)! - self.start()! + switch(self.name) + self.install(args)! + self.start()! } pub fn (mut self GiteaServer) stop() ! { - switch(self.name) - stop_pre()! - for zprocess in startupcmd()! { - mut sm := startupmanager_get(zprocess.startuptype)! - sm.stop(zprocess.name)! - } - stop_post()! + switch(self.name) + stop_pre()! + for zprocess in startupcmd()!{ + mut sm:=startupmanager_get(zprocess.startuptype)! + sm.stop(zprocess.name)! + } + stop_post()! } pub fn (mut self GiteaServer) restart() ! { - switch(self.name) - self.stop()! - self.start()! + switch(self.name) + self.stop()! + self.start()! } pub fn (mut self GiteaServer) running() !bool { - switch(self.name) + switch(self.name) - // walk over the generic processes, if not running return - for zprocess in startupcmd()! { - mut sm := startupmanager_get(zprocess.startuptype)! - r := sm.running(zprocess.name)! - if r == false { - return false - } - } - return running()! + //walk over the generic processes, if not running return + for zprocess in startupcmd()!{ + mut sm:=startupmanager_get(zprocess.startuptype)! + r:=sm.running(zprocess.name)! + if r==false{ + return false + } + } + return running()! } @[params] -pub struct InstallArgs { +pub struct InstallArgs{ pub mut: - reset bool + reset bool } pub fn (mut self GiteaServer) install(args InstallArgs) ! { - switch(self.name) - if args.reset || (!installed()!) { - install()! - } + switch(self.name) + if args.reset || (!installed()!) { + install()! + } } pub fn (mut self GiteaServer) build() ! { - switch(self.name) - build()! + switch(self.name) + build()! } pub fn (mut self GiteaServer) destroy() ! { - switch(self.name) - - self.stop() or {} - destroy()! + switch(self.name) + self.stop() or {} + destroy()! } -// switch instance to be used for gitea + + +//switch instance to be used for gitea pub fn switch(name string) { - gitea_default = name + gitea_default = name +} + + +//helpers + +@[params] +pub struct DefaultConfigArgs{ + instance string = 'default' } diff --git a/lib/installers/infra/gitea/gitea_model.v b/lib/installers/infra/gitea/gitea_model.v index 228ca6dc..34b90ed7 100644 --- a/lib/installers/infra/gitea/gitea_model.v +++ b/lib/installers/infra/gitea/gitea_model.v @@ -1,117 +1,93 @@ module gitea - import freeflowuniverse.herolib.data.paramsparser -import freeflowuniverse.herolib.osal.zinit +import freeflowuniverse.herolib.data.encoderhero import freeflowuniverse.herolib.core.pathlib +import freeflowuniverse.herolib.ui.console +import os +import freeflowuniverse.herolib.clients.mailclient +import freeflowuniverse.herolib.clients.postgresql_client +import rand +pub const version = '0.0.0' const singleton = true -const default = true - -// TODO: THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED IN LINE TO STRUCT BELOW, IS STRUCTURED AS HEROSCRIPT -pub fn heroscript_default() !string { - heroscript := " - !!gitea.configure - name:'gitea' - version:'1.22.6' - run_user: 'git' - path: '/var/lib/git' - passwd: '12345678' - postgresql_name: 'default' - mail_from: 'git@meet.tf' - smtp_addr: 'smtp-relay.brevo.com' - smtp_login: 'admin' - smtp_port: 587 - smtp_passwd: '12345678' - domain: 'meet.tf' - jwt_secret: '' - lfs_jwt_secret: '' - internal_token: '' - secret_key: '' - database_passwd: 'postgres' - database_name: 'postgres' - database_user: 'postgres' - database_host: 'localhost' - database_port: 5432 - " - - return heroscript -} - -// THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED +const default = false +@[heap] pub struct GiteaServer { pub mut: - name string = 'default' - - // reset bool - version string = '1.22.6' - run_user string = 'git' - path string = '/var/lib/git' + name string = 'default' + path string = '${os.home_dir()}/hero/var/gitea' passwd string - mail_from string = 'git@meet.tf' - smtp_addr string = 'smtp-relay.brevo.com' - smtp_login string @[required] - smtp_port int = 587 - smtp_passwd string domain string @[required] - jwt_secret string + jwt_secret string = rand.hex(12) lfs_jwt_secret string internal_token string secret_key string - - // Database config - database_passwd string = 'postgres' - database_name string = 'postgres' - database_user string = 'postgres' - database_host string = 'localhost' - database_port int = 5432 - - process ?zinit.ZProcess - path_config pathlib.Path + postgresql_client_name string = "default" + mail_client_name string = "default" } -fn cfg_play(p paramsparser.Params) !GiteaServer { - // THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED IN LINE WITH struct above - mut mycfg := GiteaServer{ - name: p.get_default('name', 'default')! - version: p.get_default('version', '1.22.6')! - run_user: p.get_default('run_user', 'git')! - path: p.get_default('path', '/var/lib/git')! - passwd: p.get('passwd')! - mail_from: p.get_default('mail_from', 'git@meet.tf')! - smtp_addr: p.get_default('smtp_addr', 'smtp-relay.brevo.com')! - smtp_login: p.get('smtp_login')! - smtp_port: p.get_int_default('smtp_port', 587)! - smtp_passwd: p.get('smtp_passwd')! - domain: p.get('domain')! - jwt_secret: p.get('jwt_secret')! - lfs_jwt_secret: p.get('lfs_jwt_secret')! - internal_token: p.get('internal_token')! - secret_key: p.get('secret_key')! - // Set database config - database_passwd: p.get_default('database_passwd', 'postgres')! - database_name: p.get_default('database_name', 'postgres')! - database_user: p.get_default('database_user', 'postgres')! - database_host: p.get_default('database_host', 'localhost')! - database_port: p.get_int_default('database_port', 5432)! +pub fn (obj GiteaServer) config_path() string { + return '${obj.path}/config.ini' +} + +//your checking & initialization code if needed +fn obj_init(mycfg_ GiteaServer)!GiteaServer{ + mut mycfg:=mycfg_ + return mycfg +} + +//called before start if done +fn configure() ! { + mut server := get()! + + if ! osal.exists("gitea") { + return error('gitea binary not found in path. Please install gitea first.') + } + // Generate and set any missing secrets + if server.lfs_jwt_secret == '' { + server.lfs_jwt_secret = os.execute_opt('gitea generate secret LFS_JWT_SECRET')!.output.trim() + set(server)! + } + if server.internal_token == '' { + server.internal_token = os.execute_opt('gitea generate secret INTERNAL_TOKEN')!.output.trim() + set(server)! + } + if server.secret_key == '' { + server.secret_key = os.execute_opt('gitea generate secret SECRET_KEY')!.output.trim() + set(server)! } - return mycfg + // Initialize required clients with detailed error handling + mut db_client := postgresql_client.get(name: server.postgresql_client_name) or { + return error('Failed to initialize PostgreSQL client "${server.postgresql_client_name}": ${err}') + } + mut mail_client := mailclient.get(name: server.mail_client_name) or { + return error('Failed to initialize mail client "${server.mail_client_name}": ${err}') + } + + //TODO: check database exists + if !db_client.db_exists('gitea_${server.name}')! { + console.print_header('Creating database gitea_${server.name} for gitea.') + db_client.db_create('gitea_${server.name}')! + } + + db_client.dbname = 'gitea_${server.name}' + + mut mycode := $tmpl('templates/app.ini') + mut path := pathlib.get_file(path: server.config_path(), create: true)! + path.write(mycode)! + console.print_debug(mycode) } -fn obj_init(obj_ GiteaServer) !GiteaServer { - // never call get here, only thing we can do here is work on object itself - mut obj := obj_ - return obj +/////////////NORMALLY NO NEED TO TOUCH + +pub fn heroscript_dumps(obj GiteaServer) !string { + return encoderhero.encode[GiteaServer ](obj)! } -// called before start if done -fn configure() ! { - // mut installer := get()! - - // mut mycode := $tmpl('templates/atemplate.yaml') - // mut path := pathlib.get_file(path: cfg.configpath, create: true)! - // path.write(mycode)! - // console.print_debug(mycode) +pub fn heroscript_loads(heroscript string) !GiteaServer { + mut obj := encoderhero.decode[GiteaServer](heroscript)! + return obj } diff --git a/lib/installers/infra/gitea/readme.md b/lib/installers/infra/gitea/readme.md index 23f1646f..9dfb7153 100644 --- a/lib/installers/infra/gitea/readme.md +++ b/lib/installers/infra/gitea/readme.md @@ -6,31 +6,24 @@ To get started ```vlang +import freeflowuniverse.herolib.installers.infra.gitea as gitea_installer -import freeflowuniverse.herolib.installers.something. gitea - -mut installer:= gitea.get()! +//if you want to configure using heroscript +gitea_installer.play(heroscript:' + !!gitea.configure name:test + passwd:'something' + domain: 'docs.info.com' + ')! +mut installer:= gitea_installer.get(name:'test')! installer.start()! - - -``` - -## example heroscript - - -```hero -!!gitea.install - homedir: '/home/user/gitea' - username: 'admin' - password: 'secretpassword' - title: 'Some Title' - host: 'localhost' - port: 8888 - ``` +this will look for a configured mail & postgresql client both on instance name: "default", change in heroscript if needed + +- postgresql_client_name = "default" +- mail_client_name = "default" \ No newline at end of file diff --git a/lib/installers/infra/gitea/templates/app.ini b/lib/installers/infra/gitea/templates/app.ini index c5bfed3a..4b095e70 100644 --- a/lib/installers/infra/gitea/templates/app.ini +++ b/lib/installers/infra/gitea/templates/app.ini @@ -1,6 +1,6 @@ APP_NAME = ${server.name} RUN_MODE = prod -RUN_USER = ${server.run_user} + WORK_PATH = ${server.path} [repository] @@ -26,12 +26,12 @@ LFS_JWT_SECRET = ${server.lfs_jwt_secret} OFFLINE_MODE = false [database] -PATH = ${server.path}/gitea.db +PATH = /tmp/gitea.db DB_TYPE = postgres -HOST = ${server.database_host}:${server.database_port} -NAME = ${server.database_name} -USER = ${server.database_user} -PASSWD = ${server.database_passwd} +HOST = ${db_client.host}:${db_client.port} +NAME = ${db_client.dbname} +USER = ${db_client.user} +PASSWD = ${db_client.password} LOG_SQL = false SCHEMA = SSL_MODE = disable @@ -80,12 +80,12 @@ PATH = ${server.path}/lfs [mailer] ENABLED = true -FROM = ${server.mail_from} +FROM = ${mail_client.from} ; PROTOCOL = smtps -SMTP_ADDR = ${server.smtp_addr} -SMTP_PORT = ${server.smtp_port} -USER = ${server.smtp_login} -PASSWD = ${server.smtp_passwd} +SMTP_ADDR = ${mail_client.server} +SMTP_PORT = ${mail_client.port} +USER = ${mail_client.username} +PASSWD = ${mail_client.password} [openid] ENABLE_OPENID_SIGNIN = true @@ -105,4 +105,3 @@ JWT_SECRET = ${server.jwt_secret} [actions] ENABLED=true -