feat: Add screen installer

- Add a new installer for the `screen` utility.
- This installer supports Ubuntu and macOS.
- Includes functionality for installation, uninstallation,
  and status checking.
- Fixed tests for osal.screen

Co-authored-by: mahmmoud.hassanein <mahmmoud.hassanein@gmail.com>
This commit is contained in:
2025-01-27 16:31:54 +02:00
parent 623f1a289e
commit 0ae8e227fc
8 changed files with 237 additions and 10 deletions

View File

@@ -0,0 +1,13 @@
!!hero_code.generate_installer
name:'screen'
classname:'Screen'
singleton:0
templates:0
default:1
title:''
supported_platforms:''
reset:0
startupmanager:0
hasconfig:0
build:0

View File

@@ -0,0 +1,44 @@
# screen
To get started
```vlang
import freeflowuniverse.herolib.installers.something.screen as screen_installer
heroscript:="
!!screen.configure name:'test'
password: '1234'
port: 7701
!!screen.start name:'test' reset:1
"
screen_installer.play(heroscript=heroscript)!
//or we can call the default and do a start with reset
//mut installer:= screen_installer.get()!
//installer.start(reset:true)!
```
## example heroscript
```hero
!!screen.configure
homedir: '/home/user/screen'
username: 'admin'
password: 'secretpassword'
title: 'Some Title'
host: 'localhost'
port: 8888
```

View File

@@ -0,0 +1,63 @@
module screen
import freeflowuniverse.herolib.core
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.installers.ulist
import os
//////////////////// following actions are not specific to instance of the object
// checks if a certain version or above is installed
fn installed() !bool {
res := os.execute('screen --version')
if res.exit_code != 0 {
return false
}
return true
}
// 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() ! {
}
fn install() ! {
console.print_header('install screen')
if core.is_ubuntu()! {
res := os.execute('sudo apt install screen -y')
if res.exit_code != 0 {
return error('failed to install screen: ${res.output}')
}
} else if core.is_osx()! {
res := os.execute('sudo brew install screen')
if res.exit_code != 0 {
return error('failed to install screen: ${res.output}')
}
} else {
return error('unsupported platform: ${core.platform()!}')
}
}
fn destroy() ! {
console.print_header('uninstall screen')
if core.is_ubuntu()! {
res := os.execute('sudo apt remove screen -y')
if res.exit_code != 0 {
return error('failed to uninstall screen: ${res.output}')
}
} else if core.is_osx()! {
res := os.execute('sudo brew uninstall screen')
if res.exit_code != 0 {
return error('failed to uninstall screen: ${res.output}')
}
} else {
return error('unsupported platform: ${core.platform()!}')
}
}

View File

@@ -0,0 +1,71 @@
module screen
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.sysadmin.startupmanager
import freeflowuniverse.herolib.osal.zinit
__global (
screen_global map[string]&Screen
screen_default string
)
/////////FACTORY
@[params]
pub struct ArgsGet {
pub mut:
name string
}
pub fn get(args_ ArgsGet) !&Screen {
return &Screen{}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////# 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()!
}
}
}
@[params]
pub struct InstallArgs {
pub mut:
reset bool
}
pub fn (mut self Screen) install(args InstallArgs) ! {
switch(self.name)
if args.reset || (!installed()!) {
install()!
}
}
pub fn (mut self Screen) destroy() ! {
switch(self.name)
destroy()!
}
// switch instance to be used for screen
pub fn switch(name string) {
screen_default = name
}

View File

@@ -0,0 +1,22 @@
module screen
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 Screen {
pub mut:
name string = 'default'
}
fn obj_init(obj_ Screen) !Screen {
// never call get here, only thing we can do here is work on object itself
mut obj := obj_
return obj
}
// called before start if done
fn configure() ! {
// mut installer := get()!
}

View File

