Changeset 4946 for branch/QuickScan/umit/plugin/Update.py
- Timestamp:
- 06/29/09 18:05:30 (4 years ago)
- Location:
- branch/QuickScan
- Files:
-
- 2 modified
-
. (modified) (1 prop)
-
umit/plugin/Update.py (modified) (19 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branch/QuickScan
- Property svnmerge-integrated changed from /trunk:1-4792 to /trunk:1-4937
-
branch/QuickScan/umit/plugin/Update.py
r4240 r4946 22 22 try: 23 23 from hashlib import md5 24 from hashlib import sha1 as sha 24 25 except ImportError: 25 26 from md5 import md5 27 from sha import sha 26 28 27 29 from threading import RLock 28 30 from tempfile import mkstemp 31 from StringIO import StringIO 29 32 from xml.dom.minidom import parseString 30 33 … … 47 50 FILE_CHECKING = 7 48 51 49 class UpdateObject(object): 52 from xml.sax import handler, make_parser 53 54 class Update(object): 55 def __init__(self, version, description, url, integrity): 56 self.version, self.description, self.url, self.integrity = \ 57 version, description, url, integrity 58 59 class UpdateObject(handler.ContentHandler): 50 60 def __init__(self, obj): 61 self.data = '' 62 self.parse_phase = 0 63 self.updates = [] 64 65 self.version = '' 66 self.description = '' 67 self.url = [] 68 self.integrity = {} 69 51 70 self.buffer = [] 52 71 53 72 self.status = STATUS_IDLE 54 73 55 74 self.label = None 56 75 self.fract = None 57 58 self.url = None 59 self.version = None 60 self.hash = None 61 76 62 77 self.object = obj 63 78 64 79 self.fd = None 65 80 66 81 self.size = None 67 82 self.total = None 68 83 84 self.last_update_idx = 0 85 self.selected_update_idx = -1 86 69 87 # Simple lock for sync 70 88 self.lock = RLock() 71 89 72 90 def parse_latest_file(self): 73 """ 74 @return url, version or None, None on error 75 """ 76 77 try: 78 doc = parseString("".join(self.buffer)) 79 80 if doc.documentElement.tagName != 'UmitPluginUpdate': 81 raise Exception("Not valid xml file.") 82 83 url, version, hash = None, None, None 84 85 for node in doc.documentElement.childNodes: 86 if node.nodeName == 'update-uri': 87 url = node.firstChild.data 88 if node.nodeName == 'version': 89 version = node.firstChild.data 90 if node.nodeName == 'md5': 91 hash = node.firstChild.data 92 93 return url, version, hash 94 except Exception, exc: 95 log.warning("__parse_xml: %s" % exc) 96 return None, None, None 97 91 parser = make_parser() 92 parser.setContentHandler(self) 93 parser.parse(StringIO("".join(self.buffer))) 94 95 def startElement(self, name, attrs): 96 if name == 'UmitPluginUpdate' and self.parse_phase == 0: 97 self.parse_phase = 1 98 elif name == 'update' and self.parse_phase == 1: 99 self.parse_phase = 2 100 elif name in ('version', 'description', 'url') and \ 101 self.parse_phase == 2: 102 103 self.parse_phase = 3 104 elif name == 'integrity' and self.parse_phase == 2 and \ 105 'type' in attrs.keys() and 'value' in attrs.keys(): 106 107 self.integrity[attrs.get('type')] = attrs.get('value') 108 else: 109 self.data = '' 110 111 def characters(self, ch): 112 if self.parse_phase == 3: 113 self.data += ch 114 115 def endElement(self, name): 116 if name in ('version', 'description', 'url'): 117 val = getattr(self, name, None) 118 119 if isinstance(val, basestring): 120 setattr(self, name, self.data) 121 elif isinstance(val, list): 122 val.append(self.data) 123 124 elif name == 'update': 125 if self.version and self.url: 126 self.updates.append(Update(self.version, self.description, 127 self.url, self.integrity)) 128 129 self.version = '' 130 self.description = '' 131 self.url = [] 132 self.integrity = {} 133 self.parse_phase = 1 134 self.data = '' 135 else: 136 self.parse_phase -= 1 137 self.data = '' 98 138 99 139 class UpdateEngine(object): … … 107 147 self.static_lst = None 108 148 self.updating = False 109 149 110 150 def stop(self): 111 151 "Mark as stopped" … … 127 167 128 168 self.__process_next() 129 169 130 170 self.updating = True 131 171 132 172 def start_download(self): 133 173 """ … … 145 185 146 186 self.__process_next_download() 147 187 148 188 self.updating = True 149 189 150 190 def __process_next_download(self): 151 191 """ … … 155 195 if not self.update_lst: 156 196 return 157 197 158 198 obj = self.update_lst.pop(0) 159 199 160 200 try: 161 201 user_dir = os.path.join(Path.config_dir) 162 202 filename = os.path.basename(obj.object.reader.get_path()) 163 203 164 204 obj.fd = open(mkstemp(".part", filename, \ 165 205 os.path.join(user_dir, "plugins-download"))[1], "wb+") 166 167 Network.get_url(obj.url, self.__process_plugin, obj) 206 207 Network.get_url( 208 # Maybe too long string? :P 209 obj.updates[obj.selected_update_idx].url[obj.last_update_idx], 210 self.__process_plugin, obj 211 ) 168 212 except Exception, err: 169 213 obj.status = FILE_ERROR 170 214 obj.label = err 171 215 obj.fract = None 172 216 173 217 self.__process_next_download() 174 218 219 def __remove_file(self, obj): 220 try: 221 obj.fd.close() 222 os.remove(obj.fd.name) 223 except: 224 log.error('Error while removing temp %s file' % obj.fd.name) 225 175 226 def __process_plugin(self, file, data, exc, obj): 176 227 """ … … 182 233 183 234 try: 184 obj.status = FILE_ERROR 185 obj.label = exc.reason 186 obj.fract = 1 187 235 if obj.last_update_idx + 1 < \ 236 len(obj.updates[obj.selected_update_idx].url): 237 238 obj.last_update_idx += 1 239 240 obj.status = FILE_GETTING 241 obj.label = _('Cycling to next update url. Waiting...') 242 else: 243 obj.status = FILE_ERROR 244 obj.label = _('Download failed: %s') % str(exc.reason) 245 obj.fract = 1 246 247 self.__remove_file(obj) 248 188 249 self.__process_next_download() 189 250 return 190 251 finally: 191 252 obj.lock.release() 192 253 193 254 elif isinstance(exc, StopNetException): 194 if obj.hash: 255 #TODO: CHECK THIS 256 if obj.updates[obj.selected_update_idx].integrity: 195 257 196 258 data = "" … … 200 262 obj.label = _('Checking validity ...') 201 263 obj.status = FILE_CHECKING 202 264 203 265 obj.fd.flush() 204 266 obj.fd.seek(0) … … 207 269 finally: 208 270 obj.lock.release() 209 271 210 272 # Not locked it could freeze the ui 211 hasher = md5(data) 212 273 md5_hash = sha_hash = None 274 sums = obj.updates[obj.selected_update_idx].integrity 275 276 if 'md5' in sums: 277 md5_hash = md5(data) 278 if 'sha1' in sums: 279 sha_hash = sha(data) 280 213 281 obj.lock.acquire() 214 282 215 283 try: 216 if hasher.hexdigest() == obj.hash: 284 if (md5_hash and md5_hash.hexdigest() == sums['md5']) or \ 285 (sha_hash and sha_hash.hexdigest() == sums['sha1']): 286 217 287 obj.label = _('Updated. Restart to take effect') 218 288 obj.status = FILE_GETTED … … 231 301 finally: 232 302 obj.lock.release() 233 303 234 304 obj.lock.acquire() 235 305 … … 239 309 finally: 240 310 obj.lock.release() 241 311 242 312 try: 243 313 if obj.status == FILE_ERROR: … … 249 319 # TODO: add more sensed control? 250 320 pass 251 321 252 322 self.__process_next() 253 323 254 324 elif isinstance(exc, StartNetException): 255 325 obj.lock.acquire() … … 262 332 except: 263 333 pass 264 334 265 335 obj.label = _('Downloading ...') 266 336 finally: … … 272 342 obj.fract = float(obj.size) / float(obj.total) 273 343 obj.fd.write(data) 274 344 275 345 def __process_next(self): 276 346 """ … … 280 350 if not self.update_lst: 281 351 return 282 352 283 353 obj = self.update_lst.pop(0) 284 Network.get_url("%s/latest.xml" % obj.object.reader.update, \ 354 obj.label = _('Downloading update information...') 355 356 Network.get_url("%s/latest.xml" % \ 357 obj.object.reader.update[obj.last_update_idx], \ 285 358 self.__process_manifest, obj) 286 359 … … 295 368 296 369 try: 297 obj.status = LATEST_ERROR 298 obj.label = _('Cannot find newer version (%s)') % exc.reason 299 370 if obj.last_update_idx + 1 < len(obj.object.reader.update): 371 obj.last_update_idx += 1 372 373 obj.status = LATEST_GETTING 374 obj.label = _('Cycling to next update url. Waiting...') 375 376 self.update_lst.append(obj) 377 elif isinstance(exc, ErrorNetException): 378 obj.status = LATEST_ERROR 379 obj.label = _('Cannot find newer version (%s)') % exc.reason 380 300 381 self.__process_next() 301 382 return 302 383 finally: 303 384 obj.lock.release() 304 385 305 386 elif isinstance(exc, StopNetException): 306 url, version, hash = obj.parse_latest_file() 307 308 new_v = Version(version) 309 cur_v = Version(obj.object.reader.version) 310 387 try: 388 obj.parse_latest_file() 389 except Exception, exc: 390 391 if obj.last_update_idx + 1 < len(obj.object.reader.update): 392 obj.last_update_idx += 1 393 394 obj.status = LATEST_GETTING 395 obj.label = _('Cycling to next update url. Waiting...') 396 397 self.update_lst.append(obj) 398 else: 399 obj.status = LATEST_ERROR 400 obj.label = _('Cannot find newer version (%s)') % str(exc) 401 402 self.__process_next() 403 return 404 405 version = None 311 406 type = -1 # -1 no action / 0 update / 1 downgrade 312 407 313 if new_v > cur_v: 314 type = 0 315 elif cur_v < new_v: 316 type = 1 408 # If we have only 1 update.. 409 if len(obj.updates) == 1: 410 version = obj.updates[0].version 411 412 new_v = Version(version) 413 cur_v = Version(obj.object.reader.version) 414 415 if new_v > cur_v: 416 type = 0 417 elif cur_v < new_v: 418 type = 1 317 419 318 420 obj.lock.acquire() 319 421 320 422 try: 321 if url and version and type >= 0:423 if obj.updates: 322 424 323 425 # We check if the path is the plugins in config_dir … … 330 432 obj.status = LATEST_ERROR 331 433 332 if not type: 333 obj.label = _('Version %s avaiable but need manual update.') % version 334 else: 335 obj.label = _('Version %s avaiable but need manual downgrade.') % version 434 if type == -1: 435 obj.label = _('Various versions available but require manual intervention.') 436 elif type == 0: 437 obj.label = _('Version %s available but need manual update.') % version 438 elif type == 1: 439 obj.label = _('Version %s available but need manual downgrade.') % version 336 440 else: 337 441 obj.status = LATEST_GETTED 338 obj.label = _('Version %s avaiable.') % version339 340 obj.version = version341 obj.url = url342 obj.hash = hash 442 if type == -1: 443 obj.label = _('Various versions available') 444 else: 445 obj.label = _('Version %s available.') % version 446 343 447 else: 344 448 obj.status = LATEST_ERROR … … 355 459 elif not exc: 356 460 obj.buffer.append(data) 357 461 358 462 def get_list(self): 359 463 "Getter for list" 360 464 return self.static_lst 361 465 362 466 def set_list(self, value): 363 467 "Setter for list" 364 468 lst = [] 365 469 366 470 for iter in value: 367 471 if isinstance(iter, UpdateObject): … … 369 473 else: 370 474 lst.append(UpdateObject(iter)) 371 475 372 476 self.update_lst = lst 373 477 self.static_lst = tuple(self.update_lst) 374 478 375 479 list = property(get_list, set_list) 480 481 if __name__ == "__main__": 482 parser = make_parser() 483 loader = UpdateObject(1) 484 parser.setContentHandler(loader) 485 parser.parse(open('test.xml')) 486 print loader.updates
