Merge remote-tracking branch 'upstream/master-MC1.10' into master-MC1.11

This commit is contained in:
payonel 2017-06-26 09:26:29 -07:00
commit 9890c7d65d
49 changed files with 368 additions and 378 deletions

View File

@ -4,7 +4,7 @@ local args, options = shell.parse(...)
local ec, error_prefix = 0, "alias:" local ec, error_prefix = 0, "alias:"
if options.help then if options.help then
print(string.format("Usage: alias: [name[=value] ... ]", cmd_name)) print(string.format("Usage: alias: [name[=value] ... ]"))
return return
end end
@ -53,7 +53,7 @@ if not next(args) then -- no args
print(string.format("alias %s='%s'", k, v)) print(string.format("alias %s='%s'", k, v))
end end
else else
for k,v in pairs(args) do for _,v in ipairs(args) do
checkArg(1,v,"string") checkArg(1,v,"string")
handlePair(splitPair(v)) handlePair(splitPair(v))
end end

View File

@ -1,8 +1,8 @@
local computer = require("computer") local computer = require("computer")
local total = computer.totalMemory() local total = computer.totalMemory()
local max = 0 local max = 0
for i=1,40 do for _=1,40 do
max = math.max(max, computer.freeMemory()) max = math.max(max, computer.freeMemory())
os.sleep(0) -- invokes gc os.sleep(0) -- invokes gc
end end
print(string.format("Total%12d\nUsed%13d\nFree%13d", total, total - max, max)) io.write(string.format("Total%12d\nUsed%13d\nFree%13d\n", total, total - max, max))

View File

@ -4,7 +4,7 @@ local shell = require("shell")
local options local options
do do
local basic, reason = loadfile("/opt/core/install_basics.lua", "bt", _G) local basic, reason = loadfile("/lib/core/install_basics.lua", "bt", _G)
if not basic then if not basic then
io.stderr:write("failed to load install: " .. tostring(reason) .. "\n") io.stderr:write("failed to load install: " .. tostring(reason) .. "\n")
return 1 return 1

View File

@ -1,7 +1,7 @@
-- load complex, if we can (might be low on memory) -- load complex, if we can (might be low on memory)
local ok, why = pcall(function(...) local ok, why = pcall(function(...)
return loadfile("/opt/core/full_ls.lua", "bt", _G)(...) return loadfile("/lib/core/full_ls.lua", "bt", _G)(...)
end, ...) end, ...)
if not ok then if not ok then

View File

@ -2,7 +2,7 @@ local shell = require("shell")
local args = shell.parse(...) local args = shell.parse(...)
if #args == 0 then if #args == 0 then
args = {"/opt/core/lua_shell.lua"} args = {"/lib/core/lua_shell.lua"}
end end
local filename = args[1] local filename = args[1]

View File

@ -2,7 +2,6 @@ local keyboard = require("keyboard")
local shell = require("shell") local shell = require("shell")
local term = require("term") -- TODO use tty and cursor position instead of global area and gpu local term = require("term") -- TODO use tty and cursor position instead of global area and gpu
local text = require("text") local text = require("text")
local unicode = require("unicode")
if not io.output().tty then if not io.output().tty then
return loadfile(shell.resolve("cat", "lua"), "bt", _G)(...) return loadfile(shell.resolve("cat", "lua"), "bt", _G)(...)
@ -28,7 +27,7 @@ end
local line = nil local line = nil
local function readlines(num) local function readlines(num)
local x, y, w, h = term.getGlobalArea() local _, _, w, h = term.getGlobalArea()
num = num or (h - 1) num = num or (h - 1)
for _ = 1, num do for _ = 1, num do
if not line then if not line then
@ -52,7 +51,7 @@ while true do
return return
end end
while true do while true do
local event, address, char, code = term.pull("key_down") local _, _, _, code = term.pull("key_down")
if code == keyboard.keys.q then if code == keyboard.keys.q then
term.clearLine() term.clearLine()
return return

View File

@ -55,12 +55,12 @@ else
io.stderr:write(reason,"\n") io.stderr:write(reason,"\n")
return 1 return 1
elseif ops.r then elseif ops.r then
proxy = dofile("/opt/core/ro_wrapper.lua").wrap(proxy) proxy = dofile("/lib/core/ro_wrapper.lua").wrap(proxy)
end end
local result, reason = fs.mount(proxy, shell.resolve(args[2])) local result, mount_failure = fs.mount(proxy, shell.resolve(args[2]))
if not result then if not result then
io.stderr:write(reason,"\n") io.stderr:write(mount_failure, "\n")
return 2 -- error code return 2 -- error code
end end
end end

View File

