diff options
author | Richard Purdie <richard@openedhand.com> | 2008-09-30 15:08:33 +0000 |
---|---|---|
committer | Richard Purdie <richard@openedhand.com> | 2008-09-30 15:08:33 +0000 |
commit | c30eddb243e7e65f67f656e62848a033cf6f2e5c (patch) | |
tree | 110dd95788b76f55d31cb8d30aac2de8400b6f4a /bitbake-dev/lib/bb/providers.py | |
parent | 5ef0510474004eeb2ae8a99b64e2febb1920e077 (diff) | |
download | poky-c30eddb243e7e65f67f656e62848a033cf6f2e5c.tar.gz |
Add bitbake-dev to allow ease of testing and development of bitbake trunk
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@5337 311d38ba-8fff-0310-9ca6-ca027cbcb966
Diffstat (limited to 'bitbake-dev/lib/bb/providers.py')
-rw-r--r-- | bitbake-dev/lib/bb/providers.py | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/bitbake-dev/lib/bb/providers.py b/bitbake-dev/lib/bb/providers.py new file mode 100644 index 0000000000..0ad5876ef0 --- /dev/null +++ b/bitbake-dev/lib/bb/providers.py | |||
@@ -0,0 +1,303 @@ | |||
1 | # ex:ts=4:sw=4:sts=4:et | ||
2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
3 | # | ||
4 | # Copyright (C) 2003, 2004 Chris Larson | ||
5 | # Copyright (C) 2003, 2004 Phil Blundell | ||
6 | # Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer | ||
7 | # Copyright (C) 2005 Holger Hans Peter Freyther | ||
8 | # Copyright (C) 2005 ROAD GmbH | ||
9 | # Copyright (C) 2006 Richard Purdie | ||
10 | # | ||
11 | # This program is free software; you can redistribute it and/or modify | ||
12 | # it under the terms of the GNU General Public License version 2 as | ||
13 | # published by the Free Software Foundation. | ||
14 | # | ||
15 | # This program is distributed in the hope that it will be useful, | ||
16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | # GNU General Public License for more details. | ||
19 | # | ||
20 | # You should have received a copy of the GNU General Public License along | ||
21 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
22 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
23 | |||
24 | import os, re | ||
25 | from bb import data, utils | ||
26 | import bb | ||
27 | |||
28 | class NoProvider(Exception): | ||
29 | """Exception raised when no provider of a build dependency can be found""" | ||
30 | |||
31 | class NoRProvider(Exception): | ||
32 | """Exception raised when no provider of a runtime dependency can be found""" | ||
33 | |||
34 | |||
35 | def sortPriorities(pn, dataCache, pkg_pn = None): | ||
36 | """ | ||
37 | Reorder pkg_pn by file priority and default preference | ||
38 | """ | ||
39 | |||
40 | if not pkg_pn: | ||
41 | pkg_pn = dataCache.pkg_pn | ||
42 | |||
43 | files = pkg_pn[pn] | ||
44 | priorities = {} | ||
45 | for f in files: | ||
46 | priority = dataCache.bbfile_priority[f] | ||
47 | preference = dataCache.pkg_dp[f] | ||
48 | if priority not in priorities: | ||
49 | priorities[priority] = {} | ||
50 | if preference not in priorities[priority]: | ||
51 | priorities[priority][preference] = [] | ||
52 | priorities[priority][preference].append(f) | ||
53 | pri_list = priorities.keys() | ||
54 | pri_list.sort(lambda a, b: a - b) | ||
55 | tmp_pn = [] | ||
56 | for pri in pri_list: | ||
57 | pref_list = priorities[pri].keys() | ||
58 | pref_list.sort(lambda a, b: b - a) | ||
59 | tmp_pref = [] | ||
60 | for pref in pref_list: | ||
61 | tmp_pref.extend(priorities[pri][pref]) | ||
62 | tmp_pn = [tmp_pref] + tmp_pn | ||
63 | |||
64 | return tmp_pn | ||
65 | |||
66 | |||
67 | def findPreferredProvider(pn, cfgData, dataCache, pkg_pn = None, item = None): | ||
68 | """ | ||
69 | Find the first provider in pkg_pn with a PREFERRED_VERSION set. | ||
70 | """ | ||
71 | |||
72 | preferred_file = None | ||
73 | preferred_ver = None | ||
74 | |||
75 | localdata = data.createCopy(cfgData) | ||
76 | bb.data.setVar('OVERRIDES', "pn-%s:%s:%s" % (pn, pn, data.getVar('OVERRIDES', localdata)), localdata) | ||
77 | bb.data.update_data(localdata) | ||
78 | |||
79 | preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True) | ||
80 | if preferred_v: | ||
81 | m = re.match('(\d+:)*(.*)(_.*)*', preferred_v) | ||
82 | if m: | ||
83 | if m.group(1): | ||
84 | preferred_e = int(m.group(1)[:-1]) | ||
85 | else: | ||
86 | preferred_e = None | ||
87 | preferred_v = m.group(2) | ||
88 | if m.group(3): | ||
89 | preferred_r = m.group(3)[1:] | ||
90 | else: | ||
91 | preferred_r = None | ||
92 | else: | ||
93 | preferred_e = None | ||
94 | preferred_r = None | ||
95 | |||
96 | for file_set in pkg_pn: | ||
97 | for f in file_set: | ||
98 | pe,pv,pr = dataCache.pkg_pepvpr[f] | ||
99 | if preferred_v == pv and (preferred_r == pr or preferred_r == None) and (preferred_e == pe or preferred_e == None): | ||
100 | preferred_file = f | ||
101 | preferred_ver = (pe, pv, pr) | ||
102 | break | ||
103 | if preferred_file: | ||
104 | break; | ||
105 | if preferred_r: | ||
106 | pv_str = '%s-%s' % (preferred_v, preferred_r) | ||
107 | else: | ||
108 | pv_str = preferred_v | ||
109 | if not (preferred_e is None): | ||
110 | pv_str = '%s:%s' % (preferred_e, pv_str) | ||
111 | itemstr = "" | ||
112 | if item: | ||
113 | itemstr = " (for item %s)" % item | ||
114 | if preferred_file is None: | ||
115 | bb.msg.note(1, bb.msg.domain.Provider, "preferred version %s of %s not available%s" % (pv_str, pn, itemstr)) | ||
116 | else: | ||
117 | bb.msg.debug(1, bb.msg.domain.Provider, "selecting %s as PREFERRED_VERSION %s of package %s%s" % (preferred_file, pv_str, pn, itemstr)) | ||
118 | |||
119 | return (preferred_ver, preferred_file) | ||
120 | |||
121 | |||
122 | def findLatestProvider(pn, cfgData, dataCache, file_set): | ||
123 | """ | ||
124 | Return the highest version of the providers in file_set. | ||
125 | Take default preferences into account. | ||
126 | """ | ||
127 | latest = None | ||
128 | latest_p = 0 | ||
129 | latest_f = None | ||
130 | for file_name in file_set: | ||
131 | pe,pv,pr = dataCache.pkg_pepvpr[file_name] | ||
132 | dp = dataCache.pkg_dp[file_name] | ||
133 | |||
134 | if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pe, pv, pr)) < 0)) or (dp > latest_p): | ||
135 | latest = (pe, pv, pr) | ||
136 | latest_f = file_name | ||
137 | latest_p = dp | ||
138 | |||
139 | return (latest, latest_f) | ||
140 | |||
141 | |||
142 | def findBestProvider(pn, cfgData, dataCache, pkg_pn = None, item = None): | ||
143 | """ | ||
144 | If there is a PREFERRED_VERSION, find the highest-priority bbfile | ||
145 | providing that version. If not, find the latest version provided by | ||
146 | an bbfile in the highest-priority set. | ||
147 | """ | ||
148 | |||
149 | sortpkg_pn = sortPriorities(pn, dataCache, pkg_pn) | ||
150 | # Find the highest priority provider with a PREFERRED_VERSION set | ||
151 | (preferred_ver, preferred_file) = findPreferredProvider(pn, cfgData, dataCache, sortpkg_pn, item) | ||
152 | # Find the latest version of the highest priority provider | ||
153 | (latest, latest_f) = findLatestProvider(pn, cfgData, dataCache, sortpkg_pn[0]) | ||
154 | |||
155 | if preferred_file is None: | ||
156 | preferred_file = latest_f | ||
157 | preferred_ver = latest | ||
158 | |||
159 | return (latest, latest_f, preferred_ver, preferred_file) | ||
160 | |||
161 | |||
162 | def _filterProviders(providers, item, cfgData, dataCache): | ||
163 | """ | ||
164 | Take a list of providers and filter/reorder according to the | ||
165 | environment variables and previous build results | ||
166 | """ | ||
167 | eligible = [] | ||
168 | preferred_versions = {} | ||
169 | sortpkg_pn = {} | ||
170 | |||
171 | # The order of providers depends on the order of the files on the disk | ||
172 | # up to here. Sort pkg_pn to make dependency issues reproducible rather | ||
173 | # than effectively random. | ||
174 | providers.sort() | ||
175 | |||
176 | # Collate providers by PN | ||
177 | pkg_pn = {} | ||
178 | for p in providers: | ||
179 | pn = dataCache.pkg_fn[p] | ||
180 | if pn not in pkg_pn: | ||
181 | pkg_pn[pn] = [] | ||
182 | pkg_pn[pn].append(p) | ||
183 | |||
184 | bb.msg.debug(1, bb.msg.domain.Provider, "providers for %s are: %s" % (item, pkg_pn.keys())) | ||
185 | |||
186 | # First add PREFERRED_VERSIONS | ||
187 | for pn in pkg_pn.keys(): | ||
188 | sortpkg_pn[pn] = sortPriorities(pn, dataCache, pkg_pn) | ||
189 | preferred_versions[pn] = findPreferredProvider(pn, cfgData, dataCache, sortpkg_pn[pn], item) | ||
190 | if preferred_versions[pn][1]: | ||
191 | eligible.append(preferred_versions[pn][1]) | ||
192 | |||
193 | # Now add latest verisons | ||
194 | for pn in pkg_pn.keys(): | ||
195 | if pn in preferred_versions and preferred_versions[pn][1]: | ||
196 | continue | ||
197 | preferred_versions[pn] = findLatestProvider(pn, cfgData, dataCache, sortpkg_pn[pn][0]) | ||
198 | eligible.append(preferred_versions[pn][1]) | ||
199 | |||
200 | if len(eligible) == 0: | ||
201 | bb.msg.error(bb.msg.domain.Provider, "no eligible providers for %s" % item) | ||
202 | return 0 | ||
203 | |||
204 | # If pn == item, give it a slight default preference | ||
205 | # This means PREFERRED_PROVIDER_foobar defaults to foobar if available | ||
206 | for p in providers: | ||
207 | pn = dataCache.pkg_fn[p] | ||
208 | if pn != item: | ||
209 | continue | ||
210 | (newvers, fn) = preferred_versions[pn] | ||
211 | if not fn in eligible: | ||
212 | continue | ||
213 | eligible.remove(fn) | ||
214 | eligible = [fn] + eligible | ||
215 | |||
216 | return eligible | ||
217 | |||
218 | |||
219 | def filterProviders(providers, item, cfgData, dataCache): | ||
220 | """ | ||
221 | Take a list of providers and filter/reorder according to the | ||
222 | environment variables and previous build results | ||
223 | Takes a "normal" target item | ||
224 | """ | ||
225 | |||
226 | eligible = _filterProviders(providers, item, cfgData, dataCache) | ||
227 | |||
228 | prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, cfgData, 1) | ||
229 | if prefervar: | ||
230 | dataCache.preferred[item] = prefervar | ||
231 | |||
232 | foundUnique = False | ||
233 | if item in dataCache.preferred: | ||
234 | for p in eligible: | ||
235 | pn = dataCache.pkg_fn[p] | ||
236 | if dataCache.preferred[item] == pn: | ||
237 | bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item)) | ||
238 | eligible.remove(p) | ||
239 | eligible = [p] + eligible | ||
240 | foundUnique = True | ||
241 | break | ||
242 | |||
243 | bb.msg.debug(1, bb.msg.domain.Provider, "sorted providers for %s are: %s" % (item, eligible)) | ||
244 | |||
245 | return eligible, foundUnique | ||
246 | |||
247 | def filterProvidersRunTime(providers, item, cfgData, dataCache): | ||
248 | """ | ||
249 | Take a list of providers and filter/reorder according to the | ||
250 | environment variables and previous build results | ||
251 | Takes a "runtime" target item | ||
252 | """ | ||
253 | |||
254 | eligible = _filterProviders(providers, item, cfgData, dataCache) | ||
255 | |||
256 | # Should use dataCache.preferred here? | ||
257 | preferred = [] | ||
258 | preferred_vars = [] | ||
259 | for p in eligible: | ||
260 | pn = dataCache.pkg_fn[p] | ||
261 | provides = dataCache.pn_provides[pn] | ||
262 | for provide in provides: | ||
263 | prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, cfgData, 1) | ||
264 | if prefervar == pn: | ||
265 | var = "PREFERRED_PROVIDERS_%s = %s" % (provide, prefervar) | ||
266 | bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy runtime %s due to %s" % (pn, item, var)) | ||
267 | preferred_vars.append(var) | ||
268 | eligible.remove(p) | ||
269 | eligible = [p] + eligible | ||
270 | preferred.append(p) | ||
271 | break | ||
272 | |||
273 | numberPreferred = len(preferred) | ||
274 | |||
275 | if numberPreferred > 1: | ||
276 | bb.msg.error(bb.msg.domain.Provider, "Conflicting PREFERRED_PROVIDERS entries were found which resulted in an attempt to select multiple providers (%s) for runtime dependecy %s\nThe entries resulting in this conflict were: %s" % (preferred, item, preferred_vars)) | ||
277 | |||
278 | bb.msg.debug(1, bb.msg.domain.Provider, "sorted providers for %s are: %s" % (item, eligible)) | ||
279 | |||
280 | return eligible, numberPreferred | ||
281 | |||
282 | def getRuntimeProviders(dataCache, rdepend): | ||
283 | """ | ||
284 | Return any providers of runtime dependency | ||
285 | """ | ||
286 | rproviders = [] | ||
287 | |||
288 | if rdepend in dataCache.rproviders: | ||
289 | rproviders += dataCache.rproviders[rdepend] | ||
290 | |||
291 | if rdepend in dataCache.packages: | ||
292 | rproviders += dataCache.packages[rdepend] | ||
293 | |||
294 | if rproviders: | ||
295 | return rproviders | ||
296 | |||
297 | # Only search dynamic packages if we can't find anything in other variables | ||
298 | for pattern in dataCache.packages_dynamic: | ||
299 | regexp = re.compile(pattern) | ||
300 | if regexp.match(rdepend): | ||
301 | rproviders += dataCache.packages_dynamic[pattern] | ||
302 | |||
303 | return rproviders | ||