-- Leave empty for public repos, or add "your-token-here" local GIT_TOKEN = "" local GIT_OUTPUT_LOCATION = "/home" -- Update config local UPDATE_URL = "https://git.ejebring.com/eejebring/CC-tweaked-Gitea-Client/raw/branch/main/git.lua" local GIT_FILE = "git.lua" ---@param str string ---@param comp string function string.beginsWith(str, comp) local compLen = string.len(comp) local begining = string.sub(str, 0, compLen) return begining == comp end ---@param str string ---@param comp string function string.endsWith(str, comp) local reverseStr = string.reverse(str) local reverseComp = string.reverse(comp) return string.beginsWith(reverseStr, reverseComp) end ---@param str string ---@param delimiter string function string.split(str, delimiter) local returnTable = {} for k in string.gmatch(str, "([^" .. delimiter .. "]+)") do returnTable[#returnTable + 1] = k end return returnTable end local protocols = { "http://", "https://" } local ending = ".git" ---@param url string local function parseGiteaURL(url) ---@class urlinfo local urlInfo = { protocol = "", origin = "", owner = "", repo = "", branch = "main", treeUrl = "", } local lowerUrl = string.lower(url) if not string.endsWith(lowerUrl, ending) then error("A gitea link needs to end with " .. ending) end for _, proto in pairs(protocols) do if string.beginsWith(lowerUrl, proto) then urlInfo.protocol = proto break end end local urlLen = string.len(url) local protoLen = string.len(urlInfo.protocol) local endLen = string.len(ending) local cleaned = string.sub(url, protoLen + 1, urlLen - endLen) local urlParts = string.split(cleaned, "/") if not (#urlParts) == 3 then error("Unexpected link length.") end urlInfo.origin, urlInfo.owner, urlInfo.repo = urlParts[1], urlParts[2], urlParts[3] urlInfo.treeUrl = ("%s%s/api/v1/repos/%s/%s/git/trees/%s?recursive=1") :format(urlInfo.protocol, urlInfo.origin, urlInfo.owner, urlInfo.repo, urlInfo.branch) for k, v in pairs(urlInfo) do if v == "" or v == nil then error("Could not parse " .. k .. " from link.") end end print("treeUrl: ", urlInfo.treeUrl) return urlInfo end ---@param urlInfo urlinfo ---@param path string ---@param target string local function downloadFile(urlInfo, path, target) local url = ("%s%s/api/v1/repos/%s/%s/raw/%s/%s"):format(urlInfo.protocol, urlInfo.origin, urlInfo.owner, urlInfo.repo, urlInfo.branch, path) local req = { url = url } if GIT_TOKEN ~= "" then req.headers = { Authorization = "token " .. GIT_TOKEN } end local response, err = http.get(req) if not response then error("Failed to download: " .. path .. " due to: " .. err) end local data = response.readAll() response.close() local file, fileError = fs.open(target, "w") if file then file.write(data) file.close() else error("Could not download file '" .. target "' due to: " .. fileError) end end local function cloneRepo(url) local urlInfo = parseGiteaURL(url) print("Cloning: " .. urlInfo.owner .. "/" .. urlInfo.repo .. "@" .. urlInfo.branch) local req = { url = urlInfo.treeUrl } if GIT_TOKEN ~= "" then req.headers = { Authorization = "token " .. GIT_TOKEN } end local resp = http.get(req) if not resp then error("Cannot access repository. Check URL or token.") end local responseJSON = resp.readAll() resp.close() if not responseJSON then error("Response returned empty.") end local tree = textutils.unserializeJSON(responseJSON) if not tree then error("Response could not be unserialized") end local count = 0 for _, node in ipairs(tree.tree) do if node.type == "blob" then local localPath = ("%s/%s/%s"):format(GIT_OUTPUT_LOCATION, urlInfo.repo, node.path) local dir = fs.getDir(localPath) if not fs.isDir(dir) then fs.makeDir(dir) end downloadFile(urlInfo, node.path, localPath) count = count + 1 end end print(("Cloned %d files to %s/%s"):format(count, GIT_OUTPUT_LOCATION, urlInfo.repo)) end local args = { ... } if args[1] == "clone" and args[2] then cloneRepo(args[2]) elseif args[1] == "update" then local resp = http.get(UPDATE_URL) if not resp then error("Failed to download update.") end local code = resp.readAll() if not code then error("Recived empty response from server.") end local file = fs.open(GIT_FILE, "w+") if not file then error("Could not overwite " .. GIT_FILE) end file.write(code) else print("Usage:") print(" git update") print(" git clone ") print("") print("Examples:") print(' git clone "https://gitea.example.com/user/myrepo"') --print(' git clone "https://gitea.example.com/user/myrepo/tree/main/path/to/file.lua"') print("") print("Set GIT_TOKEN variable above for private repos.") end