@ -5,70 +5,50 @@ local text = require("text")
local sh = require("sh") local sh = require("sh")
local input = table.pack(...) local input = table.pack(...)
local args, options = shell.parse(select(3,table.unpack(input))) local args = shell.parse(select(3,table.unpack(input)))
if input[2] then if input[2] then
table.insert(args, 1, input[2]) table.insert(args, 1, input[2])
end end
local history = {hint = sh.hintHandler} local history = {hint = sh.hintHandler}
shell.prime() shell.prime()
local update_gpu = io.output().tty
local interactive = io.input().tty
local foreground
if #args == 0 and (io.stdin.tty or options.i) and not options.c then if #args == 0 then
-- interactive shell.
-- source profile
if not tty.isAvailable() then event.pull("term_available") end
loadfile(shell.resolve("source","lua"))("/etc/profile")
while true do while true do
if not tty.isAvailable() then -- don't clear unless we lost the term if update_gpu then
while not tty.isAvailable() do while not tty.isAvailable() do
event.pull("term_available") event.pull("term_available")
end end
tty.clear() if not foreground and interactive then -- first time run AND interactive
end dofile("/etc/profile.lua")
local gpu = tty.gpu()
while tty.isAvailable() do
local foreground = gpu.setForeground(0xFF0000)
tty.write(sh.expand(os.getenv("PS1") or "$ "))
gpu.setForeground(foreground)
tty.setCursorBlink(true)
local command = tty.read(history)
if not command then
if command == false then
break -- soft interrupt
end
io.write("exit\n") -- pipe closed
return -- eof
end end
foreground = tty.gpu().setForeground(0xFF0000)
io.write(sh.expand(os.getenv("PS1") or "$ "))
tty.gpu().setForeground(foreground)
tty.setCursorBlink(true)
end
local command = tty.read(history)
if command then
command = text.trim(command) command = text.trim(command)
if command == "exit" then if command == "exit" then
return return
elseif command ~= "" then elseif command ~= "" then
local result, reason = sh.execute(_ENV, command) local result, reason = sh.execute(_ENV, command)
if tty.getCursor() > 1 then if update_gpu and tty.getCursor() > 1 then
print() io.write("\n")
end end
if not result then if not result then
io.stderr:write((reason and tostring(reason) or "unknown error") .. "\n") io.stderr:write((reason and tostring(reason) or "unknown error") .. "\n")
end end
end end
end elseif command == nil then -- command==false is a soft interrupt, ignore it
end if interactive then
elseif #args == 0 and not io.stdin.tty then io.write("exit\n") -- pipe closed
while true do
io.write(sh.expand(os.getenv("PS1") or "$ "))
local command = io.read("*l")
if not command then
command = "exit"
io.write(command,"\n")
end
command = text.trim(command)
if command == "exit" then
return
elseif command ~= "" then
local result, reason = os.execute(command)
if not result then
io.stderr:write((reason and tostring(reason) or "unknown error") .. "\n")
end end
return -- eof
end end
end end
else else

View File

@ -1,6 +1,5 @@
local shell = require("shell") local shell = require("shell")
local fs = require("filesystem") local process = require("process")
local sh = require("sh")
local args, options = shell.parse(...) local args, options = shell.parse(...)
@ -9,23 +8,25 @@ if #args ~= 1 then
return 1 return 1
end end
local file, reason = io.open(args[1], "r") local file, open_reason = io.open(args[1], "r")
if not file then if not file then
if not options.q then if not options.q then
io.stderr:write(string.format("could not source %s because: %s\n", args[1], reason)); io.stderr:write(string.format("could not source %s because: %s\n", args[1], open_reason));
end end
return 1 return 1
else
local status, reason = xpcall(function()
repeat
local line = file:read()
if line then
sh.execute(nil, line)
end
until not line
end, function(msg) return {msg, debug.traceback()} end)
file:close()
if not status and reason then assert(false, tostring(reason[1]) .."\n".. tostring(reason[2])) end
end end
local current_data = process.info().data
local source_proc = process.load((assert(os.getenv("SHELL"), "no $SHELL set")))
local source_data = process.list[source_proc].data
source_data.aliases = current_data.aliases -- hacks to propogate sub shell env changes
source_data.vars = current_data.vars
source_data.io[0] = file -- set stdin to the file
if options.q then
source_data.io[1] = {tty=false,write=function()end} -- set stdin to the file
end
process.internal.continue(source_proc)
file:close() -- should have closed when the process closed, but just to be sure

View File

@ -2,9 +2,9 @@ function loadfile(filename, ...)
if filename:sub(1,1) ~= "/" then if filename:sub(1,1) ~= "/" then
filename = (os.getenv("PWD") or "/") .. "/" .. filename filename = (os.getenv("PWD") or "/") .. "/" .. filename
end end
local handle, reason = require("filesystem").open(filename) local handle, open_reason = require("filesystem").open(filename)
if not handle then if not handle then
return nil, reason return nil, open_reason
end end
local buffer = {} local buffer = {}
while true do while true do

View File

@ -27,21 +27,26 @@ local intercept_load
intercept_load = function(source, label, mode, env) intercept_load = function(source, label, mode, env)
if env then if env then
local prev_load = env.load or intercept_load local prev_load = env.load or intercept_load
local env_mt = getmetatable(env) or {} local next_load = function(_source, _label, _mode, _env)
local env_mt_index = env_mt.__index return prev_load(_source, _label, _mode, _env or env)
env_mt.__index = function(tbl, key) end
if key == "load" then if rawget(env, "load") then -- overwrite load
return function(_source, _label, _mode, _env) env.load = next_load
return prev_load(_source, _label, _mode, _env or env) else -- else it must be an __index load, or it didn't have one
end local env_mt = getmetatable(env) or {}
elseif type(env_mt_index) == "table" then local env_mt_index = env_mt.__index
return env_mt_index[key] env_mt.__index = function(tbl, key)
elseif env_mt_index then if key == "load" then
return env_mt_index(tbl, key) return next_load
end elseif type(env_mt_index) == "table" then
return nil return env_mt_index[key]
elseif env_mt_index then
return env_mt_index(tbl, key)
end
return nil
end
setmetatable(env, env_mt)
end end
setmetatable(env, env_mt)
end end
return kernel_load(source, label, mode, env or process.info().env) return kernel_load(source, label, mode, env or process.info().env)
end end

View File

