1
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
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
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()
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
79 'live_packagemasking': {
80 'unmask_matches': set(),
81 'mask_matches': set(),
82 },
83 }
84
85 self.__setup_const()
86 self.__scan()
87
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
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
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
157 'keywords': etpConst['confpackagesdir']+"/package.keywords",
158
159 'unmask': etpConst['confpackagesdir']+"/package.unmask",
160
161 'mask': etpConst['confpackagesdir']+"/package.mask",
162
163 'satisfied': etpConst['confpackagesdir']+"/package.satisfied",
164
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
198
199 """
200 Internal method. Scan settings and fill variables.
201
202 @return: None
203 @rtype: None
204 """
205
206 def enforce_persistent():
207
208 self.__data.update(self.__persistent_settings)
209
210 self.__data.update(self.__persistent_settings['backed_up'].copy())
211
212 self.__parse()
213 enforce_persistent()
214
215
216 for plugin_id in sorted(self.__plugins):
217 self.__plugins[plugin_id].parse(self)
218
219
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
229 for plugin_id in sorted(self.__plugins):
230 self.__plugins[plugin_id].post_setup(self)
231
232
233 for external_plugin_id in sorted(self.__external_plugins):
234 self.__external_plugins[external_plugin_id].post_setup(self)
235
237 """
238 dict method. See Python dict API reference.
239 """
240 with self.__mutex:
241
242 if self.__persistent_settings.has_key(mykey):
243 self.__persistent_settings[mykey] = myvalue
244 self.__data[mykey] = myvalue
245
247 """
248 dict method. See Python dict API reference.
249 """
250 with self.__mutex:
251 return self.__data[mykey]
252
254 """
255 dict method. See Python dict API reference.
256 """
257 with self.__mutex:
258 del self.__data[mykey]
259
261 """
262 dict method. See Python dict API reference.
263 """
264 with self.__mutex:
265 return iter(self.__data)
266
268 """
269 dict method. See Python dict API reference.
270 """
271 with self.__mutex:
272 return item in self.__data
273
275 """
276 dict method. See Python dict API reference.
277 """
278 with self.__mutex:
279 return cmp(self.__data, other)
280
282 """
283 dict method. See Python dict API reference.
284 """
285 with self.__mutex:
286 return hash(self.__data)
287
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
303 """
304 dict method. See Python dict API reference.
305 """
306 with self.__mutex:
307 return self.__data.has_key(mykey)
308
310 """
311 dict method. See Python dict API reference.
312 """
313 with self.__mutex:
314 return self.__data.copy()
315
317 """
318 dict method. See Python dict API reference.
319 """
320 with self.__mutex:
321 return self.__data.fromkeys(seq, val)
322
324 """
325 dict method. See Python dict API reference.
326 """
327 with self.__mutex:
328 return self.__data.items()
329
331 """
332 dict method. See Python dict API reference.
333 """
334 with self.__mutex:
335 return self.__data.iteritems()
336
338 """
339 dict method. See Python dict API reference.
340 """
341 with self.__mutex:
342 return self.__data.iterkeys()
343
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
359 """
360 dict method. See Python dict API reference.
361 """
362 with self.__mutex:
363 return self.__data.popitem()
364
366 """
367 dict method. See Python dict API reference.
368 """
369 with self.__mutex:
370 return self.__data.setdefault(mykey, default)
371
373 """
374 dict method. See Python dict API reference.
375 """
376 with self.__mutex:
377 return self.__data.update(kwargs)
378
380 """
381 dict method. See Python dict API reference.
382 """
383 with self.__mutex:
384 return self.__data.values()
385
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
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
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
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
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
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
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
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
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
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
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
514 if len(keywordinfo) > 3:
515 continue
516
517 if len(keywordinfo) == 1:
518 if keywordinfo[0].startswith("repo="):
519 continue
520
521 if keywordinfo[0] == "**":
522 keywordinfo[0] = ""
523 data['universal'].add(keywordinfo[0])
524 continue
525
526 if len(keywordinfo) in (2, 3,):
527
528 if keywordinfo[0].startswith("repo="):
529 continue
530
531 items = keywordinfo[1:]
532
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
542 if keywordinfo[0] not in data['repositories'][reponame]:
543 data['repositories'][reponame][keywordinfo[0]] = set()
544 if len(items) == 1:
545
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
555
556 continue
557 else:
558
559 if keywordinfo[0] not in data['packages']:
560 data['packages'][keywordinfo[0]] = set()
561 data['packages'][keywordinfo[0]].add(items[0])
562
563
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
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
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
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
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
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
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
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
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
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
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
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
729 """
730 Parser returning important system symlinks mapping. For example:
731 {'/usr/lib': ['/usr/lib64']}
732 Useful for reverse matching files belonging to packages.
733
734 @return: dict containing the mapping
735 @rtype: dict
736 """
737 setting_file = self.__setting_files['system_rev_symlinks']
738 raw_data = self.__generic_parser(setting_file)
739 data = {}
740 for line in raw_data:
741 line = line.split()
742 if len(line) < 2:
743 continue
744 data[line[0]] = frozenset(line[1:])
745 return data
746
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
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
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
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
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
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
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
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
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
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:
1152 etpUi['pretend'] = True
1153 return
1154 except OSError:
1155 return
1156
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:
1180 etpUi['pretend'] = True
1181 return
1182 except (OSError,), e:
1183
1184
1185 return
1186
1187 try:
1188 mtime_f = open(tosaveinto,"w")
1189 except IOError, e:
1190 if e.errno == 30:
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
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
1218
1219 if os.getuid() != 0:
1220 return
1221
1222
1223
1224
1225 if not os.path.isfile(mtimefile):
1226
1227
1228 self.__remove_repo_cache(repoid = repoid)
1229 self.__save_file_mtime(settingfile, mtimefile)
1230 else:
1231
1232 try:
1233 mtime_f = open(mtimefile,"r")
1234 mtime = mtime_f.readline().strip()
1235 mtime_f.close()
1236
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