Updated the Halyde web installer to work on read-only floppies, now with a graphical environment

This commit is contained in:
Ponali
2025-07-11 11:30:52 +02:00
parent 221bd0229e
commit 876e5160df
2 changed files with 221 additions and 74 deletions
+1
View File
@@ -10,6 +10,7 @@ local agcfg = {
"halyde/core", "halyde/core",
"halyde/drivers", "halyde/drivers",
"halyde/lib", "halyde/lib",
"halyde"
"home", "home",
"mnt" "mnt"
}, },
+220 -74
View File
@@ -7,56 +7,142 @@ local internet = component.internet
local computer = require("computer") local computer = require("computer")
local fs = require("filesystem") local fs = require("filesystem")
local gpu = component.gpu local gpu = component.gpu
local width,height = gpu.getResolution()
local event = require("event")
local keyboard = require("keyboard")
local installLocation local installLocation
local installAddress
local drives = {} local drives = {}
local driveAddresses = {}
for drive in fs.list("/mnt/") do for drive in fs.list("/mnt/") do
table.insert(drives, drive) 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 end
if #drives == 1 and not component.invoke(component.get(drives[1]:sub(1, 3), "filesystem"), "isReadOnly") then
installLocation = "/mnt/" .. drives[1] local function reset()
elseif #drives == 1 then gpu.setBackground(0x000000)
io.stderr.write("All drives are read-only.\nHalyde cannot be installed.") gpu.setForeground(0xFFFFFF)
else gpu.fill(1,1,width,height," ")
local installDrivesText = "Possible drives to install to:" require("tty").setCursor(1,1)
for i = 1, #drives do end
local address = component.get(drives[i]:sub(1, 3), "filesystem")
local fsComponent = component.proxy(address) local function chooseDrive()
if not fsComponent.isReadOnly() then local driveLabels = {}
local label = fsComponent.getLabel() for i,drive in ipairs(drives) do
if label then local address = driveAddresses[i]
installDrivesText = installDrivesText .. "\n " .. tostring(i) .. ". - " .. label .. "(" .. address:sub(1, 5) .. "...)" table.insert(driveLabels,component.invoke(address,"getLabel"))
else
installDrivesText = installDrivesText .. "\n " .. tostring(i) .. ". - " .. address:sub(1, 5) .. "..."
end
else
table.remove(drives, i)
i = i - 1
end
end end
io.write(installDrivesText .. "\nPlease select a drive by entering its number or \"q\" to quit. ")
local answer 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 while true do
answer = io.read() local args = {event.pull("key_down")}
if tonumber(answer) and tonumber(answer) >= 1 and tonumber(answer) <= #drives then 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 break
elseif answer == "q" then elseif key=="left" or key=="back" then
return return false
else
print("Answer invalid, try again.")
end 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]
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
installLocation = "/mnt/" .. drives[tonumber(answer)]
end end
if not installLocation then if not installLocation then
print("All drives are read-only.\nHalyde cannot be installed.") reset()
return io.stderr.write("All drives are read-only.\nHalyde cannot be installed.")
end
io.write("Are you sure you would like to install Halyde to " .. installLocation .. "? This will erase all data on this disk. [Y/n] ")
if io.read():lower() == "n" then
return return
end 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 -- installation
local computer = require("computer") local computer = require("computer")
local function getFile(url) local function getFile(url)
@@ -79,42 +165,86 @@ local function getFile(url)
return data return data
end end
local function getFile(path) -- installation graphics
if path:sub(1,1) == "/" then local webInstallConfig
if not fs.exists(path) then local installationOrder = {"halyde", "edit", "argentum", "webinstall-extras"}
return false, "file does not exist"
end gpu.setBackground(0x000000)
local handle, data, tmpdata = fs.open(path, "r"), "", nil gpu.setForeground(0xFFFFFF)
repeat gpu.fill(1,1,width,height," ")
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "") local function lpad(str, len, char)
until not tmpdata str=tostring(str)
handle:close() if char == nil then char = ' ' end
return data return string.rep(char, len - #str) .. str
else
local request, data, tmpdata = nil, "", nil
local status, errorMessage = pcall(function()
request = internet.request(path)
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
end end
local webInstallConfig = getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/argentum.cfg")
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 = load(webInstallConfig)
webInstallConfig = webInstallConfig() webInstallConfig = webInstallConfig()
local installationOrder = {"halyde", "edit", "argentum", "webinstall-extras"} log("Looking for outdated files in the drive")
progress("Preparing",1)
local oldFiles = {} local oldFiles = {}
for oldFile in fs.list(installLocation) do for oldFile in fs.list(installLocation) do
local usedFlag = false local usedFlag = false
@@ -132,29 +262,45 @@ for oldFile in fs.list(installLocation) do
end end
end end
end end
if oldFile=="halyde/" then usedFlag = true end
if not usedFlag then if not usedFlag then
table.insert(oldFiles, oldFile) table.insert(oldFiles, oldFile)
end end
end end
log("Found "..#oldFiles)
progress(1,0)
for i = 1, 4 do for i = 1, 4 do
local webInstallConfig = webInstallConfig[installationOrder[i]] local webInstallConfig = webInstallConfig[installationOrder[i]]
local dirCount = 0
if webInstallConfig.directories then if webInstallConfig.directories then
for _, directory in pairs(webInstallConfig.directories) do dirCount=#webInstallConfig.directories
print("Creating " .. directory .. "...") for dirIdx, directory in ipairs(webInstallConfig.directories) do
log("Creating " .. directory .. "...")
progress(i,dirIdx-1)
fs.makeDirectory(installLocation .. directory) fs.makeDirectory(installLocation .. directory)
end end
end end
for _, file in pairs(webInstallConfig.files) do for fileIdx, file in ipairs(webInstallConfig.files) do
print("Downloading " .. file .. "...") log("Downloading " .. file .. "...")
progress(i,fileIdx-1+dirCount)
local handle = fs.open(installLocation .. file, "w") local handle = fs.open(installLocation .. file, "w")
handle:write(getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/" .. file)) handle:write(getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/" .. file))
handle:close() handle:close()
end end
end end
for _, oldFile in pairs(oldFiles) do for i, oldFile in ipairs(oldFiles) do
fs.remove(oldFile) log("Removing "..oldFile)
progress("Finishing up",(i-1)/#oldFiles*1)
fs.remove(installLocation .. oldFile)
end end
log("Setting boot address")
progress("Finishing up",1)
computer.setBootAddress(component.get(installLocation:sub(6, -2))) computer.setBootAddress(component.get(installLocation:sub(6, -2)))
log("Setting label to Halyde")
component.invoke(component.get(installLocation:sub(6, -2)), "setLabel", "Halyde") component.invoke(component.get(installLocation:sub(6, -2)), "setLabel", "Halyde")
gpu.fill(1,1,width,height," ")
computer.shutdown(true) computer.shutdown(true)