@@ -31,17 +31,25 @@ pub enum ScreenStatus {
pub fn (self Screen) status() !ScreenStatus { pub fn (self Screen) status() !ScreenStatus {
// Command to list screen sessions // Command to list screen sessions
cmd := 'screen -ls' cmd := 'screen -ls'
response := osal.execute_silent(cmd)!
ls_response := os.execute(cmd)
if ls_response.exit_code != 0 {
if ls_response.output.contains('No Sockets found') {
return .inactive
}
return error('failed to list screen sessions: ${ls_response.output}')
}
// Check if the screen session exists by looking for the session name in the output // Check if the screen session exists by looking for the session name in the output
if !response.contains(self.name) { if !ls_response.output.contains(self.name) {
return .inactive return .inactive
} }
// Command to send a dummy command to the screen session and check response // Command to send a dummy command to the screen session and check response
cmd_check := "screen -S ${self.name} -X eval \"stuff \\\"\\003\\\"; sleep 0.1; stuff \\\"ps\\n\\\"\"" cmd_check := "screen -S ${self.name} -X stuff $'\003' && sleep 0.1 && screen -S ${self.name} -X stuff $'ps\n'"
osal.execute_silent(cmd_check)! osal.execute_silent(cmd_check)!
time.sleep(100 * time.millisecond)
// Command to check if there is an active process in the screen session // Command to check if there is an active process in the screen session
cmd_ps := 'screen -S ${self.name} -X hardcopy -h /tmp/screen_output; cat /tmp/screen_output' cmd_ps := 'screen -S ${self.name} -X hardcopy -h /tmp/screen_output; cat /tmp/screen_output'
ps_response := osal.execute_silent(cmd_ps)! ps_response := osal.execute_silent(cmd_ps)!

View File

@@ -29,11 +29,6 @@ pub fn testsuite_begin() ! {
cleanup_test_screens()! cleanup_test_screens()!
} }
// Cleanup after all tests
pub fn testsuite_end() ! {
cleanup_test_screens()!
}
fn cleanup_test_screens() ! { fn cleanup_test_screens() ! {
mut screen_factory := new(reset: false)! mut screen_factory := new(reset: false)!
screen_factory.scan()! screen_factory.scan()!
@@ -80,6 +75,9 @@ fn create_and_verify_screen(mut screen_factory ScreensFactory, name string, cmd
// Test screen creation and basic status // Test screen creation and basic status
pub fn test_screen_creation() ! { pub fn test_screen_creation() ! {
defer {
cleanup_test_screens() or { panic('failed to cleanup test screens: ${err}') }
}
mut screen_factory := new(reset: false)! mut screen_factory := new(reset: false)!
mut screen := create_and_verify_screen(mut &screen_factory, test_screen_name, '/bin/bash')! mut screen := create_and_verify_screen(mut &screen_factory, test_screen_name, '/bin/bash')!
@@ -90,6 +88,9 @@ pub fn test_screen_creation() ! {
// Test command sending functionality // Test command sending functionality
pub fn test_screen_cmd_send() ! { pub fn test_screen_cmd_send() ! {
defer {
cleanup_test_screens() or { panic('failed to cleanup test screens: ${err}') }
}
mut screen_factory := new(reset: false)! mut screen_factory := new(reset: false)!
mut screen := create_and_verify_screen(mut &screen_factory, test_screen_name, '/bin/bash')! mut screen := create_and_verify_screen(mut &screen_factory, test_screen_name, '/bin/bash')!
@@ -106,6 +107,9 @@ pub fn test_screen_cmd_send() ! {
// Test error cases // Test error cases
pub fn test_screen_errors() ! { pub fn test_screen_errors() ! {
defer {
cleanup_test_screens() or { panic('failed to cleanup test screens: ${err}') }
}
mut screen_factory := new(reset: false)! mut screen_factory := new(reset: false)!
// Test invalid screen name // Test invalid screen name
@@ -127,6 +131,9 @@ pub fn test_screen_errors() ! {
// Test multiple screens // Test multiple screens
pub fn test_multiple_screens() ! { pub fn test_multiple_screens() ! {
defer {
cleanup_test_screens() or { panic('failed to cleanup test screens: ${err}') }
}
mut screen_factory := new(reset: false)! mut screen_factory := new(reset: false)!
screen1_name := '${test_screen_name}_1' screen1_name := '${test_screen_name}_1'

View File

@@ -185,7 +185,6 @@ clients/livekit
' '
tests_error := ' tests_error := '
screen_test.v
tmux_session_test.v tmux_session_test.v
tmux_window_test.v tmux_window_test.v
tmux_test.v tmux_test.v