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