diff --git a/git.lua b/git.lua index 09faebd..d3f8860 100644 --- a/git.lua +++ b/git.lua @@ -1,107 +1,109 @@ --- Save as /home/git.lua -local http = require("http") -local fs = require("fs") -local json = textutils.unserializeJSON - --- Configuration -local GIT_TOKEN = "" -- Leave empty for public repos, or add "your-token-here" +local GIT_TOKEN = "" -- Leave empty for public repos, or add "your-token-here" -- Parse a Gitea URL like: https://gitea.example.com/owner/repo or /owner/repo/branch/filename local function parseGiteaURL(url) - local protocol, domain, path = url:match("^(https?://([^/]+))(/[^?]*)") - if not protocol then - protocol, domain, path = "https://gitea.local", "gitea.local", url - end - - -- Remove trailing slashes and clean path - path = path:gsub("/+$", "") - - -- Extract components from path (format: /owner/repo or /owner/repo/branch) - local parts = {} - for segment in path:gmatch("[^/]+") do - if segment ~= "" then table.insert(parts, segment) end - end - - if #parts < 2 then - return nil, "Invalid URL format. Expected: https://domain.com/owner/repo" - end - - local owner = parts[1] - local repo = parts[2] - local branch = parts[3] or "master" - - return { - base = protocol .. "/" .. domain, - owner = owner, - repo = repo, - branch = branch - } + local protocol, domain, path = url:match("^(https?://([^/]+))(/[^?]*)") + if not protocol then + protocol, domain, path = "https://gitea.local", "gitea.local", url + end + + -- Remove trailing slashes and clean path + path = path:gsub("/+$", "") + + -- Extract components from path (format: /owner/repo or /owner/repo/branch) + local parts = {} + for segment in path:gmatch("[^/]+") do + if segment ~= "" then table.insert(parts, segment) end + end + + if #parts < 2 then + return nil, "Invalid URL format. Expected: https://domain.com/owner/repo" + end + + local owner = parts[1] + local repo = parts[2] + local branch = parts[3] or "master" + + return { + base = protocol .. "/" .. domain, + owner = owner, + repo = repo, + branch = branch + } end local function downloadFile(base, owner, repo, branch, path, target) - local url = ("%s/api/v1/repos/%s/%s/raw/%s/%s"):format(base, owner, repo, branch, path) - - local req = {url = url} - if GIT_TOKEN ~= "" then - req.headers = {Authorization = "token " .. GIT_TOKEN} - end - - local response = http.get(req) - if not response then error("Failed to download: "..path) end - - local data = response.readAll() - response.close() - - local file = fs.open(target, "w") - file.write(data) - file.close() + local url = ("%s/api/v1/repos/%s/%s/raw/%s/%s"):format(base, owner, repo, branch, path) + + local req = { url = url } + if GIT_TOKEN ~= "" then + req.headers = { Authorization = "token " .. GIT_TOKEN } + end + + local response = http.get(req) + if not response then error("Failed to download: " .. path) 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 info, err = parseGiteaURL(url) - if not info then error(err) end - - print("Cloning: " .. info.owner .. "/" .. info.repo .. "@" .. info.branch) - - local treeUrl = ("%s/api/v1/repos/%s/%s/git/trees/%s?recursive=1"):format(info.base, info.owner, info.repo, info.branch) - - local req = {url = 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 tree = json(resp.readAll()) - resp.close() - - local count = 0 - for _, node in ipairs(tree.tree) do - if node.type == "blob" then - local localPath = ("git/%s/%s/%s"):format(info.owner, info.repo, node.path) - local dir = fs.getDir(localPath) - - if not fs.isDir(dir) then fs.makeDir(dir) end - - downloadFile(info.base, info.owner, info.repo, info.branch, node.path, localPath) - count = count + 1 + local info, err = parseGiteaURL(url) + if not info then error(err) end + + print("Cloning: " .. info.owner .. "/" .. info.repo .. "@" .. info.branch) + + local treeUrl = ("%s/api/v1/repos/%s/%s/git/trees/%s?recursive=1"):format(info.base, info.owner, info.repo, + info.branch) + + local req = { url = treeUrl } + if GIT_TOKEN ~= "" then + req.headers = { Authorization = "token " .. GIT_TOKEN } end - end - - print(("Cloned %d files to /home/git/%s/%s"):format(count, info.owner, info.repo)) + + 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 = ("git/%s/%s/%s"):format(info.owner, info.repo, node.path) + local dir = fs.getDir(localPath) + + if not fs.isDir(dir) then fs.makeDir(dir) end + + downloadFile(info.base, info.owner, info.repo, info.branch, node.path, localPath) + count = count + 1 + end + end + + print(("Cloned %d files to /home/git/%s/%s"):format(count, info.owner, info.repo)) end -local args = {...} -if args[1] == "pull" and args[2] then - cloneRepo(args[2]) +local args = { ... } +if args[1] == "clone" and args[2] then + cloneRepo(args[2]) else - print("Usage:") - print(" git pull ") - print("") - print("Examples:") - print(' git pull "https://gitea.example.com/user/myrepo"') - print(' git pull "https://gitea.example.com/user/myrepo/tree/main/path/to/file.lua"') - print("") - print("Set GIT_TOKEN variable above for private repos.") -end \ No newline at end of file + print("Usage:") + print(" git pull ") + print("") + print("Examples:") + print(' git pull "https://gitea.example.com/user/myrepo"') + print(' git pull "https://gitea.example.com/user/myrepo/tree/main/path/to/file.lua"') + print("") + print("Set GIT_TOKEN variable above for private repos.") +end