Package entropy :: Package core :: Package settings :: Module base

Source Code for Module entropy.core.settings.base

   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 Framework SystemSettings module}. 
  10   
  11      SystemSettings is a singleton, pluggable interface which contains 
  12      all the runtime settings (mostly parsed from configuration files 
  13      and inherited from entropy.const -- which contains almost all the 
  14      default values). 
  15      SystemSettings works as a I{dict} object. Due to limitations of 
  16      multiple inherittance when using the Singleton class, SystemSettings 
  17      ONLY mimics a I{dict} AND it's not a subclass of it. 
  18   
  19  """ 
  20  from __future__ import with_statement 
  21  import os 
  22  import sys 
  23  from threading import RLock 
  24   
  25  from entropy.const import etpConst, etpUi, etpSys, const_setup_perms, \ 
  26      const_secure_config_file, const_set_nice_level, \ 
  27      const_extract_cli_repo_params, etpCache 
  28  from entropy.core import Singleton 
  29  from entropy.core.settings.plugins.skel import SystemSettingsPlugin 
  30   
31 -class SystemSettings(Singleton):
32 33 """ 34 This is the place where all the Entropy settings are stored if 35 they are not considered instance constants (etpConst). 36 For example, here we store package masking cache information and 37 settings, client-side, server-side and services settings. 38 Also, this class mimics a dictionary (even if not inheriting it 39 due to development choices). 40 41 Sample code: 42 43 >>> from entropy.core.settings.base import SystemSettings 44 >>> system_settings = SystemSettings() 45 >>> system_settings.clear() 46 >>> system_settings.destroy() 47 48 """ 49 50 import entropy.tools as entropyTools
51 - def init_singleton(self):
52 53 """ 54 Replaces __init__ because SystemSettings is a Singleton. 55 see Singleton API reference for more information. 56 57 """ 58 59 from entropy.core.settings.plugins.factory import get_available_plugins 60 self.__get_external_plugins = get_available_plugins 61 62 from entropy.cache import EntropyCacher 63 self.__cacher = EntropyCacher() 64 self.__data = {} 65 self.__is_destroyed = False 66 self.__mutex = RLock() # reentrant lock on purpose 67 68 self.__plugins = {} 69 self.__external_plugins = {} 70 self.__setting_files_order = [] 71 self.__setting_files_pre_run = [] 72 self.__setting_files = {} 73 self.__mtime_files = {} 74 self.__persistent_settings = { 75 'pkg_masking_reasons': etpConst['pkg_masking_reasons'].copy(), 76 'pkg_masking_reference': etpConst['pkg_masking_reference'].copy(), 77 'backed_up': {}, 78 # package masking, live 79 'live_packagemasking': { 80 'unmask_matches': set(), 81 'mask_matches': set(), 82 }, 83 } 84 85 self.__setup_const() 86 self.__scan()
87
88 - def destroy(self):
89 """ 90 Overloaded method from Singleton. 91 "Destroys" the instance. 92 93 @return: None 94 @rtype: None 95 """ 96 with self.__mutex: 97 self.__is_destroyed = True
98
99 - def add_plugin(self, system_settings_plugin_instance):
100 """ 101 This method lets you add custom parsers to SystemSettings. 102 Mind that you are responsible of handling your plugin instance 103 and remove it before it is destroyed. You can remove the plugin 104 instance at any time by issuing remove_plugin. 105 Every add_plugin or remove_plugin method will also issue clear() 106 for you. This could be bad and it might be removed in future. 107 108 @param plugin_id: plugin identifier 109 @type plugin_id: string 110 @param system_settings_plugin_instance: valid SystemSettingsPlugin 111 instance 112 @type system_settings_plugin_instance: SystemSettingsPlugin instance 113 @return: None 114 @rtype: None 115 """ 116 inst = system_settings_plugin_instance 117 if not isinstance(inst, SystemSettingsPlugin): 118 raise AttributeError("SystemSettings: expected valid " + \ 119 "SystemSettingsPlugin instance") 120 with self.__mutex: 121 self.__plugins[inst.get_id()] = inst 122 self.clear()
123
124 - def remove_plugin(self, plugin_id):
125 """ 126 This method lets you remove previously added custom parsers from 127 SystemSettings through its plugin identifier. If plugin_id is not 128 available, KeyError exception will be raised. 129 Every add_plugin or remove_plugin method will also issue clear() 130 for you. This could be bad and it might be removed in future. 131 132 @param plugin_id: plugin identifier 133 @type plugin_id: basestring 134 @return: None 135 @rtype: None 136 """ 137 with self.__mutex: 138 del self.__plugins[plugin_id] 139 self.clear()
140
141 - def __setup_const(self):
142 143 """ 144 Internal method. Does constants initialization. 145 146 @return: None 147 @rtype: None 148 """ 149 150 del self.__setting_files_order[:] 151 del self.__setting_files_pre_run[:] 152 self.__setting_files.clear() 153 self.__mtime_files.clear() 154 155 self.__setting_files.update({ 156 # keywording configuration files 157 'keywords': etpConst['confpackagesdir']+"/package.keywords", 158 # unmasking configuration files 159 'unmask': etpConst['confpackagesdir']+"/package.unmask", 160 # masking configuration files 161 'mask': etpConst['confpackagesdir']+"/package.mask", 162 # satisfied packages configuration file 163 'satisfied': etpConst['confpackagesdir']+"/package.satisfied", 164 # masking configuration files 165 'license_mask': etpConst['confpackagesdir']+"/license.mask", 166 'system_mask': etpConst['confpackagesdir']+"/system.mask", 167 'system_dirs': etpConst['confdir']+"/fsdirs.conf", 168 'system_dirs_mask': etpConst['confdir']+"/fsdirsmask.conf", 169 'system_rev_symlinks': etpConst['confdir']+"/fssymlinks.conf", 170 'broken_syms': etpConst['confdir']+"/brokensyms.conf", 171 'broken_libs_mask': etpConst['confdir']+"/brokenlibsmask.conf", 172 'hw_hash': etpConst['confdir']+"/.hw.hash", 173 'socket_service': etpConst['socketconf'], 174 'system': etpConst['entropyconf'], 175 'repositories': etpConst['repositoriesconf'], 176 'system_package_sets': {}, 177 }) 178 self.__setting_files_order.extend([ 179 'keywords', 'unmask', 'mask', 'satisfied', 'license_mask', 180 'system_mask', 'system_package_sets', 'system_dirs', 181 'system_dirs_mask', 'socket_service', 'system', 182 'system_rev_symlinks', 'hw_hash', 'broken_syms', 'broken_libs_mask' 183 ]) 184 self.__setting_files_pre_run.extend(['repositories']) 185 186 dmp_dir = etpConst['dumpstoragedir'] 187 self.__mtime_files.update({ 188 'keywords_mtime': dmp_dir+"/keywords.mtime", 189 'unmask_mtime': dmp_dir+"/unmask.mtime", 190 'mask_mtime': dmp_dir+"/mask.mtime", 191 'satisfied_mtime': dmp_dir+"/satisfied.mtime", 192 'license_mask_mtime': dmp_dir+"/license_mask.mtime", 193 'system_mask_mtime': dmp_dir+"/system_mask.mtime", 194 })
195 196
197 - def __scan(self):
198 199 """ 200 Internal method. Scan settings and fill variables. 201 202 @return: None 203 @rtype: None 204 """ 205 206 def enforce_persistent(): 207 # merge persistent settings back 208 self.__data.update(self.__persistent_settings) 209 # restore backed-up settings 210 self.__data.update(self.__persistent_settings['backed_up'].copy())
211 212 self.__parse() 213 enforce_persistent() 214 215 # plugins support 216 for plugin_id in sorted(self.__plugins): 217 self.__plugins[plugin_id].parse(self) 218 219 # external plugins support 220 external_plugins = self.__get_external_plugins() 221 for external_plugin_id in sorted(external_plugins): 222 external_plugin = external_plugins[external_plugin_id]() 223 external_plugin.parse(self) 224 self.__external_plugins[external_plugin_id] = external_plugin 225 226 enforce_persistent() 227 228 # run post-SystemSettings setup, plugins hook 229 for plugin_id in sorted(self.__plugins): 230 self.__plugins[plugin_id].post_setup(self) 231 232 # run post-SystemSettings setup for external plugins too 233 for external_plugin_id in sorted(self.__external_plugins): 234 self.__external_plugins[external_plugin_id].post_setup(self)
235
236 - def __setitem__(self, mykey, myvalue):
237 """ 238 dict method. See Python dict API reference. 239 """ 240 with self.__mutex: 241 # backup here too 242 if self.__persistent_settings.has_key(mykey): 243 self.__persistent_settings[mykey] = myvalue 244 self.__data[mykey] = myvalue
245
246 - def __getitem__(self, mykey):
247 """ 248 dict method. See Python dict API reference. 249 """ 250 with self.__mutex: 251 return self.__data[mykey]
252
253 - def __delitem__(self, mykey):
254 """ 255 dict method. See Python dict API reference. 256 """ 257 with self.__mutex: 258 del self.__data[mykey]
259
260 - def __iter__(self):
261 """ 262 dict method. See Python dict API reference. 263 """ 264 with self.__mutex: 265 return iter(self.__data)
266
267 - def __contains__(self, item):
268 """ 269 dict method. See Python dict API reference. 270 """ 271 with self.__mutex: 272 return item in self.__data
273
274 - def __cmp__(self, other):
275 """ 276 dict method. See Python dict API reference. 277 """ 278 with self.__mutex: 279 return cmp(self.__data, other)
280
281 - def __hash__(self):
282 """ 283 dict method. See Python dict API reference. 284 """ 285 with self.__mutex: 286 return hash(self.__data)
287
288 - def __len__(self):
289 """ 290 dict method. See Python dict API reference. 291 """ 292 with self.__mutex: 293 return len(self.__data)
294
295 - def get(self, mykey, alt_obj = None):
296 """ 297 dict method. See Python dict API reference. 298 """ 299 with self.__mutex: 300 return self.__data.get(mykey, alt_obj)
301
302 - def has_key(self, mykey):
303 """ 304 dict method. See Python dict API reference. 305 """ 306 with self.__mutex: 307 return self.__data.has_key(mykey)
308
309 - def copy(self):
310 """ 311 dict method. See Python dict API reference. 312 """ 313 with self.__mutex: 314 return self.__data.copy()
315
316 - def fromkeys(self, seq, val = None):
317 """ 318 dict method. See Python dict API reference. 319 """ 320 with self.__mutex: 321 return self.__data.fromkeys(seq, val)
322
323 - def items(self):
324 """ 325 dict method. See Python dict API reference. 326 """ 327 with self.__mutex: 328 return self.__data.items()
329
330 - def iteritems(self):
331 """ 332 dict method. See Python dict API reference. 333 """ 334 with self.__mutex: 335 return self.__data.iteritems()
336
337 - def iterkeys(self):
338 """ 339 dict method. See Python dict API reference. 340 """ 341 with self.__mutex: 342 return self.__data.iterkeys()
343
344 - def keys(self):
345 """ 346 dict method. See Python dict API reference. 347 """ 348 with self.__mutex: 349 return self.__data.keys()
350
351 - def pop(self, mykey, default = None):
352 """ 353 dict method. See Python dict API reference. 354 """ 355 with self.__mutex: 356 return self.__data.pop(mykey, default)
357
358 - def popitem(self):
359 """ 360 dict method. See Python dict API reference. 361 """ 362 with self.__mutex: 363 return self.__data.popitem()
364
365 - def setdefault(self, mykey, default = None):
366 """ 367 dict method. See Python dict API reference. 368 """ 369 with self.__mutex: 370 return self.__data.setdefault(mykey, default)
371
372 - def update(self, kwargs):
373 """ 374 dict method. See Python dict API reference. 375 """ 376 with self.__mutex: 377 return self.__data.update(kwargs)
378
379 - def values(self):
380 """ 381 dict method. See Python dict API reference. 382 """ 383 with self.__mutex: 384 return self.__data.values()
385
386 - def clear(self):
387 """ 388 dict method. See Python dict API reference. 389 Settings are also re-initialized here. 390 391 @return None 392 """ 393 with self.__mutex: 394 self.__data.clear() 395 self.__setup_const() 396 self.__scan()
397
398 - def set_persistent_setting(self, persistent_dict):
399 """ 400 Make metadata persistent, the input dict will be merged 401 with the base one at every reset call (clear()). 402 403 @param persistent_dict: dictionary to merge 404 @type persistent_dict: dict 405 406 @return: None 407 @rtype: None 408 """ 409 with self.__mutex: 410 self.__persistent_settings.update(persistent_dict)
411
412 - def unset_persistent_setting(self, persistent_key):
413 """ 414 Remove dict key from persistent dictionary 415 416 @param persistent_key: key to remove 417 @type persistent_dict: dict 418 419 @return: None 420 @rtype: None 421 """ 422 with self.__mutex: 423 del self.__persistent_settings[persistent_key] 424 del self.__data[persistent_key]
425
426 - def __setup_package_sets_vars(self):
427 428 """ 429 This function setups the *files* dictionary about package sets 430 that will be read and parsed afterwards by the respective 431 internal parser. 432 433 @return: None 434 @rtype: None 435 """ 436 437 # user defined package sets 438 sets_dir = etpConst['confsetsdir'] 439 pkg_set_data = {} 440 if (os.path.isdir(sets_dir) and os.access(sets_dir, os.R_OK)): 441 set_files = [x for x in os.listdir(sets_dir) if \ 442 (os.path.isfile(os.path.join(sets_dir, x)) and \ 443 os.access(os.path.join(sets_dir, x),os.R_OK))] 444 for set_file in set_files: 445 try: 446 set_file = set_file.decode(sys.getfilesystemencoding()) 447 except (UnicodeDecodeError, UnicodeEncodeError,): 448 continue 449 pkg_set_data[set_file] = os.path.join(sets_dir, set_file) 450 self.__setting_files['system_package_sets'].update(pkg_set_data)
451
452 - def __parse(self):
453 """ 454 This is the main internal parsing method. 455 *files* and *mtimes* dictionaries are prepared and 456 parsed just a few lines later. 457 458 @return: None 459 @rtype: None 460 """ 461 # some parsers must be run BEFORE everything: 462 for item in self.__setting_files_pre_run: 463 myattr = '_%s_parser' % (item,) 464 if not hasattr(self, myattr): 465 continue 466 func = getattr(self, myattr) 467 self.__data[item] = func() 468 469 # parse main settings 470 self.__setup_package_sets_vars() 471 472 for item in self.__setting_files_order: 473 myattr = '_%s_parser' % (item,) 474 if not hasattr(self, myattr): 475 continue 476 func = getattr(self, myattr) 477 self.__data[item] = func()
478
479 - def get_setting_files_data(self):
480 """ 481 Return a copy of the internal *files* dictionary. 482 This dict contains config file paths and their identifiers. 483 484 @return: dict __setting_files 485 @rtype: dict 486 """ 487 with self.__mutex: 488 return self.__setting_files.copy()
489
490 - def _keywords_parser(self):
491 """ 492 Parser returning package keyword masking metadata 493 read from package.keywords file. 494 This file contains package mask or unmask directives 495 based on package keywords. 496 497 @return: parsed metadata 498 @rtype: dict 499 """ 500 # merge universal keywords 501 data = { 502 'universal': set(), 503 'packages': {}, 504 'repositories': {}, 505 } 506 507 self.validate_entropy_cache(self.__setting_files['keywords'], 508 self.__mtime_files['keywords_mtime']) 509 content = [x.split() for x in \ 510 self.__generic_parser(self.__setting_files['keywords']) \ 511 if len(x.split()) < 4] 512 for keywordinfo in content: 513 # skip wrong lines 514 if len(keywordinfo) > 3: 515 continue 516 # inversal keywording, check if it's not repo= 517 if len(keywordinfo) == 1: 518 if keywordinfo[0].startswith("repo="): 519 continue 520 # convert into entropy format 521 if keywordinfo[0] == "**": 522 keywordinfo[0] = "" 523 data['universal'].add(keywordinfo[0]) 524 continue 525 # inversal keywording, check if it's not repo= 526 if len(keywordinfo) in (2, 3,): 527 # repo=? 528 if keywordinfo[0].startswith("repo="): 529 continue 530 # add to repo? 531 items = keywordinfo[1:] 532 # convert into entropy format 533 if keywordinfo[0] == "**": 534 keywordinfo[0] = "" 535 reponame = [x for x in items if x.startswith("repo=") \ 536 and (len(x.split("=")) == 2)] 537 if reponame: 538 reponame = reponame[0].split("=")[1] 539 if reponame not in data['repositories']: 540 data['repositories'][reponame] = {} 541 # repository unmask or package in repository unmask? 542 if keywordinfo[0] not in data['repositories'][reponame]: 543 data['repositories'][reponame][keywordinfo[0]] = set() 544 if len(items) == 1: 545 # repository unmask 546 data['repositories'][reponame][keywordinfo[0]].add('*') 547 elif "*" not in \ 548 data['repositories'][reponame][keywordinfo[0]]: 549 550 item = [x for x in items if not x.startswith("repo=")] 551 data['repositories'][reponame][keywordinfo[0]].add( 552 item[0]) 553 elif len(items) == 2: 554 # it's going to be a faulty line!!?? 555 # can't have two items and no repo= 556 continue 557 else: 558 # add keyword to packages 559 if keywordinfo[0] not in data['packages']: 560 data['packages'][keywordinfo[0]] = set() 561 data['packages'][keywordinfo[0]].add(items[0]) 562 563 # merge universal keywords 564 etpConst['keywords'].clear() 565 etpConst['keywords'].update(etpSys['keywords']) 566 for keyword in data['universal']: 567 etpConst['keywords'].add(keyword) 568 569 return data
570 571
572 - def _unmask_parser(self):
573 """ 574 Parser returning package unmasking metadata read from 575 package.unmask file. 576 This file contains package unmask directives, allowing 577 to enable experimental or *secret* packages. 578 579 @return: parsed metadata 580 @rtype: dict 581 """ 582 self.validate_entropy_cache(self.__setting_files['unmask'], 583 self.__mtime_files['unmask_mtime']) 584 return self.__generic_parser(self.__setting_files['unmask'])
585
586 - def _mask_parser(self):
587 """ 588 Parser returning package masking metadata read from 589 package.mask file. 590 This file contains package mask directives, allowing 591 to disable experimental or *secret* packages. 592 593 @return: parsed metadata 594 @rtype: dict 595 """ 596 self.validate_entropy_cache(self.__setting_files['mask'], 597 self.__mtime_files['mask_mtime']) 598 return self.__generic_parser(self.__setting_files['mask'])
599
600 - def _satisfied_parser(self):
601 """ 602 Parser returning package forced satisfaction metadata 603 read from package.satisfied file. 604 This file contains packages which updates as dependency are 605 filtered out. 606 607 @return: parsed metadata 608 @rtype: dict 609 """ 610 self.validate_entropy_cache(self.__setting_files['satisfied'], 611 self.__mtime_files['satisfied_mtime']) 612 return self.__generic_parser(self.__setting_files['satisfied'])
613
614 - def _system_mask_parser(self):
615 """ 616 Parser returning system packages mask metadata read from 617 package.system_mask file. 618 This file contains packages that should be always kept 619 installed, extending the already defined (in repository database) 620 set of atoms. 621 622 @return: parsed metadata 623 @rtype: dict 624 """ 625 self.validate_entropy_cache(self.__setting_files['system_mask'], 626 self.__mtime_files['system_mask_mtime']) 627 return self.__generic_parser(self.__setting_files['system_mask'])
628
629 - def _license_mask_parser(self):
630 """ 631 Parser returning packages masked by license metadata read from 632 license.mask file. 633 Packages shipped with licenses listed there will be masked. 634 635 @return: parsed metadata 636 @rtype: dict 637 """ 638 self.validate_entropy_cache(self.__setting_files['license_mask'], 639 self.__mtime_files['license_mask_mtime']) 640 return self.__generic_parser(self.__setting_files['license_mask'])
641
642 - def _system_package_sets_parser(self):
643 """ 644 Parser returning system defined package sets read from 645 /etc/entropy/packages/sets. 646 647 @return: parsed metadata 648 @rtype: dict 649 """ 650 data = {} 651 for set_name in self.__setting_files['system_package_sets']: 652 set_filepath = self.__setting_files['system_package_sets'][set_name] 653 set_elements = self.entropyTools.extract_packages_from_set_file( 654 set_filepath) 655 if set_elements: 656 data[set_name] = set_elements.copy() 657 return data
658
659 - def _system_dirs_parser(self):
660 """ 661 Parser returning directories considered part of the base system. 662 663 @return: parsed metadata 664 @rtype: dict 665 """ 666 return self.__generic_parser(self.__setting_files['system_dirs'])
667
668 - def _system_dirs_mask_parser(self):
669 """ 670 Parser returning directories NOT considered part of the base system. 671 Settings here overlay system_dirs_parser. 672 673 @return: parsed metadata 674 @rtype: dict 675 """ 676 return self.__generic_parser(self.__setting_files['system_dirs_mask'])
677
678 - def _broken_syms_parser(self):
679 """ 680 Parser returning a list of shared objects symbols that can be used by 681 QA tools to scan the filesystem or a subset of it. 682 683 @return: parsed metadata 684 @rtype: dict 685 """ 686 return self.__generic_parser(self.__setting_files['broken_syms'])
687
688 - def _broken_libs_mask_parser(self):
689 """ 690 Parser returning a list of broken shared libraries which are 691 always considered sane. 692 693 @return: parsed metadata 694 @rtype: dict 695 """ 696 return self.__generic_parser(self.__setting_files['broken_libs_mask'])
697
698 - def _hw_hash_parser(self):
699 """ 700 Hardware hash metadata parser and generator. It returns a theorically 701 unique SHA256 hash bound to the computer running this Framework. 702 703 @return: string containing SHA256 hexdigest 704 @rtype: string 705 """ 706 hw_hash_file = self.__setting_files['hw_hash'] 707 if os.access(hw_hash_file, os.R_OK | os.F_OK): 708 hash_f = open(hw_hash_file, "r") 709 hash_data = hash_f.readline().strip() 710 hash_f.close() 711 return hash_data 712 713 hash_file_dir = os.path.dirname(hw_hash_file) 714 hw_hash_exec = etpConst['etp_hw_hash_gen'] 715 if os.access(hash_file_dir, os.W_OK) and \ 716 os.access(hw_hash_exec, os.X_OK | os.F_OK | os.R_OK): 717 pipe = os.popen('{ ' + hw_hash_exec + '; } 2>&1', 'r') 718 hash_data = pipe.read().strip() 719 sts = pipe.close() 720 if sts != None: 721 return None 722 hash_f = open(hw_hash_file, "w") 723 hash_f.write(hash_data) 724 hash_f.flush() 725 hash_f.close() 726 return hash_data
727 746
747 - def _socket_service_parser(self):
748 """ 749 Parses socket service configuration file. 750 This file contains information about Entropy remote service ports 751 and SSL. 752 753 @return: parsed metadata 754 @rtype: dict 755 """ 756 757 data = etpConst['socket_service'].copy() 758 759 sock_conf = self.__setting_files['socket_service'] 760 if not (os.path.isfile(sock_conf) and \ 761 os.access(sock_conf,os.R_OK)): 762 return data 763 764 socket_f = open(sock_conf,"r") 765 socketconf = [x.strip() for x in socket_f.readlines() if \ 766 x.strip() and not x.strip().startswith("#")] 767 socket_f.close() 768 769 for line in socketconf: 770 771 split_line = line.split("|") 772 split_line_len = len(split_line) 773 774 if line.startswith("listen|") and (split_line_len > 1): 775 776 item = split_line[1].strip() 777 if item: 778 data['hostname'] = item 779 780 elif line.startswith("listen-port|") and \ 781 (split_line_len > 1): 782 783 item = split_line[1].strip() 784 try: 785 item = int(item) 786 data['port'] = item 787 except ValueError: 788 continue 789 790 elif line.startswith("listen-timeout|") and \ 791 (split_line_len > 1): 792 793 item = split_line[1].strip() 794 try: 795 item = int(item) 796 data['timeout'] = item 797 except ValueError: 798 continue 799 800 elif line.startswith("listen-threads|") and \ 801 (split_line_len > 1): 802 803 item = split_line[1].strip() 804 try: 805 item = int(item) 806 data['threads'] = item 807 except ValueError: 808 continue 809 810 elif line.startswith("session-ttl|") and \ 811 (split_line_len > 1): 812 813 item = split_line[1].strip() 814 try: 815 item = int(item) 816 data['session_ttl'] = item 817 except ValueError: 818 continue 819 820 elif line.startswith("max-connections|") and \ 821 (split_line_len > 1): 822 823 item = split_line[1].strip() 824 try: 825 item = int(item) 826 data['max_connections'] = item 827 except ValueError: 828 continue 829 830 elif line.startswith("ssl-port|") and \ 831 (split_line_len > 1): 832 833 item = split_line[1].strip() 834 try: 835 item = int(item) 836 data['ssl_port'] = item 837 except ValueError: 838 continue 839 840 elif line.startswith("disabled-commands|") and \ 841 (split_line_len > 1): 842 843 disabled_cmds = split_line[1].strip().split() 844 for disabled_cmd in disabled_cmds: 845 data['disabled_cmds'].add(disabled_cmd) 846 847 elif line.startswith("ip-blacklist|") and \ 848 (split_line_len > 1): 849 850 ips_blacklist = split_line[1].strip().split() 851 for ip_blacklist in ips_blacklist: 852 data['ip_blacklist'].add(ip_blacklist) 853 854 return data
855
856 - def _system_parser(self):
857 858 """ 859 Parses Entropy system configuration file. 860 861 @return: parsed metadata 862 @rtype: dict 863 """ 864 865 data = { 866 'proxy': etpConst['proxy'].copy(), 867 'name': etpConst['systemname'], 868 'log_level': etpConst['entropyloglevel'], 869 'spm_backend': etpConst['spm']['backend'], 870 } 871 872 etp_conf = self.__setting_files['system'] 873 if not os.path.isfile(etp_conf) and \ 874 os.access(etp_conf,os.R_OK): 875 return data 876 877 const_secure_config_file(etp_conf) 878 entropy_f = open(etp_conf,"r") 879 entropyconf = [x.strip() for x in entropy_f.readlines() if \ 880 x.strip() and not x.strip().startswith("#")] 881 entropy_f.close() 882 883 for line in entropyconf: 884 885 split_line = line.split("|") 886 split_line_len = len(split_line) 887 888 if line.startswith("loglevel|") and \ 889 (len(line.split("loglevel|")) == 2): 890 891 loglevel = line.split("loglevel|")[1] 892 try: 893 loglevel = int(loglevel) 894 except ValueError: 895 pass 896 if (loglevel > -1) and (loglevel < 3): 897 data['log_level'] = loglevel 898 899 elif line.startswith("ftp-proxy|") and \ 900 (split_line_len == 2): 901 902 ftpproxy = split_line[1].strip().split() 903 if ftpproxy: 904 data['proxy']['ftp'] = ftpproxy[-1] 905 906 elif line.startswith("http-proxy|") and \ 907 (split_line_len == 2): 908 909 httpproxy = split_line[1].strip().split() 910 if httpproxy: 911 data['proxy']['http'] = httpproxy[-1] 912 913 elif line.startswith("proxy-username|") and \ 914 (split_line_len == 2): 915 916 httpproxy = split_line[1].strip().split() 917 if httpproxy: 918 data['proxy']['username'] = httpproxy[-1] 919 920 elif line.startswith("proxy-password|") and \ 921 (split_line_len == 2): 922 923 httpproxy = split_line[1].strip().split() 924 if httpproxy: 925 data['proxy']['password'] = httpproxy[-1] 926 927 elif line.startswith("system-name|") and \ 928 (split_line_len == 2): 929 930 data['name'] = split_line[1].strip() 931 932 elif line.startswith("spm-backend|") and \ 933 (split_line_len == 2): 934 935 data['spm_backend'] = split_line[1].strip() 936 937 elif line.startswith("nice-level|") and \ 938 (split_line_len == 2): 939 940 mylevel = split_line[1].strip() 941 try: 942 mylevel = int(mylevel) 943 if (mylevel >= -19) and (mylevel <= 19): 944 const_set_nice_level(mylevel) 945 except (ValueError,): 946 continue 947 948 return data
949
950 - def _repositories_parser(self):
951 952 """ 953 Setup Entropy Client repository settings reading them from 954 the relative config file specified in etpConst['repositoriesconf'] 955 956 @return: parsed metadata 957 @rtype: dict 958 """ 959 960 data = { 961 'available': {}, 962 'excluded': {}, 963 'order': [], 964 'product': etpConst['product'], 965 'branch': etpConst['branch'], 966 'default_repository': etpConst['officialrepositoryid'], 967 'transfer_limit': etpConst['downloadspeedlimit'], 968 'security_advisories_url': etpConst['securityurl'], 969 } 970 971 repo_conf = etpConst['repositoriesconf'] 972 if not (os.path.isfile(repo_conf) and os.access(repo_conf, os.R_OK)): 973 return data 974 975 repo_f = open(repo_conf,"r") 976 repositoriesconf = [x.strip() for x in repo_f.readlines() if x.strip()] 977 repo_f.close() 978 979 # setup product and branch first 980 for line in repositoriesconf: 981 982 split_line = line.split("|") 983 split_line_len = len(split_line) 984 985 if (line.find("product|") != -1) and \ 986 (not line.startswith("#")) and (split_line_len == 2): 987 988 data['product'] = split_line[1] 989 990 elif (line.find("branch|") != -1) and \ 991 (not line.startswith("#")) and (split_line_len == 2): 992 993 branch = split_line[1].strip() 994 data['branch'] = branch 995 if not os.path.isdir(etpConst['packagesbindir']+"/"+branch) \ 996 and (etpConst['uid'] == 0): 997 998 try: 999 os.makedirs(etpConst['packagesbindir']+"/"+branch) 1000 except (OSError, IOError,): 1001 continue 1002 1003 for line in repositoriesconf: 1004 1005 split_line = line.split("|") 1006 split_line_len = len(split_line) 1007 1008 # populate data['available'] 1009 if (line.find("repository|") != -1) and (split_line_len == 5): 1010 1011 excluded = False 1012 my_repodata = data['available'] 1013 if line.startswith("##"): 1014 continue 1015 elif line.startswith("#"): 1016 excluded = True 1017 my_repodata = data['excluded'] 1018 line = line[1:] 1019 1020 reponame, repodata = const_extract_cli_repo_params(line, 1021 data['branch'], data['product']) 1022 if my_repodata.has_key(reponame): 1023 1024 my_repodata[reponame]['plain_packages'].extend( 1025 repodata['plain_packages']) 1026 my_repodata[reponame]['packages'].extend( 1027 repodata['packages']) 1028 1029 if (not my_repodata[reponame]['plain_database']) and \ 1030 repodata['plain_database']: 1031 1032 my_repodata[reponame]['plain_database'] = \ 1033 repodata['plain_database'] 1034 my_repodata[reponame]['database'] = \ 1035 repodata['database'] 1036 my_repodata[reponame]['dbrevision'] = \ 1037 repodata['dbrevision'] 1038 my_repodata[reponame]['dbcformat'] = \ 1039 repodata['dbcformat'] 1040 else: 1041 1042 my_repodata[reponame] = repodata.copy() 1043 if not excluded: 1044 data['order'].append(reponame) 1045 1046 elif (line.find("officialrepositoryid|") != -1) and \ 1047 (not line.startswith("#")) and (split_line_len == 2): 1048 1049 officialreponame = split_line[1] 1050 data['default_repository'] = officialreponame 1051 1052 elif (line.find("downloadspeedlimit|") != -1) and \ 1053 (not line.startswith("#")) and (split_line_len == 2): 1054 1055 try: 1056 myval = int(split_line[1]) 1057 if myval > 0: 1058 data['transfer_limit'] = myval 1059 else: 1060 data['transfer_limit'] = None 1061 except (ValueError, IndexError,): 1062 data['transfer_limit'] = None 1063 1064 elif (line.find("securityurl|") != -1) and \ 1065 (not line.startswith("#")) and (split_line_len == 2): 1066 1067 try: 1068 data['security_advisories_url'] = split_line[1] 1069 except (IndexError, ValueError, TypeError,): 1070 continue 1071 1072 return data
1073
1074 - def _clear_repository_cache(self, repoid = None):
1075 """ 1076 Internal method, go away! 1077 """ 1078 self.__cacher.discard() 1079 self._clear_dump_cache(etpCache['world_available']) 1080 self._clear_dump_cache(etpCache['world_update']) 1081 self._clear_dump_cache(etpCache['critical_update']) 1082 self._clear_dump_cache(etpCache['check_package_update']) 1083 self._clear_dump_cache(etpCache['filter_satisfied_deps']) 1084 self._clear_dump_cache(etpCache['atomMatch']) 1085 self._clear_dump_cache(etpCache['dep_tree']) 1086 if repoid != None: 1087 self._clear_dump_cache("%s/%s%s/" % ( 1088 etpCache['dbMatch'],etpConst['dbnamerepoprefix'],repoid,)) 1089 self._clear_dump_cache("%s/%s%s/" % ( 1090 etpCache['dbSearch'],etpConst['dbnamerepoprefix'],repoid,))
1091
1092 - def _clear_dump_cache(self, dump_name, skip = []):
1093 """ 1094 Internal method, go away! 1095 """ 1096 dump_path = os.path.join(etpConst['dumpstoragedir'],dump_name) 1097 dump_dir = os.path.dirname(dump_path) 1098 #dump_file = os.path.basename(dump_path) 1099 for currentdir, subdirs, files in os.walk(dump_dir): 1100 path = os.path.join(dump_dir,currentdir) 1101 if skip: 1102 found = False 1103 for myskip in skip: 1104 if path.find(myskip) != -1: 1105 found = True 1106 break 1107 if found: continue 1108 for item in files: 1109 if item.endswith(etpConst['cachedumpext']): 1110 item = os.path.join(path,item) 1111 try: 1112 os.remove(item) 1113 except (OSError, IOError,): 1114 pass 1115 try: 1116 if not os.listdir(path): 1117 os.rmdir(path) 1118 except (OSError, IOError,): 1119 pass
1120
1121 - def __generic_parser(self, filepath):
1122 """ 1123 Internal method. This is the generic file parser here. 1124 1125 @param filepath: valid path 1126 @type filepath: string 1127 @return: raw text extracted from file 1128 @rtype: list 1129 """ 1130 return self.entropyTools.generic_file_content_parser(filepath)
1131
1132 - def __remove_repo_cache(self, repoid = None):
1133 """ 1134 Internal method. Remove repository cache, because not valid anymore. 1135 1136 @keyword repoid: repository identifier or None 1137 @type repoid: string or None 1138 @return: None 1139 @rtype: None 1140 """ 1141 if os.path.isdir(etpConst['dumpstoragedir']): 1142 if repoid: 1143 self._clear_repository_cache(repoid = repoid) 1144 return 1145 for repoid in self['repositories']['order']: 1146 self._clear_repository_cache(repoid = repoid) 1147 else: 1148 try: 1149 os.makedirs(etpConst['dumpstoragedir']) 1150 except IOError, e: 1151 if e.errno == 30: # readonly filesystem 1152 etpUi['pretend'] = True 1153 return 1154 except OSError: 1155 return
1156
1157 - def __save_file_mtime(self, toread, tosaveinto):
1158 """ 1159 Internal method. Save mtime of a file to another file. 1160 1161 @param toread: file path to read 1162 @type toread: string 1163 @param tosaveinto: path where to save retrieved mtime information 1164 @type tosaveinto: string 1165 @return: None 1166 @rtype: None 1167 """ 1168 if not os.path.isfile(toread): 1169 currmtime = 0.0 1170 else: 1171 currmtime = os.path.getmtime(toread) 1172 1173 if not os.path.isdir(etpConst['dumpstoragedir']): 1174 try: 1175 os.makedirs(etpConst['dumpstoragedir'], 0775) 1176 const_setup_perms(etpConst['dumpstoragedir'], 1177 etpConst['entropygid']) 1178 except IOError, e: 1179 if e.errno == 30: # readonly filesystem 1180 etpUi['pretend'] = True 1181 return 1182 except (OSError,), e: 1183 # unable to create the storage directory 1184 # useless to continue 1185 return 1186 1187 try: 1188 mtime_f = open(tosaveinto,"w") 1189 except IOError, e: # unable to write? 1190 if e.errno == 30: # readonly filesystem 1191 etpUi['pretend'] = True 1192 return 1193 else: 1194 mtime_f.write(str(currmtime)) 1195 mtime_f.flush() 1196 mtime_f.close() 1197 os.chmod(tosaveinto, 0664) 1198 if etpConst['entropygid'] != None: 1199 os.chown(tosaveinto, 0, etpConst['entropygid'])
1200 1201
1202 - def validate_entropy_cache(self, settingfile, mtimefile, repoid = None):
1203 """ 1204 Internal method. Validates Entropy Cache based on a setting file 1205 and its stored (cache bound) mtime. 1206 1207 @param settingfile: path of the setting file 1208 @type settingfile: string 1209 @param mtimefile: path where to save retrieved mtime information 1210 @type mtimefile: string 1211 @keyword repoid: repository identifier or None 1212 @type repoid: string or None 1213 @return: None 1214 @rtype: None 1215 """ 1216 1217 # can't validate if running as user, moreover 1218 # users can't make changes, so... 1219 if os.getuid() != 0: 1220 return 1221 1222 # handle on-disk cache validation 1223 # in this case, repositories cache 1224 # if file is changed, we must destroy cache 1225 if not os.path.isfile(mtimefile): 1226 # we can't know if it has been updated 1227 # remove repositories caches 1228 self.__remove_repo_cache(repoid = repoid) 1229 self.__save_file_mtime(settingfile, mtimefile) 1230 else: 1231 # check mtime 1232 try: 1233 mtime_f = open(mtimefile,"r") 1234 mtime = mtime_f.readline().strip() 1235 mtime_f.close() 1236 # compare with current mtime 1237 try: 1238 currmtime = str(os.path.getmtime(settingfile)) 1239 except OSError: 1240 currmtime = "0.0" 1241 if mtime != currmtime: 1242 self.__remove_repo_cache(repoid = repoid) 1243 self.__save_file_mtime(settingfile, mtimefile) 1244 except (OSError, IOError,): 1245 self.__remove_repo_cache(repoid = repoid) 1246 self.__save_file_mtime(settingfile, mtimefile)
1247