Skip to content

Instantly share code, notes, and snippets.

@Ocawesome101
Created March 24, 2020 21:59
Show Gist options
  • Save Ocawesome101/02e0bbba21db0b34ab99da630ccc1237 to your computer and use it in GitHub Desktop.
Save Ocawesome101/02e0bbba21db0b34ab99da630ccc1237 to your computer and use it in GitHub Desktop.
Bare-metal installer for the Proton hybrid kernel
-- Proton installer --
---------------------------------- Graphics --------------------------------
local gpu = component.proxy(component.list("gpu")())
gpu.bind(component.list("screen")())
gpu.setResolution(50, 16)
local background = 0x000000
local boxbg = 0xFFFFFF
local boxtext = 0x000000
local bgtext = 0xFFFFFF
local w, h = gpu.getResolution()
local function clear()
gpu.setForeground(bgtext)
gpu.setBackground(background)
gpu.fill(1, 1, w, h, " ")
end
local function bgset(x, y, text)
gpu.setForeground(bgtext)
gpu.setBackground(background)
gpu.set(x, y, text)
end
local function box(x1, y1, x2, y2)
gpu.setBackground(boxbg)
gpu.setForeground(boxtext)
gpu.fill(x1, y1, x2 - x1, y2 - y1, " ")
end
local function bxset(x, y, text)
gpu.setForeground(boxtext)
gpu.setBackground(boxbg)
gpu.set(x, y, text)
end
------------------------- Menu functions -----------------------------
local function basicmenu(x, y, items)
local sel = 1
local function redraw()
for i=1, #items, 1 do
bxset(x, y + i, items[i]:sub(1, w - x) .. (" "):rep(36 - #items[i])) -- cut off items if they're too long
end
bgset(x, y + sel, items[sel]:sub(1, w - x) .. (" "):rep(36 - #items[sel]))
end
repeat
redraw()
local e, _, id, code = computer.pullSignal()
if e == "key_down" then
if code == 200 then -- up arrow
if sel > 1 then
sel = sel - 1
else
sel = #items
end
elseif code == 208 then
if sel < #items then
sel = sel + 1
else
sel = 1
end
end
end
until e == "key_down" and id == 13
return sel
end
local function selectmenu(x, y, items, defaults)
local sel = 1
local selected = {}
for k,v in pairs(defaults) do
selected[v] = true
end
local function redraw()
for i=1, #items, 1 do
local d = (sel == i and bxset) or bgset
if selected[ items[i] ] then
d(x, y + i, "[x] " .. items[i])
else
d(x, y + i, "[ ] " .. items[i])
end
end
end
repeat
redraw()
local e, _, id, code = computer.pullSignal()
if e == "key_down" then
if code == 200 then -- up
if sel > 1 then
sel = sel - 1
else
sel = #items
end
elseif code == 208 then -- down
if sel < #items then
sel = sel + 1
else
sel = 1
end
elseif code == 57 then
selected[ items[sel] ] = (not selected[ items[sel] ])
end
end
until e == "key_down" and id == 13
return selected
end
--------------------------- Internet Card -----------------------------
local inet = component.proxy(component.list("internet")())
if not inet.isHttpEnabled() then
error("HTTP is required!")
end
----------------------------------------------------------------------
-- non-optional packages
local packages = {
"proton-base",
"driver-fs",
"driver-component"
}
--------------------------- FS Selection ------------------------------
local filesystem
local tmpfs
do
clear()
bgset(1, 1, "Detecting filesystems")
local fses = {}
for addr, _ in component.list("filesystem") do
fses[#fses + 1] = addr
if component.invoke(addr, "getLabel") == "tmpfs" then
tmpfs = component.proxy(addr)
end
end
clear()
bgset(1, 1, "Proton Installer: Select medium")
bgset(w - 3, h, "1/5")
box(3, 3, w - 3, h - 3)
bxset(4, 4, "Please choose an installation medium.")
fses[#fses + 1] = "Cancel"
local install = basicmenu(4, 6, fses)
if fses[install] == "Cancel" then
computer.shutdown()
end
filesystem = component.proxy(fses[install])
end
------------------------- Driver Selection -------------------------
local ppmrepo = "https://raw.githubusercontent.com/ocawesome101/proton-packages/master/"
do
local drivers = {
"internet",
"modem",
"sound",
"gpu",
"redstone",
-- These drivers will be added later
--[["3dprinter",
"data",
"eeprom",
"robot"]]
}
clear()
bgset(1, 1, "Proton Installer: Select drivers")
bgset(w - 3, h, "2/5")
box(3, 3, w - 3, h - 3)
bxset(4, 4, "Please select drivers to be installed.")
local selections = selectmenu(4, 6, drivers, {"gpu", "internet"})
for k,v in pairs(selections) do
if v then
packages[#packages + 1] = "driver-" .. k
end
end
end
-------------------------- UI Selection ---------------------------
do
local ifaces = {
"proton-shell",
--"modularity" -- Does NOT work yet
}
clear()
bgset(1, 1, "Proton Installer: Select interface")
bgset(w - 3, h, "3/5")
box(3, 3, w - 3, h - 2)
bxset(4, 4, "Please select a user interface.")
local selections = selectmenu(4, 6, ifaces, {"proton-shell"})
for k,v in pairs(selections) do
if v then
packages[#packages + 1] = k
end
end
end
--- semi-platform-independent port of AdorableCatgirl's uncpio.lua ---
local function uncpio(f)
local file = tmpfs.open(f, "r")
local written = {}
local dent = {
magic = 0,
dev = 0,
ino = 0,
mode = 0,
uid = 0,
gid = 0,
nlink = 0,
rdev = 0,
mtime = 0,
namesize = 0,
filesize = 0,
}
local function readint(amt, rev)
local tmp = 0
for i=(rev and amt) or 1, (rev and 1) or amt, (rev and -1) or 1 do
tmp = tmp | (tmpfs.read(file, 1):byte() << ((i-1)*8))
end
return tmp
end
local function fwrite()
local dir = dent.name:match("(.+)/.*%.?.+")
if (dir) then
filesystem.makeDirectory("/"..dir)
end
local hand = filesystem.open(dent.name, "w")
filesystem.write(hand, tmpfs.read(file, dent.filesize))
filesystem.close(hand)
written[#written + 1] = dent.name
end
while true do
dent.magic = readint(2)
local rev = false
if (dent.magic ~= tonumber("070707", 8)) then rev = true end
dent.dev = readint(2)
dent.ino = readint(2)
dent.mode = readint(2)
dent.uid = readint(2)
dent.gid = readint(2)
dent.nlink = readint(2)
dent.rdev = readint(2)
dent.mtime = (readint(2) << 16) | readint(2)
dent.namesize = readint(2)
dent.filesize = (readint(2) << 16) | readint(2)
local name = tmpfs.read(file, dent.namesize):sub(1, dent.namesize-1)
if (name == "TRAILER!!!") then break end
--for k, v in pairs(dent) do
-- print(k, v)
--end
dent.name = name
-- print(name)
if (dent.namesize % 2 ~= 0) then
tmpfs.seek(file, "cur", 1)
end
if (dent.mode & 32768 ~= 0) then
fwrite()
end
if (dent.filesize % 2 ~= 0) then
tmpfs.seek(file, "cur", 1)
end
end
tmpfs.close(file)
return written
end
------------------ Do the actual installation ------------------
do
clear()
bgset(1, 1, "Proton Installer: Installing packages")
bgset(w - 3, h, "4/5")
box(3, 3, w - 3, h - 3)
local installed = "NAME,AUTHOR,FILES\n"
for i=1, #packages, 1 do
if type(packages[i]) == "number" then
table.remove(packages, i)
end
end
for i=1, #packages, 1 do
local package = packages[i]
bxset(4, 4, "Downloading " .. package .. " ")
bgset(4, 6, (" "):rep(math.floor((i / #package) * (w - 3))))
local raw, err = inet.request(ppmrepo .. package .. ".cpio")
if not raw or not raw.finishConnect() then
bxset(4, 4, "Error downloading " .. package)
else
local file = tmpfs.open(package .. ".cpio", "w")
repeat
local chunk = raw.read(math.huge)
tmpfs.write(file, (chunk or ""))
until not chunk
tmpfs.close(file)
local files = uncpio(package .. ".cpio")
installed = installed .. package .. ",Ocawesome101," .. table.concat(files, ";")
end
end
filesystem.makeDirectory("/sys/ppm/")
local handle = filesystem.open("/sys/ppm/installed.csv", "w")
filesystem.write(handle, installed)
filesystem.close(handle)
end
------------------------- Bye bye! --------------------------
do
clear()
bgset(1, 1, "Proton Installer: Done")
bgset(w - 3, h, "5/5")
box(3, 3, w - 3, h - 3)
if computer.setBootAddress then
computer.setBootAddress(filesystem.address)
end
local lines = {
"The Proton hybrid kernel is now installed",
"on your computer. Additional packages can",
"be installed with the ppm utility.",
"",
"Your system will restart in 5 seconds, or",
"if ENTER is pressed. If present, please",
"remove any installation media now."
}
for i=1, #lines, 1 do
bxset(4, i + 3, lines[i])
end
local dest = computer.uptime() + 5
repeat
local e, _, id = computer.pullSignal(dest - computer.uptime())
until computer.uptime() >= dest or (e == "key_down" and id == 13)
computer.shutdown(true)
end
while true do
computer.pullSignal()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment