2.21.2025 (BETA)
This commit is contained in:
commit
ce60ed8a0b
9
LICENSE
Normal file
9
LICENSE
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Jase Williams
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
9
test/TODO
Normal file
9
test/TODO
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
- Filesystem
|
||||||
|
Mounts and virtual mounts (ie /tmp, /dev)
|
||||||
|
Protected paths
|
||||||
|
|
||||||
|
- Package
|
||||||
|
Error handling
|
||||||
|
Paths
|
||||||
|
|
||||||
|
- I/O
|
227
test/bin/openfetch.lua
Normal file
227
test/bin/openfetch.lua
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
-- openfetch 1.4 | by ethernalsteve & Bs0Dd
|
||||||
|
|
||||||
|
local component = require("component")
|
||||||
|
local computer = require("computer")
|
||||||
|
local fs = require("filesystem")
|
||||||
|
local gpu = component.gpu
|
||||||
|
|
||||||
|
local logos = {
|
||||||
|
{
|
||||||
|
" %%%%(///////(%%% ",
|
||||||
|
" %% (///%%%/(%%%%% ",
|
||||||
|
" %% (///%%%/(%%%%% ",
|
||||||
|
" %% (///////(%%%%% ",
|
||||||
|
" %%%%%%%%%%%%%%%%%%% ",
|
||||||
|
" %%%%%%%%%%%%%%%%%%% ",
|
||||||
|
" %% %% ",
|
||||||
|
" %% %% ",
|
||||||
|
" %%%%%%%%%%%%%%%%%%% ",
|
||||||
|
" %%%%%%%%%%%%%%%%% "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
" %%%%%(///////////////(%%%% ",
|
||||||
|
" %%%###(//////%%%%%%///(%%%%%%% ",
|
||||||
|
" %%%###(//////%%%%%%///(%%%%%%% ",
|
||||||
|
" %%%###(//////%%%%%%///(%%%%%%% ",
|
||||||
|
" %%%###(//////%%%%%%///(%%%%%%% ",
|
||||||
|
" %%%###(///////////////(%%%%%%% ",
|
||||||
|
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ",
|
||||||
|
" %%%((((((((((((((((((((((((%%% ",
|
||||||
|
" %%%((((((((((((((((((((((((%%% ",
|
||||||
|
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ",
|
||||||
|
" %%% %%% ",
|
||||||
|
" %%%////////////////////////%%% ",
|
||||||
|
" %%% %%% ",
|
||||||
|
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ",
|
||||||
|
" %%%%%%%%%%%%%%%%%%%%%%%%%%%% "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
" %%%%%%%%%%(///////////////////////(%%%%%%% ",
|
||||||
|
" %%%%%%#####(///////////%%%%%%%/////(%%%%%%%%% ",
|
||||||
|
" %%%%%%#####(///////////%%%%%%%/////(%%%%%%%%%% ",
|
||||||
|
" %%%%%%#####(///////////%%%%%%%/////(%%%%%%%%%% ",
|
||||||
|
" %%%%%%#####(///////////%%%%%%%/////(%%%%%%%%%% ",
|
||||||
|
" %%%%%%#####(///////////%%%%%%%/////(%%%%%%%%%% ",
|
||||||
|
" %%%%%%#####(///////////%%%%%%%/////(%%%%%%%%%% ",
|
||||||
|
" %%%%%%#####(///////////////////////(%%%%%%%%%% ",
|
||||||
|
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ",
|
||||||
|
" %%%%%%((((((((((((((((((((((((((((((((((%%%%%% ",
|
||||||
|
" %%%%%%((((((((((((((((((((((((((((((((((%%%%%% ",
|
||||||
|
" %%%%%%((((((((((((((((((((((((((((((((((%%%%%% ",
|
||||||
|
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ",
|
||||||
|
" %%%%%% %%%%%% ",
|
||||||
|
" %%%%%% %%%%%% ",
|
||||||
|
" %%%%%% %%%%%% ",
|
||||||
|
" %%%%%%//////////////////////////////////%%%%%% ",
|
||||||
|
" %%%%%% %%%%%% ",
|
||||||
|
" %%%%%% %%%%%% ",
|
||||||
|
" %%%%%% %%%%%% ",
|
||||||
|
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ",
|
||||||
|
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local w, h = gpu.maxResolution()
|
||||||
|
local devs = component.computer.getDeviceInfo()
|
||||||
|
local gpuInfoStr
|
||||||
|
|
||||||
|
local function getGPUTier()
|
||||||
|
local dp = gpu.maxDepth()
|
||||||
|
if dp == 8 then
|
||||||
|
return 3
|
||||||
|
elseif dp == 4 then
|
||||||
|
return 2
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getModel(desc)
|
||||||
|
local name
|
||||||
|
for _, dev in pairs(devs) do
|
||||||
|
if dev.description == desc then
|
||||||
|
name = dev.product
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
|
||||||
|
local OS = "Unknown"
|
||||||
|
if fs.exists("OS.lua") then
|
||||||
|
OS = "MineOS"
|
||||||
|
elseif fs.exists("/lib/core") then
|
||||||
|
OS = "OpenOS"
|
||||||
|
elseif fs.exists("/root") then
|
||||||
|
OS = "Plan9k"
|
||||||
|
elseif fs.exists("/etc/system/") then
|
||||||
|
OS = "BananaOS"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getParsedUptime()
|
||||||
|
local seconds, minutes, hours = math.floor(computer.uptime()), 0, 0
|
||||||
|
local time = ""
|
||||||
|
if seconds >= 60 then
|
||||||
|
minutes = math.floor(seconds / 60)
|
||||||
|
seconds = seconds % 60
|
||||||
|
end
|
||||||
|
if minutes >= 60 then
|
||||||
|
hours = math.floor(minutes / 60)
|
||||||
|
minutes = minutes % 60
|
||||||
|
end
|
||||||
|
if getGPUTier() == 1 then
|
||||||
|
time = time .. string.format("%02d:%02d:%02d", hours, minutes, seconds)
|
||||||
|
else
|
||||||
|
if hours == 1 then time = hours .. " hour, "
|
||||||
|
elseif hours >= 2 then time = hours .. " hours, "
|
||||||
|
end
|
||||||
|
if minutes == 1 then time = time .. minutes .. " min, "
|
||||||
|
elseif minutes >= 2 then time = time .. minutes .. " mins, "
|
||||||
|
end
|
||||||
|
time = time .. seconds .. " sec"
|
||||||
|
end
|
||||||
|
return time
|
||||||
|
end
|
||||||
|
|
||||||
|
local logo = logos[getGPUTier()]
|
||||||
|
local function addCharacteristics()
|
||||||
|
local cpu, apu = getModel("CPU"), getModel("APU")
|
||||||
|
gpuInfoStr = 8
|
||||||
|
|
||||||
|
logo[2] = logo[2] .. "|OS:|" .. OS
|
||||||
|
logo[3] = logo[3] .. "|Uptime:|" .. getParsedUptime()
|
||||||
|
logo[4] = logo[4] .. "|Architecture:|" .. _VERSION
|
||||||
|
logo[5] = logo[5] .. "|Resolution:|" .. math.floor(w) .. "x" .. math.floor(h)
|
||||||
|
logo[6] = logo[6] .. "|Terminal:|" .. getModel("Text buffer")
|
||||||
|
if cpu ~= nil then logo[7] = logo[7] .. "|CPU:|" .. cpu:sub(0,11) .. ' (' .. cpu:match('%d') .. ' Tier)'
|
||||||
|
elseif apu ~= nil then logo[7] = logo[7] .. "|APU:|" .. apu:sub(0,11) .. ' (' .. apu:match('%d') .. ' Tier)' end
|
||||||
|
for _, dev in pairs(devs) do
|
||||||
|
if dev.description == "Graphics controller" then
|
||||||
|
logo[gpuInfoStr] = logo[gpuInfoStr] .. "|GPU:|" .. dev.product .. ' (' .. dev.product:match('%d') .. ' Tier)'
|
||||||
|
gpuInfoStr = gpuInfoStr + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
logo[gpuInfoStr] = logo[gpuInfoStr] .. "|Memory:|" .. math.floor(computer.totalMemory() / 1024 - computer.freeMemory() / 1024) .. " KB / " .. math.floor(computer.totalMemory() / 1024) .. " KB"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function drawPalette()
|
||||||
|
local palette = {{0x000000, 0x333333}, {0xCC0000, 0xFF0000}, {0x00CC00, 0x00FF00}, {0xCCCC00, 0xFFFF00},
|
||||||
|
{0x0000CC, 0x0000FF}, {0xCC00CC, 0xFF00FF}, {0x00CCCC, 0x00FFFF}, {0xCCCCCC, 0xFFFFFF}}
|
||||||
|
local cur = #logo[1] + 2
|
||||||
|
for _, color in pairs(palette) do
|
||||||
|
gpu.setForeground(color[1])
|
||||||
|
gpu.set(cur, gpuInfoStr + 2, "███")
|
||||||
|
gpu.setForeground(color[2])
|
||||||
|
gpu.set(cur, gpuInfoStr + 3, "███")
|
||||||
|
cur = cur + 3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
gpu.setResolution(w, h)
|
||||||
|
addCharacteristics()
|
||||||
|
gpu.setBackground(0x000000)
|
||||||
|
gpu.fill(1, 1, w, h, " ")
|
||||||
|
|
||||||
|
for i = 1, #logo do
|
||||||
|
local logoLine, tmp, f = {}, {}, false
|
||||||
|
logo[i]:gsub(".", function(c) table.insert(logoLine, c) end)
|
||||||
|
for ii = 1, #logoLine do
|
||||||
|
if f then
|
||||||
|
if string.match(logoLine[ii], "|") then
|
||||||
|
f = false
|
||||||
|
else
|
||||||
|
if string.match(logoLine[ii], ":") then
|
||||||
|
gpu.setForeground(0xffffff)
|
||||||
|
elseif OS == "MineOS" then
|
||||||
|
gpu.setForeground(0x32e3de)
|
||||||
|
elseif OS == "OpenOS" then
|
||||||
|
gpu.setForeground(0x30ff80)
|
||||||
|
elseif OS == "Plan9k" then
|
||||||
|
gpu.setForeground(0xff0000)
|
||||||
|
elseif OS == "BananaOS" then
|
||||||
|
gpu.setForeground(0xffff00)
|
||||||
|
end
|
||||||
|
gpu.set(ii, i, logoLine[ii])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if logoLine[ii] == "%" then
|
||||||
|
if OS == "MineOS" then
|
||||||
|
gpu.setForeground(0x35ffff)
|
||||||
|
elseif OS == "OpenOS" then
|
||||||
|
gpu.setForeground(0x228822)
|
||||||
|
elseif OS == "Plan9k" then
|
||||||
|
gpu.setForeground(0xff0000)
|
||||||
|
elseif OS == "BananaOS" then
|
||||||
|
gpu.setForeground(0xcccc00)
|
||||||
|
end
|
||||||
|
gpu.set(ii, i, logoLine[ii])
|
||||||
|
elseif logoLine[ii] == "/" then
|
||||||
|
gpu.setForeground(0xfffafa)
|
||||||
|
gpu.set(ii, i, logoLine[ii])
|
||||||
|
elseif logoLine[ii] == "#" then
|
||||||
|
gpu.setForeground(0x585858)
|
||||||
|
gpu.set(ii, i, logoLine[ii])
|
||||||
|
elseif logoLine[ii] == "(" then
|
||||||
|
gpu.setForeground(0xc0c0c0)
|
||||||
|
gpu.set(ii, i, logoLine[ii])
|
||||||
|
elseif string.match(logoLine[ii], "|") then
|
||||||
|
f = true
|
||||||
|
else
|
||||||
|
gpu.setForeground(0xffffff)
|
||||||
|
gpu.set(ii, i, logoLine[ii])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
drawPalette()
|
||||||
|
|
||||||
|
if OS == "MineOS" then
|
||||||
|
gpu.set(1, #logo + 2 > 14 and #logo + 2 or 14, 'Press any key to exit.')
|
||||||
|
local evtype
|
||||||
|
while evtype ~= 'key_down' do
|
||||||
|
evtype = computer.pullSignal()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
--require("term").setCursor(1, #logo + 2 > 14 and #logo + 2 or 14)
|
||||||
|
end
|
49
test/boot/scripts/10_components.lua
Normal file
49
test/boot/scripts/10_components.lua
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
local _, _, status, _ = ...
|
||||||
|
|
||||||
|
status(" *- Implementing component functions")
|
||||||
|
|
||||||
|
function package.loaded.component.isAvailable(componentType)
|
||||||
|
if component[componentType] then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function package.loaded.component.get(address, componentType)
|
||||||
|
local comp = package.loaded.component.list(componentType)
|
||||||
|
|
||||||
|
for a,_ in comp do
|
||||||
|
if a == address then
|
||||||
|
return a
|
||||||
|
else
|
||||||
|
local s,e = string.find(a,address)
|
||||||
|
if s == 1 then
|
||||||
|
return a
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil, "no such component"
|
||||||
|
end
|
||||||
|
|
||||||
|
function package.loaded.component.getPrimary(componentType)
|
||||||
|
local prim = component[componentType]
|
||||||
|
if not prim then
|
||||||
|
error(string.format("no primary '%s' available", componentType))
|
||||||
|
end
|
||||||
|
return prim
|
||||||
|
end
|
||||||
|
|
||||||
|
function package.loaded.component.setPrimary(componentType, address)
|
||||||
|
if componentType == "filesystem" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
address = package.loaded.component.get(address:sub(1,5), componentType) -- don't sub
|
||||||
|
package.loaded.component[componentType] = package.loaded.component.proxy(address)
|
||||||
|
end
|
||||||
|
|
||||||
|
local components = package.loaded.component.list()
|
||||||
|
status(" *- Setting primary components")
|
||||||
|
for address, componentType in components do
|
||||||
|
package.loaded.component.setPrimary(componentType,address)
|
||||||
|
end
|
12
test/etc/motd
Normal file
12
test/etc/motd
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||||
|
@ Welcome to BANANA OS. @
|
||||||
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||||
|
|
||||||
|
* The world's greatest OpenComputers
|
||||||
|
operating system. No batteries included
|
||||||
|
|
||||||
|
* It is also in beta.
|
||||||
|
|
||||||
|
To get started, do something.
|
189
test/etc/system/boot.lua
Normal file
189
test/etc/system/boot.lua
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
local loadfile, hcf, rom_invoke = ...
|
||||||
|
|
||||||
|
local computer = computer
|
||||||
|
local component = component
|
||||||
|
local unicode = unicode
|
||||||
|
|
||||||
|
local addr = computer.getBootAddress()
|
||||||
|
|
||||||
|
Journal = {}
|
||||||
|
Journal.journal = {}
|
||||||
|
Journal.call_list = {}
|
||||||
|
function Journal.write(msg)
|
||||||
|
table.insert(Journal.journal, msg)
|
||||||
|
for i=1,#Journal.call_list do
|
||||||
|
Journal.call_list[i](msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function Journal.clear()
|
||||||
|
Journal.Journal = {}
|
||||||
|
end
|
||||||
|
function Journal.attach(func)
|
||||||
|
table.insert(Journal.call_list, func)
|
||||||
|
end
|
||||||
|
|
||||||
|
local ocelot_card = component.proxy(component.list("ocelot",true)())
|
||||||
|
Journal.attach(ocelot_card.log)
|
||||||
|
|
||||||
|
_G._OSVERSION = "BananaOS 2.21.2025 (BETA)"
|
||||||
|
|
||||||
|
-- first things first load up the gpu
|
||||||
|
local screen = component.list("screen", true)()
|
||||||
|
local gpu = component.list("gpu", true)()
|
||||||
|
local w,h
|
||||||
|
if gpu then
|
||||||
|
gpu = component.proxy(gpu)
|
||||||
|
if not gpu.getScreen() then
|
||||||
|
gpu.bind(screen)
|
||||||
|
end
|
||||||
|
w, h = gpu.maxResolution()
|
||||||
|
gpu.setResolution(w, h)
|
||||||
|
gpu.setBackground(0x000000)
|
||||||
|
gpu.setForeground(0xFFFFFF)
|
||||||
|
gpu.fill(1, 1, w, h, " ")
|
||||||
|
end
|
||||||
|
|
||||||
|
gpu.cursor_y = 5
|
||||||
|
local function banner(status_)
|
||||||
|
gpu.setBackground(0xFF0000)
|
||||||
|
gpu.setForeground(0x000000)
|
||||||
|
gpu.fill(1,1, w, 3, " ")
|
||||||
|
gpu.setBackground(0x000000)
|
||||||
|
gpu.setForeground(0xFFFFFF)
|
||||||
|
gpu.fill(2,2, w-2, 1, " ")
|
||||||
|
if not status_ then
|
||||||
|
status_ = ""
|
||||||
|
end
|
||||||
|
gpu.set(2,2, _OSVERSION .. " " .. status_)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function status(message, m2)
|
||||||
|
if gpu then
|
||||||
|
gpu.set(1,gpu.cursor_y, tostring(message))
|
||||||
|
if gpu.cursor_y >= h then
|
||||||
|
gpu.copy(1, 2, w, h - 1, 0, -1)
|
||||||
|
else
|
||||||
|
gpu.cursor_y = gpu.cursor_y + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
banner(m2)
|
||||||
|
end
|
||||||
|
|
||||||
|
gpu.cursor_x = 1
|
||||||
|
|
||||||
|
local function scroll(g)
|
||||||
|
g.copy(1, 2, w, h - 1, 0, -1)
|
||||||
|
g.fill(1,h,w,h," ")
|
||||||
|
end
|
||||||
|
----------------------------------------------
|
||||||
|
function gpu.getCursor()
|
||||||
|
return {["x"]=gpu.cursor_x,["y"]=gpu.cursor_y}
|
||||||
|
end
|
||||||
|
function gpu.setCursor(x,y)
|
||||||
|
if x then
|
||||||
|
gpu.cursor_x = x
|
||||||
|
end
|
||||||
|
if y then
|
||||||
|
gpu.cursor_y = y
|
||||||
|
end
|
||||||
|
return gpu.getCursor()
|
||||||
|
end
|
||||||
|
function gpu.moveCursor(x,y)
|
||||||
|
if x then
|
||||||
|
gpu.cursor_x = gpu.cursor_x + x
|
||||||
|
end
|
||||||
|
if y then
|
||||||
|
gpu.cursor_y = gpu.cursor_y + y
|
||||||
|
end
|
||||||
|
return gpu.getCursor()
|
||||||
|
end
|
||||||
|
----------------------------------------------
|
||||||
|
function print(...)
|
||||||
|
if gpu then
|
||||||
|
local args = table.pack(...)
|
||||||
|
for i=1,#args do
|
||||||
|
args[i] = tostring(args[i])
|
||||||
|
for j=1, #args[i] do
|
||||||
|
local letter = args[i]:sub(j,j)
|
||||||
|
if letter == "\r" then
|
||||||
|
gpu.cursor_x = 1
|
||||||
|
elseif letter == "\n" then
|
||||||
|
gpu.cursor_x = 1
|
||||||
|
gpu.cursor_y = gpu.cursor_y + 1
|
||||||
|
else
|
||||||
|
gpu.set(gpu.cursor_x,gpu.cursor_y, letter)
|
||||||
|
|
||||||
|
gpu.cursor_x = gpu.cursor_x + 1
|
||||||
|
|
||||||
|
if gpu.cursor_x > w then
|
||||||
|
gpu.cursor_y = gpu.cursor_y + 1
|
||||||
|
gpu.cursor_x = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if gpu.cursor_y > h then
|
||||||
|
gpu.cursor_y = gpu.cursor_y - 1
|
||||||
|
scroll(gpu)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
status("Initializing packages", "package")
|
||||||
|
local package = loadfile("/lib/package.lua")(loadfile)
|
||||||
|
|
||||||
|
_G.component = nil
|
||||||
|
_G.computer = nil
|
||||||
|
_G.unicode = nil
|
||||||
|
_G.package = package
|
||||||
|
|
||||||
|
package.loaded.component = component
|
||||||
|
package.loaded.computer = computer
|
||||||
|
package.loaded.unicode = unicode
|
||||||
|
package.loaded.filesystem = loadfile("/lib/filesystem.lua")(false)
|
||||||
|
|
||||||
|
function AlignString(String,Number,append)
|
||||||
|
if not append then
|
||||||
|
append = " "
|
||||||
|
end
|
||||||
|
String = tostring(String)
|
||||||
|
if #String > Number then
|
||||||
|
while #String > Number do
|
||||||
|
String = String:sub(1, -2)
|
||||||
|
end
|
||||||
|
String = String:sub(1, -5) .. "..."
|
||||||
|
end
|
||||||
|
if #String < Number then
|
||||||
|
while #String < Number do
|
||||||
|
String = String .. append
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return String
|
||||||
|
end
|
||||||
|
|
||||||
|
status("Running boot scripts")
|
||||||
|
|
||||||
|
local scripts = {}
|
||||||
|
for _, file in ipairs(rom_invoke(addr, "list", "/boot/scripts/")) do
|
||||||
|
local path = "/boot/scripts/" .. file
|
||||||
|
if not rom_invoke(addr, "isDirectory", path) then
|
||||||
|
table.insert(scripts, path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.sort(scripts)
|
||||||
|
|
||||||
|
for i = 1, #scripts do
|
||||||
|
status(" -"..scripts[i], string.format("scripts (%s/%s)",i,#scripts))
|
||||||
|
loadfile(scripts[i])(loadfile, rom_invoke, status, banner)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
status("Mounting directories", "mounting")
|
||||||
|
local fs = require("filesystem")
|
||||||
|
fs.mount(computer.getBootAddress(),"/")
|
||||||
|
if computer.tmpAddress() then
|
||||||
|
fs.mount(computer.tmpAddress(), "/tmp/")
|
||||||
|
end
|
3
test/etc/system/system.cfg
Normal file
3
test/etc/system/system.cfg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
["test"] = "test"
|
||||||
|
}
|
0
test/home/.bshrc
Normal file
0
test/home/.bshrc
Normal file
24
test/home/filesystem_tests.lua
Normal file
24
test/home/filesystem_tests.lua
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
local fs = require("filesystem")
|
||||||
|
|
||||||
|
local tests = {
|
||||||
|
{["expected"]="/", ["value"]="/testFile"},
|
||||||
|
{["expected"]="/tmp/",["value"]="/tmp/ggg"},
|
||||||
|
{["expected"]="/tmp/",["value"]="/tmp/this/is/a/long/path"},
|
||||||
|
{["expected"]="/", ["value"]="/home/tmp/tmp"},
|
||||||
|
{["expected"]="/tmp/",["value"]="/tmp/"},
|
||||||
|
{["expected"]=false,["value"]="mnt/"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i=1, #tests do
|
||||||
|
local result = fs.findNode(tests[i].value)
|
||||||
|
if result == false then
|
||||||
|
print(string.format("Failed! Expected : %s got : %s\r\n",AlignString(tests[i].expected,16),result))
|
||||||
|
else
|
||||||
|
result = tostring(result.path)
|
||||||
|
if result == tests[i].expected then
|
||||||
|
print(string.format("Success! Expected : %s got : %s\r\n",AlignString(tests[i].expected,16),result))
|
||||||
|
else
|
||||||
|
print(string.format("Failed! Expected : %s got : %s\r\n",AlignString(tests[i].expected,16),result))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
11
test/home/test.lua
Normal file
11
test/home/test.lua
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
local fs = require("filesystem")
|
||||||
|
|
||||||
|
local a = fs.open("/tmp/test.txt", "w")
|
||||||
|
fs.write(a,"error(\"awesome!\")")
|
||||||
|
fs.close(a)
|
||||||
|
|
||||||
|
fs.makeDirectory("/tmp/awesome/")
|
||||||
|
|
||||||
|
local a = fs.open("/tmp/awesome/abcd", "w")
|
||||||
|
fs.write(a,"error(\"what!!!\")")
|
||||||
|
fs.close(a)
|
35
test/init.lua
Normal file
35
test/init.lua
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
local addr = computer.getBootAddress()
|
||||||
|
local _component = component -- gets overridden later
|
||||||
|
local function loadfile(file)
|
||||||
|
local handle = assert(_component.invoke(addr, "open", file))
|
||||||
|
local buffer = ""
|
||||||
|
|
||||||
|
repeat
|
||||||
|
local data = _component.invoke(addr, "read", handle, math.maxinteger or math.huge)
|
||||||
|
buffer = buffer .. (data or "")
|
||||||
|
until not data
|
||||||
|
|
||||||
|
_component.invoke(addr, "close", handle)
|
||||||
|
return load(buffer, "=" .. file, "bt", _G)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function hcf()
|
||||||
|
local ts = os.time()
|
||||||
|
while 1 do
|
||||||
|
if os.time() - ts >= 0.5 then
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function rom_invoke(a, m, ...)
|
||||||
|
return _component.invoke(a, m, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
loadfile("/etc/system/boot.lua")(loadfile, hcf, rom_invoke)
|
||||||
|
--if loadfile("/sbin/de.lua")() == 0 then -- success
|
||||||
|
-- computer.shutdown()
|
||||||
|
--else
|
||||||
|
loadfile("/sbin/bsh.lua")(loadfile)
|
||||||
|
--end
|
44
test/lib/event.lua
Normal file
44
test/lib/event.lua
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
_G.event = {}
|
||||||
|
local computer = require("computer")
|
||||||
|
|
||||||
|
function event.pull(name, timeout)
|
||||||
|
local rawSignal = {}
|
||||||
|
local signals_recieved_in_mean_time = {}
|
||||||
|
local timeouts = 0
|
||||||
|
if not timeout then
|
||||||
|
timeout = 99999999999
|
||||||
|
end
|
||||||
|
|
||||||
|
while rawSignal[1] ~= name do
|
||||||
|
-- pull any signal
|
||||||
|
rawSignal = table.pack(computer.pullSignal(0.1))
|
||||||
|
|
||||||
|
-- if no signal then add to time timeout
|
||||||
|
if rawSignal[1] == nil then
|
||||||
|
timeouts = timeouts + 0.1
|
||||||
|
else
|
||||||
|
if rawSignal[1] ~= name then
|
||||||
|
-- not the signal, push to the signals we got in the mean time
|
||||||
|
table.insert(signals_recieved_in_mean_time,rawSignal)
|
||||||
|
else
|
||||||
|
-- got the signal
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if timeouts >= timeout then
|
||||||
|
-- we never got the signal :(
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- rethrow all signals... they weren't what we wanted
|
||||||
|
if #signals_recieved_in_mean_time > 0 then
|
||||||
|
for i in ipairs(signals_recieved_in_mean_time) do
|
||||||
|
computer.pushSignal(table.unpack(signals_recieved_in_mean_time[i]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return table.unpack(rawSignal)
|
||||||
|
end
|
||||||
|
|
||||||
|
return event
|
175
test/lib/filesystem.lua
Normal file
175
test/lib/filesystem.lua
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
local debug = ...
|
||||||
|
|
||||||
|
local filesystem = {}
|
||||||
|
local component = require("component")
|
||||||
|
local computer = require("computer")
|
||||||
|
local mounts = {}
|
||||||
|
|
||||||
|
--false if file, true if dir
|
||||||
|
local function isFileOrDir(path)
|
||||||
|
return (string.sub(path, -1) == "/")
|
||||||
|
end
|
||||||
|
local function removeFilename(path) -- this sucks
|
||||||
|
local t = {}
|
||||||
|
local s = ""
|
||||||
|
|
||||||
|
for i in string.gmatch(path, "[^/]+") do
|
||||||
|
table.insert(t,i)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.remove(t,#t)
|
||||||
|
|
||||||
|
if #t == 0 then
|
||||||
|
return "/"
|
||||||
|
end
|
||||||
|
for i=1,#t do
|
||||||
|
s = s .. t[i] .. "/"
|
||||||
|
end
|
||||||
|
if s:sub(1,1) ~= "/" then
|
||||||
|
s = "/" .. s
|
||||||
|
end
|
||||||
|
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
local function log(msg,d)
|
||||||
|
if d then
|
||||||
|
if debug then
|
||||||
|
Journal.write(msg)
|
||||||
|
end
|
||||||
|
elseif not d then
|
||||||
|
Journal.write(msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Mount/node handling
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function filesystem.findNode(path,skipFileDirCheck)
|
||||||
|
--go through mounts
|
||||||
|
-- abc - / 1st iteration, does match
|
||||||
|
-- def - /mnt 2nd iteration, matches better
|
||||||
|
if not skipFileDirCheck then
|
||||||
|
if not isFileOrDir(path) then
|
||||||
|
path = removeFilename(path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local candidate = nil
|
||||||
|
local lastNum = 0
|
||||||
|
for i=1, #mounts do
|
||||||
|
local s,e = string.find(path,mounts[i].path)
|
||||||
|
log(string.format(" [FILESYSTEM.findNode] s:%s e:%s path:%s candidate:%s lastNum:%s - tagainst %s, is id %s",s,e,path,candidate,lastNum,mounts[i].path,mounts[i].disk.address or "n/a"), true)
|
||||||
|
if e == nil then
|
||||||
|
e = 0
|
||||||
|
end
|
||||||
|
if e > lastNum and s == 1 then
|
||||||
|
candidate = mounts[i]
|
||||||
|
lastNum = e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if lastNum == 0 then
|
||||||
|
log(" [FILESYSTEM.findNode] failed", true)
|
||||||
|
return false, "did not find any matching"
|
||||||
|
else
|
||||||
|
log(" [FILESYSTEM.findNode] candidate has addr "..candidate.disk.address, true)
|
||||||
|
return candidate, nil, lastNum
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function filesystem.mount(disk, path)
|
||||||
|
log(string.format(" [FILESYSTEM] mounting %sas %s", AlignString(disk,7),path),false)
|
||||||
|
-- check if disk exists
|
||||||
|
|
||||||
|
if component.get(disk, "filesystem") then
|
||||||
|
table.insert(mounts, {
|
||||||
|
["disk"]=component.proxy(disk),
|
||||||
|
["path"]=path
|
||||||
|
})
|
||||||
|
return mounts[#mounts]
|
||||||
|
else
|
||||||
|
log(string.format(" [FILESYSTEM] drive does not exist", false))
|
||||||
|
return nil, "no filesystem at address"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- File operations
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function filesystem.open(path, mode)
|
||||||
|
local mount,reason,lastNum = filesystem.findNode(path)
|
||||||
|
assert(mount,reason)
|
||||||
|
local id = mount.disk.open(path:sub(lastNum),mode)
|
||||||
|
assert(id, string.format("id is '%s', not a handle, when opening '%s' (actually '%s') as '%s'",id,path,path:sub(lastNum),mode))
|
||||||
|
return {["id"]=id,["disk"]=mount}
|
||||||
|
end
|
||||||
|
|
||||||
|
function filesystem.write(handle, data)
|
||||||
|
handle.disk.disk.write(handle.id,data)
|
||||||
|
end
|
||||||
|
|
||||||
|
function filesystem.read(handle,count)
|
||||||
|
if count == nil then
|
||||||
|
count = math.maxinteger or math.huge
|
||||||
|
end
|
||||||
|
local buffer = ""
|
||||||
|
|
||||||
|
repeat
|
||||||
|
local data = handle.disk.disk.read(handle.id, count)
|
||||||
|
buffer = buffer .. (data or "")
|
||||||
|
until not data
|
||||||
|
|
||||||
|
return buffer
|
||||||
|
end
|
||||||
|
|
||||||
|
function filesystem.close(handle)
|
||||||
|
return handle.disk.disk.close(handle.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Directory operations
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function filesystem.makeDirectory(path)
|
||||||
|
local addr,reason,lastNum = filesystem.findNode(path,true)
|
||||||
|
assert(addr, reason)
|
||||||
|
|
||||||
|
return addr.disk.makeDirectory(path:sub(lastNum))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Misc
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function filesystem.exists(path)
|
||||||
|
local addr,reason,lastNum = filesystem.findNode(path)
|
||||||
|
assert(addr, reason)
|
||||||
|
|
||||||
|
if addr.disk.isDirectory(path:sub(lastNum)) or
|
||||||
|
addr.disk.exists(path:sub(lastNum)) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function filesystem.loadfile(path, workspace)
|
||||||
|
local handle = filesystem.open(path, "r")
|
||||||
|
local data = filesystem.read(handle)
|
||||||
|
filesystem.close(handle)
|
||||||
|
if workspace == nil then
|
||||||
|
return load(data, "=" .. path, "bt", _G)
|
||||||
|
else
|
||||||
|
return load(data, "=" .. path, "bt", workspace)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function filesystem.getlisting(path) -- handle.disk.files[path]
|
||||||
|
local mount,reason,lastNum = filesystem.findNode(path)
|
||||||
|
assert(mount, reason)
|
||||||
|
return mount.disk.list(path:sub(lastNum))
|
||||||
|
end
|
||||||
|
|
||||||
|
return filesystem
|
223
test/lib/filesystem.lua.old
Normal file
223
test/lib/filesystem.lua.old
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
local debug = ...
|
||||||
|
|
||||||
|
local filesystem = {}
|
||||||
|
local component = require("component")
|
||||||
|
local computer = require("computer")
|
||||||
|
local mounts = {}
|
||||||
|
|
||||||
|
--false if file, true if dir
|
||||||
|
local function isFileOrDir(path)
|
||||||
|
return (string.sub(path, -1) == "/")
|
||||||
|
end
|
||||||
|
local function removeFilename(path) -- this sucks
|
||||||
|
local t = {}
|
||||||
|
local s = ""
|
||||||
|
|
||||||
|
for i in string.gmatch(path, "[^/]+") do
|
||||||
|
table.insert(t,i)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.remove(t,#t)
|
||||||
|
|
||||||
|
if #t == 0 then
|
||||||
|
return "/"
|
||||||
|
end
|
||||||
|
for i=1,#t do
|
||||||
|
s = s .. t[i] .. "/"
|
||||||
|
end
|
||||||
|
if s:sub(1,1) ~= "/" then
|
||||||
|
s = "/" .. s
|
||||||
|
end
|
||||||
|
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
local function log(msg,d)
|
||||||
|
if d then
|
||||||
|
if debug then
|
||||||
|
Journal.write(msg)
|
||||||
|
end
|
||||||
|
elseif not d then
|
||||||
|
Journal.write(msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Mount/node handling
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function filesystem.findNode(path)
|
||||||
|
--go through mounts
|
||||||
|
-- abc - / 1st iteration, does match
|
||||||
|
-- def - /mnt 2nd iteration, matches better
|
||||||
|
|
||||||
|
if not isFileOrDir(path) then
|
||||||
|
path = removeFilename(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
local candidate = nil
|
||||||
|
local lastNum = 0
|
||||||
|
for i=1, #mounts do
|
||||||
|
local s,e = string.find(path,mounts[i].path)
|
||||||
|
log(string.format(" [FILESYSTEM.findNode] s:%s e:%s path:%s candidate:%s lastNum:%s - tagainst %s, is id %s",s,e,path,candidate,lastNum,mounts[i].path,mounts[i].disk.address or "n/a"), true)
|
||||||
|
if e == nil then
|
||||||
|
e = 0
|
||||||
|
end
|
||||||
|
if e > lastNum and s == 1 then
|
||||||
|
candidate = mounts[i]
|
||||||
|
lastNum = e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if lastNum == 0 then
|
||||||
|
log(" [FILESYSTEM.findNode] failed", true)
|
||||||
|
return false, "did not find any matching"
|
||||||
|
else
|
||||||
|
log(" [FILESYSTEM.findNode] candidate has addr "..candidate.disk.address, true)
|
||||||
|
return candidate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function filesystem.mount(disk, path)
|
||||||
|
log(string.format(" [FILESYSTEM] mounting %sas %s", AlignString(disk,7),path),false)
|
||||||
|
|
||||||
|
if disk == nil then
|
||||||
|
table.insert(mounts, {
|
||||||
|
["disk"]={["address"]="n/a"},
|
||||||
|
["path"]=path,
|
||||||
|
["isVirtual"]=true,
|
||||||
|
["files"]={}, -- {[path] = data}
|
||||||
|
["handles"]={}
|
||||||
|
})
|
||||||
|
log(" [FILESYSTEM] drive is virtual")
|
||||||
|
return mounts
|
||||||
|
end
|
||||||
|
|
||||||
|
-- check if disk exists
|
||||||
|
|
||||||
|
if component.get(disk, "filesystem") then
|
||||||
|
table.insert(mounts, {
|
||||||
|
["disk"]=component.proxy(disk),
|
||||||
|
["path"]=path,
|
||||||
|
["isVirtual"]=false
|
||||||
|
})
|
||||||
|
return mounts[#mounts]
|
||||||
|
else
|
||||||
|
log(string.format(" [FILESYSTEM] drive does not exist", false))
|
||||||
|
return nil, "no filesystem at address"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- File operations
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function filesystem.open(path, mode)
|
||||||
|
local mount, reason = filesystem.findNode(path)
|
||||||
|
assert(mount,reason)
|
||||||
|
if mount.isVirtual then
|
||||||
|
table.insert(mount.handles,{
|
||||||
|
["path"] = path,
|
||||||
|
["mode"] = mode,
|
||||||
|
["ptr"] = 1
|
||||||
|
})
|
||||||
|
return {["id"]=#mount.handles,["disk"]=mount}
|
||||||
|
else --untested
|
||||||
|
local id = mount.disk.open(path,mode)
|
||||||
|
assert(id, string.format("id is '%s', not a handle, when opening '%s' as '%s'",id,path,mode))
|
||||||
|
return {["id"]=id,["disk"]=mount}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function filesystem.write(handle, data)
|
||||||
|
if handle.disk.isVirtual then
|
||||||
|
local mode = handle.disk.handles[handle.id].mode
|
||||||
|
local path = handle.disk.handles[handle.id].path
|
||||||
|
if mode == "a" or mode == "ab" then
|
||||||
|
error("not implemented")
|
||||||
|
elseif mode == "w" or mode == "wb" then
|
||||||
|
handle.disk.files[path] = data
|
||||||
|
return
|
||||||
|
else
|
||||||
|
error(string.format("mode '%s' not understood",mode))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
handle.disk.disk.write(handle.id,data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function filesystem.read(handle,count)
|
||||||
|
if count == nil then
|
||||||
|
count = math.maxinteger or math.huge
|
||||||
|
end
|
||||||
|
if handle.disk.isVirtual then
|
||||||
|
local d = handle.disk
|
||||||
|
local a = d.files[d.handles[handle.id].path]
|
||||||
|
:sub(d.handles[handle.id].ptr,d.handles[handle.id].ptr+count-1)
|
||||||
|
d.handles[handle.id].ptr = d.handles[handle.id].ptr +count
|
||||||
|
return a
|
||||||
|
else --untested
|
||||||
|
local buffer = ""
|
||||||
|
|
||||||
|
repeat
|
||||||
|
local data = handle.disk.disk.read(handle.id, count)
|
||||||
|
buffer = buffer .. (data or "")
|
||||||
|
until not data
|
||||||
|
|
||||||
|
return buffer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function filesystem.close(handle)
|
||||||
|
if handle.disk.isVirtual then
|
||||||
|
handle.disk.handles[handle.id] = nil
|
||||||
|
return
|
||||||
|
else --untested
|
||||||
|
return handle.disk.disk.close(handle.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Misc
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function filesystem.exists(path) -- weird, doesnt w
|
||||||
|
local addr = filesystem.findNode(path)
|
||||||
|
if addr == nil then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if addr.disk.isDirectory(path) or
|
||||||
|
addr.disk.exists(path) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function filesystem.loadfile(path, workspace)
|
||||||
|
local handle = filesystem.open(path, "r")
|
||||||
|
local data = filesystem.read(handle)
|
||||||
|
filesystem.close(handle)
|
||||||
|
if workspace == nil then
|
||||||
|
return load(data, "=" .. path, "bt", _G)
|
||||||
|
else
|
||||||
|
return load(data, "=" .. path, "bt", workspace)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function filesystem.getlisting(path) -- handle.disk.files[path]
|
||||||
|
local mount, reason = filesystem.findNode(path)
|
||||||
|
assert(mount, reason)
|
||||||
|
if mount.isVirtual then
|
||||||
|
local a = {}
|
||||||
|
print(#mount.files)
|
||||||
|
for b=1, #mount.files do
|
||||||
|
error(b)
|
||||||
|
table.insert(a, mount.files[b]:gmatch("[^/]+"))
|
||||||
|
end
|
||||||
|
print(a[1])
|
||||||
|
else
|
||||||
|
return mount.disk.list(path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return filesystem
|
40
test/lib/package.lua
Normal file
40
test/lib/package.lua
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
local loadfile = ...
|
||||||
|
local package = {}
|
||||||
|
|
||||||
|
local loaded = {
|
||||||
|
["_G"] = _G,
|
||||||
|
["bit32"] = bit32,
|
||||||
|
["coroutine"] = coroutine,
|
||||||
|
["math"] = math,
|
||||||
|
["os"] = os,
|
||||||
|
["package"] = package,
|
||||||
|
["string"] = string,
|
||||||
|
["table"] = table,
|
||||||
|
}
|
||||||
|
local pkg_path = "/lib/?.lua"
|
||||||
|
package.loaded = loaded
|
||||||
|
|
||||||
|
function package.search(file,path)
|
||||||
|
for path in path:gmatch("[^;]+") do
|
||||||
|
local possible = path:gsub("%?", file)
|
||||||
|
local s, _ = pcall(loadfile, possible)
|
||||||
|
if s then
|
||||||
|
return possible
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function require(module)
|
||||||
|
if package.loaded[module] then
|
||||||
|
return package.loaded[module]
|
||||||
|
else
|
||||||
|
local path = package.search(module,pkg_path)
|
||||||
|
assert(path, "module not found")
|
||||||
|
local mod = loadfile(path)()
|
||||||
|
package.loaded[module] = mod
|
||||||
|
return mod
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return package
|
204
test/sbin/bsh.lua
Normal file
204
test/sbin/bsh.lua
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
local bsh = {}
|
||||||
|
local component = require("component")
|
||||||
|
local computer = require("computer")
|
||||||
|
local event = require("event")
|
||||||
|
local fs = require("filesystem")
|
||||||
|
local package = require("package")
|
||||||
|
_G.ExecPath = "/sbin/?.lua;/bin/?.lua"
|
||||||
|
|
||||||
|
if fs.exists("/etc/motd") then
|
||||||
|
local motd_h = fs.open("/etc/motd", "r")
|
||||||
|
print(fs.read(motd_h))
|
||||||
|
fs.close(motd_h)
|
||||||
|
end
|
||||||
|
|
||||||
|
print("\n")
|
||||||
|
|
||||||
|
-- BUG: when in /bin directory, running something tries to run /binhello.lua
|
||||||
|
-- FEAT: autofill slashes, and .lua
|
||||||
|
-- FEAT: handle ..
|
||||||
|
|
||||||
|
bsh.running = true
|
||||||
|
local cwd = "/home/"
|
||||||
|
|
||||||
|
local function keyin(timeout)
|
||||||
|
while true do
|
||||||
|
local _,_,ascii,code,_ = event.pull("key_down",timeout)
|
||||||
|
return ascii,code
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function bsh.split(str)
|
||||||
|
local words = {}
|
||||||
|
for word in str:gmatch("%S+") do
|
||||||
|
table.insert(words, word)
|
||||||
|
end
|
||||||
|
return words
|
||||||
|
end
|
||||||
|
|
||||||
|
function bsh.is_in_arr(arr,elem)
|
||||||
|
for i in ipairs(arr) do
|
||||||
|
if tostring(arr[i]) == tostring(elem) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function bsh.command(buffer)
|
||||||
|
if #buffer == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local command = bsh.split(buffer)
|
||||||
|
if command[1] == "ls" then
|
||||||
|
local cwdls
|
||||||
|
if command[2] == nil then
|
||||||
|
cwdls = fs.getlisting(cwd)
|
||||||
|
else
|
||||||
|
cwdls = fs.getlisting(command[2])
|
||||||
|
end
|
||||||
|
if cwdls ~= nil then
|
||||||
|
for i = 1, #cwdls do
|
||||||
|
print(cwdls[i] .. " ")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print("(Nothing here!)")
|
||||||
|
end
|
||||||
|
print("\r\n")
|
||||||
|
elseif command[1] == "cd" then
|
||||||
|
if command[2] == nil then
|
||||||
|
error("no argument")
|
||||||
|
else
|
||||||
|
cwd = command[2]
|
||||||
|
end
|
||||||
|
elseif command[1] == "clear" then
|
||||||
|
local w,h=component.gpu.getResolution()
|
||||||
|
component.gpu.fill(1,1,w,h," ")
|
||||||
|
component.gpu.setCursor(2,1)
|
||||||
|
elseif command[1] == "exit" then
|
||||||
|
bsh.running = false
|
||||||
|
else -- execute file, this sucks tho
|
||||||
|
local location = command[1]
|
||||||
|
local s,_ = pcall(fs.loadfile,location)
|
||||||
|
-- is in cwd?
|
||||||
|
if not s then
|
||||||
|
if bsh.is_in_arr(fs.getlisting(cwd),command[1]) then
|
||||||
|
location = cwd .. command[1]
|
||||||
|
else
|
||||||
|
-- no, check path
|
||||||
|
local a = package.search(command[1],ExecPath)
|
||||||
|
if a ~= false then
|
||||||
|
location = a
|
||||||
|
else
|
||||||
|
error("command not found")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local a = fs.loadfile(location)
|
||||||
|
a(command)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function prompt()
|
||||||
|
print(cwd .." #> ")
|
||||||
|
end
|
||||||
|
|
||||||
|
print("bsh v3\n")
|
||||||
|
|
||||||
|
local buffer = ""
|
||||||
|
local gpu = component.gpu
|
||||||
|
|
||||||
|
prompt()
|
||||||
|
|
||||||
|
local cursor = "█"
|
||||||
|
local cursorOnOff = 1
|
||||||
|
local history = {}
|
||||||
|
local history_index = 1
|
||||||
|
|
||||||
|
while bsh.running do
|
||||||
|
local nextkeycode, code = keyin()
|
||||||
|
local charAtCurLocation = " "
|
||||||
|
local cur = gpu.getCursor()
|
||||||
|
--print(nextkeycode,"=",code," ")
|
||||||
|
|
||||||
|
if nextkeycode == nil and code == nil then
|
||||||
|
-- timeout reached, invert cursor
|
||||||
|
cursorOnOff = cursorOnOff * -1
|
||||||
|
if cursorOnOff == 1 then
|
||||||
|
charAtCurLocation = gpu.get(cur.x,cur.y)
|
||||||
|
gpu.set(cur.x,cur.y,cursor)
|
||||||
|
else
|
||||||
|
gpu.set(cur.x,cur.y,charAtCurLocation)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if nextkeycode == 0 or nextkeycode == nil then
|
||||||
|
local preBuffer=buffer
|
||||||
|
if code == 42 then -- shift
|
||||||
|
-- ignore
|
||||||
|
elseif code == 200 then -- up
|
||||||
|
if history[history_index] then
|
||||||
|
buffer = history[history_index]
|
||||||
|
history_index = history_index - 1
|
||||||
|
gpu.setCursor(1)
|
||||||
|
prompt()
|
||||||
|
for i=1,#preBuffer do print(" ") end
|
||||||
|
gpu.setCursor(1)
|
||||||
|
prompt()
|
||||||
|
print(buffer)
|
||||||
|
end
|
||||||
|
elseif code == 208 then -- down
|
||||||
|
if history[history_index+1] then
|
||||||
|
history_index = history_index + 2
|
||||||
|
buffer = history[history_index]
|
||||||
|
gpu.setCursor(1)
|
||||||
|
prompt()
|
||||||
|
for i=1,#preBuffer do print(" ") end
|
||||||
|
gpu.setCursor(1)
|
||||||
|
prompt()
|
||||||
|
print(buffer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
gpu.set(cur.x,cur.y,charAtCurLocation)
|
||||||
|
local nextkey = string.char(nextkeycode)
|
||||||
|
|
||||||
|
if nextkeycode == 13 then --enter
|
||||||
|
table.insert(history, buffer)
|
||||||
|
history_index = #history
|
||||||
|
if cursorOnOff ~= 1 then
|
||||||
|
gpu.set(cur.x,cur.y,charAtCurLocation)
|
||||||
|
end
|
||||||
|
print("\n")
|
||||||
|
local success, reason = xpcall(bsh.command, function(a)
|
||||||
|
return {a, debug.traceback()}
|
||||||
|
end, buffer)
|
||||||
|
|
||||||
|
if not success then
|
||||||
|
if reason then
|
||||||
|
print(reason[1].."\n\n")
|
||||||
|
component.gpu.setForeground(0xff3333)
|
||||||
|
print(reason[2])
|
||||||
|
component.gpu.setForeground(0xffffff)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
buffer = ""
|
||||||
|
nextkeycode = nil
|
||||||
|
print("\n")
|
||||||
|
prompt()
|
||||||
|
elseif nextkeycode == 8 then --backsp
|
||||||
|
if #buffer ~= 0 then
|
||||||
|
buffer = buffer:sub(1, -2)
|
||||||
|
gpu.moveCursor(-1)
|
||||||
|
print(" ")
|
||||||
|
gpu.moveCursor(-1)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
buffer = buffer .. nextkey
|
||||||
|
print(nextkey)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
133
test/sbin/de.lua
Normal file
133
test/sbin/de.lua
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
local component = require("component")
|
||||||
|
local computer = require("computer")
|
||||||
|
local fs = require("filesystem")
|
||||||
|
local event = require("event")
|
||||||
|
|
||||||
|
-- get GPU
|
||||||
|
local gpu = component.proxy(component.list("gpu", true)())
|
||||||
|
|
||||||
|
if gpu == nil then
|
||||||
|
return -1
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local resolution = {}
|
||||||
|
resolution.w, resolution.h = gpu.maxResolution()
|
||||||
|
local bg_color = 0xa2cffe
|
||||||
|
local touch_listeners = {} -- {x start,y start,x end,y end,function to call, with args}
|
||||||
|
local windows = {} -- {WINDOW_NAME,X,Y,WIDTH,HEIGHT}
|
||||||
|
-- local
|
||||||
|
|
||||||
|
gpu.setResolution(resolution.w, resolution.h)
|
||||||
|
|
||||||
|
local function add_touch_listener(xs,ys,xe,ye,call,args)
|
||||||
|
table.insert(touch_listeners, {xs,ys,xe,ye,call,args})
|
||||||
|
return #touch_listeners
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function draw_nav()
|
||||||
|
gpu.setBackground(0xffffff)
|
||||||
|
gpu.setForeground(0xffffff)
|
||||||
|
|
||||||
|
gpu.fill(1, 1, resolution.w, 1, " ")
|
||||||
|
|
||||||
|
gpu.setForeground(0x000000)
|
||||||
|
gpu.setBackground(0xffffff)
|
||||||
|
|
||||||
|
gpu.set(2,1, "@")
|
||||||
|
local totalmem = computer.totalMemory()
|
||||||
|
local freemem = computer.freeMemory()
|
||||||
|
gpu.set(6,1, tostring(totalmem-freemem) .. " b / " .. tostring(totalmem) .. " b")
|
||||||
|
|
||||||
|
gpu.setBackground(bg_color)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw_bg()
|
||||||
|
gpu.setBackground(bg_color)
|
||||||
|
gpu.fill(1, 2, resolution.w, resolution.h, " ")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw_windows()
|
||||||
|
for i = 1, #windows do
|
||||||
|
gpu.setBackground(0x000000)
|
||||||
|
gpu.setForeground(0xffffff)
|
||||||
|
gpu.fill(
|
||||||
|
windows[i][2],
|
||||||
|
windows[i][3]-1,
|
||||||
|
windows[i][2]+windows[i][4],
|
||||||
|
windows[i][3]-1,
|
||||||
|
" "
|
||||||
|
)
|
||||||
|
gpu.set(windows[i][2], windows[i][3]-1, "X | " .. windows[i][1])
|
||||||
|
gpu.setBackground(0xaaaaaa)
|
||||||
|
gpu.fill(
|
||||||
|
windows[i][2],
|
||||||
|
windows[i][3],
|
||||||
|
windows[i][2]+windows[i][4],
|
||||||
|
windows[i][3]+windows[i][5],
|
||||||
|
" "
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function keyin()
|
||||||
|
return event.pull("key_down")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function open_exec_menu(args)
|
||||||
|
gpu.setBackground(0xdadada)
|
||||||
|
gpu.fill(1,3,resolution.w, 1, " ")
|
||||||
|
gpu.setBackground(bg_color)
|
||||||
|
local grab = true
|
||||||
|
local buffer = ""
|
||||||
|
local curr_loc_x = 1
|
||||||
|
while grab do
|
||||||
|
local _,_,next_key = keyin()
|
||||||
|
if next_key == 13 then
|
||||||
|
local result = table.pack(pcall(fs.dofile, buffer))
|
||||||
|
if not result[1] then
|
||||||
|
print(result[2] .. "\n")
|
||||||
|
end
|
||||||
|
buffer = ""
|
||||||
|
curr_loc_x = 1
|
||||||
|
grab = false
|
||||||
|
elseif next_key == 8 then
|
||||||
|
if #buffer ~= 0 then
|
||||||
|
buffer = buffer:sub(1, -2)
|
||||||
|
gpu.set(curr_loc_x-1, 2, " ")
|
||||||
|
curr_loc_x = curr_loc_x - 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
buffer = buffer .. string.char(next_key)
|
||||||
|
gpu.set(curr_loc_x, 2, string.char(next_key))
|
||||||
|
curr_loc_x = curr_loc_x + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
gpu.setBackground(bg_color)
|
||||||
|
gpu.fill(1,2,resolution.w, 3, " ")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
draw_bg()
|
||||||
|
draw_nav()
|
||||||
|
|
||||||
|
|
||||||
|
add_touch_listener(2, 1, 2, 1, open_exec_menu, {})
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local event,uuid,x,y = computer.pullSignal(0.3)
|
||||||
|
if event == "touch" then
|
||||||
|
for i = 1, #touch_listeners do
|
||||||
|
if touch_listeners[i][1] <= x and x <= touch_listeners[i][3] then
|
||||||
|
if touch_listeners[i][2] <= y and y <= touch_listeners[i][4] then
|
||||||
|
touch_listeners[i][5](touch_listeners[i][6])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
draw_nav()
|
||||||
|
draw_windows()
|
||||||
|
end
|
4
test/sbin/free.lua
Normal file
4
test/sbin/free.lua
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
local computer = require("computer")
|
||||||
|
local free = computer.freeMemory()
|
||||||
|
local total = computer.totalMemory()
|
||||||
|
print(string.format("Total%12d\nUsed%13d\nFree%13d\n", total, total - free, free))
|
15
test/sbin/lspci.lua
Normal file
15
test/sbin/lspci.lua
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
local computer = require("computer")
|
||||||
|
|
||||||
|
|
||||||
|
local function getModel(desc)
|
||||||
|
local name
|
||||||
|
for _, dev in pairs(computer.getDeviceInfo()) do
|
||||||
|
if dev.description == desc then
|
||||||
|
name = dev.product
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
|
||||||
|
print(getModel("APU"))
|
Loading…
x
Reference in New Issue
Block a user