bitbake/lib/bb/providers.py:
[bitbake.git] / lib / bb / providers.py
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):
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         if preferred_file is None:
86             bb.msg.note(1, bb.msg.domain.Provider, "preferred version %s of %s not available" % (pv_str, pn))
87         else:
88             bb.msg.debug(1, bb.msg.domain.Provider, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
89
90     del localdata
91
92     # get highest priority file set
93     files = tmp_pn[0]
94     latest = None
95     latest_p = 0
96     latest_f = None
97     for file_name in files:
98         pv,pr = dataCache.pkg_pvpr[file_name]
99         dp = dataCache.pkg_dp[file_name]
100
101         if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
102             latest = (pv, pr)
103             latest_f = file_name
104             latest_p = dp
105     if preferred_file is None:
106         preferred_file = latest_f
107         preferred_ver = latest
108
109     return (latest,latest_f,preferred_ver, preferred_file)
110
111 #
112 # RP - build_cache_fail needs to move elsewhere
113 #
114 def filterProviders(providers, item, cfgData, dataCache, build_cache_fail = {}):
115     """
116     Take a list of providers and filter/reorder according to the 
117     environment variables and previous build results
118     """
119     eligible = []
120     preferred_versions = {}
121
122     # Collate providers by PN
123     pkg_pn = {}
124     for p in providers:
125         pn = dataCache.pkg_fn[p]
126         if pn not in pkg_pn:
127             pkg_pn[pn] = []
128         pkg_pn[pn].append(p)
129
130     bb.msg.debug(1, bb.msg.domain.Provider, "providers for %s are: %s" % (item, pkg_pn.keys()))
131
132     for pn in pkg_pn.keys():
133         preferred_versions[pn] = bb.providers.findBestProvider(pn, cfgData, dataCache, pkg_pn)[2:4]
134         eligible.append(preferred_versions[pn][1])
135
136
137     for p in eligible:
138         if p in build_cache_fail:
139             bb.msg.debug(1, bb.msg.domain.Provider, "rejecting already-failed %s" % p)
140             eligible.remove(p)
141
142     if len(eligible) == 0:
143         bb.error("no eligible providers for %s" % item)
144         return 0
145
146     # look to see if one of them is already staged, or marked as preferred.
147     # if so, bump it to the head of the queue
148     for p in providers:
149         pn = dataCache.pkg_fn[p]
150         pv, pr = dataCache.pkg_pvpr[p]
151
152         stamp = '%s.do_populate_staging' % dataCache.stamp[p]
153         if os.path.exists(stamp):
154             (newvers, fn) = preferred_versions[pn]
155             if not fn in eligible:
156                 # package was made ineligible by already-failed check
157                 continue
158             oldver = "%s-%s" % (pv, pr)
159             newver = '-'.join(newvers)
160             if (newver != oldver):
161                 extra_chat = "%s (%s) already staged but upgrading to %s to satisfy %s" % (pn, oldver, newver, item)
162             else:
163                 extra_chat = "Selecting already-staged %s (%s) to satisfy %s" % (pn, oldver, item)
164
165             bb.msg.note(2, bb.msg.domain.Provider, "%s" % extra_chat)
166             eligible.remove(fn)
167             eligible = [fn] + eligible
168             discriminated = True
169             break
170
171     return eligible
172
173 def getRuntimeProviders(dataCache, rdepend):
174     """
175     Return any providers of runtime dependency
176     """
177     rproviders = []
178
179     if rdepend in dataCache.rproviders:
180        rproviders += dataCache.rproviders[rdepend]
181
182     if rdepend in dataCache.packages:
183         rproviders += dataCache.packages[rdepend]
184
185     if rproviders:
186         return rproviders
187
188     # Only search dynamic packages if we can't find anything in other variables
189     for pattern in dataCache.packages_dynamic:
190         regexp = re.compile(pattern)
191         if regexp.match(rdepend):
192             rproviders += dataCache.packages_dynamic[pattern]
193
194     return rproviders