Package entropy :: Package client :: Package interfaces :: Module methods

Source Code for Module entropy.client.interfaces.methods

   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  from __future__ import with_statement 
  23  import os 
  24  import sys 
  25  import shutil 
  26  import time 
  27  import subprocess 
  28  from entropy.i18n import _ 
  29  from entropy.const import * 
  30  from entropy.exceptions import * 
  31  from entropy.db import dbapi2, LocalRepository 
  32  from entropy.output import purple, bold, red, blue, darkgreen, darkred, brown 
  33   
  34   
35 -class RepositoryMixin:
36 37 __repo_error_messages_cache = set() 38 __repodb_cache = {} 39 _memory_db_instances = {} 40
41 - def validate_repositories(self):
42 self.MirrorStatus.clear() 43 self.__repo_error_messages_cache.clear() 44 cl_id = self.sys_settings_client_plugin_id 45 self.SystemSettings[cl_id]['masking_validation']['cache'].clear() 46 # valid repositories 47 del self.validRepositories[:] 48 for repoid in self.SystemSettings['repositories']['order']: 49 # open database 50 try: 51 dbc = self.open_repository(repoid) 52 dbc.listConfigProtectDirectories() 53 dbc.validateDatabase() 54 self.validRepositories.append(repoid) 55 except RepositoryError: 56 t = _("Repository") + " " + repoid + " " + _("is not available") + ". " + _("Cannot validate") 57 t2 = _("Please update your repositories now in order to remove this message!") 58 self.updateProgress( 59 darkred(t), 60 importance = 1, 61 type = "warning" 62 ) 63 self.updateProgress( 64 purple(t2), 65 header = bold("!!! "), 66 importance = 1, 67 type = "warning" 68 ) 69 continue # repo not available 70 except (self.dbapi2.OperationalError,self.dbapi2.DatabaseError,SystemDatabaseError,): 71 t = _("Repository") + " " + repoid + " " + _("is corrupted") + ". " + _("Cannot validate") 72 self.updateProgress( 73 darkred(t), 74 importance = 1, 75 type = "warning" 76 ) 77 continue 78 # to avoid having zillions of open files when loading a lot of EquoInterfaces 79 self.close_all_repositories(mask_clear = False)
80
81 - def __get_repository_cache_key(self, repoid):
82 return (repoid, etpConst['systemroot'],)
83
84 - def init_generic_memory_repository(self, repoid, description, package_mirrors = []):
85 dbc = self.open_memory_database(dbname = repoid) 86 repo_key = self.__get_repository_cache_key(repoid) 87 self._memory_db_instances[repo_key] = dbc 88 89 # add to self.SystemSettings['repositories']['available'] 90 repodata = { 91 'repoid': repoid, 92 'in_memory': True, 93 'description': description, 94 'packages': package_mirrors, 95 'dbpath': ':memory:', 96 } 97 self.add_repository(repodata) 98 return dbc
99
100 - def close_all_repositories(self, mask_clear = True):
101 for item in self.__repodb_cache: 102 # in-memory repositories cannot be closed 103 # otherwise everything will be lost, to 104 # effectively close these repos you 105 # must call remove_repository method 106 if item in self._memory_db_instances: 107 continue 108 self.__repodb_cache[item].closeDB() 109 self.__repodb_cache.clear() 110 if mask_clear: self.SystemSettings.clear()
111
112 - def is_repository_connection_cached(self, repoid):
113 if (repoid,etpConst['systemroot'],) in self.__repodb_cache: 114 return True 115 return False
116
117 - def open_repository(self, repoid):
118 119 key = self.__get_repository_cache_key(repoid) 120 if not self.__repodb_cache.has_key(key): 121 dbconn = self.load_repository_database(repoid, xcache = self.xcache, 122 indexing = self.indexing) 123 try: 124 dbconn.checkDatabaseApi() 125 except (self.dbapi2.OperationalError, TypeError,): 126 pass 127 self.__repodb_cache[key] = dbconn 128 return dbconn 129 return self.__repodb_cache.get(key)
130
131 - def load_repository_database(self, repoid, xcache = True, indexing = True):
132 133 if isinstance(repoid,basestring): 134 if repoid.endswith(etpConst['packagesext']): 135 xcache = False 136 137 repo_data = self.SystemSettings['repositories']['available'] 138 if repoid not in repo_data: 139 t = _("bad repository id specified") 140 if repoid not in self.__repo_error_messages_cache: 141 self.updateProgress( 142 darkred(t), 143 importance = 2, 144 type = "warning" 145 ) 146 self.__repo_error_messages_cache.add(repoid) 147 raise RepositoryError("RepositoryError: %s" % (t,)) 148 149 if repo_data[repoid].get('in_memory'): 150 repo_key = self.__get_repository_cache_key(repoid) 151 conn = self._memory_db_instances.get(repo_key) 152 else: 153 dbfile = repo_data[repoid]['dbpath']+"/"+etpConst['etpdatabasefile'] 154 if not os.path.isfile(dbfile): 155 t = _("Repository %s hasn't been downloaded yet.") % (repoid,) 156 if repoid not in self.__repo_error_messages_cache: 157 self.updateProgress( 158 darkred(t), 159 importance = 2, 160 type = "warning" 161 ) 162 self.__repo_error_messages_cache.add(repoid) 163 raise RepositoryError("RepositoryError: %s" % (t,)) 164 165 conn = LocalRepository( 166 readOnly = True, 167 dbFile = dbfile, 168 clientDatabase = True, 169 dbname = etpConst['dbnamerepoprefix']+repoid, 170 xcache = xcache, 171 indexing = indexing, 172 OutputInterface = self, 173 ServiceInterface = self 174 ) 175 176 if (repoid not in etpConst['client_treeupdatescalled']) and \ 177 (self.entropyTools.is_root()) and \ 178 (not repoid.endswith(etpConst['packagesext'])): 179 # only as root due to Portage 180 updated = False 181 try: 182 updated = conn.clientUpdatePackagesData(self.clientDbconn) 183 except (self.dbapi2.OperationalError, self.dbapi2.DatabaseError): 184 pass 185 if updated: 186 self.clear_dump_cache(etpCache['world_update']) 187 self.clear_dump_cache(etpCache['world']) 188 self.clear_dump_cache(etpCache['install']) 189 self.clear_dump_cache(etpCache['remove']) 190 self.calculate_world_updates(use_cache = False) 191 return conn
192
193 - def get_repository_revision(self, reponame):
194 fname = self.SystemSettings['repositories']['available'][reponame]['dbpath']+"/"+etpConst['etpdatabaserevisionfile'] 195 revision = -1 196 if os.path.isfile(fname) and os.access(fname,os.R_OK): 197 with open(fname,"r") as f: 198 try: 199 revision = int(f.readline().strip()) 200 except (OSError, IOError, ValueError,): 201 pass 202 return revision
203
204 - def update_repository_revision(self, reponame):
205 r = self.get_repository_revision(reponame) 206 self.SystemSettings['repositories']['available'][reponame]['dbrevision'] = "0" 207 if r != -1: 208 self.SystemSettings['repositories']['available'][reponame]['dbrevision'] = str(r)
209
210 - def get_repository_db_file_checksum(self, reponame):
211 fname = self.SystemSettings['repositories']['available'][reponame]['dbpath']+"/"+etpConst['etpdatabasehashfile'] 212 mhash = "-1" 213 if os.path.isfile(fname) and os.access(fname,os.R_OK): 214 with open(fname,"r") as f: 215 try: 216 mhash = f.readline().strip().split()[0] 217 except (OSError, IOError, IndexError,): 218 pass 219 return mhash
220
221 - def add_repository(self, repodata):
222 product = self.SystemSettings['repositories']['product'] 223 branch = self.SystemSettings['repositories']['branch'] 224 # update self.SystemSettings['repositories']['available'] 225 try: 226 self.SystemSettings['repositories']['available'][repodata['repoid']] = {} 227 self.SystemSettings['repositories']['available'][repodata['repoid']]['description'] = repodata['description'] 228 except KeyError: 229 t = _("repodata dictionary is corrupted") 230 raise InvalidData("InvalidData: %s" % (t,)) 231 232 if repodata['repoid'].endswith(etpConst['packagesext']) or repodata.get('in_memory'): # dynamic repository 233 try: 234 # no need # self.SystemSettings['repositories']['available'][repodata['repoid']]['plain_packages'] = repodata['plain_packages'][:] 235 self.SystemSettings['repositories']['available'][repodata['repoid']]['packages'] = repodata['packages'][:] 236 smart_package = repodata.get('smartpackage') 237 if smart_package != None: 238 self.SystemSettings['repositories']['available'][repodata['repoid']]['smartpackage'] = smart_package 239 except KeyError: 240 raise InvalidData("InvalidData: repodata dictionary is corrupted") 241 self.SystemSettings['repositories']['available'][repodata['repoid']]['dbpath'] = repodata.get('dbpath') 242 self.SystemSettings['repositories']['available'][repodata['repoid']]['pkgpath'] = repodata.get('pkgpath') 243 self.SystemSettings['repositories']['available'][repodata['repoid']]['in_memory'] = repodata.get('in_memory') 244 # put at top priority, shift others 245 self.SystemSettings['repositories']['order'].insert(0, repodata['repoid']) 246 else: 247 # XXX it's boring to keep this in sync with entropyConstants stuff, solutions? 248 self.SystemSettings['repositories']['available'][repodata['repoid']]['plain_packages'] = repodata['plain_packages'][:] 249 self.SystemSettings['repositories']['available'][repodata['repoid']]['packages'] = [x+"/"+product for x in repodata['plain_packages']] 250 self.SystemSettings['repositories']['available'][repodata['repoid']]['plain_database'] = repodata['plain_database'] 251 self.SystemSettings['repositories']['available'][repodata['repoid']]['database'] = repodata['plain_database'] + \ 252 "/" + product + "/database/" + etpConst['currentarch'] + "/" + branch 253 if not repodata['dbcformat'] in etpConst['etpdatabasesupportedcformats']: 254 repodata['dbcformat'] = etpConst['etpdatabasesupportedcformats'][0] 255 self.SystemSettings['repositories']['available'][repodata['repoid']]['dbcformat'] = repodata['dbcformat'] 256 self.SystemSettings['repositories']['available'][repodata['repoid']]['dbpath'] = etpConst['etpdatabaseclientdir'] + \ 257 "/" + repodata['repoid'] + "/" + product + "/" + etpConst['currentarch'] + "/" + branch 258 # set dbrevision 259 myrev = self.get_repository_revision(repodata['repoid']) 260 if myrev == -1: 261 myrev = 0 262 self.SystemSettings['repositories']['available'][repodata['repoid']]['dbrevision'] = str(myrev) 263 if repodata.has_key("position"): 264 self.SystemSettings['repositories']['order'].insert( 265 repodata['position'], repodata['repoid']) 266 else: 267 self.SystemSettings['repositories']['order'].append( 268 repodata['repoid']) 269 if not repodata.has_key("service_port"): 270 repodata['service_port'] = int(etpConst['socket_service']['port']) 271 if not repodata.has_key("ssl_service_port"): 272 repodata['ssl_service_port'] = int(etpConst['socket_service']['ssl_port']) 273 self.SystemSettings['repositories']['available'][repodata['repoid']]['service_port'] = repodata['service_port'] 274 self.SystemSettings['repositories']['available'][repodata['repoid']]['ssl_service_port'] = repodata['ssl_service_port'] 275 self.repository_move_clear_cache(repodata['repoid']) 276 # save new self.SystemSettings['repositories']['available'] to file 277 self.entropyTools.save_repository_settings(repodata) 278 self.SystemSettings.clear() 279 self.close_all_repositories() 280 self.validate_repositories()
281
282 - def remove_repository(self, repoid, disable = False):
283 284 # ensure that all dbs are closed 285 self.close_all_repositories() 286 287 done = False 288 if self.SystemSettings['repositories']['available'].has_key(repoid): 289 del self.SystemSettings['repositories']['available'][repoid] 290 done = True 291 292 if self.SystemSettings['repositories']['excluded'].has_key(repoid): 293 del self.SystemSettings['repositories']['excluded'][repoid] 294 done = True 295 296 if done: 297 298 if repoid in self.SystemSettings['repositories']['order']: 299 self.SystemSettings['repositories']['order'].remove(repoid) 300 301 self.repository_move_clear_cache(repoid) 302 # save new self.SystemSettings['repositories']['available'] to file 303 repodata = {} 304 repodata['repoid'] = repoid 305 if disable: 306 self.entropyTools.save_repository_settings(repodata, disable = True) 307 else: 308 self.entropyTools.save_repository_settings(repodata, remove = True) 309 self.SystemSettings.clear() 310 311 repo_mem_key = self.__get_repository_cache_key(repoid) 312 mem_inst = self._memory_db_instances.pop(repo_mem_key, None) 313 if isinstance(mem_inst, LocalRepository): 314 mem_inst.closeDB() 315 316 # reset db cache 317 self.close_all_repositories() 318 self.validate_repositories()
319
320 - def shift_repository(self, repoid, toidx):
321 # update self.SystemSettings['repositories']['order'] 322 self.SystemSettings['repositories']['order'].remove(repoid) 323 self.SystemSettings['repositories']['order'].insert(toidx, repoid) 324 self.entropyTools.write_ordered_repositories_entries( 325 self.SystemSettings['repositories']['order']) 326 self.SystemSettings.clear() 327 self.close_all_repositories() 328 self.repository_move_clear_cache(repoid) 329 self.validate_repositories()
330
331 - def enable_repository(self, repoid):
332 self.repository_move_clear_cache(repoid) 333 # save new self.SystemSettings['repositories']['available'] to file 334 repodata = {} 335 repodata['repoid'] = repoid 336 self.entropyTools.save_repository_settings(repodata, enable = True) 337 self.SystemSettings.clear() 338 self.close_all_repositories() 339 self.validate_repositories()
340
341 - def disable_repository(self, repoid):
342 # update self.SystemSettings['repositories']['available'] 343 done = False 344 try: 345 del self.SystemSettings['repositories']['available'][repoid] 346 done = True 347 except: 348 pass 349 350 if done: 351 try: 352 self.SystemSettings['repositories']['order'].remove(repoid) 353 except (IndexError,): 354 pass 355 # it's not vital to reset 356 # self.SystemSettings['repositories']['order'] counters 357 358 self.repository_move_clear_cache(repoid) 359 # save new self.SystemSettings['repositories']['available'] to file 360 repodata = {} 361 repodata['repoid'] = repoid 362 self.entropyTools.save_repository_settings(repodata, disable = True) 363 self.SystemSettings.clear() 364 365 self.close_all_repositories() 366 self.validate_repositories()
367
368 - def get_repository_settings(self, repoid):
369 try: 370 repodata = self.SystemSettings['repositories']['available'][repoid].copy() 371 except KeyError: 372 if not self.SystemSettings['repositories']['excluded'].has_key(repoid): 373 raise 374 repodata = self.SystemSettings['repositories']['excluded'][repoid].copy() 375 return repodata
376 377 # every tbz2 file that would be installed must pass from here
378 - def add_tbz2_to_repos(self, tbz2file):
379 atoms_contained = [] 380 basefile = os.path.basename(tbz2file) 381 cut_idx = -1*(len(etpConst['packagesext'])) 382 db_dir = etpConst['entropyunpackdir']+"/"+basefile[:cut_idx] 383 if os.path.isdir(db_dir): 384 shutil.rmtree(db_dir) 385 os.makedirs(db_dir) 386 dbfile = self.entropyTools.extract_edb(tbz2file, 387 dbpath = db_dir+"/packages.db") 388 if dbfile == None: 389 return -1,atoms_contained 390 etpSys['dirstoclean'].add(os.path.dirname(dbfile)) 391 # add dbfile 392 repodata = {} 393 repodata['repoid'] = basefile 394 repodata['description'] = "Dynamic database from "+basefile 395 repodata['packages'] = [] 396 repodata['dbpath'] = os.path.dirname(dbfile) 397 repodata['pkgpath'] = os.path.realpath(tbz2file) # extra info added 398 repodata['smartpackage'] = False # extra info added 399 400 mydbconn = self.open_generic_database(dbfile) 401 # read all idpackages 402 try: 403 myidpackages = mydbconn.listAllIdpackages() # all branches admitted from external files 404 except (AttributeError, self.dbapi2.DatabaseError, \ 405 self.dbapi2.IntegrityError, self.dbapi2.OperationalError,): 406 return -2,atoms_contained 407 if len(myidpackages) > 1: 408 repodata[basefile]['smartpackage'] = True 409 for myidpackage in myidpackages: 410 compiled_arch = mydbconn.retrieveDownloadURL(myidpackage) 411 if compiled_arch.find("/"+etpSys['arch']+"/") == -1: 412 return -3,atoms_contained 413 atoms_contained.append((int(myidpackage),basefile)) 414 415 self.add_repository(repodata) 416 self.validate_repositories() 417 if basefile not in self.validRepositories: 418 self.remove_repository(basefile) 419 return -4,atoms_contained 420 mydbconn.closeDB() 421 del mydbconn 422 return 0,atoms_contained
423
424 - def reopen_client_repository(self):
425 self.clientDbconn.closeDB() 426 self.open_client_repository() 427 # make sure settings are in sync 428 self.SystemSettings.clear()
429
430 - def open_client_repository(self):
431 432 def load_db_from_ram(): 433 self.safe_mode = etpConst['safemodeerrors']['clientdb'] 434 mytxt = "%s, %s" % (_("System database not found or corrupted"), 435 _("running in safe mode using empty database from RAM"),) 436 self.updateProgress( 437 darkred(mytxt), 438 importance = 1, 439 type = "warning", 440 header = bold("!!!"), 441 ) 442 conn = self.open_memory_database(dbname = etpConst['clientdbid']) 443 return conn
444 445 db_dir = os.path.dirname(etpConst['etpdatabaseclientfilepath']) 446 if not os.path.isdir(db_dir): os.makedirs(db_dir) 447 448 db_path = etpConst['etpdatabaseclientfilepath'] 449 if (not self.noclientdb) and (not os.path.isfile(db_path)): 450 conn = load_db_from_ram() 451 self.entropyTools.print_traceback(f = self.clientLog) 452 else: 453 try: 454 conn = LocalRepository(readOnly = False, dbFile = db_path, 455 clientDatabase = True, dbname = etpConst['clientdbid'], 456 xcache = self.xcache, indexing = self.indexing, 457 OutputInterface = self, ServiceInterface = self 458 ) 459 except (self.dbapi2.DatabaseError,): 460 self.entropyTools.print_traceback(f = self.clientLog) 461 conn = load_db_from_ram() 462 else: 463 # validate database 464 if not self.noclientdb: 465 try: 466 conn.validateDatabase() 467 except SystemDatabaseError: 468 try: 469 conn.closeDB() 470 except: 471 pass 472 self.entropyTools.print_traceback(f = self.clientLog) 473 conn = load_db_from_ram() 474 475 self.clientDbconn = conn 476 return self.clientDbconn
477
478 - def client_repository_sanity_check(self):
479 self.updateProgress( 480 darkred(_("Sanity Check") + ": " + _("system database")), 481 importance = 2, 482 type = "warning" 483 ) 484 idpkgs = self.clientDbconn.listAllIdpackages() 485 length = len(idpkgs) 486 count = 0 487 errors = False 488 scanning_txt = _("Scanning...") 489 for x in idpkgs: 490 count += 1 491 self.updateProgress( 492 darkgreen(scanning_txt), 493 importance = 0, 494 type = "info", 495 back = True, 496 count = (count,length), 497 percent = True 498 ) 499 try: 500 self.clientDbconn.getPackageData(x) 501 except Exception ,e: 502 self.entropyTools.print_traceback() 503 errors = True 504 self.updateProgress( 505 darkred(_("Errors on idpackage %s, error: %s")) % (x,str(e)), 506 importance = 0, 507 type = "warning" 508 ) 509 510 if not errors: 511 t = _("Sanity Check") + ": %s" % (bold(_("PASSED")),) 512 self.updateProgress( 513 darkred(t), 514 importance = 2, 515 type = "warning" 516 ) 517 return 0 518 else: 519 t = _("Sanity Check") + ": %s" % (bold(_("CORRUPTED")),) 520 self.updateProgress( 521 darkred(t), 522 importance = 2, 523 type = "warning" 524 ) 525 return -1
526
527 - def open_generic_database(self, dbfile, dbname = None, xcache = None, 528 readOnly = False, indexing_override = None, skipChecks = False):
529 if xcache == None: 530 xcache = self.xcache 531 if indexing_override != None: 532 indexing = indexing_override 533 else: 534 indexing = self.indexing 535 if dbname == None: 536 dbname = etpConst['genericdbid'] 537 return LocalRepository( 538 readOnly = readOnly, 539 dbFile = dbfile, 540 clientDatabase = True, 541 dbname = dbname, 542 xcache = xcache, 543 indexing = indexing, 544 OutputInterface = self, 545 skipChecks = skipChecks 546 )
547
548 - def open_memory_database(self, dbname = None):
549 if dbname == None: 550 dbname = etpConst['genericdbid'] 551 dbc = LocalRepository( 552 readOnly = False, 553 dbFile = ':memory:', 554 clientDatabase = True, 555 dbname = dbname, 556 xcache = False, 557 indexing = False, 558 OutputInterface = self, 559 skipChecks = True, 560 ServiceInterface = self 561 ) 562 dbc.initializeDatabase() 563 return dbc
564
565 - def backup_database(self, dbpath, backup_dir = None, silent = False, compress_level = 9):
566 567 if compress_level not in range(1,10): 568 compress_level = 9 569 570 backup_dir = os.path.dirname(dbpath) 571 if not backup_dir: backup_dir = os.path.dirname(dbpath) 572 dbname = os.path.basename(dbpath) 573 bytes_required = 1024000*300 574 if not (os.access(backup_dir,os.W_OK) and \ 575 os.path.isdir(backup_dir) and os.path.isfile(dbpath) and \ 576 os.access(dbpath,os.R_OK) and self.entropyTools.check_required_space(backup_dir, bytes_required)): 577 if not silent: 578 mytxt = "%s: %s, %s" % (darkred(_("Cannot backup selected database")),blue(dbpath),darkred(_("permission denied")),) 579 self.updateProgress( 580 mytxt, 581 importance = 1, 582 type = "error", 583 header = red(" @@ ") 584 ) 585 return False, mytxt 586 587 def get_ts(): 588 from datetime import datetime 589 ts = datetime.fromtimestamp(time.time()) 590 return "%s%s%s_%sh%sm%ss" % (ts.year,ts.month,ts.day,ts.hour,ts.minute,ts.second)
591 592 comp_dbname = "%s%s.%s.bz2" % (etpConst['dbbackupprefix'],dbname,get_ts(),) 593 comp_dbpath = os.path.join(backup_dir,comp_dbname) 594 if not silent: 595 mytxt = "%s: %s ..." % (darkgreen(_("Backing up database to")),blue(comp_dbpath),) 596 self.updateProgress( 597 mytxt, 598 importance = 1, 599 type = "info", 600 header = blue(" @@ "), 601 back = True 602 ) 603 import bz2 604 try: 605 self.entropyTools.compress_file(dbpath, comp_dbpath, bz2.BZ2File, compress_level) 606 except: 607 if not silent: 608 self.entropyTools.print_traceback() 609 return False, _("Unable to compress") 610 611 if not silent: 612 mytxt = "%s: %s" % (darkgreen(_("Database backed up successfully")),blue(comp_dbpath),) 613 self.updateProgress( 614 mytxt, 615 importance = 1, 616 type = "info", 617 header = blue(" @@ "), 618 back = True 619 ) 620 return True, _("All fine") 621
622 - def restore_database(self, backup_path, db_destination, silent = False):
623 624 bytes_required = 1024000*300 625 db_dir = os.path.dirname(db_destination) 626 if not (os.access(db_dir,os.W_OK) and os.path.isdir(db_dir) and \ 627 os.path.isfile(backup_path) and os.access(backup_path,os.R_OK) and \ 628 self.entropyTools.check_required_space(db_dir, bytes_required)): 629 630 if not silent: 631 mytxt = "%s: %s, %s" % (darkred(_("Cannot restore selected backup")), 632 blue(backup_path),darkred(_("permission denied")),) 633 self.updateProgress( 634 mytxt, 635 importance = 1, 636 type = "error", 637 header = red(" @@ ") 638 ) 639 return False, mytxt 640 641 if not silent: 642 mytxt = "%s: %s => %s ..." % (darkgreen(_("Restoring backed up database")), 643 blue(os.path.basename(backup_path)),blue(db_destination),) 644 self.updateProgress( 645 mytxt, 646 importance = 1, 647 type = "info", 648 header = blue(" @@ "), 649 back = True 650 ) 651 652 import bz2 653 try: 654 self.entropyTools.uncompress_file(backup_path, db_destination, bz2.BZ2File) 655 except: 656 if not silent: 657 self.entropyTools.print_traceback() 658 return False, _("Unable to unpack") 659 660 if not silent: 661 mytxt = "%s: %s" % (darkgreen(_("Database restored successfully")), 662 blue(db_destination),) 663 self.updateProgress( 664 mytxt, 665 importance = 1, 666 type = "info", 667 header = blue(" @@ "), 668 back = True 669 ) 670 self.purge_cache() 671 return True, _("All fine")
672
673 - def list_backedup_client_databases(self, client_dbdir = None):
674 if not client_dbdir: 675 client_dbdir = os.path.dirname(etpConst['etpdatabaseclientfilepath']) 676 return [os.path.join(client_dbdir,x) for x in os.listdir(client_dbdir) \ 677 if x.startswith(etpConst['dbbackupprefix']) and \ 678 os.access(os.path.join(client_dbdir,x),os.R_OK) 679 ]
680
681 -class MiscMixin:
682
683 - def reload_constants(self):
686
687 - def setup_default_file_perms(self, filepath):
688 # setup file permissions 689 os.chmod(filepath,0664) 690 if etpConst['entropygid'] != None: 691 os.chown(filepath,-1,etpConst['entropygid'])
692
693 - def resources_create_lock(self):
694 self.create_pid_file_lock(etpConst['locks']['using_resources'])
695
696 - def resources_remove_lock(self):
697 if os.path.isfile(etpConst['locks']['using_resources']): 698 os.remove(etpConst['locks']['using_resources'])
699
700 - def resources_check_lock(self):
701 rc = self.check_pid_file_lock(etpConst['locks']['using_resources']) 702 return rc
703
704 - def check_pid_file_lock(self, pidfile):
705 if not os.path.isfile(pidfile): 706 return False # not locked 707 f = open(pidfile) 708 s_pid = f.readline().strip() 709 f.close() 710 try: 711 s_pid = int(s_pid) 712 except ValueError: 713 return False # not locked 714 # is it our pid? 715 mypid = os.getpid() 716 if (s_pid != mypid) and os.path.isdir("%s/proc/%s" % (etpConst['systemroot'],s_pid,)): 717 # is it running 718 return True # locked 719 return False
720
721 - def create_pid_file_lock(self, pidfile, mypid = None):
722 lockdir = os.path.dirname(pidfile) 723 if not os.path.isdir(lockdir): 724 os.makedirs(lockdir,0775) 725 const_setup_perms(lockdir,etpConst['entropygid']) 726 if mypid == None: 727 mypid = os.getpid() 728 f = open(pidfile,"w") 729 f.write(str(mypid)) 730 f.flush() 731 f.close()
732
733 - def application_lock_check(self, silent = False):
734 # check if another instance is running 735 etpConst['applicationlock'] = False 736 const_setup_entropy_pid(just_read = True) 737 locked = self.entropyTools.application_lock_check(option = None, gentle = True, silent = True) 738 if locked: 739 if not silent: 740 self.updateProgress( 741 red(_("Another Entropy instance is currently active, cannot satisfy your request.")), 742 importance = 1, 743 type = "error", 744 header = darkred(" @@ ") 745 ) 746 return True 747 return False
748
749 - def lock_check(self, check_function):
750 751 lock_count = 0 752 max_lock_count = 600 753 sleep_seconds = 0.5 754 755 # check lock file 756 while 1: 757 locked = check_function() 758 if not locked: 759 if lock_count > 0: 760 self.updateProgress( 761 blue(_("Resources unlocked, let's go!")), 762 importance = 1, 763 type = "info", 764 header = darkred(" @@ ") 765 ) 766 break 767 if lock_count >= max_lock_count: 768 mycalc = max_lock_count*sleep_seconds/60 769 self.updateProgress( 770 blue(_("Resources still locked after %s minutes, giving up!")) % (mycalc,), 771 importance = 1, 772 type = "warning", 773 header = darkred(" @@ ") 774 ) 775 return True # gave up 776 lock_count += 1 777 self.updateProgress( 778 blue(_("Resources locked, sleeping %s seconds, check #%s/%s")) % ( 779 sleep_seconds, 780 lock_count, 781 max_lock_count, 782 ), 783 importance = 1, 784 type = "warning", 785 header = darkred(" @@ "), 786 back = True 787 ) 788 time.sleep(sleep_seconds) 789 return False # yay!
790
791 - def backup_constant(self, constant_name):
792 if etpConst.has_key(constant_name): 793 myinst = etpConst[constant_name] 794 if type(etpConst[constant_name]) in (list,tuple): 795 myinst = etpConst[constant_name][:] 796 elif type(etpConst[constant_name]) in (dict,set): 797 myinst = etpConst[constant_name].copy() 798 else: 799 myinst = etpConst[constant_name] 800 etpConst['backed_up'].update({constant_name: myinst}) 801 else: 802 t = _("Nothing to backup in etpConst with %s key") % (constant_name,) 803 raise InvalidData("InvalidData: %s" % (t,))
804
805 - def set_priority(self, low = 0):
806 return const_set_nice_level(low)
807
808 - def reload_repositories_config(self, repositories = None):
809 if repositories == None: 810 repositories = self.validRepositories 811 for repoid in repositories: 812 dbconn = self.open_repository(repoid)
813
814 - def switch_chroot(self, chroot = ""):
815 # clean caches 816 self.purge_cache() 817 self.close_all_repositories() 818 if chroot.endswith("/"): 819 chroot = chroot[:-1] 820 etpSys['rootdir'] = chroot 821 self.reload_constants() 822 self.validate_repositories() 823 self.reopen_client_repository() 824 # keep them closed, since SystemSettings.clear() is called 825 # above on reopen_client_repository() 826 self.close_all_repositories() 827 if chroot: 828 try: 829 self.clientDbconn.resetTreeupdatesDigests() 830 except: 831 pass 832 # I don't think it's safe to keep them open 833 # isn't it? 834 self.closeAllSecurity() 835 self.closeAllQA()
836
837 - def get_file_viewer(self):
838 viewer = None 839 if os.access("/usr/bin/less",os.X_OK): 840 viewer = "/usr/bin/less" 841 elif os.access("/bin/more",os.X_OK): 842 viewer = "/bin/more" 843 if not viewer: 844 viewer = self.get_file_editor() 845 return viewer
846
847 - def get_file_editor(self):
848 editor = None 849 if os.getenv("EDITOR"): 850 editor = "$EDITOR" 851 elif os.access("/bin/nano",os.X_OK): 852 editor = "/bin/nano" 853 elif os.access("/bin/vi",os.X_OK): 854 editor = "/bin/vi" 855 elif os.access("/usr/bin/vi",os.X_OK): 856 editor = "/usr/bin/vi" 857 elif os.access("/usr/bin/emacs",os.X_OK): 858 editor = "/usr/bin/emacs" 859 elif os.access("/bin/emacs",os.X_OK): 860 editor = "/bin/emacs" 861 return editor
862
863 - def add_user_package_set(self, set_name, set_atoms):
864 865 def _ensure_package_sets_dir(): 866 sets_dir = etpConst['confsetsdir'] 867 if not os.path.isdir(sets_dir): 868 if os.path.lexists(sets_dir): 869 os.remove(sets_dir) 870 os.makedirs(sets_dir,0775) 871 const_setup_perms(sets_dir, etpConst['entropygid'])
872 873 try: 874 set_name = str(set_name) 875 except (UnicodeEncodeError,UnicodeDecodeError,): 876 raise InvalidPackageSet("InvalidPackageSet: %s %s" % (set_name,_("must be an ASCII string"),)) 877 878 if set_name.startswith(etpConst['packagesetprefix']): 879 raise InvalidPackageSet("InvalidPackageSet: %s %s '%s'" % (set_name,_("cannot start with"),etpConst['packagesetprefix'],)) 880 set_match, rc = self.package_set_match(set_name) 881 if rc: return -1,_("Name already taken") 882 883 _ensure_package_sets_dir() 884 set_file = os.path.join(etpConst['confsetsdir'],set_name) 885 if os.path.isfile(set_file) and os.access(set_file,os.W_OK): 886 try: 887 os.remove(set_file) 888 except OSError: 889 return -2,_("Cannot remove the old element") 890 if not os.access(os.path.dirname(set_file),os.W_OK): 891 return -3,_("Cannot create the element") 892 893 f = open(set_file,"w") 894 for x in set_atoms: f.write("%s\n" % (x,)) 895 f.flush() 896 f.close() 897 self.SystemSettings['system_package_sets'][set_name] = set(set_atoms) 898 return 0,_("All fine")
899
900 - def remove_user_package_set(self, set_name):
901 902 try: 903 set_name = str(set_name) 904 except (UnicodeEncodeError,UnicodeDecodeError,): 905 raise InvalidPackageSet("InvalidPackageSet: %s %s" % (set_name,_("must be an ASCII string"),)) 906 907 if set_name.startswith(etpConst['packagesetprefix']): 908 raise InvalidPackageSet("InvalidPackageSet: %s %s '%s'" % (set_name,_("cannot start with"),etpConst['packagesetprefix'],)) 909 910 set_match, rc = self.package_set_match(set_name) 911 if not rc: return -1,_("Already removed") 912 set_id, set_x, set_y = set_match 913 914 if set_id != etpConst['userpackagesetsid']: 915 return -2,_("Not defined by user") 916 set_file = os.path.join(etpConst['confsetsdir'],set_name) 917 if os.path.isfile(set_file) and os.access(set_file,os.W_OK): 918 os.remove(set_file) 919 if set_name in self.SystemSettings['system_package_sets']: 920 del self.SystemSettings['system_package_sets'][set_name] 921 return 0,_("All fine") 922 return -3,_("Set not found or unable to remove")
923
924 - def is_installed_idpackage_in_system_mask(self, idpackage):
925 client_plugin_id = etpConst['system_settings_plugins_ids']['client_plugin'] 926 mask_installed = self.SystemSettings[client_plugin_id]['system_mask']['repos_installed'] 927 if idpackage in mask_installed: 928 return True 929 return False
930
931 - def get_branch_from_download_relative_uri(self, db_download_uri):
932 return db_download_uri.split("/")[2]
933
934 - def swap_branch_in_download_relative_uri(self, new_branch, db_download_uri):
935 cur_branch = self.get_branch_from_download_relative_uri(db_download_uri) 936 return db_download_uri.replace("/%s/" % (cur_branch,), 937 "/%s/" % (new_branch,))
938
939 - def unused_packages_test(self, dbconn = None):
940 if dbconn == None: dbconn = self.clientDbconn 941 return [x for x in dbconn.retrieveUnusedIdpackages() if self.validate_package_removal(x)]
942
943 - def get_licenses_to_accept(self, install_queue):
944 if not install_queue: 945 return {} 946 licenses = {} 947 for match in install_queue: 948 repoid = match[1] 949 dbconn = self.open_repository(repoid) 950 wl = self.SystemSettings['repos_license_whitelist'].get(repoid) 951 if not wl: 952 continue 953 keys = dbconn.retrieveLicensedataKeys(match[0]) 954 for key in keys: 955 if key not in wl: 956 found = self.clientDbconn.isLicenseAccepted(key) 957 if found: 958 continue 959 if not licenses.has_key(key): 960 licenses[key] = set() 961 licenses[key].add(match) 962 return licenses
963
964 - def get_text_license(self, license_name, repoid):
965 dbconn = self.open_repository(repoid) 966 text = dbconn.retrieveLicenseText(license_name) 967 tempfile = self.entropyTools.get_random_temp_file() 968 f = open(tempfile,"w") 969 f.write(text) 970 f.flush() 971 f.close() 972 return tempfile
973
974 - def libraries_test(self, dbconn = None, broken_symbols = False, task_bombing_func = None):
975 976 if dbconn == None: 977 dbconn = self.clientDbconn 978 979 self.updateProgress( 980 blue(_("Libraries test")), 981 importance = 2, 982 type = "info", 983 header = red(" @@ ") 984 ) 985 986 if not etpConst['systemroot']: 987 myroot = "/" 988 else: 989 myroot = etpConst['systemroot']+"/" 990 # run ldconfig first 991 subprocess.call("ldconfig -r %s &> /dev/null" % (myroot,), shell = True) 992 # open /etc/ld.so.conf 993 if not os.path.isfile(etpConst['systemroot']+"/etc/ld.so.conf"): 994 self.updateProgress( 995 blue(_("Cannot find "))+red(etpConst['systemroot']+"/etc/ld.so.conf"), 996 importance = 1, 997 type = "error", 998 header = red(" @@ ") 999 ) 1000 return {},set(),-1 1001 1002 ldpaths = set(self.entropyTools.collect_linker_paths()) 1003 ldpaths |= self.entropyTools.collect_paths() 1004 # speed up when /usr/lib is a /usr/lib64 symlink 1005 if "/usr/lib64" in ldpaths and "/usr/lib" in ldpaths: 1006 if os.path.realpath("/usr/lib64") == "/usr/lib": 1007 ldpaths.discard("/usr/lib") 1008 # some crappy packages put shit here too 1009 ldpaths.add("/usr/share") 1010 # always force /usr/libexec too 1011 ldpaths.add("/usr/libexec") 1012 1013 executables = set() 1014 total = len(ldpaths) 1015 count = 0 1016 sys_root_len = len(etpConst['systemroot']) 1017 for ldpath in ldpaths: 1018 if callable(task_bombing_func): task_bombing_func() 1019 count += 1 1020 self.updateProgress( 1021 blue("Tree: ")+red(etpConst['systemroot']+ldpath), 1022 importance = 0, 1023 type = "info", 1024 count = (count,total), 1025 back = True, 1026 percent = True, 1027 header = " " 1028 ) 1029 ldpath = ldpath.encode(sys.getfilesystemencoding()) 1030 mywalk_iter = os.walk(etpConst['systemroot']+ldpath) 1031 1032 def mywimf(dt): 1033 1034 currentdir, subdirs, files = dt 1035 1036 def mymf(item): 1037 filepath = os.path.join(currentdir,item) 1038 if filepath in etpConst['libtest_files_blacklist']: 1039 return 0 1040 if not os.access(filepath,os.R_OK): 1041 return 0 1042 if not os.path.isfile(filepath): 1043 return 0 1044 if not self.entropyTools.is_elf_file(filepath): 1045 return 0 1046 return filepath[sys_root_len:]
1047 1048 return set([x for x in map(mymf,files) if type(x) != int]) 1049 1050 for x in map(mywimf,mywalk_iter): executables |= x 1051 1052 self.updateProgress( 1053 blue(_("Collecting broken executables")), 1054 importance = 2, 1055 type = "info", 1056 header = red(" @@ ") 1057 ) 1058 t = red(_("Attention")) + ": " + \ 1059 blue(_("don't worry about libraries that are shown here but not later.")) 1060 self.updateProgress( 1061 t, 1062 importance = 1, 1063 type = "info", 1064 header = red(" @@ ") 1065 ) 1066 1067 myQA = self.QA() 1068 1069 plain_brokenexecs = set() 1070 total = len(executables) 1071 count = 0 1072 scan_txt = blue("%s ..." % (_("Scanning libraries"),)) 1073 for executable in executables: 1074 if callable(task_bombing_func): task_bombing_func() 1075 count += 1 1076 if (count%10 == 0) or (count == total) or (count == 1): 1077 self.updateProgress( 1078 scan_txt, 1079 importance = 0, 1080 type = "info", 1081 count = (count,total), 1082 back = True, 1083 percent = True, 1084 header = " " 1085 ) 1086 myelfs = self.entropyTools.read_elf_dynamic_libraries(etpConst['systemroot']+executable) 1087 def mymf2(mylib): 1088 return not myQA.resolve_dynamic_library(mylib, executable) 1089 mylibs = set(filter(mymf2,myelfs)) 1090 broken_sym_found = set() 1091 if broken_symbols and not mylibs: broken_sym_found |= self.entropyTools.read_elf_broken_symbols(etpConst['systemroot']+executable) 1092 if not (mylibs or broken_sym_found): 1093 continue 1094 1095 if mylibs: 1096 alllibs = blue(' :: ').join(list(mylibs)) 1097 self.updateProgress( 1098 red(etpConst['systemroot']+executable)+" [ "+alllibs+" ]", 1099 importance = 1, 1100 type = "info", 1101 percent = True, 1102 count = (count,total), 1103 header = " " 1104 ) 1105 elif broken_sym_found: 1106 allsyms = darkred(' :: ').join([brown(x) for x in list(broken_sym_found)]) 1107 if len(allsyms) > 50: allsyms = brown(_('various broken symbols')) 1108 self.updateProgress( 1109 red(etpConst['systemroot']+executable)+" { "+allsyms+" }", 1110 importance = 1, 1111 type = "info", 1112 percent = True, 1113 count = (count,total), 1114 header = " " 1115 ) 1116 plain_brokenexecs.add(executable) 1117 1118 del executables 1119 packagesMatched = {} 1120 1121 if not etpSys['serverside']: 1122 1123 self.updateProgress( 1124 blue(_("Matching broken libraries/executables")), 1125 importance = 1, 1126 type = "info", 1127 header = red(" @@ ") 1128 ) 1129 matched = set() 1130 for brokenlib in plain_brokenexecs: 1131 idpackages = self.clientDbconn.searchBelongs(brokenlib) 1132 for idpackage in idpackages: 1133 key, slot = self.clientDbconn.retrieveKeySlot(idpackage) 1134 mymatch = self.atom_match(key, matchSlot = slot) 1135 if mymatch[0] == -1: 1136 matched.add(brokenlib) 1137 continue 1138 cmpstat = self.get_package_action(mymatch) 1139 if cmpstat == 0: 1140 continue 1141 if not packagesMatched.has_key(brokenlib): 1142 packagesMatched[brokenlib] = set() 1143 packagesMatched[brokenlib].add(mymatch) 1144 matched.add(brokenlib) 1145 plain_brokenexecs -= matched 1146 1147 return packagesMatched,plain_brokenexecs,0 1148
1149 - def set_branch(self, branch):
1150 """ 1151 Set new Entropy branch. This is NOT thread-safe. 1152 Please note that if you call this method all your 1153 repository instance references will become invalid. 1154 This is caused by close_all_repositories and SystemSettings 1155 clear methods. 1156 Once you changed branch, the repository databases won't be 1157 available until you fetch them (through Repositories class) 1158 1159 @param branch -- new branch 1160 @type branch basestring 1161 @return None 1162 """ 1163 self.Cacher.discard() 1164 self.Cacher.stop() 1165 self.purge_cache(showProgress = False) 1166 self.close_all_repositories() 1167 # etpConst should be readonly but we override the rule here 1168 # this is also useful when no config file or parameter into it exists 1169 etpConst['branch'] = branch 1170 self.entropyTools.write_new_branch(branch) 1171 self.SystemSettings.clear() 1172 1173 # reset treeupdatesactions 1174 self.reopen_client_repository() 1175 self.clientDbconn.resetTreeupdatesDigests() 1176 self.close_all_repositories() 1177 if self.xcache: 1178 self.Cacher.start()
1179
1180 - def get_meant_packages(self, search_term, from_installed = False, valid_repos = []):
1181 1182 pkg_data = [] 1183 atom_srch = False 1184 if "/" in search_term: atom_srch = True 1185 1186 if not valid_repos: valid_repos = self.validRepositories 1187 if from_installed: valid_repos = [1] 1188 for repo in valid_repos: 1189 if isinstance(repo,basestring): 1190 dbconn = self.open_repository(repo) 1191 elif isinstance(repo,LocalRepository): 1192 dbconn = repo 1193 elif hasattr(self,'clientDbconn'): 1194 dbconn = self.clientDbconn 1195 else: 1196 continue 1197 pkg_data.extend([(x,repo,) for x in dbconn.searchSimilarPackages(search_term, atom = atom_srch)]) 1198 1199 return pkg_data
1200
1201 - def list_repo_categories(self):
1202 categories = set() 1203 for repo in self.validRepositories: 1204 dbconn = self.open_repository(repo) 1205 catsdata = dbconn.listAllCategories() 1206 categories.update(set([x[1] for x in catsdata])) 1207 return categories
1208
1209 - def list_repo_packages_in_category(self, category):
1210 pkg_matches = [] 1211 for repo in self.validRepositories: 1212 dbconn = self.open_repository(repo) 1213 branch = self.SystemSettings['repositories']['branch'] 1214 catsdata = dbconn.searchPackagesByCategory(category, branch = branch) 1215 pkg_matches.extend([(x[1],repo,) for x in catsdata if (x[1],repo,) not in pkg_matches]) 1216 return pkg_matches
1217
1218 - def get_category_description_data(self, category):
1219 1220 data = {} 1221 for repo in self.validRepositories: 1222 try: 1223 dbconn = self.open_repository(repo) 1224 except RepositoryError: 1225 continue 1226 try: 1227 data = dbconn.retrieveCategoryDescription(category) 1228 except (self.dbapi2.OperationalError, self.dbapi2.IntegrityError,): 1229 continue 1230 if data: break 1231 1232 return data
1233
1234 - def list_installed_packages_in_category(self, category):
1235 pkg_matches = set([x[1] for x in self.clientDbconn.searchPackagesByCategory(category)]) 1236 return pkg_matches
1237
1238 - def get_package_match_config_protect(self, match, mask = False):
1239 1240 idpackage, repoid = match 1241 dbconn = self.open_repository(repoid) 1242 cl_id = self.sys_settings_client_plugin_id 1243 misc_data = self.SystemSettings[cl_id]['misc'] 1244 if mask: 1245 config_protect = set(dbconn.retrieveProtectMask(idpackage).split()) 1246 config_protect |= set(misc_data['configprotectmask']) 1247 else: 1248 config_protect = set(dbconn.retrieveProtect(idpackage).split()) 1249 config_protect |= set(misc_data['configprotect']) 1250 config_protect = [etpConst['systemroot']+x for x in config_protect] 1251 1252 return sorted(config_protect)
1253
1254 - def get_installed_package_config_protect(self, idpackage, mask = False):
1255 1256 if self.clientDbconn == None: 1257 return [] 1258 cl_id = self.sys_settings_client_plugin_id 1259 misc_data = self.SystemSettings[cl_id]['misc'] 1260 if mask: 1261 _pmask = self.clientDbconn.retrieveProtectMask(idpackage).split() 1262 config_protect = set(_pmask) 1263 config_protect |= set(misc_data['configprotectmask']) 1264 else: 1265 _protect = self.clientDbconn.retrieveProtect(idpackage).split() 1266 config_protect = set(_protect) 1267 config_protect |= set(misc_data['configprotect']) 1268 config_protect = [etpConst['systemroot']+x for x in config_protect] 1269 1270 return sorted(config_protect)
1271
1272 - def get_system_config_protect(self, mask = False):
1273 1274 if self.clientDbconn == None: 1275 return [] 1276 1277 # FIXME: workaround because this method is called 1278 # before misc_parser 1279 cl_id = self.sys_settings_client_plugin_id 1280 misc_data = self.SystemSettings[cl_id]['misc'] 1281 if mask: 1282 _pmask = self.clientDbconn.listConfigProtectDirectories(mask = True) 1283 config_protect = set(_pmask) 1284 config_protect |= set(misc_data['configprotectmask']) 1285 else: 1286 _protect = self.clientDbconn.listConfigProtectDirectories() 1287 config_protect = set(_protect) 1288 config_protect |= set(misc_data['configprotect']) 1289 config_protect = [etpConst['systemroot']+x for x in config_protect] 1290 1291 return sorted(config_protect)
1292
1293 - def inject_entropy_database_into_package(self, package_filename, data, treeupdates_actions = None):
1294 dbpath = self.get_tmp_dbpath() 1295 dbconn = self.open_generic_database(dbpath) 1296 dbconn.initializeDatabase() 1297 dbconn.addPackage(data, revision = data['revision']) 1298 if treeupdates_actions != None: 1299 dbconn.bumpTreeUpdatesActions(treeupdates_actions) 1300 dbconn.commitChanges() 1301 dbconn.closeDB() 1302 self.entropyTools.aggregate_edb(tbz2file = package_filename, dbfile = dbpath) 1303 return dbpath
1304
1305 - def get_tmp_dbpath(self):
1306 dbpath = etpConst['packagestmpdir']+"/"+str(self.entropyTools.get_random_number()) 1307 while os.path.isfile(dbpath): 1308 dbpath = etpConst['packagestmpdir']+"/"+str(self.entropyTools.get_random_number()) 1309 return dbpath
1310
1311 - def quickpkg(self, atomstring, savedir = None):
1312 if savedir == None: 1313 savedir = etpConst['packagestmpdir'] 1314 if not os.path.isdir(etpConst['packagestmpdir']): 1315 os.makedirs(etpConst['packagestmpdir']) 1316 # match package 1317 match = self.clientDbconn.atomMatch(atomstring) 1318 if match[0] == -1: 1319 return -1,None,None 1320 atom = self.clientDbconn.atomMatch(match[0]) 1321 pkgdata = self.clientDbconn.getPackageData(match[0]) 1322 resultfile = self.quickpkg_handler(pkgdata = pkgdata, dirpath = savedir) 1323 if resultfile == None: 1324 return -1,atom,None 1325 else: 1326 return 0,atom,resultfile
1327
1328 - def quickpkg_handler(self, pkgdata, dirpath, edb = True, 1329 portdbPath = None, fake = False, compression = "bz2", shiftpath = ""):
1330 1331 import stat 1332 import tarfile 1333 1334 if compression not in ("bz2","","gz"): 1335 compression = "bz2" 1336 1337 # getting package info 1338 pkgtag = '' 1339 pkgrev = "~"+str(pkgdata['revision']) 1340 if pkgdata['versiontag']: pkgtag = "#"+pkgdata['versiontag'] 1341 pkgname = pkgdata['name']+"-"+pkgdata['version']+pkgrev+pkgtag # + version + tag 1342 pkgcat = pkgdata['category'] 1343 #pkgfile = pkgname+etpConst['packagesext'] 1344 dirpath += "/"+pkgname+etpConst['packagesext'] 1345 if os.path.isfile(dirpath): 1346 os.remove(dirpath) 1347 tar = tarfile.open(dirpath,"w:"+compression) 1348 1349 if not fake: 1350 1351 contents = sorted([x for x in pkgdata['content']]) 1352 1353 # collect files 1354 for path in contents: 1355 # convert back to filesystem str 1356 encoded_path = path 1357 path = path.encode('raw_unicode_escape') 1358 path = shiftpath+path 1359 try: 1360 exist = os.lstat(path) 1361 except OSError: 1362 continue # skip file 1363 arcname = path[len(shiftpath):] # remove shiftpath 1364 if arcname.startswith("/"): 1365 arcname = arcname[1:] # remove trailing / 1366 ftype = pkgdata['content'][encoded_path] 1367 if str(ftype) == '0': ftype = 'dir' # force match below, '0' means databases without ftype 1368 if 'dir' == ftype and \ 1369 not stat.S_ISDIR(exist.st_mode) and \ 1370 os.path.isdir(path): # workaround for directory symlink issues 1371 path = os.path.realpath(path) 1372 1373 tarinfo = tar.gettarinfo(path, arcname) 1374 1375 if stat.S_ISREG(exist.st_mode): 1376 tarinfo.type = tarfile.REGTYPE 1377 f = open(path) 1378 try: 1379 tar.addfile(tarinfo, f) 1380 finally: 1381 f.close() 1382 else: 1383 tar.addfile(tarinfo) 1384 1385 tar.close() 1386 1387 # appending xpak metadata 1388 import entropy.xpak as xpak 1389 Spm = self.Spm() 1390 1391 gentoo_name = self.entropyTools.remove_tag(pkgname) 1392 gentoo_name = self.entropyTools.remove_entropy_revision(gentoo_name) 1393 if portdbPath == None: 1394 dbdir = Spm.get_vdb_path()+"/"+pkgcat+"/"+gentoo_name+"/" 1395 else: 1396 dbdir = portdbPath+"/"+pkgcat+"/"+gentoo_name+"/" 1397 if os.path.isdir(dbdir): 1398 tbz2 = xpak.tbz2(dirpath) 1399 tbz2.recompose(dbdir) 1400 1401 if edb: 1402 self.inject_entropy_database_into_package(dirpath, pkgdata) 1403 1404 if os.path.isfile(dirpath): 1405 return dirpath 1406 return None
1407 1408
1409 -class MatchMixin:
1410
1411 - def get_package_action(self, match):
1412 """ 1413 @input: matched atom (idpackage,repoid) 1414 @output: 1415 upgrade: int(2) 1416 install: int(1) 1417 reinstall: int(0) 1418 downgrade: int(-1) 1419 """ 1420 dbconn = self.open_repository(match[1]) 1421 pkgkey, pkgslot = dbconn.retrieveKeySlot(match[0]) 1422 results = self.clientDbconn.searchKeySlot(pkgkey, pkgslot) 1423 if not results: return 1 1424 1425 installed_idpackage = results[0][0] 1426 pkgver, pkgtag, pkgrev = dbconn.getVersioningData(match[0]) 1427 installedVer, installedTag, installedRev = self.clientDbconn.getVersioningData(installed_idpackage) 1428 pkgcmp = self.entropyTools.entropy_compare_versions((pkgver,pkgtag,pkgrev),(installedVer,installedTag,installedRev)) 1429 if pkgcmp == 0: 1430 return 0 1431 elif pkgcmp > 0: 1432 return 2 1433 return -1
1434
1435 - def get_masked_package_reason(self, match):
1436 idpackage, repoid = match 1437 dbconn = self.open_repository(repoid) 1438 idpackage, idreason = dbconn.idpackageValidator(idpackage) 1439 masked = False 1440 if idpackage == -1: masked = True 1441 return masked, idreason, self.SystemSettings['pkg_masking_reasons'].get(idreason)
1442
1443 - def get_match_conflicts(self, match):
1444 m_id, m_repo = match 1445 dbconn = self.open_repository(m_repo) 1446 conflicts = dbconn.retrieveConflicts(m_id) 1447 found_conflicts = set() 1448 for conflict in conflicts: 1449 my_m_id, my_m_rc = self.clientDbconn.atomMatch(conflict) 1450 if my_m_id != -1: 1451 # check if the package shares the same slot 1452 match_data = dbconn.retrieveKeySlot(m_id) 1453 installed_match_data = self.clientDbconn.retrieveKeySlot(my_m_id) 1454 if match_data != installed_match_data: 1455 found_conflicts.add(my_m_id) 1456 return found_conflicts
1457
1458 - def is_match_masked(self, match, live_check = True):
1459 m_id, m_repo = match 1460 dbconn = self.open_repository(m_repo) 1461 idpackage, idreason = dbconn.idpackageValidator(m_id, live = live_check) 1462 if idpackage != -1: 1463 return False 1464 return True
1465
1466 - def is_match_masked_by_user(self, match, live_check = True):
1467 # (query_status,masked?,) 1468 m_id, m_repo = match 1469 if m_repo not in self.validRepositories: return False 1470 dbconn = self.open_repository(m_repo) 1471 idpackage, idreason = dbconn.idpackageValidator(m_id, live = live_check) 1472 if idpackage != -1: return False #,False 1473 myr = self.SystemSettings['pkg_masking_reference'] 1474 user_masks = [myr['user_package_mask'],myr['user_license_mask'],myr['user_live_mask']] 1475 if idreason in user_masks: 1476 return True #,True 1477 return False #,True
1478
1479 - def is_match_unmasked_by_user(self, match, live_check = True):
1480 # (query_status,unmasked?,) 1481 m_id, m_repo = match 1482 if m_repo not in self.validRepositories: return False 1483 dbconn = self.open_repository(m_repo) 1484 idpackage, idreason = dbconn.idpackageValidator(m_id, live = live_check) 1485 if idpackage == -1: return False #,False 1486 myr = self.SystemSettings['pkg_masking_reference'] 1487 user_masks = [ 1488 myr['user_package_unmask'],myr['user_live_unmask'],myr['user_package_keywords'], 1489 myr['user_repo_package_keywords_all'], myr['user_repo_package_keywords'] 1490 ] 1491 if idreason in user_masks: 1492 return True #,True 1493 return False #,True
1494
1495 - def mask_match(self, match, method = 'atom', dry_run = False, clean_all_cache = False):
1496 if self.is_match_masked(match, live_check = False): return True 1497 methods = { 1498 'atom': self.mask_match_by_atom, 1499 'keyslot': self.mask_match_by_keyslot, 1500 } 1501 rc = self._mask_unmask_match(match, method, methods, dry_run = dry_run, clean_all_cache = clean_all_cache) 1502 if dry_run: # inject if done "live" 1503 self.SystemSettings['live_packagemasking']['unmask_matches'].discard(match) 1504 self.SystemSettings['live_packagemasking']['mask_matches'].add(match) 1505 return rc
1506
1507 - def unmask_match(self, match, method = 'atom', dry_run = False, clean_all_cache = False):
1508 if not self.is_match_masked(match, live_check = False): return True 1509 methods = { 1510 'atom': self.unmask_match_by_atom, 1511 'keyslot': self.unmask_match_by_keyslot, 1512 } 1513 rc = self._mask_unmask_match(match, method, methods, dry_run = dry_run, clean_all_cache = clean_all_cache) 1514 if dry_run: # inject if done "live" 1515 self.SystemSettings['live_packagemasking']['unmask_matches'].add(match) 1516 self.SystemSettings['live_packagemasking']['mask_matches'].discard(match) 1517 return rc
1518
1519 - def _mask_unmask_match(self, match, method, methods_reference, dry_run = False, clean_all_cache = False):
1520 1521 f = methods_reference.get(method) 1522 if not callable(f): 1523 raise IncorrectParameter('IncorrectParameter: %s: %s' % (_("not a valid method"),method,) ) 1524 1525 self.Cacher.discard() 1526 done = f(match, dry_run) 1527 if done and not dry_run: 1528 self.SystemSettings.clear() 1529 1530 # clear atomMatch cache anyway 1531 if clean_all_cache and not dry_run: 1532 self.clear_dump_cache(etpCache['world_available']) 1533 self.clear_dump_cache(etpCache['world_update']) 1534 1535 self.clear_dump_cache(etpCache['check_package_update']) 1536 self.clear_dump_cache(etpCache['filter_satisfied_deps']) 1537 self.clear_dump_cache(self.atomMatchCacheKey) 1538 self.clear_dump_cache(etpCache['dep_tree']) 1539 self.clear_dump_cache("%s/%s%s/" % (etpCache['dbMatch'],etpConst['dbnamerepoprefix'],match[1],)) 1540 self.clear_dump_cache("%s/%s%s/" % (etpCache['dbSearch'],etpConst['dbnamerepoprefix'],match[1],)) 1541 1542 cl_id = self.sys_settings_client_plugin_id 1543 self.SystemSettings[cl_id]['masking_validation']['cache'].clear() 1544 return done
1545
1546 - def unmask_match_by_atom(self, match, dry_run = False):
1547 m_id, m_repo = match 1548 dbconn = self.open_repository(m_repo) 1549 atom = dbconn.retrieveAtom(m_id) 1550 return self.unmask_match_generic(match, atom, dry_run = dry_run)
1551
1552 - def unmask_match_by_keyslot(self, match, dry_run = False):
1553 m_id, m_repo = match 1554 dbconn = self.open_repository(m_repo) 1555 keyslot = "%s:%s" % dbconn.retrieveKeySlot(m_id) 1556 return self.unmask_match_generic(match, keyslot, dry_run = dry_run)
1557
1558 - def mask_match_by_atom(self, match, dry_run = False):
1559 m_id, m_repo = match 1560 dbconn = self.open_repository(m_repo) 1561 atom = dbconn.retrieveAtom(m_id) 1562 return self.mask_match_generic(match, atom, dry_run = dry_run)
1563
1564 - def mask_match_by_keyslot(self, match, dry_run = False):
1565 m_id, m_repo = match 1566 dbconn = self.open_repository(m_repo) 1567 keyslot = "%s:%s" % dbconn.retrieveKeySlot(m_id) 1568 return self.mask_match_generic(match, keyslot, dry_run = dry_run)
1569
1570 - def unmask_match_generic(self, match, keyword, dry_run = False):
1571 self.clear_match_mask(match, dry_run) 1572 m_file = self.SystemSettings.get_setting_files_data()['unmask'] 1573 return self._mask_unmask_match_generic(keyword, m_file, dry_run = dry_run)
1574
1575 - def mask_match_generic(self, match, keyword, dry_run = False):
1576 self.clear_match_mask(match, dry_run) 1577 m_file = self.SystemSettings.get_setting_files_data()['mask'] 1578 return self._mask_unmask_match_generic(keyword, m_file, dry_run = dry_run)
1579
1580 - def _mask_unmask_match_generic(self, keyword, m_file, dry_run = False):
1581 exist = False 1582 if not os.path.isfile(m_file): 1583 if not os.access(os.path.dirname(m_file),os.W_OK): 1584 return False # cannot write 1585 elif not os.access(m_file, os.W_OK): 1586 return False 1587 elif not dry_run: 1588 exist = True 1589 1590 if dry_run: 1591 return True 1592 1593 content = [] 1594 if exist: 1595 f = open(m_file,"r") 1596 content = [x.strip() for x in f.readlines()] 1597 f.close() 1598 content.append(keyword) 1599 m_file_tmp = m_file+".tmp" 1600 f = open(m_file_tmp,"w") 1601 for line in content: 1602 f.write(line+"\n") 1603 f.flush() 1604 f.close() 1605 shutil.move(m_file_tmp,m_file) 1606 return True
1607
1608 - def clear_match_mask(self, match, dry_run = False):
1609 setting_data = self.SystemSettings.get_setting_files_data() 1610 masking_list = [setting_data['mask'],setting_data['unmask']] 1611 return self._clear_match_generic(match, masking_list = masking_list, dry_run = dry_run)
1612
1613 - def _clear_match_generic(self, match, masking_list = [], dry_run = False):
1614 1615 self.SystemSettings['live_packagemasking']['unmask_matches'].discard(match) 1616 self.SystemSettings['live_packagemasking']['mask_matches'].discard(match) 1617 1618 if dry_run: return 1619 1620 for mask_file in masking_list: 1621 if not (os.path.isfile(mask_file) and os.access(mask_file,os.W_OK)): continue 1622 f = open(mask_file,"r") 1623 newf = self.entropyTools.open_buffer() 1624 line = f.readline() 1625 while line: 1626 line = line.strip() 1627 if line.startswith("#"): 1628 newf.write(line+"\n") 1629 line = f.readline() 1630 continue 1631 elif not line: 1632 newf.write("\n") 1633 line = f.readline() 1634 continue 1635 mymatch = self.atom_match(line, packagesFilter = False) 1636 if mymatch == match: 1637 line = f.readline() 1638 continue 1639 newf.write(line+"\n") 1640 line = f.readline() 1641 f.close() 1642 tmpfile = mask_file+".w_tmp" 1643 f = open(tmpfile,"w") 1644 f.write(newf.getvalue()) 1645 f.flush() 1646 f.close() 1647 newf.close() 1648 shutil.move(tmpfile,mask_file)
1649