This commit is contained in:
2024-12-25 11:18:08 +01:00
parent 5085b377d9
commit a2a47ed7ee
23 changed files with 1678 additions and 48 deletions

View File

@@ -0,0 +1,94 @@
module vexecutor
import strings
import os { Result, fileno }
import freeflowuniverse.herolib.ui.console
fn vpopen(path string) voidptr {
// *C.FILE {
$if windows {
mode := 'rb'
wpath := path.to_wide()
return C._wpopen(wpath, mode.to_wide())
} $else {
cpath := path.str
return C.popen(&char(cpath), c'r')
}
}
fn vpclose(f voidptr) int {
$if windows {
return C._pclose(f)
} $else {
ret, _ := posix_wait4_to_exit_status(C.pclose(f))
return ret
}
}
fn posix_wait4_to_exit_status(waitret int) (int, bool) {
$if windows {
return waitret, false
} $else {
mut ret := 0
mut is_signaled := true
// (see man system, man 2 waitpid: C macro WEXITSTATUS section)
if C.WIFEXITED(waitret) {
ret = C.WEXITSTATUS(waitret)
is_signaled = false
} else if C.WIFSIGNALED(waitret) {
ret = C.WTERMSIG(waitret)
is_signaled = true
}
return ret, is_signaled
}
}
@[manualfree]
pub fn execute_large(cmd string) Result {
// if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') {
// return Result{ exit_code: -1, output: ';, &&, || and \\n are not allowed in shell commands' }
// }
pcmd := if cmd.contains('2>') { cmd.clone() } else { '${cmd} 2>&1' }
defer {
unsafe { pcmd.free() }
}
f := vpopen(pcmd)
if isnil(f) {
return Result{
exit_code: -1
output: 'exec("${cmd}") failed'
}
}
fd := fileno(f)
mut res := strings.new_builder(4096)
defer {
unsafe { res.free() }
}
buf := [8192]u8{}
unsafe {
pbuf := &buf[0]
for {
len := C.read(fd, pbuf, 8192)
if len == 0 {
break
}
res.write_ptr(pbuf, len)
}
}
soutput := res.str()
exit_code := vpclose(f)
return Result{
exit_code: exit_code
output: soutput
}
}
pub fn execute_large_or_panic(cmd string) Result {
res := execute_large(cmd)
if res.exit_code != 0 {
console.print_debug('failed cmd: ${cmd}')
console.print_debug('failed code: ${res.exit_code}')
panic(res.output)
}
return res
}

View File

@@ -0,0 +1,169 @@
module vexecutor
import freeflowuniverse.herolib.core.pathlib
import os
import freeflowuniverse.herolib.ui.console
// TODO make sure each function opens and closes the executor.vsh file, no file should be open across functions
struct VExecutor {
mut:
actions []VAction
execution_file os.File
execution_file_path pathlib.Path
final_file_path pathlib.Path
}
struct VAction {
path pathlib.Path
lines []string
}
// Creates a new executor object
// ARGS:
// path string - /directory/filename.v
// cat Category - unknown, file, dir, linkdir, linkfile (enum)
// exist UYN - unknown, yes, no (enum)
pub fn new_executor(initial_file_path_ string, execution_file_path_ string, final_file_path_ string) !VExecutor {
// create a execution file at execution_file_path and fill out
mut execution_file_path := pathlib.get(execution_file_path_)
execution_file_path.check()
mut initial_file_path := pathlib.get(initial_file_path_)
initial_file_path.check()
mut final_file_path := pathlib.get(final_file_path_)
final_file_path.check()
// ensure that the execution file is an empty file
if execution_file_path.exist == .yes {
os.rm(execution_file_path.path) or {
return error('Failed to remove execution file: ${err}')
}
}
execution_file := os.create(execution_file_path.path) or {
return error('Failed to create execution file at ' + @FN + ' : ${err}')
}
if initial_file_path.exist == .no {
return error('Initial file does not exist at path: ${initial_file_path.path}')
}
// convert the initial file into an action
initial_action := scan_file(mut initial_file_path) or {
return error('Failed to scan initial file path at ' + @FN + ' : ${err}')
}
// create an VExecutor object
mut v_executor := VExecutor{
execution_file: execution_file
execution_file_path: execution_file_path
final_file_path: final_file_path
actions: [initial_action]
}
return v_executor
}
// Adds all the top level files in a directory to the VExecutor.actions list
// ARGS:
// directory_path string
pub fn (mut v_executor VExecutor) add_dir_to_end(directory_path_ string) ! {
mut directory_path := pathlib.get(directory_path_)
directory_path.check()
mut fl := directory_path.list() or {
return error('Failed to get file_paths of directory at ' + @FN + ' : ${err}')
}
// mut count := 0
for mut file_path in fl.paths {
// if count <= 10 {
v_executor.actions << scan_file(mut file_path)!
// count += 1
// }
}
}
// Scans a file and converts it into a VAction
// cuts out all content prior to // BEGINNING
// ARGS:
// path string - path to file
fn scan_file(mut path pathlib.Path) !VAction {
if !path.exists() {
return error('cannot find path: ${path.path} to scan for vlang files.')
}
// read all the lines in the file into an array of lines
mut file := os.open(path.path) or { return error('Failed to open file: ${err}') }
mut lines := os.read_lines(path.path) or {
return error('Failed to readlines of file at ' + @FN + ' : ${err}')
}
file.close()
// remove lines until '// BEGINNING' is reached
mut beginning_found := false
mut count := 0
outer: for line in lines {
count += 1
if line.contains('// BEGINNING') {
beginning_found = true
break outer
}
}
mut trimmed_lines := lines.clone()
if beginning_found == true {
trimmed_lines = lines[count..lines.len]
}
return VAction{
lines: trimmed_lines
path: path
}
}
// combine all actions in VExecutor into one file
pub fn (mut v_executor VExecutor) compile() ! {
v_executor.actions << scan_file(mut v_executor.final_file_path) or {
return error('Failed to scan file at ' + @FN + ' : ${err}')
}
mut all_lines := []string{}
for action in v_executor.actions {
for line in action.lines {
all_lines << line
}
}
for line in all_lines {
v_executor.execution_file.writeln(line) or {
return error('Failed to write line to execution file at ' + @FN + ' : ${err}')
}
}
v_executor.execution_file.close()
}
// Executes the file
pub fn (mut v_executor VExecutor) do() ! {
console.print_debug('v run ${v_executor.execution_file_path.path}')
result := os.execute('v run ${v_executor.execution_file_path.path}')
console.print_debug('Exit Code: ${result.exit_code}')
if result.exit_code != 0 {
console.print_debug(result)
return error('Failed to run executor file! There are issues with the code.')
}
}
// prints out all the file paths accessed
pub fn (mut v_executor VExecutor) info() {
for action in v_executor.actions {
console.print_debug('action_path: ${action.path.path}')
}
}
// Cleans up VExecutors impact on the file system
pub fn (mut v_executor VExecutor) clean() ! {
os.rm(v_executor.execution_file_path.path) or {
return error('Failed to delete execution file at ' + @FN + ' : ${err}')
}
}