Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --# Notes
- --# Notes
- --[[
- Version 1.2 March 2013
- by Ignatz and Codeslinger
- This utility backs up and restores your projects for you, by storing them as images in your Dropbox folder.
- Its features are as follows:
- 1. backs up up behind the scenes every time you change the version number
- 2. tells you how long it is since the last backup
- 3. restores your backup into a new project, tabs and all
- INSTALLING IT
- Copy this project to your Codea, named as Backup
- BACKING UP
- Include a line like this in your function setup()
- b=Backup("MyProject Ver 100") -- NB no full stops or other "illegal" filename chars!
- Also create a dependency to the Backup project
- (click the + at upper right of screen, find Backup on the project list, and press it)
- The utility will only back up when the string in brackets changes. It will create a new image with that name
- in your Dropbox folder (you may need to sync to see it). The reason for not backing up every time you run, is that when you are developing, you will try a lot of stuff, and you may get into a mess. You will then want to go back to your last stable version. So the idea is that whenever you are at a checkpoint, make a new version name.
- NB each time you run, the utility will tell you how long it is since you last backed up. You can turn this off by adding a second parameter, false, when calling Backup.
- RESTORING
- Create a new project to hold your restored project, and put this in function setup()
- img=readImage("Dropbox:AAA")
- r=Restore(img)
- Now change the image name to the Dropbox file you want to restore
- BEFORE YOU RUN, create a dependency to the Backup project
- (click the + at upper right of screen, find Backup on the project list, and press it)
- Now run, and when it's done, go back to the code and it should all be there.
- --]]
- --# Main
- -- NEVER restore in this function, even for testing, because it may overwrite code
- function setup()
- --b=Backup("test302a",false,"Jeopardy")
- end
- --[[
- Backup file format - version 1
- 3 bytes version number (currently = 001)
- then for each tab...
- char 1
- tab name
- char 2
- tab text
- char 3
- final char is 0
- --]]
- --# Backup
- Backup = class()
- function Backup:init(title,remind,testproject)
- local version="001"
- if version=="001" then
- local b=Backup001(title,remind,testproject)
- end
- end
- --# Backup001
- Backup001 = class()
- --title is name of backup, backup only occurs when this changes
- --remind parameter if set to false turns off the reminder of how long it has been since last backup
- --testproject allows us to backup a named project instead of the open project, for use in debugging
- function Backup001:init(title,remind,testproject)
- self.version="001"
- local t=readProjectData(title)
- if t~=nil then --print reminder if backup exists and reminder not disabled
- if remind~=false then
- print("Last backup was",string.format("%.0f",os.difftime(os.time(),t)/60),"minutes ago")
- end
- else
- self:Store(title,testproject) --do backup
- saveProjectData(title,os.time()) --store date/time of backup
- end
- end
- function Backup001:Store(title,testproject)
- local txt=self:EncodeTabs(testproject)
- --setup image
- local n=string.len(txt)
- local s=math.floor((n/3)^.5)+1
- local img=image(s,s)
- local row,col=0,1
- local e={}
- for i=0,n-1,3 do
- for j=1,3 do
- e[j]=string.byte(string.sub(txt,i+j,i+j)) or 0
- end
- row = row + 1
- if row>s then row=1 col = col + 1 end
- img:set(col,row,e[1],e[2],e[3],255)
- end
- local docName="Dropbox:"..title
- saveImage(docName,nil)
- saveImage(docName,img)
- print(title.." - backup made")
- --verify image by restoring and comparing result with original
- img2=readImage(docName)
- local r=Restore(img2,true)
- if txt==r.RecoveredText then
- print("Backup verified")
- else
- print("ERROR - backup faulty")
- end
- end
- -- Private: Encode all tabs, including header.
- -- Returns encoded string.
- function Backup001:EncodeTabs(testproject)
- local SOH, STX, ETX = "\001", "\002", "\003"
- local encoded = self.version
- local tabs
- if testproject==nil then tabs = listProjectTabs() else tabs = listProjectTabs(testproject) end
- for i,t in pairs(tabs) do
- local tName=t if testproject~=nil then tName=testproject..":"..t end
- encoded = encoded..SOH..t..STX..readProjectTab(tName)..ETX
- end
- encoded = encoded.."\000"
- return encoded
- end
- --# Restore
- Restore = class()
- function Restore:init(img,test)
- local r,g,b,a=img:get(1,1)
- if string.char(r)..string.char(g)..string.char(b)=="001" then
- local b=Restore001(img,test)
- self.RecoveredText=b.RecoveredText
- else
- print("ERROR - Unknown version "..r)
- end
- end
- --# Restore001
- Restore001 = class()
- --test=true if verifying a backup, we need to return the decoded string and not save any tabs
- --if test is false or missing, this is a real restore, save the tabs
- function Restore001:init(img,test)
- self.version="001"
- local txt=self:ReadImage(img)
- if txt=="ERROR" then print("ERROR: I couldn't read the backup") return end
- if test then self.RecoveredText=txt return end --if testing, return the string
- print(self:DecodeAndSave(txt))
- end
- function Restore001:ReadImage(img)
- if type(img)=="string" then img=readImage(img) end
- rows,cols=img.height,img.width
- t={}
- local n=0
- local r,g,b
- for col=1,cols do
- for row=1,rows do
- r,g,b=img:get(col,row)
- table.insert(t,string.char(r)) table.insert(t,string.char(g)) table.insert(t,string.char(b))
- n = n + 3
- end
- end
- --truncate at end of text
- txt=table.concat(t)
- local u=string.find(txt,"\000",nil,true)
- if u>0 then txt=string.sub(txt,1,u) end
- return txt
- end
- -- Private: Decode one tab of an encoded string.
- --
- -- encoded - encoded string.
- -- start - start index inside |encoded|.
- --
- -- Returns tab name, tab contents, next index on success.
- -- Returns nil on failure.
- function Restore001:DecodeTab(encoded, start)
- local SOH, STX, ETX = "\001", "\002", "\003"
- local SOHidx = string.find(encoded, SOH, start)
- local STXidx = string.find(encoded, STX, start)
- local ETXidx = string.find(encoded, ETX, start)
- -- assert some basic format properties
- if not SOHidx or not STXidx or not ETXidx then
- return nil
- end
- if SOHidx ~= start or ETXidx < STXidx then
- return nil
- end
- -- decode
- local tabname = string.sub(encoded, SOHidx + 1, STXidx - 1)
- local contents = string.sub(encoded, STXidx + 1, ETXidx - 1)
- local nextidx = ETXidx + 1
- return tabname, contents, nextidx
- end
- -- Private: Decode all tabs of an encoded string and write them
- -- into the project.
- --
- -- encoded - encoded string, including header.
- -- Returns success or error message on failure.
- -- Tabs may have been saved until that point.
- function Restore001:DecodeAndSave(encoded)
- local tabidx = string.len(self.version)+1
- local result = "All done!"
- repeat
- -- check for end of data
- if string.sub(encoded, tabidx, tabidx) == "\000" then
- tabidx = nil
- else
- local tabname, contents
- tabname, contents, tabidx = self:DecodeTab(encoded, tabidx)
- if tabname ~= nil then
- saveProjectTab(tabname, contents)
- else
- result = "ERROR - Decoding error, recovery incomplete"
- end
- end
- until tabidx == nil
- return result
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement