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
tmux_pane ?&tmux.Pane
crun_config ?&crun.CrunConfig
factory &ContainerFactory
factory &HeroPods
}
// Struct to parse JSON output of `crun state`

View File

@@ -24,7 +24,7 @@ pub:
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 {
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
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
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
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
osal.exec(
cmd: 'podman pull ${docker_url}'

View File

@@ -2,10 +2,8 @@ module heropods
import incubaid.herolib.ui.console
import incubaid.herolib.osal.core as osal
import incubaid.herolib.core.pathlib
import incubaid.herolib.core.texttools
import os
import json
@[heap]
pub struct ContainerImage {
@@ -15,7 +13,7 @@ pub mut:
rootfs_path string // path to the extracted rootfs
size_mb f64 // size in MB
created_at string // creation timestamp
factory &ContainerFactory @[skip; str: skip]
factory &HeroPods @[skip; str: skip]
}
@[params]
@@ -41,7 +39,7 @@ pub mut:
}
// 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)
rootfs_path := '${self.base_dir}/images/${image_name}/rootfs'
@@ -138,7 +136,7 @@ fn (mut self ContainerImage) update_metadata() ! {
}
// List all available images
pub fn (mut self ContainerFactory) images_list() ![]&ContainerImage {
pub fn (mut self HeroPods) images_list() ![]&ContainerImage {
mut images := []&ContainerImage{}
images_base_dir := '${self.base_dir}/images'
@@ -194,7 +192,7 @@ pub fn (mut self ContainerImage) export(args ImageExportArgs) ! {
}
// 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) {
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
import incubaid.herolib.ui.console
import incubaid.herolib.data.encoderhero
import incubaid.herolib.osal.core as osal
import incubaid.herolib.ui.console
import incubaid.herolib.virt.crun
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 ContainerFactory {
pub struct HeroPods {
pub mut:
tmux_session string
containers map[string]&Container
images map[string]&ContainerImage
crun_configs map[string]&crun.CrunConfig
base_dir string
tmux_session string // tmux session name
containers map[string]&Container // name -> container mapping
images map[string]&ContainerImage // name -> image mapping
crun_configs map[string]&crun.CrunConfig // name -> crun config mapping
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]
pub struct FactoryInitArgs {
pub:
reset bool
use_podman bool = true
}
// your checking & initialization code if needed
fn obj_init(mycfg_ HeroPods) !HeroPods {
mut args := mycfg_
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
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(
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
)!
@@ -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
if args.reset {
self.cleanup_crun_state()!
heropods.cleanup_crun_state()!
}
// Load existing images into cache
self.load_existing_images()!
heropods.load_existing_images()!
// Setup default images if not using 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...')
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
fn (mut self ContainerFactory) load_existing_images() ! {
fn (mut self HeroPods) load_existing_images() ! {
images_base_dir := '${self.base_dir}/containers/images'
if !os.is_dir(images_base_dir) {
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 {
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
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 {
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
pub fn (self ContainerFactory) list() ![]Container {
pub fn (self HeroPods) list() ![]Container {
mut containers := []Container{}
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
fn (mut self ContainerFactory) cleanup_crun_state() ! {
fn (mut self HeroPods) cleanup_crun_state() ! {
console.print_debug('Cleaning up leftover crun state...')
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
```