mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-11-23 19:08:05 +11:00
dcd7154ec2
This license change should only increase the amount of stuff people can do in countries where the public domain is not a valid concept. If this license somehow restricts you as opposed to the previous one, please file an issue.
382 lines
9.3 KiB
Lua
382 lines
9.3 KiB
Lua
-- Copyright (C) 2018-2021 by KittenOS NEO contributors
|
|
--
|
|
-- Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
|
|
--
|
|
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
-- THIS SOFTWARE.
|
|
|
|
-- app-claw: Package manager.
|
|
|
|
local ldrPkg, _, tgtPkg = ...
|
|
|
|
-- libs & such
|
|
local event = require("event")(neo)
|
|
local neoux = require("neoux")(event, neo)
|
|
|
|
local primaryINet = neo.requestAccess("c.internet")
|
|
if primaryINet then primaryINet = primaryINet.list()() end
|
|
|
|
--
|
|
|
|
local function readFile(src, url, ocb)
|
|
local buf = ""
|
|
local function cb(data)
|
|
if not data then
|
|
ocb(buf)
|
|
else
|
|
buf = buf .. data
|
|
buf = buf:gsub("[^\n]*\n", function (t)
|
|
ocb(t:sub(1, -2))
|
|
return ""
|
|
end)
|
|
end
|
|
end
|
|
if type(src) == "string" then
|
|
assert(primaryINet, "no internet")
|
|
local req, err = primaryINet.request(src .. url)
|
|
assert(req, err)
|
|
-- OpenComputers#535
|
|
req.finishConnect()
|
|
while true do
|
|
local n, n2 = req.read(neo.readBufSize)
|
|
cb(n)
|
|
if not n then
|
|
req.close()
|
|
if n2 then
|
|
error(n2)
|
|
else
|
|
cb(nil)
|
|
break
|
|
end
|
|
else
|
|
if n == "" then
|
|
-- slightly dangerous, but what can we do?
|
|
pcall(event.sleepTo, os.uptime() + 0.05)
|
|
end
|
|
end
|
|
end
|
|
else
|
|
if url == "data/app-claw/local.c2l" then
|
|
for _, v in ipairs(src.list("data/app-claw/")) do
|
|
ocb(v)
|
|
end
|
|
return
|
|
end
|
|
local h, e = src.open(url, "rb")
|
|
assert(h, e)
|
|
repeat
|
|
local c = src.read(h, neo.readBufSize)
|
|
cb(c)
|
|
until not c
|
|
src.close(h)
|
|
end
|
|
end
|
|
|
|
-- Sources
|
|
|
|
local sources = {}
|
|
local sourceList = {}
|
|
-- Use all non-primary filesystems
|
|
local disks = neo.requireAccess("c.filesystem", "searching disks for packages")
|
|
local primaryDisk = disks.primary
|
|
for pass = 1, 3 do
|
|
for v in disks.list() do
|
|
local nam = nil
|
|
if v == primaryDisk then
|
|
nam = (pass == 1) and "local"
|
|
elseif v == disks.temporary then
|
|
nam = (pass == 2) and "ramfs"
|
|
elseif pass == 3 then
|
|
nam = v.address
|
|
end
|
|
if nam then
|
|
sources[nam] = v
|
|
table.insert(sourceList, nam)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- No longer needed
|
|
disks = nil
|
|
|
|
if primaryINet then
|
|
sources["inet"] = "http://20kdc.duckdns.org/neo/"
|
|
table.insert(sourceList, "inet")
|
|
end
|
|
|
|
-- List scanning for package window
|
|
|
|
local function scanList(content)
|
|
local lst = {}
|
|
local lst2 = {}
|
|
for k, v in pairs(sources) do
|
|
local ok, err = pcall(readFile, v, "data/app-claw/local.c2l", function (l)
|
|
if l:sub(-4) == ".c2p" then
|
|
local lt, ltv = l:sub(1, -5)
|
|
ltv = lt:match("%.[0-9]+$")
|
|
if ltv and l:find(content, 1, true) then
|
|
lt = lt:sub(1, -(#ltv + 1))
|
|
lst2[lt] = true
|
|
end
|
|
end
|
|
end)
|
|
if (not ok) and ((k == "inet") or (k == "local")) then
|
|
neoux.startDialog(tostring(err), k)
|
|
end
|
|
end
|
|
for k, v in pairs(lst2) do
|
|
table.insert(lst, k)
|
|
end
|
|
table.sort(lst)
|
|
return lst
|
|
end
|
|
|
|
-- Beginning Of The App (well, the actual one)
|
|
|
|
local genCurrent, genPrimary, genPackage, primaryWindow
|
|
local running = true
|
|
|
|
-- primary
|
|
local primarySearchTx = ""
|
|
local primaryPage = 1
|
|
local primaryList = scanList("")
|
|
local primaryNextMinus = false
|
|
|
|
-- package
|
|
local packageLock = nil
|
|
local packageId = "FIXME"
|
|
|
|
local function describe(pkgs)
|
|
local lowestV, highestV, myV = {}, {}, {}
|
|
for pk, pv in ipairs(pkgs) do
|
|
lowestV[pk] = math.huge
|
|
highestV[pk] = -math.huge
|
|
end
|
|
for k, v in pairs(sources) do
|
|
pcall(readFile, v, "data/app-claw/local.c2l", function (l)
|
|
local lp = l:match("%.[0-9]+%.c2p$")
|
|
for pk, pkg in ipairs(pkgs) do
|
|
if lp and l:sub(1, -(#lp + 1)) == pkg then
|
|
local v = tonumber(lp:sub(2, -5))
|
|
if k == "local" then
|
|
myV[pk] = v
|
|
end
|
|
lowestV[pk] = math.min(lowestV[pk], v)
|
|
highestV[pk] = math.max(highestV[pk], v)
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
for pk, pkg in ipairs(pkgs) do
|
|
if lowestV[pk] == math.huge then
|
|
pkgs[pk] = pkg .. " (ERR)"
|
|
elseif myV[pk] then
|
|
if highestV[pk] > myV[pk] then
|
|
pkgs[pk] = pkg .. " [v" .. myV[pk] .. "!]"
|
|
elseif lowestV[pk] < myV[pk] then
|
|
pkgs[pk] = pkg .. " (v" .. myV[pk] .. ") R<"
|
|
else
|
|
pkgs[pk] = pkg .. " (v" .. myV[pk] .. ")"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function primaryWindowRegenCore()
|
|
local gen, gens = genCurrent()
|
|
return 25, 14, "claw", neoux.tcwindow(25, 14, gen, function (w)
|
|
w.close()
|
|
running = false
|
|
end, 0xFF8F00, 0, gens)
|
|
end
|
|
local function primaryWindowRegen()
|
|
primaryWindow.reset(primaryWindowRegenCore())
|
|
end
|
|
|
|
-- Sections
|
|
|
|
function genPrimary()
|
|
local minus = (primaryNextMinus and 3) or nil
|
|
primaryNextMinus = false
|
|
local pgs = 12
|
|
local pages = math.ceil(#primaryList / pgs)
|
|
local elems = {
|
|
neoux.tcbutton(23, 1, "+", function (w)
|
|
if primaryPage < pages then
|
|
primaryPage = primaryPage + 1
|
|
primaryWindowRegen()
|
|
end
|
|
end),
|
|
neoux.tcrawview(4, 1, {neoux.pad(primaryPage .. " / " .. pages, 19, true, true)}),
|
|
neoux.tcbutton(1, 1, "-", function (w)
|
|
if primaryPage > 1 then
|
|
primaryNextMinus = true
|
|
primaryPage = primaryPage - 1
|
|
primaryWindowRegen()
|
|
end
|
|
end)
|
|
}
|
|
local base = (primaryPage - 1) * pgs
|
|
local pkgs = {}
|
|
for i = 1, pgs do
|
|
local ent = primaryList[base + i]
|
|
if ent then
|
|
pkgs[i] = ent
|
|
end
|
|
end
|
|
describe(pkgs)
|
|
for i = 1, pgs do
|
|
local ent = primaryList[base + i]
|
|
if ent then
|
|
local enttx = pkgs[i]
|
|
table.insert(elems, neoux.tcbutton(1, i + 1, unicode.safeTextFormat(enttx), function (w)
|
|
-- FREE UP MEMORY NOW
|
|
elems = {}
|
|
w.reset(25, 14, "claw", function (ev)
|
|
if ev == "close" then
|
|
w.close()
|
|
running = false
|
|
end
|
|
end)
|
|
packageId = ent
|
|
genCurrent = genPackage
|
|
primaryWindowRegen()
|
|
end))
|
|
end
|
|
end
|
|
table.insert(elems, neoux.tcfield(1, 14, 16, function (s)
|
|
if s then primarySearchTx = s end
|
|
return primarySearchTx
|
|
end))
|
|
table.insert(elems, neoux.tcbutton(17, 14, "Search!", function (w)
|
|
primaryPage = 1
|
|
primaryList = scanList(primarySearchTx)
|
|
primaryWindowRegen()
|
|
end))
|
|
return elems, minus
|
|
end
|
|
|
|
--
|
|
|
|
local function packageGetBB(src, lclI, srcI, srcW)
|
|
local buttons = {}
|
|
if srcI and srcW then
|
|
table.insert(buttons, {
|
|
"Del",
|
|
function (w)
|
|
w.close()
|
|
running = false
|
|
neo.executeAsync("svc-app-claw-worker", sources[src], packageId, nil, src == "local", primaryINet)
|
|
end
|
|
})
|
|
end
|
|
if srcI and ((not lclI) or (lclI < srcI)) then
|
|
table.insert(buttons, {
|
|
"Get",
|
|
function (w)
|
|
w.close()
|
|
running = false
|
|
neo.executeAsync("svc-app-claw-worker", sources["local"], packageId, sources[src], true, primaryINet)
|
|
end
|
|
})
|
|
end
|
|
if srcW and lclI and not srcI then
|
|
table.insert(buttons, {
|
|
"All",
|
|
function (w)
|
|
w.close()
|
|
running = false
|
|
neo.executeAsync("svc-app-claw-worker", sources[src], packageId, sources["local"], true, primaryINet)
|
|
end
|
|
})
|
|
table.insert(buttons, {
|
|
"Put",
|
|
function (w)
|
|
w.close()
|
|
running = false
|
|
neo.executeAsync("svc-app-claw-worker", sources[src], packageId, sources["local"], false, primaryINet)
|
|
end
|
|
})
|
|
end
|
|
return buttons
|
|
end
|
|
|
|
function genPackage()
|
|
if packageLock then
|
|
return {neoux.tcrawview(1, 1, neoux.fmtText(unicode.safeTextFormat(packageId .. "\n" .. packageLock), 25))}
|
|
end
|
|
-- concept:
|
|
-- mtd <back>
|
|
-- Multi-Track Drifting
|
|
--
|
|
-- local v20 <del> <run>
|
|
-- inet v21 <pull>
|
|
-- dir v22 <pull> <push>
|
|
-- crockett <push>
|
|
local sourceVers = {}
|
|
local c2pSrc = "local"
|
|
local c2pVer = -1
|
|
for k, v in pairs(sources) do
|
|
local ok, err = pcall(readFile, v, "data/app-claw/local.c2l", function (l)
|
|
local lp = l:match("%.[0-9]+%.c2p$")
|
|
if lp and l:sub(1, -(#lp + 1)) == packageId then
|
|
sourceVers[k] = tonumber(lp:sub(2, -5))
|
|
if c2pVer < sourceVers[k] then
|
|
c2pSrc = k
|
|
c2pVer = sourceVers[k]
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
if sourceVers["local"] then
|
|
c2pSrc = "local"
|
|
c2pVer = sourceVers["local"]
|
|
end
|
|
local text = ""
|
|
local ok = pcall(readFile, sources[c2pSrc], "data/app-claw/" .. packageId .. "." .. c2pVer .. ".c2p", function (l)
|
|
text = text .. l .. "\n"
|
|
end)
|
|
if not ok then
|
|
text = packageId .. "\nUnable to read v" .. c2pVer .. " c2p from: " .. c2pSrc
|
|
end
|
|
local elems = {
|
|
neoux.tcrawview(1, 1, neoux.fmtText(unicode.safeTextFormat(text), 25)),
|
|
neoux.tcbutton(20, 1, "Back", function ()
|
|
if packageLock then return end
|
|
genCurrent = genPrimary
|
|
primaryWindowRegen()
|
|
end)
|
|
}
|
|
for k, v in ipairs(sourceList) do
|
|
local row = 14 + k - #sourceList
|
|
local pfx = " "
|
|
if sourceVers[v] then
|
|
pfx = "v" .. string.format("%04i", sourceVers[v]) .. " "
|
|
end
|
|
table.insert(elems, neoux.tcrawview(1, row, {neoux.pad(pfx .. v, 14, false, true)}))
|
|
local col = 26
|
|
local srcW = type(sources[v]) ~= "string"
|
|
for _, bv in ipairs(packageGetBB(v, sourceVers["local"], sourceVers[v], srcW)) do
|
|
local b = neoux.tcbutton(col, row, bv[1], bv[2])
|
|
col = col - b.w
|
|
b.x = col
|
|
table.insert(elems, b)
|
|
end
|
|
end
|
|
return elems
|
|
end
|
|
|
|
--
|
|
|
|
if ldrPkg == "svc-app-claw-worker" and tgtPkg then
|
|
packageId = tgtPkg
|
|
genCurrent = genPackage
|
|
else
|
|
genCurrent = genPrimary
|
|
end
|
|
primaryWindow = neoux.create(primaryWindowRegenCore())
|
|
|
|
while running do
|
|
event.pull()
|
|
end
|