Advertisement
Guest User

Backup v1.2

a guest
Mar 26th, 2013
367
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. --# Notes
  3. --# Notes
  4. --[[
  5. Version 1.2 March 2013
  6. by Ignatz and Codeslinger
  7.  
  8. This utility backs up and restores your projects for you, by storing them as images in your Dropbox folder.
  9. Its features are as follows:
  10. 1. backs up up behind the scenes every time you change the version number
  11. 2. tells you how long it is since the last backup
  12. 3. restores your backup into a new project, tabs and all
  13.  
  14. INSTALLING IT
  15. Copy this project to your Codea, named as Backup
  16.  
  17. BACKING UP
  18.  
  19. Include a line like this in your function setup()
  20. b=Backup("MyProject Ver 100") -- NB no full stops or other "illegal" filename chars!
  21.  
  22. Also create a dependency to the Backup project
  23. (click the + at upper right of screen, find Backup on the project list, and press it)
  24.  
  25. The utility will only back up when the string in brackets changes. It will create a new image with that name
  26. 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.
  27.  
  28. 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.
  29.  
  30. RESTORING
  31.  
  32. Create a new project to hold your restored project, and put this in function setup()
  33. img=readImage("Dropbox:AAA")
  34. r=Restore(img)
  35.  
  36. Now change the image name to the Dropbox file you want to restore
  37.  
  38. BEFORE YOU RUN, create a dependency to the Backup project
  39. (click the + at upper right of screen, find Backup on the project list, and press it)
  40.  
  41. Now run, and when it's done, go back to the code and it should all be there.
  42.  
  43. --]]
  44.  
  45. --# Main
  46.  
  47. -- NEVER restore in this function, even for testing, because it may overwrite code
  48. function setup()
  49. --b=Backup("test302a",false,"Jeopardy")
  50. end
  51.  
  52. --[[
  53.  
  54. Backup file format - version 1
  55.  
  56. 3 bytes version number (currently = 001)
  57.  
  58. then for each tab...
  59. char 1
  60. tab name
  61. char 2
  62. tab text
  63. char 3
  64.  
  65. final char is 0
  66.  
  67. --]]
  68.  
  69.  
  70. --# Backup
  71. Backup = class()
  72.  
  73. function Backup:init(title,remind,testproject)
  74. local version="001"
  75. if version=="001" then
  76. local b=Backup001(title,remind,testproject)
  77. end
  78. end
  79.  
  80.  
  81.  
  82. --# Backup001
  83. Backup001 = class()
  84.  
  85. --title is name of backup, backup only occurs when this changes
  86. --remind parameter if set to false turns off the reminder of how long it has been since last backup
  87. --testproject allows us to backup a named project instead of the open project, for use in debugging
  88. function Backup001:init(title,remind,testproject)
  89. self.version="001"
  90. local t=readProjectData(title)
  91. if t~=nil then --print reminder if backup exists and reminder not disabled
  92. if remind~=false then
  93. print("Last backup was",string.format("%.0f",os.difftime(os.time(),t)/60),"minutes ago")
  94. end
  95. else
  96. self:Store(title,testproject) --do backup
  97. saveProjectData(title,os.time()) --store date/time of backup
  98. end
  99. end
  100.  
  101. function Backup001:Store(title,testproject)
  102. local txt=self:EncodeTabs(testproject)
  103. --setup image
  104. local n=string.len(txt)
  105. local s=math.floor((n/3)^.5)+1
  106. local img=image(s,s)
  107. local row,col=0,1
  108. local e={}
  109. for i=0,n-1,3 do
  110. for j=1,3 do
  111. e[j]=string.byte(string.sub(txt,i+j,i+j)) or 0
  112. end
  113. row = row + 1
  114. if row>s then row=1 col = col + 1 end
  115. img:set(col,row,e[1],e[2],e[3],255)
  116. end
  117. local docName="Dropbox:"..title
  118. saveImage(docName,nil)
  119. saveImage(docName,img)
  120. print(title.." - backup made")
  121. --verify image by restoring and comparing result with original
  122. img2=readImage(docName)
  123. local r=Restore(img2,true)
  124. if txt==r.RecoveredText then
  125. print("Backup verified")
  126. else
  127. print("ERROR - backup faulty")
  128. end
  129. end
  130.  
  131. -- Private: Encode all tabs, including header.
  132. -- Returns encoded string.
  133. function Backup001:EncodeTabs(testproject)
  134. local SOH, STX, ETX = "\001", "\002", "\003"
  135. local encoded = self.version
  136. local tabs
  137. if testproject==nil then tabs = listProjectTabs() else tabs = listProjectTabs(testproject) end
  138. for i,t in pairs(tabs) do
  139. local tName=t if testproject~=nil then tName=testproject..":"..t end
  140. encoded = encoded..SOH..t..STX..readProjectTab(tName)..ETX
  141. end
  142. encoded = encoded.."\000"
  143. return encoded
  144. end
  145. --# Restore
  146. Restore = class()
  147.  
  148. function Restore:init(img,test)
  149. local r,g,b,a=img:get(1,1)
  150. if string.char(r)..string.char(g)..string.char(b)=="001" then
  151. local b=Restore001(img,test)
  152. self.RecoveredText=b.RecoveredText
  153. else
  154. print("ERROR - Unknown version "..r)
  155. end
  156. end
  157.  
  158.  
  159. --# Restore001
  160. Restore001 = class()
  161.  
  162. --test=true if verifying a backup, we need to return the decoded string and not save any tabs
  163. --if test is false or missing, this is a real restore, save the tabs
  164. function Restore001:init(img,test)
  165. self.version="001"
  166. local txt=self:ReadImage(img)
  167. if txt=="ERROR" then print("ERROR: I couldn't read the backup") return end
  168. if test then self.RecoveredText=txt return end --if testing, return the string
  169. print(self:DecodeAndSave(txt))
  170. end
  171.  
  172. function Restore001:ReadImage(img)
  173. if type(img)=="string" then img=readImage(img) end
  174. rows,cols=img.height,img.width
  175. t={}
  176. local n=0
  177. local r,g,b
  178. for col=1,cols do
  179. for row=1,rows do
  180. r,g,b=img:get(col,row)
  181. table.insert(t,string.char(r)) table.insert(t,string.char(g)) table.insert(t,string.char(b))
  182. n = n + 3
  183. end
  184. end
  185. --truncate at end of text
  186. txt=table.concat(t)
  187. local u=string.find(txt,"\000",nil,true)
  188. if u>0 then txt=string.sub(txt,1,u) end
  189. return txt
  190. end
  191.  
  192. -- Private: Decode one tab of an encoded string.
  193. --
  194. -- encoded - encoded string.
  195. -- start - start index inside |encoded|.
  196. --
  197. -- Returns tab name, tab contents, next index on success.
  198. -- Returns nil on failure.
  199. function Restore001:DecodeTab(encoded, start)
  200. local SOH, STX, ETX = "\001", "\002", "\003"
  201. local SOHidx = string.find(encoded, SOH, start)
  202. local STXidx = string.find(encoded, STX, start)
  203. local ETXidx = string.find(encoded, ETX, start)
  204. -- assert some basic format properties
  205. if not SOHidx or not STXidx or not ETXidx then
  206. return nil
  207. end
  208. if SOHidx ~= start or ETXidx < STXidx then
  209. return nil
  210. end
  211. -- decode
  212. local tabname = string.sub(encoded, SOHidx + 1, STXidx - 1)
  213. local contents = string.sub(encoded, STXidx + 1, ETXidx - 1)
  214. local nextidx = ETXidx + 1
  215. return tabname, contents, nextidx
  216. end
  217.  
  218. -- Private: Decode all tabs of an encoded string and write them
  219. -- into the project.
  220. --
  221. -- encoded - encoded string, including header.
  222. -- Returns success or error message on failure.
  223. -- Tabs may have been saved until that point.
  224. function Restore001:DecodeAndSave(encoded)
  225. local tabidx = string.len(self.version)+1
  226. local result = "All done!"
  227. repeat
  228. -- check for end of data
  229. if string.sub(encoded, tabidx, tabidx) == "\000" then
  230. tabidx = nil
  231. else
  232. local tabname, contents
  233. tabname, contents, tabidx = self:DecodeTab(encoded, tabidx)
  234. if tabname ~= nil then
  235. saveProjectTab(tabname, contents)
  236. else
  237. result = "ERROR - Decoding error, recovery incomplete"
  238. end
  239. end
  240. until tabidx == nil
  241. return result
  242. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement