comparison orpg/tools/updater.py @ 28:6ef4bb8ee8ca traipse_dev

Update Manager Beta 0.1 release!! This new update manager is a boon for devs and users. This is working code and nothing more, it is 'Beta'.
author sirebral
date Sat, 01 Aug 2009 14:38:19 -0500
parents
children 3769c8d6431e
comparison
equal deleted inserted replaced
27:a571772a45c7 28:6ef4bb8ee8ca
1 import wx
2 import wx.html
3 import webbrowser
4 import urllib
5 import zipfile
6 import traceback
7 import hashlib
8 import orpg.dirpath
9 from orpg.orpgCore import *
10 import orpg.orpg_version
11 import orpg.tools.orpg_log
12 import orpg.orpg_xml
13 import orpg.dirpath
14 import orpg.tools.orpg_settings
15 import orpg.tools.validate
16 from mercurial import ui, hg, commands, repo, revlog, cmdutil
17 dir_struct = open_rpg.get_component("dir_struct")
18
19 u = ui.ui()
20 r = hg.repository(u, ".")
21 c = r.changectx('tip')
22
23 #repo = hg.repository(ui.ui(), 'http://hg.assembla.com/traipse')
24 #b = []
25
26 #b = commands.branches(u, r, True)
27 #print b
28
29 """
30 u = ui.ui()
31 r = hg.repository(u, ".")
32 l2 =[]
33 b = r.branchtags()
34 heads = dict.fromkeys(r.heads(), 1)
35 l = [((n in heads), r.changelog.rev(n), n, t) for t, n in b.items()]
36 l.sort()
37 l.reverse()
38 for ishead, r, n, t in l: l2.append(t)
39 print l2
40 """
41
42 #print heads
43 #b = []
44 #b = c.branch()
45 #print c.branch()
46 #print c.tags()
47
48 ##Process
49 #Pull
50 #Gather Changeset Info
51 #Display window with Branch + Changesets
52 #Update from Branch -Revision.
53
54
55
56
57 # --------------------
58 # | | |
59 # | Change | Download |
60 # | Log | List |
61 # | |-----------|
62 # | | butons |
63 # ----------------------
64 # Buttons area includes, []Auto Update, <advanced>
65 #
66
67
68 class AboutHTMLWindow(wx.Panel):
69 "Window used to display the About dialog box"
70 # Init using the derived from class
71 def __init__( self, parent, id):
72 wx.Panel.__init__( self, parent, id, size=(400, -1))
73
74 def OnLinkClicked( self, ref ):
75 "Open an external browser to resolve our About box links!!!"
76 href = ref.GetHref()
77 webbrowser.open( href )
78
79
80 class updaterFrame(wx.Frame):
81 def __init__(self, parent, title, openrpg):
82
83 ### Update Manager
84 self.ui = ui.ui()
85 self.repo = hg.repository(u, ".")
86 self.c = self.repo.changectx('tip')
87
88
89 self.openrpg = openrpg
90 self.parent = parent
91 self.log = self.openrpg.get_component("log")
92 self.log.log("Enter updaterFrame", ORPG_DEBUG)
93
94 wx.Frame.__init__(self, None, wx.ID_ANY, title, size=(640,480),
95 style=wx.FRAME_NO_TASKBAR | wx.STAY_ON_TOP | wx.DEFAULT_FRAME_STYLE)
96 self.SetBackgroundColour(wx.WHITE)
97 self.CenterOnScreen()
98 self.settings = openrpg.get_component('settings')
99 self.xml = openrpg.get_component('xml')
100 self.dir_struct = self.openrpg.get_component("dir_struct")
101 self.sizer = wx.GridBagSizer(hgap=1, vgap=1)
102 self.changelog = wx.TextCtrl(self, wx.ID_ANY, size=(400, -1), style=wx.TE_MULTILINE | wx.TE_READONLY)
103
104 self.filelist = wx.TextCtrl(self, wx.ID_ANY, size=(250, 300), style=wx.TE_MULTILINE | wx.TE_READONLY)
105 self.buttons = {}
106 self.buttons['progress_bar'] = wx.Gauge(self, wx.ID_ANY, 100)
107 self.buttons['auto_text'] = wx.StaticText(self, wx.ID_ANY, "Auto Update")
108 self.buttons['auto_check'] = wx.CheckBox(self, wx.ID_ANY)
109 self.buttons['advanced'] = wx.Button(self, wx.ID_ANY, "Package Select")
110 self.buttons['update'] = wx.Button(self, wx.ID_ANY, "Update Now")
111 self.buttons['finish'] = wx.Button(self, wx.ID_ANY, "Finish")
112
113 self.sizer.Add(self.changelog, (0,0), span=(3,1), flag=wx.EXPAND)
114 self.sizer.Add(self.filelist, (0,1), span=(1,3), flag=wx.EXPAND)
115
116 self.sizer.Add(self.buttons['progress_bar'], (1,1), span=(1,3), flag=wx.EXPAND)
117 self.sizer.Add(self.buttons['auto_text'], (2,1))
118 self.sizer.Add(self.buttons['auto_check'], (2,2), flag=wx.EXPAND)
119 self.sizer.Add(self.buttons['advanced'], (2,3), flag=wx.EXPAND)
120 self.sizer.Add(self.buttons['update'], (3,1), flag=wx.EXPAND)
121 self.sizer.Add(self.buttons['finish'], (3,2), span=(1,2), flag=wx.EXPAND)
122 self.sizer.AddGrowableCol(0)
123 self.sizer.AddGrowableRow(0)
124 self.SetSizer(self.sizer)
125 self.SetAutoLayout(True)
126 self.initPrefs()
127
128
129
130 if self.package == None: wx.CallAfter(self.Advanced)
131 #if self.autoupdate == "On": self.buttons['auto_check'].SetValue(True)
132
133 ## Event Handlers
134 self.Bind(wx.EVT_BUTTON, self.Update, self.buttons['update'])
135 self.Bind(wx.EVT_BUTTON, self.Finish, self.buttons['finish'])
136 self.Bind(wx.EVT_BUTTON, self.Advanced, self.buttons['advanced'])
137 self.Bind(wx.EVT_CHECKBOX, self.ToggleAutoUpdate, self.buttons['auto_check'])
138
139 try: self.check()
140 except:
141 self.buttons['finish'].Show()
142 self.buttons['update'].Show()
143
144 def showFinish(self):
145 if self.Updated: self.filelist.SetValue(self.filelist.GetValue() + "Finished ... \n")
146 self.buttons['finish'].Show()
147 self.buttons['advanced'].Show()
148
149 def initPrefs(self):
150 #self.list_url = self.settings.get_setting("PackagesURL")
151 #self.package_type = self.settings.get_setting("PackagesType")
152 #self.package_name = self.settings.get_setting("PackagesName")
153 self.SelectPackage = False
154 #self.autoupdate = self.settings.get_setting("AutoUpdate")
155 self.packages = None
156 self.package = self.get_package()
157 self.Updated = False
158 self.Finished = False
159
160 def isFinished(self):
161 return self.Finished
162
163 def ToggleAutoUpdate(self, event):
164 if self.buttons['auto_check'].GetValue():
165 self.autoupdate = "On"
166 #self.settings.set_setting("AutoUpdate", "On")
167 #self.Update(None)
168 else:
169 self.autoupdate = "Off"
170 #self.settings.set_setting("AutoUpdate", "Off")
171
172 def check(self):
173 self.buttons['finish'].Hide()
174 self.buttons['update'].Hide()
175 self.updatelist = []
176 wx.CallAfter(self.showFinish)
177 #Do the MD5 Check & DL
178 files = self.package._get_childNodes()
179 self.buttons['progress_bar'].SetRange(len(files))
180 try:
181 i = 1
182 for file in files:
183 checksum = md5.new()
184 self.buttons['progress_bar'].SetValue(i)
185 if file._get_tagName() == 'file':
186 file_name = file.getAttribute("name")
187 file_url = file.getAttribute("url").replace(' ', '%20') + '/' + file_name
188 file_path = file.getAttribute("path")
189 read_type = file.getAttribute("read_type")
190 file_checksum = file.getAttribute("checksum")
191 full_path = self.dir_struct["home"].replace("\\","/") + file_path + os.sep + file_name
192 full_path = full_path.replace("/", os.sep)
193
194 if self.verify_file(full_path):
195 if read_type == 'rb': f = open(full_path, "rb")
196 else: f = open(full_path, "r")
197 data = f.read()
198 f.close()
199 checksum.update(data)
200 if(checksum.hexdigest() != file_checksum):
201 self.log.log("Read Type: " + read_type, ORPG_DEBUG)
202 self.log.log("Filename: " + file_name + "\n\tLocal Checksum:\t" + checksum.hexdigest() + "\n\tWeb Checksum:\t" + file_checksum, ORPG_DEBUG)
203 self.updatelist.append((file_url, full_path, file_name, read_type))
204 else: self.updatelist.append((file_url, full_path, file_name, read_type))
205 elif file._get_tagName() == 'dir':
206 dir_path = file.getAttribute("path")
207 full_path = self.dir_struct['home'] + dir_path
208 if not self.verify_file(full_path):
209 self.filelist.SetValue(self.filelist.GetValue() + "Creating Directory " + dir_path + " ...\n")
210 os.makedirs(full_path)
211 i += 1
212 if len(self.updatelist) == 0:
213 wx.CallAfter(self.Finish)
214 return False
215 except: #error handing update check. Likely no internet connection. skip update check
216 self.log.log("[WARNING] Automatic update check failed.\n" + traceback.format_exc(), ORPG_GENERAL)
217 self.filelist.SetValue("[WARNING] Automatic update check failed.\n" + traceback.format_exc())
218 return False
219 dmsg = "A newer version is available.\n"
220 for file in self.updatelist: dmsg += file[2] + " is out of date\n"
221 dmsg += "Would you like to update Now?"
222 self.filelist.SetValue(dmsg)
223 data = urllib.urlretrieve(self.package.getAttribute("notes").replace(' ', '%20'))
224 file = open(data[0])
225 changelog = file.read()
226 file.close()
227 self.changelog.SetPage(changelog)
228
229 if self.autoupdate == "Off": self.buttons['update'].Show()
230 if self.autoupdate == "On": wx.CallAfter(self.Update)
231 return True
232
233 def Update(self, evt=None):
234
235 hg.clean(self.repo, self.current)
236
237 """old code
238 self.buttons['finish'].Hide()
239 self.buttons['update'].Hide()
240 self.buttons['advanced'].Hide()
241 self.buttons['progress_bar'].SetRange(len(self.updatelist))
242 self.filelist.SetValue("")
243 self.log.log("Starting Update Proccess!", ORPG_DEBUG)
244 i = 1
245 for file in self.updatelist:
246 self.downloadFile(file[0], file[1], file[2], i, file[3])
247 i += 1
248 self.Updated = True
249 self.parent.updated = True
250 wx.CallAfter(self.showFinish)
251 if self.autoupdate == 'On': wx.CallAfter(self.Finish)
252 """
253
254 def downloadFile(self, file_url, abs_path, file_name, i, read_type):
255 self.buttons['progress_bar'].SetValue(i)
256 self.buttons['finish'].Hide()
257 self.log.log("Downloading " + file_name, ORPG_DEBUG)
258 try:
259 self.filelist.SetValue(self.filelist.GetValue() + "Downloading " + file_name + " ...\n")
260 wx.Yield()
261 checksum = md5.new()
262 data = urllib.urlretrieve("http://openrpg.digitalxero.net/" + file_url)
263
264 if read_type == 'rb': file = open(data[0], "rb")
265 else: file = open(data[0], "r")
266
267 file_data = file.read()
268 file.close()
269 checksum.update(file_data)
270 self.log.log("Read Type: " + read_type, ORPG_DEBUG)
271 self.log.log("Downloaded filename: " + file_name + "\n\tDownloaded Checksum:\t" + checksum.hexdigest(), ORPG_DEBUG)
272
273 if read_type == 'rb': file = open(abs_path, 'wb')
274 else: file = open(abs_path, 'w')
275 file.write(file_data)
276 file.close()
277
278 #Debug Stuff
279 checksum = md5.new()
280 f = open(abs_path, read_type)
281 file_data = f.read()
282 f.close()
283 checksum.update(file_data)
284 self.log.log("Written filename: " + file_name + "\n\tWritten Checksum:\t" + checksum.hexdigest(), ORPG_DEBUG)
285 except:
286 self.log.log("Failed to download file: " + abs_path, ORPG_GENERAL)
287 self.log.log(traceback.format_exc(), ORPG_GENERAL)
288
289 def Finish(self, evt=None):
290 #self.settings.updateIni()
291 self.Finished = True
292 self.Destroy()
293
294 def Advanced(self, evt=None):
295 dlg = wx.Dialog(self, wx.ID_ANY, "Package Selector", style=wx.DEFAULT_DIALOG_STYLE)
296 icon = None
297 if wx.Platform == '__WXMSW__': icon = wx.Icon(self.dir_struct["icon"]+'d20.ico', wx.BITMAP_TYPE_ICO)
298 else: icon = wx.Icon(self.dir_struct["icon"]+"d20.xpm", wx.BITMAP_TYPE_XPM )
299 if icon != None: dlg.SetIcon(icon)
300
301 dlgsizer = wx.GridBagSizer(hgap=1, vgap=1)
302 Yes = wx.Button( dlg, wx.ID_OK, "Ok" )
303 Yes.SetDefault()
304 rgroup = wx.RadioButton(dlg, wx.ID_ANY, "group_start", style=wx.RB_GROUP)
305 rgroup.Hide()
306
307 if self.packages == None: self.get_packages()
308 if self.package_list == None: return
309
310
311 types = self.package_list
312 row=0
313 col=0
314 self.current = self.c.branch()
315 self.package_type = self.current
316 self.btnlist = {}; self.btn = {}
317 self.id = 1
318
319 for t in types:
320 self.btnName = str(t)
321 self.btn[self.id] = wx.RadioButton(dlg, wx.ID_ANY, str(t), name=self.btnName)
322 if self.btnName == self.current:
323 self.btn[self.id].SetValue(True)
324 self.btnlist[self.id] = self.btnName
325 dlgsizer.Add(self.btn[self.id], (row, col))
326 row += 1; self.id += 1
327
328 dlgsizer.Add(Yes, (row+1,0))
329 dlg.SetAutoLayout( True )
330 dlg.SetSizer( dlgsizer )
331 dlgsizer.Fit( dlg )
332 dlg.Centre()
333
334 dlg.Bind(wx.EVT_RADIOBUTTON, self.PackageSet)
335
336 if dlg.ShowModal():
337 dlg.Destroy()
338 if self.Updated:
339 self.Updated = False
340 self.filelist.SetValue('')
341 wx.CallAfter(self.check)
342
343 def PackageSet(self, event):
344 for btn in self.btn:
345 if self.btn[btn].GetValue() == True: self.current = self.btnlist[btn]
346
347 branches = self.repo.branchtags()
348
349 heads = dict.fromkeys(self.repo.heads(), 1)
350 l = [((n in heads), self.repo.changelog.rev(n), n, t) for t, n in branches.items()]
351
352 #l.sort()
353 #l.reverse()
354 #for ishead, r, n, t in l: self.package_list.append(t)
355
356 if self.current != type:
357 u = ui.ui()
358 r = hg.repository(u, ".")
359 #r = hg.islocal()
360 c = r.changectx('tip')
361 files = self.c.files()
362 #print commands.log(u, r, c)
363 #print r.changelog
364
365 ### Cleaning up for dev build 0.1
366 ### The below material is for the Rev Log. You can run hg log to see what data it will pull.
367 #cs = r.changectx(c.rev()).changeset()
368 #get = util.cachefunc(lambda r: repo.changectx(r).changeset())
369 #changeiter, matchfn = cmdutil.walkchangerevs(u, r, 1, cs, 1)
370 #for st, rev, fns in changeiter:
371 # revbranch = get(rev)[5]['branch']; print revbranch
372
373 heads = dict.fromkeys(self.repo.heads(), self.repo.branchtags())
374 branches = dict.copy(self.repo.branchtags())
375
376 self.filelist.SetValue('')
377 self.filelist.AppendText("Files that will change\n\n")
378
379 self.changelog.SetValue('')
380 changelog = "This is Dev Build 0.1 of the Update Manager. It has limited functionality.\n\nThe full release will search your Revision log and show the contents here."
381 self.changelog.AppendText(changelog + '\n')
382 self.filelist.AppendText("Update to " + self.current + "\n\n The full release will show the files to be changed here.")
383
384 #### Files works but not fully without the change log information, pulled for Dev 0.1
385 #for f in files:
386 # fc = c[f]
387 # self.filelist.AppendText(str(f + '\n'))
388
389
390
391
392 def verify_file(self, abs_path):
393 """Returns True if file or directory exists"""
394 try:
395 os.stat(abs_path)
396 return True
397 except OSError:
398 self.log.log("Invalid File or Directory: " + abs_path, ORPG_GENERAL)
399 return False
400
401 def get_packages(self, type=None):
402 #Fixed and ready for Test. Can be cleaner
403
404
405
406 self.package_list = []
407 b = self.repo.branchtags()
408 heads = dict.fromkeys(self.repo.heads(), 1)
409 l = [((n in heads), self.repo.changelog.rev(n), n, t) for t, n in b.items()]
410 l.sort()
411 l.reverse()
412 for ishead, r, n, t in l: self.package_list.append(t)
413
414 def get_package(self):
415 #Fixed and ready for test.
416 if self.packages == None: self.get_packages()
417 if self.package_list == None: return None
418 return None
419
420 def is_up2date(self, version, build):
421 if self.package == None:
422 self.SelectPackage == True
423 return False
424 vg = (version > self.package.getAttribute("version"))
425 ve = (version == self.package.getAttribute("version"))
426 b = (build >= self.package.getAttribute("build"))
427
428 if vg: return True
429 if (not ve) or (not b): return False
430 return True
431
432 class updateApp(wx.App):
433 def OnInit(self):
434 self.open_rpg = open_rpg
435 self.log = orpg.tools.orpg_log.orpgLog(orpg.dirpath.dir_struct["user"] + "runlogs/")
436 self.log.setLogToConsol(False)
437 self.log.log("Updater Start", ORPG_NOTE)
438
439 #Add the initial global components of the openrpg class
440 #Every class should be passed openrpg
441 self.open_rpg.add_component("log", self.log)
442 self.open_rpg.add_component("xml", orpg.orpg_xml)
443 self.open_rpg.add_component("dir_struct", orpg.dirpath.dir_struct)
444 self.validate = orpg.tools.validate.Validate()
445 self.open_rpg.add_component("validate", self.validate)
446 #self.settings = orpg.tools.orpg_settings.orpgSettings(self.open_rpg)
447 #self.open_rpg.add_component("settings", self.settings)
448 #self.settings.updateIni()
449 self.updater = updaterFrame(self, "OpenRPG Update Manager Beta 0.1", self.open_rpg)
450 self.updated = False
451
452
453 try:
454 self.updater.Show()
455 self.SetTopWindow(self.updater)
456 self.updater.Fit()
457 except: pass
458
459 return True
460
461 def OnExit(self):
462 #self.settings.save()
463 """
464 imported = ['orpg.orpgCore', 'orpg.orpg_wx', 'orpg.orpg_version', 'orpg.tools.orpg_log', 'orpg.orpg_xml', 'orpg.dirpath', 'orpg.tools.orpg_settings', 'orpg.tools.validate', 'orpg.pulldom', 'orpg.tools.NotebookCtrl', 'orpg.tools.config_update', 'orpg.systempath', 'orpg.minidom', 'orpg.dirpath.dirpath_tools', 'orpg.tools.rgbhex', 'orpg.orpg_windows']
465
466 for name in imported:
467 if name in sys.modules:
468 self.log.log("Unimported " + name, ORPG_DEBUG)
469 del sys.modules[name]
470 """
471 self.log.log("Updater Exit\n\n", ORPG_NOTE)