'MaskManager',
)
-from itertools import chain
from portage import os
from portage.dep import ExtendedAtomDict, match_from_list, _repo_separator, _slot_separator
-from portage.util import grabfile_package, stack_lists
+from portage.util import append_repo, grabfile_package, stack_lists
from portage.versions import cpv_getkey
class MaskManager(object):
- def __init__(self, pmask_locations, abs_user_config,
+ def __init__(self, repositories, profiles, abs_user_config,
user_config=True, strict_umatched_removal=False):
self._punmaskdict = ExtendedAtomDict(list)
self._pmaskdict = ExtendedAtomDict(list)
- repo_profiles, profiles = pmask_locations
+ #Read profile/package.mask form every repo.
+ #Repositories inherit masks from their parent profiles and
+ #are able to remove mask from them with -atoms.
+ #Such a removal affects only the current repo, but not the parent.
+ #Add ::repo specs to every atom to make sure atoms only affect
+ #packages from the current repo.
- #Read profile/package.mask form every repo. Stack them immediately
- #to make sure that -atoms don't effect other repos.
repo_pkgmasklines = []
- repo_pkgunmasklines = []
- for x in repo_profiles:
- repo_pkgmasklines.append(stack_lists([grabfile_package(
- os.path.join(x, "package.mask"), recursive=1, remember_source_file=True, verify_eapi=True)], \
- incremental=1, remember_source_file=True,
- warn_for_unmatched_removal=True,
+ for repo in repositories.repos_with_profiles():
+ lines = []
+ repo_lines = grabfile_package(os.path.join(repo.location, "profiles", "package.mask"), \
+ recursive=1, remember_source_file=True, verify_eapi=True)
+ masters = repo.masters
+ if masters is None:
+ masters = [repositories.mainRepo()]
+ for master in masters:
+ master_lines = grabfile_package(os.path.join(master.location, "profiles", "package.mask"), \
+ recursive=1, remember_source_file=True, verify_eapi=True)
+ lines.append(stack_lists([master_lines, repo_lines], incremental=1,
+ remember_source_file=True, warn_for_unmatched_removal=True,
strict_warn_for_unmatched_removal=strict_umatched_removal))
- repo_pkgunmasklines.append(stack_lists([grabfile_package(
- os.path.join(x, "package.unmask"), recursive=1, remember_source_file=True, verify_eapi=True)], \
- incremental=1, remember_source_file=True,
- warn_for_unmatched_removal=True,
- strict_warn_for_unmatched_removal=strict_umatched_removal))
- repo_pkgmasklines = list(chain.from_iterable(repo_pkgmasklines))
- repo_pkgunmasklines = list(chain.from_iterable(repo_pkgunmasklines))
+ repo_pkgmasklines.extend(append_repo(stack_lists(lines), repo.name, remember_source_file=True))
+
+ repo_pkgunmasklines = []
+ for repo in repositories.repos_with_profiles():
+ repo_lines = grabfile_package(os.path.join(repo.location, "profiles", "package.unmask"), \
+ recursive=1, remember_source_file=True, verify_eapi=True)
+ lines = stack_lists([repo_lines], incremental=1, \
+ remember_source_file=True, warn_for_unmatched_removal=True,
+ strict_warn_for_unmatched_removal=strict_umatched_removal)
+ repo_pkgmasklines.extend(append_repo(lines, repo.name))
#Read package.mask form the user's profile. Stack them in the end
#to allow profiles to override masks from their parent profiles.
#Stack everything together. At this point, only user_pkgmasklines may contain -atoms.
#Don't warn for unmatched -atoms here, since we don't do it for any other user config file.
pkgmasklines = stack_lists([repo_pkgmasklines, profile_pkgmasklines, user_pkgmasklines], \
- incremental=1, remember_source_file=True, warn_for_unmatched_removal=False)
+ incremental=1, remember_source_file=True, warn_for_unmatched_removal=False, ignore_repo=True)
pkgunmasklines = stack_lists([repo_pkgunmasklines, profile_pkgunmasklines, user_pkgunmasklines], \
- incremental=1, remember_source_file=True, warn_for_unmatched_removal=False)
+ incremental=1, remember_source_file=True, warn_for_unmatched_removal=False, ignore_repo=True)
for x, source_file in pkgmasklines:
self._pmaskdict.setdefault(x.cp, []).append(x)
class RepoConfig(object):
"""Stores config of one repository"""
__slots__ = ['aliases', 'eclass_overrides', 'location', 'masters', 'main_repo',
- 'missing_repo_name', 'name', 'priority', 'sync']
+ 'missing_repo_name', 'name', 'priority', 'sync', 'format']
def __init__(self, name, repo_opts):
"""Build a RepoConfig with options in repo_opts
Try to read repo_name in repository location, but if
sync = sync.strip()
self.sync = sync
+ format = repo_opts.get('format')
+ if format is not None:
+ format = format.strip()
+ self.format = format
+
self.missing_repo_name = False
location = repo_opts.get('location')
else:
return ''
+ def mainRepo(self):
+ """Returns the main repo"""
+ return self.prepos[self.prepos['DEFAULT'].main_repo]
+
def _check_locations(self):
"""Check if repositories location are correct and show a warning message if not"""
for (name, r) in self.prepos.items():
writemsg(_("!!! Invalid Repository Location"
" (not a dir): '%s'\n") % r.location, noiselevel=-1)
+ def repos_with_profiles(self):
+ for repo_name in self.prepos_order:
+ repo = self.prepos[repo_name]
+ if repo.format != "unavailable":
+ yield repo
+
def load_repository_config(settings):
#~ repoconfigpaths = [os.path.join(settings.global_config_path, "repos.conf")]
#~ repoconfigpaths.append(os.path.join(settings["PORTAGE_CONFIGROOT"],
final_dict[k] = v
return final_dict
+def append_repo(atom_list, repo_name, remember_source_file=False):
+ """
+ Takes a list of valid atoms without repo spec and appends ::repo_name.
+ """
+ if remember_source_file:
+ return [(Atom(atom + "::" + repo_name, allow_wildcard=True, allow_repo=True), source) \
+ for atom, source in atom_list]
+ else:
+ return [Atom(atom + "::" + repo_name, allow_wildcard=True, allow_repo=True) \
+ for atom in atom_list]
+
def stack_lists(lists, incremental=1, remember_source_file=False,
- warn_for_unmatched_removal=False, strict_warn_for_unmatched_removal=False):
+ warn_for_unmatched_removal=False, strict_warn_for_unmatched_removal=False, ignore_repo=False):
"""Stacks an array of list-types into one array. Optionally removing
distinct values using '-value' notation. Higher index is preferenced.
if token == "-*":
new_list.clear()
elif token[:1] == '-':
- try:
- new_list.pop(token[1:])
- except KeyError:
+ matched = False
+ if ignore_repo and not "::" in token:
+ #Let -cat/pkg remove cat/pkg::repo.
+ to_be_removed = []
+ for atom in new_list:
+ if atom == token[1:] or atom.split("::")[0] == token[1:]:
+ to_be_removed.append(atom)
+ if to_be_removed:
+ matched = True
+ for atom in to_be_removed:
+ new_list.pop(atom)
+ else:
+ try:
+ new_list.pop(token[1:])
+ matched = True
+ except KeyError:
+ pass
+
+ if not matched:
if source_file and \
(strict_warn_for_unmatched_removal or \
token_key not in matched_removals):