@ -63,3 +63,5 @@ end
event.listen("init", onInit) event.listen("init", onInit)
event.listen("component_added", onComponentAdded) event.listen("component_added", onComponentAdded)
event.listen("component_removed", onComponentRemoved) event.listen("component_removed", onComponentRemoved)
require("package").delay(fs, "/lib/core/full_filesystem.lua")

View File

@ -1,26 +0,0 @@
alias dir=ls
alias move=mv
alias rename=mv
alias copy=cp
alias del=rm
alias md=mkdir
alias cls=clear
alias rs=redstone
alias view=edit\ -r
alias help=man
alias cp=cp\ -i
set EDITOR=/bin/edit
set HISTSIZE=10
set HOME=/home
set IFS=\
set MANPATH=/usr/man:.
set PAGER=/bin/more
set PS1='$HOSTNAME$HOSTNAME_SEPARATOR$PWD # '
set PWD=/
set LS_COLORS="{FILE=0xFFFFFF,DIR=0x66CCFF,LINK=0xFFAA00,['*.lua']=0x00FF00}"
cd $HOME
clear
/etc/motd
source $HOME/.shrc -q

View File

@ -0,0 +1,38 @@
local shell = require("shell")
local tty = require("tty")
local fs = require("filesystem")
tty.clear()
dofile("/etc/motd")
shell.setAlias("dir", "ls")
shell.setAlias("move", "mv")
shell.setAlias("rename", "mv")
shell.setAlias("copy", "cp")
shell.setAlias("del", "rm")
shell.setAlias("md", "mkdir")
shell.setAlias("cls", "clear")
shell.setAlias("rs", "redstone")
shell.setAlias("view", "edit -r")
shell.setAlias("help", "man")
shell.setAlias("cp", "cp -i")
shell.setAlias("l", "ls -lhp")
shell.setAlias("..", "cd ..")
shell.setAlias("df", "df -h")
shell.setAlias("grep", "grep --color")
os.setenv("EDITOR", "/bin/edit")
os.setenv("HISTSIZE", "10")
os.setenv("HOME", "/home")
os.setenv("IFS", " ")
os.setenv("MANPATH", "/usr/man:.")
os.setenv("PAGER", "/bin/more")
os.setenv("PS1", "$HOSTNAME$HOSTNAME_SEPARATOR$PWD # ")
os.setenv("LS_COLORS", "{FILE=0xFFFFFF,DIR=0x66CCFF,LINK=0xFFAA00,['*.lua']=0x00FF00}")
shell.setWorkingDirectory(os.getenv("HOME"))
local home_shrc = shell.resolve(".shrc")
if fs.exists(home_shrc) then
loadfile(shell.resolve("source", "lua"))(home_shrc, "-q")
end

View File

@ -1,5 +0,0 @@
alias l="ls -lhp"
alias ..="cd .."
alias df="df -h"
alias grep="grep --color"

View File

@ -13,7 +13,7 @@ do
invoke(addr, "close", handle) invoke(addr, "close", handle)
return load(buffer, "=" .. file, "bt", _G) return load(buffer, "=" .. file, "bt", _G)
end]], "=loadfile", "bt", _G)() end]], "=loadfile", "bt", _G)()
loadfile("/opt/core/boot.lua")(loadfile) loadfile("/lib/core/boot.lua")(loadfile)
end end
while true do while true do

View File

@ -1,7 +1,7 @@
-- called from /init.lua -- called from /init.lua
local raw_loadfile = ... local raw_loadfile = ...
_G._OSVERSION = "OpenOS 1.6.5" _G._OSVERSION = "OpenOS 1.6.6"
local component = component local component = component
local computer = computer local computer = computer

View File

@ -1,10 +1,9 @@
local comp = require("component") local comp = require("component")
local fs = require("filesystem")
local text = require("text") local text = require("text")
local dcache = {} local dcache = {}
local pcache = {} local pcache = {}
local adapter_pwd = "/opt/core/devfs/adapters/" local adapter_pwd = "/lib/core/devfs/adapters/"
local adapter_api = {} local adapter_api = {}

View File

