Package entropy :: Module qa

Source Code for Module entropy.qa

  1  # -*- coding: utf-8 -*- 
  2  ''' 
  3      # DESCRIPTION: 
  4      # Entropy Object Oriented Interface 
  5   
  6      Copyright (C) 2007-2009 Fabio Erculiani 
  7   
  8      This program is free software; you can redistribute it and/or modify 
  9      it under the terms of the GNU General Public License as published by 
 10      the Free Software Foundation; either version 2 of the License, or 
 11      (at your option) any later version. 
 12   
 13      This program is distributed in the hope that it will be useful, 
 14      but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16      GNU General Public License for more details. 
 17   
 18      You should have received a copy of the GNU General Public License 
 19      along with this program; if not, write to the Free Software 
 20      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 21  ''' 
 22  # pylint ~ok 
 23  import os 
 24  from entropy.const import etpConst 
 25  from entropy.output import blue, darkgreen, red, darkred, bold, purple, brown 
 26  from entropy.exceptions import IncorrectParameter, PermissionDenied 
 27  from entropy.i18n import _ 
 28  from entropy.core import SystemSettings 
 29   
30 -class QAInterface:
31 32 import entropy.tools as entropyTools 33 from entropy.misc import Lifo
34 - def __init__(self, OutputInterface):
35 36 self.Output = OutputInterface 37 self.SystemSettings = SystemSettings() 38 39 if not hasattr(self.Output, 'updateProgress'): 40 mytxt = _("Output interface has no updateProgress method") 41 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,)) 42 elif not callable(self.Output.updateProgress): 43 mytxt = _("Output interface has no updateProgress method") 44 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,))
45
46 - def test_depends_linking(self, idpackages, dbconn, repo = None):
47 48 repo = self.SystemSettings['repositories']['default_repository'] 49 50 scan_msg = blue(_("Now searching for broken depends")) 51 self.Output.updateProgress( 52 "[repo:%s] %s..." % ( 53 darkgreen(repo), 54 scan_msg, 55 ), 56 importance = 1, 57 type = "info", 58 header = red(" @@ ") 59 ) 60 61 broken = False 62 63 count = 0 64 maxcount = len(idpackages) 65 for idpackage in idpackages: 66 count += 1 67 atom = dbconn.retrieveAtom(idpackage) 68 scan_msg = "%s, %s:" % ( 69 blue(_("scanning for broken depends")), 70 darkgreen(atom), 71 ) 72 self.Output.updateProgress( 73 "[repo:%s] %s" % ( 74 darkgreen(repo), 75 scan_msg, 76 ), 77 importance = 1, 78 type = "info", 79 header = blue(" @@ "), 80 back = True, 81 count = (count, maxcount,) 82 ) 83 mydepends = dbconn.retrieveDepends(idpackage) 84 if not mydepends: 85 continue 86 for mydepend in mydepends: 87 myatom = dbconn.retrieveAtom(mydepend) 88 self.Output.updateProgress( 89 "[repo:%s] %s => %s" % ( 90 darkgreen(repo), 91 darkgreen(atom), 92 darkred(myatom), 93 ), 94 importance = 0, 95 type = "info", 96 header = blue(" @@ "), 97 back = True, 98 count = (count, maxcount,) 99 ) 100 mycontent = dbconn.retrieveContent(mydepend) 101 mybreakages = self.content_test(mycontent) 102 if not mybreakages: 103 continue 104 broken = True 105 self.Output.updateProgress( 106 "[repo:%s] %s %s => %s" % ( 107 darkgreen(repo), 108 darkgreen(atom), 109 darkred(myatom), 110 bold(_("broken libraries detected")), 111 ), 112 importance = 1, 113 type = "warning", 114 header = purple(" @@ "), 115 count = (count, maxcount,) 116 ) 117 for mylib in mybreakages: 118 self.Output.updateProgress( 119 "%s %s:" % ( 120 darkgreen(mylib), 121 red(_("needs")), 122 ), 123 importance = 1, 124 type = "warning", 125 header = brown(" ## ") 126 ) 127 for needed in mybreakages[mylib]: 128 self.Output.updateProgress( 129 "%s" % ( 130 red(needed), 131 ), 132 importance = 1, 133 type = "warning", 134 header = purple(" # ") 135 ) 136 return broken
137 138
139 - def scan_missing_dependencies(self, idpackages, dbconn, ask = True, 140 self_check = False, repo = None, black_list = None, 141 black_list_adder = None):
142 143 if repo == None: 144 repo = self.SystemSettings['repositories']['default_repository'] 145 146 if not isinstance(black_list, set): 147 black_list = set() 148 149 taint = False 150 scan_msg = blue(_("Now searching for missing RDEPENDs")) 151 self.Output.updateProgress( 152 "[repo:%s] %s..." % ( 153 darkgreen(repo), 154 scan_msg, 155 ), 156 importance = 1, 157 type = "info", 158 header = red(" @@ ") 159 ) 160 scan_msg = blue(_("scanning for missing RDEPENDs")) 161 count = 0 162 maxcount = len(idpackages) 163 for idpackage in idpackages: 164 count += 1 165 atom = dbconn.retrieveAtom(idpackage) 166 if not atom: 167 continue 168 self.Output.updateProgress( 169 "[repo:%s] %s: %s" % ( 170 darkgreen(repo), 171 scan_msg, 172 darkgreen(atom), 173 ), 174 importance = 1, 175 type = "info", 176 header = blue(" @@ "), 177 back = True, 178 count = (count, maxcount,) 179 ) 180 missing_extended, missing = self.get_missing_rdepends(dbconn, 181 idpackage, self_check = self_check) 182 missing -= black_list 183 for item in missing_extended.keys(): 184 missing_extended[item] -= black_list 185 if not missing_extended[item]: 186 del missing_extended[item] 187 if (not missing) or (not missing_extended): 188 continue 189 self.Output.updateProgress( 190 "[repo:%s] %s: %s %s:" % ( 191 darkgreen(repo), 192 blue("package"), 193 darkgreen(atom), 194 blue(_("is missing the following dependencies")), 195 ), 196 importance = 1, 197 type = "info", 198 header = red(" @@ "), 199 count = (count, maxcount,) 200 ) 201 for missing_data in missing_extended: 202 self.Output.updateProgress( 203 "%s:" % (brown(unicode(missing_data)),), 204 importance = 0, 205 type = "info", 206 header = purple(" ## ") 207 ) 208 for dependency in missing_extended[missing_data]: 209 self.Output.updateProgress( 210 "%s" % (darkred(dependency),), 211 importance = 0, 212 type = "info", 213 header = blue(" # ") 214 ) 215 if ask: 216 rc_ask = self.Output.askQuestion(_("Do you want to add them?")) 217 if rc_ask == "No": 218 continue 219 rc_ask = self.Output.askQuestion(_("Selectively?")) 220 if rc_ask == "Yes": 221 newmissing = set() 222 new_blacklist = set() 223 for dependency in missing: 224 self.Output.updateProgress( 225 "[repo:%s|%s] %s" % ( 226 darkgreen(repo), 227 brown(atom), 228 blue(dependency), 229 ), 230 importance = 0, 231 type = "info", 232 header = blue(" @@ ") 233 ) 234 rc_ask = self.Output.askQuestion(_("Want to add?")) 235 if rc_ask == "Yes": 236 newmissing.add(dependency) 237 else: 238 rc_ask = self.Output.askQuestion( 239 _("Want to blacklist?")) 240 if rc_ask == "Yes": 241 new_blacklist.add(dependency) 242 if new_blacklist and (black_list_adder != None): 243 black_list_adder(new_blacklist, repo = repo) 244 missing = newmissing 245 if missing: 246 taint = True 247 dbconn.insertDependencies(idpackage, missing) 248 dbconn.commitChanges() 249 self.Output.updateProgress( 250 "[repo:%s] %s: %s" % ( 251 darkgreen(repo), 252 darkgreen(atom), 253 blue(_("missing dependencies added")), 254 ), 255 importance = 1, 256 type = "info", 257 header = red(" @@ "), 258 count = (count, maxcount,) 259 ) 260 261 return taint
262
263 - def content_test(self, mycontent):
264 265 def is_contained(needed, content): 266 for item in content: 267 if os.path.basename(item) == needed: 268 return True 269 return False
270 271 mylibs = {} 272 for myfile in mycontent: 273 myfile = myfile.encode('raw_unicode_escape') 274 if not os.access(myfile, os.R_OK): 275 continue 276 if not os.path.isfile(myfile): 277 continue 278 if not self.entropyTools.is_elf_file(myfile): 279 continue 280 mylibs[myfile] = self.entropyTools.read_elf_dynamic_libraries( 281 myfile) 282 283 broken_libs = {} 284 for mylib in mylibs: 285 for myneeded in mylibs[mylib]: 286 # is this inside myself ? 287 if is_contained(myneeded, mycontent): 288 continue 289 found = self.resolve_dynamic_library(myneeded, mylib) 290 if found: 291 continue 292 if not broken_libs.has_key(mylib): 293 broken_libs[mylib] = set() 294 broken_libs[mylib].add(myneeded) 295 296 return broken_libs
297
298 - def resolve_dynamic_library(self, library, requiring_executable):
299 300 def do_resolve(mypaths): 301 found_path = None 302 for mypath in mypaths: 303 mypath = os.path.join(etpConst['systemroot']+mypath, library) 304 if not os.access(mypath, os.R_OK): 305 continue 306 if os.path.isdir(mypath): 307 continue 308 if not self.entropyTools.is_elf_file(mypath): 309 continue 310 found_path = mypath 311 break 312 return found_path
313 314 mypaths = self.entropyTools.collect_linker_paths() 315 found_path = do_resolve(mypaths) 316 317 if not found_path: 318 mypaths = self.entropyTools.read_elf_linker_paths( 319 requiring_executable) 320 found_path = do_resolve(mypaths) 321 322 return found_path 323
324 - def get_missing_rdepends(self, dbconn, idpackage, self_check = False):
325 326 rdepends = {} 327 rdepends_plain = set() 328 neededs = dbconn.retrieveNeeded(idpackage, extended = True) 329 ldpaths = set(self.entropyTools.collect_linker_paths()) 330 deps_content = set() 331 dependencies = self.get_deep_dependency_list(dbconn, idpackage, 332 atoms = True) 333 scope_cache = set() 334 335 def update_depscontent(mycontent, dbconn, ldpaths): 336 return set( \ 337 [x for x in mycontent if os.path.dirname(x) in ldpaths \ 338 and (dbconn.isNeededAvailable(os.path.basename(x)) > 0) ])
339 340 def is_in_content(myneeded, content): 341 for item in content: 342 item = os.path.basename(item) 343 if myneeded == item: 344 return True 345 return False 346 347 for dependency in dependencies: 348 match = dbconn.atomMatch(dependency) 349 if match[0] != -1: 350 mycontent = dbconn.retrieveContent(match[0]) 351 deps_content |= update_depscontent(mycontent, dbconn, ldpaths) 352 key, slot = dbconn.retrieveKeySlot(match[0]) 353 scope_cache.add((key, slot)) 354 355 key, slot = dbconn.retrieveKeySlot(idpackage) 356 mycontent = dbconn.retrieveContent(idpackage) 357 deps_content |= update_depscontent(mycontent, dbconn, ldpaths) 358 scope_cache.add((key, slot)) 359 360 idpackages_cache = set() 361 idpackage_map = {} 362 idpackage_map_reverse = {} 363 for needed, elfclass in neededs: 364 data_solved = dbconn.resolveNeeded(needed, elfclass) 365 data_size = len(data_solved) 366 data_solved = set([x for x in data_solved if x[0] \ 367 not in idpackages_cache]) 368 if not data_solved or (data_size != len(data_solved)): 369 continue 370 371 if self_check: 372 if is_in_content(needed, mycontent): 373 continue 374 375 found = False 376 for data in data_solved: 377 if data[1] in deps_content: 378 found = True 379 break 380 if not found: 381 for data in data_solved: 382 r_idpackage = data[0] 383 key, slot = dbconn.retrieveKeySlot(r_idpackage) 384 if (key, slot) not in scope_cache: 385 if not dbconn.isSystemPackage(r_idpackage): 386 if not rdepends.has_key((needed, elfclass)): 387 rdepends[(needed, elfclass)] = set() 388 if not idpackage_map.has_key((needed, elfclass)): 389 idpackage_map[(needed, elfclass)] = set() 390 keyslot = "%s:%s" % (key, slot,) 391 obj = idpackage_map_reverse.setdefault( 392 keyslot, set()) 393 obj.add((needed, elfclass,)) 394 rdepends[(needed, elfclass)].add(keyslot) 395 idpackage_map[(needed, elfclass)].add(r_idpackage) 396 rdepends_plain.add(keyslot) 397 idpackages_cache.add(r_idpackage) 398 399 # now reduce dependencies 400 401 r_deplist = set() 402 for key in idpackage_map: 403 r_idpackages = idpackage_map.get(key) 404 for r_idpackage in r_idpackages: 405 r_deplist |= dbconn.retrieveDependencies(r_idpackage) 406 407 r_keyslots = set() 408 for r_dep in r_deplist: 409 m_idpackage, m_rc = dbconn.atomMatch(r_dep) 410 if m_rc != 0: 411 continue 412 keyslot = dbconn.retrieveKeySlotAggregated(m_idpackage) 413 if keyslot in rdepends_plain: 414 r_keyslots.add(keyslot) 415 416 rdepends_plain -= r_keyslots 417 for r_keyslot in r_keyslots: 418 keys = [x for x in idpackage_map_reverse.get(keyslot, set()) if \ 419 x in rdepends] 420 for key in keys: 421 rdepends[key].discard(r_keyslot) 422 if not rdepends[key]: 423 del rdepends[key] 424 425 return rdepends, rdepends_plain 426
427 - def get_deep_dependency_list(self, dbconn, idpackage, atoms = False):
428 429 mybuffer = self.Lifo() 430 matchcache = set() 431 depcache = set() 432 mydeps = dbconn.retrieveDependencies(idpackage) 433 for mydep in mydeps: 434 mybuffer.push(mydep) 435 mydep = mybuffer.pop() 436 437 while mydep: 438 439 if mydep in depcache: 440 mydep = mybuffer.pop() 441 continue 442 443 my_idpackage, my_rc = dbconn.atomMatch(mydep) 444 if atoms: 445 matchcache.add(mydep) 446 else: 447 matchcache.add(my_idpackage) 448 449 if my_idpackage != -1: 450 owndeps = dbconn.retrieveDependencies(my_idpackage) 451 for owndep in owndeps: 452 mybuffer.push(owndep) 453 454 depcache.add(mydep) 455 mydep = mybuffer.pop() 456 457 # always discard -1 in set 458 matchcache.discard(-1) 459 return matchcache
460
461 -class ErrorReportInterface:
462 463 import entropy.tools as entropyTools
464 - def __init__(self, post_url = etpConst['handlers']['errorsend']):
465 from entropy.misc import MultipartPostHandler 466 import urllib2 467 self.url = post_url 468 self.opener = urllib2.build_opener(MultipartPostHandler) 469 self.generated = False 470 self.params = {} 471 472 sys_settings = SystemSettings() 473 proxy_settings = sys_settings['system']['proxy'] 474 mydict = {} 475 if proxy_settings['ftp']: 476 mydict['ftp'] = proxy_settings['ftp'] 477 if proxy_settings['http']: 478 mydict['http'] = proxy_settings['http'] 479 if mydict: 480 mydict['username'] = proxy_settings['username'] 481 mydict['password'] = proxy_settings['password'] 482 self.entropyTools.add_proxy_opener(urllib2, mydict) 483 else: 484 # unset 485 urllib2._opener = None
486
487 - def prepare(self, tb_text, name, email, report_data = "", description = ""):
488 489 import sys 490 from entropy.tools import getstatusoutput 491 self.params['arch'] = etpConst['currentarch'] 492 self.params['stacktrace'] = tb_text 493 self.params['name'] = name 494 self.params['email'] = email 495 self.params['version'] = etpConst['entropyversion'] 496 self.params['errordata'] = report_data 497 self.params['description'] = description 498 self.params['arguments'] = ' '.join(sys.argv) 499 self.params['uid'] = etpConst['uid'] 500 self.params['system_version'] = "N/A" 501 if os.access(etpConst['systemreleasefile'], os.R_OK): 502 f_rel = open(etpConst['systemreleasefile'], "r") 503 self.params['system_version'] = f_rel.readline().strip() 504 f_rel.close() 505 506 self.params['processes'] = getstatusoutput('ps auxf')[1] 507 self.params['lspci'] = getstatusoutput('/usr/sbin/lspci')[1] 508 self.params['dmesg'] = getstatusoutput('dmesg')[1] 509 self.params['locale'] = getstatusoutput('locale -v')[1] 510 511 self.generated = True
512 513 # params is a dict, key(HTTP post item name): value
514 - def submit(self):
515 if self.generated: 516 result = self.opener.open(self.url, self.params).read() 517 if result.strip() == "1": 518 return True 519 return False 520 else: 521 mytxt = _("Not prepared yet") 522 raise PermissionDenied("PermissionDenied: %s" % (mytxt,))
523