Backup Options

Hi all,

A number of options have been provided in the past for backup of your Codea workspace. The most recent from the development team, I have found all of these useful and appreciate the efforts of the all the work done.

There are several systems that have been developed but all seem to cease to function, largely I think due to the changes in Codea itself. So I find it frustrating when I can’t backup my projects. I have to admit that this is largely due to my lack of organisation and I just accumulate loads of partially finished files.

One of the options was provided by @dave1707 which backed up locally in the Dropbox storage, which should be backed up by Dropbox itself. But it fails to run due to an error in reading the plist file the link for this is below :

Backup

I suspect this is due to a change in the text searching system. Any chance someone could check this out?

Bri_G

@Bri_G I wrote another backup/restore program that doesn’t use the plist file. The next version of Codea has new functions that I use. They are createProject, deleteProject, hasProject, and listProjects. It will backup all of the projects into one file into the Dropbox folder. That file can be syncd with the Dropbox app. To restore a project, just select which backup file you want to use, select the project name from a list, and then restore. It will backup my 490+ projects in about 2 seconds which creates a 1.5MB file. You can create as many backup files as you want and restore from any one you select. Once the next Codea version comes out, I’ll share the code.

@dave1707 - thanks for the prompt reply - played with the Project functions you mentioned but weren’t they temporarily removed ? because of the import function in that version of Codea?

Sounds really fast - hope it’s implemented soon.

Thanks,

Bri_G

The thing that was removed was the Codea version of the restore. You can still do the export, but only assets can be restored. The functions are still valid. Since you’re listed as a beta tester, you probably have the latest beta version of Codea. So here’s a copy of my backup/restore that uses the new functions. There are 4 sliders that need to be turned on depending on what you want to do. Allow_bkup_create needs to be on to create a backup file. Allow_project_extract needs to be on to extract a file. Only_view_project_extract needs to be on if you just want to see the extracted project printed in the print panel. Allow_overwrite needs to be on if you want to overwrite an existing project. To use the code, turn on the Allow bkup create slider and tap Create a backup file. To restore a project, tap Select a backup file and tap the backup file you want to use and then tap List all projects. Tap the project you want to extract, and tap Extract or view a project. If the project already exists, turn on Allow overwrite and tap Extract again. You can create as many backup files as you want because the backup file name is the date and time of the backup.

EDIT: THIS PROJECT IS ONLY FOR THE BETA VERSION OF CODEA. ONCE THE BETA IS LIVE, THEN THIS CAN BE USED.

function setup()
    proj=listProjects("documents")
    param()
    pns="PROJ".."NAME".."START" -- project name start
    pne="PROJ".."NAME".."END"   -- project name end
    tns="TAB".."NAME".."START"  -- tab name start
    tne="TAB".."NAME".."END"    -- tab name end
    te="TAB".."END"             -- tab end
    pe="PROJ".."END"            -- project end
end

function param()
    pasteboard.text=""
    parameter.clear()
    parameter.boolean("Allow_bkup_create",false)
    parameter.boolean("Allow_project_extract",false)
    parameter.boolean("Only_view_project_extract",false)
    parameter.boolean("Allow_overwrite",false)
    parameter.action("Create a backup file.",createBkup)
    parameter.action("Select a backup file.",selectProject)
    parameter.action("List all projects.",showProjects)
    parameter.action("Extract or view a project.",extractProject)
end

