Mercurial > traipse_dev
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) |