add profile-formats portage-1 awareness and enforcement
[portage.git] / pym / portage / package / ebuild / _config / UseManager.py
1 # Copyright 2010-2011 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 __all__ = (
5         'UseManager',
6 )
7
8 from _emerge.Package import Package
9 from portage import os
10 from portage.dep import ExtendedAtomDict, remove_slot, _get_useflag_re
11 from portage.localization import _
12 from portage.util import grabfile, grabdict_package, read_corresponding_eapi_file, stack_lists, writemsg
13 from portage.versions import cpv_getkey
14
15 from portage.package.ebuild._config.helper import ordered_by_atom_specificity
16
17 class UseManager(object):
18
19         def __init__(self, repositories, profiles, abs_user_config, user_config=True):
20                 #       file                            variable
21                 #--------------------------------
22                 #       repositories
23                 #--------------------------------
24                 #       use.mask                        _repo_usemask_dict
25                 #       use.force                       _repo_useforce_dict
26                 #       package.use.mask                _repo_pusemask_dict
27                 #       package.use.force               _repo_puseforce_dict
28                 #--------------------------------
29                 #       profiles
30                 #--------------------------------
31                 #       use.mask                        _usemask_list
32                 #       use.force                       _useforce_list
33                 #       package.use.mask                _pusemask_list
34                 #       package.use                     _pkgprofileuse
35                 #       package.use.force               _puseforce_list
36                 #--------------------------------
37                 #       user config
38                 #--------------------------------
39                 #       package.use                     _pusedict       
40
41                 # Dynamic variables tracked by the config class
42                 #--------------------------------
43                 #       profiles
44                 #--------------------------------
45                 #       usemask
46                 #       useforce
47                 #--------------------------------
48                 #       user config
49                 #--------------------------------
50                 #       puse
51
52                 self._repo_usemask_dict = self._parse_repository_files_to_dict_of_tuples("use.mask", repositories)
53                 self._repo_useforce_dict = self._parse_repository_files_to_dict_of_tuples("use.force", repositories)
54                 self._repo_pusemask_dict = self._parse_repository_files_to_dict_of_dicts("package.use.mask", repositories)
55                 self._repo_puseforce_dict = self._parse_repository_files_to_dict_of_dicts("package.use.force", repositories)
56                 self._repo_puse_dict = self._parse_repository_files_to_dict_of_dicts("package.use", repositories)
57
58                 self._usemask_list = self._parse_profile_files_to_tuple_of_tuples("use.mask", profiles)
59                 self._useforce_list = self._parse_profile_files_to_tuple_of_tuples("use.force", profiles)
60                 self._pusemask_list = self._parse_profile_files_to_tuple_of_dicts("package.use.mask", profiles)
61                 self._pkgprofileuse = self._parse_profile_files_to_tuple_of_dicts("package.use", profiles, juststrings=True)
62                 self._puseforce_list = self._parse_profile_files_to_tuple_of_dicts("package.use.force", profiles)
63
64                 self._pusedict = self._parse_user_files_to_extatomdict("package.use", abs_user_config, user_config)
65
66                 self.repositories = repositories
67         
68         def _parse_file_to_tuple(self, file_name, recursive=True):
69                 ret = []
70                 lines = grabfile(file_name, recursive=recursive)
71                 eapi = read_corresponding_eapi_file(file_name)
72                 useflag_re = _get_useflag_re(eapi)
73                 for prefixed_useflag in lines:
74                         if prefixed_useflag[:1] == "-":
75                                 useflag = prefixed_useflag[1:]
76                         else:
77                                 useflag = prefixed_useflag
78                         if useflag_re.match(useflag) is None:
79                                 writemsg(_("--- Invalid USE flag in '%s': '%s'\n") %
80                                         (file_name, prefixed_useflag), noiselevel=-1)
81                         else:
82                                 ret.append(prefixed_useflag)
83                 return tuple(ret)
84
85         def _parse_file_to_dict(self, file_name, juststrings=False, recursive=True):
86                 ret = {}
87                 location_dict = {}
88                 file_dict = grabdict_package(file_name, recursive=recursive, verify_eapi=True)
89                 eapi = read_corresponding_eapi_file(file_name)
90                 useflag_re = _get_useflag_re(eapi)
91                 for k, v in file_dict.items():
92                         useflags = []
93                         for prefixed_useflag in v:
94                                 if prefixed_useflag[:1] == "-":
95                                         useflag = prefixed_useflag[1:]
96                                 else:
97                                         useflag = prefixed_useflag
98                                 if useflag_re.match(useflag) is None:
99                                         writemsg(_("--- Invalid USE flag for '%s' in '%s': '%s'\n") %
100                                                 (k, file_name, prefixed_useflag), noiselevel=-1)
101                                 else:
102                                         useflags.append(prefixed_useflag)
103                         location_dict.setdefault(k, []).extend(useflags)
104                 for k, v in location_dict.items():
105                         if juststrings:
106                                 v = " ".join(v)
107                         else:
108                                 v = tuple(v)
109                         ret.setdefault(k.cp, {})[k] = v
110                 return ret
111
112         def _parse_user_files_to_extatomdict(self, file_name, location, user_config):
113                 ret = ExtendedAtomDict(dict)
114                 if user_config:
115                         pusedict = grabdict_package(
116                                 os.path.join(location, file_name), recursive=1, allow_wildcard=True, allow_repo=True, verify_eapi=False)
117                         for k, v in pusedict.items():
118                                 ret.setdefault(k.cp, {})[k] = tuple(v)
119
120                 return ret
121
122         def _parse_repository_files_to_dict_of_tuples(self, file_name, repositories):
123                 ret = {}
124                 for repo in repositories.repos_with_profiles():
125                         ret[repo.name] = self._parse_file_to_tuple(os.path.join(repo.location, "profiles", file_name))
126                 return ret
127
128         def _parse_repository_files_to_dict_of_dicts(self, file_name, repositories):
129                 ret = {}
130                 for repo in repositories.repos_with_profiles():
131                         ret[repo.name] = self._parse_file_to_dict(os.path.join(repo.location, "profiles", file_name))
132                 return ret
133
134         def _parse_profile_files_to_tuple_of_tuples(self, file_name, locations):
135                 return tuple(self._parse_file_to_tuple(os.path.join(profile[0], file_name), recursive=profile[1])
136                         for profile in locations)
137
138         def _parse_profile_files_to_tuple_of_dicts(self, file_name, locations, juststrings=False):
139                 return tuple(self._parse_file_to_dict(os.path.join(profile[0], file_name), juststrings, recursive=profile[1])
140                         for profile in locations)
141
142         def getUseMask(self, pkg=None):
143                 if pkg is None:
144                         return frozenset(stack_lists(
145                                 self._usemask_list, incremental=True))
146
147                 cp = getattr(pkg, "cp", None)
148                 if cp is None:
149                         cp = cpv_getkey(remove_slot(pkg))
150                 usemask = []
151                 if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO:
152                         repos = []
153                         try:
154                                 repos.extend(repo.name for repo in
155                                         self.repositories[pkg.repo].masters)
156                         except KeyError:
157                                 pass
158                         repos.append(pkg.repo)
159                         for repo in repos:
160                                 usemask.append(self._repo_usemask_dict.get(repo, {}))
161                                 cpdict = self._repo_pusemask_dict.get(repo, {}).get(cp)
162                                 if cpdict:
163                                         pkg_usemask = ordered_by_atom_specificity(cpdict, pkg)
164                                         if pkg_usemask:
165                                                 usemask.extend(pkg_usemask)
166                 for i, pusemask_dict in enumerate(self._pusemask_list):
167                         if self._usemask_list[i]:
168                                 usemask.append(self._usemask_list[i])
169                         cpdict = pusemask_dict.get(cp)
170                         if cpdict:
171                                 pkg_usemask = ordered_by_atom_specificity(cpdict, pkg)
172                                 if pkg_usemask:
173                                         usemask.extend(pkg_usemask)
174                 return frozenset(stack_lists(usemask, incremental=True))
175
176         def getUseForce(self, pkg=None):
177                 if pkg is None:
178                         return frozenset(stack_lists(
179                                 self._useforce_list, incremental=True))
180
181                 cp = getattr(pkg, "cp", None)
182                 if cp is None:
183                         cp = cpv_getkey(remove_slot(pkg))
184                 useforce = []
185                 if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO:
186                         repos = []
187                         try:
188                                 repos.extend(repo.name for repo in
189                                         self.repositories[pkg.repo].masters)
190                         except KeyError:
191                                 pass
192                         repos.append(pkg.repo)
193                         for repo in repos:
194                                 useforce.append(self._repo_useforce_dict.get(repo, {}))
195                                 cpdict = self._repo_puseforce_dict.get(repo, {}).get(cp)
196                                 if cpdict:
197                                         pkg_useforce = ordered_by_atom_specificity(cpdict, pkg)
198                                         if pkg_useforce:
199                                                 useforce.extend(pkg_useforce)
200                 for i, puseforce_dict in enumerate(self._puseforce_list):
201                         if self._useforce_list[i]:
202                                 useforce.append(self._useforce_list[i])
203                         cpdict = puseforce_dict.get(cp)
204                         if cpdict:
205                                 pkg_useforce = ordered_by_atom_specificity(cpdict, pkg)
206                                 if pkg_useforce:
207                                         useforce.extend(pkg_useforce)
208                 return frozenset(stack_lists(useforce, incremental=True))
209
210         def getPUSE(self, pkg):
211                 cp = getattr(pkg, "cp", None)
212                 if cp is None:
213                         cp = cpv_getkey(remove_slot(pkg))
214                 ret = ""
215                 cpdict = self._pusedict.get(cp)
216                 if cpdict:
217                         puse_matches = ordered_by_atom_specificity(cpdict, pkg)
218                         if puse_matches:
219                                 puse_list = []
220                                 for x in puse_matches:
221                                         puse_list.extend(x)
222                                 ret = " ".join(puse_list)
223                 return ret
224
225         def extract_global_USE_changes(self, old=""):
226                 ret = old
227                 cpdict = self._pusedict.get("*/*")
228                 if cpdict is not None:
229                         v = cpdict.pop("*/*", None)
230                         if v is not None:
231                                 ret = " ".join(v)
232                                 if old:
233                                         ret = old + " " + ret
234                                 if not cpdict:
235                                         #No tokens left in atom_license_map, remove it.
236                                         del self._pusedict["*/*"]
237                 return ret