mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-11-27 04:48:05 +11:00
CLAWv3, aka 'C2' - lower memory CLAW
Hopefully this'll finally end the "CLAW runs out of memory an awful lot" problem.
This commit is contained in:
parent
8ab47c96b3
commit
ccb9c3b279
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@
|
|||||||
# leaving in preSH.tar.gz for anyone who's interested
|
# leaving in preSH.tar.gz for anyone who's interested
|
||||||
# in how NOT to do compression
|
# in how NOT to do compression
|
||||||
code.tar
|
code.tar
|
||||||
|
code/data/app-claw/*
|
||||||
work.tar
|
work.tar
|
||||||
work
|
work
|
||||||
work/
|
work/
|
||||||
|
74
claw/C2-Format.md
Normal file
74
claw/C2-Format.md
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# Claw2 Formats
|
||||||
|
|
||||||
|
## .c2l format
|
||||||
|
|
||||||
|
The .c2l format is the server package list for Claw2.
|
||||||
|
|
||||||
|
In an exception to the rule, this file only exists on the server.
|
||||||
|
|
||||||
|
It is used solely in the main package list panel.
|
||||||
|
|
||||||
|
It is a file made up of lines.
|
||||||
|
|
||||||
|
Each line contains a package name, followed by a dot, followed by the package version.
|
||||||
|
|
||||||
|
## .V.c2p format
|
||||||
|
|
||||||
|
The .V.c2p (where V is the version) format is the entire contents of the package view panel,
|
||||||
|
as text, with newlines, in UTF-8.
|
||||||
|
|
||||||
|
This is used when a package is selected in Claw2.
|
||||||
|
|
||||||
|
## .c2x format
|
||||||
|
|
||||||
|
The .c2x format is the actual installation script for the package.
|
||||||
|
|
||||||
|
It is executed by svc-claw-worker.
|
||||||
|
|
||||||
|
It's loaded in all-at-once, then it's gmatched
|
||||||
|
with the pattern [^\n]+.
|
||||||
|
|
||||||
|
A line starting with "?" represents a dependency.
|
||||||
|
|
||||||
|
A line starting & ending with "/" represents a directory creation.
|
||||||
|
|
||||||
|
And a line starting with "+" represents a file.
|
||||||
|
|
||||||
|
Package metadata is not implied.
|
||||||
|
|
||||||
|
Thus, a valid .c2x is:
|
||||||
|
|
||||||
|
```
|
||||||
|
?neo
|
||||||
|
/apps/
|
||||||
|
+apps/app-carrot.0.c2p
|
||||||
|
+apps/app-carrot.c2x
|
||||||
|
```
|
||||||
|
|
||||||
|
## Claw2 Architecture
|
||||||
|
|
||||||
|
app-claw is a very dumb client, but the only thing that'll bother
|
||||||
|
to parse a .c2l (because it has package list/search),
|
||||||
|
and the only thing that cares about version numbers.
|
||||||
|
|
||||||
|
The purpose of it is to provide an older-CLAW-style GUI.
|
||||||
|
|
||||||
|
It *may* take an argument, in which case a package panel is opened,
|
||||||
|
otherwise the main search panel is opened.
|
||||||
|
|
||||||
|
When it wants to do anything, it shuts itself down, running svc-claw-worker.
|
||||||
|
|
||||||
|
svc-app-claw-worker does all package consistency & such work.
|
||||||
|
|
||||||
|
It can only be run from app-claw, and runs app-claw after it's done.
|
||||||
|
|
||||||
|
It takes 4 arguments:
|
||||||
|
|
||||||
|
1. The target filesystem proxy.
|
||||||
|
2. The target package name. This package is viewed in app-claw after completion.
|
||||||
|
3. The source to download files from.
|
||||||
|
If nil, the package is being deleted.
|
||||||
|
Otherwise, can either be a proxy or a string.
|
||||||
|
Proxy means it's a filesystem,
|
||||||
|
string means it's an internet base.
|
||||||
|
4. Checked flag
|
34
claw/clawconv.lua
Normal file
34
claw/clawconv.lua
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- CLAW local.lua converter. Expects to be run from outermost folder.
|
||||||
|
|
||||||
|
local target = ...
|
||||||
|
|
||||||
|
local serial = loadfile("code/libs/serial.lua")()
|
||||||
|
|
||||||
|
for k, v in pairs(serial.deserialize(io.read("*a"))) do
|
||||||
|
print(k .. "." .. v.v .. ".c2p")
|
||||||
|
print(k .. ".c2x")
|
||||||
|
local f2 = io.open(target .. k .. "." .. v.v .. ".c2p", "wb")
|
||||||
|
f2:write(k .. "\n")
|
||||||
|
f2:write(v.desc .. "\n")
|
||||||
|
f2:write("v" .. v.v .. " deps " .. table.concat(v.deps, ", "))
|
||||||
|
f2:close()
|
||||||
|
f2 = io.open(target .. k .. ".c2x", "wb")
|
||||||
|
for _, vx in ipairs(v.deps) do
|
||||||
|
f2:write("?" .. vx .. "\n")
|
||||||
|
end
|
||||||
|
for _, vx in ipairs(v.dirs) do
|
||||||
|
f2:write("/" .. vx .. "\n")
|
||||||
|
end
|
||||||
|
for _, vx in ipairs(v.files) do
|
||||||
|
f2:write("+" .. vx .. "\n")
|
||||||
|
end
|
||||||
|
f2:write("/data\n")
|
||||||
|
f2:write("/data/app-claw\n")
|
||||||
|
f2:write("+data/app-claw/" .. k .. ".c2x\n")
|
||||||
|
f2:write("+data/app-claw/" .. k .. "." .. v.v .. ".c2p\n")
|
||||||
|
f2:close()
|
||||||
|
end
|
||||||
|
|
@ -164,18 +164,16 @@ return {
|
|||||||
},
|
},
|
||||||
["app-claw"] = {
|
["app-claw"] = {
|
||||||
desc = "KittenOS NEO Package Manager",
|
desc = "KittenOS NEO Package Manager",
|
||||||
v = 2,
|
v = 3,
|
||||||
deps = {
|
deps = {
|
||||||
"neo"
|
"neo"
|
||||||
},
|
},
|
||||||
dirs = {
|
dirs = {
|
||||||
"apps",
|
"apps"
|
||||||
"libs"
|
|
||||||
},
|
},
|
||||||
files = {
|
files = {
|
||||||
"apps/app-claw.lua",
|
"apps/app-claw.lua",
|
||||||
"libs/app-claw-core.lua",
|
"apps/svc-app-claw-worker.lua"
|
||||||
"libs/app-claw-csi.lua"
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["neo-meta"] = {
|
["neo-meta"] = {
|
@ -1,17 +0,0 @@
|
|||||||
local merges = {...}
|
|
||||||
neo = {
|
|
||||||
wrapMeta = function (x)
|
|
||||||
return x
|
|
||||||
end
|
|
||||||
}
|
|
||||||
local serial = loadfile("code/libs/serial.lua")()
|
|
||||||
local repo = {}
|
|
||||||
for _, v in ipairs(merges) do
|
|
||||||
local f = io.open(v, "rb")
|
|
||||||
local fd = f:read("*a")
|
|
||||||
f:close()
|
|
||||||
for k, v in pairs(serial.deserialize(fd)) do
|
|
||||||
repo[k] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
io.write(serial.serialize(repo))
|
|
@ -3,146 +3,78 @@
|
|||||||
|
|
||||||
-- app-claw: Package manager.
|
-- app-claw: Package manager.
|
||||||
|
|
||||||
|
local ldrPkg, _, tgtPkg = ...
|
||||||
|
|
||||||
-- libs & such
|
-- libs & such
|
||||||
local event = require("event")(neo)
|
local event = require("event")(neo)
|
||||||
local neoux, err = require("neoux")
|
local neoux = require("neoux")(event, neo)
|
||||||
if not neoux then error(err) end
|
|
||||||
neoux = neoux(event, neo)
|
|
||||||
local claw = require("app-claw-core")()
|
|
||||||
local clawcsi = require("app-claw-csi")
|
|
||||||
|
|
||||||
local source = "http://20kdc.duckdns.org/neo/"
|
|
||||||
local disks = neo.requireAccess("c.filesystem", "searching disks for packages")
|
|
||||||
local primaryDisk = disks.primary
|
|
||||||
local primaryINet = neo.requestAccess("c.internet")
|
local primaryINet = neo.requestAccess("c.internet")
|
||||||
if primaryINet then primaryINet = primaryINet.list()() end
|
if primaryINet then primaryINet = primaryINet.list()() end
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|
||||||
local function yielder()
|
local function readFile(src, url, ocb)
|
||||||
-- slightly dangerous, but what can we do?
|
local buf = ""
|
||||||
pcall(event.sleepTo, os.uptime() + 0.05)
|
local function cb(data)
|
||||||
end
|
if not data then
|
||||||
|
ocb(buf)
|
||||||
local function download(url, cb)
|
else
|
||||||
if not primaryINet then return nil, "no internet" end
|
buf = buf .. data
|
||||||
local req, err = primaryINet.request(source .. url)
|
buf = buf:gsub("[^\n]*\n", function (t)
|
||||||
if not req then
|
ocb(t:sub(1, -2))
|
||||||
cb(nil)
|
return ""
|
||||||
return nil, "dlR/" .. tostring(err)
|
end)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
if type(src) == "string" then
|
||||||
|
assert(primaryINet, "no internet")
|
||||||
|
local req, err = primaryINet.request(src .. url)
|
||||||
|
assert(req, err)
|
||||||
-- OpenComputers#535
|
-- OpenComputers#535
|
||||||
req.finishConnect()
|
req.finishConnect()
|
||||||
while true do
|
while true do
|
||||||
local n, n2 = req.read(neo.readBufSize)
|
local n, n2 = req.read(neo.readBufSize)
|
||||||
local o, r = cb(n)
|
cb(n)
|
||||||
if not o then
|
|
||||||
req.close()
|
|
||||||
return nil, r
|
|
||||||
end
|
|
||||||
if not n then
|
if not n then
|
||||||
req.close()
|
req.close()
|
||||||
if n2 then
|
if n2 then
|
||||||
return nil, n2
|
error(n2)
|
||||||
else
|
else
|
||||||
|
cb(nil)
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if n == "" then
|
if n == "" then
|
||||||
yielder()
|
-- slightly dangerous, but what can we do?
|
||||||
|
pcall(event.sleepTo, os.uptime() + 0.05)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function fsSrc(disk)
|
|
||||||
return function (url, cb)
|
|
||||||
local h, e = disk.open(url, "rb")
|
|
||||||
if not h then cb(nil) return nil, tostring(e) end
|
|
||||||
local c = ""
|
|
||||||
while c do
|
|
||||||
c = disk.read(h, neo.readBufSize)
|
|
||||||
local o, r = cb(c)
|
|
||||||
if not o then return nil, r end
|
|
||||||
end
|
|
||||||
disk.close(h)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function fsDst(disk)
|
|
||||||
return {function (url)
|
|
||||||
local h, e = disk.open(url, "wb")
|
|
||||||
if not h then return nil, tostring(e) end
|
|
||||||
return function (d)
|
|
||||||
local ok, r = true
|
|
||||||
if d then
|
|
||||||
ok, r = disk.write(h, d)
|
|
||||||
else
|
else
|
||||||
disk.close(h)
|
if url == "data/app-claw/local.c2l" then
|
||||||
|
for _, v in ipairs(src.list("data/app-claw/")) do
|
||||||
|
ocb(v)
|
||||||
end
|
end
|
||||||
if not ok then return nil, tostring(r) end
|
return
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
end, disk.makeDirectory, disk.exists, disk.isDirectory, disk.remove, disk.rename}
|
local h, e = src.open(url, "rb")
|
||||||
end
|
assert(h, e)
|
||||||
|
repeat
|
||||||
local function checked(...)
|
local c = src.read(h, neo.readBufSize)
|
||||||
local res, res2, err = pcall(...)
|
cb(c)
|
||||||
if not res then
|
until not c
|
||||||
neoux.startDialog(tostring(res2), "error!", true)
|
src.close(h)
|
||||||
elseif not res2 then
|
|
||||||
neoux.startDialog(tostring(err), "failed!", true)
|
|
||||||
else
|
|
||||||
return res2
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Beginning Of The App (well, the actual one)
|
-- Sources
|
||||||
|
|
||||||
local genCurrent, genPrimary, genPackage, primaryWindow
|
|
||||||
local running = true
|
|
||||||
|
|
||||||
-- primary
|
|
||||||
local primarySearchTx = ""
|
|
||||||
local primaryPage = 1
|
|
||||||
local primaryList = {}
|
|
||||||
local primaryNextMinus = false
|
|
||||||
|
|
||||||
-- package
|
|
||||||
local packageLock = nil
|
|
||||||
local packageId = "FIXME"
|
|
||||||
|
|
||||||
|
|
||||||
local function describe(pkg)
|
|
||||||
local weHave = claw.getInfo(pkg, "local")
|
|
||||||
local theyHave = claw.getInfo(pkg, "local")
|
|
||||||
local someoneHas = claw.getInfo(pkg, nil, true)
|
|
||||||
if weHave then
|
|
||||||
if theyHave.v > weHave.v then
|
|
||||||
return pkg .. " [v" .. weHave.v .. "!]"
|
|
||||||
end
|
|
||||||
if someoneHas.v < weHave.v then
|
|
||||||
return pkg .. " (v" .. weHave.v .. ") R<"
|
|
||||||
end
|
|
||||||
return pkg .. " (v" .. weHave.v .. ")"
|
|
||||||
end
|
|
||||||
return pkg
|
|
||||||
end
|
|
||||||
|
|
||||||
local function primaryWindowRegenCore()
|
|
||||||
local gen, gens = genCurrent()
|
|
||||||
return 25, 12, "claw", neoux.tcwindow(25, 12, gen, function (w)
|
|
||||||
w.close()
|
|
||||||
running = false
|
|
||||||
end, 0xFF8F00, 0, gens)
|
|
||||||
end
|
|
||||||
local function primaryWindowRegen()
|
|
||||||
primaryWindow.reset(primaryWindowRegenCore())
|
|
||||||
end
|
|
||||||
|
|
||||||
|
local sources = {}
|
||||||
|
local sourceList = {}
|
||||||
-- Use all non-primary filesystems
|
-- 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 pass = 1, 3 do
|
||||||
for v in disks.list() do
|
for v in disks.list() do
|
||||||
local nam = nil
|
local nam = nil
|
||||||
@ -154,11 +86,8 @@ for pass = 1, 3 do
|
|||||||
nam = v.address
|
nam = v.address
|
||||||
end
|
end
|
||||||
if nam then
|
if nam then
|
||||||
local ok, r = clawcsi(claw, nam, fsSrc(v), (not v.isReadOnly()) and fsDst(v))
|
sources[nam] = v
|
||||||
if not ok and nam == "local" then
|
table.insert(sourceList, nam)
|
||||||
claw.unlock()
|
|
||||||
error(r)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -167,19 +96,105 @@ end
|
|||||||
disks = nil
|
disks = nil
|
||||||
|
|
||||||
if primaryINet then
|
if primaryINet then
|
||||||
checked(clawcsi, claw, "inet", download)
|
sources["inet"] = "http://20kdc.duckdns.org/neo/"
|
||||||
|
table.insert(sourceList, "inet")
|
||||||
end
|
end
|
||||||
|
|
||||||
clawcsi = nil
|
-- List scanning for package window
|
||||||
|
|
||||||
primaryList = claw.getList()
|
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
|
-- Sections
|
||||||
|
|
||||||
function genPrimary()
|
function genPrimary()
|
||||||
local minus = (primaryNextMinus and 3) or nil
|
local minus = (primaryNextMinus and 3) or nil
|
||||||
primaryNextMinus = false
|
primaryNextMinus = false
|
||||||
local pgs = 10
|
local pgs = 12
|
||||||
local pages = math.ceil(#primaryList / pgs)
|
local pages = math.ceil(#primaryList / pgs)
|
||||||
local elems = {
|
local elems = {
|
||||||
neoux.tcbutton(23, 1, "+", function (w)
|
neoux.tcbutton(23, 1, "+", function (w)
|
||||||
@ -198,14 +213,22 @@ function genPrimary()
|
|||||||
end)
|
end)
|
||||||
}
|
}
|
||||||
local base = (primaryPage - 1) * pgs
|
local base = (primaryPage - 1) * pgs
|
||||||
|
local pkgs = {}
|
||||||
for i = 1, pgs do
|
for i = 1, pgs do
|
||||||
local ent = primaryList[base + i]
|
local ent = primaryList[base + i]
|
||||||
if ent then
|
if ent then
|
||||||
local enttx = describe(ent)
|
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)
|
table.insert(elems, neoux.tcbutton(1, i + 1, unicode.safeTextFormat(enttx), function (w)
|
||||||
-- FREE UP MEMORY NOW
|
-- FREE UP MEMORY NOW
|
||||||
elems = {}
|
elems = {}
|
||||||
w.reset(25, 12, "claw", function (ev)
|
w.reset(25, 14, "claw", function (ev)
|
||||||
if ev == "close" then
|
if ev == "close" then
|
||||||
w.close()
|
w.close()
|
||||||
running = false
|
running = false
|
||||||
@ -217,22 +240,13 @@ function genPrimary()
|
|||||||
end))
|
end))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
table.insert(elems, neoux.tcfield(1, 12, 16, function (s)
|
table.insert(elems, neoux.tcfield(1, 14, 16, function (s)
|
||||||
if s then primarySearchTx = s end
|
if s then primarySearchTx = s end
|
||||||
return primarySearchTx
|
return primarySearchTx
|
||||||
end))
|
end))
|
||||||
table.insert(elems, neoux.tcbutton(17, 12, "Search!", function (w)
|
table.insert(elems, neoux.tcbutton(17, 14, "Search!", function (w)
|
||||||
local n = {}
|
|
||||||
for _, v in ipairs(claw.getList()) do
|
|
||||||
for i = 1, #v do
|
|
||||||
if v:sub(i, i + #primarySearchTx - 1) == primarySearchTx then
|
|
||||||
table.insert(n, v)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
primaryPage = 1
|
primaryPage = 1
|
||||||
primaryList = n
|
primaryList = scanList(primarySearchTx)
|
||||||
primaryWindowRegen()
|
primaryWindowRegen()
|
||||||
end))
|
end))
|
||||||
return elems, minus
|
return elems, minus
|
||||||
@ -245,49 +259,38 @@ local function packageGetBB(src, lclI, srcI, srcW)
|
|||||||
if srcI and srcW then
|
if srcI and srcW then
|
||||||
table.insert(buttons, {
|
table.insert(buttons, {
|
||||||
"Del",
|
"Del",
|
||||||
function ()
|
function (w)
|
||||||
if packageLock then return end
|
w.close()
|
||||||
packageLock = ""
|
running = false
|
||||||
checked(claw.remove, src, packageId, true)
|
neo.executeAsync("svc-app-claw-worker", sources[src], packageId, nil, src == "local")
|
||||||
packageLock = nil
|
|
||||||
primaryWindowRegen()
|
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
if srcI and ((not lclI) or (lclI.v < srcI.v)) then
|
if srcI and ((not lclI) or (lclI < srcI)) then
|
||||||
table.insert(buttons, {
|
table.insert(buttons, {
|
||||||
"Get",
|
"Get",
|
||||||
function ()
|
function (w)
|
||||||
if packageLock then return end
|
w.close()
|
||||||
packageLock = "installing from " .. src
|
running = false
|
||||||
primaryWindowRegen()
|
neo.executeAsync("svc-app-claw-worker", sources["local"], packageId, sources[src], true)
|
||||||
checked(claw.installTo, "local", packageId, src, true, yielder)
|
|
||||||
packageLock = nil
|
|
||||||
primaryWindowRegen()
|
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
if srcW and lclI and not srcI then
|
if srcW and lclI and not srcI then
|
||||||
table.insert(buttons, {
|
table.insert(buttons, {
|
||||||
"All",
|
"All",
|
||||||
function ()
|
function (w)
|
||||||
if packageLock then return end
|
w.close()
|
||||||
packageLock = "storing w/ dependencies at " .. src
|
running = false
|
||||||
primaryWindowRegen()
|
neo.executeAsync("svc-app-claw-worker", sources[src], packageId, sources["local"], true)
|
||||||
checked(claw.installTo, src, packageId, "local", true, yielder)
|
|
||||||
packageLock = nil
|
|
||||||
primaryWindowRegen()
|
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
table.insert(buttons, {
|
table.insert(buttons, {
|
||||||
"Put",
|
"Put",
|
||||||
function ()
|
function (w)
|
||||||
if packageLock then return end
|
w.close()
|
||||||
packageLock = "storing at " .. src
|
running = false
|
||||||
primaryWindowRegen()
|
neo.executeAsync("svc-app-claw-worker", sources[src], packageId, sources["local"], false)
|
||||||
checked(claw.installTo, src, packageId, "local", false, yielder)
|
|
||||||
packageLock = nil
|
|
||||||
primaryWindowRegen()
|
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
@ -306,26 +309,50 @@ function genPackage()
|
|||||||
-- inet v21 <pull>
|
-- inet v21 <pull>
|
||||||
-- dir v22 <pull> <push>
|
-- dir v22 <pull> <push>
|
||||||
-- crockett <push>
|
-- crockett <push>
|
||||||
local info = claw.getInfo(packageId)
|
local sourceVers = {}
|
||||||
local infoL = claw.getInfo(packageId, "local")
|
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 = {
|
local elems = {
|
||||||
neoux.tcrawview(1, 1, neoux.fmtText(unicode.safeTextFormat(packageId .. "\n" .. info.desc .. "\nv" .. info.v .. " deps " .. table.concat(info.deps, ", ")), 25)),
|
neoux.tcrawview(1, 1, neoux.fmtText(unicode.safeTextFormat(text), 25)),
|
||||||
neoux.tcbutton(20, 1, "Back", function ()
|
neoux.tcbutton(20, 1, "Back", function ()
|
||||||
if packageLock then return end
|
if packageLock then return end
|
||||||
genCurrent = genPrimary
|
genCurrent = genPrimary
|
||||||
primaryWindowRegen()
|
primaryWindowRegen()
|
||||||
end)
|
end)
|
||||||
}
|
}
|
||||||
for k, v in ipairs(claw.sourceList) do
|
for k, v in ipairs(sourceList) do
|
||||||
local lI = claw.getInfo(packageId, v[1])
|
local row = 14 + k - #sourceList
|
||||||
local row = 12 + k - #(claw.sourceList)
|
|
||||||
local pfx = " "
|
local pfx = " "
|
||||||
if lI then
|
if sourceVers[v] then
|
||||||
pfx = "v" .. string.format("%04i", lI.v) .. " "
|
pfx = "v" .. string.format("%04i", sourceVers[v]) .. " "
|
||||||
end
|
end
|
||||||
table.insert(elems, neoux.tcrawview(1, row, {neoux.pad(pfx .. v[1], 14, false, true)}))
|
table.insert(elems, neoux.tcrawview(1, row, {neoux.pad(pfx .. v, 14, false, true)}))
|
||||||
local col = 26
|
local col = 26
|
||||||
for _, bv in ipairs(packageGetBB(v[1], infoL, lI, v[2])) do
|
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])
|
local b = neoux.tcbutton(col, row, bv[1], bv[2])
|
||||||
col = col - b.w
|
col = col - b.w
|
||||||
b.x = col
|
b.x = col
|
||||||
@ -337,10 +364,14 @@ end
|
|||||||
|
|
||||||
--
|
--
|
||||||
|
|
||||||
genCurrent = genPrimary
|
if ldrPkg == "svc-app-claw-worker" and tgtPkg then
|
||||||
|
packageId = tgtPkg
|
||||||
|
genCurrent = genPackage
|
||||||
|
else
|
||||||
|
genCurrent = genPrimary
|
||||||
|
end
|
||||||
primaryWindow = neoux.create(primaryWindowRegenCore())
|
primaryWindow = neoux.create(primaryWindowRegenCore())
|
||||||
|
|
||||||
while running do
|
while running do
|
||||||
event.pull()
|
event.pull()
|
||||||
end
|
end
|
||||||
claw.unlock()
|
|
||||||
|
144
code/apps/svc-app-claw-worker.lua
Normal file
144
code/apps/svc-app-claw-worker.lua
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
-- This is released into the public domain.
|
||||||
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
-- svc-app-claw-worker: Who stays stays. Who goes goes.
|
||||||
|
|
||||||
|
local callerPkg, _, destProx, packageId, downloadSrc, checked = ...
|
||||||
|
if callerPkg ~= "app-claw" then error("Internal process for app-claw's bidding.") end
|
||||||
|
-- This 'mutex' remains active as long as the process does.
|
||||||
|
neo.requireAccess("r.svc.app-claw-worker", "CLAW mutex")
|
||||||
|
|
||||||
|
local function wrapLines(ocb)
|
||||||
|
local buf = ""
|
||||||
|
return function (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
|
||||||
|
end
|
||||||
|
|
||||||
|
local function download(url, cb, src)
|
||||||
|
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
|
||||||
|
neo.scheduleTimer(os.uptime() + 0.05)
|
||||||
|
while true do
|
||||||
|
local res = coroutine.yield()
|
||||||
|
if res == "k.timer" then break end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
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
|
||||||
|
|
||||||
|
local opInstall, opRemove
|
||||||
|
|
||||||
|
function opInstall(packageId, checked)
|
||||||
|
local gback = {} -- the ultimate strategy
|
||||||
|
download("data/app-claw/" .. packageId .. ".c2x", wrapLines(function (l)
|
||||||
|
if l:sub(1, 1) == "?" and checked then
|
||||||
|
if not destProx.exists("data/app-claw/" .. l:sub(2) .. ".c2x") then
|
||||||
|
opInstall(l:sub(2), true)
|
||||||
|
end
|
||||||
|
elseif l:sub(1, 1) == "+" then
|
||||||
|
table.insert(gback, l:sub(2))
|
||||||
|
elseif l:sub(1, 1) == "/" then
|
||||||
|
destProx.makeDirectory(l)
|
||||||
|
assert(destProx.isDirectory(l), "unable to create dir " .. l)
|
||||||
|
end
|
||||||
|
end), downloadSrc)
|
||||||
|
for _, v in ipairs(gback) do
|
||||||
|
local f = destProx.open(v .. ".C2T", "wb")
|
||||||
|
assert(f, "unable to create download file")
|
||||||
|
local ok, err = pcall(download, v, function (b)
|
||||||
|
assert(destProx.write(f, b or ""), "unable to save data")
|
||||||
|
end, downloadSrc)
|
||||||
|
assert(ok, err)
|
||||||
|
destProx.close(f)
|
||||||
|
end
|
||||||
|
-- CRITICAL SECTION --
|
||||||
|
if destProx.exists("data/app-claw/" .. packageId .. ".c2x") then
|
||||||
|
opRemove(packageId, false)
|
||||||
|
end
|
||||||
|
for _, v in ipairs(gback) do
|
||||||
|
if destProx.exists(v) then
|
||||||
|
for _, v in ipairs(gback) do
|
||||||
|
destProx.remove(v .. ".C2T")
|
||||||
|
end
|
||||||
|
error("file conflict: " .. v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, v in ipairs(gback) do
|
||||||
|
destProx.rename(v .. ".C2T", v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function opRemove(packageId, checked)
|
||||||
|
if checked then
|
||||||
|
local dependents = {}
|
||||||
|
for _, pidf in ipairs(destProx.list("data/app-claw/")) do
|
||||||
|
if pidf:sub(-4) == ".c2x" then
|
||||||
|
local pid = pidf:sub(1, -5)
|
||||||
|
download("data/app-claw/" .. pidf, wrapLines(function (l)
|
||||||
|
if l == "?" .. packageId then
|
||||||
|
table.insert(dependents, pid)
|
||||||
|
end
|
||||||
|
end), destProx)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(not dependents[1], "Cannot remove " .. packageId .. ", required by:\n" .. table.concat(dependents, ", "))
|
||||||
|
end
|
||||||
|
local rmSchedule = {}
|
||||||
|
download("data/app-claw/" .. packageId .. ".c2x", wrapLines(function (l)
|
||||||
|
if l:sub(1, 1) == "+" then
|
||||||
|
table.insert(rmSchedule, l:sub(2))
|
||||||
|
end
|
||||||
|
end), destProx)
|
||||||
|
for _, v in ipairs(rmSchedule) do
|
||||||
|
destProx.remove(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, err
|
||||||
|
if downloadSrc then
|
||||||
|
ok, err = pcall(opInstall, packageId, checked)
|
||||||
|
else
|
||||||
|
ok, err = pcall(opRemove, packageId, checked)
|
||||||
|
end
|
||||||
|
fsProxy = nil
|
||||||
|
downloadSrc = nil
|
||||||
|
neo.executeAsync("app-claw", packageId)
|
||||||
|
if not ok then
|
||||||
|
error(err)
|
||||||
|
end
|
@ -1,254 +0,0 @@
|
|||||||
-- This is released into the public domain.
|
|
||||||
-- No warranty is provided, implied or otherwise.
|
|
||||||
|
|
||||||
-- app-claw-core: assistant to app-claw
|
|
||||||
-- should only ever be one app-claw at a time
|
|
||||||
-- USING THIS LIBRARY OUTSIDE OF APP-CLAW IS A BAD IDEA.
|
|
||||||
-- SO DON'T DO IT.
|
|
||||||
|
|
||||||
-- Also serves to provide a mutex.
|
|
||||||
|
|
||||||
local lock = false
|
|
||||||
|
|
||||||
return function ()
|
|
||||||
if lock then
|
|
||||||
error("libclaw safety lock in use")
|
|
||||||
end
|
|
||||||
lock = true
|
|
||||||
local sourceList = {}
|
|
||||||
local sources = {}
|
|
||||||
-- 1 2 3 4 5 6
|
|
||||||
-- source ents: src dst index
|
|
||||||
-- dst entries: writeFile(fn), mkdir(fn), exists(fn), isDirectory(fn), remove(fn), rename(fna, fnb)
|
|
||||||
-- writeFile(fn) -> function (data/nil to close)
|
|
||||||
local function saveInfo(dn)
|
|
||||||
sources[dn][2][2]("data")
|
|
||||||
sources[dn][2][2]("data/app-claw")
|
|
||||||
local cb, _, r = sources[dn][2][1]("data/app-claw/local.lua")
|
|
||||||
if not cb then return false, r end
|
|
||||||
_, r = cb(require("serial").serialize(sources[dn][3]))
|
|
||||||
if not _ then return false, r end
|
|
||||||
_, r = cb(nil)
|
|
||||||
if not _ then return false, r end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
local remove, installTo, expandCSI, compressCSI
|
|
||||||
local function expandS(v)
|
|
||||||
return v:sub(2, v:byte(1) + 1), v:sub(v:byte(1) + 2)
|
|
||||||
end
|
|
||||||
local function expandT(v)
|
|
||||||
local t = {}
|
|
||||||
local n = v:byte(1)
|
|
||||||
v = v:sub(2)
|
|
||||||
for i = 1, n do
|
|
||||||
t[i], v = expandS(v)
|
|
||||||
end
|
|
||||||
return t, v
|
|
||||||
end
|
|
||||||
local function compressT(x)
|
|
||||||
local b = string.char(#x)
|
|
||||||
for _, v in ipairs(x) do
|
|
||||||
b = b .. string.char(#v) .. v
|
|
||||||
end
|
|
||||||
return b
|
|
||||||
end
|
|
||||||
local function expandCSI(v)
|
|
||||||
local t = {}
|
|
||||||
local k
|
|
||||||
k, v = expandS(v)
|
|
||||||
t.desc, v = expandS(v)
|
|
||||||
t.v = (v:byte(1) * 256) + v:byte(2)
|
|
||||||
v = v:sub(3)
|
|
||||||
t.dirs, v = expandT(v)
|
|
||||||
t.files, v = expandT(v)
|
|
||||||
t.deps, v = expandT(v)
|
|
||||||
return k, t, v
|
|
||||||
end
|
|
||||||
local function compressCSI(k, v)
|
|
||||||
local nifo = string.char(#k) .. k
|
|
||||||
nifo = nifo .. string.char(math.min(255, #v.desc)) .. v.desc:sub(1, 255)
|
|
||||||
nifo = nifo .. string.char(math.floor(v.v / 256), v.v % 256)
|
|
||||||
nifo = nifo .. compressT(v.dirs)
|
|
||||||
nifo = nifo .. compressT(v.files)
|
|
||||||
nifo = nifo .. compressT(v.deps)
|
|
||||||
return nifo
|
|
||||||
end
|
|
||||||
local function findPkg(idx, pkg, del)
|
|
||||||
del = del and ""
|
|
||||||
idx = sources[idx][3]
|
|
||||||
while #idx > 0 do
|
|
||||||
local k, d
|
|
||||||
k, d, idx = expandCSI(idx)
|
|
||||||
if del then
|
|
||||||
if k == pkg then
|
|
||||||
return d, del .. idx
|
|
||||||
end
|
|
||||||
del = del .. compressCSI(k, d)
|
|
||||||
else
|
|
||||||
if k == pkg then return d end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- NOTE: Functions in this must return something due to the checked-call wrapper,
|
|
||||||
-- but should all use error() for consistency.
|
|
||||||
-- Operations
|
|
||||||
installTo = function (dstName, pkg, srcName, checked, yielder)
|
|
||||||
local errs = {}
|
|
||||||
if srcName == dstName then
|
|
||||||
error("Invalid API use")
|
|
||||||
end
|
|
||||||
-- preliminary checks
|
|
||||||
local srcPkg = findPkg(srcName, pkg, false)
|
|
||||||
assert(srcPkg)
|
|
||||||
if checked then
|
|
||||||
for _, v in ipairs(srcPkg.deps) do
|
|
||||||
if not findPkg(dstName, v) then
|
|
||||||
if not findPkg(srcName, v) then
|
|
||||||
table.insert(errs, pkg .. " depends on " .. v .. "\n")
|
|
||||||
elseif #errs == 0 then
|
|
||||||
installTo(dstName, v, srcName, checked, yielder)
|
|
||||||
else
|
|
||||||
table.insert(errs, pkg .. " depends on " .. v .. " (can autoinstall)\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- Files from previous versions to get rid of
|
|
||||||
local ignFiles = {}
|
|
||||||
local oldDst = findPkg(dstName, pkg)
|
|
||||||
if oldDst then
|
|
||||||
for _, v in ipairs(oldDst.files) do
|
|
||||||
ignFiles[v] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
oldDst = nil
|
|
||||||
for _, v in ipairs(srcPkg.files) do
|
|
||||||
if not ignFiles[v] then
|
|
||||||
if sources[dstName][2][3](v) then
|
|
||||||
table.insert(errs, v .. " already exists (corrupt system?)")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #errs > 0 then
|
|
||||||
error(table.concat(errs))
|
|
||||||
end
|
|
||||||
for _, v in ipairs(srcPkg.dirs) do
|
|
||||||
sources[dstName][2][2](v)
|
|
||||||
if not sources[dstName][2][4](v) then
|
|
||||||
error("Unable to create directory " .. v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for _, v in ipairs(srcPkg.files) do
|
|
||||||
local tmpOut, r, ok = sources[dstName][2][1](v .. ".claw-tmp")
|
|
||||||
ok = tmpOut
|
|
||||||
if ok then
|
|
||||||
ok, r = sources[srcName][1](v, tmpOut)
|
|
||||||
end
|
|
||||||
if ok then
|
|
||||||
yielder()
|
|
||||||
else
|
|
||||||
-- Cleanup...
|
|
||||||
for _, v in ipairs(srcPkg.files) do
|
|
||||||
sources[dstName][2][5](v .. ".claw-tmp")
|
|
||||||
end
|
|
||||||
error(r)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- PAST THIS POINT, ERRORS CORRUPT!
|
|
||||||
-- Remove package from DB
|
|
||||||
local oldDst2, oldDst3 = findPkg(dstName, pkg, true)
|
|
||||||
sources[dstName][3] = oldDst3 or sources[dstName][3]
|
|
||||||
oldDst2, oldDst3 = nil
|
|
||||||
saveInfo(dstName)
|
|
||||||
-- Delete old files
|
|
||||||
for k, _ in pairs(ignFiles) do
|
|
||||||
yielder()
|
|
||||||
sources[dstName][2][5](k)
|
|
||||||
end
|
|
||||||
-- Create new files
|
|
||||||
for _, v in ipairs(srcPkg.files) do
|
|
||||||
yielder()
|
|
||||||
sources[dstName][2][6](v .. ".claw-tmp", v)
|
|
||||||
end
|
|
||||||
-- Insert into DB
|
|
||||||
sources[dstName][3] = sources[dstName][3] .. compressCSI(pkg, srcPkg)
|
|
||||||
saveInfo(dstName)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
remove = function (dstName, pkg, checked)
|
|
||||||
if checked then
|
|
||||||
local errs = {}
|
|
||||||
local buf = sources[dstName][3]
|
|
||||||
while #buf > 0 do
|
|
||||||
local dpsName, dpsV
|
|
||||||
dpsName, dpsV, buf = expandCSI(buf)
|
|
||||||
for _, v in ipairs(dpsV.deps) do
|
|
||||||
if v == pkg then
|
|
||||||
table.insert(errs, dpsName .. " depends on " .. pkg .. "\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #errs > 0 then
|
|
||||||
return nil, table.concat(errs)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local dstPkg, nbuf = findPkg(dstName, pkg, true)
|
|
||||||
assert(dstPkg, "Package wasn't installed")
|
|
||||||
for _, v in ipairs(dstPkg.files) do
|
|
||||||
sources[dstName][2][5](v)
|
|
||||||
end
|
|
||||||
sources[dstName][3] = nbuf
|
|
||||||
saveInfo(dstName)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
return {
|
|
||||||
-- Gets the latest info, or if given a source just gives that source's info.
|
|
||||||
-- Do not modify output.
|
|
||||||
getInfo = function (pkg, source, oldest)
|
|
||||||
if source then return findPkg(source, pkg) end
|
|
||||||
local bestI = {
|
|
||||||
v = -1,
|
|
||||||
desc = "An unknown package.",
|
|
||||||
deps = {}
|
|
||||||
}
|
|
||||||
if oldest then bestI.v = 10000 end
|
|
||||||
for k, v in pairs(sources) do
|
|
||||||
local pkgv = findPkg(k, pkg)
|
|
||||||
if pkgv then
|
|
||||||
if ((not oldest) and (pkgv.v > bestI.v)) or (oldest and (pkgv.v > bestI.v)) then
|
|
||||||
bestI = pkgv
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return bestI
|
|
||||||
end,
|
|
||||||
sources = sources,
|
|
||||||
sourceList = sourceList,
|
|
||||||
remove = remove,
|
|
||||||
installTo = installTo,
|
|
||||||
expandCSI = expandCSI,
|
|
||||||
compressCSI = compressCSI,
|
|
||||||
|
|
||||||
-- Gets a total list of packages, as a table of strings. You can modify output.
|
|
||||||
getList = function ()
|
|
||||||
local n = {}
|
|
||||||
local seen = {}
|
|
||||||
for k, v in pairs(sources) do
|
|
||||||
local p3 = v[3]
|
|
||||||
while #p3 > 0 do
|
|
||||||
local kb, _, nx = expandCSI(p3)
|
|
||||||
p3 = nx
|
|
||||||
if not seen[kb] then
|
|
||||||
seen[kb] = true
|
|
||||||
table.insert(n, kb)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
table.sort(n)
|
|
||||||
return n
|
|
||||||
end,
|
|
||||||
unlock = function ()
|
|
||||||
lock = false
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
@ -1,28 +0,0 @@
|
|||||||
-- This is released into the public domain.
|
|
||||||
-- No warranty is provided, implied or otherwise.
|
|
||||||
|
|
||||||
-- app-claw-csi: addSource function
|
|
||||||
-- USING THIS LIBRARY OUTSIDE OF APP-CLAW IS A BAD IDEA.
|
|
||||||
-- SO DON'T DO IT.
|
|
||||||
|
|
||||||
-- NOTE: If a source is writable, it's added anyway despite any problems.
|
|
||||||
return function (claw, name, src, dst)
|
|
||||||
local ifo = ""
|
|
||||||
local ifok, e = src("data/app-claw/local.lua", function (t)
|
|
||||||
ifo = ifo .. (t or "")
|
|
||||||
return true
|
|
||||||
end)
|
|
||||||
e = e or "local.lua parse error"
|
|
||||||
ifo = ifok and require("serial").deserialize(ifo)
|
|
||||||
if not (dst or ifo) then return false, e end
|
|
||||||
table.insert(claw.sourceList, {name, not not dst})
|
|
||||||
local nifo = ifo or ""
|
|
||||||
if type(nifo) == "table" then
|
|
||||||
nifo = ""
|
|
||||||
for k, v in pairs(ifo) do
|
|
||||||
nifo = nifo .. claw.compressCSI(k, v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
claw.sources[name] = {src, dst, nifo}
|
|
||||||
return not not ifo, e
|
|
||||||
end
|
|
@ -9,5 +9,6 @@ echo -n c1-sda > c1-eeprom/data.bin
|
|||||||
cd ..
|
cd ..
|
||||||
cp -r code/* laboratory/c1-sdb/
|
cp -r code/* laboratory/c1-sdb/
|
||||||
cp -r repository/* laboratory/c1-sdb/
|
cp -r repository/* laboratory/c1-sdb/
|
||||||
lua clawmerge.lua repository/data/app-claw/local.lua code/data/app-claw/local.lua > laboratory/c1-sdb/data/app-claw/local.lua
|
lua claw/clawconv.lua laboratory/c1-sdb/data/app-claw/ < claw/code-claw.lua > /dev/null
|
||||||
|
lua claw/clawconv.lua laboratory/c1-sdb/data/app-claw/ < claw/repo-claw.lua >> /dev/null
|
||||||
cp -r laboratory/c1-sdb/* laboratory/c1-sda/
|
cp -r laboratory/c1-sdb/* laboratory/c1-sda/
|
||||||
|
@ -8,4 +8,5 @@ mkdir repobuild
|
|||||||
cp -r code/* repobuild/
|
cp -r code/* repobuild/
|
||||||
cp -r repository/* repobuild/
|
cp -r repository/* repobuild/
|
||||||
cp inst-gold.lua repobuild/inst.lua
|
cp inst-gold.lua repobuild/inst.lua
|
||||||
lua clawmerge.lua repository/data/app-claw/local.lua code/data/app-claw/local.lua > repobuild/data/app-claw/local.lua
|
lua claw/clawconv.lua repobuild/data/app-claw/ < claw/code-claw.lua > repobuild/data/app-claw/local.c2l
|
||||||
|
lua claw/clawconv.lua repobuild/data/app-claw/ < claw/repo-claw.lua >> repobuild/data/app-claw/local.c2l
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
# This is released into the public domain.
|
# This is released into the public domain.
|
||||||
# No warranty is provided, implied or otherwise.
|
# No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
|
rm code/data/app-claw/*
|
||||||
|
lua claw/clawconv.lua code/data/app-claw/ < claw/code-claw.lua > /dev/null
|
||||||
rm code.tar
|
rm code.tar
|
||||||
# Hey, look behind you, there's nothing to see here.
|
# Hey, look behind you, there's nothing to see here.
|
||||||
# ... ok, are they seriously all named "Mann"?
|
# ... ok, are they seriously all named "Mann"?
|
||||||
@ -12,9 +14,10 @@ echo -n "--[[" >> inst.lua
|
|||||||
cat com2/code.tar.bd >> inst.lua
|
cat com2/code.tar.bd >> inst.lua
|
||||||
echo -n "]]" >> inst.lua
|
echo -n "]]" >> inst.lua
|
||||||
|
|
||||||
stat repobuild/data/app-claw/local.lua && rm -rf repobuild
|
stat repobuild/data/app-claw && rm -rf repobuild
|
||||||
mkdir repobuild
|
mkdir repobuild
|
||||||
cp -r code/* repobuild/
|
cp -r code/* repobuild/
|
||||||
cp -r repository/* repobuild/
|
cp -r repository/* repobuild/
|
||||||
cp inst.lua repobuild/
|
cp inst.lua repobuild/
|
||||||
lua clawmerge.lua repository/data/app-claw/local.lua code/data/app-claw/local.lua > repobuild/data/app-claw/local.lua
|
lua claw/clawconv.lua repobuild/data/app-claw/ < claw/code-claw.lua > repobuild/data/app-claw/local.c2l
|
||||||
|
lua claw/clawconv.lua repobuild/data/app-claw/ < claw/repo-claw.lua >> repobuild/data/app-claw/local.c2l
|
||||||
|
Loading…
Reference in New Issue
Block a user