bitbake/lib/bb/__init__.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 #
11 # This program is free software; you can redistribute it and/or modify it under
12 # the terms of the GNU General Public License as published by the Free Software
13 # Foundation; either version 2 of the License, or (at your option) any later
14 # version.
15 #
16 # This program is distributed in the hope that it will be useful, but WITHOUT
17 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License along with
21 # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 # Place, Suite 330, Boston, MA 02111-1307 USA.
23
24 import os, re
25 from bb import data, utils
26 import bb
27
28 def findBestProvider(pn, cfgData, dataCache, pkg_pn = None):
29     """
30     If there is a PREFERRED_VERSION, find the highest-priority bbfile
31     providing that version.  If not, find the latest version provided by
32     an bbfile in the highest-priority set.
33     """
34     if not pkg_pn:
35         pkg_pn = dataCache.pkg_pn
36
37     files = pkg_pn[pn]
38     priorities = {}
39     for f in files:
40         priority = dataCache.bbfile_priority[f]
41         if priority not in priorities:
42             priorities[priority] = []
43         priorities[priority].append(f)
44     p_list = priorities.keys()
45     p_list.sort(lambda a, b: a - b)
46     tmp_pn = []
47     for p in p_list:
48         tmp_pn = [priorities[p]] + tmp_pn
49
50     preferred_file = None
51
52     localdata = data.createCopy(cfgData)
53     bb.data.setVar('OVERRIDES', "%s:%s" % (pn, data.getVar('OVERRIDES', localdata)), localdata)
54     bb.data.update_data(localdata)
55
56     preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True)
57     if preferred_v:
58         m = re.match('(.*)_(.*)', preferred_v)
59         if m:
60             preferred_v = m.group(1)
61             preferred_r = m.group(2)
62         else:
63             preferred_r = None
64
65         for file_set in tmp_pn:
66             for f in file_set:
67                 pv,pr = dataCache.pkg_pvpr[f]
68                 if preferred_v == pv and (preferred_r == pr or preferred_r == None):
69                     preferred_file = f
70                     preferred_ver = (pv, pr)
71                     break
72             if preferred_file:
73                 break;
74         if preferred_r:
75             pv_str = '%s-%s' % (preferred_v, preferred_r)
76         else:
77             pv_str = preferred_v
78         if preferred_file is None:
79             bb.msg.note(1, bb.msg.domain.Provider, "preferred version %s of %s not available" % (pv_str, pn))
80         else:
81             bb.msg.debug(1, bb.msg.domain.Provider, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
82
83     del localdata
84
85     # get highest priority file set
86     files = tmp_pn[0]
87     latest = None
88     latest_p = 0
89     latest_f = None
90     for file_name in files:
91         pv,pr = dataCache.pkg_pvpr[file_name]
92         dp = dataCache.pkg_dp[file_name]
93
94         if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
95             latest = (pv, pr)
96             latest_f = file_name
97             latest_p = dp
98     if preferred_file is None:
99         preferred_file = latest_f
100         preferred_ver = latest
101
102     return (latest,latest_f,preferred_ver, preferred_file)
103
104 def filterProviders(providers, item, cfgData, dataCache, build_cache_fail):
105     """
106     Take a list of providers and filter/reorder according to the 
107     environment variables and previous build results
108     """
109     eligible = []
110     preferred_versions = {}
111
112     # Collate providers by PN
113     pkg_pn = {}
114     for p in providers:
115         pn = dataCache.pkg_fn[p]
116         if pn not in pkg_pn:
117             pkg_pn[pn] = []
118         pkg_pn[pn].append(p)
119
120     bb.msg.debug(1, bb.msg.domain.Provider, "providers for %s are: %s" % (item, pkg_pn.keys()))
121
122     for pn in pkg_pn.keys():
123         preferred_versions[pn] = bb.providers.findBestProvider(pn, cfgData, dataCache, pkg_pn)[2:4]
124         eligible.append(preferred_versions[pn][1])
125
126
127     for p in eligible:
128         if p in build_cache_fail:
129             bb.msg.debug(1, bb.msg.domain.Provider, "rejecting already-failed %s" % p)
130             eligible.remove(p)
131
132     if len(eligible) == 0:
133         bb.error("no eligible providers for %s" % item)
134         return 0
135
136     # look to see if one of them is already staged, or marked as preferred.
137     # if so, bump it to the head of the queue
138     for p in providers:
139         pn = dataCache.pkg_fn[p]
140         pv, pr = dataCache.pkg_pvpr[p]
141
142         stamp = '%s.do_populate_staging' % dataCache.stamp[p]
143         if os.path.exists(stamp):
144             (newvers, fn) = preferred_versions[pn]
145             if not fn in eligible:
146                 # package was made ineligible by already-failed check
147                 continue
148             oldver = "%s-%s" % (pv, pr)
149             newver = '-'.join(newvers)
150             if (newver != oldver):
151                 extra_chat = "%s (%s) already staged but upgrading to %s to satisfy %s" % (pn, oldver, newver, item)
152             else:
153                 extra_chat = "Selecting already-staged %s (%s) to satisfy %s" % (pn, oldver, item)
154
155             bb.msg.note(2, bb.msg.domain.Provider, "%s" % extra_chat)
156             eligible.remove(fn)
157             eligible = [fn] + eligible
158             discriminated = True
159             break
160
161     return eligible
162