xref: /OK3568_Linux_fs/yocto/poky/bitbake/lib/bb/providers.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#
2*4882a593Smuzhiyun# Copyright (C) 2003, 2004  Chris Larson
3*4882a593Smuzhiyun# Copyright (C) 2003, 2004  Phil Blundell
4*4882a593Smuzhiyun# Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
5*4882a593Smuzhiyun# Copyright (C) 2005        Holger Hans Peter Freyther
6*4882a593Smuzhiyun# Copyright (C) 2005        ROAD GmbH
7*4882a593Smuzhiyun# Copyright (C) 2006        Richard Purdie
8*4882a593Smuzhiyun#
9*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only
10*4882a593Smuzhiyun#
11*4882a593Smuzhiyun
12*4882a593Smuzhiyunimport re
13*4882a593Smuzhiyunimport logging
14*4882a593Smuzhiyunfrom bb import data, utils
15*4882a593Smuzhiyunfrom collections import defaultdict
16*4882a593Smuzhiyunimport bb
17*4882a593Smuzhiyun
18*4882a593Smuzhiyunlogger = logging.getLogger("BitBake.Provider")
19*4882a593Smuzhiyun
20*4882a593Smuzhiyunclass NoProvider(bb.BBHandledException):
21*4882a593Smuzhiyun    """Exception raised when no provider of a build dependency can be found"""
22*4882a593Smuzhiyun
23*4882a593Smuzhiyunclass NoRProvider(bb.BBHandledException):
24*4882a593Smuzhiyun    """Exception raised when no provider of a runtime dependency can be found"""
25*4882a593Smuzhiyun
26*4882a593Smuzhiyunclass MultipleRProvider(bb.BBHandledException):
27*4882a593Smuzhiyun    """Exception raised when multiple providers of a runtime dependency can be found"""
28*4882a593Smuzhiyun
29*4882a593Smuzhiyundef findProviders(cfgData, dataCache, pkg_pn = None):
30*4882a593Smuzhiyun    """
31*4882a593Smuzhiyun    Convenience function to get latest and preferred providers in pkg_pn
32*4882a593Smuzhiyun    """
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun    if not pkg_pn:
35*4882a593Smuzhiyun        pkg_pn = dataCache.pkg_pn
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun    # Need to ensure data store is expanded
38*4882a593Smuzhiyun    localdata = data.createCopy(cfgData)
39*4882a593Smuzhiyun    bb.data.expandKeys(localdata)
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun    required = {}
42*4882a593Smuzhiyun    preferred_versions = {}
43*4882a593Smuzhiyun    latest_versions = {}
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun    for pn in pkg_pn:
46*4882a593Smuzhiyun        (last_ver, last_file, pref_ver, pref_file, req) = findBestProvider(pn, localdata, dataCache, pkg_pn)
47*4882a593Smuzhiyun        preferred_versions[pn] = (pref_ver, pref_file)
48*4882a593Smuzhiyun        latest_versions[pn] = (last_ver, last_file)
49*4882a593Smuzhiyun        required[pn] = req
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun    return (latest_versions, preferred_versions, required)
52*4882a593Smuzhiyun
53*4882a593Smuzhiyundef allProviders(dataCache):
54*4882a593Smuzhiyun    """
55*4882a593Smuzhiyun    Find all providers for each pn
56*4882a593Smuzhiyun    """
57*4882a593Smuzhiyun    all_providers = defaultdict(list)
58*4882a593Smuzhiyun    for (fn, pn) in dataCache.pkg_fn.items():
59*4882a593Smuzhiyun        ver = dataCache.pkg_pepvpr[fn]
60*4882a593Smuzhiyun        all_providers[pn].append((ver, fn))
61*4882a593Smuzhiyun    return all_providers
62*4882a593Smuzhiyun
63*4882a593Smuzhiyundef sortPriorities(pn, dataCache, pkg_pn = None):
64*4882a593Smuzhiyun    """
65*4882a593Smuzhiyun    Reorder pkg_pn by file priority and default preference
66*4882a593Smuzhiyun    """
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun    if not pkg_pn:
69*4882a593Smuzhiyun        pkg_pn = dataCache.pkg_pn
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun    files = pkg_pn[pn]
72*4882a593Smuzhiyun    priorities = {}
73*4882a593Smuzhiyun    for f in files:
74*4882a593Smuzhiyun        priority = dataCache.bbfile_priority[f]
75*4882a593Smuzhiyun        preference = dataCache.pkg_dp[f]
76*4882a593Smuzhiyun        if priority not in priorities:
77*4882a593Smuzhiyun            priorities[priority] = {}
78*4882a593Smuzhiyun        if preference not in priorities[priority]:
79*4882a593Smuzhiyun            priorities[priority][preference] = []
80*4882a593Smuzhiyun        priorities[priority][preference].append(f)
81*4882a593Smuzhiyun    tmp_pn = []
82*4882a593Smuzhiyun    for pri in sorted(priorities):
83*4882a593Smuzhiyun        tmp_pref = []
84*4882a593Smuzhiyun        for pref in sorted(priorities[pri]):
85*4882a593Smuzhiyun            tmp_pref.extend(priorities[pri][pref])
86*4882a593Smuzhiyun        tmp_pn = [tmp_pref] + tmp_pn
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun    return tmp_pn
89*4882a593Smuzhiyun
90*4882a593Smuzhiyundef versionVariableMatch(cfgData, keyword, pn):
91*4882a593Smuzhiyun    """
92*4882a593Smuzhiyun    Return the value of the <keyword>_VERSION variable if set.
93*4882a593Smuzhiyun    """
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun    # pn can contain '_', e.g. gcc-cross-x86_64 and an override cannot
96*4882a593Smuzhiyun    # hence we do this manually rather than use OVERRIDES
97*4882a593Smuzhiyun    ver = cfgData.getVar("%s_VERSION:pn-%s" % (keyword, pn))
98*4882a593Smuzhiyun    if not ver:
99*4882a593Smuzhiyun        ver = cfgData.getVar("%s_VERSION_%s" % (keyword, pn))
100*4882a593Smuzhiyun    if not ver:
101*4882a593Smuzhiyun        ver = cfgData.getVar("%s_VERSION" % keyword)
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun    return ver
104*4882a593Smuzhiyun
105*4882a593Smuzhiyundef preferredVersionMatch(pe, pv, pr, preferred_e, preferred_v, preferred_r):
106*4882a593Smuzhiyun    """
107*4882a593Smuzhiyun    Check if the version pe,pv,pr is the preferred one.
108*4882a593Smuzhiyun    If there is preferred version defined and ends with '%', then pv has to start with that version after removing the '%'
109*4882a593Smuzhiyun    """
110*4882a593Smuzhiyun    if pr == preferred_r or preferred_r is None:
111*4882a593Smuzhiyun        if pe == preferred_e or preferred_e is None:
112*4882a593Smuzhiyun            if preferred_v == pv:
113*4882a593Smuzhiyun                return True
114*4882a593Smuzhiyun            if preferred_v is not None and preferred_v.endswith('%') and pv.startswith(preferred_v[:len(preferred_v)-1]):
115*4882a593Smuzhiyun                return True
116*4882a593Smuzhiyun    return False
117*4882a593Smuzhiyun
118*4882a593Smuzhiyundef findPreferredProvider(pn, cfgData, dataCache, pkg_pn = None, item = None):
119*4882a593Smuzhiyun    """
120*4882a593Smuzhiyun    Find the first provider in pkg_pn with REQUIRED_VERSION or PREFERRED_VERSION set.
121*4882a593Smuzhiyun    """
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun    preferred_file = None
124*4882a593Smuzhiyun    preferred_ver = None
125*4882a593Smuzhiyun    required = False
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun    required_v = versionVariableMatch(cfgData, "REQUIRED", pn)
128*4882a593Smuzhiyun    preferred_v = versionVariableMatch(cfgData, "PREFERRED", pn)
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun    itemstr = ""
131*4882a593Smuzhiyun    if item:
132*4882a593Smuzhiyun        itemstr = " (for item %s)" % item
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun    if required_v is not None:
135*4882a593Smuzhiyun        if preferred_v is not None:
136*4882a593Smuzhiyun            logger.warning("REQUIRED_VERSION and PREFERRED_VERSION for package %s%s are both set using REQUIRED_VERSION %s", pn, itemstr, required_v)
137*4882a593Smuzhiyun        else:
138*4882a593Smuzhiyun            logger.debug("REQUIRED_VERSION is set for package %s%s", pn, itemstr)
139*4882a593Smuzhiyun        # REQUIRED_VERSION always takes precedence over PREFERRED_VERSION
140*4882a593Smuzhiyun        preferred_v = required_v
141*4882a593Smuzhiyun        required = True
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun    if preferred_v:
144*4882a593Smuzhiyun        m = re.match(r'(\d+:)*(.*)(_.*)*', preferred_v)
145*4882a593Smuzhiyun        if m:
146*4882a593Smuzhiyun            if m.group(1):
147*4882a593Smuzhiyun                preferred_e = m.group(1)[:-1]
148*4882a593Smuzhiyun            else:
149*4882a593Smuzhiyun                preferred_e = None
150*4882a593Smuzhiyun            preferred_v = m.group(2)
151*4882a593Smuzhiyun            if m.group(3):
152*4882a593Smuzhiyun                preferred_r = m.group(3)[1:]
153*4882a593Smuzhiyun            else:
154*4882a593Smuzhiyun                preferred_r = None
155*4882a593Smuzhiyun        else:
156*4882a593Smuzhiyun            preferred_e = None
157*4882a593Smuzhiyun            preferred_r = None
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun        for file_set in pkg_pn:
160*4882a593Smuzhiyun            for f in file_set:
161*4882a593Smuzhiyun                pe, pv, pr = dataCache.pkg_pepvpr[f]
162*4882a593Smuzhiyun                if preferredVersionMatch(pe, pv, pr, preferred_e, preferred_v, preferred_r):
163*4882a593Smuzhiyun                    preferred_file = f
164*4882a593Smuzhiyun                    preferred_ver = (pe, pv, pr)
165*4882a593Smuzhiyun                    break
166*4882a593Smuzhiyun            if preferred_file:
167*4882a593Smuzhiyun                break;
168*4882a593Smuzhiyun        if preferred_r:
169*4882a593Smuzhiyun            pv_str = '%s-%s' % (preferred_v, preferred_r)
170*4882a593Smuzhiyun        else:
171*4882a593Smuzhiyun            pv_str = preferred_v
172*4882a593Smuzhiyun        if not (preferred_e is None):
173*4882a593Smuzhiyun            pv_str = '%s:%s' % (preferred_e, pv_str)
174*4882a593Smuzhiyun        if preferred_file is None:
175*4882a593Smuzhiyun            if not required:
176*4882a593Smuzhiyun                logger.warning("preferred version %s of %s not available%s", pv_str, pn, itemstr)
177*4882a593Smuzhiyun            available_vers = []
178*4882a593Smuzhiyun            for file_set in pkg_pn:
179*4882a593Smuzhiyun                for f in file_set:
180*4882a593Smuzhiyun                    pe, pv, pr = dataCache.pkg_pepvpr[f]
181*4882a593Smuzhiyun                    ver_str = pv
182*4882a593Smuzhiyun                    if pe:
183*4882a593Smuzhiyun                        ver_str = "%s:%s" % (pe, ver_str)
184*4882a593Smuzhiyun                    if not ver_str in available_vers:
185*4882a593Smuzhiyun                        available_vers.append(ver_str)
186*4882a593Smuzhiyun            if available_vers:
187*4882a593Smuzhiyun                available_vers.sort()
188*4882a593Smuzhiyun                logger.warning("versions of %s available: %s", pn, ' '.join(available_vers))
189*4882a593Smuzhiyun            if required:
190*4882a593Smuzhiyun                logger.error("required version %s of %s not available%s", pv_str, pn, itemstr)
191*4882a593Smuzhiyun        else:
192*4882a593Smuzhiyun            if required:
193*4882a593Smuzhiyun                logger.debug("selecting %s as REQUIRED_VERSION %s of package %s%s", preferred_file, pv_str, pn, itemstr)
194*4882a593Smuzhiyun            else:
195*4882a593Smuzhiyun                logger.debug("selecting %s as PREFERRED_VERSION %s of package %s%s", preferred_file, pv_str, pn, itemstr)
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun    return (preferred_ver, preferred_file, required)
198*4882a593Smuzhiyun
199*4882a593Smuzhiyundef findLatestProvider(pn, cfgData, dataCache, file_set):
200*4882a593Smuzhiyun    """
201*4882a593Smuzhiyun    Return the highest version of the providers in file_set.
202*4882a593Smuzhiyun    Take default preferences into account.
203*4882a593Smuzhiyun    """
204*4882a593Smuzhiyun    latest = None
205*4882a593Smuzhiyun    latest_p = 0
206*4882a593Smuzhiyun    latest_f = None
207*4882a593Smuzhiyun    for file_name in file_set:
208*4882a593Smuzhiyun        pe, pv, pr = dataCache.pkg_pepvpr[file_name]
209*4882a593Smuzhiyun        dp = dataCache.pkg_dp[file_name]
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun        if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pe, pv, pr)) < 0)) or (dp > latest_p):
212*4882a593Smuzhiyun            latest = (pe, pv, pr)
213*4882a593Smuzhiyun            latest_f = file_name
214*4882a593Smuzhiyun            latest_p = dp
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun    return (latest, latest_f)
217*4882a593Smuzhiyun
218*4882a593Smuzhiyundef findBestProvider(pn, cfgData, dataCache, pkg_pn = None, item = None):
219*4882a593Smuzhiyun    """
220*4882a593Smuzhiyun    If there is a PREFERRED_VERSION, find the highest-priority bbfile
221*4882a593Smuzhiyun    providing that version.  If not, find the latest version provided by
222*4882a593Smuzhiyun    an bbfile in the highest-priority set.
223*4882a593Smuzhiyun    """
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun    sortpkg_pn = sortPriorities(pn, dataCache, pkg_pn)
226*4882a593Smuzhiyun    # Find the highest priority provider with a REQUIRED_VERSION or PREFERRED_VERSION set
227*4882a593Smuzhiyun    (preferred_ver, preferred_file, required) = findPreferredProvider(pn, cfgData, dataCache, sortpkg_pn, item)
228*4882a593Smuzhiyun    # Find the latest version of the highest priority provider
229*4882a593Smuzhiyun    (latest, latest_f) = findLatestProvider(pn, cfgData, dataCache, sortpkg_pn[0])
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun    if not required and preferred_file is None:
232*4882a593Smuzhiyun        preferred_file = latest_f
233*4882a593Smuzhiyun        preferred_ver = latest
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun    return (latest, latest_f, preferred_ver, preferred_file, required)
236*4882a593Smuzhiyun
237*4882a593Smuzhiyundef _filterProviders(providers, item, cfgData, dataCache):
238*4882a593Smuzhiyun    """
239*4882a593Smuzhiyun    Take a list of providers and filter/reorder according to the
240*4882a593Smuzhiyun    environment variables
241*4882a593Smuzhiyun    """
242*4882a593Smuzhiyun    eligible = []
243*4882a593Smuzhiyun    preferred_versions = {}
244*4882a593Smuzhiyun    sortpkg_pn = {}
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun    # The order of providers depends on the order of the files on the disk
247*4882a593Smuzhiyun    # up to here. Sort pkg_pn to make dependency issues reproducible rather
248*4882a593Smuzhiyun    # than effectively random.
249*4882a593Smuzhiyun    providers.sort()
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun    # Collate providers by PN
252*4882a593Smuzhiyun    pkg_pn = {}
253*4882a593Smuzhiyun    for p in providers:
254*4882a593Smuzhiyun        pn = dataCache.pkg_fn[p]
255*4882a593Smuzhiyun        if pn not in pkg_pn:
256*4882a593Smuzhiyun            pkg_pn[pn] = []
257*4882a593Smuzhiyun        pkg_pn[pn].append(p)
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun    logger.debug("providers for %s are: %s", item, list(sorted(pkg_pn.keys())))
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun    # First add REQUIRED_VERSIONS or PREFERRED_VERSIONS
262*4882a593Smuzhiyun    for pn in sorted(pkg_pn):
263*4882a593Smuzhiyun        sortpkg_pn[pn] = sortPriorities(pn, dataCache, pkg_pn)
264*4882a593Smuzhiyun        preferred_ver, preferred_file, required = findPreferredProvider(pn, cfgData, dataCache, sortpkg_pn[pn], item)
265*4882a593Smuzhiyun        if required and preferred_file is None:
266*4882a593Smuzhiyun            return eligible
267*4882a593Smuzhiyun        preferred_versions[pn] = (preferred_ver, preferred_file)
268*4882a593Smuzhiyun        if preferred_versions[pn][1]:
269*4882a593Smuzhiyun            eligible.append(preferred_versions[pn][1])
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun    # Now add latest versions
272*4882a593Smuzhiyun    for pn in sorted(sortpkg_pn):
273*4882a593Smuzhiyun        if pn in preferred_versions and preferred_versions[pn][1]:
274*4882a593Smuzhiyun            continue
275*4882a593Smuzhiyun        preferred_versions[pn] = findLatestProvider(pn, cfgData, dataCache, sortpkg_pn[pn][0])
276*4882a593Smuzhiyun        eligible.append(preferred_versions[pn][1])
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun    if not eligible:
279*4882a593Smuzhiyun        return eligible
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun    # If pn == item, give it a slight default preference
282*4882a593Smuzhiyun    # This means PREFERRED_PROVIDER_foobar defaults to foobar if available
283*4882a593Smuzhiyun    for p in providers:
284*4882a593Smuzhiyun        pn = dataCache.pkg_fn[p]
285*4882a593Smuzhiyun        if pn != item:
286*4882a593Smuzhiyun            continue
287*4882a593Smuzhiyun        (newvers, fn) = preferred_versions[pn]
288*4882a593Smuzhiyun        if not fn in eligible:
289*4882a593Smuzhiyun            continue
290*4882a593Smuzhiyun        eligible.remove(fn)
291*4882a593Smuzhiyun        eligible = [fn] + eligible
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun    return eligible
294*4882a593Smuzhiyun
295*4882a593Smuzhiyundef filterProviders(providers, item, cfgData, dataCache):
296*4882a593Smuzhiyun    """
297*4882a593Smuzhiyun    Take a list of providers and filter/reorder according to the
298*4882a593Smuzhiyun    environment variables
299*4882a593Smuzhiyun    Takes a "normal" target item
300*4882a593Smuzhiyun    """
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun    eligible = _filterProviders(providers, item, cfgData, dataCache)
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun    prefervar = cfgData.getVar('PREFERRED_PROVIDER_%s' % item)
305*4882a593Smuzhiyun    if prefervar:
306*4882a593Smuzhiyun        dataCache.preferred[item] = prefervar
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun    foundUnique = False
309*4882a593Smuzhiyun    if item in dataCache.preferred:
310*4882a593Smuzhiyun        for p in eligible:
311*4882a593Smuzhiyun            pn = dataCache.pkg_fn[p]
312*4882a593Smuzhiyun            if dataCache.preferred[item] == pn:
313*4882a593Smuzhiyun                logger.verbose("selecting %s to satisfy %s due to PREFERRED_PROVIDERS", pn, item)
314*4882a593Smuzhiyun                eligible.remove(p)
315*4882a593Smuzhiyun                eligible = [p] + eligible
316*4882a593Smuzhiyun                foundUnique = True
317*4882a593Smuzhiyun                break
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun    logger.debug("sorted providers for %s are: %s", item, eligible)
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun    return eligible, foundUnique
322*4882a593Smuzhiyun
323*4882a593Smuzhiyundef filterProvidersRunTime(providers, item, cfgData, dataCache):
324*4882a593Smuzhiyun    """
325*4882a593Smuzhiyun    Take a list of providers and filter/reorder according to the
326*4882a593Smuzhiyun    environment variables
327*4882a593Smuzhiyun    Takes a "runtime" target item
328*4882a593Smuzhiyun    """
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun    eligible = _filterProviders(providers, item, cfgData, dataCache)
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun    # First try and match any PREFERRED_RPROVIDER entry
333*4882a593Smuzhiyun    prefervar = cfgData.getVar('PREFERRED_RPROVIDER_%s' % item)
334*4882a593Smuzhiyun    foundUnique = False
335*4882a593Smuzhiyun    if prefervar:
336*4882a593Smuzhiyun        for p in eligible:
337*4882a593Smuzhiyun            pn = dataCache.pkg_fn[p]
338*4882a593Smuzhiyun            if prefervar == pn:
339*4882a593Smuzhiyun                logger.verbose("selecting %s to satisfy %s due to PREFERRED_RPROVIDER", pn, item)
340*4882a593Smuzhiyun                eligible.remove(p)
341*4882a593Smuzhiyun                eligible = [p] + eligible
342*4882a593Smuzhiyun                foundUnique = True
343*4882a593Smuzhiyun                numberPreferred = 1
344*4882a593Smuzhiyun                break
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun    # If we didn't find an RPROVIDER entry, try and infer the provider from PREFERRED_PROVIDER entries
347*4882a593Smuzhiyun    # by looking through the provides of each eligible recipe and seeing if a PREFERRED_PROVIDER was set.
348*4882a593Smuzhiyun    # This is most useful for virtual/ entries rather than having a RPROVIDER per entry.
349*4882a593Smuzhiyun    if not foundUnique:
350*4882a593Smuzhiyun        # Should use dataCache.preferred here?
351*4882a593Smuzhiyun        preferred = []
352*4882a593Smuzhiyun        preferred_vars = []
353*4882a593Smuzhiyun        pns = {}
354*4882a593Smuzhiyun        for p in eligible:
355*4882a593Smuzhiyun            pns[dataCache.pkg_fn[p]] = p
356*4882a593Smuzhiyun        for p in eligible:
357*4882a593Smuzhiyun            pn = dataCache.pkg_fn[p]
358*4882a593Smuzhiyun            provides = dataCache.pn_provides[pn]
359*4882a593Smuzhiyun            for provide in provides:
360*4882a593Smuzhiyun                prefervar = cfgData.getVar('PREFERRED_PROVIDER_%s' % provide)
361*4882a593Smuzhiyun                #logger.debug("checking PREFERRED_PROVIDER_%s (value %s) against %s", provide, prefervar, pns.keys())
362*4882a593Smuzhiyun                if prefervar in pns and pns[prefervar] not in preferred:
363*4882a593Smuzhiyun                    var = "PREFERRED_PROVIDER_%s = %s" % (provide, prefervar)
364*4882a593Smuzhiyun                    logger.verbose("selecting %s to satisfy runtime %s due to %s", prefervar, item, var)
365*4882a593Smuzhiyun                    preferred_vars.append(var)
366*4882a593Smuzhiyun                    pref = pns[prefervar]
367*4882a593Smuzhiyun                    eligible.remove(pref)
368*4882a593Smuzhiyun                    eligible = [pref] + eligible
369*4882a593Smuzhiyun                    preferred.append(pref)
370*4882a593Smuzhiyun                    break
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun        numberPreferred = len(preferred)
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun    if numberPreferred > 1:
375*4882a593Smuzhiyun        logger.error("Trying to resolve runtime dependency %s resulted in conflicting PREFERRED_PROVIDER entries being found.\nThe providers found were: %s\nThe PREFERRED_PROVIDER entries resulting in this conflict were: %s. You could set PREFERRED_RPROVIDER_%s" % (item, preferred, preferred_vars, item))
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun    logger.debug("sorted runtime providers for %s are: %s", item, eligible)
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun    return eligible, numberPreferred
380*4882a593Smuzhiyun
381*4882a593Smuzhiyunregexp_cache = {}
382*4882a593Smuzhiyun
383*4882a593Smuzhiyundef getRuntimeProviders(dataCache, rdepend):
384*4882a593Smuzhiyun    """
385*4882a593Smuzhiyun    Return any providers of runtime dependency
386*4882a593Smuzhiyun    """
387*4882a593Smuzhiyun    rproviders = []
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun    if rdepend in dataCache.rproviders:
390*4882a593Smuzhiyun        rproviders += dataCache.rproviders[rdepend]
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun    if rdepend in dataCache.packages:
393*4882a593Smuzhiyun        rproviders += dataCache.packages[rdepend]
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun    if rproviders:
396*4882a593Smuzhiyun        return rproviders
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun    # Only search dynamic packages if we can't find anything in other variables
399*4882a593Smuzhiyun    for pat_key in dataCache.packages_dynamic:
400*4882a593Smuzhiyun        pattern = pat_key.replace(r'+', r"\+")
401*4882a593Smuzhiyun        if pattern in regexp_cache:
402*4882a593Smuzhiyun            regexp = regexp_cache[pattern]
403*4882a593Smuzhiyun        else:
404*4882a593Smuzhiyun            try:
405*4882a593Smuzhiyun                regexp = re.compile(pattern)
406*4882a593Smuzhiyun            except:
407*4882a593Smuzhiyun                logger.error("Error parsing regular expression '%s'", pattern)
408*4882a593Smuzhiyun                raise
409*4882a593Smuzhiyun            regexp_cache[pattern] = regexp
410*4882a593Smuzhiyun        if regexp.match(rdepend):
411*4882a593Smuzhiyun            rproviders += dataCache.packages_dynamic[pat_key]
412*4882a593Smuzhiyun            logger.debug("Assuming %s is a dynamic package, but it may not exist" % rdepend)
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun    return rproviders
415*4882a593Smuzhiyun
416*4882a593Smuzhiyundef buildWorldTargetList(dataCache, task=None):
417*4882a593Smuzhiyun    """
418*4882a593Smuzhiyun    Build package list for "bitbake world"
419*4882a593Smuzhiyun    """
420*4882a593Smuzhiyun    if dataCache.world_target:
421*4882a593Smuzhiyun        return
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun    logger.debug("collating packages for \"world\"")
424*4882a593Smuzhiyun    for f in dataCache.possible_world:
425*4882a593Smuzhiyun        terminal = True
426*4882a593Smuzhiyun        pn = dataCache.pkg_fn[f]
427*4882a593Smuzhiyun        if task and task not in dataCache.task_deps[f]['tasks']:
428*4882a593Smuzhiyun            logger.debug2("World build skipping %s as task %s doesn't exist", f, task)
429*4882a593Smuzhiyun            terminal = False
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun        for p in dataCache.pn_provides[pn]:
432*4882a593Smuzhiyun            if p.startswith('virtual/'):
433*4882a593Smuzhiyun                logger.debug2("World build skipping %s due to %s provider starting with virtual/", f, p)
434*4882a593Smuzhiyun                terminal = False
435*4882a593Smuzhiyun                break
436*4882a593Smuzhiyun            for pf in dataCache.providers[p]:
437*4882a593Smuzhiyun                if dataCache.pkg_fn[pf] != pn:
438*4882a593Smuzhiyun                    logger.debug2("World build skipping %s due to both us and %s providing %s", f, pf, p)
439*4882a593Smuzhiyun                    terminal = False
440*4882a593Smuzhiyun                    break
441*4882a593Smuzhiyun        if terminal:
442*4882a593Smuzhiyun            dataCache.world_target.add(pn)
443