function createBkup()
    output.clear()
    if not Allow_bkup_create then
        print("Allow_bkup_create not on.")
        return
    end
    local t=os.date("*t")
    backupName=string.format("bkup%02d%02d-%02d%02d",t.month,t.day,t.hour,t.min)
    local temp={}
    local dt=os.date()
    local cnt=0
    table.insert(temp,"BKUP==START.."..dt)
    for a,b in pairs(proj) do
        print(b)
        lst=listProjectTabs(b)
        cnt=cnt+1
        table.insert(temp,pns.."=="..b.."=="..pne)
        for c,d in pairs(lst) do
            table.insert(temp,tns.."=="..d.."=="..tne)
            table.insert(temp,readProjectTab(b..":"..d))
            table.insert(temp,"=="..te)
        end
        table.insert(temp,"=="..pe)
    end
    table.insert(temp,"BKUP==END")
    local str=table.concat(temp,"\
")
    print("Backup file created.")
    print(dt)
    print(cnt.." Projects.")
    print("File size  "..#str.." bytes.")
    saveText("Dropbox:"..backupName,str)
    param()
end

function selectProject()
    output.clear()
    local lst=assetList("Dropbox")
    for a,b in pairs(lst) do
        if string.find(b,"bkup") then
            print(b)
        end
    end
end

function showProjects()
    output.clear()
    local s=#pasteboard.text
    local name=string.sub(pasteboard.text,1,s-1)
    bkupFile=readText("Dropbox:"..name)
    if bkupFile==nil then
        print("No backup files were selected.")
        return
    end
    local sss=pns.."==(%g+)=="..pne
    for projName,proj in     
            string.gmatch(bkupFile,sss) do
        print(projName)
    end 
end

function extractProject()
    output.clear()
    if pasteboard.text=="" then
        print("A project wasn't selected.")
        return
    end
    local s=#pasteboard.text
    name=string.sub(pasteboard.text,1,s-1)
    local sss=pns.."==(%g+)=="..pne.."\
(.-)=="..pe
    if Only_view_project_extract then
        for projName,proj in string.gmatch(bkupFile,sss) do
            if name==projName then
                print("===  "..name.."  ===\
")
                print(proj)
                return
            end
        end
    end
    if not Allow_project_extract then 
        print("Allow_project_extract not on.")
        return
    end
    if Allow_overwrite then
        if hasProject(name) then
            print("Deleting project..."..name)
            deleteProject(name)
        end
    end
    if not hasProject(name) then
        print("Creating project... "..name)
        createProject(name)
        for projName,proj in string.gmatch(bkupFile,sss) do
            if name==projName then
                getTab(proj)
            end
        end 
        param()
    else
        print("Project "..name.." already exists.\
\
Allow_overwrite not on.")
    end        
end

function getTab(proj)
    local sss=tns.."==(%g+)=="..tne.."\
(.-)\
=="..te
    for tabName,tab in string.gmatch(proj,sss) do
        saveProjectTab(name..":"..tabName,tab)
        print("Tab created  "..name..":"..tabName)
    end        
end

@dave1707 - very neat and have used the backup option followed by the Dropbox sync to get the file backed up in the cloud. This has allowed me to delete most of my projects and slim down my work-space.

Thanks for that - do you think we would be better moving this to the development folders?

Bri_G

@Bri_G I hope you tested my code and did backups and restores before you deleted your projects. Another thing that can be done with the Dropbox app is to view the file and copy sections of code from it while on a PC linked to Dropbox. Things always change and as people leave the forum, their projects created for everyone’s use aren’t kept up to date by those who are left. So I don’t think it really matters where the code is kept. If someone does a search for backups, they’ll find this eventually or be referred to it. So is this backup/restore easy enough to use. I know I don’t have a mass restore option, but I’m not sure it’s really needed because you can pull a project from the backup as needed. I also was thinking of deleting a lot of my projects to free up memory. If I look in Settings/Usage/Codea, it takes up 364 MB of memory.

Just a warning to anyone who uses this code, it hasn’t been fully tested. Make sure you have multiple backup files just in case a backup gets corrupted. The name uses mmdd-hhmm so wait at least a minute between multiple backups. This is still a work in progress.

@dave1707 Just used the code to save to my Dropbox. Have confirmed transfer but not used any other features yet. Have only deleted older backed up files so far.

Thanks

Here’s an updated version of my backup/restore code. I removed the print option since I only used that as I was writing/testing the program and didn’t see any need for it anymore. I also added code so that you had to do the extract steps in order (Select, List, Extract) otherwise I’ll print a message. I think I have this working to make the backup/restore easy. As a test, I copied Cargo-Bot to a test file and backed up that test file. I restored that test file using overwrite and again with the test file deleted before the restore. Both times I restored the Cargo-Bot test file and in both cases Cargo-Bot started OK. I didn’t try running a full game though.

NOTE: As I said above, this uses some new functions that are in the beta version, so it can’t be used until the beta version is accepted by Apple.

function setup()
    proj=listProjects("documents")
    param()
    pns="PROJ".."NAME".."START" -- project name start
    pne="PROJ".."NAME".."END"   -- project name end
    tns="TAB".."NAME".."START"  -- tab name start
    tne="TAB".."NAME".."END"    -- tab name end
    te="TAB".."END"             -- tab end
    pe="PROJ".."END"            -- project end
end

function param()
    pasteboard.text=""
    parameter.clear()
    parameter.boolean("Allow_bkup_create",false)
    parameter.action("Create a backup file.",createBkup)
    parameter.action("Select a backup file.",selectProject)
    parameter.action("List all projects.",showProjects)
    parameter.boolean("Allow_project_extract",false)
    parameter.boolean("Allow_overwrite",false)
    parameter.action("Extract a project.",extractProject)    
end

function createBkup()
    nextFunction=""
    pasteboard.text=""
    output.clear()
    if not Allow_bkup_create then
        print("Allow_bkup_create not on.")
        return
    end
    local t=os.date("*t")
    backupName=string.format("bkup%02d%02d-%02d%02d",t.month,t.day,t.hour,t.min)
    local temp={}
    local dt=os.date()
    local cnt=0
    table.insert(temp,"BKUP==START.."..dt)
    for a,b in pairs(proj) do
        print(b)
        lst=listProjectTabs(b)
        cnt=cnt+1
        table.insert(temp,pns.."=="..b.."=="..pne)
        for c,d in pairs(lst) do
            table.insert(temp,tns.."=="..d.."=="..tne)
            table.insert(temp,readProjectTab(b..":"..d))
            table.insert(temp,"=="..te)
        end
        table.insert(temp,"=="..pe)
    end
    table.insert(temp,"BKUP==END")
    local str=table.concat(temp,"\
")
    print("Backup file created.")
    print(dt)
    print(cnt.." Projects.")
    print("File size  "..#str.." bytes.")
    saveText("Dropbox:"..backupName,str)
    param()
end

function selectProject()
    output.clear()
    pasteboard.text=""
    local lst=assetList("Dropbox")
    for a,b in pairs(lst) do
        if string.find(b,"bkup") then
            print(b)
        end
    end
    nextFunction="show"
end

function showProjects()
    output.clear()
    local s=#pasteboard.text
    local name=string.sub(pasteboard.text,1,s-1)
    bkupFile=readText("Dropbox:"..name)
    if bkupFile==nil or nextFunction~="show" then
        print("No backup file was selected.")
        return
    end
    local sss=pns.."==(%g+)=="..pne
    for projName,proj in     
            string.gmatch(bkupFile,sss) do
        print(projName)
    end 
    pasteboard.text=""
    nextFunction="extract"
end

function extractProject()
    output.clear()
    if pasteboard.text=="" or nextFunction~="extract" then
        print("A project wasn't selected.")
        return
    end
    local s=#pasteboard.text
    name=string.sub(pasteboard.text,1,s-1)
    local sss=pns.."==(%g+)=="..pne.."\
(.-)=="..pe
    if not Allow_project_extract then 
        print("Allow_project_extract not on.")
        return
    end
    if Allow_overwrite then
        if hasProject(name) then
            print("Deleting project..."..name)
            deleteProject(name)
        end
    end
    if not hasProject(name) then
        print("Creating project... "..name)
        createProject(name)
        for projName,proj in string.gmatch(bkupFile,sss) do
            if name==projName then
                getTab(proj)
            end
        end 
        param()
        nextFunction=""
    else
        print("Project "..name.." already exists.\
\
Allow_overwrite not on.")
    end        
end

function getTab(proj)
    local sss=tns.."==(%g+)=="..tne.."\
(.-)\
=="..te
    for tabName,tab in string.gmatch(proj,sss) do
        saveProjectTab(name..":"..tabName,tab)
        print("Tab created  "..name..":"..tabName)
    end        
end

Just a note that the above code DOESN’T backup any local or project data associated with any project. There also isn’t any option to backup any global data. I guess I can look into adding those if needed.

EDIT: The local and project data CAN’T be backed up in the above program. In order to read local and project data of a project, you have to be running that project. There’s no easy way that I know of where one program can read the local or project data of another project. It can be done, but not easy enough that I’ll add it to the above code. If you want to save local or project data, you’ll have to do it yourself.

@dave1707
I was thinking that it might be helpful to add some functions for archiving and unarchiving projects (i.e. to and from zip format). That way you can treat the project as a single file and do whatever you want with it.

@John I’m not sure I understand what you’re saying. When I create a backup, it creates a single file with all the projects in it and a single project can be pulled from the file. I don’t zip the file because it wasn’t that big of a file (1.5MB) for my 499 projects. When it gets syncd with Dropbox on my PC, it can be viewed as a text file and I can highlight and copy any text from the file. The thing I don’t understand is why Apple won’t let you do the export/restore like what was in the first version of this beta if I can write something similar.

@dave1707
The main advantage to archiving and unarchiving projects in that way is that you can easily transfer both the source code and additional files (sounds, images, text, project data, info plist etc). I feel that most people sharing projects avoid having any additional dependencies due to this, which in-turn limits what you can share.

Apple is being very strict with us in particular (and less so with other developers) for some reason. They allow and encourage code sharing with Swift Playgrounds on iPad, going as far as to advertise the feature as a major benefit of using it while at the same time disallowing it for us. The reason why appears to be strict application of the Terms of Service that we must agree to as developers.

@John I wasn’t trying to write something all inclusive, just something simple. Something that if I deleted a project by mistake, I could easily get it back. I wasn’t worried about dependencies, assets, or local/project data. I figured Codea would eventually have all that, which you did have until Apple made you remove it. I figure what I have above will do until Apple stops being so picky. I’m past the point of trying to write large, complicated code. I did all of that for too long while I was working.