From bee55ea2ac3e3addae5dbbe98cbd4552abe69f30 Mon Sep 17 00:00:00 2001 From: CadenCoaster <114967401+cadenthecreator@users.noreply.github.com> Date: Wed, 6 Aug 2025 11:23:32 -0700 Subject: [PATCH] Update setup.lua --- setup.lua | 304 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 302 insertions(+), 2 deletions(-) diff --git a/setup.lua b/setup.lua index 3192676..11ba6ef 100644 --- a/setup.lua +++ b/setup.lua @@ -1,13 +1,303 @@ +local function installMBS(loc,...) + local arg = {...} + local root_dir = settings.get("mbs.install_path", ".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.define then + settings.define(setting.name, { + description = setting.description, + type = setting.type, + default = setting.default, + }) + elseif 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(loc, "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 +end + +local function saveFile(url,file) + fs.makeDir(fs.getDir(file)) + local file = fs.open(file,"w") + file.write(http.get(url).readAll()) + file.close() +end + local function isYes(str) if str:lower():find("n") then return false end return true end +local mbs = false +local netmount = false + +term.write("install mildly better shell? (Y/n)") + +if isYes(read()) then + mbs = true +end term.write("setup netmountcc? (Y/n)") if isYes(read()) then + netmount = true +end + +if netmount then term.write("url: ") local url = read() term.write("user: ") @@ -24,10 +314,20 @@ if isYes(read()) then settings.save() fs.makeDir("/startup") local file = fs.open("/startup/-01_mount.lua","w") - file.write(http.get(url.."/mount.lua").readAll()) + local filedata = http.get(url.."/mount.lua").readAll() + if mbs then + filedata:gsub('shell%.run%("shell"%)','shell.run(".mbs.lua")') + end + file.write(filedata) file.close() end - print("done setting up netmountcc!") + print("done setting up netmountcc!") +end + +if mbs and not netmount then + installMBS("startup/00_mbs.lua","install") +elseif mbs and netmount then + installMBS(".mbs.lua","install") end os.reboot()