@ -0,0 +1,138 @@
local filesystem = require("filesystem")
function filesystem.makeDirectory(path)
if filesystem.exists(path) then
return nil, "file or directory with that name already exists"
end
local node, rest = filesystem.findNode(path)
if node.fs and rest then
local success, reason = node.fs.makeDirectory(rest)
if not success and not reason and node.fs.isReadOnly() then
reason = "filesystem is readonly"
end
return success, reason
end
if node.fs then
return nil, "virtual directory with that name already exists"
end
return nil, "cannot create a directory in a virtual directory"
end
function filesystem.lastModified(path)
local node, rest, vnode, vrest = filesystem.findNode(path, false, true)
if not node or not vnode.fs and not vrest then
return 0 -- virtual directory
end
if node.fs and rest then
return node.fs.lastModified(rest)
end
return 0 -- no such file or directory
end
function filesystem.mounts()
local tmp = {}
for path,node in pairs(filesystem.fstab) do
table.insert(tmp, {node.fs,path})
end
return function()
local next = table.remove(tmp)
if next then return table.unpack(next) end
end
end
function filesystem.link(target, linkpath)
checkArg(1, target, "string")
checkArg(2, linkpath, "string")
if filesystem.exists(linkpath) then
return nil, "file already exists"
end
local linkpath_parent = filesystem.path(linkpath)
if not filesystem.exists(linkpath_parent) then
return nil, "no such directory"
end
local linkpath_real, reason = filesystem.realPath(linkpath_parent)
if not linkpath_real then
return nil, reason
end
if not filesystem.isDirectory(linkpath_real) then
return nil, "not a directory"
end
local _, _, vnode, _ = filesystem.findNode(linkpath_real, true)
vnode.links[filesystem.name(linkpath)] = target
return true
end
function filesystem.umount(fsOrPath)
checkArg(1, fsOrPath, "string", "table")
local real
local fs
local addr
if type(fsOrPath) == "string" then
real = filesystem.realPath(fsOrPath)
addr = fsOrPath
else -- table
fs = fsOrPath
end
local paths = {}
for path,node in pairs(filesystem.fstab) do
if real == path or addr == node.fs.address or fs == node.fs then
table.insert(paths, path)
end
end
for _,path in ipairs(paths) do
local node = filesystem.fstab[path]
filesystem.fstab[path] = nil
node.fs = nil
node.parent.children[node.name] = nil
end
return #paths > 0
end
function filesystem.size(path)
local node, rest, vnode, vrest = filesystem.findNode(path, false, true)
if not node or not vnode.fs and (not vrest or vnode.links[vrest]) then
return 0 -- virtual directory or symlink
end
if node.fs and rest then
return node.fs.size(rest)
end
return 0 -- no such file or directory
end
function filesystem.isLink(path)
local name = filesystem.name(path)
local node, rest, vnode, vrest = filesystem.findNode(filesystem.path(path), false, true)
if not node then return nil, rest end
local target = vnode.links[name]
-- having vrest here indicates we are not at the
-- owning vnode due to a mount point above this point
-- but we can have a target when there is a link at
-- the mount point root, with the same name
if not vrest and target ~= nil then
return true, target
end
return false
end
function filesystem.copy(fromPath, toPath)
local data = false
local input, reason = filesystem.open(fromPath, "rb")
if input then
local output, reason = filesystem.open(toPath, "wb")
if output then
repeat
data, reason = input:read(1024)
if not data then break end
data, reason = output:write(data)
if not data then data, reason = false, "failed to write" end
until not data
output:close()
end
input:close()
end
return data == nil, reason
end

View File

