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

Source Code for Module entropy.client.interfaces.package

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