diff --git a/lib/apps/biz/erpnext/.heroscript b/lib/apps/biz/erpnext/.heroscript new file mode 100644 index 00000000..4ab1f81b --- /dev/null +++ b/lib/apps/biz/erpnext/.heroscript @@ -0,0 +1,12 @@ + +!!hero_code.generate_installer + name:'' + classname:'ERPNext' + singleton:0 + templates:1 + default:1 + title:'' + supported_platforms:'' + startupmanager:1 + hasconfig:1 + build:1 \ No newline at end of file diff --git a/lib/apps/biz/erpnext/erpnext_actions.v b/lib/apps/biz/erpnext/erpnext_actions.v new file mode 100644 index 00000000..517ac373 --- /dev/null +++ b/lib/apps/biz/erpnext/erpnext_actions.v @@ -0,0 +1,187 @@ +module erpnext + +import incubaid.herolib.osal.core as osal +import incubaid.herolib.ui.console +import incubaid.herolib.core.texttools +import incubaid.herolib.core.pathlib +import incubaid.herolib.osal.systemd +import incubaid.herolib.osal.startupmanager +import incubaid.herolib.installers.ulist +import incubaid.herolib.installers.lang.golang +import incubaid.herolib.installers.lang.rust +import incubaid.herolib.installers.lang.python +import os + +fn startupcmd() ![]startupmanager.ZProcessNewArgs { + mut installer := get()! + mut res := []startupmanager.ZProcessNewArgs{} + // THIS IS EXAMPLE CODEAND NEEDS TO BE CHANGED + // res << startupmanager.ZProcessNewArgs{ + // name: 'erpnext' + // cmd: 'erpnext server' + // env: { + // 'HOME': '/root' + // } + // } + + return res +} + +fn running() !bool { + mut installer := get()! + // THIS IS EXAMPLE CODEAND NEEDS TO BE CHANGED + // this checks health of erpnext + // curl http://localhost:3333/api/v1/s --oauth2-bearer 1234 works + // url:='http://127.0.0.1:${cfg.port}/api/v1' + // mut conn := httpconnection.new(name: 'erpnext', url: url)! + + // if cfg.secret.len > 0 { + // conn.default_header.add(.authorization, 'Bearer ${cfg.secret}') + // } + // conn.default_header.add(.content_type, 'application/json') + // console.print_debug("curl -X 'GET' '${url}'/tags --oauth2-bearer ${cfg.secret}") + // r := conn.get_json_dict(prefix: 'tags', debug: false) or {return false} + // println(r) + // if true{panic("ssss")} + // tags := r['Tags'] or { return false } + // console.print_debug(tags) + // console.print_debug('erpnext is answering.') + return false +} + +fn start_pre() ! { +} + +fn start_post() ! { +} + +fn stop_pre() ! { +} + +fn stop_post() ! { +} + +//////////////////// following actions are not specific to instance of the object + +// checks if a certain version or above is installed +fn installed() !bool { + // THIS IS EXAMPLE CODEAND NEEDS TO BE CHANGED + // res := os.execute('${osal.profile_path_source_and()!} erpnext version') + // if res.exit_code != 0 { + // return false + // } + // r := res.output.split_into_lines().filter(it.trim_space().len > 0) + // if r.len != 1 { + // return error("couldn't parse erpnext version.\n${res.output}") + // } + // if texttools.version(version) == texttools.version(r[0]) { + // return true + // } + return false +} + +// get the Upload List of the files +fn ulist_get() !ulist.UList { + // optionally build a UList which is all paths which are result of building, is then used e.g. in upload + return ulist.UList{} +} + +// uploads to S3 server if configured +fn upload() ! { + // installers.upload( + // cmdname: 'erpnext' + // source: '${gitpath}/target/x86_64-unknown-linux-musl/release/erpnext' + // )! +} + +fn install() ! { + console.print_header('install erpnext') + // THIS IS EXAMPLE CODEAND NEEDS TO BE CHANGED + // mut url := '' + // if core.is_linux_arm()! { + // url = 'https://github.com/erpnext-dev/erpnext/releases/download/v${version}/erpnext_${version}_linux_arm64.tar.gz' + // } else if core.is_linux_intel()! { + // url = 'https://github.com/erpnext-dev/erpnext/releases/download/v${version}/erpnext_${version}_linux_amd64.tar.gz' + // } else if core.is_osx_arm()! { + // url = 'https://github.com/erpnext-dev/erpnext/releases/download/v${version}/erpnext_${version}_darwin_arm64.tar.gz' + // } else if osal.is_osx_intel()! { + // url = 'https://github.com/erpnext-dev/erpnext/releases/download/v${version}/erpnext_${version}_darwin_amd64.tar.gz' + // } else { + // return error('unsported platform') + // } + + // mut dest := osal.download( + // url: url + // minsize_kb: 9000 + // expand_dir: '/tmp/erpnext' + // )! + + // //dest.moveup_single_subdir()! + + // mut binpath := dest.file_get('erpnext')! + // osal.cmd_add( + // cmdname: 'erpnext' + // source: binpath.path + // )! +} + +fn build() ! { + // url := 'https://github.com/threefoldtech/erpnext' + + // make sure we install base on the node + // if core.platform() != .ubuntu { + // return error('only support ubuntu for now') + // } + // golang.install()! + + // console.print_header('build erpnext') + + // gitpath := gittools.get_repo(coderoot: '/tmp/builder', url: url, reset: true, pull: true)! + + // cmd := ' + // cd ${gitpath} + // source ~/.cargo/env + // exit 1 #todo + // ' + // osal.execute_stdout(cmd)! + // + // //now copy to the default bin path + // mut binpath := dest.file_get('...')! + // adds it to path + // osal.cmd_add( + // cmdname: 'griddriver2' + // source: binpath.path + // )! +} + +fn destroy() ! { + // mut systemdfactory := systemd.new()! + // systemdfactory.destroy("zinit")! + + // osal.process_kill_recursive(name:'zinit')! + // osal.cmd_delete('zinit')! + + // osal.package_remove(' + // podman + // conmon + // buildah + // skopeo + // runc + // ')! + + // //will remove all paths where go/bin is found + // osal.profile_path_add_remove(paths2delete:"go/bin")! + + // osal.rm(" + // podman + // conmon + // buildah + // skopeo + // runc + // /var/lib/containers + // /var/lib/podman + // /var/lib/buildah + // /tmp/podman + // /tmp/conmon + // ")! +} diff --git a/lib/apps/biz/erpnext/erpnext_factory_.v b/lib/apps/biz/erpnext/erpnext_factory_.v new file mode 100644 index 00000000..c95e2d70 --- /dev/null +++ b/lib/apps/biz/erpnext/erpnext_factory_.v @@ -0,0 +1,312 @@ +module erpnext + +import incubaid.herolib.core.base +import incubaid.herolib.core.playbook { PlayBook } +import incubaid.herolib.ui.console +import json +import incubaid.herolib.osal.startupmanager +import time + +__global ( + erpnext_global map[string]&ERPNext + erpnext_default string +) + +/////////FACTORY + +@[params] +pub struct ArgsGet { +pub mut: + name string = 'default' + fromdb bool // will load from filesystem + create bool // default will not create if not exist +} + +pub fn new(args ArgsGet) !&ERPNext { + mut obj := ERPNext{ + name: args.name + } + set(obj)! + return get(name: args.name)! +} + +pub fn get(args ArgsGet) !&ERPNext { + mut context := base.context()! + erpnext_default = args.name + if args.fromdb || args.name !in erpnext_global { + mut r := context.redis()! + if r.hexists('context:erpnext', args.name)! { + data := r.hget('context:erpnext', args.name)! + if data.len == 0 { + print_backtrace() + return error('ERPNext with name: erpnext does not exist, prob bug.') + } + mut obj := json.decode(ERPNext, data)! + set_in_mem(obj)! + } else { + if args.create { + new(args)! + } else { + print_backtrace() + return error("ERPNext with name 'erpnext' does not exist") + } + } + return get(name: args.name)! // no longer from db nor create + } + return erpnext_global[args.name] or { + print_backtrace() + return error('could not get config for erpnext with name:erpnext') + } +} + +// register the config for the future +pub fn set(o ERPNext) ! { + mut o2 := set_in_mem(o)! + erpnext_default = o2.name + mut context := base.context()! + mut r := context.redis()! + r.hset('context:erpnext', o2.name, json.encode(o2))! +} + +// does the config exists? +pub fn exists(args ArgsGet) !bool { + mut context := base.context()! + mut r := context.redis()! + return r.hexists('context:erpnext', args.name)! +} + +pub fn delete(args ArgsGet) ! { + mut context := base.context()! + mut r := context.redis()! + r.hdel('context:erpnext', args.name)! +} + +@[params] +pub struct ArgsList { +pub mut: + fromdb bool // will load from filesystem +} + +// if fromdb set: load from filesystem, and not from mem, will also reset what is in mem +pub fn list(args ArgsList) ![]&ERPNext { + mut res := []&ERPNext{} + mut context := base.context()! + if args.fromdb { + // reset what is in mem + erpnext_global = map[string]&ERPNext{} + erpnext_default = '' + } + if args.fromdb { + mut r := context.redis()! + mut l := r.hkeys('context:erpnext')! + + for name in l { + res << get(name: name, fromdb: true)! + } + return res + } else { + // load from memory + for _, client in erpnext_global { + res << client + } + } + return res +} + +// only sets in mem, does not set as config +fn set_in_mem(o ERPNext) !ERPNext { + mut o2 := obj_init(o)! + erpnext_global[o2.name] = &o2 + erpnext_default = o2.name + return o2 +} + +pub fn play(mut plbook PlayBook) ! { + if !plbook.exists(filter: 'erpnext.') { + return + } + mut install_actions := plbook.find(filter: 'erpnext.configure')! + if install_actions.len > 0 { + for mut install_action in install_actions { + heroscript := install_action.heroscript() + mut obj2 := heroscript_loads(heroscript)! + set(obj2)! + install_action.done = true + } + } + mut other_actions := plbook.find(filter: 'erpnext.')! + for mut 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 erpnext.destroy') + destroy()! + } + if other_action.name == 'install' { + console.print_debug('install action erpnext.install') + install()! + } + } + if other_action.name in ['start', 'stop', 'restart'] { + mut p := other_action.params + name := p.get('name')! + mut erpnext_obj := get(name: name)! + console.print_debug('action object:\n${erpnext_obj}') + if other_action.name == 'start' { + console.print_debug('install action erpnext.${other_action.name}') + erpnext_obj.start()! + } + + if other_action.name == 'stop' { + console.print_debug('install action erpnext.${other_action.name}') + erpnext_obj.stop()! + } + if other_action.name == 'restart' { + console.print_debug('install action erpnext.${other_action.name}') + erpnext_obj.restart()! + } + } + other_action.done = true + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////# LIVE CYCLE MANAGEMENT FOR INSTALLERS /////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +fn startupmanager_get(cat startupmanager.StartupManagerType) !startupmanager.StartupManager { + // unknown + // screen + // zinit + // tmux + // systemd + match cat { + .screen { + console.print_debug("installer: erpnext' startupmanager get screen") + return startupmanager.get(.screen)! + } + .zinit { + console.print_debug("installer: erpnext' startupmanager get zinit") + return startupmanager.get(.zinit)! + } + .systemd { + console.print_debug("installer: erpnext' startupmanager get systemd") + return startupmanager.get(.systemd)! + } + else { + console.print_debug("installer: erpnext' startupmanager get auto") + return startupmanager.get(.auto)! + } + } +} + +// load from disk and make sure is properly intialized +pub fn (mut self ERPNext) reload() ! { + switch(self.name) + self = obj_init(self)! +} + +pub fn (mut self ERPNext) start() ! { + switch(self.name) + if self.running()! { + return + } + + console.print_header('installer: erpnext start') + + if !installed()! { + install()! + } + + configure()! + + start_pre()! + + for zprocess in startupcmd()! { + mut sm := startupmanager_get(zprocess.startuptype)! + + console.print_debug('installer: erpnext starting with ${zprocess.startuptype}...') + + sm.new(zprocess)! + + sm.start(zprocess.name)! + } + + start_post()! + + for _ in 0 .. 50 { + if self.running()! { + return + } + time.sleep(100 * time.millisecond) + } + return error('erpnext did not install properly.') +} + +pub fn (mut self ERPNext) install_start(args InstallArgs) ! { + switch(self.name) + self.install(args)! + self.start()! +} + +pub fn (mut self ERPNext) stop() ! { + 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 ERPNext) restart() ! { + switch(self.name) + self.stop()! + self.start()! +} + +pub fn (mut self ERPNext) running() !bool { + switch(self.name) + + // walk over the generic processes, if not running return + for zprocess in startupcmd()! { + if zprocess.startuptype != .screen { + mut sm := startupmanager_get(zprocess.startuptype)! + r := sm.running(zprocess.name)! + if r == false { + return false + } + } + } + return running()! +} + +@[params] +pub struct InstallArgs { +pub mut: + reset bool +} + +pub fn (mut self ERPNext) install(args InstallArgs) ! { + switch(self.name) + if args.reset || (!installed()!) { + install()! + } +} + +pub fn (mut self ERPNext) build() ! { + switch(self.name) + build()! +} + +pub fn (mut self ERPNext) destroy() ! { + switch(self.name) + self.stop() or {} + destroy()! +} + +// switch instance to be used for erpnext +pub fn switch(name string) { + erpnext_default = name +} diff --git a/lib/apps/biz/erpnext/erpnext_model.v b/lib/apps/biz/erpnext/erpnext_model.v new file mode 100644 index 00000000..ce466c41 --- /dev/null +++ b/lib/apps/biz/erpnext/erpnext_model.v @@ -0,0 +1,48 @@ +module erpnext + +import incubaid.herolib.data.paramsparser +import incubaid.herolib.data.encoderhero +import os + +pub const version = '0.0.0' +const singleton = false +const default = true + +// THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED +@[heap] +pub struct ERPNext { +pub mut: + name string = 'default' + homedir string + configpath string + username string + password string @[secret] + title string + host string + port int +} + +// your checking & initialization code if needed +fn obj_init(mycfg_ ERPNext) !ERPNext { + mut mycfg := mycfg_ + if mycfg.password == '' && mycfg.secret == '' { + return error('password or secret needs to be filled in for ${mycfg.name}') + } + return mycfg +} + +// 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) +} + +/////////////NORMALLY NO NEED TO TOUCH + +pub fn heroscript_loads(heroscript string) !ERPNext { + mut obj := encoderhero.decode[ERPNext](heroscript)! + return obj +} diff --git a/lib/apps/biz/erpnext/readme.md b/lib/apps/biz/erpnext/readme.md new file mode 100644 index 00000000..3444f6a3 --- /dev/null +++ b/lib/apps/biz/erpnext/readme.md @@ -0,0 +1,44 @@ +# erpnext + + + +To get started + +```v + + +import incubaid.herolib.installers.something.erpnext as erpnext_installer + +heroscript:=" +!!erpnext.configure name:'test' + password: '1234' + port: 7701 + +!!erpnext.start name:'test' reset:1 +" + +erpnext_installer.play(heroscript=heroscript)! + +//or we can call the default and do a start with reset +//mut installer:= erpnext_installer.get()! +//installer.start(reset:true)! + + + + +``` + +## example heroscript + + +```hero +!!erpnext.configure + homedir: '/home/user/erpnext' + username: 'admin' + password: 'secretpassword' + title: 'Some Title' + host: 'localhost' + port: 8888 + +``` + diff --git a/lib/apps/biz/erpnext/templates/atemplate.yaml b/lib/apps/biz/erpnext/templates/atemplate.yaml new file mode 100644 index 00000000..a4c386dd --- /dev/null +++ b/lib/apps/biz/erpnext/templates/atemplate.yaml @@ -0,0 +1,5 @@ + + +name: ${cfg.configpath} + + diff --git a/lib/core/generator/generic/generate.v b/lib/core/generator/generic/generate.v index 843ac4e4..defd790b 100644 --- a/lib/core/generator/generic/generate.v +++ b/lib/core/generator/generic/generate.v @@ -146,17 +146,17 @@ pub fn generate(args_ GenerateArgs) ! { description: 'Are there builders for the installers (compilation)' )! } - - // args.reset = myconsole.ask_yesno( - // description: 'Reset, overwrite code.' - // question: 'This will overwrite all files in your existing dir, be carefule?' - // )! + meta.path = args.path + println(meta) create_heroscript(meta)! generate_exec(args.path, true)! } pub fn create_heroscript(args ModuleMeta) ! { mut script := '' + if args.path == '' { + return error('no path provided to create heroscript') + } if args.cat == .installer { script = " !!hero_code.generate_installer @@ -205,7 +205,7 @@ pub fn create_heroscript(args ModuleMeta) ! { '1' } else { '0' - }} + } }" } if !os.exists(args.path) { diff --git a/lib/ui/uimodel/uimodel.v b/lib/ui/uimodel/uimodel.v index c588eed1..302356aa 100644 --- a/lib/ui/uimodel/uimodel.v +++ b/lib/ui/uimodel/uimodel.v @@ -42,7 +42,7 @@ pub mut: warning string clear bool reset bool - default bool + default bool = true validation fn (string) bool = fn (s string) bool { return true }