1 # ex:ts=4:sw=4:sts=4:et
2 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
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
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.
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.
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.
25 from bb import data, utils
28 class NoProvider(Exception):
29 """Exception raised when no provider of a build dependency can be found"""
31 class NoRProvider(Exception):
32 """Exception raised when no provider of a runtime dependency can be found"""
35 def sortPriorities(pn, dataCache, pkg_pn = None):
37 Reorder pkg_pn by file priority and default preference
41 pkg_pn = dataCache.pkg_pn
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)
57 pref_list = priorities[pri].keys()
58 pref_list.sort(lambda a, b: b - a)
60 for pref in pref_list:
61 tmp_pref.extend(priorities[pri][pref])
62 tmp_pn = [tmp_pref] + tmp_pn
67 def findPreferredProvider(pn, cfgData, dataCache, pkg_pn = None, item = None):
69 Find the first provider in pkg_pn with a PREFERRED_VERSION set.
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)
79 preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True)
81 m = re.match('(\d+:)*(.*)(_.*)*', preferred_v)
84 preferred_e = int(m.group(1)[:-1])
87 preferred_v = m.group(2)
89 preferred_r = m.group(3)[1:]
96 for file_set in pkg_pn:
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):
101 preferred_ver = (pe, pv, pr)
106 pv_str = '%s-%s' % (preferred_v, preferred_r)
109 if not (preferred_e is None):
110 pv_str = '%s:%s' % (preferred_e, pv_str)
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))
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))
119 return (preferred_ver, preferred_file)
122 def findLatestProvider(pn, cfgData, dataCache, file_set):
124 Return the highest version of the providers in file_set.
125 Take default preferences into account.
130 for file_name in file_set:
131 pe,pv,pr = dataCache.pkg_pepvpr[file_name]
132 dp = dataCache.pkg_dp[file_name]
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)
139 return (latest, latest_f)
142 def findBestProvider(pn, cfgData, dataCache, pkg_pn = None, item = None):
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.
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])
155 if preferred_file is None:
156 preferred_file = latest_f
157 preferred_ver = latest
159 return (latest, latest_f, preferred_ver, preferred_file)
162 def _filterProviders(providers, item, cfgData, dataCache):
164 Take a list of providers and filter/reorder according to the
165 environment variables and previous build results
168 preferred_versions = {}
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.
176 # Collate providers by PN
179 pn = dataCache.pkg_fn[p]
184 bb.msg.debug(1, bb.msg.domain.Provider, "providers for %s are: %s" % (item, pkg_pn.keys()))
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])
193 # Now add latest verisons
194 for pn in pkg_pn.keys():
195 if pn in preferred_versions and preferred_versions[pn][1]:
197 preferred_versions[pn] = findLatestProvider(pn, cfgData, dataCache, sortpkg_pn[pn][0])
198 eligible.append(preferred_versions[pn][1])
200 if len(eligible) == 0:
201 bb.msg.error(bb.msg.domain.Provider, "no eligible providers for %s" % item)
204 # If pn == item, give it a slight default preference
205 # This means PREFERRED_PROVIDER_foobar defaults to foobar if available
207 pn = dataCache.pkg_fn[p]
210 (newvers, fn) = preferred_versions[pn]
211 if not fn in eligible:
214 eligible = [fn] + eligible
219 def filterProviders(providers, item, cfgData, dataCache):
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
226 eligible = _filterProviders(providers, item, cfgData, dataCache)
228 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, cfgData, 1)
230 dataCache.preferred[item] = prefervar
233 if item in dataCache.preferred:
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))
239 eligible = [p] + eligible
243 bb.msg.debug(1, bb.msg.domain.Provider, "sorted providers for %s are: %s" % (item, eligible))
245 return eligible, foundUnique
247 def filterProvidersRunTime(providers, item, cfgData, dataCache):
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
254 eligible = _filterProviders(providers, item, cfgData, dataCache)
256 # Should use dataCache.preferred here?
260 pn = dataCache.pkg_fn[p]
261 provides = dataCache.pn_provides[pn]
262 for provide in provides:
263 bb.msg.note(2, bb.msg.domain.Provider, "checking PREFERRED_PROVIDER_%s" % (provide))
264 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, cfgData, 1)
266 var = "PREFERRED_PROVIDER_%s = %s" % (provide, prefervar)
267 bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy runtime %s due to %s" % (pn, item, var))
268 preferred_vars.append(var)
270 eligible = [p] + eligible
274 numberPreferred = len(preferred)
276 if numberPreferred > 1:
277 bb.msg.error(bb.msg.domain.Provider, "Conflicting PREFERRED_PROVIDER 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))
279 bb.msg.debug(1, bb.msg.domain.Provider, "sorted providers for %s are: %s" % (item, eligible))
281 return eligible, numberPreferred
283 def getRuntimeProviders(dataCache, rdepend):
285 Return any providers of runtime dependency
289 if rdepend in dataCache.rproviders:
290 rproviders += dataCache.rproviders[rdepend]
292 if rdepend in dataCache.packages:
293 rproviders += dataCache.packages[rdepend]
298 # Only search dynamic packages if we can't find anything in other variables
299 for pattern in dataCache.packages_dynamic:
301 regexp = re.compile(pattern.replace('+', "\+"))
303 bb.msg.error(bb.msg.domain.Provider, "Error parsing re expression: %s" % pattern)
305 if regexp.match(rdepend):
306 rproviders += dataCache.packages_dynamic[pattern]