From 03f00fc2a43e3f5b96bfc3e91b1f70623dc310d9 Mon Sep 17 00:00:00 2001 From: MayaTheShy Date: Sun, 22 Mar 2026 15:50:40 -0400 Subject: [PATCH] Refactor git module to support Gitea and improve error handling --- sys/modules/opus/git.lua | 97 +++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 37 deletions(-) diff --git a/sys/modules/opus/git.lua b/sys/modules/opus/git.lua index dc3dbdb..4207841 100644 --- a/sys/modules/opus/git.lua +++ b/sys/modules/opus/git.lua @@ -1,67 +1,90 @@ local json = require('opus.json') local Util = require('opus.util') -local TREE_URL = 'https://api.github.com/repos/%s/%s/git/trees/%s?recursive=1' -local FILE_URL = 'https://raw.githubusercontent.com/%s/%s/%s/%s' +local GITHUB_TREE_URL = 'https://api.github.com/repos/%s/%s/git/trees/%s?recursive=1' +local GITHUB_FILE_URL = 'https://raw.githubusercontent.com/%s/%s/%s/%s' +local GITEA_TREE_URL = 'https://%s/api/v1/repos/%s/%s/git/trees/%s?recursive=1' +local GITEA_FILE_URL = 'https://%s/%s/%s/raw/branch/%s/%s' local TREE_HEADERS = {} local git = { } if _G._GIT_API_KEY then - TREE_HEADERS.Authorization = 'token ' .. _G._GIT_API_KEY + TREE_HEADERS.Authorization = 'token ' .. _G._GIT_API_KEY end -function git.list(repository) - local t = Util.split(repository, '(.-)/') - - local user = table.remove(t, 1) - local repo = table.remove(t, 1) - local branch = table.remove(t, 1) or 'main' - local path - - if not Util.empty(t) then - path = table.concat(t, '/') .. '/' - end - - local function getContents() - local dataUrl = string.format(TREE_URL, user, repo, branch) - local contents, msg = Util.httpGet(dataUrl, TREE_HEADERS) - if not contents then - error(string.format('Failed to download %s\n%s', dataUrl, msg), 2) - else - return json.decode(contents) +local function parseTree(data, path, fileUrlFn) + if data.message then + if data.message:find("API rate limit exceeded") then + error("Out of API calls, try again later") + end + if data.message == "Not found" or data.message == "Not Found" then + error("Invalid repository") end end - local data = getContents() or error('Invalid repository') - - if data.message and data.message:find("API rate limit exceeded") then - error("Out of API calls, try again later") - end - - if data.message and data.message == "Not found" then - error("Invalid repository") - end - local list = { } - for _,v in pairs(data.tree) do + for _, v in pairs(data.tree) do if v.type == "blob" then - v.path = v.path:gsub("%s","%%20") + v.path = v.path:gsub("%s", "%%20") if not path then list[v.path] = { - url = string.format(FILE_URL, user, repo, branch, v.path), + url = fileUrlFn(v.path), size = v.size, } elseif Util.startsWith(v.path, path) then local p = string.sub(v.path, #path) list[p] = { - url = string.format(FILE_URL, user, repo, branch, path .. p), + url = fileUrlFn(path .. p), size = v.size, } end end end - return list end +local function fetchTree(url) + local contents, msg = Util.httpGet(url, TREE_HEADERS) + if not contents then + error(string.format('Failed to download %s\n%s', url, msg), 2) + end + return json.decode(contents) or error('Invalid repository') +end + +-- GitHub: user/repo/branch/subdir/ +local function listGithub(repository) + local t = Util.split(repository, '(.-)/') + local user = table.remove(t, 1) + local repo = table.remove(t, 1) + local branch = table.remove(t, 1) or 'main' + local path = not Util.empty(t) and (table.concat(t, '/') .. '/') or nil + + local data = fetchTree(string.format(GITHUB_TREE_URL, user, repo, branch)) + return parseTree(data, path, function(p) + return string.format(GITHUB_FILE_URL, user, repo, branch, p) + end) +end + +-- Gitea: gitea://host/user/repo/branch/subdir/ +local function listGitea(host, remainder) + local t = Util.split(remainder, '(.-)/') + local user = table.remove(t, 1) + local repo = table.remove(t, 1) + local branch = table.remove(t, 1) or 'main' + local path = not Util.empty(t) and (table.concat(t, '/') .. '/') or nil + + local data = fetchTree(string.format(GITEA_TREE_URL, host, user, repo, branch)) + return parseTree(data, path, function(p) + return string.format(GITEA_FILE_URL, host, user, repo, branch, p) + end) +end + +function git.list(repository) + local host_type, host, rest = repository:match('^(%w+)://(.-)/(.*)') + if host_type == 'gitea' then + return listGitea(host, rest) + end + return listGithub(repository) +end + return git