Files
Halyde/webinstall.lua
T
2026-06-20 14:25:40 +03:00

309 lines
8.7 KiB
Lua

local io = require("terminal")
local component = require("component")
if not component.isAvailable("internet") then
io.stderr.write("This program requires an internet card to run.")
return
end
local internet = component.internet
local computer = require("computer")
local fs = require("filesystem")
local gpu = component.gpu
local width,height = gpu.getResolution()
local event = require("event")
local keyboard = require("keyboard")
local installLocation
local installAddress
local drives = {}
local driveAddresses = {}
for drive in fs.list("/mnt/") do
local address = component.get(drive:sub(1, 3), "filesystem")
if not component.invoke(address, "isReadOnly") then
table.insert(drives, drive)
table.insert(driveAddresses,address)
end
end
local function reset()
gpu.setBackground(0x000000)
gpu.setForeground(0xFFFFFF)
gpu.fill(1,1,width,height," ")
require("tty").setCursor(1,1)
end
local function chooseDrive()
local driveLabels = {}
for i,drive in ipairs(drives) do
local address = driveAddresses[i]
table.insert(driveLabels,component.invoke(address,"getLabel"))
end
gpu.set(1,1,"Please select a drive to install Halyde to:")
local cur = 1
local function renderItem(idx,cur)
if cur then
gpu.setBackground(0xFFFFFF)
gpu.setForeground(0x000000)
else
gpu.setBackground(0x000000)
gpu.setForeground(0xFFFFFF)
end
gpu.fill(4,2+idx,width-3,1," ")
local label = driveLabels[idx] or "No label"
gpu.set(4,2+idx,label)
gpu.set(4+#label+1,2+idx,driveAddresses[idx]:sub(1,5).."...")
end
local function moveCur(dir)
local ncur = math.max(math.min(cur+dir,#drives),1)
if cur==ncur then return end
renderItem(ncur,true)
renderItem(cur,false)
cur=ncur
end
gpu.fill(2,3,1,#drives,"*")
for i=1,#drives do
renderItem(i,cur==i)
end
while true do
local args = {event.pull("key_down")}
if not args or not args[1] or not args[4] then goto continue end
local key = keyboard.keys[args[4]]
if key=="up" then
moveCur(-1)
elseif key=="down" then
moveCur(1)
elseif key=="right" or key=="enter" then
gpu.setBackground(0x000000)
gpu.setForeground(0xFFFFFF)
gpu.fill(1,1,width,height-1," ")
break
elseif key=="left" or key=="back" then
return false
end
::continue::
end
installLocation = "/mnt/" .. drives[cur]
installAddress = driveAddresses[cur]
return true
end
if #drives == 0 then
io.stderr.write("All drives are read-only.\nHalyde cannot be installed.")
elseif #drives == 1 then
installLocation = "/mnt/" .. drives[1]
installAddress = driveAddresses[1]
end
gpu.fill(1,1,width,height," ")
gpu.setBackground(0xFFFFFF)
gpu.setForeground(0x000000)
gpu.fill(1,height,width,1," ")
gpu.set(1,height,"Halyde Web Installer (OpenOS)")
gpu.setBackground(0x000000)
gpu.setForeground(0xFFFFFF)
if #drives>1 then
if not chooseDrive() then
reset()
return
end
end
if not installLocation then
reset()
io.stderr.write("All drives are read-only.\nHalyde cannot be installed.")
return
end
if width<80 then
gpu.set(1,1,"Are you sure you would like to install Halyde?")
else
gpu.set(1,1,"Are you sure you would like to install Halyde to "..installLocation.."?")
end
gpu.set(1,2,"This will erase all data on this disk.")
gpu.set(1,height-1,"Press Y to accept, or N to cancel.")
gpu.set(3,4,"Capacity: ")
gpu.set(3,5,"Used: ")
gpu.set(3,6,"ID: ")
gpu.set(3,7,"Label: ")
gpu.setForeground(0x00FF00)
if width>=80 then
gpu.set(50,1,installLocation)
end
gpu.set(13,4,math.floor(component.invoke(installAddress,"spaceTotal")/1024).." KiB")
gpu.set(9,5,math.floor(component.invoke(installAddress,"spaceUsed")/1024).." KiB")
gpu.set(7,6,installAddress)
gpu.set(10,7,component.invoke(installAddress,"getLabel") or "No label")
if keyboard.keys[({event.pull("key_down")})[4]]=="n" then
return reset()
end
-- installation
local computer = require("computer")
local function getFile(url)
local request, data, tmpdata = nil, "", nil
local status, errorMessage = pcall(function()
request = internet.request(url)
request:finishConnect()
end)
if not status then
return false, errorMessage
end
local responseCode = request:response()
if responseCode and responseCode ~= 200 then
return false, responseCode
end
repeat
tmpdata = request.read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
return data
end
-- installation graphics
local webInstallConfig
local installationOrder = {"halyde", "edit", "argentum", "webinstall-extras"}
gpu.setBackground(0x000000)
gpu.setForeground(0xFFFFFF)
gpu.fill(1,1,width,height," ")
local function lpad(str, len, char)
str=tostring(str)
if char == nil then char = ' ' end
return string.rep(char, len - #str) .. str
end
local function progress(package,progress)
local total = 0
if webInstallConfig and type(webInstallConfig)=="table" then
for i,pck in ipairs(installationOrder) do
local packConfig = webInstallConfig[pck]
-- print(pck,packConfig)
total=total+#(packConfig.directories or {})+#(packConfig.files or {})
end
else
total=1
end
local info = ""
local realProgress = 1
if type(package)=="string" then
realProgress = progress
info = string.format("%s %s%%",package,lpad(math.floor(progress*100),2))
else
realProgress = 0
for i=1,package do
local packConfig = webInstallConfig[installationOrder[i]]
if i==package then
realProgress=realProgress+progress
else
local value = #(packConfig.directories or {})+#packConfig.files
realProgress=realProgress+value
end
end
realProgress=realProgress/total
local packConfig = webInstallConfig[installationOrder[package]]
progress=progress/(#(packConfig.directories or {})+#packConfig.files)
-- realProgress = (progress+package-1)/#installationOrder
local packInfo = installationOrder[package].." "..lpad(math.floor(progress*100),2).."%"
info = string.format("%s%% [%s]",lpad(math.floor(realProgress*100),2),packInfo)
end
info=info..string.rep(" ",width-#info)
local progX = math.floor(realProgress*width)
gpu.setBackground(0x00FF00)
gpu.setForeground(0x000000)
gpu.set(1,height,info:sub(1,progX))
gpu.setBackground(0x000000)
gpu.setForeground(0xFFFFFF)
gpu.set(progX+1,height,info:sub(progX+1))
end
local logY = 1
local function log(txt)
if logY>=height then
gpu.copy(1,2,width,height-2,0,-1)
gpu.fill(1,height-1,width,1," ")
logY=logY-1
end
gpu.set(1,logY,txt)
logY=logY+1
end
----------------------------
log("Fetching Argentum configuration for Halyde")
progress("Preparing",0)
webInstallConfig = getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/argentum.cfg")
log("Loading Argentum configuration")
progress("Preparing",0.5)
webInstallConfig = load(webInstallConfig)
webInstallConfig = webInstallConfig()
log("Looking for outdated files in the drive")
progress("Preparing",1)
local oldFiles = {}
for oldFile in fs.list(installLocation) do
local usedFlag = false
for i = 1, 3 do
for _, file in pairs(webInstallConfig[installationOrder[i]].files) do
if oldFile == file then
usedFlag = true
end
end
if webInstallConfig[installationOrder[i]].directories then
for _, dir in pairs(webInstallConfig[installationOrder[i]].directories) do
if oldFile == dir .. "/" then
usedFlag = true
end
end
end
end
if oldFile=="halyde/" then usedFlag = true end
if not usedFlag then
table.insert(oldFiles, oldFile)
end
end
log("Found "..#oldFiles)
progress(1,0)
for i = 1, 4 do
local webInstallConfig = webInstallConfig[installationOrder[i]]
local dirCount = 0
if webInstallConfig.directories then
dirCount=#webInstallConfig.directories
for dirIdx, directory in ipairs(webInstallConfig.directories) do
log("Creating " .. directory .. "...")
progress(i,dirIdx-1)
fs.makeDirectory(installLocation .. directory)
end
end
for fileIdx, file in ipairs(webInstallConfig.files) do
log("Downloading " .. file .. "...")
progress(i,fileIdx-1+dirCount)
local handle = fs.open(installLocation .. file, "w")
handle:write(getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/" .. file))
handle:close()
end
end
for i, oldFile in ipairs(oldFiles) do
log("Removing "..oldFile)
progress("Finishing up",(i-1)/#oldFiles*1)
fs.remove(installLocation .. oldFile)
end
log("Setting boot address")
progress("Finishing up",1)
computer.setBootAddress(component.get(installLocation:sub(6, -2)))
log("Setting label to Halyde")
component.invoke(component.get(installLocation:sub(6, -2)), "setLabel", "Halyde")
gpu.fill(1,1,width,height," ")
computer.shutdown(true)