Package entropy :: Package client :: Package interfaces :: Module package

Source Code for Module entropy.client.interfaces.package

   1   
   2  # -*- coding: utf-8 -*- 
   3  ''' 
   4      # DESCRIPTION: 
   5      # Entropy Object Oriented Interface 
   6   
   7      Copyright (C) 2007-2009 Fabio Erculiani 
   8   
   9      This program is free software; you can redistribute it and/or modify 
  10      it under the terms of the GNU General Public License as published by 
  11      the Free Software Foundation; either version 2 of the License, or 
  12      (at your option) any later version. 
  13   
  14      This program is distributed in the hope that it will be useful, 
  15      but WITHOUT ANY WARRANTY; without even the implied warranty of 
  16      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  17      GNU General Public License for more details. 
  18   
  19      You should have received a copy of the GNU General Public License 
  20      along with this program; if not, write to the Free Software 
  21      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  22  ''' 
  23  from __future__ import with_statement 
  24  import os 
  25  import subprocess 
  26  import time 
  27  import shutil 
  28  from entropy.const import * 
  29  from entropy.exceptions import * 
  30  from entropy.i18n import _ 
  31  from entropy.output import TextInterface, brown, blue, bold, darkgreen, \ 
  32      darkblue, red, purple, darkred, print_info, print_error, print_warning 
  33  from entropy.misc import TimeScheduled 
  34  from entropy.db import dbapi2, LocalRepository 
  35  from entropy.client.interfaces.client import Client 
  36  from entropy.cache import EntropyCacher 
  37   
