refactor: Rename ContainerFactory to HeroPods

- Rename ContainerFactory struct to HeroPods
- Update method names and receiver types accordingly
- Adjust imports and internal references
This commit is contained in:
Mahmoud-Emad
2025-11-11 10:08:15 +02:00
parent 759870e01e
commit deb1210405
7 changed files with 239 additions and 41 deletions

View File

@@ -0,0 +1,7 @@
!!hero_code.generate_client
name:''
classname:'HeroPods'
singleton:0
default:1
hasconfig:1

View File

@@ -15,7 +15,7 @@ pub mut:
node ?&builder.Node node ?&builder.Node
tmux_pane ?&tmux.Pane tmux_pane ?&tmux.Pane
crun_config ?&crun.CrunConfig crun_config ?&crun.CrunConfig
factory &ContainerFactory factory &HeroPods
} }
// Struct to parse JSON output of `crun state` // Struct to parse JSON output of `crun state`

View File

@@ -24,7 +24,7 @@ pub:
reset bool reset bool
} }
pub fn (mut self ContainerFactory) new(args ContainerNewArgs) !&Container { pub fn (mut self HeroPods) container_new(args ContainerNewArgs) !&Container {
if args.name in self.containers && !args.reset { if args.name in self.containers && !args.reset {
return self.containers[args.name] or { panic('bug: container should exist') } return self.containers[args.name] or { panic('bug: container should exist') }
} }
@@ -88,7 +88,7 @@ pub fn (mut self ContainerFactory) new(args ContainerNewArgs) !&Container {
} }
// Create crun configuration using the crun module // Create crun configuration using the crun module
fn (mut self ContainerFactory) create_crun_config(container_name string, rootfs_path string) !&crun.CrunConfig { fn (mut self HeroPods) create_crun_config(container_name string, rootfs_path string) !&crun.CrunConfig {
// Create crun configuration using the factory pattern // Create crun configuration using the factory pattern
mut config := crun.new(mut self.crun_configs, name: container_name)! mut config := crun.new(mut self.crun_configs, name: container_name)!
@@ -120,7 +120,7 @@ fn (mut self ContainerFactory) create_crun_config(container_name string, rootfs_
} }
// Use podman to pull image and extract rootfs // Use podman to pull image and extract rootfs
fn (self ContainerFactory) podman_pull_and_export(docker_url string, image_name string, rootfs_path string) ! { fn (self HeroPods) podman_pull_and_export(docker_url string, image_name string, rootfs_path string) ! {
// Pull image // Pull image
osal.exec( osal.exec(
cmd: 'podman pull ${docker_url}' cmd: 'podman pull ${docker_url}'

View File

@@ -2,10 +2,8 @@ module heropods
import incubaid.herolib.ui.console import incubaid.herolib.ui.console
import incubaid.herolib.osal.core as osal import incubaid.herolib.osal.core as osal
import incubaid.herolib.core.pathlib
import incubaid.herolib.core.texttools import incubaid.herolib.core.texttools
import os import os
import json
@[heap] @[heap]
pub struct ContainerImage { pub struct ContainerImage {
@@ -15,7 +13,7 @@ pub mut:
rootfs_path string // path to the extracted rootfs rootfs_path string // path to the extracted rootfs
size_mb f64 // size in MB size_mb f64 // size in MB
created_at string // creation timestamp created_at string // creation timestamp
factory &ContainerFactory @[skip; str: skip] factory &HeroPods @[skip; str: skip]
} }
@[params] @[params]
@@ -41,7 +39,7 @@ pub mut:
} }
// Create new image or get existing // Create new image or get existing
pub fn (mut self ContainerFactory) image_new(args ContainerImageArgs) !&ContainerImage { pub fn (mut self HeroPods) image_new(args ContainerImageArgs) !&ContainerImage {
mut image_name := texttools.name_fix(args.image_name) mut image_name := texttools.name_fix(args.image_name)
rootfs_path := '${self.base_dir}/images/${image_name}/rootfs' rootfs_path := '${self.base_dir}/images/${image_name}/rootfs'
@@ -138,7 +136,7 @@ fn (mut self ContainerImage) update_metadata() ! {
} }
// List all available images // List all available images
pub fn (mut self ContainerFactory) images_list() ![]&ContainerImage { pub fn (mut self HeroPods) images_list() ![]&ContainerImage {
mut images := []&ContainerImage{} mut images := []&ContainerImage{}
images_base_dir := '${self.base_dir}/images' images_base_dir := '${self.base_dir}/images'
@@ -194,7 +192,7 @@ pub fn (mut self ContainerImage) export(args ImageExportArgs) ! {
} }
// Import image from .tgz file // Import image from .tgz file
pub fn (mut self ContainerFactory) image_import(args ImageImportArgs) !&ContainerImage { pub fn (mut self HeroPods) image_import(args ImageImportArgs) !&ContainerImage {
if !os.exists(args.source_path) { if !os.exists(args.source_path) {
return error('Source file not found: ${args.source_path}') return error('Source file not found: ${args.source_path}')
} }

View File

@@ -0,0 +1,143 @@
module heropods
import incubaid.herolib.core.base
import incubaid.herolib.core.playbook { PlayBook }
import json
__global (
heropods_global map[string]&HeroPods
heropods_default string
)
/////////FACTORY
@[params]
pub struct ArgsGet {
pub mut:
name string = 'default' // name of the heropods
fromdb bool // will load from filesystem
create bool // default will not create if not exist
reset bool // will reset the heropods
use_podman bool = true // will use podman for image management
}
pub fn new(args ArgsGet) !&HeroPods {
mut obj := HeroPods{
name: args.name
reset: args.reset
use_podman: args.use_podman
}
set(obj)!
return get(name: args.name)!
}
pub fn get(args ArgsGet) !&HeroPods {
mut context := base.context()!
heropods_default = args.name
if args.fromdb || args.name !in heropods_global {
mut r := context.redis()!
if r.hexists('context:heropods', args.name)! {
data := r.hget('context:heropods', args.name)!
if data.len == 0 {
print_backtrace()
return error('HeroPods with name: ${args.name} does not exist, prob bug.')
}
mut obj := json.decode(HeroPods, data)!
set_in_mem(obj)!
} else {
if args.create {
new(args)!
} else {
print_backtrace()
return error("HeroPods with name '${args.name}' does not exist")
}
}
return get(args)! // no longer from db nor create
}
return heropods_global[args.name] or {
print_backtrace()
return error('could not get config for heropods with name:${args.name}')
}
}
// register the config for the future
pub fn set(o HeroPods) ! {
mut o2 := set_in_mem(o)!
heropods_default = o2.name
mut context := base.context()!
mut r := context.redis()!
r.hset('context:heropods', 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:heropods', args.name)!
}
pub fn delete(args ArgsGet) ! {
mut context := base.context()!
mut r := context.redis()!
r.hdel('context:heropods', 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) ![]&HeroPods {
mut res := []&HeroPods{}
mut context := base.context()!
if args.fromdb {
// reset what is in mem
heropods_global = map[string]&HeroPods{}
heropods_default = ''
}
if args.fromdb {
mut r := context.redis()!
mut l := r.hkeys('context:heropods')!
for name in l {
res << get(name: name, fromdb: true)!
}
return res
} else {
// load from memory
for _, client in heropods_global {
res << client
}
}
return res
}
// only sets in mem, does not set as config
fn set_in_mem(o HeroPods) !HeroPods {
mut o2 := obj_init(o)!
heropods_global[o2.name] = &o2
heropods_default = o2.name
return o2
}
pub fn play(mut plbook PlayBook) ! {
if !plbook.exists(filter: 'heropods.') {
return
}
mut install_actions := plbook.find(filter: 'heropods.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
}
}
}
// switch instance to be used for heropods
pub fn switch(name string) {
heropods_default = name
}

View File

@@ -1,39 +1,39 @@
module heropods module heropods
import incubaid.herolib.ui.console import incubaid.herolib.data.encoderhero
import incubaid.herolib.osal.core as osal import incubaid.herolib.osal.core as osal
import incubaid.herolib.ui.console
import incubaid.herolib.virt.crun import incubaid.herolib.virt.crun
import os 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] @[heap]
pub struct ContainerFactory { pub struct HeroPods {
pub mut: pub mut:
tmux_session string tmux_session string // tmux session name
containers map[string]&Container containers map[string]&Container // name -> container mapping
images map[string]&ContainerImage images map[string]&ContainerImage // name -> image mapping
crun_configs map[string]&crun.CrunConfig crun_configs map[string]&crun.CrunConfig // name -> crun config mapping
base_dir string base_dir string // base directory for all container data
reset bool // will reset the heropods
use_podman bool = true // will use podman for image management
name string // name of the heropods
} }
@[params] // your checking & initialization code if needed
pub struct FactoryInitArgs { fn obj_init(mycfg_ HeroPods) !HeroPods {
pub: mut args := mycfg_
reset bool
use_podman bool = true
}
pub fn new(args FactoryInitArgs) !ContainerFactory {
mut f := ContainerFactory{}
f.init(args)!
return f
}
fn (mut self ContainerFactory) init(args FactoryInitArgs) ! {
// Ensure base directories exist // Ensure base directories exist
self.base_dir = os.getenv_opt('CONTAINERS_DIR') or { os.home_dir() + '/.containers' } args.base_dir = os.getenv_opt('CONTAINERS_DIR') or { os.home_dir() + '/.containers' }
osal.exec( osal.exec(
cmd: 'mkdir -p ${self.base_dir}/images ${self.base_dir}/configs ${self.base_dir}/runtime' cmd: 'mkdir -p ${args.base_dir}/images ${args.base_dir}/configs ${args.base_dir}/runtime'
stdout: false stdout: false
)! )!
@@ -46,21 +46,41 @@ fn (mut self ContainerFactory) init(args FactoryInitArgs) ! {
} }
} }
mut heropods := HeroPods{
tmux_session: args.name
containers: map[string]&Container{}
images: map[string]&ContainerImage{}
crun_configs: map[string]&crun.CrunConfig{}
base_dir: args.base_dir
reset: args.reset
use_podman: args.use_podman
name: args.name
}
// Clean up any leftover crun state if reset is requested // Clean up any leftover crun state if reset is requested
if args.reset { if args.reset {
self.cleanup_crun_state()! heropods.cleanup_crun_state()!
} }
// Load existing images into cache // Load existing images into cache
self.load_existing_images()! heropods.load_existing_images()!
// Setup default images if not using podman // Setup default images if not using podman
if !args.use_podman { if !args.use_podman {
self.setup_default_images(args.reset)! heropods.setup_default_images(args.reset)!
} }
return args
} }
fn (mut self ContainerFactory) setup_default_images(reset bool) ! { /////////////NORMALLY NO NEED TO TOUCH
pub fn heroscript_loads(heroscript string) !HeroPods {
mut obj := encoderhero.decode[HeroPods](heroscript)!
return obj
}
fn (mut self HeroPods) setup_default_images(reset bool) ! {
console.print_header('Setting up default images...') console.print_header('Setting up default images...')
default_images := [ContainerImageType.alpine_3_20, .ubuntu_24_04, .ubuntu_25_04] default_images := [ContainerImageType.alpine_3_20, .ubuntu_24_04, .ubuntu_25_04]
@@ -78,7 +98,7 @@ fn (mut self ContainerFactory) setup_default_images(reset bool) ! {
} }
// Load existing images from filesystem into cache // Load existing images from filesystem into cache
fn (mut self ContainerFactory) load_existing_images() ! { fn (mut self HeroPods) load_existing_images() ! {
images_base_dir := '${self.base_dir}/containers/images' images_base_dir := '${self.base_dir}/containers/images'
if !os.is_dir(images_base_dir) { if !os.is_dir(images_base_dir) {
return return
@@ -106,7 +126,7 @@ fn (mut self ContainerFactory) load_existing_images() ! {
} }
} }
pub fn (mut self ContainerFactory) get(args ContainerNewArgs) !&Container { pub fn (mut self HeroPods) get(args ContainerNewArgs) !&Container {
if args.name !in self.containers { if args.name !in self.containers {
return error('Container "${args.name}" does not exist. Use factory.new() to create it first.') return error('Container "${args.name}" does not exist. Use factory.new() to create it first.')
} }
@@ -114,7 +134,7 @@ pub fn (mut self ContainerFactory) get(args ContainerNewArgs) !&Container {
} }
// Get image by name // Get image by name
pub fn (mut self ContainerFactory) image_get(name string) !&ContainerImage { pub fn (mut self HeroPods) image_get(name string) !&ContainerImage {
if name !in self.images { if name !in self.images {
return error('Image "${name}" not found in cache. Try importing or downloading it.') return error('Image "${name}" not found in cache. Try importing or downloading it.')
} }
@@ -122,7 +142,7 @@ pub fn (mut self ContainerFactory) image_get(name string) !&ContainerImage {
} }
// List all containers currently managed by crun // List all containers currently managed by crun
pub fn (self ContainerFactory) list() ![]Container { pub fn (self HeroPods) list() ![]Container {
mut containers := []Container{} mut containers := []Container{}
result := osal.exec(cmd: 'crun list --format json', stdout: false)! result := osal.exec(cmd: 'crun list --format json', stdout: false)!
@@ -144,7 +164,7 @@ pub fn (self ContainerFactory) list() ![]Container {
} }
// Clean up any leftover crun state // Clean up any leftover crun state
fn (mut self ContainerFactory) cleanup_crun_state() ! { fn (mut self HeroPods) cleanup_crun_state() ! {
console.print_debug('Cleaning up leftover crun state...') console.print_debug('Cleaning up leftover crun state...')
crun_root := '${self.base_dir}/runtime' crun_root := '${self.base_dir}/runtime'

View File

@@ -0,0 +1,30 @@
# heropods
To get started
```v
import incubaid.herolib.clients. heropods
mut client:= heropods.get()!
client...
```
## example heroscript
```hero
!!heropods.configure
secret: '...'
host: 'localhost'
port: 8888
```