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