38 -class Package:
39 40 import entropy.tools as entropyTools 41 import entropy.dump as dumpTools
42 - def __init__(self, EquoInstance):
43 44 if not isinstance(EquoInstance,Client): 45 mytxt = _("A valid Client instance or subclass is needed") 46 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,)) 47 self.Entropy = EquoInstance 48 49 self.Cacher = EntropyCacher() 50 self.infoDict = {} 51 self.prepared = False 52 self.matched_atom = () 53 self.valid_actions = ("source","fetch","multi_fetch","remove", 54 "remove_conflict","install","config" 55 ) 56 self.action = None 57 self.fetch_abort_function = None 58 self.xterm_title = ''
59
60 - def kill(self):
61 self.infoDict.clear() 62 self.matched_atom = () 63 self.valid_actions = () 64 self.action = None 65 self.prepared = False 66 self.fetch_abort_function = None
67
68 - def error_on_prepared(self):
69 if self.prepared: 70 mytxt = _("Already prepared") 71 raise PermissionDenied("PermissionDenied: %s" % (mytxt,))
72
73 - def error_on_not_prepared(self):
74 if not self.prepared: 75 mytxt = _("Not yet prepared") 76 raise PermissionDenied("PermissionDenied: %s" % (mytxt,))
77
78 - def check_action_validity(self, action):
79 if action not in self.valid_actions: 80 mytxt = _("Action must be in") 81 raise InvalidData("InvalidData: %s %s" % (mytxt,self.valid_actions,))
82
83 - def match_checksum(self, repository = None, checksum = None, 84 download = None, signatures = None):
85 86 self.error_on_not_prepared() 87 88 if repository == None: 89 repository = self.infoDict['repository'] 90 if checksum == None: 91 checksum = self.infoDict['checksum'] 92 if download == None: 93 download = self.infoDict['download'] 94 if signatures == None: 95 signatures = self.infoDict['signatures'] 96 97 def do_signatures_validation(signatures): 98 # check signatures, if available 99 if isinstance(signatures,dict): 100 for hash_type in sorted(signatures): 101 hash_val = signatures[hash_type] 102 # XXX workaround bug on unreleased 103 # entropy versions 104 if hash_val in signatures: 105 continue 106 elif hash_val == None: 107 continue 108 elif not hasattr(self.entropyTools, 109 'compare_%s' % (hash_type,)): 110 continue 111 112 self.Entropy.updateProgress( 113 "%s: %s" % (blue(_("Checking package hash")), 114 purple(hash_type.upper()),), 115 importance = 0, 116 type = "info", 117 header = red(" ## "), 118 back = True 119 ) 120 cmp_func = getattr(self.entropyTools, 121 'compare_%s' % (hash_type,)) 122 mydownload = os.path.join(etpConst['entropyworkdir'], 123 download) 124 valid = cmp_func(mydownload, hash_val) 125 if not valid: 126 self.Entropy.updateProgress( 127 "%s: %s %s" % ( 128 darkred(_("Package hash")), 129 purple(hash_type.upper()), 130 darkred(_("does not match the recorded one")), 131 ), 132 importance = 0, 133 type = "warning", 134 header = darkred(" ## ") 135 ) 136 return 1 137 self.Entropy.updateProgress( 138 "%s %s" % ( 139 purple(hash_type.upper()), 140 darkgreen(_("matches")), 141 ), 142 importance = 0, 143 type = "info", 144 header = " : " 145 ) 146 return 0
147 148 dlcount = 0 149 match = False 150 while dlcount <= 5: 151 152 self.Entropy.updateProgress( 153 blue(_("Checking package checksum...")), 154 importance = 0, 155 type = "info", 156 header = red(" ## "), 157 back = True 158 ) 159 160 dlcheck = self.Entropy.check_needed_package_download(download, 161 checksum = checksum) 162 if dlcheck == 0: 163 basef = os.path.basename(download) 164 self.Entropy.updateProgress( 165 "%s: %s" % ( 166 blue(_("Package checksum matches")), 167 darkgreen(basef), 168 ), 169 importance = 0, 170 type = "info", 171 header = red(" ## ") 172 ) 173 174 dlcheck = do_signatures_validation(signatures) 175 if dlcheck == 0: 176 self.infoDict['verified'] = True 177 match = True 178 break # file downloaded successfully 179 180 if dlcheck != 0: 181 dlcount += 1 182 self.Entropy.updateProgress( 183 darkred(_("Package checksum does not match. Redownloading... attempt #%s") % (dlcount,)), 184 importance = 0, 185 type = "warning", 186 header = darkred(" ## ") 187 ) 188 fetch = self.Entropy.fetch_file_on_mirrors( 189 repository, 190 self.Entropy.get_branch_from_download_relative_uri(download), 191 download, 192 checksum, 193 fetch_abort_function = self.fetch_abort_function 194 ) 195 if fetch != 0: 196 self.Entropy.updateProgress( 197 blue(_("Cannot properly fetch package! Quitting.")), 198 importance = 0, 199 type = "error", 200 header = darkred(" ## ") 201 ) 202 return fetch 203 204 # package is fetched, let's loop one more time 205 # to make sure to run all the checksum checks 206 continue 207 208 if not match: 209 mytxt = _("Cannot properly fetch package or checksum does not match. Try download latest repositories.") 210 self.Entropy.updateProgress( 211 blue(mytxt), 212 importance = 0, 213 type = "info", 214 header = red(" ## ") 215 ) 216 return 1 217 218 return 0
219
220 - def multi_match_checksum(self):
221 rc = 0 222 for repository, branch, download, digest, signatures in self.infoDict['multi_checksum_list']: 223 rc = self.match_checksum(repository, digest, download, signatures) 224 if rc != 0: break 225 return rc
226
227 - def __unpack_package(self):
228 229 if not self.infoDict['merge_from']: 230 self.Entropy.clientLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_NORMAL,"Unpacking package: "+str(self.infoDict['atom'])) 231 else: 232 self.Entropy.clientLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_NORMAL,"Merging package: "+str(self.infoDict['atom'])) 233 234 if os.path.isdir(self.infoDict['unpackdir']): 235 shutil.rmtree(self.infoDict['unpackdir'].encode('raw_unicode_escape')) 236 elif os.path.isfile(self.infoDict['unpackdir']): 237 os.remove(self.infoDict['unpackdir'].encode('raw_unicode_escape')) 238 os.makedirs(self.infoDict['imagedir']) 239 240 if not os.path.isfile(self.infoDict['pkgpath']) and not self.infoDict['merge_from']: 241 if os.path.isdir(self.infoDict['pkgpath']): 242 shutil.rmtree(self.infoDict['pkgpath']) 243 if os.path.islink(self.infoDict['pkgpath']): 244 os.remove(self.infoDict['pkgpath']) 245 self.infoDict['verified'] = False 246 rc = self.fetch_step() 247 if rc != 0: 248 return rc 249 250 if not self.infoDict['merge_from']: 251 252 # extract entropy database from package file 253 # in order to avoid having to read content data 254 # from the repository database, which, in future 255 # is allowed to not provide such info. 256 pkg_dbdir = os.path.dirname(self.infoDict['pkgdbpath']) 257 if not os.path.isdir(pkg_dbdir): 258 os.makedirs(pkg_dbdir, 0755) 259 # extract edb 260 self.entropyTools.extract_edb(self.infoDict['pkgpath'], 261 self.infoDict['pkgdbpath']) 262 263 unpack_tries = 3 264 while 1: 265 unpack_tries -= 1 266 try: 267 rc = self.entropyTools.spawn_function( 268 self.entropyTools.uncompress_tar_bz2, 269 self.infoDict['pkgpath'], 270 self.infoDict['imagedir'], 271 catchEmpty = True 272 ) 273 except EOFError: 274 self.Entropy.clientLog.log( 275 ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, 276 "EOFError on " + self.infoDict['pkgpath'] 277 ) 278 rc = 1 279 except (UnicodeEncodeError, UnicodeDecodeError, 280 self.dumpTools.pickle.PicklingError,): 281 # this will make devs to actually catch the 282 # right exception and prepare a fix 283 self.Entropy.clientLog.log( 284 ETP_LOGPRI_INFO, 285 ETP_LOGLEVEL_NORMAL, 286 "Raising Unicode/Pickling Error for " + \ 287 self.infoDict['pkgpath'] 288 ) 289 rc = self.entropyTools.uncompress_tar_bz2( 290 self.infoDict['pkgpath'],self.infoDict['imagedir'], 291 catchEmpty = True 292 ) 293 if rc == 0: 294 break 295 if unpack_tries <= 0: 296 return rc 297 # otherwise, try to download it again 298 self.infoDict['verified'] = False 299 f_rc = self.fetch_step() 300 if f_rc != 0: 301 return f_rc 302 303 else: 304 305 pid = os.fork() 306 if pid > 0: 307 os.waitpid(pid, 0) 308 else: 309 self.__fill_image_dir(self.infoDict['merge_from'], 310 self.infoDict['imagedir']) 311 os._exit(0) 312 313 # unpack xpak ? 314 if os.path.isdir(self.infoDict['xpakpath']): 315 shutil.rmtree(self.infoDict['xpakpath']) 316 try: 317 os.rmdir(self.infoDict['xpakpath']) 318 except OSError: 319 pass 320 321 # create data dir where we'll unpack the xpak 322 os.makedirs(self.infoDict['xpakpath']+"/"+etpConst['entropyxpakdatarelativepath'],0755) 323 #os.mkdir(self.infoDict['xpakpath']+"/"+etpConst['entropyxpakdatarelativepath']) 324 xpakPath = self.infoDict['xpakpath']+"/"+etpConst['entropyxpakfilename'] 325 326 if not self.infoDict['merge_from']: 327 if (self.infoDict['smartpackage']): 328 # we need to get the .xpak from database 329 xdbconn = self.Entropy.open_repository(self.infoDict['repository']) 330 xpakdata = xdbconn.retrieveXpakMetadata(self.infoDict['idpackage']) 331 if xpakdata: 332 # save into a file 333 f = open(xpakPath,"wb") 334 f.write(xpakdata) 335 f.flush() 336 f.close() 337 self.infoDict['xpakstatus'] = self.entropyTools.unpack_xpak( 338 xpakPath, 339 self.infoDict['xpakpath']+"/"+etpConst['entropyxpakdatarelativepath'] 340 ) 341 else: 342 self.infoDict['xpakstatus'] = None 343 del xpakdata 344 else: 345 self.infoDict['xpakstatus'] = self.entropyTools.extract_xpak( 346 self.infoDict['pkgpath'], 347 self.infoDict['xpakpath']+"/"+etpConst['entropyxpakdatarelativepath'] 348 ) 349 else: 350 # link xpakdir to self.infoDict['xpakpath']+"/"+etpConst['entropyxpakdatarelativepath'] 351 tolink_dir = self.infoDict['xpakpath']+"/"+etpConst['entropyxpakdatarelativepath'] 352 if os.path.isdir(tolink_dir): 353 shutil.rmtree(tolink_dir,True) 354 # now link 355 os.symlink(self.infoDict['xpakdir'],tolink_dir) 356 357 # create fake portage ${D} linking it to imagedir 358 portage_db_fakedir = os.path.join( 359 self.infoDict['unpackdir'], 360 "portage/"+self.infoDict['category'] + "/" + self.infoDict['name'] + "-" + self.infoDict['version'] 361 ) 362 363 os.makedirs(portage_db_fakedir,0755) 364 # now link it to self.infoDict['imagedir'] 365 os.symlink(self.infoDict['imagedir'],os.path.join(portage_db_fakedir,"image")) 366 367 return 0
368
369 - def __configure_package(self):
370 371 try: Spm = self.Entropy.Spm() 372 except: return 1 373 374 spm_atom = self.infoDict['key']+"-"+self.infoDict['version'] 375 myebuild = Spm.get_vdb_path()+spm_atom+"/"+self.infoDict['key'].split("/")[1]+"-"+self.infoDict['version']+etpConst['spm']['source_build_ext'] 376 if not os.path.isfile(myebuild): 377 return 2 378 379 self.Entropy.updateProgress( 380 brown(" Ebuild: pkg_config()"), 381 importance = 0, 382 header = red(" ##") 383 ) 384 385 try: 386 rc = Spm.spm_doebuild( 387 myebuild, 388 mydo = "config", 389 tree = "bintree", 390 cpv = spm_atom 391 ) 392 if rc == 1: 393 self.Entropy.clientLog.log( 394 ETP_LOGPRI_INFO, 395 ETP_LOGLEVEL_NORMAL, 396 "[PRE] ATTENTION Cannot properly run Spm pkg_config() for " + \ 397 str(spm_atom)+". Something bad happened." 398 ) 399 return 3 400 except Exception, e: 401 self.entropyTools.print_traceback() 402 self.Entropy.clientLog.log( 403 ETP_LOGPRI_INFO, 404 ETP_LOGLEVEL_NORMAL, 405 "[PRE] ATTENTION Cannot run Spm pkg_config() for "+spm_atom+"!! "+str(type(Exception))+": "+str(e) 406 ) 407 mytxt = "%s: %s %s. %s. %s: %s, %s" % ( 408 bold(_("QA")), 409 brown(_("Cannot run Spm pkg_config() for")), 410 bold(str(spm_atom)), 411 brown(_("Please report it")), 412 bold(_("Error")), 413 type(Exception), 414 e, 415 ) 416 self.Entropy.updateProgress( 417 mytxt, 418 importance = 0, 419 header = red(" ## ") 420 ) 421 return 1 422 423 return 0
424 425
426 - def __remove_package(self):
427 428 # clear on-disk cache 429 self.__clear_cache() 430 431 self.Entropy.clientLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_NORMAL,"Removing package: %s" % (self.infoDict['removeatom'],)) 432 433 protected_removable_config_files = {} 434 # remove from database 435 if self.infoDict['removeidpackage'] != -1: 436 mytxt = "%s: " % (_("Removing from Entropy"),) 437 self.Entropy.updateProgress( 438 blue(mytxt) + red(self.infoDict['removeatom']), 439 importance = 1, 440 type = "info", 441 header = red(" ## ") 442 ) 443 protected_removable_config_files = self.Entropy.clientDbconn.retrieveAutomergefiles( 444 self.infoDict['removeidpackage'], get_dict = True 445 ) 446 self.__remove_package_from_database() 447 448 # Handle spm database 449 spm_atom = self.entropyTools.remove_tag(self.infoDict['removeatom']) 450 self.Entropy.clientLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_NORMAL,"Removing from Spm: "+str(spm_atom)) 451 self.__remove_package_from_spm_database(spm_atom) 452 453 self.__remove_content_from_system(protected_removable_config_files) 454 return 0
455
456 - def __remove_content_from_system(self, protected_removable_config_files):
457 458 sys_root = etpConst['systemroot'] 459 # load CONFIG_PROTECT and CONFIG_PROTECT_MASK 460 sys_settings = self.Entropy.SystemSettings 461 protect = self.Entropy.get_installed_package_config_protect( 462 self.infoDict['idpackage']) 463 mask = self.Entropy.get_installed_package_config_protect( 464 self.infoDict['idpackage'], mask = True) 465 sys_set_plg_id = \ 466 etpConst['system_settings_plugins_ids']['client_plugin'] 467 col_protect = sys_settings[sys_set_plg_id]['misc']['collisionprotect'] 468 469 # remove files from system 470 directories = set() 471 for item in self.infoDict['removecontent']: 472 sys_root_item = sys_root+item 473 # collision check 474 if col_protect > 0: 475 476 if self.Entropy.clientDbconn.isFileAvailable(item) and os.path.isfile(sys_root_item): 477 # in this way we filter out directories 478 mytxt = red(_("Collision found during removal of")) + " " + sys_root_item + " - " 479 mytxt += red(_("cannot overwrite")) 480 self.Entropy.updateProgress( 481 mytxt, 482 importance = 1, 483 type = "warning", 484 header = red(" ## ") 485 ) 486 self.Entropy.clientLog.log( 487 ETP_LOGPRI_INFO, 488 ETP_LOGLEVEL_NORMAL, 489 "Collision found during remove of "+sys_root_item+" - cannot overwrite" 490 ) 491 continue 492 493 protected = False 494 if (not self.infoDict['removeconfig']) and (not self.infoDict['diffremoval']): 495 496 protected_item_test = sys_root_item 497 if isinstance(protected_item_test,unicode): 498 protected_item_test = protected_item_test.encode('utf-8') 499 500 in_mask, protected, x, do_continue = self._handle_config_protect( 501 protect, mask, None, protected_item_test, 502 do_allocation_check = False, do_quiet = True) 503 504 if do_continue: protected = True 505 506 # when files have not been modified by the user 507 # and they are inside a config protect directory 508 # we could even remove them directly 509 if in_mask: 510 511 oldprot_md5 = protected_removable_config_files.get(item) 512 if oldprot_md5 and os.path.exists(protected_item_test) and \ 513 os.access(protected_item_test, os.R_OK): 514 515 in_system_md5 = self.entropyTools.md5sum(protected_item_test) 516 if oldprot_md5 == in_system_md5: 517 mytxt = "%s: %s" % ( 518 darkgreen(_("Removing config file, never modified")), 519 blue(item),) 520 self.Entropy.updateProgress( 521 mytxt, 522 importance = 1, 523 type = "info", 524 header = red(" ## ") 525 ) 526 protected = False 527 do_continue = False 528 529 if protected: 530 self.Entropy.clientLog.log( 531 ETP_LOGPRI_INFO, 532 ETP_LOGLEVEL_VERBOSE, 533 "[remove] Protecting config file: "+sys_root_item 534 ) 535 mytxt = "[%s] %s: %s" % ( 536 red(_("remove")), 537 brown(_("Protecting config file")), 538 sys_root_item, 539 ) 540 self.Entropy.updateProgress( 541 mytxt, 542 importance = 1, 543 type = "warning", 544 header = red(" ## ") 545 ) 546 else: 547 try: 548 os.lstat(sys_root_item) 549 except OSError: 550 continue # skip file, does not exist 551 except UnicodeEncodeError: 552 mytxt = brown(_("This package contains a badly encoded file !!!")) 553 self.Entropy.updateProgress( 554 red("QA: ")+mytxt, 555 importance = 1, 556 type = "warning", 557 header = darkred(" ## ") 558 ) 559 continue # file has a really bad encoding 560 561 if os.path.isdir(sys_root_item) and os.path.islink(sys_root_item): 562 # S_ISDIR returns False for directory symlinks, so using os.path.isdir 563 # valid directory symlink 564 directories.add((sys_root_item,"link")) 565 elif os.path.isdir(sys_root_item): 566 # plain directory 567 directories.add((sys_root_item,"dir")) 568 else: # files, symlinks or not 569 # just a file or symlink or broken directory symlink (remove now) 570 try: 571 os.remove(sys_root_item) 572 # add its parent directory 573 dirfile = os.path.dirname(sys_root_item) 574 if os.path.isdir(dirfile) and os.path.islink(dirfile): 575 directories.add((dirfile,"link")) 576 elif os.path.isdir(dirfile): 577 directories.add((dirfile,"dir")) 578 except OSError: 579 pass 580 581 # now handle directories 582 directories = sorted(directories, reverse = True) 583 while 1: 584 taint = False 585 for directory, dirtype in directories: 586 mydir = "%s%s" % (sys_root,directory,) 587 if dirtype == "link": 588 try: 589 mylist = os.listdir(mydir) 590 if not mylist: 591 try: 592 os.remove(mydir) 593 taint = True 594 except OSError: 595 pass 596 except OSError: 597 pass 598 elif dirtype == "dir": 599 try: 600 mylist = os.listdir(mydir) 601 if not mylist: 602 try: 603 os.rmdir(mydir) 604 taint = True 605 except OSError: 606 pass 607 except OSError: 608 pass 609 610 if not taint: 611 break 612 del directories
613 614 615 ''' 616 @description: remove package entry from Spm database 617 @input spm package atom (cat/name+ver): 618 @output: 0 = all fine, <0 = error! 619 '''
620 - def __remove_package_from_spm_database(self, atom):
621 622 # handle spm support 623 try: 624 Spm = self.Entropy.Spm() 625 except: 626 return -1 # no Spm support ?? 627 628 portdb_dir = Spm.get_vdb_path() 629 remove_path = portdb_dir+atom 630 key = self.entropyTools.dep_getkey(atom) 631 others_installed = [x for x in Spm.search_keys(key) if \ 632 self.entropyTools.dep_getkey(x) == key] 633 if atom in others_installed: 634 others_installed.remove(atom) 635 slot = self.infoDict['slot'] 636 tag = self.infoDict['versiontag'] 637 if (tag == slot) and tag: slot = "0" 638 639 def do_rm_path_atomic(xpath): 640 for my_el in os.listdir(xpath): 641 my_el = os.path.join(xpath, my_el) 642 try: 643 os.remove(my_el) 644 except OSError: 645 pass 646 try: 647 os.rmdir(xpath) 648 except OSError: 649 pass
650 651 if os.path.isdir(remove_path): 652 do_rm_path_atomic(remove_path) 653 654 if others_installed: 655 656 for myatom in others_installed: 657 myslot = Spm.get_installed_package_slot(myatom) 658 if myslot != slot: 659 continue 660 mydir = portdb_dir+myatom 661 if not os.path.isdir(mydir): 662 continue 663 do_rm_path_atomic(mydir) 664 665 else: 666 667 world_file = Spm.get_world_file() 668 world_file_tmp = world_file+".entropy.tmp" 669 if os.access(world_file,os.W_OK) and os.path.isfile(world_file): 670 new = open(world_file_tmp,"w") 671 old = open(world_file,"r") 672 line = old.readline() 673 while line: 674 if line.find(key) != -1: 675 line = old.readline() 676 continue 677 if line.find(key+":"+slot) != -1: 678 line = old.readline() 679 continue 680 new.write(line) 681 line = old.readline() 682 new.flush() 683 new.close() 684 old.close() 685 os.rename(world_file_tmp,world_file) 686 687 return 0 688 689 ''' 690 @description: function that runs at the end of the package installation process, just removes data left by other steps 691 @output: 0 = all fine, >0 = error! 692 '''
693 - def _cleanup_package(self, unpack_dir):
694 # remove unpack dir 695 shutil.rmtree(unpack_dir,True) 696 try: os.rmdir(unpack_dir) 697 except OSError: pass 698 return 0
699
700 - def __remove_package_from_database(self, do_commit = False, do_cleanup = False):
701 self.error_on_not_prepared() 702 self.Entropy.clientDbconn.removePackage(self.infoDict['removeidpackage'], 703 do_commit = do_commit, do_cleanup = do_cleanup) 704 return 0
705
706 - def __clear_cache(self):
707 self.Entropy.clear_dump_cache(etpCache['advisories']) 708 self.Entropy.clear_dump_cache(etpCache['filter_satisfied_deps']) 709 self.Entropy.clear_dump_cache(etpCache['depends_tree']) 710 self.Entropy.clear_dump_cache(etpCache['check_package_update']) 711 self.Entropy.clear_dump_cache(etpCache['dep_tree']) 712 self.Entropy.clear_dump_cache(etpCache['dbMatch']+etpConst['clientdbid']+"/") 713 self.Entropy.clear_dump_cache(etpCache['dbSearch']+etpConst['clientdbid']+"/") 714 715 self.__update_available_cache() 716 try: 717 self.__update_world_cache() 718 except: 719 self.Entropy.clear_dump_cache(etpCache['world_update'])
720
721 - def __update_world_cache(self):
722 if self.Entropy.xcache and (self.action in ("install","remove",)): 723 wc_dir = os.path.dirname(os.path.join(etpConst['dumpstoragedir'],etpCache['world_update'])) 724 wc_filename = os.path.basename(etpCache['world_update']) 725 wc_cache_files = [os.path.join(wc_dir,x) for x in os.listdir(wc_dir) if x.startswith(wc_filename)] 726 for cache_file in wc_cache_files: 727 728 try: 729 data = self.Entropy.dumpTools.loadobj(cache_file, complete_path = True) 730 (update, remove, fine) = data['r'] 731 empty_deps = data['empty_deps'] 732 except: 733 self.Entropy.clear_dump_cache(etpCache['world_update']) 734 return 735 736 if empty_deps: 737 continue 738 739 if self.action == "install": 740 if self.matched_atom in update: 741 update.remove(self.matched_atom) 742 self.Entropy.dumpTools.dumpobj( 743 cache_file, 744 {'r':(update, remove, fine),'empty_deps': empty_deps}, 745 complete_path = True 746 ) 747 else: 748 key, slot = self.Entropy.clientDbconn.retrieveKeySlot(self.infoDict['removeidpackage']) 749 matches = self.Entropy.atom_match(key, matchSlot = slot, multiMatch = True, multiRepo = True) 750 if matches[1] != 0: 751 # hell why! better to rip all off 752 self.Entropy.clear_dump_cache(etpCache['world_update']) 753 return 754 taint = False 755 for match in matches[0]: 756 if match in update: 757 taint = True 758 update.remove(match) 759 if match in remove: 760 taint = True 761 remove.remove(match) 762 if taint: 763 self.Entropy.dumpTools.dumpobj( 764 cache_file, 765 {'r':(update, remove, fine),'empty_deps': empty_deps}, 766 complete_path = True 767 ) 768 769 elif (not self.Entropy.xcache) or (self.action in ("install",)): 770 self.Entropy.clear_dump_cache(etpCache['world_update'])
771
772 - def __update_available_cache(self):
773 774 # update world available cache 775 if self.Entropy.xcache and (self.action in ("remove","install")): 776 777 branch = self.Entropy.SystemSettings['repositories']['branch'] 778 c_hash = self.Entropy.get_available_packages_chash(branch) 779 780 disk_cache = self.Entropy.get_available_packages_cache( 781 myhash = c_hash) 782 if disk_cache != None: 783 try: 784 785 # remove and old install 786 if self.infoDict['removeidpackage'] != -1: 787 taint = False 788 key = self.entropyTools.dep_getkey( 789 self.infoDict['removeatom']) 790 slot = self.infoDict['slot'] 791 matches = self.Entropy.atom_match(key, 792 matchSlot = slot, multiRepo = True, 793 multiMatch = True) 794 for mymatch in matches[0]: 795 if mymatch not in disk_cache: 796 disk_cache.append(mymatch) 797 taint = True 798 if taint: 799 mydata = {} 800 mylist = [] 801 for myidpackage,myrepo in disk_cache: 802 mydbc = self.Entropy.open_repository(myrepo) 803 mydata[mydbc.retrieveAtom(myidpackage)] = (myidpackage,myrepo) 804 for mykey in sorted(mydata): 805 mylist.append(mydata[mykey]) 806 disk_cache = mylist 807 808 # install, doing here because matches[0] 809 # could contain self.matched_atoms 810 if self.matched_atom in disk_cache: 811 disk_cache.remove(self.matched_atom) 812 813 self.Cacher.push("%s%s" % (etpCache['world_available'], 814 c_hash), disk_cache) 815 816 except KeyError: 817 self.Cacher.push("%s%s" % (etpCache['world_available'], 818 c_hash), {}) 819 820 elif not self.Entropy.xcache: 821 822 self.Entropy.clear_dump_cache(etpCache['world_available'])
823 824
825 - def __install_package(self):
826 827 # clear on-disk cache 828 self.__clear_cache() 829 830 self.Entropy.clientLog.log( 831 ETP_LOGPRI_INFO, 832 ETP_LOGLEVEL_NORMAL, 833 "Installing package: %s" % (self.infoDict['atom'],) 834 ) 835 836 already_protected_config_files = {} 837 if self.infoDict['removeidpackage'] != -1: 838 already_protected_config_files = self.Entropy.clientDbconn.retrieveAutomergefiles( 839 self.infoDict['removeidpackage'], get_dict = True 840 ) 841 842 # copy files over - install 843 # use fork? (in this case all the changed structures need to be pushed back) 844 rc = self.__move_image_to_system(already_protected_config_files) 845 if rc != 0: 846 return rc 847 del already_protected_config_files 848 849 # inject into database 850 mytxt = "%s: %s" % (blue(_("Updating database")),red(self.infoDict['atom']),) 851 self.Entropy.updateProgress( 852 mytxt, 853 importance = 1, 854 type = "info", 855 header = red(" ## ") 856 ) 857 newidpackage = self._install_package_into_database() 858 859 # remove old files and spm stuff 860 if self.infoDict['removeidpackage'] != -1: 861 # doing a diff removal 862 self.Entropy.clientLog.log( 863 ETP_LOGPRI_INFO, 864 ETP_LOGLEVEL_NORMAL, 865 "Remove old package: %s" % (self.infoDict['removeatom'],) 866 ) 867 self.infoDict['removeidpackage'] = -1 # disabling database removal 868 869 self.Entropy.clientLog.log( 870 ETP_LOGPRI_INFO, 871 ETP_LOGLEVEL_NORMAL, 872 "Removing Entropy and Spm database entry for %s" % ( 873 self.infoDict['removeatom'],) 874 ) 875 876 self.Entropy.updateProgress( 877 blue(_("Cleaning old package files...")), 878 importance = 1, 879 type = "info", 880 header = red(" ## ") 881 ) 882 self.__remove_package() 883 884 self.Entropy.clientLog.log( 885 ETP_LOGPRI_INFO, 886 ETP_LOGLEVEL_NORMAL, 887 "Installing new Spm database entry: %s" % (self.infoDict['atom'],) 888 ) 889 rc = self._install_package_into_spm_database(newidpackage) 890 891 return rc
892 893 ''' 894 @description: inject the database information into the Gentoo database 895 @output: 0 = all fine, !=0 = error! 896 '''
897 - def _install_package_into_spm_database(self, newidpackage):
898 899 # handle spm support 900 try: 901 Spm = self.Entropy.Spm() 902 except: 903 return -1 # no Spm support 904 905 portdb_dir = Spm.get_vdb_path() 906 if not os.path.isdir(portdb_dir): 907 os.makedirs(portdb_dir) 908 909 category = self.infoDict['category'] 910 name = self.infoDict['name'] 911 key = category + "/" + name 912 913 atomsfound = set() 914 dbdirs = os.listdir(portdb_dir) 915 if category in dbdirs: 916 catdirs = os.listdir(portdb_dir + "/" + category) 917 dirsfound = set([category + "/" + x for x in catdirs if \ 918 key == self.entropyTools.dep_getkey(category + "/" + x)]) 919 atomsfound.update(dirsfound) 920 921 ### REMOVE 922 # parse slot and match and remove 923 if atomsfound: 924 pkg_to_remove = None 925 for atom in atomsfound: 926 atomslot = Spm.get_installed_package_slot(atom) 927 # get slot from spm db 928 if atomslot == self.infoDict['slot']: 929 pkg_to_remove = atom 930 break 931 if pkg_to_remove: 932 remove_path = portdb_dir + pkg_to_remove 933 shutil.rmtree(remove_path, True) 934 try: 935 os.rmdir(remove_path) 936 except OSError: 937 pass 938 del atomsfound 939 940 # we now install it 941 xpak_rel_path = etpConst['entropyxpakdatarelativepath'] 942 if ((self.infoDict['xpakstatus'] != None) and \ 943 os.path.isdir( self.infoDict['xpakpath'] + "/" + xpak_rel_path)) or \ 944 self.infoDict['merge_from']: 945 946 if self.infoDict['merge_from']: 947 copypath = self.infoDict['xpakdir'] 948 if not os.path.isdir(copypath): 949 return 0 950 else: 951 copypath = self.infoDict['xpakpath'] + "/" + xpak_rel_path 952 953 if not os.path.isdir(portdb_dir + category): 954 os.makedirs(portdb_dir + category, 0755) 955 destination = portdb_dir + category + "/" + name + "-" + \ 956 self.infoDict['version'] 957 958 if os.path.isdir(destination): 959 shutil.rmtree(destination) 960 961 try: 962 shutil.copytree(copypath, destination) 963 except (IOError,), e: 964 mytxt = "%s: %s: %s: %s" % (red(_("QA")), 965 brown(_("Cannot update Portage database to destination")), 966 purple(destination),e,) 967 self.Entropy.updateProgress( 968 mytxt, 969 importance = 1, 970 type = "warning", 971 header = darkred(" ## ") 972 ) 973 974 # test if /var/cache/edb/counter is fine 975 if os.path.isfile(etpConst['edbcounter']): 976 try: 977 f = open(etpConst['edbcounter'],"r") 978 counter = int(f.readline().strip()) 979 f.close() 980 except: 981 # need file recreation, parse spm tree 982 counter = Spm.refill_counter() 983 else: 984 counter = Spm.refill_counter() 985 986 # write new counter to file 987 if os.path.isdir(destination): 988 counter += 1 989 f = open(destination+"/"+etpConst['spm']['xpak_entries']['counter'],"w") 990 f.write(str(counter)) 991 f.flush() 992 f.close() 993 f = open(etpConst['edbcounter'],"w") 994 f.write(str(counter)) 995 f.flush() 996 f.close() 997 # update counter inside clientDatabase 998 self.Entropy.clientDbconn.insertCounter(newidpackage, counter) 999 else: 1000 mytxt = brown(_("Cannot update Portage counter, destination %s does not exist.") % (destination,)) 1001 self.Entropy.updateProgress( 1002 red("QA: ")+mytxt, 1003 importance = 1, 1004 type = "warning", 1005 header = darkred(" ## ") 1006 ) 1007 1008 user_inst_source = etpConst['install_sources']['user'] 1009 if self.infoDict['install_source'] != user_inst_source: 1010 self.Entropy.clientLog.log( 1011 ETP_LOGPRI_INFO, 1012 ETP_LOGLEVEL_NORMAL, 1013 "Not updating Portage world file for: %s" % (self.infoDict['atom'],) 1014 ) 1015 # only user selected packages in Portage world file 1016 return 0 1017 1018 # add to Portage world 1019 # key: key 1020 # slot: self.infoDict['slot'] 1021 myslot = self.infoDict['slot'] 1022 if (self.infoDict['versiontag'] == self.infoDict['slot']) and self.infoDict['versiontag']: 1023 # usually kernel packages 1024 myslot = "0" 1025 keyslot = key+":"+myslot 1026 world_file = Spm.get_world_file() 1027 world_atoms = set() 1028 1029 if os.access(world_file,os.R_OK) and os.path.isfile(world_file): 1030 f = open(world_file,"r") 1031 world_atoms = set([x.strip() for x in f.readlines() if x.strip()]) 1032 f.close() 1033 else: 1034 mytxt = brown(_("Cannot update Portage world file, destination %s does not exist.") % (world_file,)) 1035 self.Entropy.updateProgress( 1036 red("QA: ")+mytxt, 1037 importance = 1, 1038 type = "warning", 1039 header = darkred(" ## ") 1040 ) 1041 return 0 1042 1043 try: 1044 if keyslot not in world_atoms and \ 1045 os.access(os.path.dirname(world_file),os.W_OK) and \ 1046 self.entropyTools.istextfile(world_file): 1047 world_atoms.discard(key) 1048 world_atoms.add(keyslot) 1049 world_atoms = sorted(list(world_atoms)) 1050 world_file_tmp = world_file+".entropy_inst" 1051 f = open(world_file_tmp,"w") 1052 for item in world_atoms: 1053 f.write(item+"\n") 1054 f.flush() 1055 f.close() 1056 shutil.move(world_file_tmp,world_file) 1057 except (UnicodeDecodeError,UnicodeEncodeError), e: 1058 self.entropyTools.print_traceback(f = self.Entropy.clientLog) 1059 mytxt = brown(_("Cannot update Portage world file, destination %s is corrupted.") % (world_file,)) 1060 self.Entropy.updateProgress( 1061 red("QA: ")+mytxt+": "+unicode(e), 1062 importance = 1, 1063 type = "warning", 1064 header = darkred(" ## ") 1065 ) 1066 1067 return 0
1068 1069 ''' 1070 @description: injects package info into the installed packages database 1071 @output: 0 = all fine, >0 = error! 1072 '''
1073 - def _install_package_into_database(self):
1074 1075 # fetch info 1076 smart_pkg = self.infoDict['smartpackage'] 1077 dbconn = self.Entropy.open_repository(self.infoDict['repository']) 1078 1079 if smart_pkg or self.infoDict['merge_from']: 1080 1081 data = dbconn.getPackageData(self.infoDict['idpackage'], 1082 content_insert_formatted = True) 1083 1084 else: 1085 1086 # normal repositories 1087 data = dbconn.getPackageData(self.infoDict['idpackage'], 1088 get_content = False) 1089 pkg_dbconn = self.Entropy.open_generic_database( 1090 self.infoDict['pkgdbpath']) 1091 # it is safe to consider that package dbs coming from repos 1092 # contain only one entry 1093 content = [] 1094 for pkg_idpackage in pkg_dbconn.listAllIdpackages(): 1095 content += pkg_dbconn.retrieveContent( 1096 pkg_idpackage, extended = True, 1097 formatted = True, insert_formatted = True 1098 ) 1099 real_idpk = self.infoDict['idpackage'] 1100 content = [(real_idpk, x, y,) for orig_idpk, x, y in content] 1101 data['content'] = content 1102 pkg_dbconn.closeDB() 1103 1104 # open client db 1105 # always set data['injected'] to False 1106 # installed packages database SHOULD never have more 1107 # than one package for scope (key+slot) 1108 data['injected'] = False 1109 # spm counter will be set in self._install_package_into_spm_database() 1110 data['counter'] = -1 1111 # branch must be always set properly, it could happen it's not 1112 # when installing packages through their .tbz2s 1113 data['branch'] = self.Entropy.SystemSettings['repositories']['branch'] 1114 # there is no need to store needed paths into db 1115 if data.get('needed_paths'): 1116 del data['needed_paths'] 1117 1118 idpackage, rev, x = self.Entropy.clientDbconn.handlePackage( 1119 etpData = data, forcedRevision = data['revision'], 1120 formattedContent = True) 1121 1122 # update datecreation 1123 ctime = self.entropyTools.get_current_unix_time() 1124 self.Entropy.clientDbconn.setDateCreation(idpackage, str(ctime)) 1125 1126 # add idpk to the installedtable 1127 self.Entropy.clientDbconn.removePackageFromInstalledTable(idpackage) 1128 self.Entropy.clientDbconn.addPackageToInstalledTable(idpackage, 1129 self.infoDict['repository'], self.infoDict['install_source']) 1130 1131 automerge_data = self.infoDict.get('configprotect_data') 1132 if automerge_data: 1133 self.Entropy.clientDbconn.insertAutomergefiles(idpackage, 1134 automerge_data) 1135 1136 # clear depends table, this will make clientdb dependstable to be 1137 # regenerated during the next request (retrieveDepends) 1138 self.Entropy.clientDbconn.clearDependsTable() 1139 return idpackage
1140
1141 - def __fill_image_dir(self, mergeFrom, imageDir):
1142 1143 dbconn = self.Entropy.open_repository(self.infoDict['repository']) 1144 # this is triggered by merge_from infoDict metadata 1145 # even if repositories are allowed to not have content 1146 # metadata, in this particular case, it is mandatory 1147 package_content = dbconn.retrieveContent( 1148 self.infoDict['idpackage'], extended = True, formatted = True) 1149 contents = sorted(package_content) 1150 1151 # collect files 1152 for path in contents: 1153 # convert back to filesystem str 1154 encoded_path = path 1155 path = os.path.join(mergeFrom,encoded_path[1:]) 1156 topath = os.path.join(imageDir,encoded_path[1:]) 1157 path = path.encode('raw_unicode_escape') 1158 topath = topath.encode('raw_unicode_escape') 1159 1160 try: 1161 exist = os.lstat(path) 1162 except OSError: 1163 continue # skip file 1164 ftype = package_content[encoded_path] 1165 1166 if 'dir' == ftype and \ 1167 not stat.S_ISDIR(exist.st_mode) and \ 1168 os.path.isdir(path): 1169 # workaround for directory symlink issues 1170 path = os.path.realpath(path) 1171 1172 copystat = False 1173 # if our directory is a symlink instead, then copy the symlink 1174 if os.path.islink(path): 1175 tolink = os.readlink(path) 1176 if os.path.islink(topath): 1177 os.remove(topath) 1178 os.symlink(tolink,topath) 1179 elif os.path.isdir(path): 1180 if not os.path.isdir(topath): 1181 os.makedirs(topath) 1182 copystat = True 1183 elif os.path.isfile(path): 1184 if os.path.isfile(topath): 1185 os.remove(topath) # should never happen 1186 shutil.copy2(path,topath) 1187 copystat = True 1188 1189 if copystat: 1190 user = os.stat(path)[stat.ST_UID] 1191 group = os.stat(path)[stat.ST_GID] 1192 os.chown(topath,user,group) 1193 shutil.copystat(path,topath)
1194 1195
1196 - def __move_image_to_system(self, already_protected_config_files):
1197 1198 # load CONFIG_PROTECT and its mask 1199 repoid = self.infoDict['repository'] 1200 protect = self.Entropy.get_package_match_config_protect( 1201 self.matched_atom) 1202 mask = self.Entropy.get_package_match_config_protect( 1203 self.matched_atom, mask = True) 1204 sys_root = etpConst['systemroot'] 1205 sys_set_plg_id = \ 1206 etpConst['system_settings_plugins_ids']['client_plugin'] 1207 col_protect = self.Entropy.SystemSettings[sys_set_plg_id]['misc']['collisionprotect'] 1208 items_installed = set() 1209 1210 # setup imageDir properly 1211 imageDir = self.infoDict['imagedir'] 1212 encoded_imageDir = imageDir.encode('utf-8') 1213 movefile = self.entropyTools.movefile 1214 1215 # merge data into system 1216 for currentdir,subdirs,files in os.walk(encoded_imageDir): 1217 # create subdirs 1218 for subdir in subdirs: 1219 1220 imagepathDir = "%s/%s" % (currentdir,subdir,) 1221 rootdir = "%s%s" % (sys_root,imagepathDir[len(imageDir):],) 1222 1223 # handle broken symlinks 1224 if os.path.islink(rootdir) and not os.path.exists(rootdir):# broken symlink 1225 os.remove(rootdir) 1226 1227 # if our directory is a file on the live system 1228 elif os.path.isfile(rootdir): # really weird...! 1229 self.Entropy.clientLog.log( 1230 ETP_LOGPRI_INFO, 1231 ETP_LOGLEVEL_NORMAL, 1232 "WARNING!!! %s is a file when it should be a directory !! Removing in 20 seconds..." % (rootdir,) 1233 ) 1234 mytxt = darkred(_("%s is a file when should be a directory !! Removing in 20 seconds...") % (rootdir,)) 1235 self.Entropy.updateProgress( 1236 red("QA: ")+mytxt, 1237 importance = 1, 1238 type = "warning", 1239 header = red(" !!! ") 1240 ) 1241 self.entropyTools.ebeep(20) 1242 os.remove(rootdir) 1243 1244 # if our directory is a symlink instead, then copy the symlink 1245 if os.path.islink(imagepathDir): 1246 1247 # if our live system features a directory instead of 1248 # a symlink, we should consider removing the directory 1249 if (not os.path.islink(rootdir)) and os.path.isdir(rootdir): 1250 self.Entropy.clientLog.log( 1251 ETP_LOGPRI_INFO, 1252 ETP_LOGLEVEL_NORMAL, 1253 "WARNING!!! %s is a directory when it should be a symlink !! Removing in 20 seconds..." % (rootdir,) 1254 ) 1255 mytxt = darkred(_("%s is a directory when should be a symlink !! Removing in 20 seconds...") % (rootdir,)) 1256 self.Entropy.updateProgress( 1257 red("QA: ")+mytxt, 1258 importance = 1, 1259 type = "warning", 1260 header = red(" !!! ") 1261 ) 1262 self.entropyTools.ebeep(20) 1263 shutil.rmtree(rootdir, True) 1264 os.rmdir(rootdir) 1265 1266 tolink = os.readlink(imagepathDir) 1267 live_tolink = None 1268 if os.path.islink(rootdir): 1269 live_tolink = os.readlink(rootdir) 1270 if tolink != live_tolink: 1271 if os.path.lexists(rootdir): 1272 # at this point, it must be a file 1273 os.remove(rootdir) 1274 os.symlink(tolink, rootdir) 1275 1276 elif (not os.path.isdir(rootdir)) and (not os.access(rootdir,os.R_OK)): 1277 try: 1278 # we should really force a simple mkdir first of all 1279 os.mkdir(rootdir) 1280 except OSError: 1281 os.makedirs(rootdir) 1282 1283 1284 if not os.path.islink(rootdir) and os.access(rootdir,os.W_OK): 1285 # symlink doesn't need permissions, also until os.walk ends they might be broken 1286 # XXX also, added os.access() check because there might be directories/files unwritable 1287 # what to do otherwise? 1288 user = os.stat(imagepathDir)[stat.ST_UID] 1289 group = os.stat(imagepathDir)[stat.ST_GID] 1290 os.chown(rootdir,user,group) 1291 shutil.copystat(imagepathDir,rootdir) 1292 1293 items_installed.add(os.path.join(os.path.realpath(os.path.dirname(rootdir)),os.path.basename(rootdir))) 1294 1295 for item in files: 1296 1297 fromfile = "%s/%s" % (currentdir,item,) 1298 tofile = "%s%s" % (sys_root,fromfile[len(imageDir):],) 1299 1300 if col_protect > 1: 1301 todbfile = fromfile[len(imageDir):] 1302 myrc = self._handle_install_collision_protect(tofile, todbfile) 1303 if not myrc: 1304 continue 1305 1306 prot_old_tofile = tofile[len(sys_root):] 1307 pre_tofile = tofile[:] 1308 in_mask, protected, tofile, do_continue = self._handle_config_protect( 1309 protect, mask, fromfile, tofile) 1310 1311 # collect new config automerge data 1312 if in_mask and os.path.exists(fromfile): 1313 try: 1314 prot_md5 = self.entropyTools.md5sum(fromfile) 1315 self.infoDict['configprotect_data'].append( 1316 (prot_old_tofile,prot_md5,)) 1317 except (IOError,): 1318 pass 1319 1320 # check if it's really necessary to protect file 1321 if protected: 1322 1323 try: 1324 1325 # second task 1326 oldprot_md5 = already_protected_config_files.get( 1327 prot_old_tofile) 1328 1329 if oldprot_md5 and os.path.exists(pre_tofile) and \ 1330 os.access(pre_tofile, os.R_OK): 1331 1332 in_system_md5 = self.entropyTools.md5sum(pre_tofile) 1333 if oldprot_md5 == in_system_md5: 1334 # we can merge it, files, even if 1335 # contains changes have not been modified 1336 # by the user 1337 mytxt = "%s: %s" % ( 1338 darkgreen(_("Automerging config file, never modified")), 1339 blue(pre_tofile),) 1340 self.Entropy.updateProgress( 1341 mytxt, 1342 importance = 1, 1343 type = "info", 1344 header = red(" ## ") 1345 ) 1346 protected = False 1347 do_continue = False 1348 tofile = pre_tofile 1349 1350 except (IOError,): 1351 pass 1352 1353 if do_continue: 1354 continue 1355 1356 try: 1357 1358 if os.path.realpath(fromfile) == os.path.realpath(tofile) and os.path.islink(tofile): 1359 # there is a serious issue here, better removing tofile, happened to someone: 1360 try: # try to cope... 1361 os.remove(tofile) 1362 except OSError: 1363 pass 1364 1365 # if our file is a dir on the live system 1366 if os.path.isdir(tofile) and not os.path.islink(tofile): # really weird...! 1367 self.Entropy.clientLog.log( 1368 ETP_LOGPRI_INFO, 1369 ETP_LOGLEVEL_NORMAL, 1370 "WARNING!!! %s is a directory when it should be a file !! Removing in 20 seconds..." % (tofile,) 1371 ) 1372 mytxt = _("%s is a directory when it should be a file !! Removing in 20 seconds...") % (tofile,) 1373 self.Entropy.updateProgress( 1374 red("QA: ")+darkred(mytxt), 1375 importance = 1, 1376 type = "warning", 1377 header = red(" !!! ") 1378 ) 1379 self.entropyTools.ebeep(10) 1380 time.sleep(20) 1381 try: 1382 shutil.rmtree(tofile, True) 1383 os.rmdir(tofile) 1384 except: 1385 pass 1386 try: # if it was a link 1387 os.remove(tofile) 1388 except OSError: 1389 pass 1390 1391 # XXX 1392 # XXX moving file using the raw format like portage does 1393 # XXX 1394 done = movefile(fromfile, tofile, src_basedir = encoded_imageDir) 1395 if not done: 1396 self.Entropy.clientLog.log( 1397 ETP_LOGPRI_INFO, 1398 ETP_LOGLEVEL_NORMAL, 1399 "WARNING!!! Error during file move to system: %s => %s" % (fromfile,tofile,) 1400 ) 1401 mytxt = "%s: %s => %s, %s" % (_("File move error"),fromfile,tofile,_("please report"),) 1402 self.Entropy.updateProgress( 1403 red("QA: ")+darkred(mytxt), 1404 importance = 1, 1405 type = "warning", 1406 header = red(" !!! ") 1407 ) 1408 return 4 1409 1410 except IOError, e: 1411 # try to move forward, sometimes packages might be 1412 # fucked up and contain broken things 1413 if e.errno != 2: raise 1414 1415 items_installed.add(os.path.join(os.path.realpath(os.path.dirname(tofile)),os.path.basename(tofile))) 1416 if protected: 1417 # add to disk cache 1418 self.Entropy.FileUpdates.add_to_cache(tofile, quiet = True) 1419 1420 # this is useful to avoid the removal of installed files by __remove_package just because 1421 # there's a difference in the directory path, perhaps, which is not handled correctly by 1422 # LocalRepository.contentDiff for obvious reasons (think about stuff in /usr/lib and /usr/lib64, 1423 # where the latter is just a symlink to the former) 1424 if self.infoDict.get('removecontent'): 1425 my_remove_content = set([x for x in self.infoDict['removecontent'] \ 1426 if os.path.join(os.path.realpath( 1427 os.path.dirname("%s%s" % (sys_root,x,))),os.path.basename(x) 1428 ) in items_installed]) 1429 self.infoDict['removecontent'] -= my_remove_content 1430 1431 return 0
1432
1433 - def _handle_config_protect(self, protect, mask, fromfile, tofile, 1434 do_allocation_check = True, do_quiet = False):
1435 1436 protected = False 1437 tofile_before_protect = tofile 1438 do_continue = False 1439 in_mask = False 1440 1441 try: 1442 encoded_protect = [x.encode('raw_unicode_escape') for x in protect] 1443 if tofile in encoded_protect: 1444 protected = True 1445 in_mask = True 1446 elif os.path.dirname(tofile) in encoded_protect: 1447 protected = True 1448 in_mask = True 1449 else: 1450 tofile_testdir = os.path.dirname(tofile) 1451 old_tofile_testdir = None 1452 while tofile_testdir != old_tofile_testdir: 1453 if tofile_testdir in encoded_protect: 1454 protected = True 1455 in_mask = True 1456 break 1457 old_tofile_testdir = tofile_testdir 1458 tofile_testdir = os.path.dirname(tofile_testdir) 1459 1460 if protected: # check if perhaps, file is masked, so unprotected 1461 newmask = [x.encode('raw_unicode_escape') for x in mask] 1462 if tofile in newmask: 1463 protected = False 1464 in_mask = False 1465 elif os.path.dirname(tofile) in newmask: 1466 protected = False 1467 in_mask = False 1468 else: 1469 tofile_testdir = os.path.dirname(tofile) 1470 old_tofile_testdir = None 1471 while tofile_testdir != old_tofile_testdir: 1472 if tofile_testdir in newmask: 1473 protected = False 1474 in_mask = False 1475 break 1476 old_tofile_testdir = tofile_testdir 1477 tofile_testdir = os.path.dirname(tofile_testdir) 1478 1479 if not os.path.lexists(tofile): 1480 protected = False # file doesn't exist 1481 1482 # check if it's a text file 1483 if (protected) and os.path.isfile(tofile): 1484 protected = self.entropyTools.istextfile(tofile) 1485 in_mask = protected 1486 else: 1487 protected = False # it's not a file 1488 1489 # request new tofile then 1490 if protected: 1491 sys_set_plg_id = \ 1492 etpConst['system_settings_plugins_ids']['client_plugin'] 1493 client_settings = self.Entropy.SystemSettings[sys_set_plg_id]['misc'] 1494 if tofile not in client_settings['configprotectskip']: 1495 prot_status = True 1496 if do_allocation_check: 1497 tofile, prot_status = self.entropyTools.allocate_masked_file(tofile, fromfile) 1498 if not prot_status: 1499 protected = False 1500 else: 1501 oldtofile = tofile 1502 if oldtofile.find("._cfg") != -1: 1503 oldtofile = os.path.join(os.path.dirname(oldtofile), 1504 os.path.basename(oldtofile)[10:]) 1505 if not do_quiet: 1506 self.Entropy.clientLog.log( 1507 ETP_LOGPRI_INFO, 1508 ETP_LOGLEVEL_NORMAL, 1509 "Protecting config file: %s" % (oldtofile,) 1510 ) 1511 mytxt = red("%s: %s") % (_("Protecting config file"),oldtofile,) 1512 self.Entropy.updateProgress( 1513 mytxt, 1514 importance = 1, 1515 type = "warning", 1516 header = darkred(" ## ") 1517 ) 1518 else: 1519 if not do_quiet: 1520 self.Entropy.clientLog.log( 1521 ETP_LOGPRI_INFO, 1522 ETP_LOGLEVEL_NORMAL, 1523 "Skipping config file installation/removal, as stated in client.conf: %s" % (tofile,) 1524 ) 1525 mytxt = "%s: %s" % (_("Skipping file installation/removal"),tofile,) 1526 self.Entropy.updateProgress( 1527 mytxt, 1528 importance = 1, 1529 type = "warning", 1530 header = darkred(" ## ") 1531 ) 1532 do_continue = True 1533 1534 except Exception, e: 1535 self.entropyTools.print_traceback() 1536 protected = False # safely revert to false 1537 tofile = tofile_before_protect 1538 mytxt = darkred("%s: %s") % (_("Cannot check CONFIG PROTECTION. Error"),e,) 1539 self.Entropy.updateProgress( 1540 red("QA: ")+mytxt, 1541 importance = 1, 1542 type = "warning", 1543 header = darkred(" ## ") 1544 ) 1545 1546 return in_mask, protected, tofile, do_continue
1547 1548
1549 - def _handle_install_collision_protect(self, tofile, todbfile):
1550 avail = self.Entropy.clientDbconn.isFileAvailable(todbfile, get_id = True) 1551 if (self.infoDict['removeidpackage'] not in avail) and avail: 1552 mytxt = darkred(_("Collision found during install for")) 1553 mytxt += " %s - %s" % (blue(tofile),darkred(_("cannot overwrite")),) 1554 self.Entropy.updateProgress( 1555 red("QA: ")+mytxt, 1556 importance = 1, 1557 type = "warning", 1558 header = darkred(" ## ") 1559 ) 1560 self.Entropy.clientLog.log( 1561 ETP_LOGPRI_INFO, 1562 ETP_LOGLEVEL_NORMAL, 1563 "WARNING!!! Collision found during install for %s - cannot overwrite" % (tofile,) 1564 ) 1565 return False 1566 return True
1567
1568 - def sources_fetch_step(self):
1569 self.error_on_not_prepared() 1570 down_data = self.infoDict['download'] 1571 down_keys = down_data.keys() 1572 d_cache = set() 1573 rc = 0 1574 key_cache = [os.path.basename(x) for x in down_keys] 1575 for key in sorted(down_keys): 1576 key_name = os.path.basename(key) 1577 if key_name in d_cache: continue 1578 # first fine wins 1579 for url in down_data[key]: 1580 file_name = os.path.basename(url) 1581 if self.infoDict.get('fetch_path'): 1582 dest_file = os.path.join(self.infoDict['fetch_path'], 1583 file_name) 1584 else: 1585 dest_file = os.path.join(self.infoDict['unpackdir'], 1586 file_name) 1587 rc = self._fetch_source(url, dest_file) 1588 if rc == 0: 1589 d_cache.add(key_name) 1590 break 1591 key_cache.remove(key_name) 1592 if rc != 0 and key_name not in key_cache: 1593 break 1594 rc = 0 1595 1596 return rc
1597
1598 - def _fetch_source(self, url, dest_file):
1599 rc = 1 1600 try: 1601 mytxt = "%s: %s" % (blue(_("Downloading")),brown(url),) 1602 # now fetch the new one 1603 self.Entropy.updateProgress( 1604 mytxt, 1605 importance = 1, 1606 type = "info", 1607 header = red(" ## ") 1608 ) 1609 1610 rc, data_transfer, resumed = self.Entropy.fetch_file( 1611 url, 1612 None, 1613 None, 1614 False, 1615 fetch_file_abort_function = self.fetch_abort_function, 1616 filepath = dest_file 1617 ) 1618 if rc == 0: 1619 mytxt = blue("%s: ") % (_("Successfully downloaded from"),) 1620 mytxt += red(self.entropyTools.spliturl(url)[1]) 1621 mytxt += " %s %s/%s" % (_("at"),self.entropyTools.bytes_into_human(data_transfer),_("second"),) 1622 self.Entropy.updateProgress( 1623 mytxt, 1624 importance = 1, 1625 type = "info", 1626 header = red(" ## ") 1627 ) 1628 self.Entropy.updateProgress( 1629 "%s: %s" % (blue(_("Local path")),brown(dest_file),), 1630 importance = 1, 1631 type = "info", 1632 header = red(" # ") 1633 ) 1634 else: 1635 error_message = blue("%s: %s") % ( 1636 _("Error downloading from"), 1637 red(self.entropyTools.spliturl(url)[1]), 1638 ) 1639 # something bad happened 1640 if rc == -1: 1641 error_message += " - %s." % (_("file not available on this mirror"),) 1642 elif rc == -3: 1643 error_message += " - not found." 1644 elif rc == -100: 1645 error_message += " - %s." % (_("discarded download"),) 1646 else: 1647 error_message += " - %s: %s" % (_("unknown reason"),rc,) 1648 self.Entropy.updateProgress( 1649 error_message, 1650 importance = 1, 1651 type = "warning", 1652 header = red(" ## ") 1653 ) 1654 except KeyboardInterrupt: 1655 pass 1656 return rc
1657
1658 - def fetch_step(self):
1659 self.error_on_not_prepared() 1660 mytxt = "%s: %s" % (blue(_("Downloading archive")), 1661 red(os.path.basename(self.infoDict['download'])),) 1662 self.Entropy.updateProgress( 1663 mytxt, 1664 importance = 1, 1665 type = "info", 1666 header = red(" ## ") 1667 ) 1668 1669 rc = 0 1670 if not self.infoDict['verified']: 1671 rc = self.Entropy.fetch_file_on_mirrors( 1672 self.infoDict['repository'], 1673 self.Entropy.get_branch_from_download_relative_uri(self.infoDict['download']), 1674 self.infoDict['download'], 1675 self.infoDict['checksum'], 1676 fetch_abort_function = self.fetch_abort_function 1677 ) 1678 if rc != 0: 1679 mytxt = "%s. %s: %s" % ( 1680 red(_("Package cannot be fetched. Try to update repositories and retry")), 1681 blue(_("Error")), 1682 rc, 1683 ) 1684 self.Entropy.updateProgress( 1685 mytxt, 1686 importance = 1, 1687 type = "error", 1688 header = darkred(" ## ") 1689 ) 1690 return rc
1691
1692 - def multi_fetch_step(self):
1693 self.error_on_not_prepared() 1694 m_fetch_len = len(self.infoDict['multi_fetch_list']) 1695 mytxt = "%s: %s %s" % (blue(_("Downloading")),darkred(str(m_fetch_len)),_("archives"),) 1696 self.Entropy.updateProgress( 1697 mytxt, 1698 importance = 1, 1699 type = "info", 1700 header = red(" ## ") 1701 ) 1702 # fetch_files_on_mirrors(self, download_list, checksum = False, fetch_abort_function = None) 1703 rc, err_list = self.Entropy.fetch_files_on_mirrors( 1704 self.infoDict['multi_fetch_list'], 1705 self.infoDict['checksum'], 1706 fetch_abort_function = self.fetch_abort_function 1707 ) 1708 if rc != 0: 1709 mytxt = "%s. %s: %s" % ( 1710 red(_("Some packages cannot be fetched. Try to update repositories and retry")), 1711 blue(_("Error")), 1712 rc, 1713 ) 1714 self.Entropy.updateProgress( 1715 mytxt, 1716 importance = 1, 1717 type = "error", 1718 header = darkred(" ## ") 1719 ) 1720 for repo,branch,fname,cksum in err_list: 1721 self.Entropy.updateProgress( 1722 "[%s:%s|%s] %s" % (blue(repo),brown(branch), 1723 darkgreen(cksum),darkred(fname),), 1724 importance = 1, 1725 type = "error", 1726 header = darkred(" # ") 1727 ) 1728 return rc
1729
1730 - def fetch_not_available_step(self):
1731 self.Entropy.updateProgress( 1732 blue(_("Fetch for the chosen package is not available, unknown error.")), 1733 importance = 1, 1734 type = "info", 1735 header = red(" ## ") 1736 ) 1737 return 0
1738
1739 - def vanished_step(self):
1740 self.Entropy.updateProgress( 1741 blue(_("Installed package in queue vanished, skipping.")), 1742 importance = 1, 1743 type = "info", 1744 header = red(" ## ") 1745 ) 1746 return 0
1747
1748 - def checksum_step(self):
1749 self.error_on_not_prepared() 1750 return self.match_checksum()
1751
1752 - def multi_checksum_step(self):
1753 self.error_on_not_prepared() 1754 return self.multi_match_checksum()
1755
1756 - def unpack_step(self):
1757 self.error_on_not_prepared() 1758 1759 if not self.infoDict['merge_from']: 1760 mytxt = "%s: %s" % (blue(_("Unpacking package")),red(os.path.basename(self.infoDict['download'])),) 1761 self.Entropy.updateProgress( 1762 mytxt, 1763 importance = 1, 1764 type = "info", 1765 header = red(" ## ") 1766 ) 1767 else: 1768 mytxt = "%s: %s" % (blue(_("Merging package")),red(os.path.basename(self.infoDict['atom'])),) 1769 self.Entropy.updateProgress( 1770 mytxt, 1771 importance = 1, 1772 type = "info", 1773 header = red(" ## ") 1774 ) 1775 rc = self.__unpack_package() 1776 if rc != 0: 1777 if rc == 512: 1778 errormsg = "%s. %s. %s: 512" % ( 1779 red(_("You are running out of disk space")), 1780 red(_("I bet, you're probably Michele")), 1781 blue(_("Error")), 1782 ) 1783 else: 1784 errormsg = "%s. %s. %s: %s" % ( 1785 red(_("An error occured while trying to unpack the package")), 1786 red(_("Check if your system is healthy")), 1787 blue(_("Error")), 1788 rc, 1789 ) 1790 self.Entropy.updateProgress( 1791 errormsg, 1792 importance = 1, 1793 type = "error", 1794 header = red(" ## ") 1795 ) 1796 return rc
1797
1798 - def install_step(self):
1799 self.error_on_not_prepared() 1800 mytxt = "%s: %s" % (blue(_("Installing package")),red(self.infoDict['atom']),) 1801 self.Entropy.updateProgress( 1802 mytxt, 1803 importance = 1, 1804 type = "info", 1805 header = red(" ## ") 1806 ) 1807 rc = self.__install_package() 1808 if rc != 0: 1809 mytxt = "%s. %s. %s: %s" % ( 1810 red(_("An error occured while trying to install the package")), 1811 red(_("Check if your system is healthy")), 1812 blue(_("Error")), 1813 rc, 1814 ) 1815 self.Entropy.updateProgress( 1816 mytxt, 1817 importance = 1, 1818 type = "error", 1819 header = red(" ## ") 1820 ) 1821 return rc
1822
1823 - def remove_step(self):
1824 self.error_on_not_prepared() 1825 mytxt = "%s: %s" % (blue(_("Removing data")),red(self.infoDict['removeatom']),) 1826 self.Entropy.updateProgress( 1827 mytxt, 1828 importance = 1, 1829 type = "info", 1830 header = red(" ## ") 1831 ) 1832 rc = self.__remove_package() 1833 if rc != 0: 1834 mytxt = "%s. %s. %s: %s" % ( 1835 red(_("An error occured while trying to remove the package")), 1836 red(_("Check if you have enough disk space on your hard disk")), 1837 blue(_("Error")), 1838 rc, 1839 ) 1840 self.Entropy.updateProgress( 1841 mytxt, 1842 importance = 1, 1843 type = "error", 1844 header = red(" ## ") 1845 ) 1846 return rc
1847
1848 - def cleanup_step(self):
1849 self.error_on_not_prepared() 1850 mytxt = "%s: %s" % (blue(_("Cleaning")),red(self.infoDict['atom']),) 1851 self.Entropy.updateProgress( 1852 mytxt, 1853 importance = 1, 1854 type = "info", 1855 header = red(" ## ") 1856 ) 1857 self._cleanup_package(self.infoDict['unpackdir']) 1858 # we don't care if cleanupPackage fails since it's not critical 1859 return 0
1860
1861 - def logmessages_step(self):
1862 for msg in self.infoDict['messages']: 1863 self.Entropy.clientLog.write(">>> "+msg) 1864 return 0
1865
1866 - def postinstall_step(self):
1867 self.error_on_not_prepared() 1868 pkgdata = self.infoDict['triggers'].get('install') 1869 if pkgdata: 1870 trigger = self.Entropy.Triggers('postinstall',pkgdata, self.action) 1871 do = trigger.prepare() 1872 if do: 1873 trigger.run() 1874 trigger.kill() 1875 del pkgdata 1876 return 0
1877
1878 - def preinstall_step(self):
1879 self.error_on_not_prepared() 1880 pkgdata = self.infoDict['triggers'].get('install') 1881 if pkgdata: 1882 1883 trigger = self.Entropy.Triggers('preinstall',pkgdata, self.action) 1884 do = trigger.prepare() 1885 if self.infoDict.get("diffremoval") and do: 1886 # diffremoval is true only when the 1887 # removal is triggered by a package install 1888 remdata = self.infoDict['triggers'].get('remove') 1889 if remdata: 1890 r_trigger = self.Entropy.Triggers('preremove',remdata, self.action) 1891 r_trigger.prepare() 1892 r_trigger.triggers = [x for x in trigger.triggers if x not in r_trigger.triggers] 1893 r_trigger.kill() 1894 del remdata 1895 if do: 1896 trigger.run() 1897 trigger.kill() 1898 1899 del pkgdata 1900 return 0
1901
1902 - def preremove_step(self):
1903 self.error_on_not_prepared() 1904 remdata = self.infoDict['triggers'].get('remove') 1905 if remdata: 1906 trigger = self.Entropy.Triggers('preremove',remdata, self.action) 1907 do = trigger.prepare() 1908 if do: 1909 trigger.run() 1910 trigger.kill() 1911 del remdata 1912 return 0
1913
1914 - def postremove_step(self):
1915 self.error_on_not_prepared() 1916 remdata = self.infoDict['triggers'].get('remove') 1917 if remdata: 1918 1919 trigger = self.Entropy.Triggers('postremove',remdata, self.action) 1920 do = trigger.prepare() 1921 if self.infoDict['diffremoval'] and (self.infoDict.get("atom") != None) and do: 1922 # diffremoval is true only when the remove action is triggered by installPackages() 1923 pkgdata = self.infoDict['triggers'].get('install') 1924 if pkgdata: 1925 i_trigger = self.Entropy.Triggers('postinstall',pkgdata, self.action) 1926 i_trigger.prepare() 1927 i_trigger.triggers = [x for x in trigger.triggers if x not in i_trigger.triggers] 1928 i_trigger.kill() 1929 del pkgdata 1930 if do: 1931 trigger.run() 1932 trigger.kill() 1933 1934 del remdata 1935 return 0
1936
1937 - def removeconflict_step(self):
1938 self.error_on_not_prepared() 1939 for idpackage in self.infoDict['conflicts']: 1940 if not self.Entropy.clientDbconn.isIDPackageAvailable(idpackage): 1941 continue 1942 pkg = self.Entropy.Package() 1943 pkg.prepare((idpackage,),"remove_conflict", self.infoDict['remove_metaopts']) 1944 rc = pkg.run(xterm_header = self.xterm_title) 1945 pkg.kill() 1946 if rc != 0: 1947 return rc 1948 1949 return 0
1950
1951 - def config_step(self):
1952 self.error_on_not_prepared() 1953 mytxt = "%s: %s" % (blue(_("Configuring package")),red(self.infoDict['atom']),) 1954 self.Entropy.updateProgress( 1955 mytxt, 1956 importance = 1, 1957 type = "info", 1958 header = red(" ## ") 1959 ) 1960 rc = self.__configure_package() 1961 if rc == 1: 1962 mytxt = "%s. %s. %s: %s" % ( 1963 red(_("An error occured while trying to configure the package")), 1964 red(_("Make sure that your system is healthy")), 1965 blue(_("Error")), 1966 rc, 1967 ) 1968 self.Entropy.updateProgress( 1969 mytxt, 1970 importance = 1, 1971 type = "error", 1972 header = red(" ## ") 1973 ) 1974 elif rc == 2: 1975 mytxt = "%s. %s. %s: %s" % ( 1976 red(_("An error occured while trying to configure the package")), 1977 red(_("It seems that the Source Package Manager entry is missing")), 1978 blue(_("Error")), 1979 rc, 1980 ) 1981 self.Entropy.updateProgress( 1982 mytxt, 1983 importance = 1, 1984 type = "error", 1985 header = red(" ## ") 1986 ) 1987 return rc
1988
1989 - def run_stepper(self, xterm_header):
1990 if xterm_header == None: 1991 xterm_header = "" 1992 1993 if self.infoDict.has_key('remove_installed_vanished'): 1994 self.xterm_title += ' Installed package vanished' 1995 self.Entropy.setTitle(self.xterm_title) 1996 rc = self.vanished_step() 1997 return rc 1998 1999 if self.infoDict.has_key('fetch_not_available'): 2000 self.xterm_title += ' Fetch not available' 2001 self.Entropy.setTitle(self.xterm_title) 2002 rc = self.fetch_not_available_step() 2003 return rc 2004 2005 def do_fetch(): 2006 self.xterm_title += ' %s: %s' % (_("Fetching"),os.path.basename(self.infoDict['download']),) 2007 self.Entropy.setTitle(self.xterm_title) 2008 return self.fetch_step()
2009 2010 def do_multi_fetch(): 2011 self.xterm_title += ' %s: %s %s' % (_("Multi Fetching"), 2012 len(self.infoDict['multi_fetch_list']),_("packages"),) 2013 self.Entropy.setTitle(self.xterm_title) 2014 return self.multi_fetch_step() 2015 2016 def do_sources_fetch(): 2017 self.xterm_title += ' %s: %s' % (_("Fetching sources"),os.path.basename(self.infoDict['atom']),) 2018 self.Entropy.setTitle(self.xterm_title) 2019 return self.sources_fetch_step() 2020 2021 def do_checksum(): 2022 self.xterm_title += ' %s: %s' % (_("Verifying"),os.path.basename(self.infoDict['download']),) 2023 self.Entropy.setTitle(self.xterm_title) 2024 return self.checksum_step() 2025 2026 def do_multi_checksum(): 2027 self.xterm_title += ' %s: %s %s' % (_("Multi Verification"), 2028 len(self.infoDict['multi_checksum_list']),_("packages"),) 2029 self.Entropy.setTitle(self.xterm_title) 2030 return self.multi_checksum_step() 2031 2032 def do_unpack(): 2033 if not self.infoDict['merge_from']: 2034 mytxt = _("Unpacking") 2035 self.xterm_title += ' %s: %s' % (mytxt,os.path.basename(self.infoDict['download']),) 2036 else: 2037 mytxt = _("Merging") 2038 self.xterm_title += ' %s: %s' % (mytxt,os.path.basename(self.infoDict['atom']),) 2039 self.Entropy.setTitle(self.xterm_title) 2040 return self.unpack_step() 2041 2042 def do_remove_conflicts(): 2043 return self.removeconflict_step() 2044 2045 def do_install(): 2046 self.xterm_title += ' %s: %s' % (_("Installing"),self.infoDict['atom'],) 2047 self.Entropy.setTitle(self.xterm_title) 2048 return self.install_step() 2049 2050 def do_remove(): 2051 self.xterm_title += ' %s: %s' % (_("Removing"),self.infoDict['removeatom'],) 2052 self.Entropy.setTitle(self.xterm_title) 2053 return self.remove_step() 2054 2055 def do_logmessages(): 2056 return self.logmessages_step() 2057 2058 def do_cleanup(): 2059 self.xterm_title += ' %s: %s' % (_("Cleaning"),self.infoDict['atom'],) 2060 self.Entropy.setTitle(self.xterm_title) 2061 return self.cleanup_step() 2062 2063 def do_postinstall(): 2064 self.xterm_title += ' %s: %s' % (_("Postinstall"),self.infoDict['atom'],) 2065 self.Entropy.setTitle(self.xterm_title) 2066 return self.postinstall_step() 2067 2068 def do_preinstall(): 2069 self.xterm_title += ' %s: %s' % (_("Preinstall"),self.infoDict['atom'],) 2070 self.Entropy.setTitle(self.xterm_title) 2071 return self.preinstall_step() 2072 2073 def do_preremove(): 2074 self.xterm_title += ' %s: %s' % (_("Preremove"),self.infoDict['removeatom'],) 2075 self.Entropy.setTitle(self.xterm_title) 2076 return self.preremove_step() 2077 2078 def do_postremove(): 2079 self.xterm_title += ' %s: %s' % (_("Postremove"),self.infoDict['removeatom'],) 2080 self.Entropy.setTitle(self.xterm_title) 2081 return self.postremove_step() 2082 2083 def do_config(): 2084 self.xterm_title += ' %s: %s' % (_("Configuring"),self.infoDict['atom'],) 2085 self.Entropy.setTitle(self.xterm_title) 2086 return self.config_step() 2087 2088 steps_data = { 2089 "fetch": do_fetch, 2090 "multi_fetch": do_multi_fetch, 2091 "multi_checksum": do_multi_checksum, 2092 "sources_fetch": do_sources_fetch, 2093 "checksum": do_checksum, 2094 "unpack": do_unpack, 2095 "remove_conflicts": do_remove_conflicts, 2096 "install": do_install, 2097 "remove": do_remove, 2098 "logmessages": do_logmessages, 2099 "cleanup": do_cleanup, 2100 "postinstall": do_postinstall, 2101 "preinstall": do_preinstall, 2102 "postremove": do_postremove, 2103 "preremove": do_preremove, 2104 "config": do_config, 2105 } 2106 2107 rc = 0 2108 for step in self.infoDict['steps']: 2109 self.xterm_title = xterm_header 2110 rc = steps_data.get(step)() 2111 if rc != 0: break 2112 return rc 2113 2114 2115 ''' 2116 @description: execute the requested steps 2117 @input xterm_header: purely optional 2118 '''
2119 - def run(self, xterm_header = None):
2120 self.error_on_not_prepared() 2121 2122 gave_up = self.Entropy.lock_check(self.Entropy.resources_check_lock) 2123 if gave_up: 2124 return 20 2125 2126 locked = self.Entropy.application_lock_check() 2127 if locked: 2128 self.Entropy.resources_remove_lock() 2129 return 21 2130 2131 # lock 2132 self.Entropy.resources_create_lock() 2133 2134 try: 2135 rc = self.run_stepper(xterm_header) 2136 except: 2137 self.Entropy.resources_remove_lock() 2138 raise 2139 2140 # remove lock 2141 self.Entropy.resources_remove_lock() 2142 2143 if rc != 0: 2144 self.Entropy.updateProgress( 2145 blue(_("An error occured. Action aborted.")), 2146 importance = 2, 2147 type = "error", 2148 header = darkred(" ## ") 2149 ) 2150 return rc
2151 2152 ''' 2153 Install/Removal process preparation function 2154 - will generate all the metadata needed to run the action steps, creating infoDict automatically 2155 @input matched_atom(tuple): is what is returned by EquoInstance.atom_match: 2156 (idpackage,repoid): 2157 (2000,u'sabayonlinux.org') 2158 NOTE: in case of remove action, matched_atom must be: 2159 (idpackage,) 2160 NOTE: in case of multi_fetch, matched_atom can be a list of matches 2161 @input action(string): is an action to take, which must be one in self.valid_actions 2162 '''
2163 - def prepare(self, matched_atom, action, metaopts = {}):
2164 2165 self.error_on_prepared() 2166 self.check_action_validity(action) 2167 2168 self.action = action 2169 self.matched_atom = matched_atom 2170 self.metaopts = metaopts 2171 # generate metadata dictionary 2172 self.generate_metadata()
2173
2174 - def generate_metadata(self):
2175 self.error_on_prepared() 2176 self.check_action_validity(self.action) 2177 2178 if self.action == "fetch": 2179 self.__generate_fetch_metadata() 2180 elif self.action == "multi_fetch": 2181 self.__generate_multi_fetch_metadata() 2182 elif self.action in ("remove","remove_conflict"): 2183 self.__generate_remove_metadata() 2184 elif self.action == "install": 2185 self.__generate_install_metadata() 2186 elif self.action == "source": 2187 self.__generate_fetch_metadata(sources = True) 2188 elif self.action == "config": 2189 self.__generate_config_metadata() 2190 self.prepared = True
2191
2192 - def __generate_remove_metadata(self):
2193 self.infoDict.clear() 2194 idpackage = self.matched_atom[0] 2195 2196 if not self.Entropy.clientDbconn.isIDPackageAvailable(idpackage): 2197 self.infoDict['remove_installed_vanished'] = True 2198 return 0 2199 2200 self.infoDict['idpackage'] = idpackage 2201 self.infoDict['configprotect_data'] = [] 2202 self.infoDict['triggers'] = {} 2203 self.infoDict['removeatom'] = self.Entropy.clientDbconn.retrieveAtom(idpackage) 2204 self.infoDict['slot'] = self.Entropy.clientDbconn.retrieveSlot(idpackage) 2205 self.infoDict['versiontag'] = self.Entropy.clientDbconn.retrieveVersionTag(idpackage) 2206 self.infoDict['removeidpackage'] = idpackage 2207 self.infoDict['diffremoval'] = False 2208 removeConfig = False 2209 if self.metaopts.has_key('removeconfig'): 2210 removeConfig = self.metaopts.get('removeconfig') 2211 self.infoDict['removeconfig'] = removeConfig 2212 self.infoDict['removecontent'] = self.Entropy.clientDbconn.retrieveContent(idpackage) 2213 self.infoDict['triggers']['remove'] = self.Entropy.clientDbconn.getTriggerInfo(idpackage) 2214 self.infoDict['triggers']['remove']['removecontent'] = self.infoDict['removecontent'] 2215 self.infoDict['steps'] = [] 2216 self.infoDict['steps'].append("preremove") 2217 self.infoDict['steps'].append("remove") 2218 self.infoDict['steps'].append("postremove") 2219 2220 return 0
2221
2222 - def __generate_config_metadata(self):
2223 self.infoDict.clear() 2224 idpackage = self.matched_atom[0] 2225 2226 self.infoDict['atom'] = self.Entropy.clientDbconn.retrieveAtom(idpackage) 2227 key, slot = self.Entropy.clientDbconn.retrieveKeySlot(idpackage) 2228 self.infoDict['key'], self.infoDict['slot'] = key, slot 2229 self.infoDict['version'] = self.Entropy.clientDbconn.retrieveVersion(idpackage) 2230 self.infoDict['steps'] = [] 2231 self.infoDict['steps'].append("config") 2232 2233 return 0
2234
2235 - def __generate_install_metadata(self):
2236 self.infoDict.clear() 2237 2238 idpackage, repository = self.matched_atom 2239 self.infoDict['idpackage'] = idpackage 2240 self.infoDict['repository'] = repository 2241 2242 # fetch abort function 2243 if self.metaopts.has_key('fetch_abort_function'): 2244 self.fetch_abort_function = self.metaopts.pop('fetch_abort_function') 2245 2246 install_source = etpConst['install_sources']['unknown'] 2247 meta_inst_source = self.metaopts.get('install_source', install_source) 2248 if meta_inst_source in etpConst['install_sources'].values(): 2249 install_source = meta_inst_source 2250 self.infoDict['install_source'] = install_source 2251 2252 self.infoDict['configprotect_data'] = [] 2253 dbconn = self.Entropy.open_repository(repository) 2254 self.infoDict['triggers'] = {} 2255 self.infoDict['atom'] = dbconn.retrieveAtom(idpackage) 2256 self.infoDict['slot'] = dbconn.retrieveSlot(idpackage) 2257 self.infoDict['version'], self.infoDict['versiontag'], self.infoDict['revision'] = dbconn.getVersioningData(idpackage) 2258 self.infoDict['category'] = dbconn.retrieveCategory(idpackage) 2259 self.infoDict['download'] = dbconn.retrieveDownloadURL(idpackage) 2260 self.infoDict['name'] = dbconn.retrieveName(idpackage) 2261 self.infoDict['messages'] = dbconn.retrieveMessages(idpackage) 2262 self.infoDict['checksum'] = dbconn.retrieveDigest(idpackage) 2263 self.infoDict['signatures'] = dbconn.retrieveSignatures(idpackage) 2264 self.infoDict['accept_license'] = dbconn.retrieveLicensedataKeys(idpackage) 2265 self.infoDict['conflicts'] = self.Entropy.get_match_conflicts(self.matched_atom) 2266 2267 # fill action queue 2268 self.infoDict['removeidpackage'] = -1 2269 removeConfig = False 2270 if self.metaopts.has_key('removeconfig'): 2271 removeConfig = self.metaopts.get('removeconfig') 2272 2273 self.infoDict['remove_metaopts'] = { 2274 'removeconfig': True, 2275 } 2276 if self.metaopts.has_key('remove_metaopts'): 2277 self.infoDict['remove_metaopts'] = self.metaopts.get('remove_metaopts') 2278 2279 self.infoDict['merge_from'] = None 2280 mf = self.metaopts.get('merge_from') 2281 if mf != None: 2282 self.infoDict['merge_from'] = unicode(mf) 2283 self.infoDict['removeconfig'] = removeConfig 2284 2285 pkgkey = self.entropyTools.dep_getkey(self.infoDict['atom']) 2286 inst_match = self.Entropy.clientDbconn.atomMatch(pkgkey, matchSlot = self.infoDict['slot']) 2287 inst_idpackage = -1 2288 if inst_match[1] == 0: inst_idpackage = inst_match[0] 2289 self.infoDict['removeidpackage'] = inst_idpackage 2290 2291 if self.infoDict['removeidpackage'] != -1: 2292 avail = self.Entropy.clientDbconn.isIDPackageAvailable(self.infoDict['removeidpackage']) 2293 if avail: 2294 self.infoDict['removeatom'] = self.Entropy.clientDbconn.retrieveAtom(self.infoDict['removeidpackage']) 2295 else: 2296 self.infoDict['removeidpackage'] = -1 2297 2298 # smartpackage ? 2299 self.infoDict['smartpackage'] = False 2300 # set unpack dir and image dir 2301 if self.infoDict['repository'].endswith(etpConst['packagesext']): 2302 # do arch check 2303 compiled_arch = dbconn.retrieveDownloadURL(idpackage) 2304 if compiled_arch.find("/"+etpSys['arch']+"/") == -1: 2305 self.infoDict.clear() 2306 self.prepared = False 2307 return -1 2308 self.infoDict['smartpackage'] = self.Entropy.SystemSettings['repositories']['available'][self.infoDict['repository']]['smartpackage'] 2309 self.infoDict['pkgpath'] = self.Entropy.SystemSettings['repositories']['available'][self.infoDict['repository']]['pkgpath'] 2310 else: 2311 self.infoDict['pkgpath'] = etpConst['entropyworkdir']+"/"+self.infoDict['download'] 2312 self.infoDict['unpackdir'] = etpConst['entropyunpackdir']+"/"+self.infoDict['download'] 2313 self.infoDict['imagedir'] = etpConst['entropyunpackdir']+"/"+self.infoDict['download']+"/"+etpConst['entropyimagerelativepath'] 2314 2315 self.infoDict['pkgdbpath'] = os.path.join(self.infoDict['unpackdir'], 2316 "edb/pkg.db") 2317 2318 # spm xpak data 2319 self.infoDict['xpakpath'] = etpConst['entropyunpackdir'] + "/" + \ 2320 self.infoDict['download'] + "/" + \ 2321 etpConst['entropyxpakrelativepath'] 2322 if not self.infoDict['merge_from']: 2323 self.infoDict['xpakstatus'] = None 2324 self.infoDict['xpakdir'] = self.infoDict['xpakpath'] + "/" + \ 2325 etpConst['entropyxpakdatarelativepath'] 2326 else: 2327 self.infoDict['xpakstatus'] = True 2328 portdbdir = 'var/db/pkg' # XXX hard coded ? 2329 portdbdir = os.path.join(self.infoDict['merge_from'], portdbdir) 2330 portdbdir = os.path.join(portdbdir, self.infoDict['category']) 2331 portdbdir = os.path.join(portdbdir, self.infoDict['name'] + "-" + \ 2332 self.infoDict['version']) 2333 self.infoDict['xpakdir'] = portdbdir 2334 2335 # compare both versions and if they match, disable removeidpackage 2336 if self.infoDict['removeidpackage'] != -1: 2337 installedVer, installedTag, installedRev = self.Entropy.clientDbconn.getVersioningData(self.infoDict['removeidpackage']) 2338 pkgcmp = self.entropyTools.entropy_compare_versions( 2339 (self.infoDict['version'], self.infoDict['versiontag'], self.infoDict['revision'],), 2340 (installedVer, installedTag, installedRev,) 2341 ) 2342 if pkgcmp == 0: 2343 self.infoDict['removeidpackage'] = -1 2344 else: 2345 # differential remove list 2346 self.infoDict['diffremoval'] = True 2347 self.infoDict['removeatom'] = self.Entropy.clientDbconn.retrieveAtom(self.infoDict['removeidpackage']) 2348 self.infoDict['removecontent'] = self.Entropy.clientDbconn.contentDiff( 2349 self.infoDict['removeidpackage'], 2350 dbconn, 2351 idpackage 2352 ) 2353 self.infoDict['triggers']['remove'] = self.Entropy.clientDbconn.getTriggerInfo( 2354 self.infoDict['removeidpackage'] 2355 ) 2356 self.infoDict['triggers']['remove']['removecontent'] = self.infoDict['removecontent'] 2357 2358 # set steps 2359 self.infoDict['steps'] = [] 2360 if self.infoDict['conflicts']: 2361 self.infoDict['steps'].append("remove_conflicts") 2362 # install 2363 self.infoDict['steps'].append("unpack") 2364 # preinstall placed before preremove in order 2365 # to respect Spm order 2366 self.infoDict['steps'].append("preinstall") 2367 if (self.infoDict['removeidpackage'] != -1): 2368 self.infoDict['steps'].append("preremove") 2369 self.infoDict['steps'].append("install") 2370 if (self.infoDict['removeidpackage'] != -1): 2371 self.infoDict['steps'].append("postremove") 2372 self.infoDict['steps'].append("postinstall") 2373 self.infoDict['steps'].append("logmessages") 2374 self.infoDict['steps'].append("cleanup") 2375 2376 self.infoDict['triggers']['install'] = dbconn.getTriggerInfo(idpackage) 2377 self.infoDict['triggers']['install']['accept_license'] = self.infoDict['accept_license'] 2378 self.infoDict['triggers']['install']['unpackdir'] = self.infoDict['unpackdir'] 2379 self.infoDict['triggers']['install']['imagedir'] = self.infoDict['imagedir'] 2380 self.infoDict['triggers']['install']['xpakdir'] = self.infoDict['xpakdir'] 2381 2382 return 0
2383
2384 - def __generate_fetch_metadata(self, sources = False):
2385 self.infoDict.clear() 2386 2387 idpackage, repository = self.matched_atom 2388 dochecksum = True 2389 2390 # fetch abort function 2391 if self.metaopts.has_key('fetch_abort_function'): 2392 self.fetch_abort_function = self.metaopts.pop('fetch_abort_function') 2393 2394 if self.metaopts.has_key('dochecksum'): 2395 dochecksum = self.metaopts.get('dochecksum') 2396 2397 # fetch_path is the path where data should be downloaded 2398 # at the moment is implemented only for sources = True 2399 if self.metaopts.has_key('fetch_path'): 2400 fetch_path = self.metaopts.get('fetch_path') 2401 if self.entropyTools.is_valid_path(fetch_path): 2402 self.infoDict['fetch_path'] = fetch_path 2403 2404 self.infoDict['repository'] = repository 2405 self.infoDict['idpackage'] = idpackage 2406 dbconn = self.Entropy.open_repository(repository) 2407 self.infoDict['atom'] = dbconn.retrieveAtom(idpackage) 2408 if sources: 2409 self.infoDict['download'] = dbconn.retrieveSources(idpackage, extended = True) 2410 else: 2411 self.infoDict['checksum'] = dbconn.retrieveDigest(idpackage) 2412 self.infoDict['signatures'] = dbconn.retrieveSignatures(idpackage) 2413 self.infoDict['download'] = dbconn.retrieveDownloadURL(idpackage) 2414 2415 if not self.infoDict['download']: 2416 self.infoDict['fetch_not_available'] = True 2417 return 0 2418 2419 self.infoDict['verified'] = False 2420 self.infoDict['steps'] = [] 2421 if not repository.endswith(etpConst['packagesext']) and not sources: 2422 if self.Entropy.check_needed_package_download(self.infoDict['download'], None) < 0: 2423 self.infoDict['steps'].append("fetch") 2424 if dochecksum: 2425 self.infoDict['steps'].append("checksum") 2426 elif sources: 2427 self.infoDict['steps'].append("sources_fetch") 2428 2429 if sources: 2430 # create sources destination directory 2431 unpack_dir = etpConst['entropyunpackdir']+"/sources/"+self.infoDict['atom'] 2432 self.infoDict['unpackdir'] = unpack_dir 2433 if not self.infoDict.get('fetch_path'): 2434 if os.path.lexists(unpack_dir): 2435 if os.path.isfile(unpack_dir): 2436 os.remove(unpack_dir) 2437 elif os.path.isdir(unpack_dir): 2438 shutil.rmtree(unpack_dir,True) 2439 if not os.path.lexists(unpack_dir): 2440 os.makedirs(unpack_dir,0775) 2441 const_setup_perms(unpack_dir,etpConst['entropygid']) 2442 2443 else: 2444 # if file exists, first checksum then fetch 2445 if os.path.isfile(os.path.join(etpConst['entropyworkdir'],self.infoDict['download'])): 2446 # check size first 2447 repo_size = dbconn.retrieveSize(idpackage) 2448 f = open(os.path.join(etpConst['entropyworkdir'],self.infoDict['download']),"r") 2449 f.seek(0,2) 2450 disk_size = f.tell() 2451 f.close() 2452 if repo_size == disk_size: 2453 self.infoDict['steps'].reverse() 2454 return 0
2455
2456 - def __generate_multi_fetch_metadata(self):
2457 self.infoDict.clear() 2458 2459 if not isinstance(self.matched_atom,list): 2460 raise IncorrectParameter("IncorrectParameter: " 2461 "matched_atom must be a list of tuples, not %s" % (type(self.matched_atom,)) 2462 ) 2463 2464 dochecksum = True 2465 2466 # meta options 2467 if self.metaopts.has_key('fetch_abort_function'): 2468 self.fetch_abort_function = self.metaopts.pop('fetch_abort_function') 2469 if self.metaopts.has_key('dochecksum'): 2470 dochecksum = self.metaopts.get('dochecksum') 2471 self.infoDict['checksum'] = dochecksum 2472 2473 matches = self.matched_atom 2474 self.infoDict['matches'] = matches 2475 self.infoDict['atoms'] = [] 2476 self.infoDict['repository_atoms'] = {} 2477 temp_fetch_list = [] 2478 temp_checksum_list = [] 2479 temp_already_downloaded_count = 0 2480 etp_workdir = etpConst['entropyworkdir'] 2481 for idpackage, repository in matches: 2482 if repository.endswith(etpConst['packagesext']): continue 2483 2484 dbconn = self.Entropy.open_repository(repository) 2485 myatom = dbconn.retrieveAtom(idpackage) 2486 2487 # general purpose metadata 2488 self.infoDict['atoms'].append(myatom) 2489 if not self.infoDict['repository_atoms'].has_key(repository): 2490 self.infoDict['repository_atoms'][repository] = set() 2491 self.infoDict['repository_atoms'][repository].add(myatom) 2492 2493 download = dbconn.retrieveDownloadURL(idpackage) 2494 digest = dbconn.retrieveDigest(idpackage) 2495 signatures = dbconn.retrieveSignatures(idpackage) 2496 repo_size = dbconn.retrieveSize(idpackage) 2497 orig_branch = self.Entropy.get_branch_from_download_relative_uri(download) 2498 if self.Entropy.check_needed_package_download(download, None) < 0: 2499 temp_fetch_list.append((repository, orig_branch, download, digest, signatures,)) 2500 continue 2501 elif dochecksum: 2502 temp_checksum_list.append((repository, orig_branch, download, digest, signatures,)) 2503 down_path = os.path.join(etp_workdir,download) 2504 if os.path.isfile(down_path): 2505 with open(down_path,"r") as f: 2506 f.seek(0,2) 2507 disk_size = f.tell() 2508 if repo_size == disk_size: 2509 temp_already_downloaded_count += 1 2510 2511 self.infoDict['steps'] = [] 2512 self.infoDict['multi_fetch_list'] = temp_fetch_list 2513 self.infoDict['multi_checksum_list'] = temp_checksum_list 2514 if self.infoDict['multi_fetch_list']: 2515 self.infoDict['steps'].append("multi_fetch") 2516 if self.infoDict['multi_checksum_list']: 2517 self.infoDict['steps'].append("multi_checksum") 2518 if temp_already_downloaded_count == len(temp_checksum_list): 2519 self.infoDict['steps'].reverse() 2520 2521 return 0
2522