@ -253,7 +253,7 @@ local function display(names)
max_size_width = math.max(max_size_width, formatSize(info.size):len()) max_size_width = math.max(max_size_width, formatSize(info.size):len())
max_date_width = math.max(max_date_width, formatDate(info.time):len()) max_date_width = math.max(max_date_width, formatDate(info.time):len())
end end
mt.__index = function(tbl, index) mt.__index = function(_, index)
local info = stat(names, index) local info = stat(names, index)
local file_type = info.isLink and 'l' or info.isDir and 'd' or 'f' local file_type = info.isLink and 'l' or info.isDir and 'd' or 'f'
local link_target = info.isLink and string.format(" -> %s", info.link:gsub("/+$", "") .. (info.isDir and "/" or "")) or "" local link_target = info.isLink and string.format(" -> %s", info.link:gsub("/+$", "") .. (info.isDir and "/" or "")) or ""
@ -267,7 +267,7 @@ local function display(names)
end end
elseif ops["1"] or not fOut then elseif ops["1"] or not fOut then
lines.n = #names lines.n = #names
mt.__index = function(tbl, index) mt.__index = function(_, index)
local info = stat(names, index) local info = stat(names, index)
return {{color = colorize(info), name = info.name}} return {{color = colorize(info), name = info.name}}
end end
@ -302,10 +302,10 @@ local function display(names)
end end
end end
lines.n = items_per_column lines.n = items_per_column
mt.__index=function(tbl, line_index) mt.__index=function(_, line_index)
return setmetatable({},{ return setmetatable({},{
__len=function()return num_columns end, __len=function()return num_columns end,
__index=function(tbl, column_index) __index=function(_, column_index)
local ri = real(column_index, line_index) local ri = real(column_index, line_index)
if not ri then return end if not ri then return end
local info = stat(names, ri) local info = stat(names, ri)

View File

@ -22,7 +22,7 @@ if options.help then
return nil -- exit success return nil -- exit success
end end
local utils_path = "/opt/core/install_utils.lua" local utils_path = "/lib/core/install_utils.lua"
local utils local utils
local rootfs = fs.get("/") local rootfs = fs.get("/")
@ -64,7 +64,7 @@ local targets = {}
local devices = {} local devices = {}
for dev, path in fs.mounts() do for dev, path in fs.mounts() do
devices[dev] = path devices[dev] = devices[dev] and #devices[dev] < #path and devices[dev] or path
end end
devices[fs.get("/dev/") or false] = nil devices[fs.get("/dev/") or false] = nil
@ -81,6 +81,7 @@ for dev, path in pairs(devices) do
os.exit(1) os.exit(1)
end end
elseif specified or elseif specified or
not (source_filter and address:find(source_filter, 1, true) == 1) and -- specified for source
not target_filter and not target_filter and
address ~= tmpAddress then address ~= tmpAddress then
table.insert(targets, {dev=dev, path=install_path, specified=specified}) table.insert(targets, {dev=dev, path=install_path, specified=specified})
@ -156,8 +157,8 @@ local cp_args =
local source_display = options.label or source.dev.getLabel() or source.path local source_display = options.label or source.dev.getLabel() or source.path
local special_target = "" local special_target = ""
if #targets > 1 or target_filter then if #targets > 1 or target_filter or source_filter then
special_target = " to " .. cp_args[3] special_target = " to " .. cp_args[4]
end end
io.write("Install " .. source_display .. special_target .. "? [Y/n] ") io.write("Install " .. source_display .. special_target .. "? [Y/n] ")

View File

@ -13,7 +13,7 @@ local function select_prompt(devs, prompt)
for i = 1, num_devs do for i = 1, num_devs do
local src = devs[i] local src = devs[i]
local dev = src.dev local dev = src.dev
local selection_label = src.prop.label or dev.getLabel() local selection_label = (src.prop or {}).label or dev.getLabel()
if selection_label then if selection_label then
selection_label = string.format("%s (%s...)", selection_label, dev.address:sub(1, 8)) selection_label = string.format("%s (%s...)", selection_label, dev.address:sub(1, 8))
else else

View File

@ -1,6 +1,5 @@
local package = require("package") local package = require("package")
local tty = require("tty") local tty = require("tty")
local process = require("process")
local gpu = tty.gpu() local gpu = tty.gpu()
@ -92,16 +91,16 @@ function read_handler.hint(line, index)
end end
gpu.setForeground(0xFFFFFF) gpu.setForeground(0xFFFFFF)
tty.write(_VERSION .. " Copyright (C) 1994-2017 Lua.org, PUC-Rio\n") io.write(_VERSION .. " Copyright (C) 1994-2017 Lua.org, PUC-Rio\n")
gpu.setForeground(0xFFFF00) gpu.setForeground(0xFFFF00)
tty.write("Enter a statement and hit enter to evaluate it.\n") io.write("Enter a statement and hit enter to evaluate it.\n")
tty.write("Prefix an expression with '=' to show its value.\n") io.write("Prefix an expression with '=' to show its value.\n")
tty.write("Press Ctrl+D to exit the interpreter.\n") io.write("Press Ctrl+D to exit the interpreter.\n")
gpu.setForeground(0xFFFFFF) gpu.setForeground(0xFFFFFF)
while tty.isAvailable() do while tty.isAvailable() do
local foreground = gpu.setForeground(0x00FF00) local foreground = gpu.setForeground(0x00FF00)
tty.write(env._PROMPT) io.write(env._PROMPT)
gpu.setForeground(foreground) gpu.setForeground(foreground)
local command = tty.read(read_handler) local command = tty.read(read_handler)
if not command then -- eof if not command then -- eof
@ -122,10 +121,10 @@ while tty.isAvailable() do
io.stderr:write(tostring(result[2]) .. "\n") io.stderr:write(tostring(result[2]) .. "\n")
else else
for i = 2, result.n do for i = 2, result.n do
tty.write(require("serialization").serialize(result[i], true) .. "\t", true) io.write(require("serialization").serialize(result[i], true) .. "\t")
end end
if tty.getCursor() > 1 then if tty.getCursor() > 1 then
tty.write("\n") io.write("\n")
end end
end end
else else

View File

@ -153,7 +153,7 @@ inject_dynamic_pairs = function(fsnode, path, bStoreUse)
}) })
end end
local label_lib = dofile("/opt/core/device_labeling.lua") local label_lib = dofile("/lib/core/device_labeling.lua")
label_lib.loadRules() label_lib.loadRules()
api.getDeviceLabel = label_lib.getDeviceLabel api.getDeviceLabel = label_lib.getDeviceLabel
api.setDeviceLabel = label_lib.setDeviceLabel api.setDeviceLabel = label_lib.setDeviceLabel
@ -163,7 +163,7 @@ function api.register(public_proxy)
if registered then return end if registered then return end
registered = true registered = true
local start_path = "/opt/core/devfs/" local start_path = "/lib/core/devfs/"
for starter in fs.list(start_path) do for starter in fs.list(start_path) do
local full_path = start_path .. starter local full_path = start_path .. starter
local _,matched = starter:gsub("%.lua$","") local _,matched = starter:gsub("%.lua$","")

View File

