1
2 '''
3 # DESCRIPTION:
4 # Entropy Object Oriented Interface
5
6 Copyright (C) 2007-2009 Fabio Erculiani
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 '''
22 from __future__ import with_statement
23 import os
24 import stat
25 import sys
26 import shutil
27 import time
28 import subprocess
29 import tempfile
30 from entropy.i18n import _
31 from entropy.const import *
32 from entropy.exceptions import *
33 from entropy.db import dbapi2, EntropyRepository, EntropyRepository
34 from entropy.output import purple, bold, red, blue, darkgreen, darkred, brown
35
36
38
39 __repo_error_messages_cache = set()
40 __repodb_cache = {}
41 _memory_db_instances = {}
42
44 self.MirrorStatus.clear()
45 self.__repo_error_messages_cache.clear()
46
47
48 cl_id = self.sys_settings_client_plugin_id
49 client_metadata = self.SystemSettings.get(cl_id, {})
50 if "masking_validation" in client_metadata:
51 client_metadata['masking_validation']['cache'].clear()
52
53
54 del self.validRepositories[:]
55 for repoid in self.SystemSettings['repositories']['order']:
56
57 try:
58 dbc = self.open_repository(repoid)
59 dbc.listConfigProtectDirectories()
60 dbc.validateDatabase()
61 self.validRepositories.append(repoid)
62 except RepositoryError:
63 t = _("Repository") + " " + repoid + " " + \
64 _("is not available") + ". " + _("Cannot validate")
65 t2 = _("Please update your repositories now in order to remove this message!")
66 self.updateProgress(
67 darkred(t),
68 importance = 1,
69 type = "warning"
70 )
71 self.updateProgress(
72 purple(t2),
73 header = bold("!!! "),
74 importance = 1,
75 type = "warning"
76 )
77 continue
78 except (self.dbapi2.OperationalError,self.dbapi2.DatabaseError,SystemDatabaseError,):
79 t = _("Repository") + " " + repoid + " " + \
80 _("is corrupted") + ". " + _("Cannot validate")
81 self.updateProgress(
82 darkred(t),
83 importance = 1,
84 type = "warning"
85 )
86 continue
87
88 self.close_all_repositories(mask_clear = False)
89
91 return (repoid, etpConst['systemroot'],)
92
94 dbc = self.open_memory_database(dbname = repoid)
95 repo_key = self.__get_repository_cache_key(repoid)
96 self._memory_db_instances[repo_key] = dbc
97
98
99 repodata = {
100 'repoid': repoid,
101 'in_memory': True,
102 'description': description,
103 'packages': package_mirrors,
104 'dbpath': ':memory:',
105 }
106 self.add_repository(repodata)
107 return dbc
108
120
125
139
141
142 if isinstance(repoid,basestring):
143 if repoid.endswith(etpConst['packagesext']):
144 xcache = False
145
146 repo_data = self.SystemSettings['repositories']['available']
147 if repoid not in repo_data:
148 t = _("bad repository id specified")
149 if repoid not in self.__repo_error_messages_cache:
150 self.updateProgress(
151 darkred(t),
152 importance = 2,
153 type = "warning"
154 )
155 self.__repo_error_messages_cache.add(repoid)
156 raise RepositoryError("RepositoryError: %s" % (t,))
157
158 if repo_data[repoid].get('in_memory'):
159 repo_key = self.__get_repository_cache_key(repoid)
160 conn = self._memory_db_instances.get(repo_key)
161 else:
162 dbfile = repo_data[repoid]['dbpath']+"/"+etpConst['etpdatabasefile']
163 if not os.path.isfile(dbfile):
164 t = _("Repository %s hasn't been downloaded yet.") % (repoid,)
165 if repoid not in self.__repo_error_messages_cache:
166 self.updateProgress(
167 darkred(t),
168 importance = 2,
169 type = "warning"
170 )
171 self.__repo_error_messages_cache.add(repoid)
172 raise RepositoryError("RepositoryError: %s" % (t,))
173
174 conn = EntropyRepository(
175 readOnly = True,
176 dbFile = dbfile,
177 clientDatabase = True,
178 dbname = etpConst['dbnamerepoprefix']+repoid,
179 xcache = xcache,
180 indexing = indexing,
181 OutputInterface = self,
182 ServiceInterface = self
183 )
184
185 if (repoid not in etpConst['client_treeupdatescalled']) and \
186 (self.entropyTools.is_root()) and \
187 (not repoid.endswith(etpConst['packagesext'])):
188
189 updated = False
190 try:
191 updated = conn.clientUpdatePackagesData(self.clientDbconn)
192 except (self.dbapi2.OperationalError, self.dbapi2.DatabaseError):
193 pass
194 if updated:
195 self.clear_dump_cache(etpCache['world_update'])
196 self.clear_dump_cache(etpCache['critical_update'])
197 self.clear_dump_cache(etpCache['world'])
198 self.clear_dump_cache(etpCache['install'])
199 self.clear_dump_cache(etpCache['remove'])
200 return conn
201
203 fname = self.SystemSettings['repositories']['available'][reponame]['dbpath']+"/"+etpConst['etpdatabaserevisionfile']
204 revision = -1
205 if os.path.isfile(fname) and os.access(fname,os.R_OK):
206 with open(fname,"r") as f:
207 try:
208 revision = int(f.readline().strip())
209 except (OSError, IOError, ValueError,):
210 pass
211 return revision
212
218
220 fname = self.SystemSettings['repositories']['available'][reponame]['dbpath']+"/"+etpConst['etpdatabasehashfile']
221 mhash = "-1"
222 if os.path.isfile(fname) and os.access(fname,os.R_OK):
223 with open(fname,"r") as f:
224 try:
225 mhash = f.readline().strip().split()[0]
226 except (OSError, IOError, IndexError,):
227 pass
228 return mhash
229
231 product = self.SystemSettings['repositories']['product']
232 branch = self.SystemSettings['repositories']['branch']
233
234 try:
235 self.SystemSettings['repositories']['available'][repodata['repoid']] = {}
236 self.SystemSettings['repositories']['available'][repodata['repoid']]['description'] = repodata['description']
237 except KeyError:
238 t = _("repodata dictionary is corrupted")
239 raise InvalidData("InvalidData: %s" % (t,))
240
241 if repodata['repoid'].endswith(etpConst['packagesext']) or repodata.get('in_memory'):
242 try:
243
244 self.SystemSettings['repositories']['available'][repodata['repoid']]['packages'] = repodata['packages'][:]
245 smart_package = repodata.get('smartpackage')
246 if smart_package != None:
247 self.SystemSettings['repositories']['available'][repodata['repoid']]['smartpackage'] = smart_package
248 except KeyError:
249 raise InvalidData("InvalidData: repodata dictionary is corrupted")
250 self.SystemSettings['repositories']['available'][repodata['repoid']]['dbpath'] = repodata.get('dbpath')
251 self.SystemSettings['repositories']['available'][repodata['repoid']]['pkgpath'] = repodata.get('pkgpath')
252 self.SystemSettings['repositories']['available'][repodata['repoid']]['in_memory'] = repodata.get('in_memory')
253
254 self.SystemSettings['repositories']['order'].insert(0, repodata['repoid'])
255 else:
256
257 self.SystemSettings['repositories']['available'][repodata['repoid']]['plain_packages'] = repodata['plain_packages'][:]
258 self.SystemSettings['repositories']['available'][repodata['repoid']]['packages'] = [x+"/"+product for x in repodata['plain_packages']]
259 self.SystemSettings['repositories']['available'][repodata['repoid']]['plain_database'] = repodata['plain_database']
260 self.SystemSettings['repositories']['available'][repodata['repoid']]['database'] = repodata['plain_database'] + \
261 "/" + product + "/database/" + etpConst['currentarch'] + "/" + branch
262 if not repodata['dbcformat'] in etpConst['etpdatabasesupportedcformats']:
263 repodata['dbcformat'] = etpConst['etpdatabasesupportedcformats'][0]
264 self.SystemSettings['repositories']['available'][repodata['repoid']]['dbcformat'] = repodata['dbcformat']
265 self.SystemSettings['repositories']['available'][repodata['repoid']]['dbpath'] = etpConst['etpdatabaseclientdir'] + \
266 "/" + repodata['repoid'] + "/" + product + "/" + etpConst['currentarch'] + "/" + branch
267
268 myrev = self.get_repository_revision(repodata['repoid'])
269 if myrev == -1:
270 myrev = 0
271 self.SystemSettings['repositories']['available'][repodata['repoid']]['dbrevision'] = str(myrev)
272 if repodata.has_key("position"):
273 self.SystemSettings['repositories']['order'].insert(
274 repodata['position'], repodata['repoid'])
275 else:
276 self.SystemSettings['repositories']['order'].append(
277 repodata['repoid'])
278 if not repodata.has_key("service_port"):
279 repodata['service_port'] = int(etpConst['socket_service']['port'])
280 if not repodata.has_key("ssl_service_port"):
281 repodata['ssl_service_port'] = int(etpConst['socket_service']['ssl_port'])
282 self.SystemSettings['repositories']['available'][repodata['repoid']]['service_port'] = repodata['service_port']
283 self.SystemSettings['repositories']['available'][repodata['repoid']]['ssl_service_port'] = repodata['ssl_service_port']
284 self.repository_move_clear_cache(repodata['repoid'])
285
286 self.entropyTools.save_repository_settings(repodata)
287 self.SystemSettings.clear()
288 self.close_all_repositories()
289 self.validate_repositories()
290
337
348
358
385
387 try:
388 repodata = self.SystemSettings['repositories']['available'][repoid].copy()
389 except KeyError:
390 if not self.SystemSettings['repositories']['excluded'].has_key(repoid):
391 raise
392 repodata = self.SystemSettings['repositories']['excluded'][repoid].copy()
393 return repodata
394
395
397 atoms_contained = []
398 basefile = os.path.basename(tbz2file)
399 cut_idx = -1*(len(etpConst['packagesext']))
400 db_dir = tempfile.mkdtemp()
401 dbfile = self.entropyTools.extract_edb(tbz2file,
402 dbpath = db_dir+"/packages.db")
403 if dbfile == None:
404 return -1, atoms_contained
405 etpSys['dirstoclean'].add(os.path.dirname(dbfile))
406
407 repodata = {}
408 repodata['repoid'] = basefile
409 repodata['description'] = "Dynamic database from " + basefile
410 repodata['packages'] = []
411 repodata['dbpath'] = os.path.dirname(dbfile)
412 repodata['pkgpath'] = os.path.realpath(tbz2file)
413 repodata['smartpackage'] = False
414
415 mydbconn = self.open_generic_database(dbfile)
416
417 try:
418 myidpackages = mydbconn.listAllIdpackages()
419 except (AttributeError, self.dbapi2.DatabaseError, \
420 self.dbapi2.IntegrityError, self.dbapi2.OperationalError,):
421 return -2, atoms_contained
422 if len(myidpackages) > 1:
423 repodata[basefile]['smartpackage'] = True
424 for myidpackage in myidpackages:
425 compiled_arch = mydbconn.retrieveDownloadURL(myidpackage)
426 if compiled_arch.find("/"+etpSys['arch']+"/") == -1:
427 return -3, atoms_contained
428 atoms_contained.append((int(myidpackage), basefile))
429
430 self.add_repository(repodata)
431 self.validate_repositories()
432 if basefile not in self.validRepositories:
433 self.remove_repository(basefile)
434 return -4, atoms_contained
435 mydbconn.closeDB()
436 del mydbconn
437 return 0, atoms_contained
438
444
446
447 def load_db_from_ram():
448 self.safe_mode = etpConst['safemodeerrors']['clientdb']
449 mytxt = "%s, %s" % (_("System database not found or corrupted"),
450 _("running in safe mode using empty database from RAM"),)
451 self.updateProgress(
452 darkred(mytxt),
453 importance = 1,
454 type = "warning",
455 header = bold("!!!"),
456 )
457 conn = self.open_memory_database(dbname = etpConst['clientdbid'])
458 return conn
459
460 db_dir = os.path.dirname(etpConst['etpdatabaseclientfilepath'])
461 if not os.path.isdir(db_dir): os.makedirs(db_dir)
462
463 db_path = etpConst['etpdatabaseclientfilepath']
464 if (not self.noclientdb) and (not os.path.isfile(db_path)):
465 conn = load_db_from_ram()
466 self.entropyTools.print_traceback(f = self.clientLog)
467 else:
468 try:
469 conn = EntropyRepository(readOnly = False, dbFile = db_path,
470 clientDatabase = True, dbname = etpConst['clientdbid'],
471 xcache = self.xcache, indexing = self.indexing,
472 OutputInterface = self, ServiceInterface = self
473 )
474 except (self.dbapi2.DatabaseError,):
475 self.entropyTools.print_traceback(f = self.clientLog)
476 conn = load_db_from_ram()
477 else:
478
479 if not self.noclientdb:
480 try:
481 conn.validateDatabase()
482 except SystemDatabaseError:
483 try:
484 conn.closeDB()
485 except:
486 pass
487 self.entropyTools.print_traceback(f = self.clientLog)
488 conn = load_db_from_ram()
489
490 self.clientDbconn = conn
491 return self.clientDbconn
492
494 self.updateProgress(
495 darkred(_("Sanity Check") + ": " + _("system database")),
496 importance = 2,
497 type = "warning"
498 )
499 idpkgs = self.clientDbconn.listAllIdpackages()
500 length = len(idpkgs)
501 count = 0
502 errors = False
503 scanning_txt = _("Scanning...")
504 for x in idpkgs:
505 count += 1
506 self.updateProgress(
507 darkgreen(scanning_txt),
508 importance = 0,
509 type = "info",
510 back = True,
511 count = (count,length),
512 percent = True
513 )
514 try:
515 self.clientDbconn.getPackageData(x)
516 except Exception ,e:
517 self.entropyTools.print_traceback()
518 errors = True
519 self.updateProgress(
520 darkred(_("Errors on idpackage %s, error: %s")) % (x,str(e)),
521 importance = 0,
522 type = "warning"
523 )
524
525 if not errors:
526 t = _("Sanity Check") + ": %s" % (bold(_("PASSED")),)
527 self.updateProgress(
528 darkred(t),
529 importance = 2,
530 type = "warning"
531 )
532 return 0
533 else:
534 t = _("Sanity Check") + ": %s" % (bold(_("CORRUPTED")),)
535 self.updateProgress(
536 darkred(t),
537 importance = 2,
538 type = "warning"
539 )
540 return -1
541
542 - def open_generic_database(self, dbfile, dbname = None, xcache = None,
543 readOnly = False, indexing_override = None, skipChecks = False):
544 if xcache == None:
545 xcache = self.xcache
546 if indexing_override != None:
547 indexing = indexing_override
548 else:
549 indexing = self.indexing
550 if dbname == None:
551 dbname = etpConst['genericdbid']
552 return EntropyRepository(
553 readOnly = readOnly,
554 dbFile = dbfile,
555 clientDatabase = True,
556 dbname = dbname,
557 xcache = xcache,
558 indexing = indexing,
559 OutputInterface = self,
560 skipChecks = skipChecks
561 )
562
564 if dbname == None:
565 dbname = etpConst['genericdbid']
566 dbc = EntropyRepository(
567 readOnly = False,
568 dbFile = ':memory:',
569 clientDatabase = True,
570 dbname = dbname,
571 xcache = False,
572 indexing = False,
573 OutputInterface = self,
574 skipChecks = True,
575 ServiceInterface = self
576 )
577 dbc.initializeDatabase()
578 return dbc
579
580 - def backup_database(self, dbpath, backup_dir = None, silent = False, compress_level = 9):
581
582 if compress_level not in range(1,10):
583 compress_level = 9
584
585 backup_dir = os.path.dirname(dbpath)
586 if not backup_dir: backup_dir = os.path.dirname(dbpath)
587 dbname = os.path.basename(dbpath)
588 bytes_required = 1024000*300
589 if not (os.access(backup_dir,os.W_OK) and \
590 os.path.isdir(backup_dir) and os.path.isfile(dbpath) and \
591 os.access(dbpath,os.R_OK) and self.entropyTools.check_required_space(backup_dir, bytes_required)):
592 if not silent:
593 mytxt = "%s: %s, %s" % (darkred(_("Cannot backup selected database")),blue(dbpath),darkred(_("permission denied")),)
594 self.updateProgress(
595 mytxt,
596 importance = 1,
597 type = "error",
598 header = red(" @@ ")
599 )
600 return False, mytxt
601
602 def get_ts():
603 from datetime import datetime
604 ts = datetime.fromtimestamp(time.time())
605 return "%s%s%s_%sh%sm%ss" % (ts.year,ts.month,ts.day,ts.hour,ts.minute,ts.second)
606
607 comp_dbname = "%s%s.%s.bz2" % (etpConst['dbbackupprefix'],dbname,get_ts(),)
608 comp_dbpath = os.path.join(backup_dir,comp_dbname)
609 if not silent:
610 mytxt = "%s: %s ..." % (darkgreen(_("Backing up database to")),blue(comp_dbpath),)
611 self.updateProgress(
612 mytxt,
613 importance = 1,
614 type = "info",
615 header = blue(" @@ "),
616 back = True
617 )
618 import bz2
619 try:
620 self.entropyTools.compress_file(dbpath, comp_dbpath, bz2.BZ2File, compress_level)
621 except:
622 if not silent:
623 self.entropyTools.print_traceback()
624 return False, _("Unable to compress")
625
626 if not silent:
627 mytxt = "%s: %s" % (darkgreen(_("Database backed up successfully")),blue(comp_dbpath),)
628 self.updateProgress(
629 mytxt,
630 importance = 1,
631 type = "info",
632 header = blue(" @@ "),
633 back = True
634 )
635 return True, _("All fine")
636
638
639 bytes_required = 1024000*300
640 db_dir = os.path.dirname(db_destination)
641 if not (os.access(db_dir,os.W_OK) and os.path.isdir(db_dir) and \
642 os.path.isfile(backup_path) and os.access(backup_path,os.R_OK) and \
643 self.entropyTools.check_required_space(db_dir, bytes_required)):
644
645 if not silent:
646 mytxt = "%s: %s, %s" % (darkred(_("Cannot restore selected backup")),
647 blue(backup_path),darkred(_("permission denied")),)
648 self.updateProgress(
649 mytxt,
650 importance = 1,
651 type = "error",
652 header = red(" @@ ")
653 )
654 return False, mytxt
655
656 if not silent:
657 mytxt = "%s: %s => %s ..." % (darkgreen(_("Restoring backed up database")),
658 blue(os.path.basename(backup_path)),blue(db_destination),)
659 self.updateProgress(
660 mytxt,
661 importance = 1,
662 type = "info",
663 header = blue(" @@ "),
664 back = True
665 )
666
667 import bz2
668 try:
669 self.entropyTools.uncompress_file(backup_path, db_destination, bz2.BZ2File)
670 except:
671 if not silent:
672 self.entropyTools.print_traceback()
673 return False, _("Unable to unpack")
674
675 if not silent:
676 mytxt = "%s: %s" % (darkgreen(_("Database restored successfully")),
677 blue(db_destination),)
678 self.updateProgress(
679 mytxt,
680 importance = 1,
681 type = "info",
682 header = blue(" @@ "),
683 back = True
684 )
685 self.purge_cache()
686 return True, _("All fine")
687
689 if not client_dbdir:
690 client_dbdir = os.path.dirname(etpConst['etpdatabaseclientfilepath'])
691 return [os.path.join(client_dbdir,x) for x in os.listdir(client_dbdir) \
692 if x.startswith(etpConst['dbbackupprefix']) and \
693 os.access(os.path.join(client_dbdir,x),os.R_OK)
694 ]
695
697 """
698 This method is called whenever branch is successfully switched by user.
699 Branch is switched when user wants to upgrade the OS to a new
700 major release.
701 Any repository can be shipped with a sh script which if available,
702 handles system configuration to ease the migration.
703
704 @param old_branch: previously set branch
705 @type old_branch: string
706 @param new_branch: newly set branch
707 @type new_branch: string
708 @return: tuple composed by (1) list of repositories whose script has
709 been run and (2) bool describing if scripts exited with error
710 @rtype: tuple(set, bool)
711 """
712
713 const_debug_write(__name__,
714 "run_repositories_post_branch_switch_hooks: called")
715
716 client_dbconn = self.clientDbconn
717 hooks_ran = set()
718 if client_dbconn is None:
719 const_debug_write(__name__,
720 "run_repositories_post_branch_switch_hooks: clientdb not avail")
721 return hooks_ran, True
722
723 from datetime import datetime
724 place_status_file = set()
725 errors = False
726 repo_data = self.SystemSettings['repositories']['available']
727 repo_data_excl = self.SystemSettings['repositories']['available']
728 all_repos = sorted(set(repo_data.keys() + repo_data_excl.keys()))
729
730 for repoid in all_repos:
731
732 const_debug_write(__name__,
733 "run_repositories_post_branch_switch_hooks: %s" % (
734 repoid,)
735 )
736
737 mydata = repo_data.get(repoid)
738 if mydata is None:
739 mydata = repo_data_excl.get(repoid)
740
741 if mydata is None:
742 const_debug_write(__name__,
743 "run_repositories_post_branch_switch_hooks: skipping %s" % (
744 repoid,)
745 )
746 continue
747
748 branch_mig_script = mydata['post_branch_hop_script']
749 branch_mig_md5sum = '0'
750 if os.access(branch_mig_script, os.R_OK | os.F_OK):
751 branch_mig_md5sum = self.entropyTools.md5sum(branch_mig_script)
752
753 const_debug_write(__name__,
754 "run_repositories_post_branch_switch_hooks: script md5: %s" % (
755 branch_mig_md5sum,)
756 )
757
758
759 status_md5sums = client_dbconn.isBranchMigrationAvailable(
760 repoid, old_branch, new_branch)
761 if status_md5sums:
762 if branch_mig_md5sum == status_md5sums[0]:
763 const_debug_write(__name__,
764 "run_repositories_post_branch_switch_hooks: skip %s" % (
765 branch_mig_script,)
766 )
767 continue
768
769 const_debug_write(__name__,
770 "run_repositories_post_branch_switch_hooks: preparing run: %s" % (
771 branch_mig_script,)
772 )
773
774 if branch_mig_md5sum != '0':
775 args = ["/bin/sh", branch_mig_script, repoid,
776 etpConst['systemroot'] + "/", old_branch, new_branch]
777 const_debug_write(__name__,
778 "run_repositories_post_branch_switch_hooks: run: %s" % (
779 args,)
780 )
781 proc = subprocess.Popen(args, stdin = sys.stdin,
782 stdout = sys.stdout, stderr = sys.stderr)
783
784
785
786 br_rc = proc.wait()
787 const_debug_write(__name__,
788 "run_repositories_post_branch_switch_hooks: rc: %s" % (
789 br_rc,)
790 )
791 if br_rc != 0:
792 errors = True
793
794 const_debug_write(__name__,
795 "run_repositories_post_branch_switch_hooks: done")
796
797
798
799
800
801
802 client_dbconn.insertBranchMigration(repoid, old_branch, new_branch,
803 branch_mig_md5sum, '0')
804
805 const_debug_write(__name__,
806 "run_repositories_post_branch_switch_hooks: db data: %s" % (
807 (repoid, old_branch, new_branch, branch_mig_md5sum, '0',),)
808 )
809
810 hooks_ran.add(repoid)
811
812 return hooks_ran, errors
813
815 """
816 This method is called whenever branch is successfully switched by user
817 and all the updates have been installed (also look at:
818 run_repositories_post_branch_switch_hooks()).
819 Any repository can be shipped with a sh script which if available,
820 handles system configuration to ease the migration.
821
822 @return: list of repositories whose script has been run
823 @rtype: set
824 """
825
826 const_debug_write(__name__,
827 "run_repository_post_branch_upgrade_hooks: called"
828 )
829
830 client_dbconn = self.clientDbconn
831 hooks_ran = set()
832 if client_dbconn is None:
833 return hooks_ran, True
834
835 repo_data = self.SystemSettings['repositories']['available']
836 branch = self.SystemSettings['repositories']['branch']
837 errors = False
838
839 for repoid in self.validRepositories:
840
841 const_debug_write(__name__,
842 "run_repository_post_branch_upgrade_hooks: repoid: %s" % (
843 (repoid,),
844 )
845 )
846
847 mydata = repo_data.get(repoid)
848 if mydata is None:
849 const_debug_write(__name__,
850 "run_repository_post_branch_upgrade_hooks: repo data N/A")
851 continue
852
853
854 branch_upg_script = mydata['post_branch_upgrade_script']
855 branch_upg_md5sum = '0'
856 if os.access(branch_upg_script, os.R_OK | os.F_OK):
857 branch_upg_md5sum = self.entropyTools.md5sum(branch_upg_script)
858
859 const_debug_write(__name__,
860 "run_repository_post_branch_upgrade_hooks: script md5: %s" % (
861 branch_upg_md5sum,)
862 )
863
864 upgrade_data = client_dbconn.retrieveBranchMigration(branch)
865 if upgrade_data.get(repoid) is None:
866
867 const_debug_write(__name__,
868 "run_repository_post_branch_upgrade_hooks: %s: %s" % (
869 repoid, "branch upgrade data not avail",)
870 )
871 continue
872 repo_upgrade_data = upgrade_data[repoid]
873
874 const_debug_write(__name__,
875 "run_repository_post_branch_upgrade_hooks: upgrade data: %s" % (
876 repo_upgrade_data,)
877 )
878
879 for from_branch in sorted(repo_upgrade_data):
880
881 const_debug_write(__name__,
882 "run_repository_post_branch_upgrade_hooks: upgrade: %s" % (
883 from_branch,)
884 )
885
886
887
888
889 post_mig_md5, post_upg_md5 = repo_upgrade_data[from_branch]
890 if branch_upg_md5sum == post_upg_md5:
891
892 const_debug_write(__name__,
893 "run_repository_post_branch_upgrade_hooks: %s: %s" % (
894 "already run for from_branch", from_branch,)
895 )
896 continue
897
898 const_debug_write(__name__,
899 "run_repository_post_branch_upgrade_hooks: %s: %s" % (
900 "running upgrade script from_branch:", from_branch,)
901 )
902
903 args = ["/bin/sh", branch_upg_script, repoid,
904 etpConst['systemroot'] + "/", from_branch, branch]
905 proc = subprocess.Popen(args, stdin = sys.stdin,
906 stdout = sys.stdout, stderr = sys.stderr)
907 mig_rc = proc.wait()
908
909 const_debug_write(__name__,
910 "run_repository_post_branch_upgrade_hooks: %s: %s" % (
911 "upgrade script exit status", mig_rc,)
912 )
913
914 if mig_rc != 0:
915 errors = True
916
917
918 client_dbconn.setBranchMigrationPostUpgradeMd5sum(repoid,
919 from_branch, branch, branch_upg_md5sum)
920
921 const_debug_write(__name__,
922 "run_repository_post_branch_upgrade_hooks: %s: %s" % (
923 "saved upgrade data",
924 (repoid, from_branch, branch, branch_upg_md5sum,),
925 )
926 )
927
928 return hooks_ran, errors
929
930
932
936
938
939 os.chmod(filepath,0664)
940 if etpConst['entropygid'] != None:
941 os.chown(filepath,-1,etpConst['entropygid'])
942
945
947 if os.path.isfile(etpConst['locks']['using_resources']):
948 os.remove(etpConst['locks']['using_resources'])
949
953
955 if not os.path.isfile(pidfile):
956 return False
957 f = open(pidfile)
958 s_pid = f.readline().strip()
959 f.close()
960 try:
961 s_pid = int(s_pid)
962 except ValueError:
963 return False
964
965 mypid = os.getpid()
966 if (s_pid != mypid) and os.path.isdir("%s/proc/%s" % (etpConst['systemroot'],s_pid,)):
967
968 return True
969 return False
970
972 lockdir = os.path.dirname(pidfile)
973 if not os.path.isdir(lockdir):
974 os.makedirs(lockdir,0775)
975 const_setup_perms(lockdir,etpConst['entropygid'])
976 if mypid == None:
977 mypid = os.getpid()
978 f = open(pidfile,"w")
979 f.write(str(mypid))
980 f.flush()
981 f.close()
982
984
985 etpConst['applicationlock'] = False
986 const_setup_entropy_pid(just_read = True)
987 locked = self.entropyTools.application_lock_check(option = None, gentle = True)
988 if locked:
989 if not silent:
990 self.updateProgress(
991 red(_("Another Entropy instance is currently active, cannot satisfy your request.")),
992 importance = 1,
993 type = "error",
994 header = darkred(" @@ ")
995 )
996 return True
997 return False
998
1000
1001 lock_count = 0
1002 max_lock_count = 600
1003 sleep_seconds = 0.5
1004
1005
1006 while 1:
1007 locked = check_function()
1008 if not locked:
1009 if lock_count > 0:
1010 self.updateProgress(
1011 blue(_("Resources unlocked, let's go!")),
1012 importance = 1,
1013 type = "info",
1014 header = darkred(" @@ ")
1015 )
1016
1017
1018 time.sleep(5)
1019 break
1020 if lock_count >= max_lock_count:
1021 mycalc = max_lock_count*sleep_seconds/60
1022 self.updateProgress(
1023 blue(_("Resources still locked after %s minutes, giving up!")) % (mycalc,),
1024 importance = 1,
1025 type = "warning",
1026 header = darkred(" @@ ")
1027 )
1028 return True
1029 lock_count += 1
1030 self.updateProgress(
1031 blue(_("Resources locked, sleeping %s seconds, check #%s/%s")) % (
1032 sleep_seconds,
1033 lock_count,
1034 max_lock_count,
1035 ),
1036 importance = 1,
1037 type = "warning",
1038 header = darkred(" @@ "),
1039 back = True
1040 )
1041 time.sleep(sleep_seconds)
1042 return False
1043
1045 if etpConst.has_key(constant_name):
1046 myinst = etpConst[constant_name]
1047 if type(etpConst[constant_name]) in (list,tuple):
1048 myinst = etpConst[constant_name][:]
1049 elif type(etpConst[constant_name]) in (dict,set):
1050 myinst = etpConst[constant_name].copy()
1051 else:
1052 myinst = etpConst[constant_name]
1053 etpConst['backed_up'].update({constant_name: myinst})
1054 else:
1055 t = _("Nothing to backup in etpConst with %s key") % (constant_name,)
1056 raise InvalidData("InvalidData: %s" % (t,))
1057
1060
1062 if repositories == None:
1063 repositories = self.validRepositories
1064 for repoid in repositories:
1065 dbconn = self.open_repository(repoid)
1066
1089
1091 viewer = None
1092 if os.access("/usr/bin/less",os.X_OK):
1093 viewer = "/usr/bin/less"
1094 elif os.access("/bin/more",os.X_OK):
1095 viewer = "/bin/more"
1096 if not viewer:
1097 viewer = self.get_file_editor()
1098 return viewer
1099
1101 editor = None
1102 if os.getenv("EDITOR"):
1103 editor = "$EDITOR"
1104 elif os.access("/bin/nano",os.X_OK):
1105 editor = "/bin/nano"
1106 elif os.access("/bin/vi",os.X_OK):
1107 editor = "/bin/vi"
1108 elif os.access("/usr/bin/vi",os.X_OK):
1109 editor = "/usr/bin/vi"
1110 elif os.access("/usr/bin/emacs",os.X_OK):
1111 editor = "/usr/bin/emacs"
1112 elif os.access("/bin/emacs",os.X_OK):
1113 editor = "/bin/emacs"
1114 return editor
1115
1117
1118 def _ensure_package_sets_dir():
1119 sets_dir = etpConst['confsetsdir']
1120 if not os.path.isdir(sets_dir):
1121 if os.path.lexists(sets_dir):
1122 os.remove(sets_dir)
1123 os.makedirs(sets_dir,0775)
1124 const_setup_perms(sets_dir, etpConst['entropygid'])
1125
1126 try:
1127 set_name = str(set_name)
1128 except (UnicodeEncodeError,UnicodeDecodeError,):
1129 raise InvalidPackageSet("InvalidPackageSet: %s %s" % (set_name,_("must be an ASCII string"),))
1130
1131 if set_name.startswith(etpConst['packagesetprefix']):
1132 raise InvalidPackageSet("InvalidPackageSet: %s %s '%s'" % (set_name,_("cannot start with"),etpConst['packagesetprefix'],))
1133 set_match, rc = self.package_set_match(set_name)
1134 if rc: return -1,_("Name already taken")
1135
1136 _ensure_package_sets_dir()
1137 set_file = os.path.join(etpConst['confsetsdir'],set_name)
1138 if os.path.isfile(set_file) and os.access(set_file,os.W_OK):
1139 try:
1140 os.remove(set_file)
1141 except OSError:
1142 return -2,_("Cannot remove the old element")
1143 if not os.access(os.path.dirname(set_file),os.W_OK):
1144 return -3,_("Cannot create the element")
1145
1146 f = open(set_file,"w")
1147 for x in set_atoms: f.write("%s\n" % (x,))
1148 f.flush()
1149 f.close()
1150 self.SystemSettings['system_package_sets'][set_name] = set(set_atoms)
1151 return 0,_("All fine")
1152
1154
1155 try:
1156 set_name = str(set_name)
1157 except (UnicodeEncodeError,UnicodeDecodeError,):
1158 raise InvalidPackageSet("InvalidPackageSet: %s %s" % (set_name,_("must be an ASCII string"),))
1159
1160 if set_name.startswith(etpConst['packagesetprefix']):
1161 raise InvalidPackageSet("InvalidPackageSet: %s %s '%s'" % (set_name,_("cannot start with"),etpConst['packagesetprefix'],))
1162
1163 set_match, rc = self.package_set_match(set_name)
1164 if not rc: return -1,_("Already removed")
1165 set_id, set_x, set_y = set_match
1166
1167 if set_id != etpConst['userpackagesetsid']:
1168 return -2,_("Not defined by user")
1169 set_file = os.path.join(etpConst['confsetsdir'],set_name)
1170 if os.path.isfile(set_file) and os.access(set_file,os.W_OK):
1171 os.remove(set_file)
1172 if set_name in self.SystemSettings['system_package_sets']:
1173 del self.SystemSettings['system_package_sets'][set_name]
1174 return 0,_("All fine")
1175 return -3,_("Set not found or unable to remove")
1176
1178 client_plugin_id = etpConst['system_settings_plugins_ids']['client_plugin']
1179 mask_installed = self.SystemSettings[client_plugin_id]['system_mask']['repos_installed']
1180 if idpackage in mask_installed:
1181 return True
1182 return False
1183
1185 return db_download_uri.split("/")[2]
1186
1191
1195
1197 if not install_queue:
1198 return {}
1199 licenses = {}
1200 cl_id = self.sys_settings_client_plugin_id
1201 repo_sys_data = self.SystemSettings[cl_id]['repositories']
1202
1203 for match in install_queue:
1204 repoid = match[1]
1205 dbconn = self.open_repository(repoid)
1206 wl = repo_sys_data['license_whitelist'].get(repoid)
1207 if not wl:
1208 continue
1209 keys = dbconn.retrieveLicensedataKeys(match[0])
1210 for key in keys:
1211 if key not in wl:
1212 found = self.clientDbconn.isLicenseAccepted(key)
1213 if found:
1214 continue
1215 if not licenses.has_key(key):
1216 licenses[key] = set()
1217 licenses[key].add(match)
1218 return licenses
1219
1220 - def get_text_license(self, license_name, repoid):
1221 dbconn = self.open_repository(repoid)
1222 text = dbconn.retrieveLicenseText(license_name)
1223 tempfile = self.entropyTools.get_random_temp_file()
1224 f = open(tempfile,"w")
1225 f.write(text)
1226 f.flush()
1227 f.close()
1228 return tempfile
1229
1231 """
1232 Set new Entropy branch. This is NOT thread-safe.
1233 Please note that if you call this method all your
1234 repository instance references will become invalid.
1235 This is caused by close_all_repositories and SystemSettings
1236 clear methods.
1237 Once you changed branch, the repository databases won't be
1238 available until you fetch them (through Repositories class)
1239
1240 @param branch -- new branch
1241 @type branch basestring
1242 @return None
1243 """
1244 self.Cacher.discard()
1245 self.Cacher.stop()
1246 self.purge_cache(showProgress = False)
1247 self.close_all_repositories()
1248
1249
1250 etpConst['branch'] = branch
1251 self.entropyTools.write_new_branch(branch)
1252 self.SystemSettings.clear()
1253
1254
1255 self.reopen_client_repository()
1256 self.clientDbconn.resetTreeupdatesDigests()
1257 self.close_all_repositories()
1258 if self.xcache:
1259 self.Cacher.start()
1260
1261 - def get_meant_packages(self, search_term, from_installed = False,
1262 valid_repos = []):
1263
1264 pkg_data = []
1265 atom_srch = False
1266 if "/" in search_term:
1267 atom_srch = True
1268
1269 if not valid_repos:
1270 valid_repos = self.validRepositories
1271 if from_installed:
1272 valid_repos = []
1273 if hasattr(self,'clientDbconn'):
1274 valid_repos.append(self.clientDbconn)
1275
1276 for repo in valid_repos:
1277 if isinstance(repo, basestring):
1278 dbconn = self.open_repository(repo)
1279 elif isinstance(repo, EntropyRepository):
1280 dbconn = repo
1281 else:
1282 continue
1283 pkg_data.extend([(x,repo,) for x in \
1284 dbconn.searchSimilarPackages(search_term, atom = atom_srch)])
1285
1286 return pkg_data
1287
1289 categories = set()
1290 for repo in self.validRepositories:
1291 dbconn = self.open_repository(repo)
1292 catsdata = dbconn.listAllCategories()
1293 categories.update(set([x[1] for x in catsdata]))
1294 return categories
1295
1297 pkg_matches = []
1298 for repo in self.validRepositories:
1299 dbconn = self.open_repository(repo)
1300 branch = self.SystemSettings['repositories']['branch']
1301 catsdata = dbconn.searchPackagesByCategory(category, branch = branch)
1302 pkg_matches.extend([(x[1],repo,) for x in catsdata if (x[1],repo,) not in pkg_matches])
1303 return pkg_matches
1304
1306
1307 data = {}
1308 for repo in self.validRepositories:
1309 try:
1310 dbconn = self.open_repository(repo)
1311 except RepositoryError:
1312 continue
1313 try:
1314 data = dbconn.retrieveCategoryDescription(category)
1315 except (self.dbapi2.OperationalError, self.dbapi2.IntegrityError,):
1316 continue
1317 if data: break
1318
1319 return data
1320
1324
1326
1327 idpackage, repoid = match
1328 dbconn = self.open_repository(repoid)
1329 cl_id = self.sys_settings_client_plugin_id
1330 misc_data = self.SystemSettings[cl_id]['misc']
1331 if mask:
1332 config_protect = set(dbconn.retrieveProtectMask(idpackage).split())
1333 config_protect |= set(misc_data['configprotectmask'])
1334 else:
1335 config_protect = set(dbconn.retrieveProtect(idpackage).split())
1336 config_protect |= set(misc_data['configprotect'])
1337 config_protect = [etpConst['systemroot']+x for x in config_protect]
1338
1339 return sorted(config_protect)
1340
1342
1343 if self.clientDbconn == None:
1344 return []
1345 cl_id = self.sys_settings_client_plugin_id
1346 misc_data = self.SystemSettings[cl_id]['misc']
1347 if mask:
1348 _pmask = self.clientDbconn.retrieveProtectMask(idpackage).split()
1349 config_protect = set(_pmask)
1350 config_protect |= set(misc_data['configprotectmask'])
1351 else:
1352 _protect = self.clientDbconn.retrieveProtect(idpackage).split()
1353 config_protect = set(_protect)
1354 config_protect |= set(misc_data['configprotect'])
1355 config_protect = [etpConst['systemroot']+x for x in config_protect]
1356
1357 return sorted(config_protect)
1358
1360
1361 if self.clientDbconn == None:
1362 return []
1363
1364
1365
1366 cl_id = self.sys_settings_client_plugin_id
1367 misc_data = self.SystemSettings[cl_id]['misc']
1368 if mask:
1369 _pmask = self.clientDbconn.listConfigProtectDirectories(mask = True)
1370 config_protect = set(_pmask)
1371 config_protect |= set(misc_data['configprotectmask'])
1372 else:
1373 _protect = self.clientDbconn.listConfigProtectDirectories()
1374 config_protect = set(_protect)
1375 config_protect |= set(misc_data['configprotect'])
1376 config_protect = [etpConst['systemroot']+x for x in config_protect]
1377
1378 return sorted(config_protect)
1379
1391
1397
1398 - def quickpkg(self, atomstring, savedir = None):
1399 if savedir == None:
1400 savedir = etpConst['packagestmpdir']
1401 if not os.path.isdir(etpConst['packagestmpdir']):
1402 os.makedirs(etpConst['packagestmpdir'])
1403
1404 match = self.clientDbconn.atomMatch(atomstring)
1405 if match[0] == -1:
1406 return -1,None,None
1407 atom = self.clientDbconn.atomMatch(match[0])
1408 pkgdata = self.clientDbconn.getPackageData(match[0])
1409 resultfile = self.quickpkg_handler(pkgdata = pkgdata, dirpath = savedir)
1410 if resultfile == None:
1411 return -1,atom,None
1412 else:
1413 return 0,atom,resultfile
1414
1415 - def quickpkg_handler(self, pkgdata, dirpath, edb = True,
1416 portdbPath = None, fake = False, compression = "bz2", shiftpath = ""):
1417
1418 import stat
1419 import tarfile
1420
1421 if compression not in ("bz2","","gz"):
1422 compression = "bz2"
1423
1424
1425 pkgtag = ''
1426 pkgrev = "~"+str(pkgdata['revision'])
1427 if pkgdata['versiontag']: pkgtag = "#"+pkgdata['versiontag']
1428 pkgname = pkgdata['name']+"-"+pkgdata['version']+pkgrev+pkgtag
1429 pkgcat = pkgdata['category']
1430
1431 dirpath += "/"+pkgname+etpConst['packagesext']
1432 if os.path.isfile(dirpath):
1433 os.remove(dirpath)
1434 tar = tarfile.open(dirpath,"w:"+compression)
1435
1436 if not fake:
1437
1438 contents = sorted([x for x in pkgdata['content']])
1439
1440
1441 for path in contents:
1442
1443 encoded_path = path
1444 path = path.encode('raw_unicode_escape')
1445 path = shiftpath+path
1446 try:
1447 exist = os.lstat(path)
1448 except OSError:
1449 continue
1450 arcname = path[len(shiftpath):]
1451 if arcname.startswith("/"):
1452 arcname = arcname[1:]
1453 ftype = pkgdata['content'][encoded_path]
1454 if str(ftype) == '0': ftype = 'dir'
1455 if 'dir' == ftype and \
1456 not stat.S_ISDIR(exist.st_mode) and \
1457 os.path.isdir(path):
1458 path = os.path.realpath(path)
1459
1460 tarinfo = tar.gettarinfo(path, arcname)
1461
1462 if stat.S_ISREG(exist.st_mode):
1463 tarinfo.mode = stat.S_IMODE(exist.st_mode)
1464 tarinfo.type = tarfile.REGTYPE
1465 f = open(path)
1466 try:
1467 tar.addfile(tarinfo, f)
1468 finally:
1469 f.close()
1470 else:
1471 tar.addfile(tarinfo)
1472
1473 tar.close()
1474
1475
1476 import entropy.xpak as xpak
1477 Spm = self.Spm()
1478
1479 gentoo_name = self.entropyTools.remove_tag(pkgname)
1480 gentoo_name = self.entropyTools.remove_entropy_revision(gentoo_name)
1481 if portdbPath == None:
1482 dbdir = Spm.get_vdb_path()+"/"+pkgcat+"/"+gentoo_name+"/"
1483 else:
1484 dbdir = portdbPath+"/"+pkgcat+"/"+gentoo_name+"/"
1485 if os.path.isdir(dbdir):
1486 tbz2 = xpak.tbz2(dirpath)
1487 tbz2.recompose(dbdir)
1488
1489 if edb:
1490 self.inject_entropy_database_into_package(dirpath, pkgdata)
1491
1492 if os.path.isfile(dirpath):
1493 return dirpath
1494 return None
1495
1496
1498
1500 """
1501 @input: matched atom (idpackage,repoid)
1502 @output:
1503 upgrade: int(2)
1504 install: int(1)
1505 reinstall: int(0)
1506 downgrade: int(-1)
1507 """
1508 dbconn = self.open_repository(match[1])
1509 pkgkey, pkgslot = dbconn.retrieveKeySlot(match[0])
1510 results = self.clientDbconn.searchKeySlot(pkgkey, pkgslot)
1511 if not results: return 1
1512
1513 installed_idpackage = results[0][0]
1514 pkgver, pkgtag, pkgrev = dbconn.getVersioningData(match[0])
1515 installedVer, installedTag, installedRev = self.clientDbconn.getVersioningData(installed_idpackage)
1516 pkgcmp = self.entropyTools.entropy_compare_versions((pkgver,pkgtag,pkgrev),(installedVer,installedTag,installedRev))
1517 if pkgcmp == 0:
1518 return 0
1519 elif pkgcmp > 0:
1520 return 2
1521 return -1
1522
1524 idpackage, repoid = match
1525 dbconn = self.open_repository(repoid)
1526 idpackage, idreason = dbconn.idpackageValidator(idpackage)
1527 masked = False
1528 if idpackage == -1: masked = True
1529 return masked, idreason, self.SystemSettings['pkg_masking_reasons'].get(idreason)
1530
1532 m_id, m_repo = match
1533 dbconn = self.open_repository(m_repo)
1534 conflicts = dbconn.retrieveConflicts(m_id)
1535 found_conflicts = set()
1536 for conflict in conflicts:
1537 my_m_id, my_m_rc = self.clientDbconn.atomMatch(conflict)
1538 if my_m_id != -1:
1539
1540 match_data = dbconn.retrieveKeySlot(m_id)
1541 installed_match_data = self.clientDbconn.retrieveKeySlot(my_m_id)
1542 if match_data != installed_match_data:
1543 found_conflicts.add(my_m_id)
1544 return found_conflicts
1545
1547 m_id, m_repo = match
1548 dbconn = self.open_repository(m_repo)
1549 idpackage, idreason = dbconn.idpackageValidator(m_id, live = live_check)
1550 if idpackage != -1:
1551 return False
1552 return True
1553
1555
1556 m_id, m_repo = match
1557 if m_repo not in self.validRepositories: return False
1558 dbconn = self.open_repository(m_repo)
1559 idpackage, idreason = dbconn.idpackageValidator(m_id, live = live_check)
1560 if idpackage != -1: return False
1561 myr = self.SystemSettings['pkg_masking_reference']
1562 user_masks = [myr['user_package_mask'],myr['user_license_mask'],myr['user_live_mask']]
1563 if idreason in user_masks:
1564 return True
1565 return False
1566
1568
1569 m_id, m_repo = match
1570 if m_repo not in self.validRepositories: return False
1571 dbconn = self.open_repository(m_repo)
1572 idpackage, idreason = dbconn.idpackageValidator(m_id, live = live_check)
1573 if idpackage == -1: return False
1574 myr = self.SystemSettings['pkg_masking_reference']
1575 user_masks = [
1576 myr['user_package_unmask'],myr['user_live_unmask'],myr['user_package_keywords'],
1577 myr['user_repo_package_keywords_all'], myr['user_repo_package_keywords']
1578 ]
1579 if idreason in user_masks:
1580 return True
1581 return False
1582
1583 - def mask_match(self, match, method = 'atom', dry_run = False, clean_all_cache = False):
1594
1595 - def unmask_match(self, match, method = 'atom', dry_run = False, clean_all_cache = False):
1606
1607 - def _mask_unmask_match(self, match, method, methods_reference, dry_run = False, clean_all_cache = False):
1634
1640
1646
1652
1658
1663
1668
1670 exist = False
1671 if not os.path.isfile(m_file):
1672 if not os.access(os.path.dirname(m_file),os.W_OK):
1673 return False
1674 elif not os.access(m_file, os.W_OK):
1675 return False
1676 elif not dry_run:
1677 exist = True
1678
1679 if dry_run:
1680 return True
1681
1682 content = []
1683 if exist:
1684 f = open(m_file,"r")
1685 content = [x.strip() for x in f.readlines()]
1686 f.close()
1687 content.append(keyword)
1688 m_file_tmp = m_file+".tmp"
1689 f = open(m_file_tmp,"w")
1690 for line in content:
1691 f.write(line+"\n")
1692 f.flush()
1693 f.close()
1694 shutil.move(m_file_tmp,m_file)
1695 return True
1696
1698 setting_data = self.SystemSettings.get_setting_files_data()
1699 masking_list = [setting_data['mask'],setting_data['unmask']]
1700 return self._clear_match_generic(match, masking_list = masking_list, dry_run = dry_run)
1701
1703
1704 self.SystemSettings['live_packagemasking']['unmask_matches'].discard(match)
1705 self.SystemSettings['live_packagemasking']['mask_matches'].discard(match)
1706
1707 if dry_run: return
1708
1709 for mask_file in masking_list:
1710 if not (os.path.isfile(mask_file) and os.access(mask_file,os.W_OK)): continue
1711 f = open(mask_file,"r")
1712 newf = self.entropyTools.open_buffer()
1713 line = f.readline()
1714 while line:
1715 line = line.strip()
1716 if line.startswith("#"):
1717 newf.write(line+"\n")
1718 line = f.readline()
1719 continue
1720 elif not line:
1721 newf.write("\n")
1722 line = f.readline()
1723 continue
1724 mymatch = self.atom_match(line, packagesFilter = False)
1725 if mymatch == match:
1726 line = f.readline()
1727 continue
1728 newf.write(line+"\n")
1729 line = f.readline()
1730 f.close()
1731 tmpfile = mask_file+".w_tmp"
1732 f = open(tmpfile,"w")
1733 f.write(newf.getvalue())
1734 f.flush()
1735 f.close()
1736 newf.close()
1737 shutil.move(tmpfile,mask_file)
1738