From 88bd38b9730fbdb27b541e29c6c053780cbf48ad Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Wed, 19 Jul 2023 18:40:02 +0200 Subject: [PATCH 01/51] Issue-30 Require Issues --- .gitignore | 1 - libs/scm/autocomplete.lua | 297 ++++++++++ libs/scm/config.lua | 136 +++++ libs/scm/log.lua | 24 + libs/scm/net.lua | 329 +++++++++++ libs/scm/scriptManager.lua | 330 ++++++++++++ libs/scm/ui.lua | 9 + scm.lua | 1049 +----------------------------------- scmInstaller.lua | 23 + 9 files changed, 1177 insertions(+), 1021 deletions(-) create mode 100644 libs/scm/autocomplete.lua create mode 100644 libs/scm/config.lua create mode 100644 libs/scm/log.lua create mode 100644 libs/scm/net.lua create mode 100644 libs/scm/scriptManager.lua create mode 100644 libs/scm/ui.lua create mode 100644 scmInstaller.lua diff --git a/.gitignore b/.gitignore index 708e7a1..db2c1a4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ -libs/ config/ TODO \ No newline at end of file diff --git a/libs/scm/autocomplete.lua b/libs/scm/autocomplete.lua new file mode 100644 index 0000000..56fd949 --- /dev/null +++ b/libs/scm/autocomplete.lua @@ -0,0 +1,297 @@ +---@class SCMAutoComplete +local Autocomplete = {} + +do + ---@class SCMNet + local Net + ---@class SCMScriptManager + local ScriptManager + ---@class SCMUI + local UI + ---@class SCMConfig + local config + ---@type fun(...):SCMLog + local log + -- TODO: add autocomplete + Autocomplete.commands = { + ["require"] = { + ---@param args table + func = function(args) + Net:download(args[2], "library", nil) + end, + description = [[ +Adds a library with all its dependencies. +If only a name is given, it will try to download from the official GitHub repositories. +$ require +$ require @ + ]] + }, + ["add"] = { + ---@param args table + func = function(args) + Net:download(args[2], "program", nil) + end, + description = [[ +Adds a program with all its dependencies. +If only a name is given, it will try to download from the official GitHub repositories. +$ add +$ add @ + ]] + }, + ["update"] = { + ---@param args table + func = function(args) + if args[2] == "all" then + ScriptManager:updateAllScripts() + elseif args[3] then + ScriptManager:updateScript(args[2], args[3]) + elseif args[2] then + ScriptManager:updateScript(args[2], nil) + else + Net:updateSCM() + end + end, + description = [[ +$ update + Updates this program (SCM) +$ update + Updates the script with the given name +$ update all + Updates all installed programs and libraries +$ update + Updates the script with an specific source + ]] + }, + ["remove"] = { + ---@param args table + func = function(args) + if args[2] == "all" then + ScriptManager:removeAllScripts() + else + ScriptManager:removeScript(args[2]) + end + end, + description = [[ +$ remove + Removes the given script +$ remove all + Removes all scripts + ]] + }, + ["list"] = { + ---@param _ table + func = function(_) + UI:listScripts() + end, + description = [[ +$ list + Lists all installed scripts + ]] + }, + ["config"] = { + ---@param args table + func = function(args) + if args[3] then + config:updateConfig(args[2], args[3]) + elseif args[2] then + if config.getAll(config)[args[2]] ~= nil then + print(args[2], tostring(config.getAll(config)[args[2]])) + end + else + print("You can currently configure the following variables:") + for cname, cvalue in pairs(config.getAll(config)) do + textutils.pagedPrint(cname .. "\t" .. tostring(cvalue)) + end + end + end, + description = [[ +$ config + Lists all available configurations +$ config + Shows a specific configuration +$ config + Updates the configuration + ]] + }, + ["refresh"] = { + func = function(args) + Autocomplete:refreshAutocomplete() + end, + description = [[ +$ refresh + Downloads the names of all programs and libraries of the official repository. + Refreshes autocomplete. + ]] + }, + ["help"] = { + ---@param args table + func = function(args) + if args[2] then + if Autocomplete.commands[args[2]] then + textutils.pagedPrint(args[2] .. "\n" .. Autocomplete.commands[args[2]]["description"]) + end + else + for k, v in pairs(Autocomplete.commands) do + textutils.pagedPrint("# " .. k .. "\n" .. v.description) + end + end + end, + description = [[ +$ help + Shows all available commands and their description +$ help + Shows the description of the given command + ]] + } + } + + function Autocomplete:init(libs) + log = function(...) libs["log"](libs.log, ...) end + Net = libs.Net + ScriptManager = libs.scriptManager + UI = libs.UI + config = libs.config + end + + function Autocomplete:addScriptToAutoComplete(source) + self.commands["update"]["args"] = self.commands["update"]["args"] or {} + self.commands["remove"]["args"] = self.commands["remove"]["args"] or {} + self.commands["update"]["args"][source.name] = {} + self.commands["remove"]["args"][source.name] = {} + end + + function Autocomplete:prepareAutocomplete() + -- prepare update and remove + ScriptManager:loadScripts() + local installedScripts = {} + for i = 1, #ScriptManager.scripts, 1 do + installedScripts[ScriptManager.scripts[i].name] = {} + end + installedScripts["all"] = {} + + self.commands["update"]["args"] = installedScripts + self.commands["remove"]["args"] = installedScripts + + -- prepare add and require + Net:loadRepoScripts() + + -- prepare config + local availableConfigs = {} + + for k, _ in pairs(config.getAll(config)) do + availableConfigs[k] = {} + end + + self.commands["config"]["args"] = availableConfigs + + -- prepare help + local availableCommands = {} + + for k, _ in pairs(self.commands) do + availableCommands[k] = {} + end + + self.commands["help"]["args"] = availableCommands + end + + function Autocomplete:refreshRepoScripts() + log("Downloading program and library names from GitHub...") + local repoScripts = {} + + local programs = {} + local libraries = {} + + local request = http.get(config.getAll(config)["apiGithubURL"] + .. config.getAll(config)["user"] + .. config.getAll(config)["apiGithubGetRepos"]) + if request then + local response = request.readAll() + request.close() + + local responseTable = textutils.unserializeJSON(response) + + local programSuffix = config.getAll(config)["programSuffix"] + local librarySuffix = config.getAll(config)["librarySuffix"] + + for i = 1, #responseTable, 1 do + local scriptName = responseTable[i]["name"] + if string.sub(scriptName, -string.len(programSuffix)) == programSuffix then + programs[ + string.sub(scriptName, 0, string.len(scriptName) - string.len(programSuffix)) + ] = {} + elseif string.sub(scriptName, -string.len(librarySuffix)) == librarySuffix then + libraries[ + string.sub(scriptName, 0, string.len(scriptName) - string.len(librarySuffix)) + ] = {} + end + end + log("Done") + else + log("Download failed") + end + + self.commands["add"]["args"] = programs + self.commands["require"]["args"] = libraries + + repoScripts["libraries"] = libraries + repoScripts["programs"] = programs + + local file = fs.open(config.getAll(config)["configDirectory"] + .. config.getAll(config)["repoScriptsFile"], "w") + if file then + file.write(textutils.serializeJSON(repoScripts)) + file.close() + end + end + + ---@param shell table + ---@param index integer + ---@param argument string + ---@param previous table + ---@return table | nil + local function completionFunction(shell, index, argument, previous) + local commands = {} + for k, _ in pairs(Autocomplete.commands) do + commands[k] = Autocomplete.commands[k]["args"] or {} + end + + local currArg = commands + for i = 2, #previous do + if currArg[previous[i]] then + currArg = currArg[previous[i]] + else + return nil + end + end + + local results = {} + for word, _ in pairs(currArg) do + if word:sub(1, #argument) == argument then + results[#results + 1] = word:sub(#argument + 1) + end + end + return results; + end + + function Autocomplete:updateAutocomplete() + shell.setCompletionFunction("scm", completionFunction) + end + + function Autocomplete:refreshAutocomplete() + self:refreshRepoScripts() + self:prepareAutocomplete() + self:updateAutocomplete() + end + + ---@param t table + function Autocomplete:setProgramms(t) + self.commands["add"]["args"] = t + end + + + ---@param t table + function Autocomplete:setLibaries(t) + self.commands["require"]["args"] = t + end +end +return Autocomplete diff --git a/libs/scm/config.lua b/libs/scm/config.lua new file mode 100644 index 0000000..5c7ddcb --- /dev/null +++ b/libs/scm/config.lua @@ -0,0 +1,136 @@ +---@class SCMConfig +local Config = {} + +do + ---@class SCMLog + local log = {} + + + ---@class SCMConfigData + Config.config = { + -- Git Settings (In this case on GitHub, not tested with others) + ["user"] = "mc-cc-scripts", + ["repository"] = "script-manager", + ["branch"] = "master", + ["rawURL"] = "https://raw.githubusercontent.com/", + ["programSuffix"] = "-prog", + ["librarySuffix"] = "-lib", + ["infoFile"] = "files.txt", -- provides the structure of a git repo (paths to all files) + ["apiGithubURL"] = "https://api.github.com/orgs/", + ["apiGithubGetRepos"] = "/repos?type=all&per_page=100&page=1", + ["apiGithubGetTags"] = "https://api.github.com/repos///tags", + ["installScript"] = "1kKZ8zTS", + -- Local Settings + ["currentVersion"] = "0.0.0", -- will get the newest version through the github api, no need to update here + ["updateAvailable"] = false, + ["lastVersionCheck"] = "1", + ["programDirectory"] = "progs/", + ["libraryDirectory"] = "libs/", + ["configDirectory"] = "config/", + ["configFile"] = "scm-config.json", + ["scriptFile"] = "scm-scripts.json", -- will be saved in configDirectory as well + ["verbose"] = true, + ["printPrefix"] = "[scm] ", + ["logDate"] = false, + ["writeLogFile"] = false, + ["logFilePath"] = "logs/scm-log.txt", + ["repoScriptsFile"] = "scm-repo-scripts.txt", -- will be saved in configDirectory as well + ["allowCLIPrefix"] = true, + ["cliPrefix"] = false, + ["SCMFileNames"] = { + ["Log"] = "Log", + ["UI"] = "UI" + } + } + + ---@source: https://stackoverflow.com/a/2705804/10495683 + ---@param T table + ---@return integer + local function tablelength(T) + local count = 0 + for _ in pairs(T) do count = count + 1 end + return count + end + + ---comment + ---@param lib SCMLibraries + function Config:init(lib) + log = lib["log"] + end + + --- saves the config to the config file + ---@param config SCMConfigData | nil + function Config:saveConfig(config) + config = config or self.config + local file = fs.open(config["configDirectory"] .. config["configFile"], "w") + file.write(textutils.serializeJSON(config)) + file.close() + end + + --- loads the config from the config file + ---@param config SCMConfigData | nil + function Config:loadConfig(config) + config = config or self.config + local file = fs.open(config["configDirectory"] .. config["configFile"], "r") + + if not file then + -- Create config file if it does not exist yet + self:saveConfig(config) + else + -- Load config from file + local temp = textutils.unserializeJSON(file.readAll()) or {} + -- Check if loaded config size is equal to the default size, + -- otherwise the config is corrupted and will be overwritten + if tablelength(temp) == tablelength(self.config) then + self.config = temp + else + self:saveConfig(config) + end + file.close() + end + end + + ---@param name string + ---@param value string + function Config:updateConfig(name, value) + local writeConfig = true + + if name and value then + if self.config[name] ~= nil then + if type(self.config[name]) == type(true) then + -- Check for boolean + if value == "true" then + self.config[name] = true + elseif value == "false" then + self.config[name] = false + end + else + -- We assume it's a string + self.config[name] = value + end + else + writeConfig = false + end + + if writeConfig then + self:saveConfig(self.config) + end + else + log:log("You can currently configure the following variables:") + for cname, cvalue in pairs(self.config) do + log:log(cname, tostring(cvalue)) + end + end + end + + function Config:getAll() + return self.config + end + + ---@param name string + ---@param value any + function Config:set(name, value) + self.config[name] = value + end +end +return Config diff --git a/libs/scm/log.lua b/libs/scm/log.lua new file mode 100644 index 0000000..6bdf829 --- /dev/null +++ b/libs/scm/log.lua @@ -0,0 +1,24 @@ +---@class SCMLog +local Log = {} + +do + local config = {} + function Log:init(lib) + config = lib["config"].config + end + + function Log:log(message) + local datetime = "" + if config["logDate"] then datetime = "" .. os.date("[%Y-%m-%d %H:%M:%S] ") end + if config["verbose"] then print(config["printPrefix"] .. message) end + + if config["writeLogFile"] then + local file = fs.open(config["logFilePath"], "a") + file.write(datetime .. message .. "\n") + file.close() + end + end +end + + +return Log \ No newline at end of file diff --git a/libs/scm/net.lua b/libs/scm/net.lua new file mode 100644 index 0000000..c75460c --- /dev/null +++ b/libs/scm/net.lua @@ -0,0 +1,329 @@ +---@class SCMNet +local Net = {} + +do + ---@type fun(...) + local log + ---@class SCMScriptManager + local ScriptManager + ---@type fun():SCMConfigData + local config + ---@class SCMConfig + local configLib + ---@class SCMAutoComplete + local Autocomplete + + function Net:init(libs) + log = function(...) libs["log"](libs.log, ...) end + ScriptManager = libs["scriptManager"] + config = function() + return libs["config"].getAll(libs.config) + end + configLib = libs["config"] + Autocomplete = libs["autocomplete"] + end + + ---@param target string + ---@param fileType string + ---@param updateObj table | nil + ---@return boolean + function Net:download(target, fileType, updateObj) + log("Downloading " .. fileType .. " " .. target .. "...") + if target == nil then + --@TODO: Error handling + return false + end + + local sourceObject = { + name = nil, + source = { + ["default"] = target + }, + type = fileType + } + + if updateObj then sourceObject.name = updateObj.name end + + -- Check for Pastebin + local name, code = ScriptManager:splitNameCode(target) + if name and code then + sourceObject.name = name + return ScriptManager:addScript(self:downloadPastebin(sourceObject, code, config()[fileType .. "Directory"], + updateObj)) + end + + -- We assume it's Git + -- The suffix is used to find the correct repository on GitHub + local suffix + if fileType == "library" then + suffix = config()["librarySuffix"] + else + suffix = config()["programSuffix"] + end + local repository = target .. suffix + sourceObject.name = target + + return ScriptManager:addScript(self:downloadGit(sourceObject, repository, config()[fileType .. "Directory"], + updateObj)) + end + + ---@param sourceObject table + ---@param code string + ---@param targetDirectory string + ---@param updateObj table | nil + ---@return table | nil + ---@return boolean + function Net:downloadPastebin(sourceObject, code, targetDirectory, updateObj) + -- Only download if it does not already exist, or if it should be updated + if fs.exists(targetDirectory .. sourceObject.name) then + if updateObj then + fs.delete(targetDirectory .. sourceObject.name) + sourceObject = updateObj + else + -- File already exists, you should use update + return nil, false + end + end + + if updateObj then + fs.delete(sourceObject.name) + end + + if sourceObject.type == "program" then + shell.run("pastebin", "get", code, sourceObject.name .. ".lua") + else + shell.run("pastebin", "get", code, targetDirectory .. sourceObject.name .. ".lua") + end + + return sourceObject, true + end + + ---@param sourceObject table + ---@param repository string + ---@param targetDirectory string + ---@param updateObj table | nil + ---@return table | nil + ---@return boolean + function Net:downloadGit(sourceObject, repository, targetDirectory, updateObj) + local baseUrl = config()["rawURL"] .. + config()["user"] .. "/" .. + repository .. "/" .. + config()["branch"] .. "/" + + local filesUrl = baseUrl .. config()["infoFile"] + + local request = http.get(filesUrl) + if request then + local content = request.readAll() + request.close() + + if content then + local file = fs.open(targetDirectory .. sourceObject.name + .. config()[sourceObject.type .. "Suffix"] + .. "/" .. config()["infoFile"], "w") + file.write(content) + file.close() + + local filePaths = {} + file = fs.open(targetDirectory .. sourceObject.name + .. config()[sourceObject.type .. "Suffix"] + .. "/" .. config()["infoFile"], "r") + for line in file.readLine do + filePaths[#filePaths + 1] = line + end + file.close() + + for i = 1, #filePaths, 1 do + local success = true + local tmpRequest = http.get(baseUrl .. filePaths[i]) + if tmpRequest then + local tmpContent = tmpRequest.readAll() + if tmpContent then + local tmpFile = fs.open(targetDirectory .. sourceObject.name + .. config()[sourceObject.type .. "Suffix"] + .. "/" .. filePaths[i], "w") + tmpFile.write(tmpContent) + tmpFile.close() + else + success = false + end + + tmpRequest.close() + else + success = false + end + + if not success then + return nil, false + end + end + + -- create a link that calls the file within the program directory + if sourceObject.type == "program" then + local progamLink = fs.open(sourceObject.name, "w") + progamLink.write("shell.execute(\"" .. targetDirectory .. sourceObject.name .. + config()[sourceObject.type .. "Suffix"] + .. "/" .. sourceObject.name .. ".lua" .. "\", ...)") + progamLink.close() + elseif sourceObject.type == "library" then + local libraryLink = fs.open(targetDirectory .. sourceObject.name .. ".lua", "w") + + local tmpName = sourceObject.name + if tmpName:find("%.") then + tmpName = tmpName:match("(.+)%..+$") + end + + libraryLink.write("return require(\"./" .. config()["libraryDirectory"] + .. tmpName .. config()[sourceObject.type .. "Suffix"] + .. "/" .. tmpName .. "\")") + libraryLink.close() + end + + return sourceObject, true + end + end + + return nil, false + end + + ---@param sourceObject table + ---@param targetDirectory string + ---@param updateObj table | nil + ---@return table | nil + ---@return boolean + function Net:downloadURL(sourceObject, targetDirectory, updateObj) + local sourceName = "default" or (updateObj and updateObj.sourceName) + if updateObj then + sourceObject.name = sourceObject.name or updateObj.name + end + + if not sourceObject.name then + sourceObject.name = self:getNameFromURL(sourceObject.source[sourceName]) + end + + local request = http.get(sourceObject.source[sourceName]) + + if request then + local content = request.readAll() + request.close() + + if content then + local file = fs.open(targetDirectory .. sourceObject.name, "w") + file.write(content) + file.close() + return sourceObject, true + end + end + + return nil, false + end + + ---@param url string + ---@return string + function Net:getNameFromURL(url) + -- Gets the filename + extension from a url (everything after last /) + local name = url:match("[^/]+$") + + -- Remove file extension if name contains a dot + if name:find("%.") then + name = name:match("(.+)%..+$") + end + + return name + end + + function Net:getNewestVersion() + local githubAPIgetTags = config()["apiGithubGetTags"] + githubAPIgetTags = githubAPIgetTags:gsub("", config()["user"]) + githubAPIgetTags = githubAPIgetTags:gsub("", config()["repository"]) + + local request = http.get(githubAPIgetTags) + + if request then + local content = request.readAll() + request.close() + local scmTags = textutils.unserializeJSON(content) + return true, scmTags[1]["name"] + else + log("Request to GitHub API failed.") + return false, "0.0.0" + end + end + + function Net:updateSCM() + log("Updating scm...") + shell.run("pastebin", "run", config().installScript) + local success, version = self:getNewestVersion() + if success then + configLib:set("currentVersion", version) + configLib:set("updateAvailable", false) + configLib:set("lastVersionCheck", os.day("utc")) + configLib:saveConfig() + end + end + + function Net:loadRepoScripts() + local file = fs.open(config()["configDirectory"] .. config()["repoScriptsFile"], "r") + + if not file then + self:refreshRepoScripts() + else + local repoScripts = textutils.unserializeJSON(file.readAll()) or nil + if repoScripts then + Autocomplete:setProgramms(repoScripts["programs"]) + Autocomplete:setLibaries(repoScripts["libraries"]) + end + + file.close() + end + end + + function Net:refreshRepoScripts() + log("Downloading program and library names from GitHub...") + local repoScripts = {} + + local programs = {} + local libraries = {} + + local request = http.get(config()["apiGithubURL"] .. config()["user"] .. self.config["apiGithubGetRepos"]) + if request then + local response = request.readAll() + request.close() + + local responseTable = textutils.unserializeJSON(response) + + local programSuffix = config()["programSuffix"] + local librarySuffix = config()["librarySuffix"] + + for i = 1, #responseTable, 1 do + local scriptName = responseTable[i]["name"] + if string.sub(scriptName, -string.len(programSuffix)) == programSuffix then + programs[ + string.sub(scriptName, 0, string.len(scriptName) - string.len(programSuffix)) + ] = {} + elseif string.sub(scriptName, -string.len(librarySuffix)) == librarySuffix then + libraries[ + string.sub(scriptName, 0, string.len(scriptName) - string.len(librarySuffix)) + ] = {} + end + end + log("Done") + else + log("Download failed") + end + + Autocomplete:setProgramms(programs) + Autocomplete:setLibaries(libraries) + + repoScripts["libraries"] = libraries + repoScripts["programs"] = programs + + local file = fs.open(config()["configDirectory"] .. config()["repoScriptsFile"], "w") + if file then + file.write(textutils.serializeJSON(repoScripts)) + file.close() + end + end +end + +return Net \ No newline at end of file diff --git a/libs/scm/scriptManager.lua b/libs/scm/scriptManager.lua new file mode 100644 index 0000000..13d5915 --- /dev/null +++ b/libs/scm/scriptManager.lua @@ -0,0 +1,330 @@ +--- done +---@class SCMScriptManager +local ScriptManager = { scripts = {} } + +do + + --#region imports + + ---@class SCMAutoComplete + local Autocomplete = {} + ---@type fun(...):SCMLog + local log + ---@type fun():SCMConfigData + local config + ---@class SCMNet + local Net + ---@class SCMConfig + local configLib + + --#endregion imports + + ---init function of the scriptManager + ---@param lib SCMLibraries + function ScriptManager:init(lib) + log = function(...) lib["log"](lib.log, ...) end + Autocomplete = lib["UI"] + config = function() + return lib["config"].getAll(lib.config) + end + Net = lib["Net"] + configLib = lib["config"] + end + + ---loads the scripts + function ScriptManager:loadScripts() + local file = fs.open(config()["configDirectory"] .. config()["scriptFile"], "r") + if not file then + self:saveScripts() + else + self.scripts = textutils.unserialiseJSON(file.readAll() or {}) + file.close() + end + end + + ---loads all scripts + function ScriptManager:saveScripts() + local file = fs.open(config()["configDirectory"] .. config()["scriptFile"], "w") + file.write(textutils.serializeJSON(self.scripts)) + file.close() + end + + ---adds a script to the script File + ---@param sourceObject table | nil + ---@param success boolean + ---@param config SCMConfigData + ---@return boolean + function ScriptManager:addScript(sourceObject, success) + if not success or not sourceObject then return false end + log("Adding script" .. sourceObject.name .. "...") + local scriptExists = false + + -- Check if script already exists, then update + for i = 1, #self.scripts, 1 do + if self.scripts[i].name == sourceObject.name and self.scripts[i].type == sourceObject.type then + scriptExists = true + if self.scripts[i].source[sourceObject.sourceName] then + self.scripts[i].source[sourceObject.sourceName] = sourceObject.source[sourceObject.sourceName] + self:saveScripts() + return true + end + end + end + + if not scriptExists then + log("Script added: " .. sourceObject.name) + table.insert(self.scripts, sourceObject) + else + log("Script already exists.") + return false + end + + self:saveScripts() + + Autocomplete:addScriptToAutoComplete(sourceObject) + Autocomplete:prepareAutocomplete() + Autocomplete:updateAutocomplete() + + return true + end + + ---@param name string + ---@param sourceName string + ---@return boolean + function ScriptManager:updateScript(name, sourceName) + if not sourceName then sourceName = "default" end + + local updateObj = { + ["name"] = name, + ["type"] = nil, + ["sourceName"] = sourceName, + ["source"] = {} + } + + for i = 1, #self.scripts, 1 do + if self.scripts[i].name == name then + updateObj.source[sourceName] = self.scripts[i].source[sourceName] + updateObj.type = self.scripts[i].type + end + end + + if updateObj.source[sourceName] and updateObj.type then + self:removeScript(name, true) + Net:download(updateObj.source[sourceName], updateObj.type, updateObj) + return true + end + + return false + end + + --- updates all scripts + function ScriptManager:updateAllScripts() + for i = 1, #self.scripts, 1 do + self:updateScript(self.scripts[i].name, "default") + end + end + + --- removes a script + ---@param name string + ---@param keepScriptConfig boolean + function ScriptManager:removeScript(name, keepScriptConfig) + log("Removing script: " .. name) + local o = {} + local scriptType = nil + + if keepScriptConfig ~= true then + for i = 1, #self.scripts, 1 do + if self.scripts[i].name ~= name then + table.insert(o, self.scripts[i]) + else + scriptType = self.scripts[i].type + end + end + + self.scripts = o + self:saveScripts() + end + + -- delete file + if scriptType and fs.exists(config()[scriptType .. "Directory"] .. name .. ".lua") then + fs.delete(config()[scriptType .. "Directory"] .. name .. config()[scriptType .. "Suffix"]) + if scriptType == "library" then + fs.delete(config()[scriptType .. "Directory"] .. name .. ".lua") + end + end + + if scriptType == "program" then + fs.delete(name) + end + + -- update autocomplete + Autocomplete:prepareAutocomplete() + Autocomplete:updateAutocomplete() + end + + --- removes all scripts + function ScriptManager:removeAllScripts() + local tmpScripts = {} + for i = 1, #self.scripts, 1 do + table.insert(tmpScripts, self.scripts[i].name) + end + + for i = 1, #tmpScripts, 1 do + self:removeScript(tmpScripts[i]) + end + end + +---@param name string +---@param localPath string | nil | unknown +function ScriptManager:checkRequirements(name, localPath) + log("Checking requirements of " .. (localPath or name) .. "...") + local file + if localPath then + file = fs.open(localPath, "r") + if not file then + file = fs.open('./' .. localPath .. ".lua", "r") + end + elseif fs.exists("./" .. config()["libraryDirectory"] .. name .. config()["librarySuffix"] .. "/" .. name .. ".lua") then + file = fs.open("./" .. config()["libraryDirectory"] + .. name .. config()["librarySuffix"] + .. "/" .. name .. ".lua", "r") + else + file = fs.open("./" .. config()["libraryDirectory"] .. name .. ".lua", "r") + end + if not file then log('File ' .. name .. ' not found') end + -- Find requirements by searching for comment --@requires name + local requires = {} + while true do + local line = file.readLine() + if not line then break end + + local find = string.find(line, "--@requires") + if find then + line = string.sub(line, find + 12) + local lineEnd = string.find(line, " ") + + local scriptName = nil + if lineEnd then + scriptName = string.sub(line, 0, lineEnd - 1) + else + scriptName = string.sub(line, 0) + end + + requires[#requires + 1] = scriptName + end + end + file.close() + + -- Install missing requirements + for i = 1, #requires do + local n = requires[i] + local tmpName, tmpCode = self:splitNameCode(n) + if tmpCode then n = tmpName end + + log("Trying to install " .. n .. "...") + + local scriptExists = false + for j = 1, #self.scripts, 1 do + if self.scripts[j].name == n then + scriptExists = true + end + end + + if not scriptExists then + if tmpCode then + Net:download(tmpName .. "@" .. tmpCode, "library") + else + Net:download(n, "library") + end + else + log(n .. " already exists.") + end + + self:checkRequirements(n --[[@as string]]) + end +end + +--- used when no script with the name was found online +--- searches locally for the script +---@param name string +---@return any | nil +local function fallbackRequire(name) + log(name .. " not found online, try to find locally") + --- if script does not exist + local possiblePath = { + name, + config()["libraryDirectory"] .. name, + config()["libraryDirectory"] .. name .. "/" .. name, + config()["libraryDirectory"] .. name .. "/" .. "init.lua" + } + local script + local success + ---TryFunction for Require + ---@param path string + ---@return any + local function tryRequire(path) + return require(path) + end + + for _, path in pairs(possiblePath) do + success, script = pcall(tryRequire, path) + if success then + ScriptManager:checkRequirements(name, path) + return script + end + end + log("Could not load " .. name) + return nil +end + + ---@param name string +---@return any +function ScriptManager:load(name) + log("Loading " .. name .. "...") + local scriptExists = false + for i = 1, #self.scripts, 1 do + if self.scripts[i].name == name then + scriptExists = true + end + end + + if not scriptExists then + Net:download(name, "library") + end + + scriptExists = false + for i = 1, #self.scripts, 1 do + if self.scripts[i].name == name then + scriptExists = true + end + end + + if scriptExists then + self:checkRequirements(name) + local path = "./" .. config()["libraryDirectory"] .. name + local script = require(path) + log("Done") + return script + end + + return fallbackRequire(name) +end + +---@param str string +---@return string | nil +---@return string | nil +function ScriptManager:splitNameCode(str) + local separator = string.find(str, "@") + + if separator then + local name = string.sub(str, 1, separator - 1) + local code = string.sub(str, separator + 1) + return name, code + end + + return nil, nil +end + +end + +return ScriptManager diff --git a/libs/scm/ui.lua b/libs/scm/ui.lua new file mode 100644 index 0000000..3c2d1c6 --- /dev/null +++ b/libs/scm/ui.lua @@ -0,0 +1,9 @@ +---@class SCMUI +local UI = {} + +do + function UI:listScripts() + end +end + +return UI \ No newline at end of file diff --git a/scm.lua b/scm.lua index efc0fd3..0f24b67 100644 --- a/scm.lua +++ b/scm.lua @@ -1,1029 +1,38 @@ ----Note: scm is not a real class, it should only exist once. ----@class scm -local scm = {} - --- Configuration -scm.config = { - -- Git Settings (In this case on GitHub, not tested with others) - ["user"] = "mc-cc-scripts", - ["repository"] = "script-manager", - ["branch"] = "master", - ["rawURL"] = "https://raw.githubusercontent.com/", - ["programSuffix"] = "-prog", - ["librarySuffix"] = "-lib", - ["infoFile"] = "files.txt", -- provides the structure of a git repo (paths to all files) - ["apiGithubURL"] = "https://api.github.com/orgs/", - ["apiGithubGetRepos"] = "/repos?type=all&per_page=100&page=1", - ["apiGithubGetTags"] = "https://api.github.com/repos///tags", - ["installScript"] = "1kKZ8zTS", - -- Local Settings - ["currentVersion"] = "0.0.0", -- will get the newest version through the github api, no need to update here - ["updateAvailable"] = false, - ["lastVersionCheck"] = "1", - ["programDirectory"] = "progs/", - ["libraryDirectory"] = "libs/", - ["configDirectory"] = "config/", - ["configFile"] = "scm-config.json", - ["scriptFile"] = "scm-scripts.json", -- will be saved in configDirectory as well - ["verbose"] = true, - ["printPrefix"] = "[scm] ", - ["logDate"] = false, - ["writeLogFile"] = false, - ["logFilePath"] = "logs/scm-log.txt", - ["repoScriptsFile"] = "scm-repo-scripts.txt", -- will be saved in configDirectory as well - ["allowCLIPrefix"] = true, - ["cliPrefix"] = false -} ----------------- - - -scm.scripts = {} -scm.commands = { - ["require"] = { - ---@param args table - func = function(args) - scm:download(args[2], "library", nil) - end, - description = [[ -Adds a library with all its dependencies. -If only a name is given, it will try to download from the official GitHub repositories. -$ require -$ require @ - ]] - }, - ["add"] = { - ---@param args table - func = function(args) - scm:download(args[2], "program", nil) - end, - description = [[ -Adds a program with all its dependencies. -If only a name is given, it will try to download from the official GitHub repositories. -$ add -$ add @ - ]] - }, - ["update"] = { - ---@param args table - func = function(args) - if args[2] == "all" then - scm:updateAllScripts() - elseif args[3] then - scm:updateScript(args[2], args[3]) - elseif args[2] then - scm:updateScript(args[2], nil) - else - scm:updateSCM() - end - end, - description = [[ -$ update - Updates this program (SCM) -$ update - Updates the script with the given name -$ update all - Updates all installed programs and libraries -$ update - Updates the script with an specific source - ]] - }, - ["remove"] = { - ---@param args table - func = function(args) - if args[2] == "all" then - scm:removeAllScripts() - else - scm:removeScript(args[2]) - end - end, - description = [[ -$ remove - Removes the given script -$ remove all - Removes all scripts - ]] - }, - ["list"] = { - ---@param _ table - func = function(_) - scm:listScripts() - end, - description = [[ -$ list - Lists all installed scripts - ]] - }, - ["config"] = { - ---@param args table - func = function(args) - if args[3] then - scm:updateConfig(args[2], args[3]) - elseif args[2] then - if scm.config[args[2]] ~= nil then - print(args[2], tostring(scm.config[args[2]])) - end - else - print("You can currently configure the following variables:") - for cname, cvalue in pairs(scm.config) do - textutils.pagedPrint(cname .. "\t" .. tostring(cvalue)) - end - end - end, - description = [[ -$ config - Lists all available configurations -$ config - Shows a specific configuration -$ config - Updates the configuration - ]] - }, - ["refresh"] = { - func = function(args) - scm:refreshAutocomplete() - end, - description = [[ -$ refresh - Downloads the names of all programs and libraries of the official repository. - Refreshes autocomplete. - ]] - }, - ["help"] = { - ---@param args table - func = function(args) - if args[2] then - if scm.commands[args[2]] then - textutils.pagedPrint(args[2] .. "\n" .. scm.commands[args[2]]["description"]) - end - else - for k, v in pairs(scm.commands) do - textutils.pagedPrint("# " .. k .. "\n" .. v.description) - end - end - end, - description = [[ -$ help - Shows all available commands and their description -$ help - Shows the description of the given command - ]] - } -} - -function scm:refreshRepoScripts() - self:log("Downloading program and library names from GitHub...") - local repoScripts = {} - - local programs = {} - local libraries = {} - - local request = http.get(self.config["apiGithubURL"] .. self.config["user"] .. self.config["apiGithubGetRepos"]) - if request then - local response = request.readAll() - request.close() - - local responseTable = textutils.unserializeJSON(response) - - local programSuffix = self.config["programSuffix"] - local librarySuffix = self.config["librarySuffix"] - - for i = 1, #responseTable, 1 do - local scriptName = responseTable[i]["name"] - if string.sub(scriptName, -string.len(programSuffix)) == programSuffix then - programs[ - string.sub(scriptName, 0, string.len(scriptName) - string.len(programSuffix)) - ] = {} - elseif string.sub(scriptName, -string.len(librarySuffix)) == librarySuffix then - libraries[ - string.sub(scriptName, 0, string.len(scriptName) - string.len(librarySuffix)) - ] = {} - end - end - scm:log("Done") - else - scm:log("Download failed") - end - - self.commands["add"]["args"] = programs - self.commands["require"]["args"] = libraries - - repoScripts["libraries"] = libraries - repoScripts["programs"] = programs - - local file = fs.open(self.config["configDirectory"] .. self.config["repoScriptsFile"], "w") - if file then - file.write(textutils.serializeJSON(repoScripts)) - file.close() - end -end - -function scm:loadRepoScripts() - local file = fs.open(self.config["configDirectory"] .. self.config["repoScriptsFile"], "r") - - if not file then - self:refreshRepoScripts() - else - local repoScripts = textutils.unserializeJSON(file.readAll()) or nil - if repoScripts then - self.commands["add"]["args"] = repoScripts["programs"] - self.commands["require"]["args"] = repoScripts["libraries"] - end - - file.close() - end -end - -function scm:prepareAutocomplete() - -- prepare update and remove - scm:loadScripts() - local installedScripts = {} - for i = 1, #self.scripts, 1 do - installedScripts[self.scripts[i].name] = {} - end - installedScripts["all"] = {} - - self.commands["update"]["args"] = installedScripts - self.commands["remove"]["args"] = installedScripts - - -- prepare add and require - self:loadRepoScripts() - - -- prepare config - local availableConfigs = {} - - for k, _ in pairs(self.config) do - availableConfigs[k] = {} - end - - self.commands["config"]["args"] = availableConfigs - - -- prepare help - local availableCommands = {} - - for k, _ in pairs(self.commands) do - availableCommands[k] = {} - end - - self.commands["help"]["args"] = availableCommands -end - ----@param shell table ----@param index integer ----@param argument string ----@param previous table ----@return table | nil -local function completionFunction(shell, index, argument, previous) - local commands = {} - for k, _ in pairs(scm.commands) do - commands[k] = scm.commands[k]["args"] or {} - end - - local currArg = commands - for i = 2, #previous do - if currArg[previous[i]] then - currArg = currArg[previous[i]] - else - return nil - end - end - - local results = {} - for word, _ in pairs(currArg) do - if word:sub(1, #argument) == argument then - results[#results + 1] = word:sub(#argument + 1) - end - end - return results; -end - -local function updateAutocomplete() - shell.setCompletionFunction("scm", completionFunction) -end - -function scm:refreshAutocomplete() - scm:refreshRepoScripts() - scm:prepareAutocomplete() - updateAutocomplete() -end - ----@param message string -function scm:log(message) - local datetime = "" - if self.config["logDate"] then datetime = os.date("[%Y-%m-%d %H:%M:%S] ") end - if self.config["verbose"] then print(self.config["printPrefix"] .. message) end - - if self.config["writeLogFile"] then - local file = fs.open(self.config["logFilePath"], "a") - file.write(datetime .. message .. "\n") - file.close() - end -end - ----@param str string ----@return string | nil ----@return string | nil -function scm:splitNameCode(str) - local separator = string.find(str, "@") - - if separator then - local name = string.sub(str, 1, separator - 1) - local code = string.sub(str, separator + 1) - return name, code - end - - return nil, nil -end - ----@param target string ----@param fileType string ----@param updateObj table | nil ----@return boolean -function scm:download(target, fileType, updateObj) - scm:log("Downloading " .. fileType .. " " .. target .. "...") - if target == nil then - --@TODO: Error handling - return false - end - - local sourceObject = { - name = nil, - source = { - ["default"] = target - }, - type = fileType - } - - if updateObj then sourceObject.name = updateObj.name end - - -- Check for Pastebin - local name, code = self:splitNameCode(target) - if name and code then - sourceObject.name = name - return scm:addScript(self:downloadPastebin(sourceObject, code, self.config[fileType .. "Directory"], updateObj)) - end - - -- We assume it's Git - -- The suffix is used to find the correct repository on GitHub - local suffix - if fileType == "library" then - suffix = self.config["librarySuffix"] - else - suffix = self.config["programSuffix"] - end - local repository = target .. suffix - sourceObject.name = target - - return scm:addScript(self:downloadGit(sourceObject, repository, self.config[fileType .. "Directory"], updateObj)) -end - ----@param sourceObject table ----@param repository string ----@param targetDirectory string ----@param updateObj table | nil ----@return table | nil ----@return boolean -function scm:downloadGit(sourceObject, repository, targetDirectory, updateObj) - local baseUrl = self.config["rawURL"] .. - self.config["user"] .. "/" .. - repository .. "/" .. - self.config["branch"] .. "/" - - local filesUrl = baseUrl .. self.config["infoFile"] - - local request = http.get(filesUrl) - if request then - local content = request.readAll() - request.close() - - if content then - local file = fs.open(targetDirectory .. sourceObject.name - .. self.config[sourceObject.type .. "Suffix"] - .. "/" .. self.config["infoFile"], "w") - file.write(content) - file.close() - - local filePaths = {} - file = fs.open(targetDirectory .. sourceObject.name - .. self.config[sourceObject.type .. "Suffix"] - .. "/" .. self.config["infoFile"], "r") - for line in file.readLine do - filePaths[#filePaths + 1] = line - end - file.close() - - for i = 1, #filePaths, 1 do - local success = true - local tmpRequest = http.get(baseUrl .. filePaths[i]) - if tmpRequest then - local tmpContent = tmpRequest.readAll() - if tmpContent then - local tmpFile = fs.open(targetDirectory .. sourceObject.name - .. self.config[sourceObject.type .. "Suffix"] - .. "/" .. filePaths[i], "w") - tmpFile.write(tmpContent) - tmpFile.close() - else - success = false - end - - tmpRequest.close() - else - success = false - end - - if not success then - return nil, false - end - end - - -- create a link that calls the file within the program directory - if sourceObject.type == "program" then - local progamLink = fs.open(sourceObject.name, "w") - progamLink.write("shell.execute(\"" .. targetDirectory .. sourceObject.name .. - self.config[sourceObject.type .. "Suffix"] - .. "/" .. sourceObject.name .. ".lua" .. "\", ...)") - progamLink.close() - elseif sourceObject.type == "library" then - local libraryLink = fs.open(targetDirectory .. sourceObject.name .. ".lua", "w") - - local tmpName = sourceObject.name - if tmpName:find("%.") then - tmpName = tmpName:match("(.+)%..+$") - end - - libraryLink.write("return require(\"./" .. self.config["libraryDirectory"] - .. tmpName .. self.config[sourceObject.type .. "Suffix"] - .. "/" .. tmpName .. "\")") - libraryLink.close() - end - - return sourceObject, true - end - end - - return nil, false -end - ----@param sourceObject table ----@param code string ----@param targetDirectory string ----@param updateObj table | nil ----@return table | nil ----@return boolean -function scm:downloadPastebin(sourceObject, code, targetDirectory, updateObj) - -- Only download if it does not already exist, or if it should be updated - if fs.exists(targetDirectory .. sourceObject.name) then - if updateObj then - fs.delete(targetDirectory .. sourceObject.name) - sourceObject = updateObj - else - -- File already exists, you should use update - return nil, false - end - end - - if updateObj then - fs.delete(sourceObject.name) - end - - if sourceObject.type == "program" then - shell.run("pastebin", "get", code, sourceObject.name .. ".lua") - else - shell.run("pastebin", "get", code, targetDirectory .. sourceObject.name .. ".lua") - end - - return sourceObject, true -end - ----@param sourceObject table ----@param targetDirectory string ----@param updateObj table | nil ----@return table | nil ----@return boolean -function scm:downloadURL(sourceObject, targetDirectory, updateObj) - local sourceName = "default" or updateObj.sourceName - if updateObj then - sourceObject.name = sourceObject.name or updateObj.name - end - - if not sourceObject.name then - sourceObject.name = self:getNameFromURL(sourceObject.source[sourceName]) - end - - local request = http.get(sourceObject.source[sourceName]) - - if request then - local content = request.readAll() - request.close() - - if content then - local file = fs.open(targetDirectory .. sourceObject.name, "w") - file.write(content) - file.close() - return sourceObject, true - end - end - - return nil, false -end - ----@param url string ----@return string -function scm:getNameFromURL(url) - -- Gets the filename + extension from a url (everything after last /) - local name = url:match("[^/]+$") - - -- Remove file extension if name contains a dot - if name:find("%.") then - name = name:match("(.+)%..+$") - end - - return name -end - ----@param sourceObject table | nil ----@param success boolean ----@return boolean -function scm:addScript(sourceObject, success) - if not success or not sourceObject then return false end - scm:log("Adding script " .. sourceObject.name .. "...") - local scriptExists = false - - -- Check if script already exists, then update - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == sourceObject.name and self.scripts[i].type == sourceObject.type then - scriptExists = true - if self.scripts[i].source[sourceObject.sourceName] then - self.scripts[i].source[sourceObject.sourceName] = sourceObject.source[sourceObject.sourceName] - self:saveScripts() - - return true - end - end - end - - if not scriptExists then - scm:log("Script added: " .. sourceObject.name) - table.insert(self.scripts, sourceObject) - else - scm:log("Script already exists.") - return false - end - - self:saveScripts() - - -- update for autocomplete - self.commands["update"]["args"] = self.commands["update"]["args"] or {} - self.commands["remove"]["args"] = self.commands["remove"]["args"] or {} - self.commands["update"]["args"][sourceObject.name] = {} - self.commands["remove"]["args"][sourceObject.name] = {} - self:prepareAutocomplete() - updateAutocomplete() - - return true -end - -function scm:saveScripts() - local file = fs.open(self.config["configDirectory"] .. self.config["scriptFile"], "w") - file.write(textutils.serializeJSON(self.scripts)) - file.close() -end - -function scm:loadScripts() - local file = fs.open(self.config["configDirectory"] .. self.config["scriptFile"], "r") - - if not file then - self:saveScripts() - else - self.scripts = textutils.unserializeJSON(file.readAll()) or {} - file.close() - end -end - -function scm:listScripts() - print("name", "type") - print("----------------------") - for i = 1, #self.scripts, 1 do - print(self.scripts[i].name, self.scripts[i].type) - end -end - ----@param name string -function scm:removeScript(name, keepScriptConfig) - scm:log("Removing script: " .. name) - local o = {} - local scriptType = nil - - if keepScriptConfig ~= true then - for i = 1, #self.scripts, 1 do - if self.scripts[i].name ~= name then - table.insert(o, self.scripts[i]) - else - scriptType = self.scripts[i].type - end - end - - self.scripts = o - self:saveScripts() - end - - -- delete file - if scriptType and fs.exists(self.config[scriptType .. "Directory"] .. name .. ".lua") then - fs.delete(self.config[scriptType .. "Directory"] .. name .. self.config[scriptType .. "Suffix"]) - if scriptType == "library" then - fs.delete(self.config[scriptType .. "Directory"] .. name .. ".lua") - end - end - - if scriptType == "program" then - fs.delete(name) - end - - -- update autocomplete - self:prepareAutocomplete() - updateAutocomplete() -end - -function scm:removeAllScripts() - local tmpScripts = {} - for i = 1, #self.scripts, 1 do - table.insert(tmpScripts, self.scripts[i].name) - end - - for i = 1, #tmpScripts, 1 do - self:removeScript(tmpScripts[i]) - end -end - ----@param name string ----@param sourceName string ----@return boolean -function scm:updateScript(name, sourceName) - if not sourceName then sourceName = "default" end - - local updateObj = { - ["name"] = name, - ["type"] = nil, - ["sourceName"] = sourceName, - ["source"] = {} +---@class SCMConfig +local Config = require('libs.scm.config') +---@class SCMNet +local Net = require('computer.1.libs.scm.net') +---@class SCMScriptManager +local ScriptManager = require('libs.scm.scriptManager') +---@class SCMAutocomplete +local Autocomplete = require('libs.scm.autocomplete') +---@class SCMUI +local UI = require('libs.scm.ui') + +---@class SCM +local SCM = {} + ---@class SCMLibraries + SCM.libraries = { + config = Config, + Net = Net, + scriptManager = ScriptManager, + autocomplete = Autocomplete, + UI = UI, } - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == name then - updateObj.source[sourceName] = self.scripts[i].source[sourceName] - updateObj.type = self.scripts[i].type - end - end - - if updateObj.source[sourceName] and updateObj.type then - self:removeScript(name, true) - self:download(updateObj.source[sourceName], updateObj.type, updateObj) - return true - end - - return false -end - -function scm:updateAllScripts() - for i = 1, #self.scripts, 1 do - self:updateScript(self.scripts[i].name, "default") - end -end - -function scm:updateSCM() - scm:log("Updating scm...") - shell.run("pastebin", "run", self.config.installScript) - local success, version = self:getNewestVersion() - if success then - self.config["currentVersion"] = version - self.config["updateAvailable"] = false - self.config["lastVersionCheck"] = os.day("utc") - self:saveConfig() - end -end - ----@source: https://stackoverflow.com/a/2705804/10495683 ----@param T table ----@return integer -local function tablelength(T) - local count = 0 - for _ in pairs(T) do count = count + 1 end - return count -end - -function scm:saveConfig() - local file = fs.open(self.config["configDirectory"] .. self.config["configFile"], "w") - file.write(textutils.serializeJSON(self.config)) - file.close() -end - -function scm:loadConfig() - local file = fs.open(self.config["configDirectory"] .. self.config["configFile"], "r") - - if not file then - -- Create config file if it does not exist yet - self:saveConfig() - else - -- Load config from file - local temp = textutils.unserializeJSON(file.readAll()) or {} - -- Check if loaded config size is equal to the default size, - -- otherwise the config is corrupted and will be overwritten - if tablelength(temp) == tablelength(self.config) then - self.config = temp - else - self:saveConfig() + function SCM:init() + for _, lib in ipairs(SCM.libraries) do + pcall(lib.init, lib) end - file.close() end -end - ----@param name string ----@param value string -function scm:updateConfig(name, value) - local writeConfig = true - - if name and value then - if self.config[name] ~= nil then - if type(self.config[name]) == type(true) then - -- Check for boolean - if value == "true" then - self.config[name] = true - elseif value == "false" then - self.config[name] = false - end - else - -- We assume it's a string - self.config[name] = value - end - else - writeConfig = false - end - if writeConfig then - self:saveConfig() - end - else - scm:log("You can currently configure the following variables:") - for cname, cvalue in pairs(self.config) do - scm:log(cname, tostring(cvalue)) - end + function SCM:load(name) + return ScriptManager:load(name) end -end ----@param name string ----@param localPath string | nil | unknown -function scm:checkRequirements(name, localPath) - scm:log("Checking requirements of " .. (localPath or name) .. "...") - local file - if localPath then - file = fs.open(localPath, "r") - if not file then - file = fs.open('./' .. localPath .. ".lua", "r") - end - elseif fs.exists("./" .. self.config["libraryDirectory"] .. name .. self.config["librarySuffix"] .. "/" .. name .. ".lua") then - file = fs.open("./" .. self.config["libraryDirectory"] - .. name .. self.config["librarySuffix"] - .. "/" .. name .. ".lua", "r") - else - file = fs.open("./" .. self.config["libraryDirectory"] .. name .. ".lua", "r") - end - if not file then scm:log('File ' .. name .. ' not found') end - -- Find requirements by searching for comment --@requires name - local requires = {} - while true do - local line = file.readLine() - if not line then break end - - local find = string.find(line, "--@requires") - if find then - line = string.sub(line, find + 12) - local lineEnd = string.find(line, " ") - - local scriptName = nil - if lineEnd then - scriptName = string.sub(line, 0, lineEnd - 1) - else - scriptName = string.sub(line, 0) - end - - requires[#requires + 1] = scriptName - end - end - file.close() - - -- Install missing requirements - for i = 1, #requires do - local n = requires[i] - local tmpName, tmpCode = self:splitNameCode(n) - if tmpCode then n = tmpName end - - scm:log("Trying to install " .. n .. "...") - - local scriptExists = false - for j = 1, #self.scripts, 1 do - if self.scripts[j].name == n then - scriptExists = true - end - end - - if not scriptExists then - if tmpCode then - self:download(tmpName .. "@" .. tmpCode, "library") - else - self:download(n, "library") - end - else - scm:log(n .. " already exists.") - end - - self:checkRequirements(n) - end -end - ---- used when no script with the name was found online ---- searches locally for the script ----@param name string ----@return any | nil -local function fallbackRequire(name) - scm:log(name .. " not found online, try to find locally") - --- if script does not exist - local possiblePath = { - name, - scm.config["libraryDirectory"] .. name, - scm.config["libraryDirectory"] .. name .. "/" .. name, - scm.config["libraryDirectory"] .. name .. "/" .. "init.lua" - } - local script - local success - ---TryFunction for Require - ---@param path string - ---@return any - local function tryRequire(path) - return require(path) - end - - for _, path in pairs(possiblePath) do - success, script = pcall(tryRequire, path) - if success then - scm:checkRequirements(name, path) - return script - end - end - scm:log("Could not load " .. name) - return nil -end - ----@param name string ----@return any -function scm:load(name) - scm:log("Loading " .. name .. "...") - local scriptExists = false - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == name then - scriptExists = true - end - end - - if not scriptExists then - self:download(name, "library") - end - - scriptExists = false - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == name then - scriptExists = true - end - end - - if scriptExists then - self:checkRequirements(name) - local path = "./" .. self.config["libraryDirectory"] .. name - local script = require(path) - scm:log("Done") - return script - end - - return fallbackRequire(name) -end - -function scm:getNewestVersion() - local githubAPIgetTags = self.config["apiGithubGetTags"] - githubAPIgetTags = githubAPIgetTags:gsub("", self.config["user"]) - githubAPIgetTags = githubAPIgetTags:gsub("", self.config["repository"]) - - local request = http.get(githubAPIgetTags) - - if request then - local content = request.readAll() - request.close() - local scmTags = textutils.unserializeJSON(content) - return true, scmTags[1]["name"] - else - self:log("Request to GitHub API failed.") - return false, "0.0.0" - end -end - -function scm:checkVersion() - if not self.config["updateAvailable"] and self.config["lastVersionCheck"] ~= '' .. os.day("utc") then - local success, newestVersion = scm:getNewestVersion() - if success and newestVersion ~= self.config["currentVersion"] then - self.config["updateAvailable"] = true - end - - self.config["lastVersionCheck"] = os.day("utc") .. '' - self:saveConfig() - end -end - -function scm:init() - -- Create directories - if not fs.exists(self.config["configDirectory"]) then - fs.makeDir(self.config["configDirectory"]) - end - if not fs.exists(self.config["libraryDirectory"]) then - fs.makeDir(self.config["libraryDirectory"]) - end - - self:loadConfig() - self:loadScripts() - - self:checkVersion() -end - ----@param resetPosition boolean | nil -function scm:cli(resetPosition, args) - if resetPosition ~= nil and resetPosition == true then - term.setCursorPos(1, 7) - end - - -- enable autocomplete - self:prepareAutocomplete() - updateAutocomplete() - - -- enable newline starting with `scm ` - if self.config["allowCLIPrefix"] then - self.config["cliPrefix"] = true - self:saveConfig() - end - - -- some interface - local _, cursorY = term.getCursorPos() - if cursorY < 7 then cursorY = 7 end - term.setCursorPos(1, cursorY) - term.blit(" ", - "ffffffffffffffffffffffffffffffff", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - term.blit(" SCM - Script Manager ", - "ffffffffffffffffffffffffffffffff", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - term.blit(" Autocomplete enabled. ", - "77777777777777777777777777777777", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - term.blit(" Type `scm help` to learn more. ", - "77777777ffffffff7777777777777777", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - if (self.config["updateAvailable"]) then - term.blit(" Update available! ", - "7eeeeeeeeeeeeeeeee77777777777777", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - end - term.blit(" ", - "ffffffffffffffffffffffffffffffff", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(2) - - if self.config["cliPrefix"] then - shell.run(read(nil, nil, shell.complete, "scm ")) - end -end - ----@param args table -function scm:handleArguments(args) - if #args == 0 then - self:cli(false, args) - return - end - - if args[1] and self.commands[args[1]] then - self.commands[args[1]]["func"](args) - if self.config["cliPrefix"] then - shell.run(read(nil, nil, shell.complete, "scm ")) - end + function SCM:loadScript(name) + return ScriptManager:loadScript(name) end -end -scm:init() -scm:handleArguments({ ... }) -return scm + +return SCM \ No newline at end of file diff --git a/scmInstaller.lua b/scmInstaller.lua new file mode 100644 index 0000000..6ecc620 --- /dev/null +++ b/scmInstaller.lua @@ -0,0 +1,23 @@ +-- Updates / Installs the Script Manager (scm) from GitHub +-- Run `pastebin run xxxxxx` +-- SCM: https://github.com/mc-cc-scripts/script-manager + +local files = { + 'libs/scm/autocomplete.lua', + 'libs/scm/config.lua', + 'libs/scm/net.lua', + 'libs/scm/scriptManager.lua', + 'libs/scm/ui.lua', + 'libs/scm.lua', + 'scm.lua', +} + +local function installFiles() + for _, script in ipairs(files) do + http.get('https://raw.githubusercontent.com/mc-cc-scripts/script-manager/master/' .. file, nil, function(_, data) + local file = fs.open(script, 'w') + file.write(data) + file.close() + end) + end +end \ No newline at end of file From ea5ac0610d82ef6f312c3efade3ad37f5681daf6 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Fri, 21 Jul 2023 16:53:46 +0200 Subject: [PATCH 02/51] Issue-30 Fixed require --- libs/scm/autocomplete.lua | 83 +++++++++++++++----------------------- libs/scm/config.lua | 13 ++---- libs/scm/log.lua | 2 +- libs/scm/net.lua | 41 ++++++------------- libs/scm/scriptManager.lua | 52 +++++++----------------- libs/scm/ui.lua | 2 +- scm.lua | 38 ++++------------- scmInstaller.lua | 2 +- 8 files changed, 73 insertions(+), 160 deletions(-) diff --git a/libs/scm/autocomplete.lua b/libs/scm/autocomplete.lua index 56fd949..5fe3555 100644 --- a/libs/scm/autocomplete.lua +++ b/libs/scm/autocomplete.lua @@ -1,23 +1,15 @@ ----@class SCMAutoComplete + +---@class Autocomplete local Autocomplete = {} +table.insert(scm, Autocomplete) do - ---@class SCMNet - local Net - ---@class SCMScriptManager - local ScriptManager - ---@class SCMUI - local UI - ---@class SCMConfig - local config - ---@type fun(...):SCMLog - local log - -- TODO: add autocomplete + local log = function(...) scm.log:log(...) end Autocomplete.commands = { ["require"] = { ---@param args table func = function(args) - Net:download(args[2], "library", nil) + scm.Net:download(args[2], "library", nil) end, description = [[ Adds a library with all its dependencies. @@ -29,7 +21,7 @@ $ require @ ["add"] = { ---@param args table func = function(args) - Net:download(args[2], "program", nil) + scm.Net:download(args[2], "program", nil) end, description = [[ Adds a program with all its dependencies. @@ -42,13 +34,13 @@ $ add @ ---@param args table func = function(args) if args[2] == "all" then - ScriptManager:updateAllScripts() + scm.ScriptManager:updateAllScripts() elseif args[3] then - ScriptManager:updateScript(args[2], args[3]) + scm.ScriptManager:updateScript(args[2], args[3]) elseif args[2] then - ScriptManager:updateScript(args[2], nil) + scm.ScriptManager:updateScript(args[2], nil) else - Net:updateSCM() + scm.Net:updateSCM() end end, description = [[ @@ -66,9 +58,9 @@ $ update ---@param args table func = function(args) if args[2] == "all" then - ScriptManager:removeAllScripts() + scm.ScriptManager:removeAllScripts() else - ScriptManager:removeScript(args[2]) + scm.ScriptManager:removeScript(args[2]) end end, description = [[ @@ -81,7 +73,7 @@ $ remove all ["list"] = { ---@param _ table func = function(_) - UI:listScripts() + scm.UI:listScripts() end, description = [[ $ list @@ -92,14 +84,14 @@ $ list ---@param args table func = function(args) if args[3] then - config:updateConfig(args[2], args[3]) + scm.config:updateConfig(args[2], args[3]) elseif args[2] then - if config.getAll(config)[args[2]] ~= nil then - print(args[2], tostring(config.getAll(config)[args[2]])) + if scm.config.getAll(scm.config)[args[2]] ~= nil then + print(args[2], tostring(scm.config.getAll(scm.config)[args[2]])) end else print("You can currently configure the following variables:") - for cname, cvalue in pairs(config.getAll(config)) do + for cname, cvalue in pairs(scm.config.getAll(scm.config)) do textutils.pagedPrint(cname .. "\t" .. tostring(cvalue)) end end @@ -115,7 +107,7 @@ $ config }, ["refresh"] = { func = function(args) - Autocomplete:refreshAutocomplete() + scm.Autocomplete:refreshAutocomplete() end, description = [[ $ refresh @@ -127,11 +119,11 @@ $ refresh ---@param args table func = function(args) if args[2] then - if Autocomplete.commands[args[2]] then - textutils.pagedPrint(args[2] .. "\n" .. Autocomplete.commands[args[2]]["description"]) + if scm.Autocomplete.commands[args[2]] then + textutils.pagedPrint(args[2] .. "\n" .. scm.Autocomplete.commands[args[2]]["description"]) end else - for k, v in pairs(Autocomplete.commands) do + for k, v in pairs(scm.Autocomplete.commands) do textutils.pagedPrint("# " .. k .. "\n" .. v.description) end end @@ -145,14 +137,6 @@ $ help } } - function Autocomplete:init(libs) - log = function(...) libs["log"](libs.log, ...) end - Net = libs.Net - ScriptManager = libs.scriptManager - UI = libs.UI - config = libs.config - end - function Autocomplete:addScriptToAutoComplete(source) self.commands["update"]["args"] = self.commands["update"]["args"] or {} self.commands["remove"]["args"] = self.commands["remove"]["args"] or {} @@ -162,10 +146,10 @@ $ help function Autocomplete:prepareAutocomplete() -- prepare update and remove - ScriptManager:loadScripts() + scm.ScriptManager:loadScripts() local installedScripts = {} - for i = 1, #ScriptManager.scripts, 1 do - installedScripts[ScriptManager.scripts[i].name] = {} + for i = 1, #scm.ScriptManager.scripts, 1 do + installedScripts[scm.ScriptManager.scripts[i].name] = {} end installedScripts["all"] = {} @@ -173,12 +157,12 @@ $ help self.commands["remove"]["args"] = installedScripts -- prepare add and require - Net:loadRepoScripts() + scm.Net:loadRepoScripts() -- prepare config local availableConfigs = {} - for k, _ in pairs(config.getAll(config)) do + for k, _ in pairs(scm.config.getAll()) do availableConfigs[k] = {} end @@ -201,17 +185,17 @@ $ help local programs = {} local libraries = {} - local request = http.get(config.getAll(config)["apiGithubURL"] - .. config.getAll(config)["user"] - .. config.getAll(config)["apiGithubGetRepos"]) + local request = http.get(scm.config.getAll(scm.config)["apiGithubURL"] + .. scm.config.getAll(scm.config)["user"] + .. scm.config.getAll(scm.config)["apiGithubGetRepos"]) if request then local response = request.readAll() request.close() local responseTable = textutils.unserializeJSON(response) - local programSuffix = config.getAll(config)["programSuffix"] - local librarySuffix = config.getAll(config)["librarySuffix"] + local programSuffix = scm.config.getAll(scm.config)["programSuffix"] + local librarySuffix = scm.config.getAll(scm.config)["librarySuffix"] for i = 1, #responseTable, 1 do local scriptName = responseTable[i]["name"] @@ -236,8 +220,8 @@ $ help repoScripts["libraries"] = libraries repoScripts["programs"] = programs - local file = fs.open(config.getAll(config)["configDirectory"] - .. config.getAll(config)["repoScriptsFile"], "w") + local file = fs.open(scm.config.getAll(scm.config)["configDirectory"] + .. scm.config.getAll(scm.config)["repoScriptsFile"], "w") if file then file.write(textutils.serializeJSON(repoScripts)) file.close() @@ -294,4 +278,3 @@ $ help self.commands["require"]["args"] = t end end -return Autocomplete diff --git a/libs/scm/config.lua b/libs/scm/config.lua index 5c7ddcb..afe737e 100644 --- a/libs/scm/config.lua +++ b/libs/scm/config.lua @@ -1,9 +1,7 @@ ---@class SCMConfig local Config = {} - +table.insert(scm, Config) do - ---@class SCMLog - local log = {} ---@class SCMConfigData @@ -52,11 +50,6 @@ do return count end - ---comment - ---@param lib SCMLibraries - function Config:init(lib) - log = lib["log"] - end --- saves the config to the config file ---@param config SCMConfigData | nil @@ -116,9 +109,9 @@ do self:saveConfig(self.config) end else - log:log("You can currently configure the following variables:") + scm.log:log("You can currently configure the following variables:") for cname, cvalue in pairs(self.config) do - log:log(cname, tostring(cvalue)) + scm.log:log(cname, tostring(cvalue)) end end end diff --git a/libs/scm/log.lua b/libs/scm/log.lua index 6bdf829..0690db0 100644 --- a/libs/scm/log.lua +++ b/libs/scm/log.lua @@ -1,6 +1,6 @@ ---@class SCMLog local Log = {} - +table.insert(scm, Log) do local config = {} function Log:init(lib) diff --git a/libs/scm/net.lua b/libs/scm/net.lua index c75460c..7c8ed75 100644 --- a/libs/scm/net.lua +++ b/libs/scm/net.lua @@ -1,27 +1,12 @@ ---@class SCMNet local Net = {} - +table.insert(scm, Net) do - ---@type fun(...) - local log - ---@class SCMScriptManager - local ScriptManager - ---@type fun():SCMConfigData - local config - ---@class SCMConfig - local configLib - ---@class SCMAutoComplete - local Autocomplete - - function Net:init(libs) - log = function(...) libs["log"](libs.log, ...) end - ScriptManager = libs["scriptManager"] - config = function() - return libs["config"].getAll(libs.config) - end - configLib = libs["config"] - Autocomplete = libs["autocomplete"] + local configLib = scm.config + local config = function() + return scm.config:getAll(scm.config.config) end + local log= function(...) scm.log:log(...) end ---@param target string ---@param fileType string @@ -45,10 +30,10 @@ do if updateObj then sourceObject.name = updateObj.name end -- Check for Pastebin - local name, code = ScriptManager:splitNameCode(target) + local name, code = scm.ScriptManager:splitNameCode(target) if name and code then sourceObject.name = name - return ScriptManager:addScript(self:downloadPastebin(sourceObject, code, config()[fileType .. "Directory"], + return scm.ScriptManager:addScript(self:downloadPastebin(sourceObject, code, config()[fileType .. "Directory"], updateObj)) end @@ -63,7 +48,7 @@ do local repository = target .. suffix sourceObject.name = target - return ScriptManager:addScript(self:downloadGit(sourceObject, repository, config()[fileType .. "Directory"], + return scm.ScriptManager:addScript(self:downloadGit(sourceObject, repository, config()[fileType .. "Directory"], updateObj)) end @@ -270,8 +255,8 @@ do else local repoScripts = textutils.unserializeJSON(file.readAll()) or nil if repoScripts then - Autocomplete:setProgramms(repoScripts["programs"]) - Autocomplete:setLibaries(repoScripts["libraries"]) + scm.Autocomplete:setProgramms(repoScripts["programs"]) + scm.Autocomplete:setLibaries(repoScripts["libraries"]) end file.close() @@ -285,7 +270,7 @@ do local programs = {} local libraries = {} - local request = http.get(config()["apiGithubURL"] .. config()["user"] .. self.config["apiGithubGetRepos"]) + local request = http.get(config()["apiGithubURL"] .. config()["user"] .. config()["apiGithubGetRepos"]) if request then local response = request.readAll() request.close() @@ -312,8 +297,8 @@ do log("Download failed") end - Autocomplete:setProgramms(programs) - Autocomplete:setLibaries(libraries) + scm.Autocomplete:setProgramms(programs) + scm.Autocomplete:setLibaries(libraries) repoScripts["libraries"] = libraries repoScripts["programs"] = programs diff --git a/libs/scm/scriptManager.lua b/libs/scm/scriptManager.lua index 13d5915..4829975 100644 --- a/libs/scm/scriptManager.lua +++ b/libs/scm/scriptManager.lua @@ -1,35 +1,12 @@ --- done ---@class SCMScriptManager local ScriptManager = { scripts = {} } - +table.insert(scm, ScriptManager) do - - --#region imports - - ---@class SCMAutoComplete - local Autocomplete = {} - ---@type fun(...):SCMLog - local log - ---@type fun():SCMConfigData - local config - ---@class SCMNet - local Net - ---@class SCMConfig - local configLib - - --#endregion imports - - ---init function of the scriptManager - ---@param lib SCMLibraries - function ScriptManager:init(lib) - log = function(...) lib["log"](lib.log, ...) end - Autocomplete = lib["UI"] - config = function() - return lib["config"].getAll(lib.config) - end - Net = lib["Net"] - configLib = lib["config"] + local config = function() + return scm.config:getAll(scm.config.config) end + local log = function(...) scm.log:log(...) end ---loads the scripts function ScriptManager:loadScripts() @@ -52,7 +29,6 @@ do ---adds a script to the script File ---@param sourceObject table | nil ---@param success boolean - ---@param config SCMConfigData ---@return boolean function ScriptManager:addScript(sourceObject, success) if not success or not sourceObject then return false end @@ -81,9 +57,9 @@ do self:saveScripts() - Autocomplete:addScriptToAutoComplete(sourceObject) - Autocomplete:prepareAutocomplete() - Autocomplete:updateAutocomplete() + scm.Autocomplete:addScriptToAutoComplete(sourceObject) + scm.Autocomplete:prepareAutocomplete() + scm.Autocomplete:updateAutocomplete() return true end @@ -110,7 +86,7 @@ do if updateObj.source[sourceName] and updateObj.type then self:removeScript(name, true) - Net:download(updateObj.source[sourceName], updateObj.type, updateObj) + scm.Net:download(updateObj.source[sourceName], updateObj.type, updateObj) return true end @@ -126,7 +102,7 @@ do --- removes a script ---@param name string - ---@param keepScriptConfig boolean + ---@param keepScriptConfig boolean | nil function ScriptManager:removeScript(name, keepScriptConfig) log("Removing script: " .. name) local o = {} @@ -158,8 +134,8 @@ do end -- update autocomplete - Autocomplete:prepareAutocomplete() - Autocomplete:updateAutocomplete() + scm.Autocomplete:prepareAutocomplete() + scm.Autocomplete:updateAutocomplete() end --- removes all scripts @@ -232,9 +208,9 @@ function ScriptManager:checkRequirements(name, localPath) if not scriptExists then if tmpCode then - Net:download(tmpName .. "@" .. tmpCode, "library") + scm.Net:download(tmpName .. "@" .. tmpCode, "library") else - Net:download(n, "library") + scm.Net:download(n, "library") end else log(n .. " already exists.") @@ -289,7 +265,7 @@ function ScriptManager:load(name) end if not scriptExists then - Net:download(name, "library") + scm.Net:download(name, "library") end scriptExists = false diff --git a/libs/scm/ui.lua b/libs/scm/ui.lua index 3c2d1c6..f89ba0e 100644 --- a/libs/scm/ui.lua +++ b/libs/scm/ui.lua @@ -1,6 +1,6 @@ ---@class SCMUI local UI = {} - +table.insert(scm, UI) do function UI:listScripts() end diff --git a/scm.lua b/scm.lua index 0f24b67..e746fbd 100644 --- a/scm.lua +++ b/scm.lua @@ -1,38 +1,14 @@ ----@class SCMConfig -local Config = require('libs.scm.config') ----@class SCMNet -local Net = require('computer.1.libs.scm.net') ----@class SCMScriptManager -local ScriptManager = require('libs.scm.scriptManager') ----@class SCMAutocomplete -local Autocomplete = require('libs.scm.autocomplete') ----@class SCMUI -local UI = require('libs.scm.ui') +require('libs.scm.config') +require('computer.1.libs.scm.net') +require('libs.scm.scriptManager') +require('libs.scm.autocomplete') +require('libs.scm.ui') ---@class SCM local SCM = {} - ---@class SCMLibraries - SCM.libraries = { - config = Config, - Net = Net, - scriptManager = ScriptManager, - autocomplete = Autocomplete, - UI = UI, - } - function SCM:init() - for _, lib in ipairs(SCM.libraries) do - pcall(lib.init, lib) - end + function SCM:Test() + end - - function SCM:load(name) - return ScriptManager:load(name) - end - - function SCM:loadScript(name) - return ScriptManager:loadScript(name) - end - return SCM \ No newline at end of file diff --git a/scmInstaller.lua b/scmInstaller.lua index 6ecc620..a21f492 100644 --- a/scmInstaller.lua +++ b/scmInstaller.lua @@ -14,7 +14,7 @@ local files = { local function installFiles() for _, script in ipairs(files) do - http.get('https://raw.githubusercontent.com/mc-cc-scripts/script-manager/master/' .. file, nil, function(_, data) + http.get('https://raw.githubusercontent.com/mc-cc-scripts/script-manager/master/' .. script, nil, function(_, data) local file = fs.open(script, 'w') file.write(data) file.close() From 40b1368f72fb8a18c7c2af6132eef448dd04250a Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Fri, 21 Jul 2023 16:58:33 +0200 Subject: [PATCH 03/51] Issue 30 fixed require again --- scm.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm.lua b/scm.lua index e746fbd..e2228cb 100644 --- a/scm.lua +++ b/scm.lua @@ -1,5 +1,5 @@ require('libs.scm.config') -require('computer.1.libs.scm.net') +require('libs.scm.net') require('libs.scm.scriptManager') require('libs.scm.autocomplete') require('libs.scm.ui') From 9e7054036dd8a3e2d545b32494b5a129e0a72952 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Sat, 22 Jul 2023 11:15:09 +0200 Subject: [PATCH 04/51] Issue-30 Fixed Requires --- libs/scm/autocomplete.lua | 64 +++++++++++++++++++------------------- libs/scm/config.lua | 2 +- libs/scm/log.lua | 2 +- libs/scm/net.lua | 28 ++++++++--------- libs/scm/scriptManager.lua | 30 +++++++++--------- libs/scm/ui.lua | 2 +- scm.lua | 4 +-- 7 files changed, 66 insertions(+), 66 deletions(-) diff --git a/libs/scm/autocomplete.lua b/libs/scm/autocomplete.lua index 5fe3555..7ef58a3 100644 --- a/libs/scm/autocomplete.lua +++ b/libs/scm/autocomplete.lua @@ -1,15 +1,15 @@ ---@class Autocomplete local Autocomplete = {} -table.insert(scm, Autocomplete) +SCM.Autocomplete = Autocomplete do - local log = function(...) scm.log:log(...) end + local log = function(...) SCM.log:log(...) end Autocomplete.commands = { ["require"] = { ---@param args table func = function(args) - scm.Net:download(args[2], "library", nil) + SCM.Net:download(args[2], "library", nil) end, description = [[ Adds a library with all its dependencies. @@ -21,7 +21,7 @@ $ require @ ["add"] = { ---@param args table func = function(args) - scm.Net:download(args[2], "program", nil) + SCM.Net:download(args[2], "program", nil) end, description = [[ Adds a program with all its dependencies. @@ -34,13 +34,13 @@ $ add @ ---@param args table func = function(args) if args[2] == "all" then - scm.ScriptManager:updateAllScripts() + SCM.ScriptManager:updateAllScripts() elseif args[3] then - scm.ScriptManager:updateScript(args[2], args[3]) + SCM.ScriptManager:updateScript(args[2], args[3]) elseif args[2] then - scm.ScriptManager:updateScript(args[2], nil) + SCM.ScriptManager:updateScript(args[2], nil) else - scm.Net:updateSCM() + SCM.Net:updateSCM() end end, description = [[ @@ -58,9 +58,9 @@ $ update ---@param args table func = function(args) if args[2] == "all" then - scm.ScriptManager:removeAllScripts() + SCM.ScriptManager:removeAllScripts() else - scm.ScriptManager:removeScript(args[2]) + SCM.ScriptManager:removeScript(args[2]) end end, description = [[ @@ -73,7 +73,7 @@ $ remove all ["list"] = { ---@param _ table func = function(_) - scm.UI:listScripts() + SCM.UI:listScripts() end, description = [[ $ list @@ -84,14 +84,14 @@ $ list ---@param args table func = function(args) if args[3] then - scm.config:updateConfig(args[2], args[3]) + SCM.Config:updateConfig(args[2], args[3]) elseif args[2] then - if scm.config.getAll(scm.config)[args[2]] ~= nil then - print(args[2], tostring(scm.config.getAll(scm.config)[args[2]])) + if SCM.Config.getAll(SCM.Config)[args[2]] ~= nil then + print(args[2], tostring(SCM.Config.getAll(SCM.Config)[args[2]])) end else print("You can currently configure the following variables:") - for cname, cvalue in pairs(scm.config.getAll(scm.config)) do + for cname, cvalue in pairs(SCM.Config.getAll(SCM.Config)) do textutils.pagedPrint(cname .. "\t" .. tostring(cvalue)) end end @@ -107,7 +107,7 @@ $ config }, ["refresh"] = { func = function(args) - scm.Autocomplete:refreshAutocomplete() + SCM.Autocomplete:refreshAutocomplete() end, description = [[ $ refresh @@ -119,11 +119,11 @@ $ refresh ---@param args table func = function(args) if args[2] then - if scm.Autocomplete.commands[args[2]] then - textutils.pagedPrint(args[2] .. "\n" .. scm.Autocomplete.commands[args[2]]["description"]) + if SCM.Autocomplete.commands[args[2]] then + textutils.pagedPrint(args[2] .. "\n" .. SCM.Autocomplete.commands[args[2]]["description"]) end else - for k, v in pairs(scm.Autocomplete.commands) do + for k, v in pairs(SCM.Autocomplete.commands) do textutils.pagedPrint("# " .. k .. "\n" .. v.description) end end @@ -146,10 +146,10 @@ $ help function Autocomplete:prepareAutocomplete() -- prepare update and remove - scm.ScriptManager:loadScripts() + SCM.ScriptManager:loadScripts() local installedScripts = {} - for i = 1, #scm.ScriptManager.scripts, 1 do - installedScripts[scm.ScriptManager.scripts[i].name] = {} + for i = 1, #SCM.ScriptManager.scripts, 1 do + installedScripts[SCM.ScriptManager.scripts[i].name] = {} end installedScripts["all"] = {} @@ -157,12 +157,12 @@ $ help self.commands["remove"]["args"] = installedScripts -- prepare add and require - scm.Net:loadRepoScripts() + SCM.Net:loadRepoScripts() -- prepare config local availableConfigs = {} - for k, _ in pairs(scm.config.getAll()) do + for k, _ in pairs(SCM.Config.getAll()) do availableConfigs[k] = {} end @@ -185,17 +185,17 @@ $ help local programs = {} local libraries = {} - local request = http.get(scm.config.getAll(scm.config)["apiGithubURL"] - .. scm.config.getAll(scm.config)["user"] - .. scm.config.getAll(scm.config)["apiGithubGetRepos"]) + local request = http.get(SCM.Config.getAll(SCM.Config)["apiGithubURL"] + .. SCM.Config.getAll(SCM.Config)["user"] + .. SCM.Config.getAll(SCM.Config)["apiGithubGetRepos"]) if request then local response = request.readAll() request.close() local responseTable = textutils.unserializeJSON(response) - local programSuffix = scm.config.getAll(scm.config)["programSuffix"] - local librarySuffix = scm.config.getAll(scm.config)["librarySuffix"] + local programSuffix = SCM.Config.getAll(SCM.Config)["programSuffix"] + local librarySuffix = SCM.Config.getAll(SCM.Config)["librarySuffix"] for i = 1, #responseTable, 1 do local scriptName = responseTable[i]["name"] @@ -220,8 +220,8 @@ $ help repoScripts["libraries"] = libraries repoScripts["programs"] = programs - local file = fs.open(scm.config.getAll(scm.config)["configDirectory"] - .. scm.config.getAll(scm.config)["repoScriptsFile"], "w") + local file = fs.open(SCM.Config.getAll(SCM.Config)["configDirectory"] + .. SCM.Config.getAll(SCM.Config)["repoScriptsFile"], "w") if file then file.write(textutils.serializeJSON(repoScripts)) file.close() @@ -258,7 +258,7 @@ $ help end function Autocomplete:updateAutocomplete() - shell.setCompletionFunction("scm", completionFunction) + shell.setCompletionFunction("SCM", completionFunction) end function Autocomplete:refreshAutocomplete() diff --git a/libs/scm/config.lua b/libs/scm/config.lua index afe737e..17348b6 100644 --- a/libs/scm/config.lua +++ b/libs/scm/config.lua @@ -1,6 +1,6 @@ ---@class SCMConfig local Config = {} -table.insert(scm, Config) +SCM.Config = Config do diff --git a/libs/scm/log.lua b/libs/scm/log.lua index 0690db0..9485b18 100644 --- a/libs/scm/log.lua +++ b/libs/scm/log.lua @@ -1,6 +1,6 @@ ---@class SCMLog local Log = {} -table.insert(scm, Log) +SCM.Log = Log do local config = {} function Log:init(lib) diff --git a/libs/scm/net.lua b/libs/scm/net.lua index 7c8ed75..065c7bd 100644 --- a/libs/scm/net.lua +++ b/libs/scm/net.lua @@ -1,12 +1,12 @@ ---@class SCMNet local Net = {} -table.insert(scm, Net) +SCM.Net = Net do - local configLib = scm.config + local configLib = SCM.Config local config = function() - return scm.config:getAll(scm.config.config) + return SCM.Config:getAll() end - local log= function(...) scm.log:log(...) end + local log= function(...) SCM.Log:log(...) end ---@param target string ---@param fileType string @@ -30,10 +30,10 @@ do if updateObj then sourceObject.name = updateObj.name end -- Check for Pastebin - local name, code = scm.ScriptManager:splitNameCode(target) + local name, code = SCM.ScriptManager:splitNameCode(target) if name and code then sourceObject.name = name - return scm.ScriptManager:addScript(self:downloadPastebin(sourceObject, code, config()[fileType .. "Directory"], + return SCM.ScriptManager:addScript(self:downloadPastebin(sourceObject, code, config()[fileType .. "Directory"], updateObj)) end @@ -48,7 +48,7 @@ do local repository = target .. suffix sourceObject.name = target - return scm.ScriptManager:addScript(self:downloadGit(sourceObject, repository, config()[fileType .. "Directory"], + return SCM.ScriptManager:addScript(self:downloadGit(sourceObject, repository, config()[fileType .. "Directory"], updateObj)) end @@ -227,8 +227,8 @@ do if request then local content = request.readAll() request.close() - local scmTags = textutils.unserializeJSON(content) - return true, scmTags[1]["name"] + local SCMTags = textutils.unserializeJSON(content) + return true, SCMTags[1]["name"] else log("Request to GitHub API failed.") return false, "0.0.0" @@ -236,7 +236,7 @@ do end function Net:updateSCM() - log("Updating scm...") + log("Updating SCM...") shell.run("pastebin", "run", config().installScript) local success, version = self:getNewestVersion() if success then @@ -255,8 +255,8 @@ do else local repoScripts = textutils.unserializeJSON(file.readAll()) or nil if repoScripts then - scm.Autocomplete:setProgramms(repoScripts["programs"]) - scm.Autocomplete:setLibaries(repoScripts["libraries"]) + SCM.Autocomplete:setProgramms(repoScripts["programs"]) + SCM.Autocomplete:setLibaries(repoScripts["libraries"]) end file.close() @@ -297,8 +297,8 @@ do log("Download failed") end - scm.Autocomplete:setProgramms(programs) - scm.Autocomplete:setLibaries(libraries) + SCM.Autocomplete:setProgramms(programs) + SCM.Autocomplete:setLibaries(libraries) repoScripts["libraries"] = libraries repoScripts["programs"] = programs diff --git a/libs/scm/scriptManager.lua b/libs/scm/scriptManager.lua index 4829975..5099f71 100644 --- a/libs/scm/scriptManager.lua +++ b/libs/scm/scriptManager.lua @@ -1,12 +1,12 @@ --- done ---@class SCMScriptManager local ScriptManager = { scripts = {} } -table.insert(scm, ScriptManager) +SCM.ScriptManager = ScriptManager do local config = function() - return scm.config:getAll(scm.config.config) + return SCM.Config:getAll() end - local log = function(...) scm.log:log(...) end + local log = function(...) SCM.Log:log(...) end ---loads the scripts function ScriptManager:loadScripts() @@ -57,15 +57,15 @@ do self:saveScripts() - scm.Autocomplete:addScriptToAutoComplete(sourceObject) - scm.Autocomplete:prepareAutocomplete() - scm.Autocomplete:updateAutocomplete() + SCM.Autocomplete:addScriptToAutoComplete(sourceObject) + SCM.Autocomplete:prepareAutocomplete() + SCM.Autocomplete:updateAutocomplete() return true end ---@param name string - ---@param sourceName string + ---@param sourceName string | nil ---@return boolean function ScriptManager:updateScript(name, sourceName) if not sourceName then sourceName = "default" end @@ -86,7 +86,7 @@ do if updateObj.source[sourceName] and updateObj.type then self:removeScript(name, true) - scm.Net:download(updateObj.source[sourceName], updateObj.type, updateObj) + SCM.Net:download(updateObj.source[sourceName], updateObj.type, updateObj) return true end @@ -134,8 +134,8 @@ do end -- update autocomplete - scm.Autocomplete:prepareAutocomplete() - scm.Autocomplete:updateAutocomplete() + SCM.Autocomplete:prepareAutocomplete() + SCM.Autocomplete:updateAutocomplete() end --- removes all scripts @@ -193,9 +193,9 @@ function ScriptManager:checkRequirements(name, localPath) -- Install missing requirements for i = 1, #requires do - local n = requires[i] + local n = requires[i] --[[@as string]] local tmpName, tmpCode = self:splitNameCode(n) - if tmpCode then n = tmpName end + if tmpCode then n = tmpName--[[@as string]] end log("Trying to install " .. n .. "...") @@ -208,9 +208,9 @@ function ScriptManager:checkRequirements(name, localPath) if not scriptExists then if tmpCode then - scm.Net:download(tmpName .. "@" .. tmpCode, "library") + SCM.Net:download(tmpName .. "@" .. tmpCode, "library") else - scm.Net:download(n, "library") + SCM.Net:download(n, "library") end else log(n .. " already exists.") @@ -265,7 +265,7 @@ function ScriptManager:load(name) end if not scriptExists then - scm.Net:download(name, "library") + SCM.Net:download(name, "library") end scriptExists = false diff --git a/libs/scm/ui.lua b/libs/scm/ui.lua index f89ba0e..1bb9456 100644 --- a/libs/scm/ui.lua +++ b/libs/scm/ui.lua @@ -1,6 +1,6 @@ ---@class SCMUI local UI = {} -table.insert(scm, UI) +SCM.UI = UI do function UI:listScripts() end diff --git a/scm.lua b/scm.lua index e2228cb..1b960af 100644 --- a/scm.lua +++ b/scm.lua @@ -1,11 +1,11 @@ +---@class SCM +SCM = {} require('libs.scm.config') require('libs.scm.net') require('libs.scm.scriptManager') require('libs.scm.autocomplete') require('libs.scm.ui') ----@class SCM -local SCM = {} function SCM:Test() From 27747e417dcf8aa9918fb9cbe8d95fb6323f9594 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Sun, 23 Jul 2023 21:27:44 +0200 Subject: [PATCH 05/51] Issue-30 first working tests --- .busted | 13 + libs/scm/autocomplete.lua | 4 +- libs/scm/config.lua | 19 +- libs/scm/net.lua | 99 ++- libs/scm/scriptManager.lua | 51 +- scm old.lua | 1032 +++++++++++++++++++++++++++++++ scm-1.0-0.rockspec | 25 + tests/Suite/fs.lua | 45 ++ tests/Suite/helperFunctions.lua | 5 + tests/Suite/http.lua | 7 + tests/Suite/json.lua | 184 ++++++ tests/testSuite.lua | 36 ++ tests/test_spec.lua | 180 ++++++ tests/testtemplate.lua | 27 + 14 files changed, 1670 insertions(+), 57 deletions(-) create mode 100644 .busted create mode 100644 scm old.lua create mode 100644 scm-1.0-0.rockspec create mode 100644 tests/Suite/fs.lua create mode 100644 tests/Suite/helperFunctions.lua create mode 100644 tests/Suite/http.lua create mode 100644 tests/Suite/json.lua create mode 100644 tests/testSuite.lua create mode 100644 tests/test_spec.lua create mode 100644 tests/testtemplate.lua diff --git a/.busted b/.busted new file mode 100644 index 0000000..16ae984 --- /dev/null +++ b/.busted @@ -0,0 +1,13 @@ +return { + _all = { + coverage = false + }, + default = { + verbose = true + }, + apiUnit = { + tags = "api", + ROOT = {"tests"}, + verbose = false + } +} \ No newline at end of file diff --git a/libs/scm/autocomplete.lua b/libs/scm/autocomplete.lua index 7ef58a3..2f42cb4 100644 --- a/libs/scm/autocomplete.lua +++ b/libs/scm/autocomplete.lua @@ -4,7 +4,7 @@ local Autocomplete = {} SCM.Autocomplete = Autocomplete do - local log = function(...) SCM.log:log(...) end + local log = function(...) SCM.Log:log(...) end Autocomplete.commands = { ["require"] = { ---@param args table @@ -162,7 +162,7 @@ $ help -- prepare config local availableConfigs = {} - for k, _ in pairs(SCM.Config.getAll()) do + for k, _ in pairs(SCM.Config:getAll()) do availableConfigs[k] = {} end diff --git a/libs/scm/config.lua b/libs/scm/config.lua index 17348b6..ca5eea9 100644 --- a/libs/scm/config.lua +++ b/libs/scm/config.lua @@ -1,3 +1,5 @@ + + ---@class SCMConfig local Config = {} SCM.Config = Config @@ -55,23 +57,28 @@ do ---@param config SCMConfigData | nil function Config:saveConfig(config) config = config or self.config - local file = fs.open(config["configDirectory"] .. config["configFile"], "w") - file.write(textutils.serializeJSON(config)) - file.close() + + local file = io.open(config["configDirectory"] .. config["configFile"], "w") + if not file then + os.execute("mkdir " .. config["configDirectory"]) + file = io.open(config["configDirectory"] .. config["configFile"], "w") + end + file:write(textutils.serializeJSON(config)) + file:close() end --- loads the config from the config file ---@param config SCMConfigData | nil function Config:loadConfig(config) config = config or self.config - local file = fs.open(config["configDirectory"] .. config["configFile"], "r") + local file = io.open(config["configDirectory"] .. config["configFile"], "r") if not file then -- Create config file if it does not exist yet self:saveConfig(config) else -- Load config from file - local temp = textutils.unserializeJSON(file.readAll()) or {} + local temp = textutils.unserializeJSON(file:read("*all")) or {} -- Check if loaded config size is equal to the default size, -- otherwise the config is corrupted and will be overwritten if tablelength(temp) == tablelength(self.config) then @@ -79,7 +86,7 @@ do else self:saveConfig(config) end - file.close() + file:close() end end diff --git a/libs/scm/net.lua b/libs/scm/net.lua index 065c7bd..00026b9 100644 --- a/libs/scm/net.lua +++ b/libs/scm/net.lua @@ -47,7 +47,6 @@ do end local repository = target .. suffix sourceObject.name = target - return SCM.ScriptManager:addScript(self:downloadGit(sourceObject, repository, config()[fileType .. "Directory"], updateObj)) end @@ -62,8 +61,12 @@ do -- Only download if it does not already exist, or if it should be updated if fs.exists(targetDirectory .. sourceObject.name) then if updateObj then - fs.delete(targetDirectory .. sourceObject.name) - sourceObject = updateObj + if fs then + fs.delete(targetDirectory .. sourceObject.name) + else + os.remove(targetDirectory .. sourceObject.name) + sourceObject = updateObj + end else -- File already exists, you should use update return nil, false @@ -71,10 +74,14 @@ do end if updateObj then - fs.delete(sourceObject.name) + if fs then + fs.delete(sourceObject.name) + else + os.remove(sourceObject.name) + end end - if sourceObject.type == "program" then + if sourceObject.type == "program" and code then shell.run("pastebin", "get", code, sourceObject.name .. ".lua") else shell.run("pastebin", "get", code, targetDirectory .. sourceObject.name .. ".lua") @@ -94,30 +101,46 @@ do config()["user"] .. "/" .. repository .. "/" .. config()["branch"] .. "/" - local filesUrl = baseUrl .. config()["infoFile"] local request = http.get(filesUrl) if request then local content = request.readAll() + if content == '404: Not Found' then + return nil, false + end request.close() - if content then local file = fs.open(targetDirectory .. sourceObject.name .. config()[sourceObject.type .. "Suffix"] .. "/" .. config()["infoFile"], "w") - file.write(content) - file.close() + file:write(content) + file:close() local filePaths = {} - file = fs.open(targetDirectory .. sourceObject.name - .. config()[sourceObject.type .. "Suffix"] - .. "/" .. config()["infoFile"], "r") - for line in file.readLine do - filePaths[#filePaths + 1] = line + if fs then + file = fs.open(targetDirectory .. sourceObject.name + .. config()[sourceObject.type .. "Suffix"] + .. "/" .. config()["infoFile"], "r") + + local line = file:read() + while line do + filePaths[#filePaths + 1] = line + line = file:read() + end + file:close() + else + file = fs.open(targetDirectory .. sourceObject.name + .. config()[sourceObject.type .. "Suffix"] + .. "/" .. config()["infoFile"], "r") + -- print(file:read()) + local line = file:read() + while line do + filePaths[#filePaths + 1] = line + line = file:read() + end + file:close() end - file.close() - for i = 1, #filePaths, 1 do local success = true local tmpRequest = http.get(baseUrl .. filePaths[i]) @@ -127,8 +150,15 @@ do local tmpFile = fs.open(targetDirectory .. sourceObject.name .. config()[sourceObject.type .. "Suffix"] .. "/" .. filePaths[i], "w") - tmpFile.write(tmpContent) - tmpFile.close() + if not tmpFile then + os.execute("mkdir " .. targetDirectory .. sourceObject.name + .. config()[sourceObject.type .. "Suffix"]) + tmpFile = fs.open(targetDirectory .. sourceObject.name + .. config()[sourceObject.type .. "Suffix"] + .. "/" .. filePaths[i], "w") + end + tmpFile:write(tmpContent) + tmpFile:close() else success = false end @@ -146,22 +176,26 @@ do -- create a link that calls the file within the program directory if sourceObject.type == "program" then local progamLink = fs.open(sourceObject.name, "w") - progamLink.write("shell.execute(\"" .. targetDirectory .. sourceObject.name .. + progamLink:write("shell.execute(\"" .. targetDirectory .. sourceObject.name .. config()[sourceObject.type .. "Suffix"] .. "/" .. sourceObject.name .. ".lua" .. "\", ...)") - progamLink.close() + progamLink:close() elseif sourceObject.type == "library" then local libraryLink = fs.open(targetDirectory .. sourceObject.name .. ".lua", "w") + if not libraryLink then + os.execute("mkdir " .. targetDirectory) + libraryLink = fs.open(targetDirectory .. sourceObject.name .. ".lua", "w") + end local tmpName = sourceObject.name if tmpName:find("%.") then tmpName = tmpName:match("(.+)%..+$") end - libraryLink.write("return require(\"./" .. config()["libraryDirectory"] + libraryLink:write("return require(\"./" .. config()["libraryDirectory"] .. tmpName .. config()[sourceObject.type .. "Suffix"] .. "/" .. tmpName .. "\")") - libraryLink.close() + libraryLink:close() end return sourceObject, true @@ -194,8 +228,12 @@ do if content then local file = fs.open(targetDirectory .. sourceObject.name, "w") - file.write(content) - file.close() + if not file then + os.execute("mkdir " .. targetDirectory) + file = fs.open(targetDirectory .. sourceObject.name, "w") + end + file:write(content) + file:close() return sourceObject, true end end @@ -253,13 +291,13 @@ do if not file then self:refreshRepoScripts() else - local repoScripts = textutils.unserializeJSON(file.readAll()) or nil + local repoScripts = textutils.unserializeJSON(file:read("*all")) or nil if repoScripts then SCM.Autocomplete:setProgramms(repoScripts["programs"]) SCM.Autocomplete:setLibaries(repoScripts["libraries"]) end - file.close() + file:close() end end @@ -274,7 +312,6 @@ do if request then local response = request.readAll() request.close() - local responseTable = textutils.unserializeJSON(response) local programSuffix = config()["programSuffix"] @@ -304,9 +341,13 @@ do repoScripts["programs"] = programs local file = fs.open(config()["configDirectory"] .. config()["repoScriptsFile"], "w") + if not file then + os.execute("mkdir " .. config()["configDirectory"]) + file = fs.open(config()["configDirectory"] .. config()["repoScriptsFile"], "w") + end if file then - file.write(textutils.serializeJSON(repoScripts)) - file.close() + file:write(textutils.serializeJSON(repoScripts)) + file:close() end end end diff --git a/libs/scm/scriptManager.lua b/libs/scm/scriptManager.lua index 5099f71..d994b87 100644 --- a/libs/scm/scriptManager.lua +++ b/libs/scm/scriptManager.lua @@ -1,6 +1,13 @@ ---- done +--- @class SCMScript +---@field name string +---@field type string<"local"|"program"|"library"> +---@field sourceName string +---@field source table + ---@class SCMScriptManager -local ScriptManager = { scripts = {} } +local ScriptManager = { + ---@class SCMScript + scripts = {} } SCM.ScriptManager = ScriptManager do local config = function() @@ -14,33 +21,37 @@ do if not file then self:saveScripts() else - self.scripts = textutils.unserialiseJSON(file.readAll() or {}) - file.close() + self.scripts = textutils.unserializeJSON(file:read("*all") or "") + file:close() end end ---loads all scripts function ScriptManager:saveScripts() local file = fs.open(config()["configDirectory"] .. config()["scriptFile"], "w") - file.write(textutils.serializeJSON(self.scripts)) - file.close() + if not file then + os.execute("mkdir " .. config["configDirectory"]) + file = fs.open(config["configDirectory"] .. config["scriptFile"], "w") + end + file:write(textutils.serializeJSON(self.scripts)) + file:close() end ---adds a script to the script File - ---@param sourceObject table | nil + ---@param script table | nil ---@param success boolean ---@return boolean - function ScriptManager:addScript(sourceObject, success) - if not success or not sourceObject then return false end - log("Adding script" .. sourceObject.name .. "...") + function ScriptManager:addScript(script, success) + if not success or not script then return false end + log("Adding script" .. script.name .. "...") local scriptExists = false -- Check if script already exists, then update for i = 1, #self.scripts, 1 do - if self.scripts[i].name == sourceObject.name and self.scripts[i].type == sourceObject.type then + if self.scripts[i].name == script.name and self.scripts[i].type == script.type then scriptExists = true - if self.scripts[i].source[sourceObject.sourceName] then - self.scripts[i].source[sourceObject.sourceName] = sourceObject.source[sourceObject.sourceName] + if self.scripts[i].source[script.sourceName] then + self.scripts[i].source[script.sourceName] = script.source[script.sourceName] self:saveScripts() return true end @@ -48,8 +59,8 @@ do end if not scriptExists then - log("Script added: " .. sourceObject.name) - table.insert(self.scripts, sourceObject) + log("Script added: " .. script.name) + table.insert(self.scripts, script) else log("Script already exists.") return false @@ -57,7 +68,7 @@ do self:saveScripts() - SCM.Autocomplete:addScriptToAutoComplete(sourceObject) + SCM.Autocomplete:addScriptToAutoComplete(script) SCM.Autocomplete:prepareAutocomplete() SCM.Autocomplete:updateAutocomplete() @@ -160,7 +171,7 @@ function ScriptManager:checkRequirements(name, localPath) if not file then file = fs.open('./' .. localPath .. ".lua", "r") end - elseif fs.exists("./" .. config()["libraryDirectory"] .. name .. config()["librarySuffix"] .. "/" .. name .. ".lua") then + elseif fs.open("./" .. config()["libraryDirectory"] .. name .. config()["librarySuffix"] .. "/" .. name .. ".lua", "r") then file = fs.open("./" .. config()["libraryDirectory"] .. name .. config()["librarySuffix"] .. "/" .. name .. ".lua", "r") @@ -171,7 +182,7 @@ function ScriptManager:checkRequirements(name, localPath) -- Find requirements by searching for comment --@requires name local requires = {} while true do - local line = file.readLine() + local line = file:read() if not line then break end local find = string.find(line, "--@requires") @@ -189,7 +200,7 @@ function ScriptManager:checkRequirements(name, localPath) requires[#requires + 1] = scriptName end end - file.close() + file:close() -- Install missing requirements for i = 1, #requires do @@ -225,6 +236,7 @@ end ---@param name string ---@return any | nil local function fallbackRequire(name) + log(name .. " not found online, try to find locally") --- if script does not exist local possiblePath = { @@ -263,7 +275,6 @@ function ScriptManager:load(name) scriptExists = true end end - if not scriptExists then SCM.Net:download(name, "library") end diff --git a/scm old.lua b/scm old.lua new file mode 100644 index 0000000..2fdddfb --- /dev/null +++ b/scm old.lua @@ -0,0 +1,1032 @@ +---Note: scm is not a real class, it should only exist once. +---@class scm +local scm = {} + +-- Configuration +scm.config = { + -- Git Settings (In this case on GitHub, not tested with others) + ["user"] = "mc-cc-scripts", + ["repository"] = "script-manager", + ["branch"] = "master", + ["rawURL"] = "https://raw.githubusercontent.com/", + ["programSuffix"] = "-prog", + ["librarySuffix"] = "-lib", + ["infoFile"] = "files.txt", -- provides the structure of a git repo (paths to all files) + ["apiGithubURL"] = "https://api.github.com/orgs/", + ["apiGithubGetRepos"] = "/repos?type=all&per_page=100&page=1", + ["apiGithubGetTags"] = "https://api.github.com/repos///tags", + ["installScript"] = "1kKZ8zTS", + -- Local Settings + ["currentVersion"] = "0.0.0", -- will get the newest version through the github api, no need to update here + ["updateAvailable"] = false, + ["lastVersionCheck"] = "1", + ["programDirectory"] = "progs/", + ["libraryDirectory"] = "libs/", + ["configDirectory"] = "config/", + ["configFile"] = "scm-config.json", + ["scriptFile"] = "scm-scripts.json", -- will be saved in configDirectory as well + ["verbose"] = true, + ["printPrefix"] = "[scm] ", + ["logDate"] = false, + ["writeLogFile"] = false, + ["logFilePath"] = "logs/scm-log.txt", + ["repoScriptsFile"] = "scm-repo-scripts.txt", -- will be saved in configDirectory as well + ["allowCLIPrefix"] = true, + ["cliPrefix"] = false +} +---------------- + + +scm.scripts = {} +scm.commands = { + ["require"] = { + ---@param args table + func = function(args) + scm:download(args[2], "library", nil) + end, + description = [[ +Adds a library with all its dependencies. +If only a name is given, it will try to download from the official GitHub repositories. +$ require +$ require @ + ]] + }, + ["add"] = { + ---@param args table + func = function(args) + scm:download(args[2], "program", nil) + end, + description = [[ +Adds a program with all its dependencies. +If only a name is given, it will try to download from the official GitHub repositories. +$ add +$ add @ + ]] + }, + ["update"] = { + ---@param args table + func = function(args) + if args[2] == "all" then + scm:updateAllScripts() + elseif args[3] then + scm:updateScript(args[2], args[3]) + elseif args[2] then + scm:updateScript(args[2], nil) + else + scm:updateSCM() + end + end, + description = [[ +$ update + Updates this program (SCM) +$ update + Updates the script with the given name +$ update all + Updates all installed programs and libraries +$ update + Updates the script with an specific source + ]] + }, + ["remove"] = { + ---@param args table + func = function(args) + if args[2] == "all" then + scm:removeAllScripts() + else + scm:removeScript(args[2]) + end + end, + description = [[ +$ remove + Removes the given script +$ remove all + Removes all scripts + ]] + }, + ["list"] = { + ---@param _ table + func = function(_) + scm:listScripts() + end, + description = [[ +$ list + Lists all installed scripts + ]] + }, + ["config"] = { + ---@param args table + func = function(args) + if args[3] then + scm:updateConfig(args[2], args[3]) + elseif args[2] then + if scm.config[args[2]] ~= nil then + print(args[2], tostring(scm.config[args[2]])) + end + else + print("You can currently configure the following variables:") + for cname, cvalue in pairs(scm.config) do + textutils.pagedPrint(cname .. "\t" .. tostring(cvalue)) + end + end + end, + description = [[ +$ config + Lists all available configurations +$ config + Shows a specific configuration +$ config + Updates the configuration + ]] + }, + ["refresh"] = { + func = function(args) + scm:refreshAutocomplete() + end, + description = [[ +$ refresh + Downloads the names of all programs and libraries of the official repository. + Refreshes autocomplete. + ]] + }, + ["help"] = { + ---@param args table + func = function(args) + if args[2] then + if scm.commands[args[2]] then + textutils.pagedPrint(args[2] .. "\n" .. scm.commands[args[2]]["description"]) + end + else + for k, v in pairs(scm.commands) do + textutils.pagedPrint("# " .. k .. "\n" .. v.description) + end + end + end, + description = [[ +$ help + Shows all available commands and their description +$ help + Shows the description of the given command + ]] + } +} + +function scm:refreshRepoScripts() + self:log("Downloading program and library names from GitHub...") + local repoScripts = {} + + local programs = {} + local libraries = {} + + local request = http.get(self.config["apiGithubURL"] .. self.config["user"] .. self.config["apiGithubGetRepos"]) + if request then + local response = request.readAll() + request.close() + + local responseTable = textutils.unserializeJSON(response) + + local programSuffix = self.config["programSuffix"] + local librarySuffix = self.config["librarySuffix"] + + for i = 1, #responseTable, 1 do + local scriptName = responseTable[i]["name"] + if string.sub(scriptName, -string.len(programSuffix)) == programSuffix then + programs[ + string.sub(scriptName, 0, string.len(scriptName) - string.len(programSuffix)) + ] = {} + elseif string.sub(scriptName, -string.len(librarySuffix)) == librarySuffix then + libraries[ + string.sub(scriptName, 0, string.len(scriptName) - string.len(librarySuffix)) + ] = {} + end + end + scm:log("Done") + else + scm:log("Download failed") + end + + self.commands["add"]["args"] = programs + self.commands["require"]["args"] = libraries + + repoScripts["libraries"] = libraries + repoScripts["programs"] = programs + + local file = fs.open(self.config["configDirectory"] .. self.config["repoScriptsFile"], "w") + if file then + file.write(textutils.serializeJSON(repoScripts)) + file.close() + end +end + +function scm:loadRepoScripts() + local file = fs.open(self.config["configDirectory"] .. self.config["repoScriptsFile"], "r") + + if not file then + self:refreshRepoScripts() + else + local repoScripts = textutils.unserializeJSON(file.readAll()) or nil + if repoScripts then + self.commands["add"]["args"] = repoScripts["programs"] + self.commands["require"]["args"] = repoScripts["libraries"] + end + + file.close() + end +end + +function scm:prepareAutocomplete() + -- prepare update and remove + scm:loadScripts() + local installedScripts = {} + for i = 1, #self.scripts, 1 do + installedScripts[self.scripts[i].name] = {} + end + installedScripts["all"] = {} + + self.commands["update"]["args"] = installedScripts + self.commands["remove"]["args"] = installedScripts + + -- prepare add and require + self:loadRepoScripts() + + -- prepare config + local availableConfigs = {} + + for k, _ in pairs(self.config) do + availableConfigs[k] = {} + end + + self.commands["config"]["args"] = availableConfigs + + -- prepare help + local availableCommands = {} + + for k, _ in pairs(self.commands) do + availableCommands[k] = {} + end + + self.commands["help"]["args"] = availableCommands +end + +---@param shell table +---@param index integer +---@param argument string +---@param previous table +---@return table | nil +local function completionFunction(shell, index, argument, previous) + local commands = {} + for k, _ in pairs(scm.commands) do + commands[k] = scm.commands[k]["args"] or {} + end + + local currArg = commands + for i = 2, #previous do + if currArg[previous[i]] then + currArg = currArg[previous[i]] + else + return nil + end + end + + local results = {} + for word, _ in pairs(currArg) do + if word:sub(1, #argument) == argument then + results[#results + 1] = word:sub(#argument + 1) + end + end + return results; +end + +local function updateAutocomplete() + shell.setCompletionFunction("scm", completionFunction) +end + +function scm:refreshAutocomplete() + scm:refreshRepoScripts() + scm:prepareAutocomplete() + updateAutocomplete() +end + +---@param message string +function scm:log(message) + local datetime = "" + if self.config["logDate"] then datetime = os.date("[%Y-%m-%d %H:%M:%S] ") end + if self.config["verbose"] then print(self.config["printPrefix"] .. message) end + + if self.config["writeLogFile"] then + local file = fs.open(self.config["logFilePath"], "a") + file.write(datetime .. message .. "\n") + file.close() + end +end + +---@param str string +---@return string | nil +---@return string | nil +function scm:splitNameCode(str) + local separator = string.find(str, "@") + + if separator then + local name = string.sub(str, 1, separator - 1) + local code = string.sub(str, separator + 1) + return name, code + end + + return nil, nil +end + +---@param target string +---@param fileType string +---@param updateObj table | nil +---@return boolean +function scm:download(target, fileType, updateObj) + scm:log("Downloading " .. fileType .. " " .. target .. "...") + if target == nil then + --@TODO: Error handling + return false + end + + local sourceObject = { + name = nil, + source = { + ["default"] = target + }, + type = fileType + } + + if updateObj then sourceObject.name = updateObj.name end + + -- Check for Pastebin + local name, code = self:splitNameCode(target) + if name and code then + sourceObject.name = name + return scm:addScript(self:downloadPastebin(sourceObject, code, self.config[fileType .. "Directory"], updateObj)) + end + + -- We assume it's Git + -- The suffix is used to find the correct repository on GitHub + local suffix + if fileType == "library" then + suffix = self.config["librarySuffix"] + else + suffix = self.config["programSuffix"] + end + local repository = target .. suffix + sourceObject.name = target + + return scm:addScript(self:downloadGit(sourceObject, repository, self.config[fileType .. "Directory"], updateObj)) +end + +---@param sourceObject table +---@param repository string +---@param targetDirectory string +---@param updateObj table | nil +---@return table | nil +---@return boolean +function scm:downloadGit(sourceObject, repository, targetDirectory, updateObj) + local baseUrl = self.config["rawURL"] .. + self.config["user"] .. "/" .. + repository .. "/" .. + self.config["branch"] .. "/" + + local filesUrl = baseUrl .. self.config["infoFile"] + + local request = http.get(filesUrl) + if request then + local content = request.readAll() + request.close() + + if content then + local file = fs.open(targetDirectory .. sourceObject.name + .. self.config[sourceObject.type .. "Suffix"] + .. "/" .. self.config["infoFile"], "w") + file.write(content) + file.close() + + local filePaths = {} + file = fs.open(targetDirectory .. sourceObject.name + .. self.config[sourceObject.type .. "Suffix"] + .. "/" .. self.config["infoFile"], "r") + for line in file.readLine do + filePaths[#filePaths + 1] = line + end + file.close() + + for i = 1, #filePaths, 1 do + local success = true + local tmpRequest = http.get(baseUrl .. filePaths[i]) + if tmpRequest then + local tmpContent = tmpRequest.readAll() + if tmpContent then + local tmpFile = fs.open(targetDirectory .. sourceObject.name + .. self.config[sourceObject.type .. "Suffix"] + .. "/" .. filePaths[i], "w") + tmpFile.write(tmpContent) + tmpFile.close() + else + success = false + end + + tmpRequest.close() + else + success = false + end + + if not success then + return nil, false + end + end + + -- create a link that calls the file within the program directory + if sourceObject.type == "program" then + local progamLink = fs.open(sourceObject.name, "w") + progamLink.write("shell.execute(\"" .. targetDirectory .. sourceObject.name .. + self.config[sourceObject.type .. "Suffix"] + .. "/" .. sourceObject.name .. ".lua" .. "\", ...)") + progamLink.close() + elseif sourceObject.type == "library" then + local libraryLink = fs.open(targetDirectory .. sourceObject.name .. ".lua", "w") + + local tmpName = sourceObject.name + if tmpName:find("%.") then + tmpName = tmpName:match("(.+)%..+$") + end + + libraryLink.write("return require(\"./" .. self.config["libraryDirectory"] + .. tmpName .. self.config[sourceObject.type .. "Suffix"] + .. "/" .. tmpName .. "\")") + libraryLink.close() + end + + return sourceObject, true + end + end + + return nil, false +end + +---@param sourceObject table +---@param code string +---@param targetDirectory string +---@param updateObj table | nil +---@return table | nil +---@return boolean +function scm:downloadPastebin(sourceObject, code, targetDirectory, updateObj) + -- Only download if it does not already exist, or if it should be updated + if fs.exists(targetDirectory .. sourceObject.name) then + if updateObj then + fs.delete(targetDirectory .. sourceObject.name) + sourceObject = updateObj + else + -- File already exists, you should use update + return nil, false + end + end + + if updateObj then + fs.delete(sourceObject.name) + end + + if sourceObject.type == "program" then + shell.run("pastebin", "get", code, sourceObject.name .. ".lua") + else + shell.run("pastebin", "get", code, targetDirectory .. sourceObject.name .. ".lua") + end + + return sourceObject, true +end + +---@param sourceObject table +---@param targetDirectory string +---@param updateObj table | nil +---@return table | nil +---@return boolean +function scm:downloadURL(sourceObject, targetDirectory, updateObj) + local sourceName = "default" or updateObj.sourceName + if updateObj then + sourceObject.name = sourceObject.name or updateObj.name + end + + if not sourceObject.name then + sourceObject.name = self:getNameFromURL(sourceObject.source[sourceName]) + end + + local request = http.get(sourceObject.source[sourceName]) + + if request then + local content = request.readAll() + request.close() + + if content then + local file = fs.open(targetDirectory .. sourceObject.name, "w") + file.write(content) + file.close() + return sourceObject, true + end + end + + return nil, false +end + +---@param url string +---@return string +function scm:getNameFromURL(url) + -- Gets the filename + extension from a url (everything after last /) + local name = url:match("[^/]+$") + + -- Remove file extension if name contains a dot + if name:find("%.") then + name = name:match("(.+)%..+$") + end + + return name +end + +---@param sourceObject table | nil +---@param success boolean +---@return boolean +function scm:addScript(sourceObject, success) + if not success or not sourceObject then return false end + scm:log("Adding script " .. sourceObject.name .. "...") + local scriptExists = false + + -- Check if script already exists, then update + for i = 1, #self.scripts, 1 do + if self.scripts[i].name == sourceObject.name and self.scripts[i].type == sourceObject.type then + scriptExists = true + if self.scripts[i].source[sourceObject.sourceName] then + self.scripts[i].source[sourceObject.sourceName] = sourceObject.source[sourceObject.sourceName] + self:saveScripts() + + return true + end + end + end + + if not scriptExists then + scm:log("Script added: " .. sourceObject.name) + table.insert(self.scripts, sourceObject) + else + scm:log("Script already exists.") + return false + end + + self:saveScripts() + + -- update for autocomplete + self.commands["update"]["args"] = self.commands["update"]["args"] or {} + self.commands["remove"]["args"] = self.commands["remove"]["args"] or {} + self.commands["update"]["args"][sourceObject.name] = {} + self.commands["remove"]["args"][sourceObject.name] = {} + self:prepareAutocomplete() + updateAutocomplete() + + return true +end + +function scm:saveScripts() + local file = fs.open(self.config["configDirectory"] .. self.config["scriptFile"], "w") + file.write(textutils.serializeJSON(self.scripts)) + file.close() +end + +function scm:loadScripts() + local file = fs.open(self.config["configDirectory"] .. self.config["scriptFile"], "r") + + if not file then + self:saveScripts() + else + self.scripts = textutils.unserializeJSON(file.readAll()) or {} + file.close() + end +end + +function scm:listScripts() + print("name", "type") + print("----------------------") + for i = 1, #self.scripts, 1 do + print(self.scripts[i].name, self.scripts[i].type) + end +end + +---@param name string +function scm:removeScript(name, keepScriptConfig) + scm:log("Removing script: " .. name) + local o = {} + local scriptType = nil + + if keepScriptConfig ~= true then + for i = 1, #self.scripts, 1 do + if self.scripts[i].name ~= name then + table.insert(o, self.scripts[i]) + else + scriptType = self.scripts[i].type + end + end + + self.scripts = o + self:saveScripts() + end + + -- delete file + if scriptType and fs.exists(self.config[scriptType .. "Directory"] .. name .. ".lua") then + fs.delete(self.config[scriptType .. "Directory"] .. name .. self.config[scriptType .. "Suffix"]) + if scriptType == "library" then + fs.delete(self.config[scriptType .. "Directory"] .. name .. ".lua") + end + end + + if scriptType == "program" then + fs.delete(name) + end + + -- update autocomplete + self:prepareAutocomplete() + updateAutocomplete() +end + +function scm:removeAllScripts() + local tmpScripts = {} + for i = 1, #self.scripts, 1 do + table.insert(tmpScripts, self.scripts[i].name) + end + + for i = 1, #tmpScripts, 1 do + self:removeScript(tmpScripts[i]) + end +end + +---@param name string +---@param sourceName string +---@return boolean +function scm:updateScript(name, sourceName) + if not sourceName then sourceName = "default" end + + local updateObj = { + ["name"] = name, + ["type"] = nil, + ["sourceName"] = sourceName, + ["source"] = {} + } + + for i = 1, #self.scripts, 1 do + if self.scripts[i].name == name then + updateObj.source[sourceName] = self.scripts[i].source[sourceName] + updateObj.type = self.scripts[i].type + end + end + + if updateObj.source[sourceName] and updateObj.type then + self:removeScript(name, true) + self:download(updateObj.source[sourceName], updateObj.type, updateObj) + return true + end + + return false +end + +function scm:updateAllScripts() + for i = 1, #self.scripts, 1 do + self:updateScript(self.scripts[i].name, "default") + end +end + +function scm:updateSCM() + scm:log("Updating scm...") + shell.run("pastebin", "run", self.config.installScript) + local success, version = self:getNewestVersion() + if success then + self.config["currentVersion"] = version + self.config["updateAvailable"] = false + self.config["lastVersionCheck"] = os.day("utc") + self:saveConfig() + end +end + +---@source: https://stackoverflow.com/a/2705804/10495683 +---@param T table +---@return integer +local function tablelength(T) + local count = 0 + for _ in pairs(T) do count = count + 1 end + return count +end + +function scm:saveConfig() + local file = fs.open(self.config["configDirectory"] .. self.config["configFile"], "w") + file.write(textutils.serializeJSON(self.config)) + file.close() +end + +function scm:loadConfig() + local file = fs.open(self.config["configDirectory"] .. self.config["configFile"], "r") + + if not file then + -- Create config file if it does not exist yet + self:saveConfig() + else + -- Load config from file + local temp = textutils.unserializeJSON(file.readAll()) or {} + -- Check if loaded config size is equal to the default size, + -- otherwise the config is corrupted and will be overwritten + if tablelength(temp) == tablelength(self.config) then + self.config = temp + else + self:saveConfig() + end + file.close() + end +end + +---@param name string +---@param value string +function scm:updateConfig(name, value) + local writeConfig = true + + if name and value then + if self.config[name] ~= nil then + if type(self.config[name]) == type(true) then + -- Check for boolean + if value == "true" then + self.config[name] = true + elseif value == "false" then + self.config[name] = false + end + else + -- We assume it's a string + self.config[name] = value + end + else + writeConfig = false + end + + if writeConfig then + self:saveConfig() + end + else + scm:log("You can currently configure the following variables:") + for cname, cvalue in pairs(self.config) do + scm:log(cname, tostring(cvalue)) + end + end +end + +---@param name string +---@param localPath string | nil | unknown +function scm:checkRequirements(name, localPath) + scm:log("Checking requirements of " .. (localPath or name) .. "...") + local file + if localPath then + file = fs.open(localPath, "r") + if not file then + file = fs.open('./' .. localPath .. ".lua", "r") + end + elseif fs.exists("./" .. self.config["libraryDirectory"] .. name .. self.config["librarySuffix"] .. "/" .. name .. ".lua") then + file = fs.open("./" .. self.config["libraryDirectory"] + .. name .. self.config["librarySuffix"] + .. "/" .. name .. ".lua", "r") + else + file = fs.open("./" .. self.config["libraryDirectory"] .. name .. ".lua", "r") + end + if not file then scm:log('File ' .. name .. ' not found') end + -- Find requirements by searching for comment --@requires name + local requires = {} + while true do + local line = file.readLine() + if not line then break end + + local find = string.find(line, "--@requires") + if find then + line = string.sub(line, find + 12) + local lineEnd = string.find(line, " ") + + local scriptName = nil + if lineEnd then + scriptName = string.sub(line, 0, lineEnd - 1) + else + scriptName = string.sub(line, 0) + end + + requires[#requires + 1] = scriptName + end + end + file.close() + + -- Install missing requirements + for i = 1, #requires do + local n = requires[i] + local tmpName, tmpCode = self:splitNameCode(n) + if tmpCode then n = tmpName end + + scm:log("Trying to install " .. n .. "...") + + local scriptExists = false + for j = 1, #self.scripts, 1 do + if self.scripts[j].name == n then + scriptExists = true + end + end + + if not scriptExists then + if tmpCode then + self:download(tmpName .. "@" .. tmpCode, "library") + else + self:download(n, "library") + end + else + scm:log(n .. " already exists.") + end + + self:checkRequirements(n) + end +end + +--- used when no script with the name was found online +--- searches locally for the script +---@param name string +---@return any | nil +local function fallbackRequire(name) + scm:log(name .. " not found online, try to find locally") + --- if script does not exist + local possiblePath = { + name, + scm.config["libraryDirectory"] .. name, + scm.config["libraryDirectory"] .. name .. "/" .. name, + scm.config["libraryDirectory"] .. name .. "/" .. "init.lua" + } + local script + local success + ---TryFunction for Require + ---@param path string + ---@return any + local function tryRequire(path) + return require(path) + end + + for _, path in pairs(possiblePath) do + success, script = pcall(tryRequire, path) + if success then + scm:checkRequirements(name, path) + return script + end + end + scm:log("Could not load " .. name) + return nil +end + +---@param name string +---@return any +function scm:load(name) + scm:log("Loading " .. name .. "...") + local scriptExists = false + for i = 1, #self.scripts, 1 do + if self.scripts[i].name == name then + scriptExists = true + end + end + + if not scriptExists then + self:download(name, "library") + end + + scriptExists = false + for i = 1, #self.scripts, 1 do + if self.scripts[i].name == name then + scriptExists = true + end + end + + if scriptExists then + self:checkRequirements(name) + local path = "./" .. self.config["libraryDirectory"] .. name + local script = require(path) + scm:log("Done") + return script + end + + return fallbackRequire(name) +end + +function scm:getNewestVersion() + local githubAPIgetTags = self.config["apiGithubGetTags"] + githubAPIgetTags = githubAPIgetTags:gsub("", self.config["user"]) + githubAPIgetTags = githubAPIgetTags:gsub("", self.config["repository"]) + + local request = http.get(githubAPIgetTags) + + if request then + local content = request.readAll() + request.close() + local scmTags = textutils.unserializeJSON(content) + return true, scmTags[1]["name"] + else + self:log("Request to GitHub API failed.") + return false, "0.0.0" + end +end + +function scm:checkVersion() + if not self.config["updateAvailable"] and self.config["lastVersionCheck"] ~= '' .. os.day("utc") then + local success, newestVersion = scm:getNewestVersion() + if success and newestVersion ~= self.config["currentVersion"] then + self.config["updateAvailable"] = true + end + + self.config["lastVersionCheck"] = os.day("utc") .. '' + self:saveConfig() + end +end + +----here i was +----!!!!!!!!!!!! + +function scm:init() + -- Create directories + if not fs.exists(self.config["configDirectory"]) then + fs.makeDir(self.config["configDirectory"]) + end + if not fs.exists(self.config["libraryDirectory"]) then + fs.makeDir(self.config["libraryDirectory"]) + end + + self:loadConfig() + self:loadScripts() + + self:checkVersion() +end + +---@param resetPosition boolean | nil +function scm:cli(resetPosition, args) + if resetPosition ~= nil and resetPosition == true then + term.setCursorPos(1, 7) + end + + -- enable autocomplete + self:prepareAutocomplete() + updateAutocomplete() + + -- enable newline starting with `scm ` + if self.config["allowCLIPrefix"] then + self.config["cliPrefix"] = true + self:saveConfig() + end + + -- some interface + local _, cursorY = term.getCursorPos() + if cursorY < 7 then cursorY = 7 end + term.setCursorPos(1, cursorY) + term.blit(" ", + "ffffffffffffffffffffffffffffffff", + "44444444444444444444444444444444") + term.setCursorPos(1, cursorY) + term.scroll(1) + term.blit(" SCM - Script Manager ", + "ffffffffffffffffffffffffffffffff", + "44444444444444444444444444444444") + term.setCursorPos(1, cursorY) + term.scroll(1) + term.blit(" Autocomplete enabled. ", + "77777777777777777777777777777777", + "44444444444444444444444444444444") + term.setCursorPos(1, cursorY) + term.scroll(1) + term.blit(" Type `scm help` to learn more. ", + "77777777ffffffff7777777777777777", + "44444444444444444444444444444444") + term.setCursorPos(1, cursorY) + term.scroll(1) + if (self.config["updateAvailable"]) then + term.blit(" Update available! ", + "7eeeeeeeeeeeeeeeee77777777777777", + "44444444444444444444444444444444") + term.setCursorPos(1, cursorY) + term.scroll(1) + end + term.blit(" ", + "ffffffffffffffffffffffffffffffff", + "44444444444444444444444444444444") + term.setCursorPos(1, cursorY) + term.scroll(2) + + if self.config["cliPrefix"] then + shell.run(read(nil, nil, shell.complete, "scm ")) + end +end + +---@param args table +function scm:handleArguments(args) + if #args == 0 then + self:cli(false, args) + return + end + + if args[1] and self.commands[args[1]] then + self.commands[args[1]]["func"](args) + if self.config["cliPrefix"] then + shell.run(read(nil, nil, shell.complete, "scm ")) + end + end +end + +scm:init() +scm:handleArguments({ ... }) +return scm diff --git a/scm-1.0-0.rockspec b/scm-1.0-0.rockspec new file mode 100644 index 0000000..2f8aa92 --- /dev/null +++ b/scm-1.0-0.rockspec @@ -0,0 +1,25 @@ +package = "SCM" +version = "1.0-0" +source = { + url = "..." -- We don't have one yet +} +description = { + summary = "SCM is a script manager for Minecrafts ComputerCraft mod", + detailed = [[ + We are using CC: Tweaked and in some cases some + additional peripherals, which we ideally mention in + the repositories of the scripts that use them. + ]], + homepage = "http://...", -- We don't have one yet + license = "MIT/X11" -- or whatever you like +} +dependencies = { + "lua = 5.1", + "http >= 0.4-0" + -- If you depend on other rocks, add them here +} +build = { + -- We'll start here. + type = "builtin" + +} \ No newline at end of file diff --git a/tests/Suite/fs.lua b/tests/Suite/fs.lua new file mode 100644 index 0000000..7b9c4b0 --- /dev/null +++ b/tests/Suite/fs.lua @@ -0,0 +1,45 @@ +local fs = {} +fs.libPath = "tmpLibs/" +fs.progPath = "tmpProg/" + +do + fs.open = function(path, mode) + assert("string" == type(path), tostring(path) .. "path must be a string") + assert("string" == type(mode), tostring(mode) .." mode must be a string") + local file = io.open(path, mode) + if not file then + -- find all occurences of / in the path + local dirs = {} + for i = 1, #path do + if path:sub(i, i) == "/" then + table.insert(dirs, i) + end + end + -- create all directories + local dir = "" + for i = 1, #dirs do + dir = path:sub(1, dirs[i]) + if not fs.exists(dir) then + os.execute("mkdir " .. dir) + end + end + file = io.open(path, mode) + end + if mode == "w" then + assert(file, "file could not be opened in : "..path.. " Mode : "..mode) + end + return file + end + + fs.exists = function(path) + assert("string" == type(path), "path must be a string") + local file = io.open(path, "r") + if not file then + return false + end + file:close() + return true + end +end + +return fs diff --git a/tests/Suite/helperFunctions.lua b/tests/Suite/helperFunctions.lua new file mode 100644 index 0000000..67a2a20 --- /dev/null +++ b/tests/Suite/helperFunctions.lua @@ -0,0 +1,5 @@ +function table.copy(t) + local u = { } + for k, v in pairs(t) do u[k] = v end + return setmetatable(u, getmetatable(t)) +end \ No newline at end of file diff --git a/tests/Suite/http.lua b/tests/Suite/http.lua new file mode 100644 index 0000000..64d0230 --- /dev/null +++ b/tests/Suite/http.lua @@ -0,0 +1,7 @@ +local http = require("ssl.https") + +local url = "https://raw.githubusercontent.com/mc-cc-scripts/script-manager/master/README.md" + +local res, code, headers, status = http.request(url) + +print(res, code, headers, status) diff --git a/tests/Suite/json.lua b/tests/Suite/json.lua new file mode 100644 index 0000000..2e59c70 --- /dev/null +++ b/tests/Suite/json.lua @@ -0,0 +1,184 @@ +---@source https://gist.github.com/tylerneylon/59f4bcf316be525b30ab + +--[[ json.lua +A compact pure-Lua JSON library. +The main functions are: json.stringify, json.parse. +## json.stringify: +This expects the following to be true of any tables being encoded: + * They only have string or number keys. Number keys must be represented as + strings in json; this is part of the json spec. + * They are not recursive. Such a structure cannot be specified in json. +A Lua table is considered to be an array if and only if its set of keys is a +consecutive sequence of positive integers starting at 1. Arrays are encoded like +so: `[2, 3, false, "hi"]`. Any other type of Lua table is encoded as a json +object, encoded like so: `{"key1": 2, "key2": false}`. +Because the Lua nil value cannot be a key, and as a table value is considerd +equivalent to a missing key, there is no way to express the json "null" value in +a Lua table. The only way this will output "null" is if your entire input obj is +nil itself. +An empty Lua table, {}, could be considered either a json object or array - +it's an ambiguous edge case. We choose to treat this as an object as it is the +more general type. +To be clear, none of the above considerations is a limitation of this code. +Rather, it is what we get when we completely observe the json specification for +as arbitrary a Lua object as json is capable of expressing. +## json.parse: +This function parses json, with the exception that it does not pay attention to +\u-escaped unicode code points in strings. +It is difficult for Lua to return null as a value. In order to prevent the loss +of keys with a null value in a json string, this function uses the one-off +table value json.null (which is just an empty table) to indicate null values. +This way you can check if a value is null with the conditional +`val == json.null`. +If you have control over the data and are using Lua, I would recommend just +avoiding null values in your data to begin with. +--]] + + +local json = {} + + +-- Internal functions. + +local function kind_of(obj) + if type(obj) ~= 'table' then return type(obj) end + local i = 1 + for _ in pairs(obj) do + if obj[i] ~= nil then i = i + 1 else return 'table' end + end + if i == 1 then return 'table' else return 'array' end +end + +local function escape_str(s) + local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'} + local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'} + for i, c in ipairs(in_char) do + s = s:gsub(c, '\\' .. out_char[i]) + end + return s +end + +-- Returns pos, did_find; there are two cases: +-- 1. Delimiter found: pos = pos after leading space + delim; did_find = true. +-- 2. Delimiter not found: pos = pos after leading space; did_find = false. +-- This throws an error if err_if_missing is true and the delim is not found. +local function skip_delim(str, pos, delim, err_if_missing) + pos = pos + #str:match('^%s*', pos) + if str:sub(pos, pos) ~= delim then + if err_if_missing then + error('Expected ' .. delim .. ' near position ' .. pos) + end + return pos, false + end + return pos + 1, true +end + +-- Expects the given pos to be the first character after the opening quote. +-- Returns val, pos; the returned pos is after the closing quote character. +local function parse_str_val(str, pos, val) + val = val or '' + local early_end_error = 'End of input found while parsing string.' + if pos > #str then error(early_end_error) end + local c = str:sub(pos, pos) + if c == '"' then return val, pos + 1 end + if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end + -- We must have a \ character. + local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'} + local nextc = str:sub(pos + 1, pos + 1) + if not nextc then error(early_end_error) end + return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc)) +end + +-- Returns val, pos; the returned pos is after the number's final character. +local function parse_num_val(str, pos) + local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos) + local val = tonumber(num_str) + if not val then error('Error parsing number at position ' .. pos .. '.') end + return val, pos + #num_str +end + + +-- Public values and functions. + +function json.stringify(obj, as_key) + local s = {} -- We'll build the string as an array of strings to be concatenated. + local kind = kind_of(obj) -- This is 'array' if it's an array or type(obj) otherwise. + if kind == 'array' then + if as_key then error('Can\'t encode array as key.') end + s[#s + 1] = '[' + for i, val in ipairs(obj) do + if i > 1 then s[#s + 1] = ', ' end + s[#s + 1] = json.stringify(val) + end + s[#s + 1] = ']' + elseif kind == 'table' then + if as_key then error('Can\'t encode table as key.') end + s[#s + 1] = '{' + for k, v in pairs(obj) do + if #s > 1 then s[#s + 1] = ', ' end + s[#s + 1] = json.stringify(k, true) + s[#s + 1] = ':' + s[#s + 1] = json.stringify(v) + end + s[#s + 1] = '}' + elseif kind == 'string' then + return '"' .. escape_str(obj) .. '"' + elseif kind == 'number' then + if as_key then return '"' .. tostring(obj) .. '"' end + return tostring(obj) + elseif kind == 'boolean' then + return tostring(obj) + elseif kind == 'nil' then + return 'null' + else + error('Unjsonifiable type: ' .. kind .. '.') + end + return table.concat(s) +end + +json.null = {} -- This is a one-off table to represent the null value. + +function json.parse(str, pos, end_delim) + pos = pos or 1 + if pos > #str then error('Reached unexpected end of input.') end + local pos = pos + #str:match('^%s*', pos) -- Skip whitespace. + local first = str:sub(pos, pos) + if first == '{' then -- Parse an object. + local obj, key, delim_found = {}, true, true + pos = pos + 1 + while true do + key, pos = json.parse(str, pos, '}') + if key == nil then return obj, pos end + if not delim_found then error('Comma missing between object items.') end + pos = skip_delim(str, pos, ':', true) -- true -> error if missing. + obj[key], pos = json.parse(str, pos) + pos, delim_found = skip_delim(str, pos, ',') + end + elseif first == '[' then -- Parse an array. + local arr, val, delim_found = {}, true, true + pos = pos + 1 + while true do + val, pos = json.parse(str, pos, ']') + if val == nil then return arr, pos end + if not delim_found then error('Comma missing between array items.') end + arr[#arr + 1] = val + pos, delim_found = skip_delim(str, pos, ',') + end + elseif first == '"' then -- Parse a string. + return parse_str_val(str, pos + 1) + elseif first == '-' or first:match('%d') then -- Parse a number. + return parse_num_val(str, pos) + elseif first == end_delim then -- End of an object or array. + return nil, pos + 1 + else -- Parse true, false, or null. + local literals = {['true'] = true, ['false'] = false, ['null'] = json.null} + for lit_str, lit_val in pairs(literals) do + local lit_end = pos + #lit_str - 1 + if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end + end + local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10) + error('Invalid json syntax starting at ' .. pos_info_str) + end +end + +return json \ No newline at end of file diff --git a/tests/testSuite.lua b/tests/testSuite.lua new file mode 100644 index 0000000..62ee150 --- /dev/null +++ b/tests/testSuite.lua @@ -0,0 +1,36 @@ +-- implement Test Suite + +local json = require("tests/Suite/json") +local https = require("ssl.https") +local fs = require("tests/Suite/fs") +local textutils = {} +---@param t table +textutils.serializeJSON = function(t) return json.stringify(t) end + +---@param s string +---@return table +textutils.unserializeJSON = function(s) return json.parse(s) end + +_G.textutils = textutils + +_G.http = { + get = function(...) + local t = https.request(...) + if t == "404: Not Found" then + print("404: Not Found for request: " .. tostring(...)) + end + return + { + ["readAll"] = function() return t end, + ["close"] = function() return end + } + end +} + +_G.shell = { + -- TODO: implement shell - CompleteFunction + ["setCompletionFunction"] = function(...) return end, + ["run"] = function (...) return end +} + +_G.fs = fs diff --git a/tests/test_spec.lua b/tests/test_spec.lua new file mode 100644 index 0000000..39edc8d --- /dev/null +++ b/tests/test_spec.lua @@ -0,0 +1,180 @@ +--TODO: +--implement Test Suite +require("tests/testSuite") +require("tests.Suite.helperFunctions") + +--#region assert Definitions + +---@class are +---@field same function +---@field equal function +---@field equals function + +---@class is +---@field truthy function +---@field falsy function +---@field not_true function +---@field not_false function + +---@class has +---@field error function +---@field errors function + +---@class assert +---@field are are +---@field is is +---@field are_not are +---@field is_not is +---@field has has +---@field has_no has +---@field True function +---@field False function +---@field has_error function +---@field is_true function +---@field equal function +assert = assert + +--#endregion assert Definitions + +local configTmp +local scriptTmp +local testScript +---@param scm SCM +local function saveConfig(scm) + local config = scm.Config + config:loadConfig() + configTmp = table.copy(config:getAll()) +end + +---@param scm SCM +local function restoreConfig(scm) + local config = scm.Config + config:saveConfig(configTmp) +end + +---@param scm SCM +local function saveScripts(scm) + local scriptManager = scm.ScriptManager + scriptManager:loadScripts() + scriptTmp = table.copy(scriptManager.scripts) +end + +---@param scm SCM +local function restoreScripts(scm) + local scriptManager = scm.ScriptManager + scriptManager.scripts = scriptTmp + scriptManager:saveScripts() +end +---@param func function +---@param ... any +local function runTests(func, ...) + ---@class SCM + local scm = require("../scm") + saveConfig(scm) + saveScripts(scm) + scm.Config:set("libraryDirectory", "tmpLibs/"); + scm.Config:set("programDirectory", "tmpPrograms/"); + local success, err = pcall(func, scm, ...) + restoreConfig(scm) + restoreScripts(scm) + assert.is.falsy(err) + os.execute("rm -rf tmpLibs") + + if not success then + error('Error Message was empty') + end +end + +describe("Testing everything about SCM:", function() + describe("Require all SCM Modules", function() + it("should be able to require all modules", function() + local scm = require("../scm") + assert.is_true('table' == type(scm)) + assert.is.truthy(scm.Autocomplete) + assert.is.truthy(scm.Config) + assert.is.truthy(scm.Net) + assert.is.truthy(scm.UI) + assert.is.truthy(scm.ScriptManager) + assert.is.truthy(scm.Log) + print("Require of all modules test passed") + end) + end) + describe("Config ->", function() + it("Change SCM Config", function() + runTests(function(scm) + local config = scm.Config + -- Set Config + config:set("verbose", false) + assert.is.truthy(config:getAll()["verbose"] == false) + config:set("verbose", "Wrong") + config:saveConfig() + config:set("verbose", false) + + -- Check if the file saved correctly + config:loadConfig() + assert.equal("Wrong", config:getAll()["verbose"]) + config:set("verbose", true) + assert.is.truthy(config:getAll()["verbose"] == true) + print("Config test passed") + end) + end) + end) + describe("ScriptManager ->", function() + it("Load Empty", function() + runTests( + function(scm) + scm.Config:set("libraryDirectory", "tmpLibs"); + local scriptManager = scm.ScriptManager + scriptManager:loadScripts() + local scripts = scriptManager.scripts + assert.is.truthy(scripts) + assert.is.truthy(type(scripts) == "table") + + print("1. ScriptManager test passed") + end + ) + end) + it("Load Local", function() + runTests( + function(scm) + local scriptManager = scm.ScriptManager + local file = io.open("testFile.lua", "w") + if not file then + error('file not create') + end + file:write("local t = {test = true} \n return t") + file:close() + local tFile = scm:load("testFile") + assert.is.truthy(tFile) + assert.is.truthy(tFile.test) + os.remove("testFile.lua") + print("2. ScriptManager test passed") + end + ) + end) + describe("Load Remote", function () + it("Get TestLib", function() + runTests( + ---@param scm SCM + function(scm) + local testScript = scm:load("scmTest") + local scriptManager = scm.ScriptManager + -- what should be there: + -- local tScript = { + -- name = "testLibrary", + -- type = "remote", + -- source = { + -- ["github"] = "https://raw.githubusercontent.com/mc-cc-scripts/script-manager/master/testLibrary.lua" + -- } + -- } + -- scriptManager:addScript(tScript, true) + assert.is.truthy(testScript) + assert.is.truthy(testScript.test) + print("3. ScriptManager test passed") + end + ) + end) + + end) + end) +end) diff --git a/tests/testtemplate.lua b/tests/testtemplate.lua new file mode 100644 index 0000000..0ef3567 --- /dev/null +++ b/tests/testtemplate.lua @@ -0,0 +1,27 @@ +describe("Busted unit testing framework", function() + describe("should be awesome", function() + it("should be easy to use", function() + assert.truthy("Yup.") + end) + + it("should have lots of features", function() + -- deep check comparisons! + assert.are.same({ table = "great" }, { table = "great" }) + + -- or check by reference! + assert.are_not.equal({ table = "great" }, { table = "great" }) + + assert.truthy("this is a string") -- truthy: not false or nil + + assert.True(1 == 1) + assert.is_true(1 == 1) + + assert.falsy(nil) + assert.has_error(function() error("Wat") end, "Wat") + end) + + it("should provide some shortcuts to common functions", function() + assert.are.unique({ { thing = 1 }, { thing = 2 }, { thing = 3 } }) + end) + end) +end) From 1019d2266a653fa00a4f65adc0ab86a69003a9cc Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Sat, 5 Aug 2023 22:37:17 +0200 Subject: [PATCH 06/51] Issue-30 Started Testing --- .github/workflows/test.yml | 25 ++++++++++++++ libs/scm/autocomplete.lua | 14 ++++++++ libs/scm/net.lua | 18 ++++++++++ libs/scm/scriptManager.lua | 5 ++- libs/scm/ui.lua | 69 ++++++++++++++++++++++++++++++++++++++ scm.lua | 37 +++++++++++++++++--- scmInstaller.lua | 3 +- tests/Suite/fs.lua | 40 ++++++++++++++++++++++ tests/testSuite.lua | 4 ++- tests/test_spec.lua | 55 +++++++++++++++++++----------- 10 files changed, 244 insertions(+), 26 deletions(-) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..d37adf5 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,25 @@ +name: test + +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: get lua + uses: leafo/gh-actions-lua@v5 + with: + luaVersion: "5.1" + + - name: get luarocks + uses: leafo/gh-actions-luarocks@v2 + + - name: get busted + run: luarocks install busted + + - name: run tests + run: | + busted . -o -utfTerminal diff --git a/libs/scm/autocomplete.lua b/libs/scm/autocomplete.lua index 2f42cb4..91273bf 100644 --- a/libs/scm/autocomplete.lua +++ b/libs/scm/autocomplete.lua @@ -277,4 +277,18 @@ $ help function Autocomplete:setLibaries(t) self.commands["require"]["args"] = t end + + function Autocomplete:handleArguments (args) + if #args == 0 then + SCM.UI:cli(false, args) + return + end + + if args[1] and self.commands[args[1]] then + self.commands[args[1]]["func"](args) + if SCM.Config.config["cliPrefix"] then + shell.run(read(nil, nil, shell.complete, "scm ")) + end + end + end end diff --git a/libs/scm/net.lua b/libs/scm/net.lua index 00026b9..8a56ee1 100644 --- a/libs/scm/net.lua +++ b/libs/scm/net.lua @@ -350,6 +350,24 @@ do file:close() end end + + function Net:getNewestVersion () + local githubAPIgetTags = config()["apiGithubGetTags"] + githubAPIgetTags = githubAPIgetTags:gsub("", config()["user"]) + githubAPIgetTags = githubAPIgetTags:gsub("", config()["repository"]) + + local request = http.get(githubAPIgetTags) + + if request then + local content = request.readAll() + request.close() + local scmTags = textutils.unserializeJSON(content) + return true, scmTags[1]["name"] + else + log("Request to GitHub API failed.") + return false, "0.0.0" + end + end end return Net \ No newline at end of file diff --git a/libs/scm/scriptManager.lua b/libs/scm/scriptManager.lua index d994b87..4781182 100644 --- a/libs/scm/scriptManager.lua +++ b/libs/scm/scriptManager.lua @@ -6,7 +6,7 @@ ---@class SCMScriptManager local ScriptManager = { - ---@class SCMScript + ---@type SCMScript[] scripts = {} } SCM.ScriptManager = ScriptManager do @@ -23,6 +23,9 @@ do else self.scripts = textutils.unserializeJSON(file:read("*all") or "") file:close() + if not self.scripts then + self.scripts = {} + end end end diff --git a/libs/scm/ui.lua b/libs/scm/ui.lua index 1bb9456..3ea3fd4 100644 --- a/libs/scm/ui.lua +++ b/libs/scm/ui.lua @@ -2,7 +2,76 @@ local UI = {} SCM.UI = UI do + local scripts = SCM.ScriptManager.scripts + --Redundant + function UI:printUsage() + print("Usage: scm [args]") + print("Commands:") + print(" add [src]") + print(" update [name] [src]") + print(" remove ") + print(" list") + print(" config [value]") + end + function UI:listScripts() + print("name", "type") + print("----------------------") + for i = 1, #scripts, 1 do + print(scripts[i].name, scripts[i].type) + end + end + + ---@param resetPosition boolean | nil + function UI:cli(resetPosition, args) + if resetPosition ~= nil and resetPosition == true then + term.setCursorPos(1, 7) + end + + -- enable autocomplete + SCM.Autocomplete:prepareAutocomplete() + SCM.Autocomplete:updateAutocomplete() + + -- enable newline starting with `scm ` + if SCM.Config.config["allowCLIPrefix"] then + SCM.Config.config["cliPrefix"] = true + SCM.Config:saveConfig() + end + + -- some interface + local _, cursorY = term.getCursorPos() + if cursorY < 7 then cursorY = 7 end + term.setCursorPos(1, cursorY) + term.blit(" ", "ffffffffffffffffffffffffffffffff", + "44444444444444444444444444444444") + term.setCursorPos(1, cursorY) + term.scroll(1) + term.blit(" SCM - Script Manager ", "ffffffffffffffffffffffffffffffff", + "44444444444444444444444444444444") + term.setCursorPos(1, cursorY) + term.scroll(1) + term.blit(" Autocomplete enabled. ", "77777777777777777777777777777777", + "44444444444444444444444444444444") + term.setCursorPos(1, cursorY) + term.scroll(1) + term.blit(" Type `scm help` to learn more. ", "77777777ffffffff7777777777777777", + "44444444444444444444444444444444") + term.setCursorPos(1, cursorY) + term.scroll(1) + if (SCM.Config.config["updateAvailable"]) then + term.blit(" Update available! ", "7eeeeeeeeeeeeeeeee77777777777777", + "44444444444444444444444444444444") + term.setCursorPos(1, cursorY) + term.scroll(1) + end + term.blit(" ", "ffffffffffffffffffffffffffffffff", + "44444444444444444444444444444444") + term.setCursorPos(1, cursorY) + term.scroll(2) + + if SCM.Config.config["cliPrefix"] then + shell.run(read(nil, nil, shell.complete, "scm ")) + end end end diff --git a/scm.lua b/scm.lua index 1b960af..9035f6b 100644 --- a/scm.lua +++ b/scm.lua @@ -2,13 +2,42 @@ SCM = {} require('libs.scm.config') require('libs.scm.net') +require('libs.scm.log') require('libs.scm.scriptManager') require('libs.scm.autocomplete') require('libs.scm.ui') +function SCM:checkVersion() + if not self.Config.config["updateAvailable"] and self.Config.config["lastVersionCheck"] ~= '' .. os.day("utc") then + local success, newestVersion = self.Net:getNewestVersion() + if success and newestVersion ~= self.Config.config["currentVersion"] then + self.Config.config["updateAvailable"] = true + end - function SCM:Test() - + self.Config.config["lastVersionCheck"] = os.day("utc") .. '' + self.Config:saveConfig() end - -return SCM \ No newline at end of file +end + +function SCM:init() + if not fs.exists(self.Config.config["configDirectory"]) then + fs.makeDir(self.Config.config["configDirectory"]) + end + if not fs.exists(self.Config.config["libraryDirectory"]) then + fs.makeDir(self.Config.config["libraryDirectory"]) + end + + self.Config:loadConfig() + self.ScriptManager:loadScripts() + + self:checkVersion() +end + +function SCM:load(...) + return SCM.ScriptManager:load(...) +end + +SCM:init() +SCM.Autocomplete:handleArguments({ ... }) + +return SCM diff --git a/scmInstaller.lua b/scmInstaller.lua index a21f492..cccfbca 100644 --- a/scmInstaller.lua +++ b/scmInstaller.lua @@ -11,10 +11,11 @@ local files = { 'libs/scm.lua', 'scm.lua', } +local branch = 'master' local function installFiles() for _, script in ipairs(files) do - http.get('https://raw.githubusercontent.com/mc-cc-scripts/script-manager/master/' .. script, nil, function(_, data) + http.get('https://raw.githubusercontent.com/mc-cc-scripts/script-manager/'.. branch ..'/' .. script, nil, function(_, data) local file = fs.open(script, 'w') file.write(data) file.close() diff --git a/tests/Suite/fs.lua b/tests/Suite/fs.lua index 7b9c4b0..379d45d 100644 --- a/tests/Suite/fs.lua +++ b/tests/Suite/fs.lua @@ -40,6 +40,46 @@ do file:close() return true end + + fs.copy = function(src, dest) + assert("string" == type(src), "src must be a string") + assert("string" == type(dest), "dest must be a string") + local file = io.open(src, "r") + if not file then + print("file "..src.." not found") + return false + end + local content = file:read("*a") + file:close() + file = io.open(dest, "w") + if not file then + if not file then + -- find all occurences of / in the path + local dirs = {} + for i = 1, #dest do + if dest:sub(i, i) == "/" then + table.insert(dirs, i) + end + end + -- create all directories + local dir = "" + for i = 1, #dirs do + dir = dest:sub(1, dirs[i]) + if not fs.exists(dir) then + os.execute("mkdir " .. dir) + end + end + file = io.open(dest, "w") + if not file then + print("file"..dest.." not found") + return false + end + end + end + file:write(content) + file:close() + return true + end end return fs diff --git a/tests/testSuite.lua b/tests/testSuite.lua index 62ee150..5f3b78f 100644 --- a/tests/testSuite.lua +++ b/tests/testSuite.lua @@ -16,7 +16,7 @@ _G.textutils = textutils _G.http = { get = function(...) local t = https.request(...) - if t == "404: Not Found" then + if t == "404: Not Found" and printAllowed then print("404: Not Found for request: " .. tostring(...)) end return @@ -33,4 +33,6 @@ _G.shell = { ["run"] = function (...) return end } +_G.printAllowed = false + _G.fs = fs diff --git a/tests/test_spec.lua b/tests/test_spec.lua index 39edc8d..79d9acc 100644 --- a/tests/test_spec.lua +++ b/tests/test_spec.lua @@ -85,7 +85,20 @@ local function runTests(func, ...) end end + describe("Testing everything about SCM:", function() + + describe("Copy Files", function() + assert.is_true(fs.copy("./scm.lua", "tmpFiles/scm.lua"), "Could not copy scm.lua") + assert.is_true(fs.copy("./libs/scm/config.lua", "tmpFiles/config.lua"), "Could not copy config.lua") + assert.is_true(fs.copy("./libs/scm/net.lua", "tmpFiles/net.lua"), "Could not copy net.lua") + assert.is_true(fs.copy("./libs/scm/log.lua", "tmpFiles/log.lua"), "Could not copy log.lua") + assert.is_true(fs.copy("./libs/scm/scriptManager.lua", "tmpFiles/scriptManager.lua"), "Could not copy scriptManager.lua") + assert.is_true(fs.copy("./libs/scm/autocomplete.lua", "tmpFiles/autocomplete.lua"), "Could not copy autocomplete.lua") + assert.is_true(fs.copy("./libs/scm/ui.lua", "tmpFiles/ui.lua"), "Could not copy ui.lua") + assert.is_true(fs.copy("./scmInstaller.lua", "tmpFiles/scmInstaller.lua"), "Could not copy scmInstaller.lua") + end) + describe("Require all SCM Modules", function() it("should be able to require all modules", function() local scm = require("../scm") @@ -96,9 +109,10 @@ describe("Testing everything about SCM:", function() assert.is.truthy(scm.UI) assert.is.truthy(scm.ScriptManager) assert.is.truthy(scm.Log) - print("Require of all modules test passed") + -- print("Require of all modules test passed") end) end) + describe("Config ->", function() it("Change SCM Config", function() runTests(function(scm) @@ -115,10 +129,11 @@ describe("Testing everything about SCM:", function() assert.equal("Wrong", config:getAll()["verbose"]) config:set("verbose", true) assert.is.truthy(config:getAll()["verbose"] == true) - print("Config test passed") + -- print("Config test passed") end) end) end) + describe("ScriptManager ->", function() it("Load Empty", function() runTests( @@ -130,7 +145,7 @@ describe("Testing everything about SCM:", function() assert.is.truthy(scripts) assert.is.truthy(type(scripts) == "table") - print("1. ScriptManager test passed") + -- print("1. ScriptManager test passed (Load Empty)") end ) end) @@ -138,17 +153,17 @@ describe("Testing everything about SCM:", function() runTests( function(scm) local scriptManager = scm.ScriptManager - local file = io.open("testFile.lua", "w") + local file = io.open("localtestFile.lua", "w") if not file then error('file not create') end file:write("local t = {test = true} \n return t") file:close() - local tFile = scm:load("testFile") + local tFile = scm:load("localtestFile") assert.is.truthy(tFile) assert.is.truthy(tFile.test) - os.remove("testFile.lua") - print("2. ScriptManager test passed") + os.remove("localtestFile.lua") + -- print("2. ScriptManager test passed (Load Local)") end ) end) @@ -159,22 +174,24 @@ describe("Testing everything about SCM:", function() function(scm) local testScript = scm:load("scmTest") local scriptManager = scm.ScriptManager - -- what should be there: - -- local tScript = { - -- name = "testLibrary", - -- type = "remote", - -- source = { - -- ["github"] = "https://raw.githubusercontent.com/mc-cc-scripts/script-manager/master/testLibrary.lua" - -- } - -- } - -- scriptManager:addScript(tScript, true) assert.is.truthy(testScript) assert.is.truthy(testScript.test) - print("3. ScriptManager test passed") + -- print("3. ScriptManager test passed (Load Remote)") end ) end) - end) end) -end) + + describe("Restore Files", function() + assert.is_true(fs.copy("tmpFiles/scm.lua", "./scm.lua"), "Could not restore scm.lua") + assert.is_true(fs.copy("tmpFiles/config.lua", "./libs/scm/config.lua"), "Could not restore config.lua") + assert.is_true(fs.copy("tmpFiles/net.lua", "./libs/scm/net.lua"), "Could not restore net.lua") + assert.is_true(fs.copy("tmpFiles/log.lua", "./libs/scm/log.lua"), "Could not restore log.lua") + assert.is_true(fs.copy("tmpFiles/scriptManager.lua", "./libs/scm/scriptManager.lua"), "Could not restore scriptManager.lua") + assert.is_true(fs.copy("tmpFiles/autocomplete.lua", "./libs/scm/autocomplete.lua"), "Could not restore autocomplete.lua") + assert.is_true(fs.copy("tmpFiles/ui.lua", "./libs/scm/ui.lua"), "Could not restore ui.lua") + assert.is_true(fs.copy("tmpFiles/scmInstaller.lua", "./scmInstaller.lua"), "Could not restore scmInstaller.lua") + os.execute("rm --recursive ./tmpFiles") + end) +end) \ No newline at end of file From 1a70277a60b66c1a815698ba573e98b19d7cded4 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Sat, 5 Aug 2023 23:11:36 +0200 Subject: [PATCH 07/51] Issue-30 Updated LuaAction Version --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d37adf5..a605d92 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,12 +10,12 @@ jobs: uses: actions/checkout@v2 - name: get lua - uses: leafo/gh-actions-lua@v5 + uses: leafo/gh-actions-lua@v10 with: luaVersion: "5.1" - name: get luarocks - uses: leafo/gh-actions-luarocks@v2 + uses: leafo/gh-actions-luarocks@v4 - name: get busted run: luarocks install busted From b3e98333d9ad6762e0b8b09a1bf0ad4ca69907b5 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Sat, 5 Aug 2023 23:13:49 +0200 Subject: [PATCH 08/51] Issue-30 Removed Terminal --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a605d92..ec8da72 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,4 +22,4 @@ jobs: - name: run tests run: | - busted . -o -utfTerminal + busted . From 934f52c2e934fb8507a1b6e367c35d141006ae60 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Sat, 5 Aug 2023 23:26:48 +0200 Subject: [PATCH 09/51] Issue-30 luasocket --- .github/workflows/test.yml | 4 +++- tests/testSuite.lua | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ec8da72..8e996e8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,9 @@ jobs: uses: leafo/gh-actions-luarocks@v4 - name: get busted - run: luarocks install busted + run: | + luarocks install busted + luarocks install luasocket - name: run tests run: | diff --git a/tests/testSuite.lua b/tests/testSuite.lua index 5f3b78f..6e89e57 100644 --- a/tests/testSuite.lua +++ b/tests/testSuite.lua @@ -1,7 +1,7 @@ -- implement Test Suite local json = require("tests/Suite/json") -local https = require("ssl.https") +local https = require("socket.http") local fs = require("tests/Suite/fs") local textutils = {} ---@param t table From 489e329a45e5927821315a42f992a8ba18dd8900 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Sat, 5 Aug 2023 23:47:33 +0200 Subject: [PATCH 10/51] Issue-30 MakeDir --- .github/workflows/test.yml | 2 +- tests/Suite/fs.lua | 23 +++++++++++++++++++++++ tests/Suite/http.lua | 7 ------- 3 files changed, 24 insertions(+), 8 deletions(-) delete mode 100644 tests/Suite/http.lua diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8e996e8..0c65f65 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: - name: get luarocks uses: leafo/gh-actions-luarocks@v4 - - name: get busted + - name: get busted and luasocket run: | luarocks install busted luarocks install luasocket diff --git a/tests/Suite/fs.lua b/tests/Suite/fs.lua index 379d45d..3eb4e6c 100644 --- a/tests/Suite/fs.lua +++ b/tests/Suite/fs.lua @@ -80,6 +80,29 @@ do file:close() return true end + + fs.makeDir = function(path) + assert("string" == type(path), "path must be a string") + path = path .. "/" + local exists = os.rename(path, path) + if not exists then + local dirs = {} + for i = 1, #path do + if path:sub(i, i) == "/" then + table.insert(dirs, i) + end + end + -- create all directories + local dir = "" + for i = 1, #dirs do + dir = path:sub(1, dirs[i]) + if not fs.exists(dir) then + os.execute("mkdir " .. dir) + end + end + + end + end end return fs diff --git a/tests/Suite/http.lua b/tests/Suite/http.lua deleted file mode 100644 index 64d0230..0000000 --- a/tests/Suite/http.lua +++ /dev/null @@ -1,7 +0,0 @@ -local http = require("ssl.https") - -local url = "https://raw.githubusercontent.com/mc-cc-scripts/script-manager/master/README.md" - -local res, code, headers, status = http.request(url) - -print(res, code, headers, status) From a07d7a5bca49f228bef7e504fc341ad4ae4ee1f3 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Sat, 5 Aug 2023 23:53:24 +0200 Subject: [PATCH 11/51] Issue-30 OS.Day --- tests/testSuite.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/testSuite.lua b/tests/testSuite.lua index 6e89e57..b810fd8 100644 --- a/tests/testSuite.lua +++ b/tests/testSuite.lua @@ -33,6 +33,10 @@ _G.shell = { ["run"] = function (...) return end } +-- Just any day, does not matter as of now +_G.os.day = function() return 19574 end + _G.printAllowed = false + _G.fs = fs From 7714594537c64bb80adc4ec0cb506f58a06dcbca Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Wed, 23 Aug 2023 21:34:02 +0200 Subject: [PATCH 12/51] maybe fix https --- .github/workflows/test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0c65f65..e54ea3c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,6 +22,11 @@ jobs: luarocks install busted luarocks install luasocket + - name: fix https + run: | + mkdir /usr/share/lua/5.1/ssl/ + ln -s /usr/share/lua/5.1/https.lua /usr/share/lua/5.1/ssl/https.lua + - name: run tests run: | busted . From fa80cfc01c7b29337fd58494934d0aa60e536ae7 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Wed, 23 Aug 2023 21:36:37 +0200 Subject: [PATCH 13/51] ooof --- .github/workflows/test.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e54ea3c..90c8133 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,11 +22,18 @@ jobs: luarocks install busted luarocks install luasocket + - name: echo stuff + run: + echo ls -l /usr + echo ls -l /usr/share + echo ls -l /usr/share/lua + echo ls -l /usr/share/lua/5.1 + - name: fix https run: | - mkdir /usr/share/lua/5.1/ssl/ + mkdir -p /usr/share/lua/5.1/ssl/ ln -s /usr/share/lua/5.1/https.lua /usr/share/lua/5.1/ssl/https.lua - + - name: run tests run: | busted . From 1434a817345c3d40aefeeb0def2e57932e6aaf84 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Wed, 23 Aug 2023 21:40:35 +0200 Subject: [PATCH 14/51] ooooooooof --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 90c8133..e60fbc3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,7 +32,8 @@ jobs: - name: fix https run: | mkdir -p /usr/share/lua/5.1/ssl/ - ln -s /usr/share/lua/5.1/https.lua /usr/share/lua/5.1/ssl/https.lua + cat /usr/share/lua/5.1/ssl.lua | echo + ln -s /usr/share/lua/5.1/https.lua /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/ssl/https.lua - name: run tests run: | From 224a1e71c88f67e24429ad2fb43ccab76c05f6fc Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Wed, 23 Aug 2023 21:44:35 +0200 Subject: [PATCH 15/51] oooooooooooooof --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e60fbc3..2e04bff 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,9 +31,9 @@ jobs: - name: fix https run: | - mkdir -p /usr/share/lua/5.1/ssl/ - cat /usr/share/lua/5.1/ssl.lua | echo - ln -s /usr/share/lua/5.1/https.lua /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/ssl/https.lua + mkdir -p /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/ssl/ + cat /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/https.lua | echo + ln -s /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/https.lua /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/ssl/https.lua - name: run tests run: | From 2840ff7ebb728d655a13069cf173c13842f330af Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Wed, 23 Aug 2023 21:47:47 +0200 Subject: [PATCH 16/51] lua does not rock --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2e04bff..9897ed1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: echo ls -l /usr echo ls -l /usr/share echo ls -l /usr/share/lua - echo ls -l /usr/share/lua/5.1 + echo ls -l /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/luarocks - name: fix https run: | From 7cdd58634e21f3dcf8ff14e69e2685f716ad86d5 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Wed, 23 Aug 2023 21:54:14 +0200 Subject: [PATCH 17/51] try again --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9897ed1..a1de325 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: luarocks install luasocket - name: echo stuff - run: + run: | echo ls -l /usr echo ls -l /usr/share echo ls -l /usr/share/lua From d3705a29b0ebd9ace6be9746d3eaf20d82e15b94 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Wed, 23 Aug 2023 21:56:00 +0200 Subject: [PATCH 18/51] daskos --- .github/workflows/test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a1de325..18ca847 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,10 +24,10 @@ jobs: - name: echo stuff run: | - echo ls -l /usr - echo ls -l /usr/share - echo ls -l /usr/share/lua - echo ls -l /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/luarocks + ls -l /usr + ls -l /usr/share + ls -l /usr/share/lua + ls -l /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/luarocks - name: fix https run: | From 1f6029df26bb6536363cd495834f4b11532fc077 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Wed, 23 Aug 2023 21:58:41 +0200 Subject: [PATCH 19/51] Issue-30 macht sinn! --- .github/workflows/test.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 18ca847..93870fe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,10 +24,7 @@ jobs: - name: echo stuff run: | - ls -l /usr - ls -l /usr/share - ls -l /usr/share/lua - ls -l /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/luarocks + ls -l /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/luarocks/ - name: fix https run: | From 41abb8aa850c223aa8c08dbe7f22287694a56cea Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Wed, 23 Aug 2023 22:03:12 +0200 Subject: [PATCH 20/51] no --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 93870fe..a5fc8cd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ jobs: - name: echo stuff run: | - ls -l /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/luarocks/ + ls -l /home/runner/work/script-manager/script-manager/.lua - name: fix https run: | From ab670a6dedadfe1af5f3fef5df19853f9f18c075 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Wed, 23 Aug 2023 22:05:14 +0200 Subject: [PATCH 21/51] ooko --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a5fc8cd..c8a3505 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ jobs: - name: echo stuff run: | - ls -l /home/runner/work/script-manager/script-manager/.lua + ls -l /home/runner/work/script-manager/script-manager/.luarocks/ - name: fix https run: | From 8db884fd719fcd04bc1465983a78f8c0db51d998 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Wed, 23 Aug 2023 22:07:01 +0200 Subject: [PATCH 22/51] dasd --- .github/workflows/test.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c8a3505..fa0288b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,10 +21,14 @@ jobs: run: | luarocks install busted luarocks install luasocket + apt install lua-socket - name: echo stuff run: | - ls -l /home/runner/work/script-manager/script-manager/.luarocks/ + ls -l /home/runner/work/script-manager/script-manager/.luarocks/share + ls -l /home/runner/work/script-manager/script-manager/.luarocks/lib + ls -l /home/runner/work/script-manager/script-manager/.luarocks/etc + ls -l /home/runner/work/script-manager/script-manager/.luarocks/bin - name: fix https run: | @@ -34,4 +38,4 @@ jobs: - name: run tests run: | - busted . + busted . \ No newline at end of file From cae6b7d6512a6fa2233e15c21eaf0018368df9ce Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Wed, 23 Aug 2023 22:08:42 +0200 Subject: [PATCH 23/51] sodu --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fa0288b..52d2a6c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: run: | luarocks install busted luarocks install luasocket - apt install lua-socket + sudo apt install lua-socket - name: echo stuff run: | From a5452078605ca86e10251ed9da4efbc1c17c9bae Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Thu, 24 Aug 2023 22:30:58 +0200 Subject: [PATCH 24/51] kik --- .github/workflows/test.yml | 47 ++++++---------------------------- .github/workflows/test.yml.old | 41 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 39 deletions(-) create mode 100644 .github/workflows/test.yml.old diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 52d2a6c..e799294 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,41 +1,10 @@ -name: test - +name: Busted on: [push, pull_request] - jobs: - test: - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v2 - - - name: get lua - uses: leafo/gh-actions-lua@v10 - with: - luaVersion: "5.1" - - - name: get luarocks - uses: leafo/gh-actions-luarocks@v4 - - - name: get busted and luasocket - run: | - luarocks install busted - luarocks install luasocket - sudo apt install lua-socket - - - name: echo stuff - run: | - ls -l /home/runner/work/script-manager/script-manager/.luarocks/share - ls -l /home/runner/work/script-manager/script-manager/.luarocks/lib - ls -l /home/runner/work/script-manager/script-manager/.luarocks/etc - ls -l /home/runner/work/script-manager/script-manager/.luarocks/bin - - - name: fix https - run: | - mkdir -p /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/ssl/ - cat /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/https.lua | echo - ln -s /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/https.lua /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/ssl/https.lua - - - name: run tests - run: | - busted . \ No newline at end of file + sile: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Run Busted + uses: lunarmodules/busted@v \ No newline at end of file diff --git a/.github/workflows/test.yml.old b/.github/workflows/test.yml.old new file mode 100644 index 0000000..52d2a6c --- /dev/null +++ b/.github/workflows/test.yml.old @@ -0,0 +1,41 @@ +name: test + +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: get lua + uses: leafo/gh-actions-lua@v10 + with: + luaVersion: "5.1" + + - name: get luarocks + uses: leafo/gh-actions-luarocks@v4 + + - name: get busted and luasocket + run: | + luarocks install busted + luarocks install luasocket + sudo apt install lua-socket + + - name: echo stuff + run: | + ls -l /home/runner/work/script-manager/script-manager/.luarocks/share + ls -l /home/runner/work/script-manager/script-manager/.luarocks/lib + ls -l /home/runner/work/script-manager/script-manager/.luarocks/etc + ls -l /home/runner/work/script-manager/script-manager/.luarocks/bin + + - name: fix https + run: | + mkdir -p /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/ssl/ + cat /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/https.lua | echo + ln -s /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/https.lua /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/ssl/https.lua + + - name: run tests + run: | + busted . \ No newline at end of file From ba50f368680e20e2015a065eb3f8f0e7ed2a2cce Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Thu, 24 Aug 2023 22:32:02 +0200 Subject: [PATCH 25/51] asdsa --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e799294..ef9ebb5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,4 +7,4 @@ jobs: - name: Checkout uses: actions/checkout@v3 - name: Run Busted - uses: lunarmodules/busted@v \ No newline at end of file + uses: lunarmodules/busted@v0 \ No newline at end of file From ce88296e71aa024d17c60ddc0813514c57037952 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Thu, 24 Aug 2023 22:34:48 +0200 Subject: [PATCH 26/51] asdas --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ef9ebb5..c3604aa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,4 +7,4 @@ jobs: - name: Checkout uses: actions/checkout@v3 - name: Run Busted - uses: lunarmodules/busted@v0 \ No newline at end of file + uses: lunarmodules/busted@latest \ No newline at end of file From ccb017ba3de48d6e03b4c3ff914f0f5f3f36203c Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Thu, 24 Aug 2023 22:37:30 +0200 Subject: [PATCH 27/51] adsa --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c3604aa..3194d06 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,7 +2,7 @@ name: Busted on: [push, pull_request] jobs: sile: - runs-on: ubuntu-latest + runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v3 From 627c7532e8eee924268269e694d6fd9053867d66 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Thu, 24 Aug 2023 22:40:49 +0200 Subject: [PATCH 28/51] dsds --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3194d06..4fc9a70 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,7 +2,7 @@ name: Busted on: [push, pull_request] jobs: sile: - runs-on: windows-latest + runs-on: ubuntu-20.04 steps: - name: Checkout uses: actions/checkout@v3 From b7d781bed7f574da49ae0497e938abbb51f4b399 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Thu, 24 Aug 2023 22:53:11 +0200 Subject: [PATCH 29/51] daisj --- .github/workflows/test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4fc9a70..b7f3cfd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,9 +2,9 @@ name: Busted on: [push, pull_request] jobs: sile: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 - - name: Run Busted - uses: lunarmodules/busted@latest \ No newline at end of file + run: | + docker pull ghcr.io/lunarmodules/busted:latest + docker run -v "$(pwd):/data" ghcr.io/lunarmodules/busted:latest specs \ No newline at end of file From c56afd62e1811685cb6da86f41faae63640aca51 Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 27 Aug 2023 15:25:59 +0200 Subject: [PATCH 30/51] Update test.yml --- .github/workflows/test.yml | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b7f3cfd..a11795c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,10 +1,29 @@ name: Busted + on: [push, pull_request] + jobs: - sile: - runs-on: ubuntu-latest - steps: - - name: Checkout - run: | - docker pull ghcr.io/lunarmodules/busted:latest - docker run -v "$(pwd):/data" ghcr.io/lunarmodules/busted:latest specs \ No newline at end of file + test: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: get lua + uses: leafo/gh-actions-lua@v10 + with: + luaVersion: "5.1" + + - name: get luarocks + uses: leafo/gh-actions-luarocks@v4 + with: + luaVersion: "5.1" + + - name: get busted and luasocket + run: | + luarocks install busted + luarocks install luasocket + + - name: run tests + run: | + busted . From 4b536da5c072b387e007659b02a2faa34f7ba59c Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 27 Aug 2023 15:31:12 +0200 Subject: [PATCH 31/51] Update test.yml --- .github/workflows/test.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a11795c..9ede12a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,6 +23,18 @@ jobs: run: | luarocks install busted luarocks install luasocket + + - name: debug + run: | + ls -l /home/runner/work/script-manager/script-manager/.luarocks + ls -l /home/runner/work/script-manager/script-manager/.luarocks/share + ls -l /home/runner/work/script-manager/script-manager/.luarocks/lib + ls -l /home/runner/work/script-manager/script-manager/.luarocks/etc + ls -l /home/runner/work/script-manager/script-manager/.luarocks/bin + ls -l /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/ + ls -l /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/socket + + - name: run tests run: | From 0a965ec6932eb5093320acf43e38f2a5f2f3719a Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 27 Aug 2023 15:39:27 +0200 Subject: [PATCH 32/51] Update test.yml --- .github/workflows/test.yml | 48 ++++++++++++++------------------------ 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9ede12a..1f27425 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,39 +3,25 @@ name: Busted on: [push, pull_request] jobs: - test: - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v2 + test: + runs-on: ubuntu-latest - - name: get lua - uses: leafo/gh-actions-lua@v10 - with: - luaVersion: "5.1" + steps: + - uses: actions/checkout@master - - name: get luarocks - uses: leafo/gh-actions-luarocks@v4 - with: - luaVersion: "5.1" + - uses: leafo/gh-actions-lua@v10 + with: + luaVersion: "5.1.5" - - name: get busted and luasocket - run: | - luarocks install busted - luarocks install luasocket - - - name: debug - run: | - ls -l /home/runner/work/script-manager/script-manager/.luarocks - ls -l /home/runner/work/script-manager/script-manager/.luarocks/share - ls -l /home/runner/work/script-manager/script-manager/.luarocks/lib - ls -l /home/runner/work/script-manager/script-manager/.luarocks/etc - ls -l /home/runner/work/script-manager/script-manager/.luarocks/bin - ls -l /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/ - ls -l /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/socket + - uses: leafo/gh-actions-luarocks@v4 + with: + luaVersion: "5.1.5" - + - name: build + run: | + luarocks install busted + luarocks make - - name: run tests - run: | - busted . + - name: test + run: | + busted . From 0047d16b6169516f474aac08c99a6add6ca21a12 Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 27 Aug 2023 15:47:11 +0200 Subject: [PATCH 33/51] Update test.yml --- .github/workflows/test.yml | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1f27425..0c090de 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,20 +7,29 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - name: checkout + uses: actions/checkout@v2 - - uses: leafo/gh-actions-lua@v10 - with: - luaVersion: "5.1.5" + - name: get lua + uses: leafo/gh-actions-lua@v10 + with: + luaVersion: "5.1" - - uses: leafo/gh-actions-luarocks@v4 - with: - luaVersion: "5.1.5" + - name: get luarocks + uses: leafo/gh-actions-luarocks@v4 + with: + luaVersion: "5.1" - - name: build + - name: get busted and luasocket run: | luarocks install busted - luarocks make + luarocks install luasocket + + - name: debug + run: | + ls -l + ls -l /.lua/ + ls -l /usr/share/lua/5.1 - name: test run: | From fa959e505ed6df156370b94f8fa385b9baadda66 Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 27 Aug 2023 15:48:42 +0200 Subject: [PATCH 34/51] Update test.yml --- .github/workflows/test.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0c090de..a81da93 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,8 +27,6 @@ jobs: - name: debug run: | - ls -l - ls -l /.lua/ ls -l /usr/share/lua/5.1 - name: test From e5f8320c08568934b4ffa3b2e0fd67bf6776a8cf Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 27 Aug 2023 15:50:11 +0200 Subject: [PATCH 35/51] Update test.yml --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a81da93..b0735db 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,10 +24,11 @@ jobs: run: | luarocks install busted luarocks install luasocket + luarocks install luasec - name: debug run: | - ls -l /usr/share/lua/5.1 + ls -l /usr/share/lua/ - name: test run: | From 8044844ce1b05a4393c8e10dc804f6763f8ba4ab Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 27 Aug 2023 15:51:05 +0200 Subject: [PATCH 36/51] Update test.yml --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b0735db..8cee602 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,7 @@ jobs: - name: debug run: | - ls -l /usr/share/lua/ + ls -l /usr/share/ - name: test run: | From d9f55aed7ccc1952f3b39f4b400c86ded99890d9 Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 27 Aug 2023 15:52:25 +0200 Subject: [PATCH 37/51] remove debug from test --- .github/workflows/test.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8cee602..df43f48 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,10 +26,6 @@ jobs: luarocks install luasocket luarocks install luasec - - name: debug - run: | - ls -l /usr/share/ - - name: test run: | busted . From b4d3393ffcc43665a318f8f42cc63aa8e70fefc0 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Sun, 3 Dec 2023 13:44:11 +0100 Subject: [PATCH 38/51] Small Fixes. Testsuit not working --- libs/scm/config.lua | 14 +- libs/scm/net.lua | 34 +- libs/scm/scriptManager.lua | 12 +- scm old.lua | 1032 ------------------------------------ 4 files changed, 30 insertions(+), 1062 deletions(-) delete mode 100644 scm old.lua diff --git a/libs/scm/config.lua b/libs/scm/config.lua index ca5eea9..3287ce5 100644 --- a/libs/scm/config.lua +++ b/libs/scm/config.lua @@ -58,27 +58,27 @@ do function Config:saveConfig(config) config = config or self.config - local file = io.open(config["configDirectory"] .. config["configFile"], "w") + local file = fs.open(config["configDirectory"] .. config["configFile"], "w") if not file then os.execute("mkdir " .. config["configDirectory"]) - file = io.open(config["configDirectory"] .. config["configFile"], "w") + file = fs.open(config["configDirectory"] .. config["configFile"], "w") end - file:write(textutils.serializeJSON(config)) - file:close() + file.write(textutils.serializeJSON(config)) + file.close() end --- loads the config from the config file ---@param config SCMConfigData | nil function Config:loadConfig(config) config = config or self.config - local file = io.open(config["configDirectory"] .. config["configFile"], "r") + local file = fs.open(config["configDirectory"] .. config["configFile"], "r") if not file then -- Create config file if it does not exist yet self:saveConfig(config) else -- Load config from file - local temp = textutils.unserializeJSON(file:read("*all")) or {} + local temp = textutils.unserializeJSON(file.readAll()) or {} -- Check if loaded config size is equal to the default size, -- otherwise the config is corrupted and will be overwritten if tablelength(temp) == tablelength(self.config) then @@ -86,7 +86,7 @@ do else self:saveConfig(config) end - file:close() + file.close() end end diff --git a/libs/scm/net.lua b/libs/scm/net.lua index 8a56ee1..8b66cdf 100644 --- a/libs/scm/net.lua +++ b/libs/scm/net.lua @@ -114,8 +114,8 @@ do local file = fs.open(targetDirectory .. sourceObject.name .. config()[sourceObject.type .. "Suffix"] .. "/" .. config()["infoFile"], "w") - file:write(content) - file:close() + file.write(content) + file.close() local filePaths = {} if fs then @@ -123,23 +123,23 @@ do .. config()[sourceObject.type .. "Suffix"] .. "/" .. config()["infoFile"], "r") - local line = file:read() + local line = file.read() while line do filePaths[#filePaths + 1] = line - line = file:read() + line = file.read() end - file:close() + file.close() else file = fs.open(targetDirectory .. sourceObject.name .. config()[sourceObject.type .. "Suffix"] .. "/" .. config()["infoFile"], "r") - -- print(file:read()) - local line = file:read() + -- print(file.read()) + local line = file.read() while line do filePaths[#filePaths + 1] = line - line = file:read() + line = file.read() end - file:close() + file.close() end for i = 1, #filePaths, 1 do local success = true @@ -157,8 +157,8 @@ do .. config()[sourceObject.type .. "Suffix"] .. "/" .. filePaths[i], "w") end - tmpFile:write(tmpContent) - tmpFile:close() + tmpfile.write(tmpContent) + tmpfile.close() else success = false end @@ -232,8 +232,8 @@ do os.execute("mkdir " .. targetDirectory) file = fs.open(targetDirectory .. sourceObject.name, "w") end - file:write(content) - file:close() + file.write(content) + file.close() return sourceObject, true end end @@ -291,13 +291,13 @@ do if not file then self:refreshRepoScripts() else - local repoScripts = textutils.unserializeJSON(file:read("*all")) or nil + local repoScripts = textutils.unserializeJSON(file.readAll()) or nil if repoScripts then SCM.Autocomplete:setProgramms(repoScripts["programs"]) SCM.Autocomplete:setLibaries(repoScripts["libraries"]) end - file:close() + file.close() end end @@ -346,8 +346,8 @@ do file = fs.open(config()["configDirectory"] .. config()["repoScriptsFile"], "w") end if file then - file:write(textutils.serializeJSON(repoScripts)) - file:close() + file.write(""..textutils.serializeJSON(repoScripts)) + file.close() end end diff --git a/libs/scm/scriptManager.lua b/libs/scm/scriptManager.lua index 4781182..3e80a4d 100644 --- a/libs/scm/scriptManager.lua +++ b/libs/scm/scriptManager.lua @@ -21,8 +21,8 @@ do if not file then self:saveScripts() else - self.scripts = textutils.unserializeJSON(file:read("*all") or "") - file:close() + self.scripts = textutils.unserializeJSON(file.readAll() or "") + file.close() if not self.scripts then self.scripts = {} end @@ -36,8 +36,8 @@ do os.execute("mkdir " .. config["configDirectory"]) file = fs.open(config["configDirectory"] .. config["scriptFile"], "w") end - file:write(textutils.serializeJSON(self.scripts)) - file:close() + file.write(""..textutils.serializeJSON(self.scripts)) + file.close() end ---adds a script to the script File @@ -185,7 +185,7 @@ function ScriptManager:checkRequirements(name, localPath) -- Find requirements by searching for comment --@requires name local requires = {} while true do - local line = file:read() + local line = file.read() if not line then break end local find = string.find(line, "--@requires") @@ -203,7 +203,7 @@ function ScriptManager:checkRequirements(name, localPath) requires[#requires + 1] = scriptName end end - file:close() + file.close() -- Install missing requirements for i = 1, #requires do diff --git a/scm old.lua b/scm old.lua deleted file mode 100644 index 2fdddfb..0000000 --- a/scm old.lua +++ /dev/null @@ -1,1032 +0,0 @@ ----Note: scm is not a real class, it should only exist once. ----@class scm -local scm = {} - --- Configuration -scm.config = { - -- Git Settings (In this case on GitHub, not tested with others) - ["user"] = "mc-cc-scripts", - ["repository"] = "script-manager", - ["branch"] = "master", - ["rawURL"] = "https://raw.githubusercontent.com/", - ["programSuffix"] = "-prog", - ["librarySuffix"] = "-lib", - ["infoFile"] = "files.txt", -- provides the structure of a git repo (paths to all files) - ["apiGithubURL"] = "https://api.github.com/orgs/", - ["apiGithubGetRepos"] = "/repos?type=all&per_page=100&page=1", - ["apiGithubGetTags"] = "https://api.github.com/repos///tags", - ["installScript"] = "1kKZ8zTS", - -- Local Settings - ["currentVersion"] = "0.0.0", -- will get the newest version through the github api, no need to update here - ["updateAvailable"] = false, - ["lastVersionCheck"] = "1", - ["programDirectory"] = "progs/", - ["libraryDirectory"] = "libs/", - ["configDirectory"] = "config/", - ["configFile"] = "scm-config.json", - ["scriptFile"] = "scm-scripts.json", -- will be saved in configDirectory as well - ["verbose"] = true, - ["printPrefix"] = "[scm] ", - ["logDate"] = false, - ["writeLogFile"] = false, - ["logFilePath"] = "logs/scm-log.txt", - ["repoScriptsFile"] = "scm-repo-scripts.txt", -- will be saved in configDirectory as well - ["allowCLIPrefix"] = true, - ["cliPrefix"] = false -} ----------------- - - -scm.scripts = {} -scm.commands = { - ["require"] = { - ---@param args table - func = function(args) - scm:download(args[2], "library", nil) - end, - description = [[ -Adds a library with all its dependencies. -If only a name is given, it will try to download from the official GitHub repositories. -$ require -$ require @ - ]] - }, - ["add"] = { - ---@param args table - func = function(args) - scm:download(args[2], "program", nil) - end, - description = [[ -Adds a program with all its dependencies. -If only a name is given, it will try to download from the official GitHub repositories. -$ add -$ add @ - ]] - }, - ["update"] = { - ---@param args table - func = function(args) - if args[2] == "all" then - scm:updateAllScripts() - elseif args[3] then - scm:updateScript(args[2], args[3]) - elseif args[2] then - scm:updateScript(args[2], nil) - else - scm:updateSCM() - end - end, - description = [[ -$ update - Updates this program (SCM) -$ update - Updates the script with the given name -$ update all - Updates all installed programs and libraries -$ update - Updates the script with an specific source - ]] - }, - ["remove"] = { - ---@param args table - func = function(args) - if args[2] == "all" then - scm:removeAllScripts() - else - scm:removeScript(args[2]) - end - end, - description = [[ -$ remove - Removes the given script -$ remove all - Removes all scripts - ]] - }, - ["list"] = { - ---@param _ table - func = function(_) - scm:listScripts() - end, - description = [[ -$ list - Lists all installed scripts - ]] - }, - ["config"] = { - ---@param args table - func = function(args) - if args[3] then - scm:updateConfig(args[2], args[3]) - elseif args[2] then - if scm.config[args[2]] ~= nil then - print(args[2], tostring(scm.config[args[2]])) - end - else - print("You can currently configure the following variables:") - for cname, cvalue in pairs(scm.config) do - textutils.pagedPrint(cname .. "\t" .. tostring(cvalue)) - end - end - end, - description = [[ -$ config - Lists all available configurations -$ config - Shows a specific configuration -$ config - Updates the configuration - ]] - }, - ["refresh"] = { - func = function(args) - scm:refreshAutocomplete() - end, - description = [[ -$ refresh - Downloads the names of all programs and libraries of the official repository. - Refreshes autocomplete. - ]] - }, - ["help"] = { - ---@param args table - func = function(args) - if args[2] then - if scm.commands[args[2]] then - textutils.pagedPrint(args[2] .. "\n" .. scm.commands[args[2]]["description"]) - end - else - for k, v in pairs(scm.commands) do - textutils.pagedPrint("# " .. k .. "\n" .. v.description) - end - end - end, - description = [[ -$ help - Shows all available commands and their description -$ help - Shows the description of the given command - ]] - } -} - -function scm:refreshRepoScripts() - self:log("Downloading program and library names from GitHub...") - local repoScripts = {} - - local programs = {} - local libraries = {} - - local request = http.get(self.config["apiGithubURL"] .. self.config["user"] .. self.config["apiGithubGetRepos"]) - if request then - local response = request.readAll() - request.close() - - local responseTable = textutils.unserializeJSON(response) - - local programSuffix = self.config["programSuffix"] - local librarySuffix = self.config["librarySuffix"] - - for i = 1, #responseTable, 1 do - local scriptName = responseTable[i]["name"] - if string.sub(scriptName, -string.len(programSuffix)) == programSuffix then - programs[ - string.sub(scriptName, 0, string.len(scriptName) - string.len(programSuffix)) - ] = {} - elseif string.sub(scriptName, -string.len(librarySuffix)) == librarySuffix then - libraries[ - string.sub(scriptName, 0, string.len(scriptName) - string.len(librarySuffix)) - ] = {} - end - end - scm:log("Done") - else - scm:log("Download failed") - end - - self.commands["add"]["args"] = programs - self.commands["require"]["args"] = libraries - - repoScripts["libraries"] = libraries - repoScripts["programs"] = programs - - local file = fs.open(self.config["configDirectory"] .. self.config["repoScriptsFile"], "w") - if file then - file.write(textutils.serializeJSON(repoScripts)) - file.close() - end -end - -function scm:loadRepoScripts() - local file = fs.open(self.config["configDirectory"] .. self.config["repoScriptsFile"], "r") - - if not file then - self:refreshRepoScripts() - else - local repoScripts = textutils.unserializeJSON(file.readAll()) or nil - if repoScripts then - self.commands["add"]["args"] = repoScripts["programs"] - self.commands["require"]["args"] = repoScripts["libraries"] - end - - file.close() - end -end - -function scm:prepareAutocomplete() - -- prepare update and remove - scm:loadScripts() - local installedScripts = {} - for i = 1, #self.scripts, 1 do - installedScripts[self.scripts[i].name] = {} - end - installedScripts["all"] = {} - - self.commands["update"]["args"] = installedScripts - self.commands["remove"]["args"] = installedScripts - - -- prepare add and require - self:loadRepoScripts() - - -- prepare config - local availableConfigs = {} - - for k, _ in pairs(self.config) do - availableConfigs[k] = {} - end - - self.commands["config"]["args"] = availableConfigs - - -- prepare help - local availableCommands = {} - - for k, _ in pairs(self.commands) do - availableCommands[k] = {} - end - - self.commands["help"]["args"] = availableCommands -end - ----@param shell table ----@param index integer ----@param argument string ----@param previous table ----@return table | nil -local function completionFunction(shell, index, argument, previous) - local commands = {} - for k, _ in pairs(scm.commands) do - commands[k] = scm.commands[k]["args"] or {} - end - - local currArg = commands - for i = 2, #previous do - if currArg[previous[i]] then - currArg = currArg[previous[i]] - else - return nil - end - end - - local results = {} - for word, _ in pairs(currArg) do - if word:sub(1, #argument) == argument then - results[#results + 1] = word:sub(#argument + 1) - end - end - return results; -end - -local function updateAutocomplete() - shell.setCompletionFunction("scm", completionFunction) -end - -function scm:refreshAutocomplete() - scm:refreshRepoScripts() - scm:prepareAutocomplete() - updateAutocomplete() -end - ----@param message string -function scm:log(message) - local datetime = "" - if self.config["logDate"] then datetime = os.date("[%Y-%m-%d %H:%M:%S] ") end - if self.config["verbose"] then print(self.config["printPrefix"] .. message) end - - if self.config["writeLogFile"] then - local file = fs.open(self.config["logFilePath"], "a") - file.write(datetime .. message .. "\n") - file.close() - end -end - ----@param str string ----@return string | nil ----@return string | nil -function scm:splitNameCode(str) - local separator = string.find(str, "@") - - if separator then - local name = string.sub(str, 1, separator - 1) - local code = string.sub(str, separator + 1) - return name, code - end - - return nil, nil -end - ----@param target string ----@param fileType string ----@param updateObj table | nil ----@return boolean -function scm:download(target, fileType, updateObj) - scm:log("Downloading " .. fileType .. " " .. target .. "...") - if target == nil then - --@TODO: Error handling - return false - end - - local sourceObject = { - name = nil, - source = { - ["default"] = target - }, - type = fileType - } - - if updateObj then sourceObject.name = updateObj.name end - - -- Check for Pastebin - local name, code = self:splitNameCode(target) - if name and code then - sourceObject.name = name - return scm:addScript(self:downloadPastebin(sourceObject, code, self.config[fileType .. "Directory"], updateObj)) - end - - -- We assume it's Git - -- The suffix is used to find the correct repository on GitHub - local suffix - if fileType == "library" then - suffix = self.config["librarySuffix"] - else - suffix = self.config["programSuffix"] - end - local repository = target .. suffix - sourceObject.name = target - - return scm:addScript(self:downloadGit(sourceObject, repository, self.config[fileType .. "Directory"], updateObj)) -end - ----@param sourceObject table ----@param repository string ----@param targetDirectory string ----@param updateObj table | nil ----@return table | nil ----@return boolean -function scm:downloadGit(sourceObject, repository, targetDirectory, updateObj) - local baseUrl = self.config["rawURL"] .. - self.config["user"] .. "/" .. - repository .. "/" .. - self.config["branch"] .. "/" - - local filesUrl = baseUrl .. self.config["infoFile"] - - local request = http.get(filesUrl) - if request then - local content = request.readAll() - request.close() - - if content then - local file = fs.open(targetDirectory .. sourceObject.name - .. self.config[sourceObject.type .. "Suffix"] - .. "/" .. self.config["infoFile"], "w") - file.write(content) - file.close() - - local filePaths = {} - file = fs.open(targetDirectory .. sourceObject.name - .. self.config[sourceObject.type .. "Suffix"] - .. "/" .. self.config["infoFile"], "r") - for line in file.readLine do - filePaths[#filePaths + 1] = line - end - file.close() - - for i = 1, #filePaths, 1 do - local success = true - local tmpRequest = http.get(baseUrl .. filePaths[i]) - if tmpRequest then - local tmpContent = tmpRequest.readAll() - if tmpContent then - local tmpFile = fs.open(targetDirectory .. sourceObject.name - .. self.config[sourceObject.type .. "Suffix"] - .. "/" .. filePaths[i], "w") - tmpFile.write(tmpContent) - tmpFile.close() - else - success = false - end - - tmpRequest.close() - else - success = false - end - - if not success then - return nil, false - end - end - - -- create a link that calls the file within the program directory - if sourceObject.type == "program" then - local progamLink = fs.open(sourceObject.name, "w") - progamLink.write("shell.execute(\"" .. targetDirectory .. sourceObject.name .. - self.config[sourceObject.type .. "Suffix"] - .. "/" .. sourceObject.name .. ".lua" .. "\", ...)") - progamLink.close() - elseif sourceObject.type == "library" then - local libraryLink = fs.open(targetDirectory .. sourceObject.name .. ".lua", "w") - - local tmpName = sourceObject.name - if tmpName:find("%.") then - tmpName = tmpName:match("(.+)%..+$") - end - - libraryLink.write("return require(\"./" .. self.config["libraryDirectory"] - .. tmpName .. self.config[sourceObject.type .. "Suffix"] - .. "/" .. tmpName .. "\")") - libraryLink.close() - end - - return sourceObject, true - end - end - - return nil, false -end - ----@param sourceObject table ----@param code string ----@param targetDirectory string ----@param updateObj table | nil ----@return table | nil ----@return boolean -function scm:downloadPastebin(sourceObject, code, targetDirectory, updateObj) - -- Only download if it does not already exist, or if it should be updated - if fs.exists(targetDirectory .. sourceObject.name) then - if updateObj then - fs.delete(targetDirectory .. sourceObject.name) - sourceObject = updateObj - else - -- File already exists, you should use update - return nil, false - end - end - - if updateObj then - fs.delete(sourceObject.name) - end - - if sourceObject.type == "program" then - shell.run("pastebin", "get", code, sourceObject.name .. ".lua") - else - shell.run("pastebin", "get", code, targetDirectory .. sourceObject.name .. ".lua") - end - - return sourceObject, true -end - ----@param sourceObject table ----@param targetDirectory string ----@param updateObj table | nil ----@return table | nil ----@return boolean -function scm:downloadURL(sourceObject, targetDirectory, updateObj) - local sourceName = "default" or updateObj.sourceName - if updateObj then - sourceObject.name = sourceObject.name or updateObj.name - end - - if not sourceObject.name then - sourceObject.name = self:getNameFromURL(sourceObject.source[sourceName]) - end - - local request = http.get(sourceObject.source[sourceName]) - - if request then - local content = request.readAll() - request.close() - - if content then - local file = fs.open(targetDirectory .. sourceObject.name, "w") - file.write(content) - file.close() - return sourceObject, true - end - end - - return nil, false -end - ----@param url string ----@return string -function scm:getNameFromURL(url) - -- Gets the filename + extension from a url (everything after last /) - local name = url:match("[^/]+$") - - -- Remove file extension if name contains a dot - if name:find("%.") then - name = name:match("(.+)%..+$") - end - - return name -end - ----@param sourceObject table | nil ----@param success boolean ----@return boolean -function scm:addScript(sourceObject, success) - if not success or not sourceObject then return false end - scm:log("Adding script " .. sourceObject.name .. "...") - local scriptExists = false - - -- Check if script already exists, then update - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == sourceObject.name and self.scripts[i].type == sourceObject.type then - scriptExists = true - if self.scripts[i].source[sourceObject.sourceName] then - self.scripts[i].source[sourceObject.sourceName] = sourceObject.source[sourceObject.sourceName] - self:saveScripts() - - return true - end - end - end - - if not scriptExists then - scm:log("Script added: " .. sourceObject.name) - table.insert(self.scripts, sourceObject) - else - scm:log("Script already exists.") - return false - end - - self:saveScripts() - - -- update for autocomplete - self.commands["update"]["args"] = self.commands["update"]["args"] or {} - self.commands["remove"]["args"] = self.commands["remove"]["args"] or {} - self.commands["update"]["args"][sourceObject.name] = {} - self.commands["remove"]["args"][sourceObject.name] = {} - self:prepareAutocomplete() - updateAutocomplete() - - return true -end - -function scm:saveScripts() - local file = fs.open(self.config["configDirectory"] .. self.config["scriptFile"], "w") - file.write(textutils.serializeJSON(self.scripts)) - file.close() -end - -function scm:loadScripts() - local file = fs.open(self.config["configDirectory"] .. self.config["scriptFile"], "r") - - if not file then - self:saveScripts() - else - self.scripts = textutils.unserializeJSON(file.readAll()) or {} - file.close() - end -end - -function scm:listScripts() - print("name", "type") - print("----------------------") - for i = 1, #self.scripts, 1 do - print(self.scripts[i].name, self.scripts[i].type) - end -end - ----@param name string -function scm:removeScript(name, keepScriptConfig) - scm:log("Removing script: " .. name) - local o = {} - local scriptType = nil - - if keepScriptConfig ~= true then - for i = 1, #self.scripts, 1 do - if self.scripts[i].name ~= name then - table.insert(o, self.scripts[i]) - else - scriptType = self.scripts[i].type - end - end - - self.scripts = o - self:saveScripts() - end - - -- delete file - if scriptType and fs.exists(self.config[scriptType .. "Directory"] .. name .. ".lua") then - fs.delete(self.config[scriptType .. "Directory"] .. name .. self.config[scriptType .. "Suffix"]) - if scriptType == "library" then - fs.delete(self.config[scriptType .. "Directory"] .. name .. ".lua") - end - end - - if scriptType == "program" then - fs.delete(name) - end - - -- update autocomplete - self:prepareAutocomplete() - updateAutocomplete() -end - -function scm:removeAllScripts() - local tmpScripts = {} - for i = 1, #self.scripts, 1 do - table.insert(tmpScripts, self.scripts[i].name) - end - - for i = 1, #tmpScripts, 1 do - self:removeScript(tmpScripts[i]) - end -end - ----@param name string ----@param sourceName string ----@return boolean -function scm:updateScript(name, sourceName) - if not sourceName then sourceName = "default" end - - local updateObj = { - ["name"] = name, - ["type"] = nil, - ["sourceName"] = sourceName, - ["source"] = {} - } - - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == name then - updateObj.source[sourceName] = self.scripts[i].source[sourceName] - updateObj.type = self.scripts[i].type - end - end - - if updateObj.source[sourceName] and updateObj.type then - self:removeScript(name, true) - self:download(updateObj.source[sourceName], updateObj.type, updateObj) - return true - end - - return false -end - -function scm:updateAllScripts() - for i = 1, #self.scripts, 1 do - self:updateScript(self.scripts[i].name, "default") - end -end - -function scm:updateSCM() - scm:log("Updating scm...") - shell.run("pastebin", "run", self.config.installScript) - local success, version = self:getNewestVersion() - if success then - self.config["currentVersion"] = version - self.config["updateAvailable"] = false - self.config["lastVersionCheck"] = os.day("utc") - self:saveConfig() - end -end - ----@source: https://stackoverflow.com/a/2705804/10495683 ----@param T table ----@return integer -local function tablelength(T) - local count = 0 - for _ in pairs(T) do count = count + 1 end - return count -end - -function scm:saveConfig() - local file = fs.open(self.config["configDirectory"] .. self.config["configFile"], "w") - file.write(textutils.serializeJSON(self.config)) - file.close() -end - -function scm:loadConfig() - local file = fs.open(self.config["configDirectory"] .. self.config["configFile"], "r") - - if not file then - -- Create config file if it does not exist yet - self:saveConfig() - else - -- Load config from file - local temp = textutils.unserializeJSON(file.readAll()) or {} - -- Check if loaded config size is equal to the default size, - -- otherwise the config is corrupted and will be overwritten - if tablelength(temp) == tablelength(self.config) then - self.config = temp - else - self:saveConfig() - end - file.close() - end -end - ----@param name string ----@param value string -function scm:updateConfig(name, value) - local writeConfig = true - - if name and value then - if self.config[name] ~= nil then - if type(self.config[name]) == type(true) then - -- Check for boolean - if value == "true" then - self.config[name] = true - elseif value == "false" then - self.config[name] = false - end - else - -- We assume it's a string - self.config[name] = value - end - else - writeConfig = false - end - - if writeConfig then - self:saveConfig() - end - else - scm:log("You can currently configure the following variables:") - for cname, cvalue in pairs(self.config) do - scm:log(cname, tostring(cvalue)) - end - end -end - ----@param name string ----@param localPath string | nil | unknown -function scm:checkRequirements(name, localPath) - scm:log("Checking requirements of " .. (localPath or name) .. "...") - local file - if localPath then - file = fs.open(localPath, "r") - if not file then - file = fs.open('./' .. localPath .. ".lua", "r") - end - elseif fs.exists("./" .. self.config["libraryDirectory"] .. name .. self.config["librarySuffix"] .. "/" .. name .. ".lua") then - file = fs.open("./" .. self.config["libraryDirectory"] - .. name .. self.config["librarySuffix"] - .. "/" .. name .. ".lua", "r") - else - file = fs.open("./" .. self.config["libraryDirectory"] .. name .. ".lua", "r") - end - if not file then scm:log('File ' .. name .. ' not found') end - -- Find requirements by searching for comment --@requires name - local requires = {} - while true do - local line = file.readLine() - if not line then break end - - local find = string.find(line, "--@requires") - if find then - line = string.sub(line, find + 12) - local lineEnd = string.find(line, " ") - - local scriptName = nil - if lineEnd then - scriptName = string.sub(line, 0, lineEnd - 1) - else - scriptName = string.sub(line, 0) - end - - requires[#requires + 1] = scriptName - end - end - file.close() - - -- Install missing requirements - for i = 1, #requires do - local n = requires[i] - local tmpName, tmpCode = self:splitNameCode(n) - if tmpCode then n = tmpName end - - scm:log("Trying to install " .. n .. "...") - - local scriptExists = false - for j = 1, #self.scripts, 1 do - if self.scripts[j].name == n then - scriptExists = true - end - end - - if not scriptExists then - if tmpCode then - self:download(tmpName .. "@" .. tmpCode, "library") - else - self:download(n, "library") - end - else - scm:log(n .. " already exists.") - end - - self:checkRequirements(n) - end -end - ---- used when no script with the name was found online ---- searches locally for the script ----@param name string ----@return any | nil -local function fallbackRequire(name) - scm:log(name .. " not found online, try to find locally") - --- if script does not exist - local possiblePath = { - name, - scm.config["libraryDirectory"] .. name, - scm.config["libraryDirectory"] .. name .. "/" .. name, - scm.config["libraryDirectory"] .. name .. "/" .. "init.lua" - } - local script - local success - ---TryFunction for Require - ---@param path string - ---@return any - local function tryRequire(path) - return require(path) - end - - for _, path in pairs(possiblePath) do - success, script = pcall(tryRequire, path) - if success then - scm:checkRequirements(name, path) - return script - end - end - scm:log("Could not load " .. name) - return nil -end - ----@param name string ----@return any -function scm:load(name) - scm:log("Loading " .. name .. "...") - local scriptExists = false - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == name then - scriptExists = true - end - end - - if not scriptExists then - self:download(name, "library") - end - - scriptExists = false - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == name then - scriptExists = true - end - end - - if scriptExists then - self:checkRequirements(name) - local path = "./" .. self.config["libraryDirectory"] .. name - local script = require(path) - scm:log("Done") - return script - end - - return fallbackRequire(name) -end - -function scm:getNewestVersion() - local githubAPIgetTags = self.config["apiGithubGetTags"] - githubAPIgetTags = githubAPIgetTags:gsub("", self.config["user"]) - githubAPIgetTags = githubAPIgetTags:gsub("", self.config["repository"]) - - local request = http.get(githubAPIgetTags) - - if request then - local content = request.readAll() - request.close() - local scmTags = textutils.unserializeJSON(content) - return true, scmTags[1]["name"] - else - self:log("Request to GitHub API failed.") - return false, "0.0.0" - end -end - -function scm:checkVersion() - if not self.config["updateAvailable"] and self.config["lastVersionCheck"] ~= '' .. os.day("utc") then - local success, newestVersion = scm:getNewestVersion() - if success and newestVersion ~= self.config["currentVersion"] then - self.config["updateAvailable"] = true - end - - self.config["lastVersionCheck"] = os.day("utc") .. '' - self:saveConfig() - end -end - -----here i was -----!!!!!!!!!!!! - -function scm:init() - -- Create directories - if not fs.exists(self.config["configDirectory"]) then - fs.makeDir(self.config["configDirectory"]) - end - if not fs.exists(self.config["libraryDirectory"]) then - fs.makeDir(self.config["libraryDirectory"]) - end - - self:loadConfig() - self:loadScripts() - - self:checkVersion() -end - ----@param resetPosition boolean | nil -function scm:cli(resetPosition, args) - if resetPosition ~= nil and resetPosition == true then - term.setCursorPos(1, 7) - end - - -- enable autocomplete - self:prepareAutocomplete() - updateAutocomplete() - - -- enable newline starting with `scm ` - if self.config["allowCLIPrefix"] then - self.config["cliPrefix"] = true - self:saveConfig() - end - - -- some interface - local _, cursorY = term.getCursorPos() - if cursorY < 7 then cursorY = 7 end - term.setCursorPos(1, cursorY) - term.blit(" ", - "ffffffffffffffffffffffffffffffff", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - term.blit(" SCM - Script Manager ", - "ffffffffffffffffffffffffffffffff", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - term.blit(" Autocomplete enabled. ", - "77777777777777777777777777777777", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - term.blit(" Type `scm help` to learn more. ", - "77777777ffffffff7777777777777777", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - if (self.config["updateAvailable"]) then - term.blit(" Update available! ", - "7eeeeeeeeeeeeeeeee77777777777777", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - end - term.blit(" ", - "ffffffffffffffffffffffffffffffff", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(2) - - if self.config["cliPrefix"] then - shell.run(read(nil, nil, shell.complete, "scm ")) - end -end - ----@param args table -function scm:handleArguments(args) - if #args == 0 then - self:cli(false, args) - return - end - - if args[1] and self.commands[args[1]] then - self.commands[args[1]]["func"](args) - if self.config["cliPrefix"] then - shell.run(read(nil, nil, shell.complete, "scm ")) - end - end -end - -scm:init() -scm:handleArguments({ ... }) -return scm From 5d60eb5a7c55225c13df86b556a505b6a6638cbf Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Sun, 3 Dec 2023 13:44:11 +0100 Subject: [PATCH 39/51] Small Fixes. Testsuit not working Co-authored-by: Josh --- libs/scm/config.lua | 14 +- libs/scm/net.lua | 34 +- libs/scm/scriptManager.lua | 12 +- scm old.lua | 1032 ------------------------------------ 4 files changed, 30 insertions(+), 1062 deletions(-) delete mode 100644 scm old.lua diff --git a/libs/scm/config.lua b/libs/scm/config.lua index ca5eea9..3287ce5 100644 --- a/libs/scm/config.lua +++ b/libs/scm/config.lua @@ -58,27 +58,27 @@ do function Config:saveConfig(config) config = config or self.config - local file = io.open(config["configDirectory"] .. config["configFile"], "w") + local file = fs.open(config["configDirectory"] .. config["configFile"], "w") if not file then os.execute("mkdir " .. config["configDirectory"]) - file = io.open(config["configDirectory"] .. config["configFile"], "w") + file = fs.open(config["configDirectory"] .. config["configFile"], "w") end - file:write(textutils.serializeJSON(config)) - file:close() + file.write(textutils.serializeJSON(config)) + file.close() end --- loads the config from the config file ---@param config SCMConfigData | nil function Config:loadConfig(config) config = config or self.config - local file = io.open(config["configDirectory"] .. config["configFile"], "r") + local file = fs.open(config["configDirectory"] .. config["configFile"], "r") if not file then -- Create config file if it does not exist yet self:saveConfig(config) else -- Load config from file - local temp = textutils.unserializeJSON(file:read("*all")) or {} + local temp = textutils.unserializeJSON(file.readAll()) or {} -- Check if loaded config size is equal to the default size, -- otherwise the config is corrupted and will be overwritten if tablelength(temp) == tablelength(self.config) then @@ -86,7 +86,7 @@ do else self:saveConfig(config) end - file:close() + file.close() end end diff --git a/libs/scm/net.lua b/libs/scm/net.lua index 8a56ee1..8b66cdf 100644 --- a/libs/scm/net.lua +++ b/libs/scm/net.lua @@ -114,8 +114,8 @@ do local file = fs.open(targetDirectory .. sourceObject.name .. config()[sourceObject.type .. "Suffix"] .. "/" .. config()["infoFile"], "w") - file:write(content) - file:close() + file.write(content) + file.close() local filePaths = {} if fs then @@ -123,23 +123,23 @@ do .. config()[sourceObject.type .. "Suffix"] .. "/" .. config()["infoFile"], "r") - local line = file:read() + local line = file.read() while line do filePaths[#filePaths + 1] = line - line = file:read() + line = file.read() end - file:close() + file.close() else file = fs.open(targetDirectory .. sourceObject.name .. config()[sourceObject.type .. "Suffix"] .. "/" .. config()["infoFile"], "r") - -- print(file:read()) - local line = file:read() + -- print(file.read()) + local line = file.read() while line do filePaths[#filePaths + 1] = line - line = file:read() + line = file.read() end - file:close() + file.close() end for i = 1, #filePaths, 1 do local success = true @@ -157,8 +157,8 @@ do .. config()[sourceObject.type .. "Suffix"] .. "/" .. filePaths[i], "w") end - tmpFile:write(tmpContent) - tmpFile:close() + tmpfile.write(tmpContent) + tmpfile.close() else success = false end @@ -232,8 +232,8 @@ do os.execute("mkdir " .. targetDirectory) file = fs.open(targetDirectory .. sourceObject.name, "w") end - file:write(content) - file:close() + file.write(content) + file.close() return sourceObject, true end end @@ -291,13 +291,13 @@ do if not file then self:refreshRepoScripts() else - local repoScripts = textutils.unserializeJSON(file:read("*all")) or nil + local repoScripts = textutils.unserializeJSON(file.readAll()) or nil if repoScripts then SCM.Autocomplete:setProgramms(repoScripts["programs"]) SCM.Autocomplete:setLibaries(repoScripts["libraries"]) end - file:close() + file.close() end end @@ -346,8 +346,8 @@ do file = fs.open(config()["configDirectory"] .. config()["repoScriptsFile"], "w") end if file then - file:write(textutils.serializeJSON(repoScripts)) - file:close() + file.write(""..textutils.serializeJSON(repoScripts)) + file.close() end end diff --git a/libs/scm/scriptManager.lua b/libs/scm/scriptManager.lua index 4781182..3e80a4d 100644 --- a/libs/scm/scriptManager.lua +++ b/libs/scm/scriptManager.lua @@ -21,8 +21,8 @@ do if not file then self:saveScripts() else - self.scripts = textutils.unserializeJSON(file:read("*all") or "") - file:close() + self.scripts = textutils.unserializeJSON(file.readAll() or "") + file.close() if not self.scripts then self.scripts = {} end @@ -36,8 +36,8 @@ do os.execute("mkdir " .. config["configDirectory"]) file = fs.open(config["configDirectory"] .. config["scriptFile"], "w") end - file:write(textutils.serializeJSON(self.scripts)) - file:close() + file.write(""..textutils.serializeJSON(self.scripts)) + file.close() end ---adds a script to the script File @@ -185,7 +185,7 @@ function ScriptManager:checkRequirements(name, localPath) -- Find requirements by searching for comment --@requires name local requires = {} while true do - local line = file:read() + local line = file.read() if not line then break end local find = string.find(line, "--@requires") @@ -203,7 +203,7 @@ function ScriptManager:checkRequirements(name, localPath) requires[#requires + 1] = scriptName end end - file:close() + file.close() -- Install missing requirements for i = 1, #requires do diff --git a/scm old.lua b/scm old.lua deleted file mode 100644 index 2fdddfb..0000000 --- a/scm old.lua +++ /dev/null @@ -1,1032 +0,0 @@ ----Note: scm is not a real class, it should only exist once. ----@class scm -local scm = {} - --- Configuration -scm.config = { - -- Git Settings (In this case on GitHub, not tested with others) - ["user"] = "mc-cc-scripts", - ["repository"] = "script-manager", - ["branch"] = "master", - ["rawURL"] = "https://raw.githubusercontent.com/", - ["programSuffix"] = "-prog", - ["librarySuffix"] = "-lib", - ["infoFile"] = "files.txt", -- provides the structure of a git repo (paths to all files) - ["apiGithubURL"] = "https://api.github.com/orgs/", - ["apiGithubGetRepos"] = "/repos?type=all&per_page=100&page=1", - ["apiGithubGetTags"] = "https://api.github.com/repos///tags", - ["installScript"] = "1kKZ8zTS", - -- Local Settings - ["currentVersion"] = "0.0.0", -- will get the newest version through the github api, no need to update here - ["updateAvailable"] = false, - ["lastVersionCheck"] = "1", - ["programDirectory"] = "progs/", - ["libraryDirectory"] = "libs/", - ["configDirectory"] = "config/", - ["configFile"] = "scm-config.json", - ["scriptFile"] = "scm-scripts.json", -- will be saved in configDirectory as well - ["verbose"] = true, - ["printPrefix"] = "[scm] ", - ["logDate"] = false, - ["writeLogFile"] = false, - ["logFilePath"] = "logs/scm-log.txt", - ["repoScriptsFile"] = "scm-repo-scripts.txt", -- will be saved in configDirectory as well - ["allowCLIPrefix"] = true, - ["cliPrefix"] = false -} ----------------- - - -scm.scripts = {} -scm.commands = { - ["require"] = { - ---@param args table - func = function(args) - scm:download(args[2], "library", nil) - end, - description = [[ -Adds a library with all its dependencies. -If only a name is given, it will try to download from the official GitHub repositories. -$ require -$ require @ - ]] - }, - ["add"] = { - ---@param args table - func = function(args) - scm:download(args[2], "program", nil) - end, - description = [[ -Adds a program with all its dependencies. -If only a name is given, it will try to download from the official GitHub repositories. -$ add -$ add @ - ]] - }, - ["update"] = { - ---@param args table - func = function(args) - if args[2] == "all" then - scm:updateAllScripts() - elseif args[3] then - scm:updateScript(args[2], args[3]) - elseif args[2] then - scm:updateScript(args[2], nil) - else - scm:updateSCM() - end - end, - description = [[ -$ update - Updates this program (SCM) -$ update - Updates the script with the given name -$ update all - Updates all installed programs and libraries -$ update - Updates the script with an specific source - ]] - }, - ["remove"] = { - ---@param args table - func = function(args) - if args[2] == "all" then - scm:removeAllScripts() - else - scm:removeScript(args[2]) - end - end, - description = [[ -$ remove - Removes the given script -$ remove all - Removes all scripts - ]] - }, - ["list"] = { - ---@param _ table - func = function(_) - scm:listScripts() - end, - description = [[ -$ list - Lists all installed scripts - ]] - }, - ["config"] = { - ---@param args table - func = function(args) - if args[3] then - scm:updateConfig(args[2], args[3]) - elseif args[2] then - if scm.config[args[2]] ~= nil then - print(args[2], tostring(scm.config[args[2]])) - end - else - print("You can currently configure the following variables:") - for cname, cvalue in pairs(scm.config) do - textutils.pagedPrint(cname .. "\t" .. tostring(cvalue)) - end - end - end, - description = [[ -$ config - Lists all available configurations -$ config - Shows a specific configuration -$ config - Updates the configuration - ]] - }, - ["refresh"] = { - func = function(args) - scm:refreshAutocomplete() - end, - description = [[ -$ refresh - Downloads the names of all programs and libraries of the official repository. - Refreshes autocomplete. - ]] - }, - ["help"] = { - ---@param args table - func = function(args) - if args[2] then - if scm.commands[args[2]] then - textutils.pagedPrint(args[2] .. "\n" .. scm.commands[args[2]]["description"]) - end - else - for k, v in pairs(scm.commands) do - textutils.pagedPrint("# " .. k .. "\n" .. v.description) - end - end - end, - description = [[ -$ help - Shows all available commands and their description -$ help - Shows the description of the given command - ]] - } -} - -function scm:refreshRepoScripts() - self:log("Downloading program and library names from GitHub...") - local repoScripts = {} - - local programs = {} - local libraries = {} - - local request = http.get(self.config["apiGithubURL"] .. self.config["user"] .. self.config["apiGithubGetRepos"]) - if request then - local response = request.readAll() - request.close() - - local responseTable = textutils.unserializeJSON(response) - - local programSuffix = self.config["programSuffix"] - local librarySuffix = self.config["librarySuffix"] - - for i = 1, #responseTable, 1 do - local scriptName = responseTable[i]["name"] - if string.sub(scriptName, -string.len(programSuffix)) == programSuffix then - programs[ - string.sub(scriptName, 0, string.len(scriptName) - string.len(programSuffix)) - ] = {} - elseif string.sub(scriptName, -string.len(librarySuffix)) == librarySuffix then - libraries[ - string.sub(scriptName, 0, string.len(scriptName) - string.len(librarySuffix)) - ] = {} - end - end - scm:log("Done") - else - scm:log("Download failed") - end - - self.commands["add"]["args"] = programs - self.commands["require"]["args"] = libraries - - repoScripts["libraries"] = libraries - repoScripts["programs"] = programs - - local file = fs.open(self.config["configDirectory"] .. self.config["repoScriptsFile"], "w") - if file then - file.write(textutils.serializeJSON(repoScripts)) - file.close() - end -end - -function scm:loadRepoScripts() - local file = fs.open(self.config["configDirectory"] .. self.config["repoScriptsFile"], "r") - - if not file then - self:refreshRepoScripts() - else - local repoScripts = textutils.unserializeJSON(file.readAll()) or nil - if repoScripts then - self.commands["add"]["args"] = repoScripts["programs"] - self.commands["require"]["args"] = repoScripts["libraries"] - end - - file.close() - end -end - -function scm:prepareAutocomplete() - -- prepare update and remove - scm:loadScripts() - local installedScripts = {} - for i = 1, #self.scripts, 1 do - installedScripts[self.scripts[i].name] = {} - end - installedScripts["all"] = {} - - self.commands["update"]["args"] = installedScripts - self.commands["remove"]["args"] = installedScripts - - -- prepare add and require - self:loadRepoScripts() - - -- prepare config - local availableConfigs = {} - - for k, _ in pairs(self.config) do - availableConfigs[k] = {} - end - - self.commands["config"]["args"] = availableConfigs - - -- prepare help - local availableCommands = {} - - for k, _ in pairs(self.commands) do - availableCommands[k] = {} - end - - self.commands["help"]["args"] = availableCommands -end - ----@param shell table ----@param index integer ----@param argument string ----@param previous table ----@return table | nil -local function completionFunction(shell, index, argument, previous) - local commands = {} - for k, _ in pairs(scm.commands) do - commands[k] = scm.commands[k]["args"] or {} - end - - local currArg = commands - for i = 2, #previous do - if currArg[previous[i]] then - currArg = currArg[previous[i]] - else - return nil - end - end - - local results = {} - for word, _ in pairs(currArg) do - if word:sub(1, #argument) == argument then - results[#results + 1] = word:sub(#argument + 1) - end - end - return results; -end - -local function updateAutocomplete() - shell.setCompletionFunction("scm", completionFunction) -end - -function scm:refreshAutocomplete() - scm:refreshRepoScripts() - scm:prepareAutocomplete() - updateAutocomplete() -end - ----@param message string -function scm:log(message) - local datetime = "" - if self.config["logDate"] then datetime = os.date("[%Y-%m-%d %H:%M:%S] ") end - if self.config["verbose"] then print(self.config["printPrefix"] .. message) end - - if self.config["writeLogFile"] then - local file = fs.open(self.config["logFilePath"], "a") - file.write(datetime .. message .. "\n") - file.close() - end -end - ----@param str string ----@return string | nil ----@return string | nil -function scm:splitNameCode(str) - local separator = string.find(str, "@") - - if separator then - local name = string.sub(str, 1, separator - 1) - local code = string.sub(str, separator + 1) - return name, code - end - - return nil, nil -end - ----@param target string ----@param fileType string ----@param updateObj table | nil ----@return boolean -function scm:download(target, fileType, updateObj) - scm:log("Downloading " .. fileType .. " " .. target .. "...") - if target == nil then - --@TODO: Error handling - return false - end - - local sourceObject = { - name = nil, - source = { - ["default"] = target - }, - type = fileType - } - - if updateObj then sourceObject.name = updateObj.name end - - -- Check for Pastebin - local name, code = self:splitNameCode(target) - if name and code then - sourceObject.name = name - return scm:addScript(self:downloadPastebin(sourceObject, code, self.config[fileType .. "Directory"], updateObj)) - end - - -- We assume it's Git - -- The suffix is used to find the correct repository on GitHub - local suffix - if fileType == "library" then - suffix = self.config["librarySuffix"] - else - suffix = self.config["programSuffix"] - end - local repository = target .. suffix - sourceObject.name = target - - return scm:addScript(self:downloadGit(sourceObject, repository, self.config[fileType .. "Directory"], updateObj)) -end - ----@param sourceObject table ----@param repository string ----@param targetDirectory string ----@param updateObj table | nil ----@return table | nil ----@return boolean -function scm:downloadGit(sourceObject, repository, targetDirectory, updateObj) - local baseUrl = self.config["rawURL"] .. - self.config["user"] .. "/" .. - repository .. "/" .. - self.config["branch"] .. "/" - - local filesUrl = baseUrl .. self.config["infoFile"] - - local request = http.get(filesUrl) - if request then - local content = request.readAll() - request.close() - - if content then - local file = fs.open(targetDirectory .. sourceObject.name - .. self.config[sourceObject.type .. "Suffix"] - .. "/" .. self.config["infoFile"], "w") - file.write(content) - file.close() - - local filePaths = {} - file = fs.open(targetDirectory .. sourceObject.name - .. self.config[sourceObject.type .. "Suffix"] - .. "/" .. self.config["infoFile"], "r") - for line in file.readLine do - filePaths[#filePaths + 1] = line - end - file.close() - - for i = 1, #filePaths, 1 do - local success = true - local tmpRequest = http.get(baseUrl .. filePaths[i]) - if tmpRequest then - local tmpContent = tmpRequest.readAll() - if tmpContent then - local tmpFile = fs.open(targetDirectory .. sourceObject.name - .. self.config[sourceObject.type .. "Suffix"] - .. "/" .. filePaths[i], "w") - tmpFile.write(tmpContent) - tmpFile.close() - else - success = false - end - - tmpRequest.close() - else - success = false - end - - if not success then - return nil, false - end - end - - -- create a link that calls the file within the program directory - if sourceObject.type == "program" then - local progamLink = fs.open(sourceObject.name, "w") - progamLink.write("shell.execute(\"" .. targetDirectory .. sourceObject.name .. - self.config[sourceObject.type .. "Suffix"] - .. "/" .. sourceObject.name .. ".lua" .. "\", ...)") - progamLink.close() - elseif sourceObject.type == "library" then - local libraryLink = fs.open(targetDirectory .. sourceObject.name .. ".lua", "w") - - local tmpName = sourceObject.name - if tmpName:find("%.") then - tmpName = tmpName:match("(.+)%..+$") - end - - libraryLink.write("return require(\"./" .. self.config["libraryDirectory"] - .. tmpName .. self.config[sourceObject.type .. "Suffix"] - .. "/" .. tmpName .. "\")") - libraryLink.close() - end - - return sourceObject, true - end - end - - return nil, false -end - ----@param sourceObject table ----@param code string ----@param targetDirectory string ----@param updateObj table | nil ----@return table | nil ----@return boolean -function scm:downloadPastebin(sourceObject, code, targetDirectory, updateObj) - -- Only download if it does not already exist, or if it should be updated - if fs.exists(targetDirectory .. sourceObject.name) then - if updateObj then - fs.delete(targetDirectory .. sourceObject.name) - sourceObject = updateObj - else - -- File already exists, you should use update - return nil, false - end - end - - if updateObj then - fs.delete(sourceObject.name) - end - - if sourceObject.type == "program" then - shell.run("pastebin", "get", code, sourceObject.name .. ".lua") - else - shell.run("pastebin", "get", code, targetDirectory .. sourceObject.name .. ".lua") - end - - return sourceObject, true -end - ----@param sourceObject table ----@param targetDirectory string ----@param updateObj table | nil ----@return table | nil ----@return boolean -function scm:downloadURL(sourceObject, targetDirectory, updateObj) - local sourceName = "default" or updateObj.sourceName - if updateObj then - sourceObject.name = sourceObject.name or updateObj.name - end - - if not sourceObject.name then - sourceObject.name = self:getNameFromURL(sourceObject.source[sourceName]) - end - - local request = http.get(sourceObject.source[sourceName]) - - if request then - local content = request.readAll() - request.close() - - if content then - local file = fs.open(targetDirectory .. sourceObject.name, "w") - file.write(content) - file.close() - return sourceObject, true - end - end - - return nil, false -end - ----@param url string ----@return string -function scm:getNameFromURL(url) - -- Gets the filename + extension from a url (everything after last /) - local name = url:match("[^/]+$") - - -- Remove file extension if name contains a dot - if name:find("%.") then - name = name:match("(.+)%..+$") - end - - return name -end - ----@param sourceObject table | nil ----@param success boolean ----@return boolean -function scm:addScript(sourceObject, success) - if not success or not sourceObject then return false end - scm:log("Adding script " .. sourceObject.name .. "...") - local scriptExists = false - - -- Check if script already exists, then update - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == sourceObject.name and self.scripts[i].type == sourceObject.type then - scriptExists = true - if self.scripts[i].source[sourceObject.sourceName] then - self.scripts[i].source[sourceObject.sourceName] = sourceObject.source[sourceObject.sourceName] - self:saveScripts() - - return true - end - end - end - - if not scriptExists then - scm:log("Script added: " .. sourceObject.name) - table.insert(self.scripts, sourceObject) - else - scm:log("Script already exists.") - return false - end - - self:saveScripts() - - -- update for autocomplete - self.commands["update"]["args"] = self.commands["update"]["args"] or {} - self.commands["remove"]["args"] = self.commands["remove"]["args"] or {} - self.commands["update"]["args"][sourceObject.name] = {} - self.commands["remove"]["args"][sourceObject.name] = {} - self:prepareAutocomplete() - updateAutocomplete() - - return true -end - -function scm:saveScripts() - local file = fs.open(self.config["configDirectory"] .. self.config["scriptFile"], "w") - file.write(textutils.serializeJSON(self.scripts)) - file.close() -end - -function scm:loadScripts() - local file = fs.open(self.config["configDirectory"] .. self.config["scriptFile"], "r") - - if not file then - self:saveScripts() - else - self.scripts = textutils.unserializeJSON(file.readAll()) or {} - file.close() - end -end - -function scm:listScripts() - print("name", "type") - print("----------------------") - for i = 1, #self.scripts, 1 do - print(self.scripts[i].name, self.scripts[i].type) - end -end - ----@param name string -function scm:removeScript(name, keepScriptConfig) - scm:log("Removing script: " .. name) - local o = {} - local scriptType = nil - - if keepScriptConfig ~= true then - for i = 1, #self.scripts, 1 do - if self.scripts[i].name ~= name then - table.insert(o, self.scripts[i]) - else - scriptType = self.scripts[i].type - end - end - - self.scripts = o - self:saveScripts() - end - - -- delete file - if scriptType and fs.exists(self.config[scriptType .. "Directory"] .. name .. ".lua") then - fs.delete(self.config[scriptType .. "Directory"] .. name .. self.config[scriptType .. "Suffix"]) - if scriptType == "library" then - fs.delete(self.config[scriptType .. "Directory"] .. name .. ".lua") - end - end - - if scriptType == "program" then - fs.delete(name) - end - - -- update autocomplete - self:prepareAutocomplete() - updateAutocomplete() -end - -function scm:removeAllScripts() - local tmpScripts = {} - for i = 1, #self.scripts, 1 do - table.insert(tmpScripts, self.scripts[i].name) - end - - for i = 1, #tmpScripts, 1 do - self:removeScript(tmpScripts[i]) - end -end - ----@param name string ----@param sourceName string ----@return boolean -function scm:updateScript(name, sourceName) - if not sourceName then sourceName = "default" end - - local updateObj = { - ["name"] = name, - ["type"] = nil, - ["sourceName"] = sourceName, - ["source"] = {} - } - - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == name then - updateObj.source[sourceName] = self.scripts[i].source[sourceName] - updateObj.type = self.scripts[i].type - end - end - - if updateObj.source[sourceName] and updateObj.type then - self:removeScript(name, true) - self:download(updateObj.source[sourceName], updateObj.type, updateObj) - return true - end - - return false -end - -function scm:updateAllScripts() - for i = 1, #self.scripts, 1 do - self:updateScript(self.scripts[i].name, "default") - end -end - -function scm:updateSCM() - scm:log("Updating scm...") - shell.run("pastebin", "run", self.config.installScript) - local success, version = self:getNewestVersion() - if success then - self.config["currentVersion"] = version - self.config["updateAvailable"] = false - self.config["lastVersionCheck"] = os.day("utc") - self:saveConfig() - end -end - ----@source: https://stackoverflow.com/a/2705804/10495683 ----@param T table ----@return integer -local function tablelength(T) - local count = 0 - for _ in pairs(T) do count = count + 1 end - return count -end - -function scm:saveConfig() - local file = fs.open(self.config["configDirectory"] .. self.config["configFile"], "w") - file.write(textutils.serializeJSON(self.config)) - file.close() -end - -function scm:loadConfig() - local file = fs.open(self.config["configDirectory"] .. self.config["configFile"], "r") - - if not file then - -- Create config file if it does not exist yet - self:saveConfig() - else - -- Load config from file - local temp = textutils.unserializeJSON(file.readAll()) or {} - -- Check if loaded config size is equal to the default size, - -- otherwise the config is corrupted and will be overwritten - if tablelength(temp) == tablelength(self.config) then - self.config = temp - else - self:saveConfig() - end - file.close() - end -end - ----@param name string ----@param value string -function scm:updateConfig(name, value) - local writeConfig = true - - if name and value then - if self.config[name] ~= nil then - if type(self.config[name]) == type(true) then - -- Check for boolean - if value == "true" then - self.config[name] = true - elseif value == "false" then - self.config[name] = false - end - else - -- We assume it's a string - self.config[name] = value - end - else - writeConfig = false - end - - if writeConfig then - self:saveConfig() - end - else - scm:log("You can currently configure the following variables:") - for cname, cvalue in pairs(self.config) do - scm:log(cname, tostring(cvalue)) - end - end -end - ----@param name string ----@param localPath string | nil | unknown -function scm:checkRequirements(name, localPath) - scm:log("Checking requirements of " .. (localPath or name) .. "...") - local file - if localPath then - file = fs.open(localPath, "r") - if not file then - file = fs.open('./' .. localPath .. ".lua", "r") - end - elseif fs.exists("./" .. self.config["libraryDirectory"] .. name .. self.config["librarySuffix"] .. "/" .. name .. ".lua") then - file = fs.open("./" .. self.config["libraryDirectory"] - .. name .. self.config["librarySuffix"] - .. "/" .. name .. ".lua", "r") - else - file = fs.open("./" .. self.config["libraryDirectory"] .. name .. ".lua", "r") - end - if not file then scm:log('File ' .. name .. ' not found') end - -- Find requirements by searching for comment --@requires name - local requires = {} - while true do - local line = file.readLine() - if not line then break end - - local find = string.find(line, "--@requires") - if find then - line = string.sub(line, find + 12) - local lineEnd = string.find(line, " ") - - local scriptName = nil - if lineEnd then - scriptName = string.sub(line, 0, lineEnd - 1) - else - scriptName = string.sub(line, 0) - end - - requires[#requires + 1] = scriptName - end - end - file.close() - - -- Install missing requirements - for i = 1, #requires do - local n = requires[i] - local tmpName, tmpCode = self:splitNameCode(n) - if tmpCode then n = tmpName end - - scm:log("Trying to install " .. n .. "...") - - local scriptExists = false - for j = 1, #self.scripts, 1 do - if self.scripts[j].name == n then - scriptExists = true - end - end - - if not scriptExists then - if tmpCode then - self:download(tmpName .. "@" .. tmpCode, "library") - else - self:download(n, "library") - end - else - scm:log(n .. " already exists.") - end - - self:checkRequirements(n) - end -end - ---- used when no script with the name was found online ---- searches locally for the script ----@param name string ----@return any | nil -local function fallbackRequire(name) - scm:log(name .. " not found online, try to find locally") - --- if script does not exist - local possiblePath = { - name, - scm.config["libraryDirectory"] .. name, - scm.config["libraryDirectory"] .. name .. "/" .. name, - scm.config["libraryDirectory"] .. name .. "/" .. "init.lua" - } - local script - local success - ---TryFunction for Require - ---@param path string - ---@return any - local function tryRequire(path) - return require(path) - end - - for _, path in pairs(possiblePath) do - success, script = pcall(tryRequire, path) - if success then - scm:checkRequirements(name, path) - return script - end - end - scm:log("Could not load " .. name) - return nil -end - ----@param name string ----@return any -function scm:load(name) - scm:log("Loading " .. name .. "...") - local scriptExists = false - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == name then - scriptExists = true - end - end - - if not scriptExists then - self:download(name, "library") - end - - scriptExists = false - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == name then - scriptExists = true - end - end - - if scriptExists then - self:checkRequirements(name) - local path = "./" .. self.config["libraryDirectory"] .. name - local script = require(path) - scm:log("Done") - return script - end - - return fallbackRequire(name) -end - -function scm:getNewestVersion() - local githubAPIgetTags = self.config["apiGithubGetTags"] - githubAPIgetTags = githubAPIgetTags:gsub("", self.config["user"]) - githubAPIgetTags = githubAPIgetTags:gsub("", self.config["repository"]) - - local request = http.get(githubAPIgetTags) - - if request then - local content = request.readAll() - request.close() - local scmTags = textutils.unserializeJSON(content) - return true, scmTags[1]["name"] - else - self:log("Request to GitHub API failed.") - return false, "0.0.0" - end -end - -function scm:checkVersion() - if not self.config["updateAvailable"] and self.config["lastVersionCheck"] ~= '' .. os.day("utc") then - local success, newestVersion = scm:getNewestVersion() - if success and newestVersion ~= self.config["currentVersion"] then - self.config["updateAvailable"] = true - end - - self.config["lastVersionCheck"] = os.day("utc") .. '' - self:saveConfig() - end -end - -----here i was -----!!!!!!!!!!!! - -function scm:init() - -- Create directories - if not fs.exists(self.config["configDirectory"]) then - fs.makeDir(self.config["configDirectory"]) - end - if not fs.exists(self.config["libraryDirectory"]) then - fs.makeDir(self.config["libraryDirectory"]) - end - - self:loadConfig() - self:loadScripts() - - self:checkVersion() -end - ----@param resetPosition boolean | nil -function scm:cli(resetPosition, args) - if resetPosition ~= nil and resetPosition == true then - term.setCursorPos(1, 7) - end - - -- enable autocomplete - self:prepareAutocomplete() - updateAutocomplete() - - -- enable newline starting with `scm ` - if self.config["allowCLIPrefix"] then - self.config["cliPrefix"] = true - self:saveConfig() - end - - -- some interface - local _, cursorY = term.getCursorPos() - if cursorY < 7 then cursorY = 7 end - term.setCursorPos(1, cursorY) - term.blit(" ", - "ffffffffffffffffffffffffffffffff", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - term.blit(" SCM - Script Manager ", - "ffffffffffffffffffffffffffffffff", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - term.blit(" Autocomplete enabled. ", - "77777777777777777777777777777777", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - term.blit(" Type `scm help` to learn more. ", - "77777777ffffffff7777777777777777", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - if (self.config["updateAvailable"]) then - term.blit(" Update available! ", - "7eeeeeeeeeeeeeeeee77777777777777", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(1) - end - term.blit(" ", - "ffffffffffffffffffffffffffffffff", - "44444444444444444444444444444444") - term.setCursorPos(1, cursorY) - term.scroll(2) - - if self.config["cliPrefix"] then - shell.run(read(nil, nil, shell.complete, "scm ")) - end -end - ----@param args table -function scm:handleArguments(args) - if #args == 0 then - self:cli(false, args) - return - end - - if args[1] and self.commands[args[1]] then - self.commands[args[1]]["func"](args) - if self.config["cliPrefix"] then - shell.run(read(nil, nil, shell.complete, "scm ")) - end - end -end - -scm:init() -scm:handleArguments({ ... }) -return scm From 1388dffb19572dd5d2514ff608b9ca102abb1c34 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Sun, 3 Dec 2023 14:25:26 +0100 Subject: [PATCH 40/51] Fixed autocomplete Co-authored-by: Josh --- libs/scm/autocomplete.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/scm/autocomplete.lua b/libs/scm/autocomplete.lua index 91273bf..909f1a1 100644 --- a/libs/scm/autocomplete.lua +++ b/libs/scm/autocomplete.lua @@ -258,7 +258,7 @@ $ help end function Autocomplete:updateAutocomplete() - shell.setCompletionFunction("SCM", completionFunction) + shell.setCompletionFunction("scm.lua", completionFunction) end function Autocomplete:refreshAutocomplete() From cb3cd8b506d9b13125c4bd38f35c1863645ad016 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Sun, 3 Dec 2023 15:15:51 +0100 Subject: [PATCH 41/51] resolves Issue-33 Co-authored-by: Josh --- libs/scm/net.lua | 12 ++++++------ libs/scm/scriptManager.lua | 10 +++++++--- scm.lua | 12 ++++++------ 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/libs/scm/net.lua b/libs/scm/net.lua index 8b66cdf..cd75326 100644 --- a/libs/scm/net.lua +++ b/libs/scm/net.lua @@ -157,8 +157,8 @@ do .. config()[sourceObject.type .. "Suffix"] .. "/" .. filePaths[i], "w") end - tmpfile.write(tmpContent) - tmpfile.close() + tmpFile.write(tmpContent) + tmpFile.close() else success = false end @@ -176,10 +176,10 @@ do -- create a link that calls the file within the program directory if sourceObject.type == "program" then local progamLink = fs.open(sourceObject.name, "w") - progamLink:write("shell.execute(\"" .. targetDirectory .. sourceObject.name .. + progamLink.write("shell.execute(\"" .. targetDirectory .. sourceObject.name .. config()[sourceObject.type .. "Suffix"] .. "/" .. sourceObject.name .. ".lua" .. "\", ...)") - progamLink:close() + progamLink.close() elseif sourceObject.type == "library" then local libraryLink = fs.open(targetDirectory .. sourceObject.name .. ".lua", "w") if not libraryLink then @@ -192,10 +192,10 @@ do tmpName = tmpName:match("(.+)%..+$") end - libraryLink:write("return require(\"./" .. config()["libraryDirectory"] + libraryLink.write("return require(\"./" .. config()["libraryDirectory"] .. tmpName .. config()[sourceObject.type .. "Suffix"] .. "/" .. tmpName .. "\")") - libraryLink:close() + libraryLink.close() end return sourceObject, true diff --git a/libs/scm/scriptManager.lua b/libs/scm/scriptManager.lua index 3e80a4d..0d9593c 100644 --- a/libs/scm/scriptManager.lua +++ b/libs/scm/scriptManager.lua @@ -136,10 +136,14 @@ do end -- delete file - if scriptType and fs.exists(config()[scriptType .. "Directory"] .. name .. ".lua") then - fs.delete(config()[scriptType .. "Directory"] .. name .. config()[scriptType .. "Suffix"]) + local scriptDir = config()[scriptType .. "Directory"] + if scriptType and ( + fs.exists(scriptDir .. name .. ".lua") or + fs.exists(scriptDir .. name .. config()[scriptType .. "Suffix"]) + ) then + fs.delete(scriptDir .. name .. config()[scriptType .. "Suffix"]) if scriptType == "library" then - fs.delete(config()[scriptType .. "Directory"] .. name .. ".lua") + fs.delete(scriptDir .. name .. ".lua") end end diff --git a/scm.lua b/scm.lua index 9035f6b..2ceaf03 100644 --- a/scm.lua +++ b/scm.lua @@ -1,11 +1,11 @@ ---@class SCM SCM = {} -require('libs.scm.config') -require('libs.scm.net') -require('libs.scm.log') -require('libs.scm.scriptManager') -require('libs.scm.autocomplete') -require('libs.scm.ui') +require('./libs.scm.config') +require('./libs.scm.net') +require('./libs.scm.log') +require('./libs.scm.scriptManager') +require('./libs.scm.autocomplete') +require('./libs.scm.ui') function SCM:checkVersion() if not self.Config.config["updateAvailable"] and self.Config.config["lastVersionCheck"] ~= '' .. os.day("utc") then From adec0a67311a243c3ed8cdba1071e0176688e160 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Sun, 3 Dec 2023 22:49:36 +0100 Subject: [PATCH 42/51] Fixed Testing - FileSystem Removed SCMInstaller Co-authored-by: Josh --- scmInstaller.lua | 24 ------------------------ tests/Suite/fs.lua | 43 ++++++++++++++++++++++++++++++++++++++++--- tests/test_spec.lua | 24 +++++++++++++++--------- 3 files changed, 55 insertions(+), 36 deletions(-) delete mode 100644 scmInstaller.lua diff --git a/scmInstaller.lua b/scmInstaller.lua deleted file mode 100644 index cccfbca..0000000 --- a/scmInstaller.lua +++ /dev/null @@ -1,24 +0,0 @@ --- Updates / Installs the Script Manager (scm) from GitHub --- Run `pastebin run xxxxxx` --- SCM: https://github.com/mc-cc-scripts/script-manager - -local files = { - 'libs/scm/autocomplete.lua', - 'libs/scm/config.lua', - 'libs/scm/net.lua', - 'libs/scm/scriptManager.lua', - 'libs/scm/ui.lua', - 'libs/scm.lua', - 'scm.lua', -} -local branch = 'master' - -local function installFiles() - for _, script in ipairs(files) do - http.get('https://raw.githubusercontent.com/mc-cc-scripts/script-manager/'.. branch ..'/' .. script, nil, function(_, data) - local file = fs.open(script, 'w') - file.write(data) - file.close() - end) - end -end \ No newline at end of file diff --git a/tests/Suite/fs.lua b/tests/Suite/fs.lua index 3eb4e6c..f6745d0 100644 --- a/tests/Suite/fs.lua +++ b/tests/Suite/fs.lua @@ -1,4 +1,5 @@ local fs = {} + fs.libPath = "tmpLibs/" fs.progPath = "tmpProg/" @@ -28,7 +29,28 @@ do if mode == "w" then assert(file, "file could not be opened in : "..path.. " Mode : "..mode) end - return file + if not file then + return nil + end + local file2 = {} + setmetatable(file2, {__index = file}) + file2.base = file + file2.readAll = function() + return file2.base:read("*a") + end + file2["readLine"] = function() + return file2.base:read("*l") + end + file2["write"] = function(content) + return file2.base:write(content) + end + file2["read"] = function(...) + return file2.base:read(...) + end + file2["close"] = function() + file2.base:close() + end + return file2 end fs.exists = function(path) @@ -100,9 +122,24 @@ do os.execute("mkdir " .. dir) end end + end + end + fs.delete = function (path) + assert("string" == type(path), "path must be a string") + if fs.exists(path) then + os.execute("rm -rf " .. path) end end + fs.readAll = function (path) + assert("string" == type(path), "path must be a string") + local file = io.open(path, "r") + if not file then + return nil + end + local content = file:read("*a") + file:close() + return content + end end - -return fs +return fs \ No newline at end of file diff --git a/tests/test_spec.lua b/tests/test_spec.lua index 79d9acc..f7e9c8c 100644 --- a/tests/test_spec.lua +++ b/tests/test_spec.lua @@ -69,6 +69,7 @@ end ---@param ... any local function runTests(func, ...) ---@class SCM + local scm = require("../scm") saveConfig(scm) saveScripts(scm) @@ -87,8 +88,9 @@ end describe("Testing everything about SCM:", function() - + --only neccessary for local testing describe("Copy Files", function() + assert.is_true(fs.copy("./scm.lua", "tmpFiles/scm.lua"), "Could not copy scm.lua") assert.is_true(fs.copy("./libs/scm/config.lua", "tmpFiles/config.lua"), "Could not copy config.lua") assert.is_true(fs.copy("./libs/scm/net.lua", "tmpFiles/net.lua"), "Could not copy net.lua") @@ -96,7 +98,6 @@ describe("Testing everything about SCM:", function() assert.is_true(fs.copy("./libs/scm/scriptManager.lua", "tmpFiles/scriptManager.lua"), "Could not copy scriptManager.lua") assert.is_true(fs.copy("./libs/scm/autocomplete.lua", "tmpFiles/autocomplete.lua"), "Could not copy autocomplete.lua") assert.is_true(fs.copy("./libs/scm/ui.lua", "tmpFiles/ui.lua"), "Could not copy ui.lua") - assert.is_true(fs.copy("./scmInstaller.lua", "tmpFiles/scmInstaller.lua"), "Could not copy scmInstaller.lua") end) describe("Require all SCM Modules", function() @@ -109,7 +110,6 @@ describe("Testing everything about SCM:", function() assert.is.truthy(scm.UI) assert.is.truthy(scm.ScriptManager) assert.is.truthy(scm.Log) - -- print("Require of all modules test passed") end) end) @@ -129,7 +129,6 @@ describe("Testing everything about SCM:", function() assert.equal("Wrong", config:getAll()["verbose"]) config:set("verbose", true) assert.is.truthy(config:getAll()["verbose"] == true) - -- print("Config test passed") end) end) end) @@ -144,8 +143,6 @@ describe("Testing everything about SCM:", function() local scripts = scriptManager.scripts assert.is.truthy(scripts) assert.is.truthy(type(scripts) == "table") - - -- print("1. ScriptManager test passed (Load Empty)") end ) end) @@ -163,7 +160,6 @@ describe("Testing everything about SCM:", function() assert.is.truthy(tFile) assert.is.truthy(tFile.test) os.remove("localtestFile.lua") - -- print("2. ScriptManager test passed (Load Local)") end ) end) @@ -176,13 +172,24 @@ describe("Testing everything about SCM:", function() local scriptManager = scm.ScriptManager assert.is.truthy(testScript) assert.is.truthy(testScript.test) - -- print("3. ScriptManager test passed (Load Remote)") end ) end) end) + describe("Update SCM", function() + it("Update SCM", function() + runTests( + ---@param scm SCM + function(scm) + -- TODO: implement + end + ) + end) + end) + end) + -- only neccessary for local testing describe("Restore Files", function() assert.is_true(fs.copy("tmpFiles/scm.lua", "./scm.lua"), "Could not restore scm.lua") assert.is_true(fs.copy("tmpFiles/config.lua", "./libs/scm/config.lua"), "Could not restore config.lua") @@ -191,7 +198,6 @@ describe("Testing everything about SCM:", function() assert.is_true(fs.copy("tmpFiles/scriptManager.lua", "./libs/scm/scriptManager.lua"), "Could not restore scriptManager.lua") assert.is_true(fs.copy("tmpFiles/autocomplete.lua", "./libs/scm/autocomplete.lua"), "Could not restore autocomplete.lua") assert.is_true(fs.copy("tmpFiles/ui.lua", "./libs/scm/ui.lua"), "Could not restore ui.lua") - assert.is_true(fs.copy("tmpFiles/scmInstaller.lua", "./scmInstaller.lua"), "Could not restore scmInstaller.lua") os.execute("rm --recursive ./tmpFiles") end) end) \ No newline at end of file From d0fc8e65a1b133662ab68d133cf8fcb44619c516 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Mon, 4 Dec 2023 21:42:16 +0100 Subject: [PATCH 43/51] HotFixes Co-authored-by: Josh --- libs/scm/net.lua | 57 +++----- libs/scm/scriptManager.lua | 281 ++++++++++++++++++------------------- libs/scm/ui.lua | 4 +- 3 files changed, 162 insertions(+), 180 deletions(-) diff --git a/libs/scm/net.lua b/libs/scm/net.lua index cd75326..19bc869 100644 --- a/libs/scm/net.lua +++ b/libs/scm/net.lua @@ -6,7 +6,7 @@ do local config = function() return SCM.Config:getAll() end - local log= function(...) SCM.Log:log(...) end + local log = function(...) SCM.Log:log(...) end ---@param target string ---@param fileType string @@ -18,22 +18,22 @@ do --@TODO: Error handling return false end - local sourceObject = { name = nil, source = { - ["default"] = target + ["default"] = target, }, + sourceName = "default", type = fileType } - if updateObj then sourceObject.name = updateObj.name end -- Check for Pastebin local name, code = SCM.ScriptManager:splitNameCode(target) if name and code then sourceObject.name = name - return SCM.ScriptManager:addScript(self:downloadPastebin(sourceObject, code, config()[fileType .. "Directory"], + return SCM.ScriptManager:addScript(self:downloadPastebin(sourceObject, code, + config()[fileType .. "Directory"], updateObj)) end @@ -47,6 +47,7 @@ do end local repository = target .. suffix sourceObject.name = target + return SCM.ScriptManager:addScript(self:downloadGit(sourceObject, repository, config()[fileType .. "Directory"], updateObj)) end @@ -118,29 +119,15 @@ do file.close() local filePaths = {} - if fs then - file = fs.open(targetDirectory .. sourceObject.name - .. config()[sourceObject.type .. "Suffix"] - .. "/" .. config()["infoFile"], "r") - - local line = file.read() - while line do - filePaths[#filePaths + 1] = line - line = file.read() - end - file.close() - else - file = fs.open(targetDirectory .. sourceObject.name - .. config()[sourceObject.type .. "Suffix"] - .. "/" .. config()["infoFile"], "r") - -- print(file.read()) - local line = file.read() - while line do - filePaths[#filePaths + 1] = line - line = file.read() - end - file.close() + file = fs.open(targetDirectory .. sourceObject.name + .. config()[sourceObject.type .. "Suffix"] + .. "/" .. config()["infoFile"], "r") + local line = file.readLine() + while line do + filePaths[#filePaths + 1] = line + line = file.readLine() end + file.close() for i = 1, #filePaths, 1 do local success = true local tmpRequest = http.get(baseUrl .. filePaths[i]) @@ -175,7 +162,7 @@ do -- create a link that calls the file within the program directory if sourceObject.type == "program" then - local progamLink = fs.open(sourceObject.name, "w") + local progamLink = fs.open(sourceObject.name .. ".lua", "w") progamLink.write("shell.execute(\"" .. targetDirectory .. sourceObject.name .. config()[sourceObject.type .. "Suffix"] .. "/" .. sourceObject.name .. ".lua" .. "\", ...)") @@ -219,7 +206,6 @@ do if not sourceObject.name then sourceObject.name = self:getNameFromURL(sourceObject.source[sourceName]) end - local request = http.get(sourceObject.source[sourceName]) if request then @@ -234,6 +220,7 @@ do end file.write(content) file.close() + return sourceObject, true end end @@ -344,20 +331,20 @@ do if not file then os.execute("mkdir " .. config()["configDirectory"]) file = fs.open(config()["configDirectory"] .. config()["repoScriptsFile"], "w") - end + end if file then - file.write(""..textutils.serializeJSON(repoScripts)) + file.write("" .. textutils.serializeJSON(repoScripts)) file.close() end end - function Net:getNewestVersion () + function Net:getNewestVersion() local githubAPIgetTags = config()["apiGithubGetTags"] githubAPIgetTags = githubAPIgetTags:gsub("", config()["user"]) githubAPIgetTags = githubAPIgetTags:gsub("", config()["repository"]) - + local request = http.get(githubAPIgetTags) - + if request then local content = request.readAll() request.close() @@ -370,4 +357,4 @@ do end end -return Net \ No newline at end of file +return Net diff --git a/libs/scm/scriptManager.lua b/libs/scm/scriptManager.lua index 0d9593c..e9a9c41 100644 --- a/libs/scm/scriptManager.lua +++ b/libs/scm/scriptManager.lua @@ -5,9 +5,10 @@ ---@field source table ---@class SCMScriptManager -local ScriptManager = { +local ScriptManager = { ---@type SCMScript[] - scripts = {} } + scripts = {} +} SCM.ScriptManager = ScriptManager do local config = function() @@ -36,7 +37,7 @@ do os.execute("mkdir " .. config["configDirectory"]) file = fs.open(config["configDirectory"] .. config["scriptFile"], "w") end - file.write(""..textutils.serializeJSON(self.scripts)) + file.write("" .. textutils.serializeJSON(self.scripts)) file.close() end @@ -60,7 +61,6 @@ do end end end - if not scriptExists then log("Script added: " .. script.name) table.insert(self.scripts, script) @@ -122,40 +122,37 @@ do local o = {} local scriptType = nil - if keepScriptConfig ~= true then - for i = 1, #self.scripts, 1 do - if self.scripts[i].name ~= name then - table.insert(o, self.scripts[i]) - else - scriptType = self.scripts[i].type - end + for i = 1, #self.scripts, 1 do + if self.scripts[i].name ~= name and keepScriptConfig ~= true then + table.insert(o, self.scripts[i]) + else + scriptType = self.scripts[i].type end - + end + if keepScriptConfig ~= true then self.scripts = o self:saveScripts() end - -- delete file local scriptDir = config()[scriptType .. "Directory"] if scriptType and ( - fs.exists(scriptDir .. name .. ".lua") or - fs.exists(scriptDir .. name .. config()[scriptType .. "Suffix"]) - ) then + fs.exists(scriptDir .. name .. ".lua") or + fs.exists(scriptDir .. name .. config()[scriptType .. "Suffix"]) + ) then fs.delete(scriptDir .. name .. config()[scriptType .. "Suffix"]) if scriptType == "library" then fs.delete(scriptDir .. name .. ".lua") end end - if scriptType == "program" then - fs.delete(name) + fs.delete(name .. ".lua") end -- update autocomplete SCM.Autocomplete:prepareAutocomplete() SCM.Autocomplete:updateAutocomplete() end - + --- removes all scripts function ScriptManager:removeAllScripts() local tmpScripts = {} @@ -168,157 +165,155 @@ do end end ----@param name string ----@param localPath string | nil | unknown -function ScriptManager:checkRequirements(name, localPath) - log("Checking requirements of " .. (localPath or name) .. "...") - local file - if localPath then - file = fs.open(localPath, "r") - if not file then - file = fs.open('./' .. localPath .. ".lua", "r") - end - elseif fs.open("./" .. config()["libraryDirectory"] .. name .. config()["librarySuffix"] .. "/" .. name .. ".lua", "r") then - file = fs.open("./" .. config()["libraryDirectory"] - .. name .. config()["librarySuffix"] - .. "/" .. name .. ".lua", "r") - else - file = fs.open("./" .. config()["libraryDirectory"] .. name .. ".lua", "r") - end - if not file then log('File ' .. name .. ' not found') end - -- Find requirements by searching for comment --@requires name - local requires = {} - while true do - local line = file.read() - if not line then break end - - local find = string.find(line, "--@requires") - if find then - line = string.sub(line, find + 12) - local lineEnd = string.find(line, " ") - - local scriptName = nil - if lineEnd then - scriptName = string.sub(line, 0, lineEnd - 1) - else - scriptName = string.sub(line, 0) + ---@param name string + ---@param localPath string | nil | unknown + function ScriptManager:checkRequirements(name, localPath) + log("Checking requirements of " .. (localPath or name) .. "...") + local file + if localPath then + file = fs.open(localPath, "r") + if not file then + file = fs.open('./' .. localPath .. ".lua", "r") end + elseif fs.open("./" .. config()["libraryDirectory"] .. name .. config()["librarySuffix"] .. "/" .. name .. ".lua", "r") then + file = fs.open("./" .. config()["libraryDirectory"] + .. name .. config()["librarySuffix"] + .. "/" .. name .. ".lua", "r") + else + file = fs.open("./" .. config()["libraryDirectory"] .. name .. ".lua", "r") + end + if not file then log('File ' .. name .. ' not found') end + -- Find requirements by searching for comment --@requires name + local requires = {} + while true do + local line = file.read() + if not line then break end + + local find = string.find(line, "--@requires") + if find then + line = string.sub(line, find + 12) + local lineEnd = string.find(line, " ") + + local scriptName = nil + if lineEnd then + scriptName = string.sub(line, 0, lineEnd - 1) + else + scriptName = string.sub(line, 0) + end - requires[#requires + 1] = scriptName + requires[#requires + 1] = scriptName + end end - end - file.close() + file.close() - -- Install missing requirements - for i = 1, #requires do - local n = requires[i] --[[@as string]] - local tmpName, tmpCode = self:splitNameCode(n) - if tmpCode then n = tmpName--[[@as string]] end + -- Install missing requirements + for i = 1, #requires do + local n = requires[i] --[[@as string]] + local tmpName, tmpCode = self:splitNameCode(n) + if tmpCode then n = tmpName --[[@as string]] end - log("Trying to install " .. n .. "...") + log("Trying to install " .. n .. "...") - local scriptExists = false - for j = 1, #self.scripts, 1 do - if self.scripts[j].name == n then - scriptExists = true + local scriptExists = false + for j = 1, #self.scripts, 1 do + if self.scripts[j].name == n then + scriptExists = true + end end - end - if not scriptExists then - if tmpCode then - SCM.Net:download(tmpName .. "@" .. tmpCode, "library") + if not scriptExists then + if tmpCode then + SCM.Net:download(tmpName .. "@" .. tmpCode, "library") + else + SCM.Net:download(n, "library") + end else - SCM.Net:download(n, "library") + log(n .. " already exists.") end - else - log(n .. " already exists.") - end - self:checkRequirements(n --[[@as string]]) + self:checkRequirements(n --[[@as string]]) + end end -end ---- used when no script with the name was found online ---- searches locally for the script ----@param name string ----@return any | nil -local function fallbackRequire(name) - - log(name .. " not found online, try to find locally") - --- if script does not exist - local possiblePath = { - name, - config()["libraryDirectory"] .. name, - config()["libraryDirectory"] .. name .. "/" .. name, - config()["libraryDirectory"] .. name .. "/" .. "init.lua" - } - local script - local success - ---TryFunction for Require - ---@param path string - ---@return any - local function tryRequire(path) - return require(path) - end + --- used when no script with the name was found online + --- searches locally for the script + ---@param name string + ---@return any | nil + local function fallbackRequire(name) + log(name .. " not found online, try to find locally") + --- if script does not exist + local possiblePath = { + name, + config()["libraryDirectory"] .. name, + config()["libraryDirectory"] .. name .. "/" .. name, + config()["libraryDirectory"] .. name .. "/" .. "init.lua" + } + local script + local success + ---TryFunction for Require + ---@param path string + ---@return any + local function tryRequire(path) + return require(path) + end - for _, path in pairs(possiblePath) do - success, script = pcall(tryRequire, path) - if success then - ScriptManager:checkRequirements(name, path) - return script + for _, path in pairs(possiblePath) do + success, script = pcall(tryRequire, path) + if success then + ScriptManager:checkRequirements(name, path) + return script + end end + log("Could not load " .. name) + return nil end - log("Could not load " .. name) - return nil -end ---@param name string ----@return any -function ScriptManager:load(name) - log("Loading " .. name .. "...") - local scriptExists = false - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == name then - scriptExists = true + ---@return any + function ScriptManager:load(name) + log("Loading " .. name .. "...") + local scriptExists = false + for i = 1, #self.scripts, 1 do + if self.scripts[i].name == name then + scriptExists = true + end + end + if not scriptExists then + SCM.Net:download(name, "library") end - end - if not scriptExists then - SCM.Net:download(name, "library") - end - scriptExists = false - for i = 1, #self.scripts, 1 do - if self.scripts[i].name == name then - scriptExists = true + scriptExists = false + for i = 1, #self.scripts, 1 do + if self.scripts[i].name == name then + scriptExists = true + end end - end - if scriptExists then - self:checkRequirements(name) - local path = "./" .. config()["libraryDirectory"] .. name - local script = require(path) - log("Done") - return script + if scriptExists then + self:checkRequirements(name) + local path = "./" .. config()["libraryDirectory"] .. name + local script = require(path) + log("Done") + return script + end + + return fallbackRequire(name) end - return fallbackRequire(name) -end + ---@param str string + ---@return string | nil + ---@return string | nil + function ScriptManager:splitNameCode(str) + local separator = string.find(str, "@") ----@param str string ----@return string | nil ----@return string | nil -function ScriptManager:splitNameCode(str) - local separator = string.find(str, "@") + if separator then + local name = string.sub(str, 1, separator - 1) + local code = string.sub(str, separator + 1) + return name, code + end - if separator then - local name = string.sub(str, 1, separator - 1) - local code = string.sub(str, separator + 1) - return name, code + return nil, nil end - - return nil, nil -end - end return ScriptManager diff --git a/libs/scm/ui.lua b/libs/scm/ui.lua index 3ea3fd4..a5cd3f9 100644 --- a/libs/scm/ui.lua +++ b/libs/scm/ui.lua @@ -2,7 +2,6 @@ local UI = {} SCM.UI = UI do - local scripts = SCM.ScriptManager.scripts --Redundant function UI:printUsage() print("Usage: scm [args]") @@ -15,6 +14,7 @@ do end function UI:listScripts() + local scripts = SCM.ScriptManager.scripts print("name", "type") print("----------------------") for i = 1, #scripts, 1 do @@ -75,4 +75,4 @@ do end end -return UI \ No newline at end of file +return UI From b55f59759bf15d1e89f99f461c90a2ef8745da51 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Mon, 4 Dec 2023 21:55:06 +0100 Subject: [PATCH 44/51] Log function fixed Removed redundant logs Co-authored-by: Josh --- libs/scm/autocomplete.lua | 7 ++----- libs/scm/log.lua | 10 +++------- libs/scm/net.lua | 1 - libs/scm/scriptManager.lua | 1 - 4 files changed, 5 insertions(+), 14 deletions(-) diff --git a/libs/scm/autocomplete.lua b/libs/scm/autocomplete.lua index 909f1a1..abb4e8b 100644 --- a/libs/scm/autocomplete.lua +++ b/libs/scm/autocomplete.lua @@ -1,4 +1,3 @@ - ---@class Autocomplete local Autocomplete = {} SCM.Autocomplete = Autocomplete @@ -209,7 +208,6 @@ $ help ] = {} end end - log("Done") else log("Download failed") end @@ -272,18 +270,17 @@ $ help self.commands["add"]["args"] = t end - ---@param t table function Autocomplete:setLibaries(t) self.commands["require"]["args"] = t end - function Autocomplete:handleArguments (args) + function Autocomplete:handleArguments(args) if #args == 0 then SCM.UI:cli(false, args) return end - + if args[1] and self.commands[args[1]] then self.commands[args[1]]["func"](args) if SCM.Config.config["cliPrefix"] then diff --git a/libs/scm/log.lua b/libs/scm/log.lua index 9485b18..fd79588 100644 --- a/libs/scm/log.lua +++ b/libs/scm/log.lua @@ -2,16 +2,12 @@ local Log = {} SCM.Log = Log do - local config = {} - function Log:init(lib) - config = lib["config"].config - end - function Log:log(message) + local config = SCM.Config.config local datetime = "" if config["logDate"] then datetime = "" .. os.date("[%Y-%m-%d %H:%M:%S] ") end if config["verbose"] then print(config["printPrefix"] .. message) end - + if config["writeLogFile"] then local file = fs.open(config["logFilePath"], "a") file.write(datetime .. message .. "\n") @@ -21,4 +17,4 @@ do end -return Log \ No newline at end of file +return Log diff --git a/libs/scm/net.lua b/libs/scm/net.lua index 19bc869..eadb724 100644 --- a/libs/scm/net.lua +++ b/libs/scm/net.lua @@ -316,7 +316,6 @@ do ] = {} end end - log("Done") else log("Download failed") end diff --git a/libs/scm/scriptManager.lua b/libs/scm/scriptManager.lua index e9a9c41..68331c4 100644 --- a/libs/scm/scriptManager.lua +++ b/libs/scm/scriptManager.lua @@ -293,7 +293,6 @@ do self:checkRequirements(name) local path = "./" .. config()["libraryDirectory"] .. name local script = require(path) - log("Done") return script end From 73519b45cf06520f375e437fddd0bed9c65be856 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Thu, 7 Dec 2023 19:31:33 +0100 Subject: [PATCH 45/51] Added Files txt and Installer WIP Co-authored-by: Josh --- files.txt | 7 +++++++ scmInstaller.lua | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 files.txt create mode 100644 scmInstaller.lua diff --git a/files.txt b/files.txt new file mode 100644 index 0000000..f6d8c01 --- /dev/null +++ b/files.txt @@ -0,0 +1,7 @@ +scm.lua +/libs/scm/autocomplete.lua +/libs/scm/config.lua +/libs/scm/log.lua +/libs/scm/net.lua +/libs/scm/scriptManager.lua +/libs/scm/ui.lua \ No newline at end of file diff --git a/scmInstaller.lua b/scmInstaller.lua new file mode 100644 index 0000000..279175e --- /dev/null +++ b/scmInstaller.lua @@ -0,0 +1,43 @@ +--installs the scm files into the game +---@class SCMInstaller +local SCMInstaller = {} + + +local files = {} +local source = "raw.githubusercontent.com/mc-cc-scripts/script-manager/Issue-30-Spilt-SCM/" + + +function SCMInstaller:getFilesTxt() + http.get(source .. "files.txt", nil, function(response) + local file = response.readLine() + while file ~= nil do + table.insert(files, file) + file = response.readLine() + end + response.close() + end) +end + +function SCMInstaller:delteFiles() + for _, value in ipairs(files) do + print("Deleting File " .. value) + if fs.exists(value) then + fs.delete(value) + end + end +end + +-- download the files +function SCMInstaller:downloadFiles() + for index, value in ipairs(files) do + http.get(source .. value, nil, function(response) + print('Downloading ' .. index .. ' of ' .. #files .. ' files: ' .. value) + local file = fs.open(value, "w") + file.write(response.readAll()) + file.close() + response.close() + end) + end +end + +return SCMInstaller From 04ec0d6fab509b170565ee1b8da5d91bec066f01 Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Thu, 7 Dec 2023 19:40:34 +0100 Subject: [PATCH 46/51] Updated Installer --- scmInstaller.lua | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/scmInstaller.lua b/scmInstaller.lua index 279175e..c40239a 100644 --- a/scmInstaller.lua +++ b/scmInstaller.lua @@ -2,23 +2,23 @@ ---@class SCMInstaller local SCMInstaller = {} - -local files = {} -local source = "raw.githubusercontent.com/mc-cc-scripts/script-manager/Issue-30-Spilt-SCM/" - - -function SCMInstaller:getFilesTxt() - http.get(source .. "files.txt", nil, function(response) - local file = response.readLine() - while file ~= nil do - table.insert(files, file) - file = response.readLine() - end - response.close() - end) +function SCMInstaller:getFilesTxt(source) + local files = {} + print("Downloading from " .. source .. "files.txt") + local response = http.get(source .. "files.txt") + if response == nil or response.getResponseCode() ~= 200 then + error("Failed to download files.txt") + end + local file = response.readLine() + while file ~= nil do + table.insert(files, file) + file = response.readLine() + end + response.close() + return files end -function SCMInstaller:delteFiles() +function SCMInstaller:deleteFiles(files) for _, value in ipairs(files) do print("Deleting File " .. value) if fs.exists(value) then @@ -28,15 +28,17 @@ function SCMInstaller:delteFiles() end -- download the files -function SCMInstaller:downloadFiles() +function SCMInstaller:downloadFiles(source, files) for index, value in ipairs(files) do - http.get(source .. value, nil, function(response) - print('Downloading ' .. index .. ' of ' .. #files .. ' files: ' .. value) - local file = fs.open(value, "w") - file.write(response.readAll()) - file.close() - response.close() - end) + print('Downloading ' .. index .. ' of ' .. #files .. ' files: ' .. value) + local response = http.get(source .. value) + if not response or response.getResponseCode() ~= 200 then + error("Failed to download " .. value) + end + local file = fs.open(value, "w") + file.write(response.readAll()) + file.close() + response.close() end end From 39d74f24e29d509be23ace5436483bbf444f3b1d Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Thu, 7 Dec 2023 19:58:19 +0100 Subject: [PATCH 47/51] Removed downloadURL function Co-authored-by: Josh --- libs/scm/net.lua | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/libs/scm/net.lua b/libs/scm/net.lua index eadb724..57c497e 100644 --- a/libs/scm/net.lua +++ b/libs/scm/net.lua @@ -192,42 +192,6 @@ do return nil, false end - ---@param sourceObject table - ---@param targetDirectory string - ---@param updateObj table | nil - ---@return table | nil - ---@return boolean - function Net:downloadURL(sourceObject, targetDirectory, updateObj) - local sourceName = "default" or (updateObj and updateObj.sourceName) - if updateObj then - sourceObject.name = sourceObject.name or updateObj.name - end - - if not sourceObject.name then - sourceObject.name = self:getNameFromURL(sourceObject.source[sourceName]) - end - local request = http.get(sourceObject.source[sourceName]) - - if request then - local content = request.readAll() - request.close() - - if content then - local file = fs.open(targetDirectory .. sourceObject.name, "w") - if not file then - os.execute("mkdir " .. targetDirectory) - file = fs.open(targetDirectory .. sourceObject.name, "w") - end - file.write(content) - file.close() - - return sourceObject, true - end - end - - return nil, false - end - ---@param url string ---@return string function Net:getNameFromURL(url) From ecc7cf9b0659af9c7ac56d9a924263c43f3a805f Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Thu, 7 Dec 2023 20:13:20 +0100 Subject: [PATCH 48/51] removed redundant refresh Co-authored-by: Josh --- libs/scm/autocomplete.lua | 53 ++------------------------------------- libs/scm/net.lua | 4 +-- 2 files changed, 4 insertions(+), 53 deletions(-) diff --git a/libs/scm/autocomplete.lua b/libs/scm/autocomplete.lua index abb4e8b..d16b220 100644 --- a/libs/scm/autocomplete.lua +++ b/libs/scm/autocomplete.lua @@ -177,55 +177,6 @@ $ help self.commands["help"]["args"] = availableCommands end - function Autocomplete:refreshRepoScripts() - log("Downloading program and library names from GitHub...") - local repoScripts = {} - - local programs = {} - local libraries = {} - - local request = http.get(SCM.Config.getAll(SCM.Config)["apiGithubURL"] - .. SCM.Config.getAll(SCM.Config)["user"] - .. SCM.Config.getAll(SCM.Config)["apiGithubGetRepos"]) - if request then - local response = request.readAll() - request.close() - - local responseTable = textutils.unserializeJSON(response) - - local programSuffix = SCM.Config.getAll(SCM.Config)["programSuffix"] - local librarySuffix = SCM.Config.getAll(SCM.Config)["librarySuffix"] - - for i = 1, #responseTable, 1 do - local scriptName = responseTable[i]["name"] - if string.sub(scriptName, -string.len(programSuffix)) == programSuffix then - programs[ - string.sub(scriptName, 0, string.len(scriptName) - string.len(programSuffix)) - ] = {} - elseif string.sub(scriptName, -string.len(librarySuffix)) == librarySuffix then - libraries[ - string.sub(scriptName, 0, string.len(scriptName) - string.len(librarySuffix)) - ] = {} - end - end - else - log("Download failed") - end - - self.commands["add"]["args"] = programs - self.commands["require"]["args"] = libraries - - repoScripts["libraries"] = libraries - repoScripts["programs"] = programs - - local file = fs.open(SCM.Config.getAll(SCM.Config)["configDirectory"] - .. SCM.Config.getAll(SCM.Config)["repoScriptsFile"], "w") - if file then - file.write(textutils.serializeJSON(repoScripts)) - file.close() - end - end - ---@param shell table ---@param index integer ---@param argument string @@ -260,13 +211,13 @@ $ help end function Autocomplete:refreshAutocomplete() - self:refreshRepoScripts() + SCM.Net:refreshRepoScripts() self:prepareAutocomplete() self:updateAutocomplete() end ---@param t table - function Autocomplete:setProgramms(t) + function Autocomplete:setPrograms(t) self.commands["add"]["args"] = t end diff --git a/libs/scm/net.lua b/libs/scm/net.lua index 57c497e..01000bf 100644 --- a/libs/scm/net.lua +++ b/libs/scm/net.lua @@ -244,7 +244,7 @@ do else local repoScripts = textutils.unserializeJSON(file.readAll()) or nil if repoScripts then - SCM.Autocomplete:setProgramms(repoScripts["programs"]) + SCM.Autocomplete:setPrograms(repoScripts["programs"]) SCM.Autocomplete:setLibaries(repoScripts["libraries"]) end @@ -284,7 +284,7 @@ do log("Download failed") end - SCM.Autocomplete:setProgramms(programs) + SCM.Autocomplete:setPrograms(programs) SCM.Autocomplete:setLibaries(libraries) repoScripts["libraries"] = libraries From f3ed4f2aace1ea808b921e2469d0232529f5544b Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Thu, 7 Dec 2023 20:19:12 +0100 Subject: [PATCH 49/51] remove old files --- .github/workflows/test.yml.old | 41 ---------------------------------- scm-1.0-0.rockspec | 25 --------------------- 2 files changed, 66 deletions(-) delete mode 100644 .github/workflows/test.yml.old delete mode 100644 scm-1.0-0.rockspec diff --git a/.github/workflows/test.yml.old b/.github/workflows/test.yml.old deleted file mode 100644 index 52d2a6c..0000000 --- a/.github/workflows/test.yml.old +++ /dev/null @@ -1,41 +0,0 @@ -name: test - -on: [push, pull_request] - -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v2 - - - name: get lua - uses: leafo/gh-actions-lua@v10 - with: - luaVersion: "5.1" - - - name: get luarocks - uses: leafo/gh-actions-luarocks@v4 - - - name: get busted and luasocket - run: | - luarocks install busted - luarocks install luasocket - sudo apt install lua-socket - - - name: echo stuff - run: | - ls -l /home/runner/work/script-manager/script-manager/.luarocks/share - ls -l /home/runner/work/script-manager/script-manager/.luarocks/lib - ls -l /home/runner/work/script-manager/script-manager/.luarocks/etc - ls -l /home/runner/work/script-manager/script-manager/.luarocks/bin - - - name: fix https - run: | - mkdir -p /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/ssl/ - cat /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/https.lua | echo - ln -s /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/https.lua /home/runner/work/script-manager/script-manager/.luarocks/share/lua/5.1/ssl/https.lua - - - name: run tests - run: | - busted . \ No newline at end of file diff --git a/scm-1.0-0.rockspec b/scm-1.0-0.rockspec deleted file mode 100644 index 2f8aa92..0000000 --- a/scm-1.0-0.rockspec +++ /dev/null @@ -1,25 +0,0 @@ -package = "SCM" -version = "1.0-0" -source = { - url = "..." -- We don't have one yet -} -description = { - summary = "SCM is a script manager for Minecrafts ComputerCraft mod", - detailed = [[ - We are using CC: Tweaked and in some cases some - additional peripherals, which we ideally mention in - the repositories of the scripts that use them. - ]], - homepage = "http://...", -- We don't have one yet - license = "MIT/X11" -- or whatever you like -} -dependencies = { - "lua = 5.1", - "http >= 0.4-0" - -- If you depend on other rocks, add them here -} -build = { - -- We'll start here. - type = "builtin" - -} \ No newline at end of file From 39a85530065f15fa506f57354934db0a983bf1ef Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Thu, 7 Dec 2023 20:26:15 +0100 Subject: [PATCH 50/51] updated comments Co-authored-by: Josh --- libs/scm/scriptManager.lua | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libs/scm/scriptManager.lua b/libs/scm/scriptManager.lua index 68331c4..4065cb6 100644 --- a/libs/scm/scriptManager.lua +++ b/libs/scm/scriptManager.lua @@ -16,7 +16,6 @@ do end local log = function(...) SCM.Log:log(...) end - ---loads the scripts function ScriptManager:loadScripts() local file = fs.open(config()["configDirectory"] .. config()["scriptFile"], "r") if not file then @@ -30,7 +29,6 @@ do end end - ---loads all scripts function ScriptManager:saveScripts() local file = fs.open(config()["configDirectory"] .. config()["scriptFile"], "w") if not file then @@ -41,7 +39,6 @@ do file.close() end - ---adds a script to the script File ---@param script table | nil ---@param success boolean ---@return boolean @@ -107,14 +104,12 @@ do return false end - --- updates all scripts function ScriptManager:updateAllScripts() for i = 1, #self.scripts, 1 do self:updateScript(self.scripts[i].name, "default") end end - --- removes a script ---@param name string ---@param keepScriptConfig boolean | nil function ScriptManager:removeScript(name, keepScriptConfig) @@ -133,6 +128,7 @@ do self.scripts = o self:saveScripts() end + -- delete file local scriptDir = config()[scriptType .. "Directory"] if scriptType and ( @@ -153,7 +149,6 @@ do SCM.Autocomplete:updateAutocomplete() end - --- removes all scripts function ScriptManager:removeAllScripts() local tmpScripts = {} for i = 1, #self.scripts, 1 do @@ -183,6 +178,7 @@ do file = fs.open("./" .. config()["libraryDirectory"] .. name .. ".lua", "r") end if not file then log('File ' .. name .. ' not found') end + -- Find requirements by searching for comment --@requires name local requires = {} while true do From f49b5f6efb6ad9f7a71d050f447166dfdc7b00ce Mon Sep 17 00:00:00 2001 From: ChristophLHR <11349102+ChristophLHR@users.noreply.github.com> Date: Thu, 7 Dec 2023 20:32:14 +0100 Subject: [PATCH 51/51] Formatted Files Co-authored-by: Josh --- libs/scm/config.lua | 6 +----- libs/scm/ui.lua | 11 ----------- scmInstaller.lua | 1 - tests/Suite/fs.lua | 16 ++++++++-------- tests/Suite/helperFunctions.lua | 4 ++-- tests/Suite/json.lua | 34 ++++++++++++++++----------------- tests/testSuite.lua | 2 +- tests/test_spec.lua | 22 +++++++++++---------- 8 files changed, 41 insertions(+), 55 deletions(-) diff --git a/libs/scm/config.lua b/libs/scm/config.lua index 3287ce5..3275829 100644 --- a/libs/scm/config.lua +++ b/libs/scm/config.lua @@ -1,11 +1,7 @@ - - ---@class SCMConfig local Config = {} SCM.Config = Config do - - ---@class SCMConfigData Config.config = { -- Git Settings (In this case on GitHub, not tested with others) @@ -57,7 +53,7 @@ do ---@param config SCMConfigData | nil function Config:saveConfig(config) config = config or self.config - + local file = fs.open(config["configDirectory"] .. config["configFile"], "w") if not file then os.execute("mkdir " .. config["configDirectory"]) diff --git a/libs/scm/ui.lua b/libs/scm/ui.lua index a5cd3f9..86269b2 100644 --- a/libs/scm/ui.lua +++ b/libs/scm/ui.lua @@ -2,17 +2,6 @@ local UI = {} SCM.UI = UI do - --Redundant - function UI:printUsage() - print("Usage: scm [args]") - print("Commands:") - print(" add [src]") - print(" update [name] [src]") - print(" remove ") - print(" list") - print(" config [value]") - end - function UI:listScripts() local scripts = SCM.ScriptManager.scripts print("name", "type") diff --git a/scmInstaller.lua b/scmInstaller.lua index c40239a..6b13e20 100644 --- a/scmInstaller.lua +++ b/scmInstaller.lua @@ -27,7 +27,6 @@ function SCMInstaller:deleteFiles(files) end end --- download the files function SCMInstaller:downloadFiles(source, files) for index, value in ipairs(files) do print('Downloading ' .. index .. ' of ' .. #files .. ' files: ' .. value) diff --git a/tests/Suite/fs.lua b/tests/Suite/fs.lua index f6745d0..4841ab6 100644 --- a/tests/Suite/fs.lua +++ b/tests/Suite/fs.lua @@ -6,7 +6,7 @@ fs.progPath = "tmpProg/" do fs.open = function(path, mode) assert("string" == type(path), tostring(path) .. "path must be a string") - assert("string" == type(mode), tostring(mode) .." mode must be a string") + assert("string" == type(mode), tostring(mode) .. " mode must be a string") local file = io.open(path, mode) if not file then -- find all occurences of / in the path @@ -27,13 +27,13 @@ do file = io.open(path, mode) end if mode == "w" then - assert(file, "file could not be opened in : "..path.. " Mode : "..mode) + assert(file, "file could not be opened in : " .. path .. " Mode : " .. mode) end if not file then return nil end local file2 = {} - setmetatable(file2, {__index = file}) + setmetatable(file2, { __index = file }) file2.base = file file2.readAll = function() return file2.base:read("*a") @@ -68,7 +68,7 @@ do assert("string" == type(dest), "dest must be a string") local file = io.open(src, "r") if not file then - print("file "..src.." not found") + print("file " .. src .. " not found") return false end local content = file:read("*a") @@ -93,7 +93,7 @@ do end file = io.open(dest, "w") if not file then - print("file"..dest.." not found") + print("file" .. dest .. " not found") return false end end @@ -125,13 +125,13 @@ do end end - fs.delete = function (path) + fs.delete = function(path) assert("string" == type(path), "path must be a string") if fs.exists(path) then os.execute("rm -rf " .. path) end end - fs.readAll = function (path) + fs.readAll = function(path) assert("string" == type(path), "path must be a string") local file = io.open(path, "r") if not file then @@ -142,4 +142,4 @@ do return content end end -return fs \ No newline at end of file +return fs diff --git a/tests/Suite/helperFunctions.lua b/tests/Suite/helperFunctions.lua index 67a2a20..7a257fe 100644 --- a/tests/Suite/helperFunctions.lua +++ b/tests/Suite/helperFunctions.lua @@ -1,5 +1,5 @@ function table.copy(t) - local u = { } + local u = {} for k, v in pairs(t) do u[k] = v end return setmetatable(u, getmetatable(t)) -end \ No newline at end of file +end diff --git a/tests/Suite/json.lua b/tests/Suite/json.lua index 2e59c70..c459c0a 100644 --- a/tests/Suite/json.lua +++ b/tests/Suite/json.lua @@ -50,8 +50,8 @@ local function kind_of(obj) end local function escape_str(s) - local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'} - local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'} + local in_char = { '\\', '"', '/', '\b', '\f', '\n', '\r', '\t' } + local out_char = { '\\', '"', '/', 'b', 'f', 'n', 'r', 't' } for i, c in ipairs(in_char) do s = s:gsub(c, '\\' .. out_char[i]) end @@ -80,10 +80,10 @@ local function parse_str_val(str, pos, val) local early_end_error = 'End of input found while parsing string.' if pos > #str then error(early_end_error) end local c = str:sub(pos, pos) - if c == '"' then return val, pos + 1 end + if c == '"' then return val, pos + 1 end if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end -- We must have a \ character. - local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'} + local esc_map = { b = '\b', f = '\f', n = '\n', r = '\r', t = '\t' } local nextc = str:sub(pos + 1, pos + 1) if not nextc then error(early_end_error) end return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc)) @@ -101,8 +101,8 @@ end -- Public values and functions. function json.stringify(obj, as_key) - local s = {} -- We'll build the string as an array of strings to be concatenated. - local kind = kind_of(obj) -- This is 'array' if it's an array or type(obj) otherwise. + local s = {} -- We'll build the string as an array of strings to be concatenated. + local kind = kind_of(obj) -- This is 'array' if it's an array or type(obj) otherwise. if kind == 'array' then if as_key then error('Can\'t encode array as key.') end s[#s + 1] = '[' @@ -136,25 +136,25 @@ function json.stringify(obj, as_key) return table.concat(s) end -json.null = {} -- This is a one-off table to represent the null value. +json.null = {} -- This is a one-off table to represent the null value. function json.parse(str, pos, end_delim) pos = pos or 1 if pos > #str then error('Reached unexpected end of input.') end - local pos = pos + #str:match('^%s*', pos) -- Skip whitespace. + local pos = pos + #str:match('^%s*', pos) -- Skip whitespace. local first = str:sub(pos, pos) - if first == '{' then -- Parse an object. + if first == '{' then -- Parse an object. local obj, key, delim_found = {}, true, true pos = pos + 1 while true do key, pos = json.parse(str, pos, '}') if key == nil then return obj, pos end if not delim_found then error('Comma missing between object items.') end - pos = skip_delim(str, pos, ':', true) -- true -> error if missing. + pos = skip_delim(str, pos, ':', true) -- true -> error if missing. obj[key], pos = json.parse(str, pos) pos, delim_found = skip_delim(str, pos, ',') end - elseif first == '[' then -- Parse an array. + elseif first == '[' then -- Parse an array. local arr, val, delim_found = {}, true, true pos = pos + 1 while true do @@ -164,14 +164,14 @@ function json.parse(str, pos, end_delim) arr[#arr + 1] = val pos, delim_found = skip_delim(str, pos, ',') end - elseif first == '"' then -- Parse a string. + elseif first == '"' then -- Parse a string. return parse_str_val(str, pos + 1) - elseif first == '-' or first:match('%d') then -- Parse a number. + elseif first == '-' or first:match('%d') then -- Parse a number. return parse_num_val(str, pos) - elseif first == end_delim then -- End of an object or array. + elseif first == end_delim then -- End of an object or array. return nil, pos + 1 - else -- Parse true, false, or null. - local literals = {['true'] = true, ['false'] = false, ['null'] = json.null} + else -- Parse true, false, or null. + local literals = { ['true'] = true, ['false'] = false, ['null'] = json.null } for lit_str, lit_val in pairs(literals) do local lit_end = pos + #lit_str - 1 if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end @@ -181,4 +181,4 @@ function json.parse(str, pos, end_delim) end end -return json \ No newline at end of file +return json diff --git a/tests/testSuite.lua b/tests/testSuite.lua index b810fd8..6422a91 100644 --- a/tests/testSuite.lua +++ b/tests/testSuite.lua @@ -30,7 +30,7 @@ _G.http = { _G.shell = { -- TODO: implement shell - CompleteFunction ["setCompletionFunction"] = function(...) return end, - ["run"] = function (...) return end + ["run"] = function(...) return end } -- Just any day, does not matter as of now diff --git a/tests/test_spec.lua b/tests/test_spec.lua index f7e9c8c..2403e7a 100644 --- a/tests/test_spec.lua +++ b/tests/test_spec.lua @@ -90,13 +90,14 @@ end describe("Testing everything about SCM:", function() --only neccessary for local testing describe("Copy Files", function() - assert.is_true(fs.copy("./scm.lua", "tmpFiles/scm.lua"), "Could not copy scm.lua") assert.is_true(fs.copy("./libs/scm/config.lua", "tmpFiles/config.lua"), "Could not copy config.lua") assert.is_true(fs.copy("./libs/scm/net.lua", "tmpFiles/net.lua"), "Could not copy net.lua") assert.is_true(fs.copy("./libs/scm/log.lua", "tmpFiles/log.lua"), "Could not copy log.lua") - assert.is_true(fs.copy("./libs/scm/scriptManager.lua", "tmpFiles/scriptManager.lua"), "Could not copy scriptManager.lua") - assert.is_true(fs.copy("./libs/scm/autocomplete.lua", "tmpFiles/autocomplete.lua"), "Could not copy autocomplete.lua") + assert.is_true(fs.copy("./libs/scm/scriptManager.lua", "tmpFiles/scriptManager.lua"), + "Could not copy scriptManager.lua") + assert.is_true(fs.copy("./libs/scm/autocomplete.lua", "tmpFiles/autocomplete.lua"), + "Could not copy autocomplete.lua") assert.is_true(fs.copy("./libs/scm/ui.lua", "tmpFiles/ui.lua"), "Could not copy ui.lua") end) @@ -163,10 +164,10 @@ describe("Testing everything about SCM:", function() end ) end) - describe("Load Remote", function () + describe("Load Remote", function() it("Get TestLib", function() runTests( - ---@param scm SCM + ---@param scm SCM function(scm) local testScript = scm:load("scmTest") local scriptManager = scm.ScriptManager @@ -179,14 +180,13 @@ describe("Testing everything about SCM:", function() describe("Update SCM", function() it("Update SCM", function() runTests( - ---@param scm SCM + ---@param scm SCM function(scm) -- TODO: implement end ) end) end) - end) -- only neccessary for local testing @@ -195,9 +195,11 @@ describe("Testing everything about SCM:", function() assert.is_true(fs.copy("tmpFiles/config.lua", "./libs/scm/config.lua"), "Could not restore config.lua") assert.is_true(fs.copy("tmpFiles/net.lua", "./libs/scm/net.lua"), "Could not restore net.lua") assert.is_true(fs.copy("tmpFiles/log.lua", "./libs/scm/log.lua"), "Could not restore log.lua") - assert.is_true(fs.copy("tmpFiles/scriptManager.lua", "./libs/scm/scriptManager.lua"), "Could not restore scriptManager.lua") - assert.is_true(fs.copy("tmpFiles/autocomplete.lua", "./libs/scm/autocomplete.lua"), "Could not restore autocomplete.lua") + assert.is_true(fs.copy("tmpFiles/scriptManager.lua", "./libs/scm/scriptManager.lua"), + "Could not restore scriptManager.lua") + assert.is_true(fs.copy("tmpFiles/autocomplete.lua", "./libs/scm/autocomplete.lua"), + "Could not restore autocomplete.lua") assert.is_true(fs.copy("tmpFiles/ui.lua", "./libs/scm/ui.lua"), "Could not restore ui.lua") os.execute("rm --recursive ./tmpFiles") end) -end) \ No newline at end of file +end)