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