diff --git a/aiprompts/herolib_advanced/advanced_paths.md b/aiprompts/herolib_advanced/advanced_paths.md index 630cc717..7f4e50ea 100644 --- a/aiprompts/herolib_advanced/advanced_paths.md +++ b/aiprompts/herolib_advanced/advanced_paths.md @@ -15,7 +15,7 @@ pub struct ListArgs { pub mut: regex []string // A slice of regular expressions to filter files. recursive bool = true // Whether to list files recursively (default true). - ignoredefault bool = true // Whether to ignore files starting with . and _ (default true). + ignore_default bool = true // Whether to ignore files starting with . and _ (default true). include_links bool // Whether to include symbolic links in the list. dirs_only bool // Whether to include only directories in the list. files_only bool // Whether to include only files in the list. @@ -77,7 +77,7 @@ for path_obj in top_level_items.paths { #### 3. Including or Excluding Hidden Files -The `ignoredefault` parameter controls whether files and directories starting with `.` or `_` are ignored. +The `ignore_default` parameter controls whether files and directories starting with `.` or `_` are ignored. ```v import freeflowuniverse.herolib.core.pathlib @@ -86,7 +86,7 @@ mut dir := pathlib.get('/some/directory')! // List all files and directories, including hidden ones mut all_items := dir.list( - ignoredefault: false + ignore_default: false )! for path_obj in all_items.paths { diff --git a/aiprompts/herolib_advanced/osal.md b/aiprompts/herolib_advanced/osal.md index e4d526b0..8ca7a963 100644 --- a/aiprompts/herolib_advanced/osal.md +++ b/aiprompts/herolib_advanced/osal.md @@ -24,13 +24,15 @@ Executes a shell command with extensive configuration. * `work_folder` (string): Working directory. * `environment` (map[string]string): Environment variables. * `stdout` (bool, default: true): Show command output. + * `stdout_log` (bool, default: true): Log stdout to internal buffer. * `raise_error` (bool, default: true): Raise V error on failure. * `ignore_error` (bool): Do not raise error, just report. * `debug` (bool): Enable debug output. * `shell` (bool): Execute in interactive shell. + * `interactive` (bool, default: true): Run in interactive mode. * `async` (bool): Run command asynchronously. * `runtime` (`RunTime` enum): Specify runtime (`.bash`, `.python`, etc.). -* **Returns**: `Job` struct (contains `status`, `output`, `error`, `exit_code`, `start`, `end`). +* **Returns**: `Job` struct (contains `status`, `output`, `error`, `exit_code`, `start`, `end`, `process`, `runnr`). * **Error Handling**: Returns `JobError` with `error_type` (`.exec`, `.timeout`, `.args`). ### `osal.execute_silent(cmd string) !string` @@ -49,7 +51,24 @@ Executes a command and prints output to stdout. * **Returns**: `string` (command output). ### `osal.execute_interactive(cmd string) !` +### `osal.execute_ok(cmd string) bool` +Executes a command and returns `true` if the command exits with a zero status, `false` otherwise. +* **Parameters**: `cmd` (string): The command string. +* **Returns**: `bool`. Executes a command in an interactive shell. +### `osal.exec_fast(cmd: CommandFast) !string` +Executes a command quickly, with options for profile sourcing and environment variables. +* **Parameters**: + * `cmd` (`CommandFast` struct): + * `cmd` (string): The command string. + * `ignore_error` (bool): Do not raise error on non-zero exit code. + * `work_folder` (string): Working directory. + * `environment` (map[string]string): Environment variables. + * `ignore_error_codes` ([]int): List of exit codes to ignore. + * `debug` (bool): Enable debug output. + * `includeprofile` (bool): Source the user's profile before execution. + * `notempty` (bool): Return an error if the output is empty. +* **Returns**: `string` (command output). * **Parameters**: `cmd` (string): The command string. ### `osal.cmd_exists(cmd string) bool` @@ -78,6 +97,18 @@ Checks if a process with a given PID exists. ### `osal.processinfo_with_children(pid int) !ProcessMap` Returns a process and all its child processes. +## 1.1. Done Context Management (`done.v`) + +Functions for managing a "done" context or state using Redis. + +* **`osal.done_set(key string, val string) !`**: Sets a key-value pair in the "done" context. +* **`osal.done_get(key string) ?string`**: Retrieves a value from the "done" context by key. +* **`osal.done_delete(key string) !`**: Deletes a key from the "done" context. +* **`osal.done_get_str(key string) string`**: Retrieves a string value from the "done" context by key (panics on error). +* **`osal.done_get_int(key string) int`**: Retrieves an integer value from the "done" context by key (panics on error). +* **`osal.done_exists(key string) bool`**: Checks if a key exists in the "done" context. +* **`osal.done_print() !`**: Prints all key-value pairs in the "done" context to debug output. +* **`osal.done_reset() !`**: Resets (deletes all keys from) the "done" context. * **Parameters**: `pid` (int): Parent Process ID. * **Returns**: `ProcessMap`. @@ -93,6 +124,10 @@ Kills a process and all its children by name or PID. * `name` (string): Process name. * `pid` (int): Process ID. +### `osal.process_exists_byname(name string) !bool` +Checks if a process with a given name exists. +* **Parameters**: `name` (string): Process name (substring match). +* **Returns**: `bool`. ### `osal.whoami() !string` Returns the current username. * **Returns**: `string`. @@ -102,6 +137,14 @@ Returns the current username. ### `osal.ping(args: PingArgs) !PingResult` Checks host reachability. * **Parameters**: +### `osal.ipaddr_pub_get_check() !string` +Retrieves the public IP address and verifies it is bound to a local interface. +* **Returns**: `string`. + +### `osal.is_ip_on_local_interface(ip string) !bool` +Checks if a given IP address is bound to a local network interface. +* **Parameters**: `ip` (string): IP address to check. +* **Returns**: `bool`. * `args` (`PingArgs` struct): * `address` (string, required): IP address or hostname. * `count` (u8, default: 1): Number of pings. @@ -156,7 +199,17 @@ Deletes and then recreates a directory. Removes files or directories. * **Parameters**: `todelete` (string): Comma or newline separated list of paths (supports `~` for home directory). +### `osal.env_get_all() map[string]string` +Returns all existing environment variables as a map. +* **Returns**: `map[string]string`. ## 4. Environment Variables +## 4.1. Package Management (`package.v`) + +Functions for managing system packages. + +* **`osal.package_refresh() !`**: Updates the package list for the detected platform. +* **`osal.package_install(name_ string) !`**: Installs one or more packages. +* **`osal.package_remove(name_ string) !`**: Removes one or more packages. ### `osal.env_set(args: EnvSet)` Sets an environment variable. @@ -229,6 +282,10 @@ Returns the `~/hero` directory path. Returns `/usr/local` for Linux or `~/hero` for macOS. * **Returns**: `string`. +### `osal.cmd_exists_profile(cmd string) bool` +Checks if a command exists in the system's PATH, considering the user's profile. +* **Parameters**: `cmd` (string): The command name. +* **Returns**: `bool`. ### `osal.profile_path_source() !string` Returns a source statement for the preferred profile file (e.g., `. /home/user/.zprofile`). * **Returns**: `string`. @@ -260,6 +317,37 @@ Lists all possible profile file paths in the OS. * **Returns**: `[]string`. ### `osal.profile_paths_preferred() ![]string` +## 5.1. SSH Key Management (`ssh_key.v`) + +Functions and structs for managing SSH keys. + +### `struct SSHKey` +Represents an SSH key pair. +* **Fields**: `name` (string), `directory` (string). +* **Methods**: + * `public_key_path() !pathlib.Path`: Returns the path to the public key. + * `private_key_path() !pathlib.Path`: Returns the path to the private key. + * `public_key() !string`: Returns the content of the public key. + * `private_key() !string`: Returns the content of the private key. + +### `struct SSHConfig` +Configuration for SSH key operations. +* **Fields**: `directory` (string, default: `~/.ssh`). + +### `osal.get_ssh_key(key_name string, config SSHConfig) ?SSHKey` +Retrieves a specific SSH key by name. +* **Parameters**: `key_name` (string), `config` (`SSHConfig` struct). +* **Returns**: `?SSHKey` (optional SSHKey struct). + +### `osal.list_ssh_keys(config SSHConfig) ![]SSHKey` +Lists all SSH keys in the specified directory. +* **Parameters**: `config` (`SSHConfig` struct). +* **Returns**: `[]SSHKey`. + +### `osal.new_ssh_key(key_name string, config SSHConfig) !SSHKey` +Creates a new SSH key pair. +* **Parameters**: `key_name` (string), `config` (`SSHConfig` struct). +* **Returns**: `SSHKey`. Lists preferred profile file paths based on the operating system. * **Returns**: `[]string`. diff --git a/aiprompts/herolib_core/core_osal.md b/aiprompts/herolib_core/core_osal.md index b09bbc83..f323fbfb 100644 --- a/aiprompts/herolib_core/core_osal.md +++ b/aiprompts/herolib_core/core_osal.md @@ -1,29 +1,27 @@ # OSAL Core Module - Key Capabilities (freeflowuniverse.herolib.osal.core) - ```v //example how to get started import freeflowuniverse.herolib.osal.core as osal -osal.exec(cmd:"ls /")! - +job := osal.exec(cmd: 'ls /')! ``` -this document has info about the most core functions, more detailed info can be found in `aiprompts/herolib_advanced/osal.md` if needed. +This document describes the core functionalities of the Operating System Abstraction Layer (OSAL) module, designed for platform-independent system operations in V. -## Key Functions - -### 1. Process Execution +## 1. Process Execution * **`osal.exec(cmd: Command) !Job`**: Execute a shell command. * **Key Parameters**: `cmd` (string), `timeout` (int), `retry` (int), `work_folder` (string), `environment` (map[string]string), `stdout` (bool), `raise_error` (bool). * **Returns**: `Job` (status, output, error, exit code). * **`osal.execute_silent(cmd string) !string`**: Execute silently, return output. +* **`osal.execute_debug(cmd string) !string`**: Execute with debug output, return output. +* **`osal.execute_stdout(cmd string) !string`**: Execute and print output to stdout, return output. +* **`osal.execute_interactive(cmd string) !`**: Execute in an interactive shell. * **`osal.cmd_exists(cmd string) bool`**: Check if a command exists. -* **`osal.process_kill_recursive(args: ProcessKillArgs) !`**: Kill a process and its children. -### 2. Network Utilities +## 2. Network Utilities * **`osal.ping(args: PingArgs) !PingResult`**: Check host reachability. * **Key Parameters**: `address` (string). @@ -32,32 +30,52 @@ this document has info about the most core functions, more detailed info can be * **Key Parameters**: `address` (string), `port` (int). * **`osal.ipaddr_pub_get() !string`**: Get public IP address. -### 3. File System Operations +## 3. File System Operations * **`osal.file_write(path string, text string) !`**: Write text to a file. * **`osal.file_read(path string) !string`**: Read content from a file. * **`osal.dir_ensure(path string) !`**: Ensure a directory exists. * **`osal.rm(todelete string) !`**: Remove files/directories. -### 4. Environment Variables +## 4. Environment Variables * **`osal.env_set(args: EnvSet)`**: Set an environment variable. * **Key Parameters**: `key` (string), `value` (string). +* **`osal.env_unset(key string)`**: Unset a specific environment variable. +* **`osal.env_unset_all()`**: Unset all environment variables. +* **`osal.env_set_all(args: EnvSetAll)`**: Set multiple environment variables. + * **Key Parameters**: `env` (map[string]string), `clear_before_set` (bool), `overwrite_if_exists` (bool). * **`osal.env_get(key string) !string`**: Get an environment variable's value. +* **`osal.env_exists(key string) !bool`**: Check if an environment variable exists. +* **`osal.env_get_default(key string, def string) string`**: Get an environment variable or a default value. * **`osal.load_env_file(file_path string) !`**: Load variables from a file. -### 5. Command & Profile Management +## 5. Command & Profile Management * **`osal.cmd_add(args: CmdAddArgs) !`**: Add a binary to system paths and update profiles. * **Key Parameters**: `source` (string, required), `cmdname` (string). * **`osal.profile_path_add_remove(args: ProfilePathAddRemoveArgs) !`**: Add/remove paths from profiles. * **Key Parameters**: `paths2add` (string), `paths2delete` (string). -### 6. System Information +## 6. System Information & Utilities +* **`osal.processmap_get() !ProcessMap`**: Get a map of all running processes. +* **`osal.processinfo_get(pid int) !ProcessInfo`**: Get detailed information for a specific process. +* **`osal.processinfo_get_byname(name string) ![]ProcessInfo`**: Get info for processes matching a name. +* **`osal.process_exists(pid int) bool`**: Check if a process exists by PID. +* **`osal.processinfo_with_children(pid int) !ProcessMap`**: Get a process and its children. +* **`osal.processinfo_children(pid int) !ProcessMap`**: Get children of a process. +* **`osal.process_kill_recursive(args: ProcessKillArgs) !`**: Kill a process and its children. + * **Key Parameters**: `name` (string), `pid` (int). +* **`osal.whoami() !string`**: Return the current username. * **`osal.platform() !PlatformType`**: Identify the operating system. * **`osal.cputype() !CPUType`**: Identify the CPU architecture. * **`osal.hostname() !string`**: Get system hostname. - ---- - +* **`osal.sleep(duration int)`**: Pause execution for a specified duration. +* **`osal.download(args: DownloadArgs) !pathlib.Path`**: Download a file from a URL. + * `pathlib.Path` is from `freeflowuniverse.herolib.core.pathlib` + * **Key Parameters**: `url` (string), `dest` (string), `timeout` (int), `retry` (int). +* **`osal.user_exists(username string) bool`**: Check if a user exists. +* **`osal.user_id_get(username string) !int`**: Get user ID. +* **`osal.user_add(args: UserArgs) !int`**: Add a user. + * **Key Parameters**: `name` (string). diff --git a/aiprompts/herolib_advanced/redis.md b/aiprompts/herolib_core/core_redis.md similarity index 100% rename from aiprompts/herolib_advanced/redis.md rename to aiprompts/herolib_core/core_redis.md diff --git a/lib/core/generator/generic/scanner.v b/lib/core/generator/generic/scanner.v index a5bfc717..02510d99 100644 --- a/lib/core/generator/generic/scanner.v +++ b/lib/core/generator/generic/scanner.v @@ -17,7 +17,7 @@ pub fn scan(args_ GeneratorArgs) ! { mut pathroot := pathlib.get_dir(path: args.path, create: false)! mut plist := pathroot.list( recursive: true - ignoredefault: false + ignore_default: false regex: ['.heroscript'] )! diff --git a/lib/core/pathlib/path_list.v b/lib/core/pathlib/path_list.v index 79a00bb1..2057167c 100644 --- a/lib/core/pathlib/path_list.v +++ b/lib/core/pathlib/path_list.v @@ -10,7 +10,7 @@ pub struct ListArgs { pub mut: regex []string recursive bool = true - ignoredefault bool = true // ignore files starting with . and _ + ignore_default bool = true // ignore files starting with . and _ include_links bool // wether to include links in list dirs_only bool files_only bool @@ -31,8 +31,8 @@ pub mut: // params: . // ``` // regex []string -// recursive bool // std off, means we recursive not over dirs by default -// ignoredefault bool = true // ignore files starting with . and _ +// recursive bool = true // default true, means we recursive over dirs by default +// ignore_default bool = true // ignore files starting with . and _ // dirs_only bool // // example see https://github.com/freeflowuniverse/herolib/blob/development/examples/core/pathlib/examples/list/path_list.v @@ -56,7 +56,7 @@ pub fn (mut path Path) list(args_ ListArgs) !PathList { mut args := ListArgsInternal{ regex: r recursive: args_.recursive - ignoredefault: args_.ignoredefault + ignore_default: args_.ignore_default dirs_only: args_.dirs_only files_only: args_.files_only include_links: args_.include_links @@ -74,7 +74,7 @@ pub struct ListArgsInternal { mut: regex []regex.RE // only put files in which follow one of the regexes recursive bool = true - ignoredefault bool = true // ignore files starting with . and _ + ignore_default bool = true // ignore files starting with . and _ dirs_only bool files_only bool include_links bool @@ -108,7 +108,7 @@ fn (mut path Path) list_internal(args ListArgsInternal) ![]Path { if new_path.is_link() && !args.include_links { continue } - if args.ignoredefault { + if args.ignore_default { if item.starts_with('_') || item.starts_with('.') { continue } diff --git a/lib/core/pathlib/path_tools.v b/lib/core/pathlib/path_tools.v index d492ccd7..2bf90a65 100644 --- a/lib/core/pathlib/path_tools.v +++ b/lib/core/pathlib/path_tools.v @@ -222,7 +222,7 @@ pub fn (mut path Path) move(args MoveArgs) ! { // e.g. path is /tmp/rclone and there is /tmp/rclone/rclone-v1.64.2-linux-amd64 . // that last dir needs to move 1 up pub fn (mut path Path) moveup_single_subdir() ! { - mut plist := path.list(recursive: false, ignoredefault: true, dirs_only: true)! + mut plist := path.list(recursive: false, ignore_default: true, dirs_only: true)! // console.print_debug(plist.str()) if plist.paths.len != 1 { return error('could not find one subdir in ${path.path} , so cannot move up') diff --git a/lib/core/pathlib/readme.md b/lib/core/pathlib/readme.md index 9a5f7152..1cfff89f 100644 --- a/lib/core/pathlib/readme.md +++ b/lib/core/pathlib/readme.md @@ -75,7 +75,7 @@ mut pathlist_with_links := dir.list( // Don't ignore hidden files (those starting with . or _) mut pathlist_all := dir.list( - ignoredefault: false + ignore_default: false )! // Access the resulting paths diff --git a/lib/develop/codewalker/codewalker.v b/lib/develop/codewalker/codewalker.v index c739115e..0fb56823 100644 --- a/lib/develop/codewalker/codewalker.v +++ b/lib/develop/codewalker/codewalker.v @@ -38,7 +38,7 @@ fn (mut cw CodeWalker) filemap_get_from_path(path string, content_read bool) !Fi return error('Source directory "${path}" does not exist') } - mut files := dir.list(ignoredefault: false)! + mut files := dir.list(ignore_default: false)! mut fm := FileMap{ source: path } diff --git a/lib/osal/core/ssh.v b/lib/osal/core/ssh.v deleted file mode 100644 index 8839d802..00000000 --- a/lib/osal/core/ssh.v +++ /dev/null @@ -1,86 +0,0 @@ -module core - -import freeflowuniverse.herolib.core.pathlib -import os - -@[params] -pub struct SSHConfig { -pub: - directory string = os.join_path(os.home_dir(), '.ssh') -} - -// Returns a specific SSH key with the given name from the default SSH directory (~/.ssh) -pub fn get_ssh_key(key_name string, config SSHConfig) ?SSHKey { - mut ssh_dir := pathlib.get_dir(path: config.directory) or { return none } - - list := ssh_dir.list(files_only: true) or { return none } - for file in list.paths { - if file.name() == key_name { - return SSHKey{ - name: file.name() - directory: ssh_dir.path - } - } - } - - return none -} - -// Lists SSH keys in the default SSH directory (~/.ssh) and returns an array of SSHKey structs -fn list_ssh_keys(config SSHConfig) ![]SSHKey { - mut ssh_dir := pathlib.get_dir(path: config.directory) or { - return error('Error getting ssh directory: ${err}') - } - - mut keys := []SSHKey{} - list := ssh_dir.list(files_only: true) or { - return error('Failed to list files in SSH directory') - } - - for file in list.paths { - if file.extension() == 'pub' || file.name().starts_with('id_') { - keys << SSHKey{ - name: file.name() - directory: ssh_dir.path - } - } - } - - return keys -} - -// Creates a new SSH key pair to the specified directory -pub fn new_ssh_key(key_name string, config SSHConfig) !SSHKey { - ssh_dir := pathlib.get_dir( - path: config.directory - create: true - ) or { return error('Error getting SSH directory: ${err}') } - - // Paths for the private and public keys - priv_key_path := os.join_path(ssh_dir.path, key_name) - pub_key_path := '${priv_key_path}.pub' - - // Check if the key already exists - if os.exists(priv_key_path) || os.exists(pub_key_path) { - return error("Key pair already exists with the name '${key_name}'") - } - - panic('implement shhkeygen logic') - // Generate a random private key (for demonstration purposes) - // Replace this with actual key generation logic (e.g., calling `ssh-keygen` or similar) - // private_key_content := '-----BEGIN PRIVATE KEY-----\n${rand.string(64)}\n-----END PRIVATE KEY-----' - // public_key_content := 'ssh-rsa ${rand.string(64)} user@host' - - // Save the keys to their respective files - // os.write_file(priv_key_path, private_key_content) or { - // return error("Failed to write private key: ${err}") - // } - // os.write_file(pub_key_path, public_key_content) or { - // return error("Failed to write public key: ${err}") - // } - - return SSHKey{ - name: key_name - directory: ssh_dir.path - } -} diff --git a/lib/osal/core/ssh_key.v b/lib/osal/core/ssh_key.v index 1f25590b..9fabb996 100644 --- a/lib/osal/core/ssh_key.v +++ b/lib/osal/core/ssh_key.v @@ -39,3 +39,91 @@ pub fn (key SSHKey) private_key() !string { content := path.read()! return content } + + +module core + +import freeflowuniverse.herolib.core.pathlib +import os + +@[params] +pub struct SSHConfig { +pub: + directory string = os.join_path(os.home_dir(), '.ssh') +} + +// Returns a specific SSH key with the given name from the default SSH directory (~/.ssh) +pub fn get_ssh_key(key_name string, config SSHConfig) ?SSHKey { + mut ssh_dir := pathlib.get_dir(path: config.directory) or { return none } + + list := ssh_dir.list(files_only: true) or { return none } + for file in list.paths { + if file.name() == key_name { + return SSHKey{ + name: file.name() + directory: ssh_dir.path + } + } + } + + return none +} + +// Lists SSH keys in the default SSH directory (~/.ssh) and returns an array of SSHKey structs +fn list_ssh_keys(config SSHConfig) ![]SSHKey { + mut ssh_dir := pathlib.get_dir(path: config.directory) or { + return error('Error getting ssh directory: ${err}') + } + + mut keys := []SSHKey{} + list := ssh_dir.list(files_only: true) or { + return error('Failed to list files in SSH directory') + } + + for file in list.paths { + if file.extension() == 'pub' || file.name().starts_with('id_') { + keys << SSHKey{ + name: file.name() + directory: ssh_dir.path + } + } + } + + return keys +} + +// Creates a new SSH key pair to the specified directory +pub fn new_ssh_key(key_name string, config SSHConfig) !SSHKey { + ssh_dir := pathlib.get_dir( + path: config.directory + create: true + ) or { return error('Error getting SSH directory: ${err}') } + + // Paths for the private and public keys + priv_key_path := os.join_path(ssh_dir.path, key_name) + pub_key_path := '${priv_key_path}.pub' + + // Check if the key already exists + if os.exists(priv_key_path) || os.exists(pub_key_path) { + return error("Key pair already exists with the name '${key_name}'") + } + + panic('implement shhkeygen logic') + // Generate a random private key (for demonstration purposes) + // Replace this with actual key generation logic (e.g., calling `ssh-keygen` or similar) + // private_key_content := '-----BEGIN PRIVATE KEY-----\n${rand.string(64)}\n-----END PRIVATE KEY-----' + // public_key_content := 'ssh-rsa ${rand.string(64)} user@host' + + // Save the keys to their respective files + // os.write_file(priv_key_path, private_key_content) or { + // return error("Failed to write private key: ${err}") + // } + // os.write_file(pub_key_path, public_key_content) or { + // return error("Failed to write public key: ${err}") + // } + + return SSHKey{ + name: key_name + directory: ssh_dir.path + } +} diff --git a/lib/virt/herocontainers/readme.md b/lib/virt/herocontainers/readme.md index eb16725f..05337d3b 100644 --- a/lib/virt/herocontainers/readme.md +++ b/lib/virt/herocontainers/readme.md @@ -16,14 +16,14 @@ console.print_header("BUILDAH Demo.") //if herocompile on, then will forced compile hero, which might be needed in debug mode for hero // to execute hero scripts inside build container -mut pm:=herocontainers.new(herocompile=true)! -//mut b:=pm.builder_new(name:"test")! +mut factory:=herocontainers.new(herocompile=true)! +//mut b:=factory.builder_new(name:"test")! //create -pm.builderv_create()! +factory.builderv_create()! //get the container -//mut b2:=pm.builder_get("builderv")! +//mut b2:=factory.builder_get("builderv")! //b2.shell()!