IonutParau 687cfebd00 testing version of LuaBIOS and OpenOS
people were having issues getting them to work so now we promote consistency
2025-06-28 20:41:49 +02:00

145 lines
3.9 KiB
Lua

local fs = require("filesystem")
local unicode = require("unicode")
local process = require("process")
local shell = {}
-- Cache loaded shells for command execution. This puts the requirement on
-- shells that they do not keep a global state, since they may be called
-- multiple times, but reduces memory usage a lot.
local shells = setmetatable({}, {__mode="v"})
function shell.getShell()
local shellPath = os.getenv("SHELL") or "/bin/sh"
local shellName, reason = shell.resolve(shellPath, "lua")
if not shellName then
return nil, "cannot resolve shell `" .. shellPath .. "': " .. reason
end
if shells[shellName] then
return shells[shellName]
end
local sh, load_reason = loadfile(shellName, nil, setmetatable({}, {__index=_G}))
if sh then
shells[shellName] = sh
end
return sh, load_reason
end
-------------------------------------------------------------------------------
function shell.prime()
local data = process.info().data
for _,key in ipairs({'aliases','vars'}) do
-- first time get need to populate
local raw = rawget(data, key)
if not raw then
-- current process does not have the key
local current = data[key]
data[key] = {}
if current then
for k,v in pairs(current) do
data[key][k] = v
end
end
end
end
end
function shell.getAlias(alias)
return process.info().data.aliases[alias]
end
function shell.setAlias(alias, value)
checkArg(1, alias, "string")
checkArg(2, value, "string", "nil")
process.info().data.aliases[alias] = value
end
function shell.getWorkingDirectory()
-- if no env PWD default to /
return os.getenv("PWD") or "/"
end
function shell.setWorkingDirectory(dir)
checkArg(1, dir, "string")
-- ensure at least /
-- and remove trailing /
dir = fs.canonical(dir):gsub("^$", "/"):gsub("(.)/$", "%1")
if fs.isDirectory(dir) then
os.setenv("PWD", dir)
return true
else
return nil, "not a directory"
end
end
function shell.resolve(path, ext)
checkArg(1, path, "string")
local dir = path
if dir:find("/") ~= 1 then
dir = fs.concat(shell.getWorkingDirectory(), dir)
end
local name = fs.name(path)
dir = fs[name and "path" or "canonical"](dir)
local fullname = fs.concat(dir, name or "")
if not ext then
return fullname
elseif name then
checkArg(2, ext, "string")
-- search for name in PATH if no dir was given
-- no dir was given if path has no /
local search_in = path:find("/") and dir or os.getenv("PATH")
for search_path in string.gmatch(search_in, "[^:]+") do
-- resolve search_path because they may be relative
local search_name = fs.concat(shell.resolve(search_path), name)
if not fs.exists(search_name) then
search_name = search_name .. "." .. ext
end
-- extensions are provided when the caller is looking for a file
if fs.exists(search_name) and not fs.isDirectory(search_name) then
return search_name
end
end
end
return nil, "file not found"
end
function shell.parse(...)
local params = table.pack(...)
local args = {}
local options = {}
local doneWithOptions = false
for i = 1, params.n do
local param = params[i]
if not doneWithOptions and type(param) == "string" then
if param == "--" then
doneWithOptions = true -- stop processing options at `--`
elseif param:sub(1, 2) == "--" then
local key, value = param:match("%-%-(.-)=(.*)")
if not key then
key, value = param:sub(3), true
end
options[key] = value
elseif param:sub(1, 1) == "-" and param ~= "-" then
for j = 2, unicode.len(param) do
options[unicode.sub(param, j, j)] = true
end
else
table.insert(args, param)
end
else
table.insert(args, param)
end
end
return args, options
end
-------------------------------------------------------------------------------
require("package").delay(shell, "/lib/core/full_shell.lua")
return shell