From 245895edfce31bb09da8cd635899fee4ba8c76fd Mon Sep 17 00:00:00 2001 From: hugeblank Date: Tue, 12 Nov 2019 19:10:13 -0800 Subject: [PATCH 1/8] Indentation and Path fixes --- allium.lua | 29 +++++++++++++++-------------- startup.lua | 10 +++++----- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/allium.lua b/allium.lua index 3362969..9adeab3 100644 --- a/allium.lua +++ b/allium.lua @@ -6,12 +6,11 @@ local raisin, color, semver, mojson, json = require("lib.raisin"), require("lib. -- Internal definitions local allium, plugins, group = {}, {}, {thread = raisin.group(1) , command = raisin.group(2)} --- Executing path +-- Get executing path local path = "/" for str in string.gmatch(shell.getRunningProgram(), ".+[/]") do path = path..str end - -- Defining custom print local nprint = _G.print local function print(prefix, wcText, ...) -- Magical function that takes in a table and changes the text color/writes at the same time @@ -238,7 +237,7 @@ allium.register = function(p_name, version, fullname) local loaded = {} plugins[real_name] = {commands = {}, loaded = loaded, name = fullname or p_name, version = version} local funcs, this = {}, plugins[real_name] - + funcs.command = function(c_name, command, info) -- name: name | command: executing function | info: help information -- Add a command for the user to execute assert(type(c_name) == "string", "Invalid argument #1 (string expected, got "..type(c_name)..")") @@ -265,7 +264,7 @@ allium.register = function(p_name, version, fullname) funcs.loadConfig = function(default) assert(type(default) == "table", "Invalid argument #1 (table expected, got "..type(default)..")") - local file = path.."/cfg/"..real_name..".lson" + local file = fs.combine(path, "/cfg/"..real_name..".lson") if not fs.exists(file) then local setting = fs.open(file,"w") setting.write(textutils.serialise(default)) @@ -296,8 +295,8 @@ allium.register = function(p_name, version, fullname) funcs.getPersistence = function(name) assert(type(name) ~= "nil", "Invalid argument #1 (expected anything but nil, got "..type(name)..")") - if fs.exists(path.."cfg/persistence.lson") then - local fper = fs.open(path.."cfg/persistence.lson", "r") + if fs.exists(fs.combine(path, "cfg/persistence.lson")) then + local fper = fs.open(fs.combine(path, "cfg/persistence.lson"), "r") local tpersist = textutils.unserialize(fper.readAll()) fper.close() if not tpersist[real_name] then @@ -309,7 +308,7 @@ allium.register = function(p_name, version, fullname) end return false end - + funcs.setPersistence = function(name, data) assert(type(name) ~= "nil", "Invalid argument #1 (expected anything but nil, got "..type(name)..")") local tpersist = funcs.getPersistence(name) or {} @@ -318,7 +317,7 @@ allium.register = function(p_name, version, fullname) end if type(name) == "string" then tpersist[real_name][name] = data - local fpers = fs.open(path.."cfg/persistence.lson", "w") + local fpers = fs.open(fs.combine(path, "cfg/persistence.lson"), "w") if not fpers then return false end @@ -330,10 +329,12 @@ allium.register = function(p_name, version, fullname) end funcs.module = function(container) - -- A container for all external functionality that other programs can utilize - assert(type(container) == "table", "Invalid argument #1 (table expected, got "..type(container)..")") - this.module = container - funcs.module = container + if type(funcs.module) == "function" then -- Prevent overwriting the module + -- A container for all external functionality that other programs can utilize + assert(type(container) == "table", "Invalid argument #1 (table expected, got "..type(container)..")") + this.module = container + funcs.module = container + end end funcs.import = function(p_name) -- request the API from a specific plugin @@ -703,8 +704,8 @@ raisin.thread(interpreter, 0) raisin.thread(player_scanner, 1) raisin.thread(update_interaction, 1) -if not fs.exists(path.."cfg/persistence.lson") then --In the situation that this is a first installation, let's do some setup - local fpers = fs.open(path.."cfg/persistence.lson", "w") +if not fs.exists(fs.combine(path, "cfg/persistence.lson")) then --In the situation that this is a first installation, let's do some setup + local fpers = fs.open(fs.combine(path, "cfg/persistence.lson"), "w") fpers.write("{}") fpers.close() end diff --git a/startup.lua b/startup.lua index f212986..e832e81 100644 --- a/startup.lua +++ b/startup.lua @@ -1,6 +1,6 @@ -- Allium version -- x.x.x-pr = unstable, potential breaking changes -local allium_version = "0.9.0" +local allium_version = "0.10.0-pr" local path = "/" local firstrun = false @@ -78,8 +78,8 @@ if config.updates.notify.dependencies then local depargs = { -- Depman args minus the task which can be inserted into the first index path, "https://raw.githubusercontent.com/hugeblank/allium-depman/master/listing.lson", - path.."/cfg/dependencies.lson", - path.."/lib", + fs.combine(path, "/cfg/dependencies.lson"), + fs.combine(path, "/lib"), allium_version } depman = function(task) @@ -141,7 +141,7 @@ if config.updates.notify.allium then print = null, write = null, shell = { - getRunningProgram = function() return path.."/lib/gget.lua" end + getRunningProgram = function() return fs.combine(path, "/lib/gget.lua") end } }, fs.combine(path, "/lib/gget.lua"), @@ -215,7 +215,7 @@ term.setCursorPos(1, 1) -- Running Allium multishell.setTitle(multishell.getCurrent(), "Allium") -local s, e = pcall(os.run, _ENV, path.."allium.lua", config, up) +local s, e = pcall(os.run, _ENV, fs.combine(path, "allium.lua"), config, up) if not s then printError(e) end From ef0dd423cfee36f68ce3e207cd1257624283d94b Mon Sep 17 00:00:00 2001 From: hugeblank Date: Tue, 12 Nov 2019 20:42:40 -0800 Subject: [PATCH 2/8] Initial Library Micro-manager Implementation Plugins now have the ability to save, load and update libraries. Cool. --- allium.lua | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/allium.lua b/allium.lua index 9adeab3..8707c0f 100644 --- a/allium.lua +++ b/allium.lua @@ -292,6 +292,75 @@ allium.register = function(p_name, version, fullname) return config end + do -- Library Managment micro service + local apis = {} + local meta_r = fs.open(fs.combine(path, "lib/plugins/metadata.lson"), "r") + local meta_t = {} + if meta_r then + meta_t = textutils.unserialise(meta_r.readAll()) or {} + meta_r.close() + end + + local loadAPI = function(url, name) + assert(type(url) == "string", "Invalid argument #1 (expected string got "..type(url)..")") + assert(type(name) == "string", "Invalid argument #2 (expected string got "..type(name)..")") + name = allium.sanitize(name) -- Remove invalid characters + if not meta_t[real_name] then meta_t[real_name] = {} end -- Create entry for plugin + local api -- Variable to put loaded lib + local fileName = fs.combine(path, "lib/plugins/"..real_name.."/"..name..".lua") -- Path for file + -- Handle updates + if meta_t[real_name][name] ~= url then -- If this is an updated version of the library + meta_t[real_name][name] = nil -- Clear the entry from metadata to add later + end + -- Handle downloading/loading + if not meta_t[real_name][name] then -- If there is no entry for this library + local handle = http.get(url) -- Download handle, make file name + if not handle then return false end -- If download failed, leave + local apiFile, contents = fs.open(fileName, "w"), handle.readAll() -- Create local file, get response contents + local s, e = load(contents, name, nil, _ENV) -- Compile program + if not s then return false, e end -- Leave if it errored + api = s + apiFile.write(contents) -- Save handle + meta_t[real_name][name] = url -- Add library entry + apiFile.close() handle.close() -- Close handles + else -- OTHERWISE the library entry exists, load locally. + local s, e = loadfile(fileName) -- Load the file. Duh. + if not s then return false, e end -- Exit if there was an error loading it + api = s + end + -- Rewrite data to disk + local meta_w = fs.open(fs.combine(path, "lib/plugins/metadata.lson"), "w") + meta_w.write(textutils.serialise(meta_t)) + meta_w.close() + apis[name] = true -- Mark library as loaded + return pcall(api) -- Safely load the library + end + local done = function() -- Do API cleaning + for name in pairs(apis) do + meta_t[real_name][name] = nil + end + for name in pairs(meta_t) do + local fileName = fs.combine(path, "lib/plugins/"..real_name.."/"..name..".lua") -- Path for file + fs.delete(fileName) + end + end + + funcs.loadLibs = function(t) + assert(type(t) == "table", "Invalid argument #1 (expected table got "..type(t)..")") + local out = {} + for name, url in pairs(t) do + assert(type(url) == "string", "Invalid URL "..tostring(url).." (expected string got "..type(url)..")") + assert(type(name) == "string", "Invalid name "..tostring(name).." (expected string got "..type(name)..")") + local temp = {loadAPI(url, name)} + table.remove(temp, 1) + out[name] = temp + end + done() + return out + end + end + + end funcs.getPersistence = function(name) assert(type(name) ~= "nil", "Invalid argument #1 (expected anything but nil, got "..type(name)..")") From 4ad81711a88171c0d90779ac49557031e3324519 Mon Sep 17 00:00:00 2001 From: hugeblank Date: Mon, 18 Nov 2019 20:43:12 -0800 Subject: [PATCH 3/8] Persistence -> Metadata | Plugin update manager implementation phoo a lot has changed. I was not expecting this to take a week --- allium.lua | 233 ++++++++++++++++++++++++++++++++++++++-------------- startup.lua | 4 - 2 files changed, 171 insertions(+), 66 deletions(-) diff --git a/allium.lua b/allium.lua index 8707c0f..b44665f 100644 --- a/allium.lua +++ b/allium.lua @@ -1,7 +1,7 @@ -- Allium by hugeblank -- Dependency Loading -local raisin, color, semver, mojson, json = require("lib.raisin"), require("lib.color"), require("lib.semver"), require("lib.mojson"), require("lib.json") +local raisin, color, semver, mojson, json, nap = require("lib.raisin"), require("lib.color"), require("lib.semver"), require("lib.mojson"), require("lib.json"), require("lib.nap") -- Internal definitions local allium, plugins, group = {}, {}, {thread = raisin.group(1) , command = raisin.group(2)} @@ -59,6 +59,65 @@ local function assert(condition, message, level) if not condition then error(message, (level or 0)+3) end end +local g_persistence +do -- Metadata magic table setup + local permdata, dummy + local function update() + local file = fs.open(fs.combine(path, "cfg/metadata.lson"), "r") + permdata = textutils.unserialise(file.readAll()) + if not permdata then permdata = {} end + file.close() + end + local function reset() + dummy = permdata + end + + local function makemt(keytbl) + return { + __index = function(_, k) + reset() + for i = 1, #keytbl do + dummy = dummy[keytbl[i]] + end + if type(dummy[k]) == "table" then + local newkeytbl = {} + for i = 1, #keytbl do + newkeytbl[#newkeytbl+1] = keytbl[i] + end + newkeytbl[#newkeytbl+1] = k + return setmetatable({}, makemt(newkeytbl)) + else + return dummy[k] + end + end, + __newindex = function(_, k, v) + allium.log(k) + reset() + for i = 1, #keytbl do + dummy = dummy[keytbl[i]] + end + dummy[k] = v + local file = fs.open(fs.combine(path, "cfg/metadata.lson"), "w") + assert(file, "Failed to open metadata file. Is the disk full?") + file.write(textutils.serialise(permdata)) + file.close() + end, + __len = function(_) + reset() + for i = 1, #keytbl do + dummy = dummy[keytbl[i]] + end + return #dummy + end + } + end + + update() + reset() + + g_persistence = setmetatable({}, makemt({})) +end + local cli = { info = {"[", colors.lime, "I", colors.white, "] "}, warn = {"[", colors.yellow, "W", colors.white, "] "}, @@ -153,7 +212,7 @@ end allium.getPlayers = function() local didexec, input = commands.exec("list") local out = {} - if not input[1]:find(":") then + if not didexec or not input[1]:find(":") then return false, input end for user in string.gmatch(input[1]:sub(input[1]:find(":")+1, -1), "%S+") do @@ -238,6 +297,13 @@ allium.register = function(p_name, version, fullname) plugins[real_name] = {commands = {}, loaded = loaded, name = fullname or p_name, version = version} local funcs, this = {}, plugins[real_name] + -- Redefining persistence locally + if not g_persistence[real_name] then + g_persistence[real_name] = {} + end + local persistence = g_persistence[real_name] + this.persistence = persistence + funcs.command = function(c_name, command, info) -- name: name | command: executing function | info: help information -- Add a command for the user to execute assert(type(c_name) == "string", "Invalid argument #1 (string expected, got "..type(c_name)..")") @@ -294,54 +360,51 @@ allium.register = function(p_name, version, fullname) do -- Library Managment micro service local apis = {} - local meta_r = fs.open(fs.combine(path, "lib/plugins/metadata.lson"), "r") - local meta_t = {} - if meta_r then - meta_t = textutils.unserialise(meta_r.readAll()) or {} - meta_r.close() - end local loadAPI = function(url, name) assert(type(url) == "string", "Invalid argument #1 (expected string got "..type(url)..")") assert(type(name) == "string", "Invalid argument #2 (expected string got "..type(name)..")") name = allium.sanitize(name) -- Remove invalid characters - if not meta_t[real_name] then meta_t[real_name] = {} end -- Create entry for plugin + if not persistence.libs then persistence.libs = {} end -- Create entry for plugin local api -- Variable to put loaded lib local fileName = fs.combine(path, "lib/plugins/"..real_name.."/"..name..".lua") -- Path for file -- Handle updates - if meta_t[real_name][name] ~= url then -- If this is an updated version of the library - meta_t[real_name][name] = nil -- Clear the entry from metadata to add later + if persistence.libs[name] ~= url then -- If this is an updated version of the library + persistence.libs[name] = nil -- Clear the entry from metadata to add later end -- Handle downloading/loading - if not meta_t[real_name][name] then -- If there is no entry for this library + if not persistence.libs[name] then -- If there is no entry for this library local handle = http.get(url) -- Download handle, make file name - if not handle then return false end -- If download failed, leave + if not handle then + handle.close() + return false + end -- If download failed, leave local apiFile, contents = fs.open(fileName, "w"), handle.readAll() -- Create local file, get response contents local s, e = load(contents, name, nil, _ENV) -- Compile program - if not s then return false, e end -- Leave if it errored + if not s then + apiFile.close() handle.close() -- Close handles + return false, e + end -- Leave if it errored api = s apiFile.write(contents) -- Save handle - meta_t[real_name][name] = url -- Add library entry + persistence.libs[name] = url -- Add library entry + allium.log(persistence.libs[name]) apiFile.close() handle.close() -- Close handles else -- OTHERWISE the library entry exists, load locally. local s, e = loadfile(fileName) -- Load the file. Duh. if not s then return false, e end -- Exit if there was an error loading it api = s end - -- Rewrite data to disk - local meta_w = fs.open(fs.combine(path, "lib/plugins/metadata.lson"), "w") - meta_w.write(textutils.serialise(meta_t)) - meta_w.close() apis[name] = true -- Mark library as loaded return pcall(api) -- Safely load the library end local done = function() -- Do API cleaning - for name in pairs(apis) do - meta_t[real_name][name] = nil - end - for name in pairs(meta_t) do - local fileName = fs.combine(path, "lib/plugins/"..real_name.."/"..name..".lua") -- Path for file - fs.delete(fileName) + for name in pairs(persistence.libs) do + if not apis[name] then + persistence.libs[name] = nil + local fileName = fs.combine(path, "lib/plugins/"..real_name.."/"..name..".lua") -- Path for file + fs.delete(fileName) + end end end @@ -360,43 +423,72 @@ allium.register = function(p_name, version, fullname) end end - end - - funcs.getPersistence = function(name) - assert(type(name) ~= "nil", "Invalid argument #1 (expected anything but nil, got "..type(name)..")") - if fs.exists(fs.combine(path, "cfg/persistence.lson")) then - local fper = fs.open(fs.combine(path, "cfg/persistence.lson"), "r") - local tpersist = textutils.unserialize(fper.readAll()) - fper.close() - if not tpersist[real_name] then - tpersist[real_name] = {} + do -- Plugin self-update micro service + funcs.update = {} + -- Magic table for the update micro API. + if not persistence.update then persistence.update = {} end + funcs.update.cache = persistence.update + + local default = {} + do -- Standard github update methods, written for you <3 + default.github = {} + local sha + default.github[1] = function(data) -- Update checker function + local github = nap("https://api.github.com") + if data.user and data.repo and data.branch then + local response = github.repos[data.user][data.repo].commits[data.branch]({ method = "GET" }) + if not response then return false end + local parsed = json.decode(response.readAll()) + if not parsed then return false end + if not data.sha then data.sha = parsed.sha end + if data.sha ~= parsed.sha then + sha = parsed.sha + return true + end + end + return false end - if type(name) == "string" then - return tpersist[real_name][name] + + default.github[2] = function(data) -- Update executor function + local null = function() end -- Please forgive me for this sin of a bodge + os.run({ + term = { + write=null, + setCursorPos=null, + getCursorPos=function() return 1, 1 end + }, + print = null, + write = null, + shell = { + getRunningProgram = function() return fs.combine(path, "/lib/gget.lua") end + } + }, + fs.combine(path, "/lib/gget.lua"), + data.user, + data.repo, + data.branch, + fs.combine(path, "plugins/"..real_name) + ) + data.sha = sha end end - return false - end - funcs.setPersistence = function(name, data) - assert(type(name) ~= "nil", "Invalid argument #1 (expected anything but nil, got "..type(name)..")") - local tpersist = funcs.getPersistence(name) or {} - if not tpersist[real_name] then - tpersist[real_name] = {} + funcs.update.getGithubMethods = function() + return table.unpack(default.github) end - if type(name) == "string" then - tpersist[real_name][name] = data - local fpers = fs.open(fs.combine(path, "cfg/persistence.lson"), "w") - if not fpers then - return false - end - fpers.write(textutils.serialise(tpersist)) - fpers.close() - return true + + funcs.update.setMethods = function(check, update) + if not up.check.plugins then up.check.plugins = {} end + if not up.run.plugins then up.run.plugins = {} end + up.check.plugins[real_name] = check + up.run.plugins[real_name] = update end - return false end + -- Magic table specifically for caching things that the user shouldn't see + if not persistence.cache then persistence.cache = {} end + funcs.cache = persistence.cache + funcs.module = function(container) if type(funcs.module) == "function" then -- Prevent overwriting the module -- A container for all external functionality that other programs can utilize @@ -503,8 +595,8 @@ end -- Packaging the Allium API if not package.preload["allium"] then - package.preload["allium"] = function() - return allium + package.preload["allium"] = function() + return allium end else print(cli.error, false, "Another instance of Allium is already running") @@ -709,11 +801,11 @@ local update_interaction = function() -- Update UI scanning and handling thread local suffixer if type(deps) == "table" and #deps > 0 then if #deps == 1 then - suffixer = {"Utility ", " is "} + suffixer = {"Utility ", " is"} else - suffixer = {"Utilities: ", " are "} + suffixer = {"Utilities: ", " are"} end - allium.log(suffixer[1]..table.concat(deps, ", ")..suffixer[2].."ready to be updated") + allium.log(suffixer[1]..table.concat(deps, ", ")..suffixer[2].." ready to be updated") common.run[#common.run+1] = {up.run.dependencies} elseif not suc then print(cli.error, true, "Error in checking for dependency updates: "..deps) @@ -729,7 +821,24 @@ local update_interaction = function() -- Update UI scanning and handling thread end end if config.updates.notify.plugins then - -- Things will also be here + local toUpdate = {} + local suffixer + for k, v in pairs(up.check.plugins or {}) do + if g_persistence[k] and g_persistence[k].update and v and up.run.plugins[k] then + if pcall(v, g_persistence[k].update) then + toUpdate[#toUpdate+1] = k + common.run[#common.run+1] = {up.run.plugins[k], g_persistence[k].update} + end + end + end + if #toUpdate == 1 then + suffixer = {"Plugin ", " is"} + elseif #toUpdate > 1 then + suffixer = {"Plugins: ", " are"} + end + if suffixer then + allium.log(suffixer[1]..table.concat(toUpdate, ", ")..suffixer[2].." ready to be updated") + end end common.refresh() end, function() -- User Interface @@ -773,8 +882,8 @@ raisin.thread(interpreter, 0) raisin.thread(player_scanner, 1) raisin.thread(update_interaction, 1) -if not fs.exists(fs.combine(path, "cfg/persistence.lson")) then --In the situation that this is a first installation, let's do some setup - local fpers = fs.open(fs.combine(path, "cfg/persistence.lson"), "w") +if not fs.exists(fs.combine(path, "cfg/metadata.lson")) then --In the situation that this is a first installation, let's do some setup + local fpers = fs.open(fs.combine(path, "cfg/metadata.lson"), "w") fpers.write("{}") fpers.close() end diff --git a/startup.lua b/startup.lua index e832e81..d6b7f07 100644 --- a/startup.lua +++ b/startup.lua @@ -161,10 +161,6 @@ if config.updates.notify.allium then end end -if config.updates.notify.plugins then - -- Things will be here -end - -- Final firstrun stuff if firstrun then print("Finalizing installation") From 1b7b5dd1d2038f3ba7a7bec706ab1d515cd1333c Mon Sep 17 00:00:00 2001 From: hugeblank Date: Mon, 18 Nov 2019 22:14:29 -0800 Subject: [PATCH 4/8] Debug | Clean up | Implement pastebin default methods With all the update service in the register method I felt like there may have been some unnecessary memory referencing/dereferencing going on. Lua may be smart about it but I don't trust Lua all that much, and Java even less. --- allium.lua | 139 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 87 insertions(+), 52 deletions(-) diff --git a/allium.lua b/allium.lua index b44665f..e6a8cb8 100644 --- a/allium.lua +++ b/allium.lua @@ -91,7 +91,6 @@ do -- Metadata magic table setup end end, __newindex = function(_, k, v) - allium.log(k) reset() for i = 1, #keytbl do dummy = dummy[keytbl[i]] @@ -118,6 +117,88 @@ do -- Metadata magic table setup g_persistence = setmetatable({}, makemt({})) end +local g_updates = {} +do + do -- Standard github update methods, written for you <3 + local github = {} + local sha + github[1] = function(data) -- Update checker function + local github = nap("https://api.github.com") + if data.user and data.repo and data.branch then + local response = github.repos[data.user][data.repo].commits[data.branch]({ method = "GET" }) + if not response then return false end + local parsed = json.decode(response.readAll()) + if not parsed then return false end + if not data.sha then data.sha = parsed.sha end + if data.sha ~= parsed.sha then + sha = parsed.sha + return true + end + end + return false + end + + github[2] = function(data) -- Update executor function + local null = function() end -- Please forgive me for this sin of a bodge + os.run({ + term = { + write=null, + setCursorPos=null, + getCursorPos=function() return 1, 1 end + }, + print = null, + write = null, + shell = { + getRunningProgram = function() return fs.combine(path, "/lib/gget.lua") end + } + }, + fs.combine(path, "/lib/gget.lua"), + data.user, + data.repo, + data.branch, + data.path or fs.combine(path, "plugins") + ) + data.sha = sha + end + + g_updates.github = function() + return table.unpack(github) + end + end + + do -- Standard pastebin update methods + local pastebin = {} + local p = fs.combine(path, "plugins") + pastebin[1] = function(data) -- Update checker function + if not (data.id and data.path and http.checkURL("https://pastebin.com/raw/"..data.id) and fs.exists(fs.combine(p, data.path))) then + return false + end + local content, file = http.get("https://pastebin.com/raw/"..data.id), fs.open(fs.combine(p, data.path), "r") + if not (content and file) then + file.close() + return false + end + local out = content.readAll() ~= file.readAll() + file.close() content.close() + return out + end + + pastebin[2] = function(data) -- Update runner function + local content, file = http.get("https://pastebin.com/raw/"..data.id), fs.open(fs.combine(p, data.path), "w") + if not file then + content.close() + error("Could not write to file. Is the disk full?") + end + file.write(content.readAll()) + file.close() content.close() + end + + g_updates.pastebin = function() + return table.unpack(pastebin) + end + end +end + local cli = { info = {"[", colors.lime, "I", colors.white, "] "}, warn = {"[", colors.yellow, "W", colors.white, "] "}, @@ -388,7 +469,6 @@ allium.register = function(p_name, version, fullname) api = s apiFile.write(contents) -- Save handle persistence.libs[name] = url -- Add library entry - allium.log(persistence.libs[name]) apiFile.close() handle.close() -- Close handles else -- OTHERWISE the library entry exists, load locally. local s, e = loadfile(fileName) -- Load the file. Duh. @@ -424,59 +504,13 @@ allium.register = function(p_name, version, fullname) end do -- Plugin self-update micro service - funcs.update = {} + funcs.update = { + default = g_updates + } -- Magic table for the update micro API. if not persistence.update then persistence.update = {} end funcs.update.cache = persistence.update - local default = {} - do -- Standard github update methods, written for you <3 - default.github = {} - local sha - default.github[1] = function(data) -- Update checker function - local github = nap("https://api.github.com") - if data.user and data.repo and data.branch then - local response = github.repos[data.user][data.repo].commits[data.branch]({ method = "GET" }) - if not response then return false end - local parsed = json.decode(response.readAll()) - if not parsed then return false end - if not data.sha then data.sha = parsed.sha end - if data.sha ~= parsed.sha then - sha = parsed.sha - return true - end - end - return false - end - - default.github[2] = function(data) -- Update executor function - local null = function() end -- Please forgive me for this sin of a bodge - os.run({ - term = { - write=null, - setCursorPos=null, - getCursorPos=function() return 1, 1 end - }, - print = null, - write = null, - shell = { - getRunningProgram = function() return fs.combine(path, "/lib/gget.lua") end - } - }, - fs.combine(path, "/lib/gget.lua"), - data.user, - data.repo, - data.branch, - fs.combine(path, "plugins/"..real_name) - ) - data.sha = sha - end - end - - funcs.update.getGithubMethods = function() - return table.unpack(default.github) - end - funcs.update.setMethods = function(check, update) if not up.check.plugins then up.check.plugins = {} end if not up.run.plugins then up.run.plugins = {} end @@ -825,7 +859,8 @@ local update_interaction = function() -- Update UI scanning and handling thread local suffixer for k, v in pairs(up.check.plugins or {}) do if g_persistence[k] and g_persistence[k].update and v and up.run.plugins[k] then - if pcall(v, g_persistence[k].update) then + local s, r = pcall(v, g_persistence[k].update) + if s and r then toUpdate[#toUpdate+1] = k common.run[#common.run+1] = {up.run.plugins[k], g_persistence[k].update} end From 1a92ded6296a6ff712339017cea5517a72bcae08 Mon Sep 17 00:00:00 2001 From: hugeblank Date: Tue, 19 Nov 2019 23:00:16 -0800 Subject: [PATCH 5/8] Cleanup before release --- allium.lua | 31 +++++++++++++++---------------- startup.lua | 28 +++++++++++++++------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/allium.lua b/allium.lua index e6a8cb8..7e96f16 100644 --- a/allium.lua +++ b/allium.lua @@ -4,7 +4,7 @@ local raisin, color, semver, mojson, json, nap = require("lib.raisin"), require("lib.color"), require("lib.semver"), require("lib.mojson"), require("lib.json"), require("lib.nap") -- Internal definitions -local allium, plugins, group = {}, {}, {thread = raisin.group(1) , command = raisin.group(2)} +local allium, plugins, group = {}, {}, {thread = raisin.group(1), command = raisin.group(2)} -- Get executing path local path = "/" @@ -12,8 +12,7 @@ for str in string.gmatch(shell.getRunningProgram(), ".+[/]") do path = path..str end -- Defining custom print -local nprint = _G.print -local function print(prefix, wcText, ...) -- Magical function that takes in a table and changes the text color/writes at the same time +local function aprint(prefix, wcText, ...) -- Magical function that takes in a table and changes the text color/writes at the same time local color = term.getTextColor() local function writeColor(cdata) for i = 1, #cdata do @@ -28,9 +27,9 @@ local function print(prefix, wcText, ...) -- Magical function that takes in a ta writeColor(prefix) if wcText then writeColor({...}) - nprint() + _G.print() else - nprint(...) + _G.print(...) end end @@ -250,8 +249,8 @@ do -- Allium image setup <3 term.setCursorPos(1, 1) term.setBackgroundColor(colors.black) -- Reset terminal and cursor term.setTextColor(colors.white) - print(cli.info, true, "Loading ", colors.magenta, "All", colors.purple, "i", colors.magenta, "um") - print(cli.info, true, "Initializing API") + aprint(cli.info, true, "Loading ", colors.magenta, "All", colors.purple, "i", colors.magenta, "um") + aprint(cli.info, true, "Initializing API") end allium.assert = assert @@ -263,11 +262,11 @@ end -- Logging wrapper functions allium.log = function(...) - print(cli.info, false, ...) + aprint(cli.info, false, ...) end allium.warn = function(...) - print(cli.warn, false, ...) + aprint(cli.warn, false, ...) end allium.tell = function(name, message, alt_name) @@ -588,7 +587,7 @@ allium.verify = function(param) -- Verification code ripped from DepMan instance return res end local range = param:find("&&") -- Matched a range definition - local comp, c_e = param:find("[><][=]*") -- I do love me some pattern matching + local comp = param:find("[><][=]*") -- I do love me some pattern matching if range then -- If there's a range beginning definition local a, b = compare(param:sub(1, range-1)), compare(param:sub(range+3, -1)) if a and b then @@ -633,7 +632,7 @@ if not package.preload["allium"] then return allium end else - print(cli.error, false, "Another instance of Allium is already running") + aprint(cli.error, false, "Another instance of Allium is already running") return end @@ -645,12 +644,12 @@ do -- Plugin loading process if (not fs.isDir(dir.."/"..plugin)) and plugin:find(".lua") then local file, err = loadfile(dir.."/"..plugin, _ENV) if not file then - print(cli.error, false, err) + aprint(cli.error, false, err) else local thread = function() local suc, err = pcall(file) if not suc then - print(cli.error, false, err) + aprint(cli.error, false, err) end end raisin.thread(thread, 0, loader_group) @@ -833,7 +832,7 @@ local update_interaction = function() -- Update UI scanning and handling thread if config.updates.notify.dependencies then local suc, deps = up.check.dependencies() local suffixer - if type(deps) == "table" and #deps > 0 then + if suc and type(deps) == "table" and #deps > 0 then if #deps == 1 then suffixer = {"Utility ", " is"} else @@ -842,7 +841,7 @@ local update_interaction = function() -- Update UI scanning and handling thread allium.log(suffixer[1]..table.concat(deps, ", ")..suffixer[2].." ready to be updated") common.run[#common.run+1] = {up.run.dependencies} elseif not suc then - print(cli.error, true, "Error in checking for dependency updates: "..deps) + aprint(cli.error, true, "Error in checking for dependency updates: "..table.concat(deps, ", ")) end end if config.updates.notify.allium then @@ -900,7 +899,7 @@ local update_interaction = function() -- Update UI scanning and handling thread for i = 1, #common.run do local s, err = pcall(table.unpack(common.run[i])) if not s then - print(cli.error, true, "Failed to execute an update: "..err) + aprint(cli.error, true, "Failed to execute an update: "..err) end end allium.log("Rebooting to apply updates...") diff --git a/startup.lua b/startup.lua index d6b7f07..d787ad8 100644 --- a/startup.lua +++ b/startup.lua @@ -71,7 +71,7 @@ up.check = {} up.run = {} if config.updates.notify.dependencies then - local depget = http.get("https://raw.githubusercontent.com/hugeblank/allium-depman/master/instance.lua") + local depget = http.get("https://raw.githubusercontent.com/hugeblank/allium-depman/046ce3e231eab81ac15275ffe8dd76ab6f2f8274/instance.lua") if depget then local contents = depget.readAll() depget.close() @@ -84,22 +84,24 @@ if config.updates.notify.dependencies then } depman = function(task) local out = {} - local temp = _G.print -- The good ol' switcheroo - _G.print = function(...) out = {...} end - local result = pcall(load(contents, "Depman", nil, _ENV), task, table.unpack(depargs)) - _G.print = temp - return result, table.unpack(out) + local temp = {_G.print, _G.printError, _G.error} -- The good ol' switcheroo + local function cache(...) + for i = 1, #({...}) do + out[#out+1] = ({...})[i] + temp[1](out[#out]) + end + end + _G.print, _G.printError, _G.error = cache, cache, cache -- Best CS map don't @ me (jk never played it) + local result, err = pcall(load(contents, "Depman", nil, _ENV), task, table.unpack(depargs)) + out[#out+1] = err + _G.print, _G.printError, _G.error = table.unpack(temp) + return result, out end up.check.dependencies = function() - local suc, out = depman("scan") - if suc then - return suc, textutils.unserialise(out) - else - return suc, out - end + return depman("scan") end up.run.dependencies = function() - return depman("upgrade") + depman("upgrade") end end end From e6d4933b4f0f4847d439993501f6ce96efe50fc4 Mon Sep 17 00:00:00 2001 From: hugeblank Date: Tue, 19 Nov 2019 23:38:30 -0800 Subject: [PATCH 6/8] Little changes to metadata magic tables --- allium.lua | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/allium.lua b/allium.lua index 7e96f16..27bbd10 100644 --- a/allium.lua +++ b/allium.lua @@ -67,17 +67,18 @@ do -- Metadata magic table setup if not permdata then permdata = {} end file.close() end - local function reset() + local function scope(kt) dummy = permdata + for i = 1, #kt do + dummy = dummy[kt[i]] + end end local function makemt(keytbl) return { + -- Dear Lua, make __modindex a thing. Sincerely, hugeblank __index = function(_, k) - reset() - for i = 1, #keytbl do - dummy = dummy[keytbl[i]] - end + scope(keytbl) if type(dummy[k]) == "table" then local newkeytbl = {} for i = 1, #keytbl do @@ -90,28 +91,22 @@ do -- Metadata magic table setup end end, __newindex = function(_, k, v) - reset() - for i = 1, #keytbl do - dummy = dummy[keytbl[i]] - end + scope(keytbl) dummy[k] = v local file = fs.open(fs.combine(path, "cfg/metadata.lson"), "w") assert(file, "Failed to open metadata file. Is the disk full?") file.write(textutils.serialise(permdata)) file.close() end, - __len = function(_) - reset() - for i = 1, #keytbl do - dummy = dummy[keytbl[i]] - end - return #dummy + __call = function() + scope(keytbl) + return dummy end } end update() - reset() + scope({}) g_persistence = setmetatable({}, makemt({})) end From 0e6541fe416dea7aa837cfe8765ffdb4bccb521c Mon Sep 17 00:00:00 2001 From: hugeblank Date: Wed, 20 Nov 2019 08:53:19 -0800 Subject: [PATCH 7/8] Final changes | 0.10.0 inbound --- allium.lua | 4 ++-- startup.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/allium.lua b/allium.lua index 27bbd10..e9fca90 100644 --- a/allium.lua +++ b/allium.lua @@ -13,7 +13,7 @@ for str in string.gmatch(shell.getRunningProgram(), ".+[/]") do end -- Defining custom print local function aprint(prefix, wcText, ...) -- Magical function that takes in a table and changes the text color/writes at the same time - local color = term.getTextColor() + local c = term.getTextColor() local function writeColor(cdata) for i = 1, #cdata do if type(cdata[i]) == "string" then @@ -22,7 +22,7 @@ local function aprint(prefix, wcText, ...) -- Magical function that takes in a t term.setTextColor(cdata[i]) end end - term.setTextColor(color) + term.setTextColor(c) end writeColor(prefix) if wcText then diff --git a/startup.lua b/startup.lua index d787ad8..9780b41 100644 --- a/startup.lua +++ b/startup.lua @@ -1,6 +1,6 @@ -- Allium version -- x.x.x-pr = unstable, potential breaking changes -local allium_version = "0.10.0-pr" +local allium_version = "0.10.0" local path = "/" local firstrun = false From a1ff30c0d206fbb569c483f48158b71900b17cf3 Mon Sep 17 00:00:00 2001 From: hugeblank Date: Wed, 20 Nov 2019 08:55:33 -0800 Subject: [PATCH 8/8] Oops I do love their music... --- startup.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/startup.lua b/startup.lua index 9780b41..8425eb8 100644 --- a/startup.lua +++ b/startup.lua @@ -18,7 +18,7 @@ end Configurations can be changed in /cfg/allium.lson ]] local default = { - label = "<&r&dAll&5&h(Kilroy wuz here.)&i(https://www.youtube.com/watch?v=XqZsoesa55w\\&t=15s)i&r&dum&r> ", -- The label the loader uses + label = "<&r&dAll&5&h(hugeblank <3 AJR)&i(https://www.youtube.com/watch?v=Vy1JwiXHwI4)i&r&dum&r> ", -- The label the loader uses import_timeout = 5, -- The maximum amount of time it takes to wait for a plugin dependency to provide its module. updates = { -- Various update configurations. notify = { -- Configurations to trigger notifications when parts of Allium are ready for an update