This commit is contained in:
ge
2025-12-28 20:42:30 +03:00
commit 7a67749f1f
20 changed files with 1130 additions and 0 deletions

64
runcmd.v Normal file
View File

@@ -0,0 +1,64 @@
module runcmd
import os
// new creates new Command instance with given command name and arguments.
pub fn new(name string, arg ...string) &Command {
return &Command{
path: name
args: arg
}
}
// is_present returns true if cmd is present on system. cmd may be a command
// name or filepath (relative or absolute).
// The result relies on `look_path()` output, see its docs for command search
// details.
pub fn is_present(cmd string) bool {
_ := look_path(cmd) or { return false }
return true
}
// look_path returns the absolute path to executable file. cmd may be a command
// name or filepath (relative or absolute). If the name contains a slash, then the
// PATH search is not performed, instead the path will be resolved and the file
// existence and its permissions will be checked (execution must be allowed).
// Note: To use executables located in the current working directory use './file'
// instead of just 'file'. Searching for executable files in the current directory
// is disabled for security reasons. See https://go.dev/blog/path-security.
pub fn look_path(cmd string) !string {
if cmd.is_blank() {
return os.ExecutableNotFoundError{}
}
// Do not search executable in PATH if its name contains a slashes (as POSIX-shells does),
// See PATH in: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03
if cmd.contains('/') {
actual_path := os.abs_path(os.expand_tilde_to_home(os.norm_path(cmd)))
if is_executable_file(actual_path) {
return actual_path
} else {
return os.ExecutableNotFoundError{}
}
}
paths := os.getenv('PATH').split(os.path_delimiter)
for path in paths {
if path in ['', '.'] {
// Prohibit current directory.
continue
}
actual_path := os.abs_path(os.join_path_single(path, cmd))
if is_executable_file(actual_path) {
return actual_path
}
}
return os.ExecutableNotFoundError{}
}
fn is_executable_file(file string) bool {
return os.is_file(file) && os.is_executable(file)
}