diff options
Diffstat (limited to 'bitbake/lib/bb/providers.py')
-rw-r--r-- | bitbake/lib/bb/providers.py | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/bitbake/lib/bb/providers.py b/bitbake/lib/bb/providers.py new file mode 100644 index 0000000000..3cb7cc1f07 --- /dev/null +++ b/bitbake/lib/bb/providers.py | |||
@@ -0,0 +1,209 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # ex:ts=4:sw=4:sts=4:et | ||
3 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
4 | # | ||
5 | # Copyright (C) 2003, 2004 Chris Larson | ||
6 | # Copyright (C) 2003, 2004 Phil Blundell | ||
7 | # Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer | ||
8 | # Copyright (C) 2005 Holger Hans Peter Freyther | ||
9 | # Copyright (C) 2005 ROAD GmbH | ||
10 | # Copyright (C) 2006 Richard Purdie | ||
11 | # | ||
12 | # This program is free software; you can redistribute it and/or modify it under | ||
13 | # the terms of the GNU General Public License as published by the Free Software | ||
14 | # Foundation; either version 2 of the License, or (at your option) any later | ||
15 | # version. | ||
16 | # | ||
17 | # This program is distributed in the hope that it will be useful, but WITHOUT | ||
18 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
19 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
20 | # | ||
21 | # You should have received a copy of the GNU General Public License along with | ||
22 | # this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
23 | # Place, Suite 330, Boston, MA 02111-1307 USA. | ||
24 | |||
25 | import os, re | ||
26 | from bb import data, utils | ||
27 | import bb | ||
28 | |||
29 | class NoProvider(Exception): | ||
30 | """Exception raised when no provider of a build dependency can be found""" | ||
31 | |||
32 | class NoRProvider(Exception): | ||
33 | """Exception raised when no provider of a runtime dependency can be found""" | ||
34 | |||
35 | def findBestProvider(pn, cfgData, dataCache, pkg_pn = None, item = None): | ||
36 | """ | ||
37 | If there is a PREFERRED_VERSION, find the highest-priority bbfile | ||
38 | providing that version. If not, find the latest version provided by | ||
39 | an bbfile in the highest-priority set. | ||
40 | """ | ||
41 | if not pkg_pn: | ||
42 | pkg_pn = dataCache.pkg_pn | ||
43 | |||
44 | files = pkg_pn[pn] | ||
45 | priorities = {} | ||
46 | for f in files: | ||
47 | priority = dataCache.bbfile_priority[f] | ||
48 | if priority not in priorities: | ||
49 | priorities[priority] = [] | ||
50 | priorities[priority].append(f) | ||
51 | p_list = priorities.keys() | ||
52 | p_list.sort(lambda a, b: a - b) | ||
53 | tmp_pn = [] | ||
54 | for p in p_list: | ||
55 | tmp_pn = [priorities[p]] + tmp_pn | ||
56 | |||
57 | preferred_file = None | ||
58 | |||
59 | localdata = data.createCopy(cfgData) | ||
60 | bb.data.setVar('OVERRIDES', "%s:%s" % (pn, data.getVar('OVERRIDES', localdata)), localdata) | ||
61 | bb.data.update_data(localdata) | ||
62 | |||
63 | preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True) | ||
64 | if preferred_v: | ||
65 | m = re.match('(.*)_(.*)', preferred_v) | ||
66 | if m: | ||
67 | preferred_v = m.group(1) | ||
68 | preferred_r = m.group(2) | ||
69 | else: | ||
70 | preferred_r = None | ||
71 | |||
72 | for file_set in tmp_pn: | ||
73 | for f in file_set: | ||
74 | pv,pr = dataCache.pkg_pvpr[f] | ||
75 | if preferred_v == pv and (preferred_r == pr or preferred_r == None): | ||
76 | preferred_file = f | ||
77 | preferred_ver = (pv, pr) | ||
78 | break | ||
79 | if preferred_file: | ||
80 | break; | ||
81 | if preferred_r: | ||
82 | pv_str = '%s-%s' % (preferred_v, preferred_r) | ||
83 | else: | ||
84 | pv_str = preferred_v | ||
85 | itemstr = "" | ||
86 | if item: | ||
87 | itemstr = " (for item %s)" % item | ||
88 | if preferred_file is None: | ||
89 | bb.msg.note(1, bb.msg.domain.Provider, "preferred version %s of %s not available%s" % (pv_str, pn, itemstr)) | ||
90 | else: | ||
91 | bb.msg.debug(1, bb.msg.domain.Provider, "selecting %s as PREFERRED_VERSION %s of package %s%s" % (preferred_file, pv_str, pn, itemstr)) | ||
92 | |||
93 | del localdata | ||
94 | |||
95 | # get highest priority file set | ||
96 | files = tmp_pn[0] | ||
97 | latest = None | ||
98 | latest_p = 0 | ||
99 | latest_f = None | ||
100 | for file_name in files: | ||
101 | pv,pr = dataCache.pkg_pvpr[file_name] | ||
102 | dp = dataCache.pkg_dp[file_name] | ||
103 | |||
104 | if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p): | ||
105 | latest = (pv, pr) | ||
106 | latest_f = file_name | ||
107 | latest_p = dp | ||
108 | if preferred_file is None: | ||
109 | preferred_file = latest_f | ||
110 | preferred_ver = latest | ||
111 | |||
112 | return (latest,latest_f,preferred_ver, preferred_file) | ||
113 | |||
114 | # | ||
115 | # RP - build_cache_fail needs to move elsewhere | ||
116 | # | ||
117 | def filterProviders(providers, item, cfgData, dataCache, build_cache_fail = {}): | ||
118 | """ | ||
119 | Take a list of providers and filter/reorder according to the | ||
120 | environment variables and previous build results | ||
121 | """ | ||
122 | eligible = [] | ||
123 | preferred_versions = {} | ||
124 | |||
125 | # Collate providers by PN | ||
126 | pkg_pn = {} | ||
127 | for p in providers: | ||
128 | pn = dataCache.pkg_fn[p] | ||
129 | if pn not in pkg_pn: | ||
130 | pkg_pn[pn] = [] | ||
131 | pkg_pn[pn].append(p) | ||
132 | |||
133 | bb.msg.debug(1, bb.msg.domain.Provider, "providers for %s are: %s" % (item, pkg_pn.keys())) | ||
134 | |||
135 | for pn in pkg_pn.keys(): | ||
136 | preferred_versions[pn] = bb.providers.findBestProvider(pn, cfgData, dataCache, pkg_pn, item)[2:4] | ||
137 | eligible.append(preferred_versions[pn][1]) | ||
138 | |||
139 | |||
140 | for p in eligible: | ||
141 | if p in build_cache_fail: | ||
142 | bb.msg.debug(1, bb.msg.domain.Provider, "rejecting already-failed %s" % p) | ||
143 | eligible.remove(p) | ||
144 | |||
145 | if len(eligible) == 0: | ||
146 | bb.msg.error(bb.msg.domain.Provider, "no eligible providers for %s" % item) | ||
147 | return 0 | ||
148 | |||
149 | |||
150 | # If pn == item, give it a slight default preference | ||
151 | # This means PREFERRED_PROVIDER_foobar defaults to foobar if available | ||
152 | for p in providers: | ||
153 | pn = dataCache.pkg_fn[p] | ||
154 | if pn != item: | ||
155 | continue | ||
156 | (newvers, fn) = preferred_versions[pn] | ||
157 | if not fn in eligible: | ||
158 | continue | ||
159 | eligible.remove(fn) | ||
160 | eligible = [fn] + eligible | ||
161 | |||
162 | # look to see if one of them is already staged, or marked as preferred. | ||
163 | # if so, bump it to the head of the queue | ||
164 | for p in providers: | ||
165 | pn = dataCache.pkg_fn[p] | ||
166 | pv, pr = dataCache.pkg_pvpr[p] | ||
167 | |||
168 | stamp = '%s.do_populate_staging' % dataCache.stamp[p] | ||
169 | if os.path.exists(stamp): | ||
170 | (newvers, fn) = preferred_versions[pn] | ||
171 | if not fn in eligible: | ||
172 | # package was made ineligible by already-failed check | ||
173 | continue | ||
174 | oldver = "%s-%s" % (pv, pr) | ||
175 | newver = '-'.join(newvers) | ||
176 | if (newver != oldver): | ||
177 | extra_chat = "%s (%s) already staged but upgrading to %s to satisfy %s" % (pn, oldver, newver, item) | ||
178 | else: | ||
179 | extra_chat = "Selecting already-staged %s (%s) to satisfy %s" % (pn, oldver, item) | ||
180 | |||
181 | bb.msg.note(2, bb.msg.domain.Provider, "%s" % extra_chat) | ||
182 | eligible.remove(fn) | ||
183 | eligible = [fn] + eligible | ||
184 | break | ||
185 | |||
186 | return eligible | ||
187 | |||
188 | def getRuntimeProviders(dataCache, rdepend): | ||
189 | """ | ||
190 | Return any providers of runtime dependency | ||
191 | """ | ||
192 | rproviders = [] | ||
193 | |||
194 | if rdepend in dataCache.rproviders: | ||
195 | rproviders += dataCache.rproviders[rdepend] | ||
196 | |||
197 | if rdepend in dataCache.packages: | ||
198 | rproviders += dataCache.packages[rdepend] | ||
199 | |||
200 | if rproviders: | ||
201 | return rproviders | ||
202 | |||
203 | # Only search dynamic packages if we can't find anything in other variables | ||
204 | for pattern in dataCache.packages_dynamic: | ||
205 | regexp = re.compile(pattern) | ||
206 | if regexp.match(rdepend): | ||
207 | rproviders += dataCache.packages_dynamic[pattern] | ||
208 | |||
209 | return rproviders | ||