aboutsummaryrefslogtreecommitdiff
path: root/mbs.lua
diff options
context:
space:
mode:
authorAndrew Lee <alee14498@protonmail.com>2020-11-15 13:41:43 -0500
committerAndrew Lee <alee14498@protonmail.com>2020-11-15 13:41:43 -0500
commitbcc38bf864e03522a37ec7a1dc1db953dbe7d473 (patch)
tree5ac40ed19006658cc875f511722c8d48bd695431 /mbs.lua
parent621e13d8bed7215a076e505eba998c7a0ec38519 (diff)
downloadbits-UI-bcc38bf864e03522a37ec7a1dc1db953dbe7d473.tar.gz
bits-UI-bcc38bf864e03522a37ec7a1dc1db953dbe7d473.tar.bz2
bits-UI-bcc38bf864e03522a37ec7a1dc1db953dbe7d473.zip
fixed mbs
Diffstat (limited to 'mbs.lua')
-rw-r--r--mbs.lua262
1 files changed, 262 insertions, 0 deletions
diff --git a/mbs.lua b/mbs.lua
new file mode 100644
index 0000000..34621cb
--- /dev/null
+++ b/mbs.lua
@@ -0,0 +1,262 @@
+local arg = table.pack(...)
+local root_dir = ".mbs"
+local rom_dir = "rom/.mbs"
+local install_dir = fs.exists(root_dir) and root_dir or rom_dir
+local repo_url = "https://raw.githubusercontent.com/SquidDev-CC/mbs/master/"
+
+--- Write a string with the given colour to the terminal
+local function write_coloured(colour, text)
+ local old = term.getTextColour()
+ term.setTextColour(colour)
+ io.write(text)
+ term.setTextColour(old)
+end
+
+--- Print usage for this program
+local commands = { "install", "modules", "module", "download" }
+local function print_usage()
+ local name = fs.getName(shell.getRunningProgram()):gsub("%.lua$", "")
+ write_coloured(colours.cyan, name .. " modules ") io.write("Print the status of all modules\n")
+ write_coloured(colours.cyan, name .. " module ") io.write("Print information about a given module\n")
+ write_coloured(colours.cyan, name .. " install ") io.write("Download all modules and create a startup file\n")
+ write_coloured(colours.cyan, name .. " download ") io.write("Download all modules WITHOUT creating a startup file\n")
+end
+
+--- Attempt to load a module from the given path, returning the module or false
+-- and an error message.
+local function load_module(path)
+ if fs.isDir(path) then return false, "Invalid module (is directory)" end
+
+ local fn, err = loadfile(path, _ENV)
+ if not fn then return false, "Invalid module (" .. err .. ")" end
+
+ local ok, res = pcall(fn)
+ if not ok then return false, "Invalid module (" .. res .. ")" end
+
+ if type(res) ~= "table" or type(res.description) ~= "string" or type(res.enabled) ~= "function" then
+ return false, "Malformed module"
+ end
+
+ return res
+end
+
+--- Setup all modules
+local function setup_module(module)
+ for _, setting in ipairs(module.settings) do
+ if settings.get(setting.name) == nil then
+ settings.set(setting.name, setting.default)
+ end
+ end
+end
+
+--- Download a set of files
+local function download_files(files)
+ if #files == 0 then return end
+
+ local urls = {}
+ for _, file in ipairs(files) do
+ local url = repo_url .. file
+ http.request(url)
+ urls[url] = file
+ end
+
+ while true do
+ local event, url, arg1 = os.pullEvent()
+ if event == "http_success" and urls[url] then
+ local handle = fs.open(fs.combine(root_dir, urls[url]), "w")
+ handle.write(arg1.readAll())
+ handle.close()
+ arg1.close()
+
+ urls[url] = nil
+ if next(urls) == nil then return end
+ elseif event == "http_failure" and urls[url] then
+ error("Could not download " .. urls[url], 0)
+ end
+ end
+end
+
+--- read completion helper, completes text using the given options
+local function complete_multi(text, options, add_spaces)
+ local results = {}
+ for n = 1, #options do
+ local option = options[n]
+ if #option + (add_spaces and 1 or 0) > #text and option:sub(1, #text) == text then
+ local result = option:sub(#text + 1)
+ if add_spaces then
+ results[#results + 1] = result .. " "
+ else
+ results[#results + 1] = result
+ end
+ end
+ end
+ return results
+end
+
+--- Append an object to a list if it is not already contained within
+local function add_unique(list, x)
+ for i = 1, #list do if list[i] == x then return end end
+ list[#list + 1] = x
+end
+
+local function load_all_modules()
+ -- Load all modules and update them.
+ local module_dir = fs.combine(root_dir, "modules")
+ local modules = fs.isDir(module_dir) and fs.list(module_dir) or {}
+
+ -- Add the default modules if not already there.
+ for _, module in ipairs { "lua.lua", "pager.lua", "readline.lua", "shell.lua" } do
+ add_unique(modules, module)
+ end
+
+ local files = {}
+ for i = 1, #modules do files[i] = "modules/" .. modules[i] end
+ download_files(files)
+
+ -- Scan for dependencies in enabled modules, downloading them as well
+ local deps = {}
+ for i = 1, #files do
+ local module = load_module(fs.combine(root_dir, files[i]))
+ if module then
+ setup_module(module)
+ if module.enabled() then
+ for _, dep in ipairs(module.dependencies) do deps[#deps + 1] = dep end
+ end
+ end
+ end
+ download_files(deps)
+end
+
+if arg.n == 0 then
+ printError("Expected some command")
+ print_usage()
+ error()
+elseif arg[1] == "download" then
+ load_all_modules()
+elseif arg[1] == "install" then
+ load_all_modules()
+
+ -- Move the existing startup file. We have to read the whole thing,
+ -- as otherwise we'd end up copying inside ourselves.
+ if fs.exists("startup") and not fs.isDir("startup") then
+ write_coloured(colours.cyan, "Moving your existing startup file to startup/30_startup.lua.\n")
+
+ local handle = fs.open("startup", "r")
+ local contents = handle.readAll()
+ handle.close()
+ fs.delete("startup")
+
+ handle = fs.open("startup/30_startup.lua", "w")
+ handle.write(contents)
+ handle.close()
+ end
+
+ -- Also move the startup.lua file afterwards
+ if fs.exists("startup.lua") and not fs.isDir("startup.lua") then
+ write_coloured(colours.cyan, "Moving your existing startup.lua file to startup/31_startup.lua.\n")
+ fs.move("startup.lua", "startup/31_startup.lua")
+ end
+
+ if fs.exists("startup/99_mbs.lua") then
+ write_coloured(colours.cyan, "Deleting the old startup/99_mbs.lua file. We now run before other startup files.\n")
+ fs.delete("startup/99_mbs.lua")
+ end
+
+ -- We'll run at the first possible position to ensure
+ local handle = fs.open("startup/00_mbs.lua", "w")
+ local current = shell.getRunningProgram()
+ handle.writeLine(("assert(loadfile(%q, _ENV))('startup', %q)"):format(current, current))
+ handle.close()
+
+ write_coloured(colours.green, "Installed! ")
+ io.write("Please reboot to apply changes.\n")
+elseif arg[1] == "startup" then
+ -- Gather a list of all modules
+ local module_dir = fs.combine(install_dir, "modules")
+ local files = fs.isDir(module_dir) and fs.list(module_dir) or {}
+
+ -- Load those modules and determine which are enabled.
+ local enabled = {}
+ local module_names = {}
+ for _, file in ipairs(files) do
+ local module = load_module(fs.combine(module_dir, file))
+ if module then
+ setup_module(module)
+ module_names[#module_names + 1] = file:gsub("%.lua$", "")
+ if module.enabled() then enabled[#enabled + 1] = module end
+ end
+ end
+
+ local current = arg[2] or shell.getRunningProgram()
+ shell.setCompletionFunction(current, function(_, index, text, previous)
+ if index == 1 then
+ return complete_multi(text, commands, true)
+ elseif index == 2 and previous[#previous] == "module" then
+ return complete_multi(text, module_names, false)
+ end
+ end)
+
+ -- Setup those modules
+ for _, module in ipairs(enabled) do
+ if type(module.setup) == "function" then module.setup(install_dir) end
+ end
+
+ -- And run the startup hook if needed
+ for _, module in ipairs(enabled) do
+ if type(module.startup) == "function" then module.startup(install_dir) end
+ end
+
+elseif arg[1] == "modules" then
+ local module_dir = fs.combine(install_dir, "modules")
+ local files = fs.isDir(module_dir) and fs.list(module_dir) or {}
+ local found_any = false
+
+ for _, file in ipairs(files) do
+ local res, err = load_module(fs.combine(module_dir, file))
+ write_coloured(colours.cyan, file:gsub("%.lua$", "") .. " ")
+ if res then
+ write(res.description)
+ if res.enabled() then
+ write_coloured(colours.green, " (enabled)")
+ else
+ write_coloured(colours.red, " (disabled)")
+ end
+ found_any = true
+ else
+ write_coloured(colours.red, err)
+ end
+
+ io.write("\n")
+ end
+
+ if not found_any then error("No modules found. Maybe try running the `install` command?", 0) end
+elseif arg[1] == "module" then
+ if not arg[2] then error("Expected module name", 0) end
+ local module, err = load_module(fs.combine(install_dir, fs.combine("modules", arg[2] .. ".lua")))
+ if not module then error(err, 0) end
+
+ io.write(module.description)
+ if module.enabled() then
+ write_coloured(colours.green, " (enabled)")
+ else
+ write_coloured(colours.red, " (disabled)")
+ end
+ io.write("\n\n")
+
+ for _, setting in ipairs(module.settings) do
+ local value = settings.get(setting.name)
+ write_coloured(colours.cyan, setting.name)
+ io.write(" " .. setting.description .. " (")
+ write_coloured(colours.yellow, textutils.serialise(value))
+ if value ~= setting.default then
+ io.write(", default is \n")
+ write_coloured(colours.yellow, textutils.serialise(setting.default))
+ end
+
+ io.write(")\n")
+ end
+else
+ printError("Unknown command")
+ print_usage()
+ error()
+end