diff options
Diffstat (limited to 'bitbake-dev/lib/bb/providers.py')
| -rw-r--r-- | bitbake-dev/lib/bb/providers.py | 327 |
1 files changed, 0 insertions, 327 deletions
diff --git a/bitbake-dev/lib/bb/providers.py b/bitbake-dev/lib/bb/providers.py deleted file mode 100644 index 8617251ca3..0000000000 --- a/bitbake-dev/lib/bb/providers.py +++ /dev/null | |||
| @@ -1,327 +0,0 @@ | |||
| 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 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 | def preferredVersionMatch(pe, pv, pr, preferred_e, preferred_v, preferred_r): | ||
| 67 | """ | ||
| 68 | Check if the version pe,pv,pr is the preferred one. | ||
| 69 | If there is preferred version defined and ends with '%', then pv has to start with that version after removing the '%' | ||
| 70 | """ | ||
| 71 | if (pr == preferred_r or preferred_r == None): | ||
| 72 | if (pe == preferred_e or preferred_e == None): | ||
| 73 | if preferred_v == pv: | ||
| 74 | return True | ||
| 75 | if preferred_v != None and preferred_v.endswith('%') and pv.startswith(preferred_v[:len(preferred_v)-1]): | ||
| 76 | return True | ||
| 77 | return False | ||
| 78 | |||
| 79 | def findPreferredProvider(pn, cfgData, dataCache, pkg_pn = None, item = None): | ||
| 80 | """ | ||
| 81 | Find the first provider in pkg_pn with a PREFERRED_VERSION set. | ||
| 82 | """ | ||
| 83 | |||
| 84 | preferred_file = None | ||
| 85 | preferred_ver = None | ||
| 86 | |||
| 87 | localdata = data.createCopy(cfgData) | ||
| 88 | bb.data.setVar('OVERRIDES', "pn-%s:%s:%s" % (pn, pn, data.getVar('OVERRIDES', localdata)), localdata) | ||
| 89 | bb.data.update_data(localdata) | ||
| 90 | |||
| 91 | preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True) | ||
| 92 | if preferred_v: | ||
| 93 | m = re.match('(\d+:)*(.*)(_.*)*', preferred_v) | ||
| 94 | if m: | ||
| 95 | if m.group(1): | ||
| 96 | preferred_e = int(m.group(1)[:-1]) | ||
| 97 | else: | ||
| 98 | preferred_e = None | ||
| 99 | preferred_v = m.group(2) | ||
| 100 | if m.group(3): | ||
| 101 | preferred_r = m.group(3)[1:] | ||
| 102 | else: | ||
| 103 | preferred_r = None | ||
| 104 | else: | ||
| 105 | preferred_e = None | ||
| 106 | preferred_r = None | ||
| 107 | |||
| 108 | for file_set in pkg_pn: | ||
| 109 | for f in file_set: | ||
| 110 | pe,pv,pr = dataCache.pkg_pepvpr[f] | ||
| 111 | if preferredVersionMatch(pe, pv, pr, preferred_e, preferred_v, preferred_r): | ||
| 112 | preferred_file = f | ||
| 113 | preferred_ver = (pe, pv, pr) | ||
| 114 | break | ||
| 115 | if preferred_file: | ||
| 116 | break; | ||
| 117 | if preferred_r: | ||
| 118 | pv_str = '%s-%s' % (preferred_v, preferred_r) | ||
| 119 | else: | ||
| 120 | pv_str = preferred_v | ||
| 121 | if not (preferred_e is None): | ||
| 122 | pv_str = '%s:%s' % (preferred_e, pv_str) | ||
| 123 | itemstr = "" | ||
| 124 | if item: | ||
| 125 | itemstr = " (for item %s)" % item | ||
| 126 | if preferred_file is None: | ||
| 127 | bb.msg.note(1, bb.msg.domain.Provider, "preferred version %s of %s not available%s" % (pv_str, pn, itemstr)) | ||
| 128 | else: | ||
| 129 | bb.msg.debug(1, bb.msg.domain.Provider, "selecting %s as PREFERRED_VERSION %s of package %s%s" % (preferred_file, pv_str, pn, itemstr)) | ||
| 130 | |||
| 131 | return (preferred_ver, preferred_file) | ||
| 132 | |||
| 133 | |||
| 134 | def findLatestProvider(pn, cfgData, dataCache, file_set): | ||
| 135 | """ | ||
| 136 | Return the highest version of the providers in file_set. | ||
| 137 | Take default preferences into account. | ||
| 138 | """ | ||
| 139 | latest = None | ||
| 140 | latest_p = 0 | ||
| 141 | latest_f = None | ||
| 142 | for file_name in file_set: | ||
| 143 | pe,pv,pr = dataCache.pkg_pepvpr[file_name] | ||
| 144 | dp = dataCache.pkg_dp[file_name] | ||
| 145 | |||
| 146 | if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pe, pv, pr)) < 0)) or (dp > latest_p): | ||
| 147 | latest = (pe, pv, pr) | ||
| 148 | latest_f = file_name | ||
| 149 | latest_p = dp | ||
| 150 | |||
| 151 | return (latest, latest_f) | ||
| 152 | |||
| 153 | |||
| 154 | def findBestProvider(pn, cfgData, dataCache, pkg_pn = None, item = None): | ||
| 155 | """ | ||
| 156 | If there is a PREFERRED_VERSION, find the highest-priority bbfile | ||
| 157 | providing that version. If not, find the latest version provided by | ||
| 158 | an bbfile in the highest-priority set. | ||
| 159 | """ | ||
| 160 | |||
| 161 | sortpkg_pn = sortPriorities(pn, dataCache, pkg_pn) | ||
| 162 | # Find the highest priority provider with a PREFERRED_VERSION set | ||
| 163 | (preferred_ver, preferred_file) = findPreferredProvider(pn, cfgData, dataCache, sortpkg_pn, item) | ||
| 164 | # Find the latest version of the highest priority provider | ||
| 165 | (latest, latest_f) = findLatestProvider(pn, cfgData, dataCache, sortpkg_pn[0]) | ||
| 166 | |||
| 167 | if preferred_file is None: | ||
| 168 | preferred_file = latest_f | ||
| 169 | preferred_ver = latest | ||
| 170 | |||
| 171 | return (latest, latest_f, preferred_ver, preferred_file) | ||
| 172 | |||
| 173 | |||
| 174 | def _filterProviders(providers, item, cfgData, dataCache): | ||
| 175 | """ | ||
| 176 | Take a list of providers and filter/reorder according to the | ||
| 177 | environment variables and previous build results | ||
| 178 | """ | ||
| 179 | eligible = [] | ||
| 180 | preferred_versions = {} | ||
| 181 | sortpkg_pn = {} | ||
| 182 | |||
| 183 | # The order of providers depends on the order of the files on the disk | ||
| 184 | # up to here. Sort pkg_pn to make dependency issues reproducible rather | ||
| 185 | # than effectively random. | ||
| 186 | providers.sort() | ||
| 187 | |||
| 188 | # Collate providers by PN | ||
| 189 | pkg_pn = {} | ||
| 190 | for p in providers: | ||
| 191 | pn = dataCache.pkg_fn[p] | ||
| 192 | if pn not in pkg_pn: | ||
| 193 | pkg_pn[pn] = [] | ||
| 194 | pkg_pn[pn].append(p) | ||
| 195 | |||
| 196 | bb.msg.debug(1, bb.msg.domain.Provider, "providers for %s are: %s" % (item, pkg_pn.keys())) | ||
| 197 | |||
| 198 | # First add PREFERRED_VERSIONS | ||
| 199 | for pn in pkg_pn.keys(): | ||
| 200 | sortpkg_pn[pn] = sortPriorities(pn, dataCache, pkg_pn) | ||
| 201 | preferred_versions[pn] = findPreferredProvider(pn, cfgData, dataCache, sortpkg_pn[pn], item) | ||
| 202 | if preferred_versions[pn][1]: | ||
| 203 | eligible.append(preferred_versions[pn][1]) | ||
| 204 | |||
| 205 | # Now add latest verisons | ||
| 206 | for pn in sortpkg_pn.keys(): | ||
| 207 | if pn in preferred_versions and preferred_versions[pn][1]: | ||
| 208 | continue | ||
| 209 | preferred_versions[pn] = findLatestProvider(pn, cfgData, dataCache, sortpkg_pn[pn][0]) | ||
| 210 | eligible.append(preferred_versions[pn][1]) | ||
| 211 | |||
| 212 | if len(eligible) == 0: | ||
| 213 | bb.msg.error(bb.msg.domain.Provider, "no eligible providers for %s" % item) | ||
| 214 | return 0 | ||
| 215 | |||
| 216 | # If pn == item, give it a slight default preference | ||
| 217 | # This means PREFERRED_PROVIDER_foobar defaults to foobar if available | ||
| 218 | for p in providers: | ||
| 219 | pn = dataCache.pkg_fn[p] | ||
| 220 | if pn != item: | ||
| 221 | continue | ||
| 222 | (newvers, fn) = preferred_versions[pn] | ||
| 223 | if not fn in eligible: | ||
| 224 | continue | ||
| 225 | eligible.remove(fn) | ||
| 226 | eligible = [fn] + eligible | ||
| 227 | |||
| 228 | return eligible | ||
| 229 | |||
| 230 | |||
| 231 | def filterProviders(providers, item, cfgData, dataCache): | ||
| 232 | """ | ||
| 233 | Take a list of providers and filter/reorder according to the | ||
| 234 | environment variables and previous build results | ||
| 235 | Takes a "normal" target item | ||
| 236 | """ | ||
| 237 | |||
| 238 | eligible = _filterProviders(providers, item, cfgData, dataCache) | ||
| 239 | |||
| 240 | prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, cfgData, 1) | ||
| 241 | if prefervar: | ||
| 242 | dataCache.preferred[item] = prefervar | ||
| 243 | |||
| 244 | foundUnique = False | ||
| 245 | if item in dataCache.preferred: | ||
| 246 | for p in eligible: | ||
| 247 | pn = dataCache.pkg_fn[p] | ||
| 248 | if dataCache.preferred[item] == pn: | ||
| 249 | bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item)) | ||
| 250 | eligible.remove(p) | ||
| 251 | eligible = [p] + eligible | ||
| 252 | foundUnique = True | ||
| 253 | break | ||
| 254 | |||
| 255 | bb.msg.debug(1, bb.msg.domain.Provider, "sorted providers for %s are: %s" % (item, eligible)) | ||
| 256 | |||
| 257 | return eligible, foundUnique | ||
| 258 | |||
| 259 | def filterProvidersRunTime(providers, item, cfgData, dataCache): | ||
| 260 | """ | ||
| 261 | Take a list of providers and filter/reorder according to the | ||
| 262 | environment variables and previous build results | ||
| 263 | Takes a "runtime" target item | ||
| 264 | """ | ||
| 265 | |||
| 266 | eligible = _filterProviders(providers, item, cfgData, dataCache) | ||
| 267 | |||
| 268 | # Should use dataCache.preferred here? | ||
| 269 | preferred = [] | ||
| 270 | preferred_vars = [] | ||
| 271 | for p in eligible: | ||
| 272 | pn = dataCache.pkg_fn[p] | ||
| 273 | provides = dataCache.pn_provides[pn] | ||
| 274 | for provide in provides: | ||
| 275 | bb.msg.note(2, bb.msg.domain.Provider, "checking PREFERRED_PROVIDER_%s" % (provide)) | ||
| 276 | prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, cfgData, 1) | ||
| 277 | if prefervar == pn: | ||
| 278 | var = "PREFERRED_PROVIDER_%s = %s" % (provide, prefervar) | ||
| 279 | bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy runtime %s due to %s" % (pn, item, var)) | ||
| 280 | preferred_vars.append(var) | ||
| 281 | eligible.remove(p) | ||
| 282 | eligible = [p] + eligible | ||
| 283 | preferred.append(p) | ||
| 284 | break | ||
| 285 | |||
| 286 | numberPreferred = len(preferred) | ||
| 287 | |||
| 288 | if numberPreferred > 1: | ||
| 289 | 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)) | ||
| 290 | |||
| 291 | bb.msg.debug(1, bb.msg.domain.Provider, "sorted providers for %s are: %s" % (item, eligible)) | ||
| 292 | |||
| 293 | return eligible, numberPreferred | ||
| 294 | |||
| 295 | regexp_cache = {} | ||
| 296 | |||
| 297 | def getRuntimeProviders(dataCache, rdepend): | ||
| 298 | """ | ||
| 299 | Return any providers of runtime dependency | ||
| 300 | """ | ||
| 301 | rproviders = [] | ||
| 302 | |||
| 303 | if rdepend in dataCache.rproviders: | ||
| 304 | rproviders += dataCache.rproviders[rdepend] | ||
| 305 | |||
| 306 | if rdepend in dataCache.packages: | ||
| 307 | rproviders += dataCache.packages[rdepend] | ||
| 308 | |||
| 309 | if rproviders: | ||
| 310 | return rproviders | ||
| 311 | |||
| 312 | # Only search dynamic packages if we can't find anything in other variables | ||
| 313 | for pattern in dataCache.packages_dynamic: | ||
| 314 | pattern = pattern.replace('+', "\+") | ||
| 315 | if pattern in regexp_cache: | ||
| 316 | regexp = regexp_cache[pattern] | ||
| 317 | else: | ||
| 318 | try: | ||
| 319 | regexp = re.compile(pattern) | ||
| 320 | except: | ||
| 321 | bb.msg.error(bb.msg.domain.Provider, "Error parsing re expression: %s" % pattern) | ||
| 322 | raise | ||
| 323 | regexp_cache[pattern] = regexp | ||
| 324 | if regexp.match(rdepend): | ||
| 325 | rproviders += dataCache.packages_dynamic[pattern] | ||
| 326 | |||
| 327 | return rproviders | ||
