Updated the Halyde web installer to work on read-only floppies, now with a graphical environment
This commit is contained in:
@@ -10,6 +10,7 @@ local agcfg = {
|
|||||||
"halyde/core",
|
"halyde/core",
|
||||||
"halyde/drivers",
|
"halyde/drivers",
|
||||||
"halyde/lib",
|
"halyde/lib",
|
||||||
|
"halyde"
|
||||||
"home",
|
"home",
|
||||||
"mnt"
|
"mnt"
|
||||||
},
|
},
|
||||||
|
|||||||
+213
-67
@@ -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
|
||||||
|
local address = component.get(drive:sub(1, 3), "filesystem")
|
||||||
|
if not component.invoke(address, "isReadOnly") then
|
||||||
table.insert(drives, drive)
|
table.insert(drives, drive)
|
||||||
|
table.insert(driveAddresses,address)
|
||||||
end
|
end
|
||||||
if #drives == 1 and not component.invoke(component.get(drives[1]:sub(1, 3), "filesystem"), "isReadOnly") then
|
end
|
||||||
installLocation = "/mnt/" .. drives[1]
|
|
||||||
elseif #drives == 1 then
|
local function reset()
|
||||||
io.stderr.write("All drives are read-only.\nHalyde cannot be installed.")
|
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
|
else
|
||||||
local installDrivesText = "Possible drives to install to:"
|
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
|
for i=1,#drives do
|
||||||
local address = component.get(drives[i]:sub(1, 3), "filesystem")
|
renderItem(i,cur==i)
|
||||||
local fsComponent = component.proxy(address)
|
|
||||||
if not fsComponent.isReadOnly() then
|
|
||||||
local label = fsComponent.getLabel()
|
|
||||||
if label then
|
|
||||||
installDrivesText = installDrivesText .. "\n " .. tostring(i) .. ". - " .. label .. "(" .. address:sub(1, 5) .. "...)"
|
|
||||||
else
|
|
||||||
installDrivesText = installDrivesText .. "\n " .. tostring(i) .. ". - " .. address:sub(1, 5) .. "..."
|
|
||||||
end
|
end
|
||||||
else
|
|
||||||
table.remove(drives, i)
|
|
||||||
i = i - 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
io.write(installDrivesText .. "\nPlease select a drive by entering its number or \"q\" to quit. ")
|
|
||||||
local answer
|
|
||||||
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 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]
|
||||||
|
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
|
return
|
||||||
else
|
|
||||||
print("Answer invalid, try again.")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
installLocation = "/mnt/" .. drives[tonumber(answer)]
|
|
||||||
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"
|
|
||||||
|
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
|
end
|
||||||
local handle, data, tmpdata = fs.open(path, "r"), "", nil
|
|
||||||
repeat
|
|
||||||
tmpdata = handle:read(math.huge)
|
|
||||||
data = data .. (tmpdata or "")
|
|
||||||
until not tmpdata
|
|
||||||
handle:close()
|
|
||||||
return data
|
|
||||||
else
|
else
|
||||||
local request, data, tmpdata = nil, "", nil
|
total=1
|
||||||
local status, errorMessage = pcall(function()
|
|
||||||
request = internet.request(path)
|
|
||||||
request:finishConnect()
|
|
||||||
end)
|
|
||||||
if not status then
|
|
||||||
return false, errorMessage
|
|
||||||
end
|
end
|
||||||
local responseCode = request:response()
|
|
||||||
if responseCode and responseCode ~= 200 then
|
local info = ""
|
||||||
return false, responseCode
|
local realProgress = 1
|
||||||
end
|
if type(package)=="string" then
|
||||||
repeat
|
realProgress = progress
|
||||||
tmpdata = request.read(math.huge)
|
info = string.format("%s %s%%",package,lpad(math.floor(progress*100),2))
|
||||||
data = data .. (tmpdata or "")
|
else
|
||||||
until not tmpdata
|
realProgress = 0
|
||||||
return data
|
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
|
||||||
end
|
end
|
||||||
local webInstallConfig = getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/argentum.cfg")
|
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)
|
||||||
|
|||||||
Reference in New Issue
Block a user