GitHub Repository Loader

Earlier today I needed a quick way to load a github repository into Codea and I didn’t find one, so I made my own.

Here is the code:

function setup()
    if not loadedModules() then
        print("Loading Base64 module..")
        http.request("https://gist.githubusercontent.com/JakAttak/72121a8657e4ffe4c53a/raw/98e3661b10e319bdaac67a6893ff6ebe0138f5c0/Base64", 
        function(d) 
            saveModule("Base64", d)
        end)
    
        print("Loading JSON module..")
        http.request("https://gist.githubusercontent.com/JakAttak/d40f78dc6bd8d9d1e86d/raw/1b0e8303353b81a98f9a8d0d83e9421a0f0ef3ee/JSON", 
        function(d) 
            saveModule("JSON", d)
        end)
    else
        output.clear()
        
        parameter.text("username")
        parameter.text("repo_name")
        parameter.text("folder_name")
        parameter.text("codea_project_name")
        parameter.action("Load repository", function()
            if #listProjectTabs(codea_project_name) ~= 0 then
                print("Loading github repository contents...")
                repo_contents_url = "https://api.github.com/repos/"..username.."/"..repo_name.."/contents/"
                if folder_name ~= "" then
                    repo_contents_url = repo_contents_url .. folder_name .. "/"
                    print("redirecting search to (" .. folder_name .. ") folder with repository")
                end
                http.request(repo_contents_url, parseForFiles, failed)
                parameter.clear()
            else
                print("ERROR! The Codea project you specified does not exist")
            end
        end)
    end
end

function loadedModules()
    local b64, js = false, false
    for n, d in pairs(listProjectTabs()) do
        if d == "Base64" then
            b64 = true
        elseif d == "JSON" then
            js = true
        end
    end
    
    return (b64 and js)
end

function saveModule(n, d)
    saveProjectTab(n, d)
    print("Saved " .. n .. " module.")
    
    tween.delay(0.1, function()
            loadstring(d)()
    end)
    
    if loadedModules() then
        print("Loaded all modules, restarting project")
        setup()
    end
end

function parseForFiles(d)
    sound("A Hero's Quest:Arrow Shoot 1")
    
    repo_files = {}

    local start = 0
    while start ~= nil do
        local s, e, fn = d:find('{"name":"(.-)"', start)
        if fn then
            local fur = repo_contents_url .. fn
            local dot = (fn:find("%.") or (fn:len() + 1))
            local fnnoex, ex = fn:sub(1, dot - 1), fn:sub(dot, fn:len())
            if ex == ".lua" then
                table.insert(repo_files, { name = fnnoex, url = fur })
            elseif ex == ".codea" then
                print("Found .codea folder, switching search to folder contents")
                repo_contents_url = fur .. "/"
                http.request(repo_contents_url, parseForFiles, failed)
                return
            else
                print("Found file (" .. fn .. ") with incompatible extension, ignoring")
            end
        end
        start = e
    end
    
    print("Found " .. #repo_files .. " files in the repository. Loading files now.")
    
    loadRepoFile(1)
end

function loadRepoFile(index)
    local file_info = repo_files[index]
    
    http.request(file_info.url, function(d) saveFile(file_info.name, d, index) end, failed)
end

function saveFile(name, data, index)
    print("Loaded file " .. name)
    
    local file = json.decode(data)
    saveProjectTab(codea_project_name..":"..name, dec(file.content))
    
    print("Saved file " .. name)
    if index < #repo_files then
        loadRepoFile(index + 1)
    else
        sound(SOUND_POWERUP, 38427)
        output.clear()
        print("Successfully loaded project!")
    end
end

function failed(d, s, h)
    print("Encountered an error: ", d, s, h)
end

@JakAttak =D> Awesome job! See if you can have it target a folder in a repo as well. Also, when it is downloading a repo, if it has a folder in it an error pops up (probably because it tries to download the folder).

@JakAttak AWSOME!
two small pb i had to solve by hand when using it to load juice and run it:

  • the README file is not lua compatible. I suppressed it.
  • the order of files is not good. I re-ordered them manually, after reading the code.

@Saturn031000, can you give me an example repository with a folder and Codea code so I can try and make it compatible?

@Jmv38 - yes, I’m not sure how to handle file order because it has no way to tell what the order should be, it is not started anywhere.

@JakAttak
https://github.com/Zoyt/StackIt

The StackIt.codea folder contains the .lua files. I was considering creating a repo to demonstrate but remembered this. :wink:


EDIT:

Or this — https://github.com/Shrike78/HarmonyCodea

(The HarmonyMesh.codea folder).

Okay I updated the code to support folders, and only save files with a lua extension - you can specify a specific folder in the repository to search in, or if you don’t and it finds a .codea folder it will start looking in it automatically.

Let me know if it works for you.

@JakAttak It works. AWESOME.

@JakAttak, this is great, I used it to bring my whole project down from GitHub. I did have to make some changes as my repos are private, so I generated an OAuth token which can be passed through as:

http.request(repo_contents_url.."?access_token=<token>", parseForFiles, failed)

and also added to each file request as:

http.request(file_info.url .. "?access_token=<token>", function(d) saveFile(file_info.name, d, index) end, failed)

and had to mangle the slashes slightly:

local fur = repo_contents_url .. "/".. fn

But this is incredibly useful, cracking stuff!

Brookesi

@brookesi, nice! I didn’t bother with Oauth for my purposes as the repos I was trying to import are all public.