@ -1,7 +1,7 @@
local component = require("component") local component = require("component")
local unicode = require("unicode") local unicode = require("unicode")
local filesystem, fileStream = {}, {} local filesystem = {}
local isAutorunEnabled = nil local isAutorunEnabled = nil
local mtab = {name="", children={}, links={}} local mtab = {name="", children={}, links={}}
local fstab = {} local fstab = {}
@ -116,8 +116,6 @@ function filesystem.setAutorunEnabled(value)
saveConfig() saveConfig()
end end
filesystem.segments = segments
function filesystem.canonical(path) function filesystem.canonical(path)
local result = table.concat(segments(path), "/") local result = table.concat(segments(path), "/")
if unicode.sub(path, 1, 1) == "/" then if unicode.sub(path, 1, 1) == "/" then
@ -165,45 +163,6 @@ function filesystem.realPath(path)
return table.concat(parts, "/") return table.concat(parts, "/")
end end
function filesystem.isLink(path)
local name = filesystem.name(path)
local node, rest, vnode, vrest = findNode(filesystem.path(path), false, true)
if not node then return nil, rest end
local target = vnode.links[name]
-- having vrest here indicates we are not at the
-- owning vnode due to a mount point above this point
-- but we can have a target when there is a link at
-- the mount point root, with the same name
if not vrest and target ~= nil then
return true, target
end
return false
end
function filesystem.link(target, linkpath)
checkArg(1, target, "string")
checkArg(2, linkpath, "string")
if filesystem.exists(linkpath) then
return nil, "file already exists"
end
local linkpath_parent = filesystem.path(linkpath)
if not filesystem.exists(linkpath_parent) then
return nil, "no such directory"
end
local linkpath_real, reason = filesystem.realPath(linkpath_parent)
if not linkpath_real then
return nil, reason
end
if not filesystem.isDirectory(linkpath_real) then
return nil, "not a directory"
end
local _, _, vnode, _ = findNode(linkpath_real, true)
vnode.links[filesystem.name(linkpath)] = target
return true
end
function filesystem.mount(fs, path) function filesystem.mount(fs, path)
checkArg(1, fs, "string", "table") checkArg(1, fs, "string", "table")
if type(fs) == "string" then if type(fs) == "string" then
@ -260,17 +219,6 @@ function filesystem.mount(fs, path)
return true return true
end end
function filesystem.mounts()
local tmp = {}
for path,node in pairs(fstab) do
table.insert(tmp, {node.fs,path})
end
return function()
local next = table.remove(tmp)
if next then return table.unpack(next) end
end
end
function filesystem.path(path) function filesystem.path(path)
local parts = segments(path) local parts = segments(path)
local result = table.concat(parts, "/", 1, #parts - 1) .. "/" local result = table.concat(parts, "/", 1, #parts - 1) .. "/"
@ -306,33 +254,6 @@ function filesystem.proxy(filter)
return component.proxy(address) return component.proxy(address)
end end
function filesystem.umount(fsOrPath)
checkArg(1, fsOrPath, "string", "table")
local real
local fs
local addr
if type(fsOrPath) == "string" then
real = filesystem.realPath(fsOrPath)
addr = fsOrPath
else -- table
fs = fsOrPath
end
local paths = {}
for path,node in pairs(fstab) do
if real == path or addr == node.fs.address or fs == node.fs then
table.insert(paths, path)
end
end
for _,path in ipairs(paths) do
local node = fstab[path]
fstab[path] = nil
node.fs = nil
node.parent.children[node.name] = nil
end
return #paths > 0
end
function filesystem.exists(path) function filesystem.exists(path)
if not filesystem.realPath(filesystem.path(path)) then if not filesystem.realPath(filesystem.path(path)) then
return false return false
@ -346,17 +267,6 @@ function filesystem.exists(path)
return false return false
end end
function filesystem.size(path)
local node, rest, vnode, vrest = findNode(path, false, true)
if not node or not vnode.fs and (not vrest or vnode.links[vrest]) then
return 0 -- virtual directory or symlink
end
if node.fs and rest then
return node.fs.size(rest)
end
return 0 -- no such file or directory
end
function filesystem.isDirectory(path) function filesystem.isDirectory(path)
local real, reason = filesystem.realPath(path) local real, reason = filesystem.realPath(path)
if not real then return nil, reason end if not real then return nil, reason end
@ -370,17 +280,6 @@ function filesystem.isDirectory(path)
return false return false
end end
function filesystem.lastModified(path)
local node, rest, vnode, vrest = findNode(path, false, true)
if not node or not vnode.fs and not vrest then
return 0 -- virtual directory
end
if node.fs and rest then
return node.fs.lastModified(rest)
end
return 0 -- no such file or directory
end
function filesystem.list(path) function filesystem.list(path)
local node, rest, vnode, vrest = findNode(path, false, true) local node, rest, vnode, vrest = findNode(path, false, true)
local result = {} local result = {}
@ -410,24 +309,6 @@ function filesystem.list(path)
end end
end end
function filesystem.makeDirectory(path)
if filesystem.exists(path) then
return nil, "file or directory with that name already exists"
end
local node, rest = findNode(path)
if node.fs and rest then
local success, reason = node.fs.makeDirectory(rest)
if not success and not reason and node.fs.isReadOnly() then
reason = "filesystem is readonly"
end
return success, reason
end
if node.fs then
return nil, "virtual directory with that name already exists"
end
return nil, "cannot create a directory in a virtual directory"
end
function filesystem.remove(path) function filesystem.remove(path)
return require("tools/fsmod").remove(path, findNode) return require("tools/fsmod").remove(path, findNode)
end end
@ -436,53 +317,6 @@ function filesystem.rename(oldPath, newPath)
return require("tools/fsmod").rename(oldPath, newPath, findNode) return require("tools/fsmod").rename(oldPath, newPath, findNode)
end end
function filesystem.copy(fromPath, toPath)
local data = false
local input, reason = filesystem.open(fromPath, "rb")
if input then
local output, reason = filesystem.open(toPath, "wb")
if output then
repeat
data, reason = input:read(1024)
if not data then break end
data, reason = output:write(data)
if not data then data, reason = false, "failed to write" end
until not data
output:close()
end
input:close()
end
return data == nil, reason
end
function fileStream:close()
if self.handle then
self.fs.close(self.handle)
self.handle = nil
end
end
function fileStream:read(n)
if not self.handle then
return nil, "file is closed"
end
return self.fs.read(self.handle, n)
end
function fileStream:seek(whence, offset)
if not self.handle then
return nil, "file is closed"
end
return self.fs.seek(self.handle, whence, offset)
end
function fileStream:write(str)
if not self.handle then
return nil, "file is closed"
end
return self.fs.write(self.handle, str)
end
function filesystem.open(path, mode) function filesystem.open(path, mode)
checkArg(1, path, "string") checkArg(1, path, "string")
mode = tostring(mode or "r") mode = tostring(mode or "r")
@ -504,13 +338,36 @@ function filesystem.open(path, mode)
return nil, reason return nil, reason
end end
local stream = {fs = node.fs, handle = handle} local function create_handle_method(key)
return function(self, ...)
if not self.handle then
return nil, "file is closed"
end
return self.fs[key](self.handle, ...)
end
end
local metatable = {__index = fileStream, local stream =
__metatable = "filestream"} {
return setmetatable(stream, metatable) fs = node.fs,
handle = handle,
close = function(self)
if self.handle then
self.fs.close(self.handle)
self.handle = nil
end
end
}
stream.read = create_handle_method("read")
stream.seek = create_handle_method("seek")
stream.write = create_handle_method("write")
return stream
end end
filesystem.findNode = findNode
filesystem.segments = segments
filesystem.fstab = fstab
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
return filesystem return filesystem

View File

@ -82,6 +82,6 @@ end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
require("package").delay(keyboard.keys, "/opt/core/full_keyboard.lua") require("package").delay(keyboard.keys, "/lib/core/full_keyboard.lua")
return keyboard return keyboard

View File

@ -70,14 +70,18 @@ function require(module)
end end
function package.delay(lib, file) function package.delay(lib, file)
setmetatable(lib, local mt = {
{
__index = function(tbl, key) __index = function(tbl, key)
setmetatable(tbl, nil)
dofile(file) dofile(file)
setmetatable(lib, nil)
setmetatable(lib.internal or {}, nil)
return tbl[key] return tbl[key]
end end
}) }
if lib.internal then
setmetatable(lib.internal, mt)
end
setmetatable(lib, mt)
end end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------

View File

@ -272,7 +272,6 @@ function sh.hintHandler(full_line, cursor)
return sh.internal.hintHandlerImpl(full_line, cursor) return sh.internal.hintHandlerImpl(full_line, cursor)
end end
require("package").delay(sh, "/opt/core/full_sh.lua") require("package").delay(sh, "/lib/core/full_sh.lua")
require("package").delay(sh.internal, "/opt/core/full_sh.lua")
return sh return sh

View File

@ -18,11 +18,11 @@ function shell.getShell()
if shells[shellName] then if shells[shellName] then
return shells[shellName] return shells[shellName]
end end
local sh, reason = loadfile(shellName) local sh, load_reason = loadfile(shellName)
if sh then if sh then
shells[shellName] = sh shells[shellName] = sh
end end
return sh, reason return sh, load_reason
end end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------

View File

@ -182,6 +182,17 @@ local function inject_mask(cursor, dobreak, pwchar)
end end
end end
-- cannot use term.write = io.write because io.write invokes metatable
function term.write(value, wrap)
local stdout = io.output()
local stream = stdout and stdout.stream
local previous_nowrap = stream.nowrap
stream.nowrap = wrap == false
stdout:write(value)
stdout:flush()
stream.nowrap = previous_nowrap
end
function term.read(history, dobreak, hint, pwchar, filter) function term.read(history, dobreak, hint, pwchar, filter)
if not io.stdin.tty then if not io.stdin.tty then
return io.read("*L") return io.read("*L")

View File

@ -89,10 +89,10 @@ function text.internal.words(input, options)
local show_escapes = options.show_escapes local show_escapes = options.show_escapes
local qr = nil local qr = nil
quotes = quotes or {{"'","'",true},{'"','"'},{'`','`'}} quotes = quotes or {{"'","'",true},{'"','"'},{'`','`'}}
local function append(dst, txt, qr) local function append(dst, txt, _qr)
local size = #dst local size = #dst
if size == 0 or dst[size].qr ~= qr then if size == 0 or dst[size].qr ~= _qr then
dst[size+1] = {txt=txt, qr=qr} dst[size+1] = {txt=txt, qr=_qr}
else else
dst[size].txt = dst[size].txt..txt dst[size].txt = dst[size].txt..txt
end end
@ -144,7 +144,6 @@ function text.internal.words(input, options)
return tokens return tokens
end end
require("package").delay(text, "/opt/core/full_text.lua") require("package").delay(text, "/lib/core/full_text.lua")
require("package").delay(text.internal, "/opt/core/full_text.lua")
return text return text

View File

@ -70,6 +70,6 @@ function lib.concat(...)
return r return r
end end
require("package").delay(lib, "/opt/core/full_transforms.lua") require("package").delay(lib, "/lib/core/full_transforms.lua")
return lib return lib

View File

@ -25,8 +25,8 @@ local function ctrl_movement(cursor, dir)
local start=index+dir+1 local start=index+dir+1
for i=start,last,dir do for i=start,last,dir do
local a,b = unicode.sub(data, i-1, i-1), unicode.sub(data, i, i) local a,b = unicode.sub(data, i-1, i-1), unicode.sub(data, i, i)
a = a == "" or not not a:find("%s") a = a == "" or a:find("%s")
b = b == "" or not not b:find("%s") b = b == "" or b:find("%s")
if a and not b then return i - (index + 1) end if a and not b then return i - (index + 1) end
end end
return last - index return last - index
@ -192,16 +192,16 @@ function tty.internal.build_vertical_reader()
index = 0, index = 0,
data = "", data = "",
sy = 0, sy = 0,
scroll = function(_) scroll = function(self)
_.sy = _.sy + tty.scroll() self.sy = self.sy + tty.scroll()
end, end,
move = function(_,n) move = function(self, n)
local win = tty.window local win = tty.window
_.index = math.min(math.max(0,_.index + n), unicode.len(_.data)) self.index = math.min(math.max(0, self.index + n), unicode.len(self.data))
local s1, s2 = tty.internal.split(_) local s1, s2 = tty.internal.split(self)
s2 = unicode.sub(s2.." ", 1, 1) s2 = unicode.sub(s2.." ", 1, 1)
local data_remaining = ("_"):rep(_.promptx - 1)..s1..s2 local data_remaining = ("_"):rep(self.promptx - 1)..s1..s2
win.y = _.prompty - _.sy win.y = self.prompty - self.sy
while true do while true do
local wlen_remaining = unicode.wlen(data_remaining) local wlen_remaining = unicode.wlen(data_remaining)
if wlen_remaining > win.width then if wlen_remaining > win.width then
@ -214,53 +214,53 @@ function tty.internal.build_vertical_reader()
end end
end end
end, end,
clear_tail = function(_) clear_tail = function(self)
local oi, width, height, dx, dy, ox, oy = _.index, tty.getViewport() local oi, width, _, dx, dy, ox, oy = self.index, tty.getViewport()
_:move(math.huge) self:move(math.huge)
_:move(-1) self:move(-1)
local ex, ey = tty.getCursor() local _, ey = tty.getCursor()
tty.setCursor(ox, oy) tty.setCursor(ox, oy)
_.index = oi self.index = oi
local x = oy == ey and ox or 1 local cx = oy == ey and ox or 1
tty.gpu().fill(x + dx, ey + dy, width - x + 1, 1, " ") tty.gpu().fill(cx + dx, ey + dy, width - cx + 1, 1, " ")
end, end,
update = function(_, arg) update = function(self, arg)
local s1, s2 = tty.internal.split(_) local s1, s2 = tty.internal.split(self)
if type(arg) == "string" then if type(arg) == "string" then
_.data = s1 .. arg .. s2 self.data = s1 .. arg .. s2
_.index = _.index + unicode.len(arg) self.index = self.index + unicode.len(arg)
_:draw(arg) self:draw(arg)
else -- number else -- number
if arg < 0 then if arg < 0 then
-- backspace? ignore if at start -- backspace? ignore if at start
if _.index <= 0 then return end if self.index <= 0 then return end
_:move(arg) self:move(arg)
s1 = unicode.sub(s1, 1, -1 + arg) s1 = unicode.sub(s1, 1, -1 + arg)
else else
-- forward? ignore if at end -- forward? ignore if at end
if _.index >= unicode.len(_.data) then return end if self.index >= unicode.len(self.data) then return end
s2 = unicode.sub(s2, 1 + arg) s2 = unicode.sub(s2, 1 + arg)
end end
_:clear_tail() self:clear_tail()
_.data = s1 .. s2 self.data = s1 .. s2
end end
-- redraw suffix -- redraw suffix
if s2 ~= "" then if s2 ~= "" then
local ps, px, py = _.sy, tty.getCursor() local ps, px, py = self.sy, tty.getCursor()
_:draw(s2) self:draw(s2)
tty.setCursor(px, py - (_.sy - ps)) tty.setCursor(px, py - (self.sy - ps))
end end
end, end,
clear = function(_) clear = function(self)
_:move(-math.huge) self:move(-math.huge)
_:draw((" "):rep(unicode.wlen(_.data))) self:draw((" "):rep(unicode.wlen(self.data)))
_:move(-math.huge) self:move(-math.huge)
_.index = 0 self.index = 0
_.data = "" self.data = ""
end, end,
draw = function(_, text) draw = function(self, text)
_.sy = _.sy + tty.drawText(text) self.sy = self.sy + tty.drawText(text)
end end
} }
end end
@ -306,17 +306,6 @@ function tty.read(handler, cursor)
end end
end end
-- cannot use tty.write = io.write because io.write invokes metatable
function tty.write(value, wrap)
local stdout = io.output()
local stream = stdout and stdout.stream
local previous_nowrap = stream.nowrap
stream.nowrap = wrap == false
stdout:write(value)
stdout:flush()
stream.nowrap = previous_nowrap
end
function tty.getCursor() function tty.getCursor()
local window = tty.window local window = tty.window
return window.x, window.y return window.x, window.y
@ -337,7 +326,7 @@ function tty.drawText(value, nowrap)
local uptime = computer.uptime local uptime = computer.uptime
local last_sleep = uptime() local last_sleep = uptime()
local last_index = 1 local last_index = 1
local width, height, dx, dy = tty.getViewport() local width, _, dx, dy = tty.getViewport()
while true do while true do
if uptime() - last_sleep > 1 then if uptime() - last_sleep > 1 then
os.sleep(0) os.sleep(0)
@ -493,6 +482,6 @@ function tty.scroll(number)
return lines return lines
end end
require("package").delay(tty, "/opt/core/full_tty.lua") require("package").delay(tty, "/lib/core/full_tty.lua")
return tty return tty

View File

@ -22,7 +22,7 @@ Many component methods have a short documentation - use `=component.componentNam
You can get a list of all attached components using the `components` program. You can get a list of all attached components using the `components` program.
If you encounter out of memory errors, throw more RAM at your computer. If you encounter out of memory errors, throw more RAM at your computer.
Have you tried turning it off and on again? Have you tried turning it off and on again?
To disable this greeting, install OpenOS to a writeable medium and remove the `/etc/motd` line from `/etc/profile`. To disable this greeting, install OpenOS to a writeable medium and remove the `/etc/motd` line from `/etc/profile.lua`.
Did you know OpenComputers has a forum? No? Well, it's at https://oc.cil.li/. Did you know OpenComputers has a forum? No? Well, it's at https://oc.cil.li/.
Please report bugs on the Github issue tracker, thank you! Please report bugs on the Github issue tracker, thank you!
Beware of cycles when building networks, or you may get duplicate messages! Beware of cycles when building networks, or you may get duplicate messages!