--autounmask: Allow package.mask changes
[portage.git] / pym / portage / package / ebuild / getmaskingstatus.py
1 # Copyright 2010 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 __all__ = ['getmaskingstatus']
5
6 import sys
7
8 import portage
9 from portage import eapi_is_supported, _eapi_is_deprecated
10 from portage.dep import match_from_list, _slot_separator, _repo_separator
11 from portage.localization import _
12 from portage.package.ebuild.config import config
13 from portage.versions import catpkgsplit, cpv_getkey
14
15 if sys.hexversion >= 0x3000000:
16         basestring = str
17
18 class _UnmaskHint(object):
19
20         __slots__ = ('key', 'value')
21
22         def __init__(self, key, value):
23                 self.key = key
24                 self.value = value
25
26 class _MaskReason(object):
27
28         __slots__ = ('category', 'message', 'unmask_hint')
29
30         def __init__(self, category, message, unmask_hint=None):
31                 self.category = category
32                 self.message = message
33                 self.unmask_hint = unmask_hint
34
35 def getmaskingstatus(mycpv, settings=None, portdb=None, myrepo=None):
36         if settings is None:
37                 settings = config(clone=portage.settings)
38         if portdb is None:
39                 portdb = portage.portdb
40
41         return [mreason.message for \
42                 mreason in _getmaskingstatus(mycpv, settings, portdb,myrepo)]
43
44 def _getmaskingstatus(mycpv, settings, portdb, myrepo=None):
45
46         metadata = None
47         installed = False
48         if not isinstance(mycpv, basestring):
49                 # emerge passed in a Package instance
50                 pkg = mycpv
51                 mycpv = pkg.cpv
52                 metadata = pkg.metadata
53                 installed = pkg.installed
54
55         mysplit = catpkgsplit(mycpv)
56         if not mysplit:
57                 raise ValueError(_("invalid CPV: %s") % mycpv)
58         if metadata is None:
59                 db_keys = list(portdb._aux_cache_keys)
60                 try:
61                         metadata = dict(zip(db_keys, portdb.aux_get(mycpv, db_keys, myrepo=myrepo)))
62                 except KeyError:
63                         if not portdb.cpv_exists(mycpv):
64                                 raise
65                         return [_MaskReason("corruption", "corruption")]
66                 if "?" in metadata["LICENSE"]:
67                         settings.setcpv(mycpv, mydb=metadata)
68                         metadata["USE"] = settings["PORTAGE_USE"]
69                 else:
70                         metadata["USE"] = ""
71
72         rValue = []
73
74         # profile checking
75         if settings._getProfileMaskAtom(mycpv, metadata):
76                 rValue.append(_MaskReason("profile", "profile"))
77
78         # package.mask checking
79         if settings._getMaskAtom(mycpv, metadata):
80                 rValue.append(_MaskReason("package.mask", "package.mask", _UnmaskHint("p_mask", None)))
81
82         # keywords checking
83         eapi = metadata["EAPI"]
84         mygroups = settings._getKeywords(mycpv, metadata)
85         licenses = metadata["LICENSE"]
86         properties = metadata["PROPERTIES"]
87         if eapi.startswith("-"):
88                 eapi = eapi[1:]
89         if not eapi_is_supported(eapi):
90                 return [_MaskReason("EAPI", "EAPI %s" % eapi)]
91         elif _eapi_is_deprecated(eapi) and not installed:
92                 return [_MaskReason("EAPI", "EAPI %s" % eapi)]
93         egroups = settings.configdict["backupenv"].get(
94                 "ACCEPT_KEYWORDS", "").split()
95         pgroups = settings["ACCEPT_KEYWORDS"].split()
96         myarch = settings["ARCH"]
97         if pgroups and myarch not in pgroups:
98                 """For operating systems other than Linux, ARCH is not necessarily a
99                 valid keyword."""
100                 myarch = pgroups[0].lstrip("~")
101
102         cp = cpv_getkey(mycpv)
103         pkgdict = settings._keywords_manager.pkeywordsdict.get(cp)
104         matches = False
105         if pkgdict:
106                 pkg = "".join((mycpv, _slot_separator, metadata["SLOT"]))
107                 if 'repository' in metadata:
108                         pkg = "".join((pkg, _repo_separator, metadata['repository']))
109                 cpv_slot_list = [pkg]
110                 for atom, pkgkeywords in pkgdict.items():
111                         if match_from_list(atom, cpv_slot_list):
112                                 matches = True
113                                 pgroups.extend(pkgkeywords)
114         if matches or egroups:
115                 pgroups.extend(egroups)
116                 inc_pgroups = set()
117                 for x in pgroups:
118                         if x.startswith("-"):
119                                 if x == "-*":
120                                         inc_pgroups.clear()
121                                 else:
122                                         inc_pgroups.discard(x[1:])
123                         else:
124                                 inc_pgroups.add(x)
125                 pgroups = inc_pgroups
126                 del inc_pgroups
127
128         kmask = "missing"
129         kmask_hint = None
130
131         if '**' in pgroups:
132                 kmask = None
133         else:
134                 for keyword in pgroups:
135                         if keyword in mygroups:
136                                 kmask = None
137                                 break
138
139         if kmask:
140                 for gp in mygroups:
141                         if gp=="*":
142                                 kmask=None
143                                 break
144                         elif gp=="-"+myarch and myarch in pgroups:
145                                 kmask="-"+myarch
146                                 break
147                         elif gp=="~"+myarch and myarch in pgroups:
148                                 kmask="~"+myarch
149                                 kmask_hint = _UnmaskHint("unstable keyword", kmask)
150                                 break
151
152         try:
153                 missing_licenses = settings._getMissingLicenses(mycpv, metadata)
154                 if missing_licenses:
155                         allowed_tokens = set(["||", "(", ")"])
156                         allowed_tokens.update(missing_licenses)
157                         license_split = licenses.split()
158                         license_split = [x for x in license_split \
159                                 if x in allowed_tokens]
160                         msg = license_split[:]
161                         msg.append("license(s)")
162                         rValue.append(_MaskReason("LICENSE", " ".join(msg), _UnmaskHint("license", set(missing_licenses))))
163         except portage.exception.InvalidDependString as e:
164                 rValue.append(_MaskReason("invalid", "LICENSE: "+str(e)))
165
166         try:
167                 missing_properties = settings._getMissingProperties(mycpv, metadata)
168                 if missing_properties:
169                         allowed_tokens = set(["||", "(", ")"])
170                         allowed_tokens.update(missing_properties)
171                         properties_split = properties.split()
172                         properties_split = [x for x in properties_split \
173                                         if x in allowed_tokens]
174                         msg = properties_split[:]
175                         msg.append("properties")
176                         rValue.append(_MaskReason("PROPERTIES", " ".join(msg)))
177         except portage.exception.InvalidDependString as e:
178                 rValue.append(_MaskReason("invalid", "PROPERTIES: "+str(e)))
179
180         # Only show KEYWORDS masks for installed packages
181         # if they're not masked for any other reason.
182         if kmask and (not installed or not rValue):
183                 rValue.append(_MaskReason("KEYWORDS",
184                         kmask + " keyword", unmask_hint=kmask_hint))
185
186         return rValue