xref: /OK3568_Linux_fs/yocto/poky/bitbake/lib/bb/taskdata.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun"""
2*4882a593SmuzhiyunBitBake 'TaskData' implementation
3*4882a593Smuzhiyun
4*4882a593SmuzhiyunTask data collection and handling
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun"""
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun# Copyright (C) 2006  Richard Purdie
9*4882a593Smuzhiyun#
10*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only
11*4882a593Smuzhiyun#
12*4882a593Smuzhiyun
13*4882a593Smuzhiyunimport logging
14*4882a593Smuzhiyunimport re
15*4882a593Smuzhiyunimport bb
16*4882a593Smuzhiyun
17*4882a593Smuzhiyunlogger = logging.getLogger("BitBake.TaskData")
18*4882a593Smuzhiyun
19*4882a593Smuzhiyundef re_match_strings(target, strings):
20*4882a593Smuzhiyun    """
21*4882a593Smuzhiyun    Whether or not the string 'target' matches
22*4882a593Smuzhiyun    any one string of the strings which can be regular expression string
23*4882a593Smuzhiyun    """
24*4882a593Smuzhiyun    for name in strings:
25*4882a593Smuzhiyun        if name.startswith("^") or name.endswith("$"):
26*4882a593Smuzhiyun            if re.match(name, target):
27*4882a593Smuzhiyun                return True
28*4882a593Smuzhiyun        elif name == target:
29*4882a593Smuzhiyun            return True
30*4882a593Smuzhiyun    return False
31*4882a593Smuzhiyun
32*4882a593Smuzhiyunclass TaskEntry:
33*4882a593Smuzhiyun    def __init__(self):
34*4882a593Smuzhiyun        self.tdepends = []
35*4882a593Smuzhiyun        self.idepends = []
36*4882a593Smuzhiyun        self.irdepends = []
37*4882a593Smuzhiyun
38*4882a593Smuzhiyunclass TaskData:
39*4882a593Smuzhiyun    """
40*4882a593Smuzhiyun    BitBake Task Data implementation
41*4882a593Smuzhiyun    """
42*4882a593Smuzhiyun    def __init__(self, halt = True, skiplist = None, allowincomplete = False):
43*4882a593Smuzhiyun        self.build_targets = {}
44*4882a593Smuzhiyun        self.run_targets = {}
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun        self.external_targets = []
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun        self.seenfns = []
49*4882a593Smuzhiyun        self.taskentries = {}
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun        self.depids = {}
52*4882a593Smuzhiyun        self.rdepids = {}
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun        self.consider_msgs_cache = []
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun        self.failed_deps = []
57*4882a593Smuzhiyun        self.failed_rdeps = []
58*4882a593Smuzhiyun        self.failed_fns = []
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun        self.halt = halt
61*4882a593Smuzhiyun        self.allowincomplete = allowincomplete
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun        self.skiplist = skiplist
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun        self.mcdepends = []
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun    def add_tasks(self, fn, dataCache):
68*4882a593Smuzhiyun        """
69*4882a593Smuzhiyun        Add tasks for a given fn to the database
70*4882a593Smuzhiyun        """
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun        task_deps = dataCache.task_deps[fn]
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun        if fn in self.failed_fns:
75*4882a593Smuzhiyun            bb.msg.fatal("TaskData", "Trying to re-add a failed file? Something is broken...")
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun        # Check if we've already seen this fn
78*4882a593Smuzhiyun        if fn in self.seenfns:
79*4882a593Smuzhiyun            return
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun        self.seenfns.append(fn)
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun        self.add_extra_deps(fn, dataCache)
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun        def add_mcdepends(task):
86*4882a593Smuzhiyun            for dep in task_deps['mcdepends'][task].split():
87*4882a593Smuzhiyun                if len(dep.split(':')) != 5:
88*4882a593Smuzhiyun                    bb.msg.fatal("TaskData", "Error for %s:%s[%s], multiconfig dependency %s does not contain exactly four  ':' characters.\n Task '%s' should be specified in the form 'mc:fromMC:toMC:packagename:task'" % (fn, task, 'mcdepends', dep, 'mcdepends'))
89*4882a593Smuzhiyun                if dep not in self.mcdepends:
90*4882a593Smuzhiyun                    self.mcdepends.append(dep)
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun        # Common code for dep_name/depends = 'depends'/idepends and 'rdepends'/irdepends
93*4882a593Smuzhiyun        def handle_deps(task, dep_name, depends, seen):
94*4882a593Smuzhiyun            if dep_name in task_deps and task in task_deps[dep_name]:
95*4882a593Smuzhiyun                ids = []
96*4882a593Smuzhiyun                for dep in task_deps[dep_name][task].split():
97*4882a593Smuzhiyun                    if dep:
98*4882a593Smuzhiyun                        parts = dep.split(":")
99*4882a593Smuzhiyun                        if len(parts) != 2:
100*4882a593Smuzhiyun                            bb.msg.fatal("TaskData", "Error for %s:%s[%s], dependency %s in '%s' does not contain exactly one ':' character.\n Task '%s' should be specified in the form 'packagename:task'" % (fn, task, dep_name, dep, task_deps[dep_name][task], dep_name))
101*4882a593Smuzhiyun                        ids.append((parts[0], parts[1]))
102*4882a593Smuzhiyun                        seen(parts[0])
103*4882a593Smuzhiyun                depends.extend(ids)
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun        for task in task_deps['tasks']:
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun            tid = "%s:%s" % (fn, task)
108*4882a593Smuzhiyun            self.taskentries[tid] = TaskEntry()
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun            # Work out task dependencies
111*4882a593Smuzhiyun            parentids = []
112*4882a593Smuzhiyun            for dep in task_deps['parents'][task]:
113*4882a593Smuzhiyun                if dep not in task_deps['tasks']:
114*4882a593Smuzhiyun                    bb.debug(2, "Not adding dependency of %s on %s since %s does not exist" % (task, dep, dep))
115*4882a593Smuzhiyun                    continue
116*4882a593Smuzhiyun                parentid = "%s:%s" % (fn, dep)
117*4882a593Smuzhiyun                parentids.append(parentid)
118*4882a593Smuzhiyun            self.taskentries[tid].tdepends.extend(parentids)
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun            # Touch all intertask dependencies
122*4882a593Smuzhiyun            handle_deps(task, 'depends', self.taskentries[tid].idepends, self.seen_build_target)
123*4882a593Smuzhiyun            handle_deps(task, 'rdepends', self.taskentries[tid].irdepends, self.seen_run_target)
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun            if 'mcdepends' in task_deps and task in task_deps['mcdepends']:
126*4882a593Smuzhiyun                add_mcdepends(task)
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun        # Work out build dependencies
129*4882a593Smuzhiyun        if not fn in self.depids:
130*4882a593Smuzhiyun            dependids = set()
131*4882a593Smuzhiyun            for depend in dataCache.deps[fn]:
132*4882a593Smuzhiyun                dependids.add(depend)
133*4882a593Smuzhiyun            self.depids[fn] = list(dependids)
134*4882a593Smuzhiyun            logger.debug2("Added dependencies %s for %s", str(dataCache.deps[fn]), fn)
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun        # Work out runtime dependencies
137*4882a593Smuzhiyun        if not fn in self.rdepids:
138*4882a593Smuzhiyun            rdependids = set()
139*4882a593Smuzhiyun            rdepends = dataCache.rundeps[fn]
140*4882a593Smuzhiyun            rrecs = dataCache.runrecs[fn]
141*4882a593Smuzhiyun            rdependlist = []
142*4882a593Smuzhiyun            rreclist = []
143*4882a593Smuzhiyun            for package in rdepends:
144*4882a593Smuzhiyun                for rdepend in rdepends[package]:
145*4882a593Smuzhiyun                    rdependlist.append(rdepend)
146*4882a593Smuzhiyun                    rdependids.add(rdepend)
147*4882a593Smuzhiyun            for package in rrecs:
148*4882a593Smuzhiyun                for rdepend in rrecs[package]:
149*4882a593Smuzhiyun                    rreclist.append(rdepend)
150*4882a593Smuzhiyun                    rdependids.add(rdepend)
151*4882a593Smuzhiyun            if rdependlist:
152*4882a593Smuzhiyun                logger.debug2("Added runtime dependencies %s for %s", str(rdependlist), fn)
153*4882a593Smuzhiyun            if rreclist:
154*4882a593Smuzhiyun                logger.debug2("Added runtime recommendations %s for %s", str(rreclist), fn)
155*4882a593Smuzhiyun            self.rdepids[fn] = list(rdependids)
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun        for dep in self.depids[fn]:
158*4882a593Smuzhiyun            self.seen_build_target(dep)
159*4882a593Smuzhiyun            if dep in self.failed_deps:
160*4882a593Smuzhiyun                self.fail_fn(fn)
161*4882a593Smuzhiyun                return
162*4882a593Smuzhiyun        for dep in self.rdepids[fn]:
163*4882a593Smuzhiyun            self.seen_run_target(dep)
164*4882a593Smuzhiyun            if dep in self.failed_rdeps:
165*4882a593Smuzhiyun                self.fail_fn(fn)
166*4882a593Smuzhiyun                return
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun    def add_extra_deps(self, fn, dataCache):
169*4882a593Smuzhiyun        func = dataCache.extradepsfunc.get(fn, None)
170*4882a593Smuzhiyun        if func:
171*4882a593Smuzhiyun            bb.providers.buildWorldTargetList(dataCache)
172*4882a593Smuzhiyun            pn = dataCache.pkg_fn[fn]
173*4882a593Smuzhiyun            params = {'deps': dataCache.deps[fn],
174*4882a593Smuzhiyun                      'world_target': dataCache.world_target,
175*4882a593Smuzhiyun                      'pkg_pn': dataCache.pkg_pn,
176*4882a593Smuzhiyun                      'self_pn': pn}
177*4882a593Smuzhiyun            funcname = '_%s_calculate_extra_depends' % pn.replace('-', '_')
178*4882a593Smuzhiyun            paramlist = ','.join(params.keys())
179*4882a593Smuzhiyun            func = 'def %s(%s):\n%s\n\n%s(%s)' % (funcname, paramlist, func, funcname, paramlist)
180*4882a593Smuzhiyun            bb.utils.better_exec(func, params)
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun    def have_build_target(self, target):
184*4882a593Smuzhiyun        """
185*4882a593Smuzhiyun        Have we a build target matching this name?
186*4882a593Smuzhiyun        """
187*4882a593Smuzhiyun        if target in self.build_targets and self.build_targets[target]:
188*4882a593Smuzhiyun            return True
189*4882a593Smuzhiyun        return False
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun    def have_runtime_target(self, target):
192*4882a593Smuzhiyun        """
193*4882a593Smuzhiyun        Have we a runtime target matching this name?
194*4882a593Smuzhiyun        """
195*4882a593Smuzhiyun        if target in self.run_targets and self.run_targets[target]:
196*4882a593Smuzhiyun            return True
197*4882a593Smuzhiyun        return False
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun    def seen_build_target(self, name):
200*4882a593Smuzhiyun        """
201*4882a593Smuzhiyun        Maintain a list of build targets
202*4882a593Smuzhiyun        """
203*4882a593Smuzhiyun        if name not in self.build_targets:
204*4882a593Smuzhiyun            self.build_targets[name] = []
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun    def add_build_target(self, fn, item):
207*4882a593Smuzhiyun        """
208*4882a593Smuzhiyun        Add a build target.
209*4882a593Smuzhiyun        If already present, append the provider fn to the list
210*4882a593Smuzhiyun        """
211*4882a593Smuzhiyun        if item in self.build_targets:
212*4882a593Smuzhiyun            if fn in self.build_targets[item]:
213*4882a593Smuzhiyun                return
214*4882a593Smuzhiyun            self.build_targets[item].append(fn)
215*4882a593Smuzhiyun            return
216*4882a593Smuzhiyun        self.build_targets[item] = [fn]
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun    def seen_run_target(self, name):
219*4882a593Smuzhiyun        """
220*4882a593Smuzhiyun        Maintain a list of runtime build targets
221*4882a593Smuzhiyun        """
222*4882a593Smuzhiyun        if name not in self.run_targets:
223*4882a593Smuzhiyun            self.run_targets[name] = []
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun    def add_runtime_target(self, fn, item):
226*4882a593Smuzhiyun        """
227*4882a593Smuzhiyun        Add a runtime target.
228*4882a593Smuzhiyun        If already present, append the provider fn to the list
229*4882a593Smuzhiyun        """
230*4882a593Smuzhiyun        if item in self.run_targets:
231*4882a593Smuzhiyun            if fn in self.run_targets[item]:
232*4882a593Smuzhiyun                return
233*4882a593Smuzhiyun            self.run_targets[item].append(fn)
234*4882a593Smuzhiyun            return
235*4882a593Smuzhiyun        self.run_targets[item] = [fn]
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun    def mark_external_target(self, target):
238*4882a593Smuzhiyun        """
239*4882a593Smuzhiyun        Mark a build target as being externally requested
240*4882a593Smuzhiyun        """
241*4882a593Smuzhiyun        if target not in self.external_targets:
242*4882a593Smuzhiyun            self.external_targets.append(target)
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun    def get_unresolved_build_targets(self, dataCache):
245*4882a593Smuzhiyun        """
246*4882a593Smuzhiyun        Return a list of build targets who's providers
247*4882a593Smuzhiyun        are unknown.
248*4882a593Smuzhiyun        """
249*4882a593Smuzhiyun        unresolved = []
250*4882a593Smuzhiyun        for target in self.build_targets:
251*4882a593Smuzhiyun            if re_match_strings(target, dataCache.ignored_dependencies):
252*4882a593Smuzhiyun                continue
253*4882a593Smuzhiyun            if target in self.failed_deps:
254*4882a593Smuzhiyun                continue
255*4882a593Smuzhiyun            if not self.build_targets[target]:
256*4882a593Smuzhiyun                unresolved.append(target)
257*4882a593Smuzhiyun        return unresolved
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun    def get_unresolved_run_targets(self, dataCache):
260*4882a593Smuzhiyun        """
261*4882a593Smuzhiyun        Return a list of runtime targets who's providers
262*4882a593Smuzhiyun        are unknown.
263*4882a593Smuzhiyun        """
264*4882a593Smuzhiyun        unresolved = []
265*4882a593Smuzhiyun        for target in self.run_targets:
266*4882a593Smuzhiyun            if re_match_strings(target, dataCache.ignored_dependencies):
267*4882a593Smuzhiyun                continue
268*4882a593Smuzhiyun            if target in self.failed_rdeps:
269*4882a593Smuzhiyun                continue
270*4882a593Smuzhiyun            if not self.run_targets[target]:
271*4882a593Smuzhiyun                unresolved.append(target)
272*4882a593Smuzhiyun        return unresolved
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun    def get_provider(self, item):
275*4882a593Smuzhiyun        """
276*4882a593Smuzhiyun        Return a list of providers of item
277*4882a593Smuzhiyun        """
278*4882a593Smuzhiyun        return self.build_targets[item]
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun    def get_dependees(self, item):
281*4882a593Smuzhiyun        """
282*4882a593Smuzhiyun        Return a list of targets which depend on item
283*4882a593Smuzhiyun        """
284*4882a593Smuzhiyun        dependees = []
285*4882a593Smuzhiyun        for fn in self.depids:
286*4882a593Smuzhiyun            if item in self.depids[fn]:
287*4882a593Smuzhiyun                dependees.append(fn)
288*4882a593Smuzhiyun        return dependees
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun    def get_rdependees(self, item):
291*4882a593Smuzhiyun        """
292*4882a593Smuzhiyun        Return a list of targets which depend on runtime item
293*4882a593Smuzhiyun        """
294*4882a593Smuzhiyun        dependees = []
295*4882a593Smuzhiyun        for fn in self.rdepids:
296*4882a593Smuzhiyun            if item in self.rdepids[fn]:
297*4882a593Smuzhiyun                dependees.append(fn)
298*4882a593Smuzhiyun        return dependees
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun    def get_reasons(self, item, runtime=False):
301*4882a593Smuzhiyun        """
302*4882a593Smuzhiyun        Get the reason(s) for an item not being provided, if any
303*4882a593Smuzhiyun        """
304*4882a593Smuzhiyun        reasons = []
305*4882a593Smuzhiyun        if self.skiplist:
306*4882a593Smuzhiyun            for fn in self.skiplist:
307*4882a593Smuzhiyun                skipitem = self.skiplist[fn]
308*4882a593Smuzhiyun                if skipitem.pn == item:
309*4882a593Smuzhiyun                    reasons.append("%s was skipped: %s" % (skipitem.pn, skipitem.skipreason))
310*4882a593Smuzhiyun                elif runtime and item in skipitem.rprovides:
311*4882a593Smuzhiyun                    reasons.append("%s RPROVIDES %s but was skipped: %s" % (skipitem.pn, item, skipitem.skipreason))
312*4882a593Smuzhiyun                elif not runtime and item in skipitem.provides:
313*4882a593Smuzhiyun                    reasons.append("%s PROVIDES %s but was skipped: %s" % (skipitem.pn, item, skipitem.skipreason))
314*4882a593Smuzhiyun        return reasons
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun    def get_close_matches(self, item, provider_list):
317*4882a593Smuzhiyun        import difflib
318*4882a593Smuzhiyun        if self.skiplist:
319*4882a593Smuzhiyun            skipped = []
320*4882a593Smuzhiyun            for fn in self.skiplist:
321*4882a593Smuzhiyun                skipped.append(self.skiplist[fn].pn)
322*4882a593Smuzhiyun            full_list = provider_list + skipped
323*4882a593Smuzhiyun        else:
324*4882a593Smuzhiyun            full_list = provider_list
325*4882a593Smuzhiyun        return difflib.get_close_matches(item, full_list, cutoff=0.7)
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun    def add_provider(self, cfgData, dataCache, item):
328*4882a593Smuzhiyun        try:
329*4882a593Smuzhiyun            self.add_provider_internal(cfgData, dataCache, item)
330*4882a593Smuzhiyun        except bb.providers.NoProvider:
331*4882a593Smuzhiyun            if self.halt:
332*4882a593Smuzhiyun                raise
333*4882a593Smuzhiyun            self.remove_buildtarget(item)
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun        self.mark_external_target(item)
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun    def add_provider_internal(self, cfgData, dataCache, item):
338*4882a593Smuzhiyun        """
339*4882a593Smuzhiyun        Add the providers of item to the task data
340*4882a593Smuzhiyun        Mark entries were specifically added externally as against dependencies
341*4882a593Smuzhiyun        added internally during dependency resolution
342*4882a593Smuzhiyun        """
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun        if re_match_strings(item, dataCache.ignored_dependencies):
345*4882a593Smuzhiyun            return
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun        if not item in dataCache.providers:
348*4882a593Smuzhiyun            close_matches = self.get_close_matches(item, list(dataCache.providers.keys()))
349*4882a593Smuzhiyun            # Is it in RuntimeProviders ?
350*4882a593Smuzhiyun            all_p = bb.providers.getRuntimeProviders(dataCache, item)
351*4882a593Smuzhiyun            for fn in all_p:
352*4882a593Smuzhiyun                new = dataCache.pkg_fn[fn] + " RPROVIDES " + item
353*4882a593Smuzhiyun                if new not in close_matches:
354*4882a593Smuzhiyun                    close_matches.append(new)
355*4882a593Smuzhiyun            bb.event.fire(bb.event.NoProvider(item, dependees=self.get_dependees(item), reasons=self.get_reasons(item), close_matches=close_matches), cfgData)
356*4882a593Smuzhiyun            raise bb.providers.NoProvider(item)
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun        if self.have_build_target(item):
359*4882a593Smuzhiyun            return
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun        all_p = dataCache.providers[item]
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun        eligible, foundUnique = bb.providers.filterProviders(all_p, item, cfgData, dataCache)
364*4882a593Smuzhiyun        eligible = [p for p in eligible if not p in self.failed_fns]
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun        if not eligible:
367*4882a593Smuzhiyun            bb.event.fire(bb.event.NoProvider(item, dependees=self.get_dependees(item), reasons=["No eligible PROVIDERs exist for '%s'" % item]), cfgData)
368*4882a593Smuzhiyun            raise bb.providers.NoProvider(item)
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun        if len(eligible) > 1 and not foundUnique:
371*4882a593Smuzhiyun            if item not in self.consider_msgs_cache:
372*4882a593Smuzhiyun                providers_list = []
373*4882a593Smuzhiyun                for fn in eligible:
374*4882a593Smuzhiyun                    providers_list.append(dataCache.pkg_fn[fn])
375*4882a593Smuzhiyun                bb.event.fire(bb.event.MultipleProviders(item, providers_list), cfgData)
376*4882a593Smuzhiyun            self.consider_msgs_cache.append(item)
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun        for fn in eligible:
379*4882a593Smuzhiyun            if fn in self.failed_fns:
380*4882a593Smuzhiyun                continue
381*4882a593Smuzhiyun            logger.debug2("adding %s to satisfy %s", fn, item)
382*4882a593Smuzhiyun            self.add_build_target(fn, item)
383*4882a593Smuzhiyun            self.add_tasks(fn, dataCache)
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun            #item = dataCache.pkg_fn[fn]
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun    def add_rprovider(self, cfgData, dataCache, item):
389*4882a593Smuzhiyun        """
390*4882a593Smuzhiyun        Add the runtime providers of item to the task data
391*4882a593Smuzhiyun        (takes item names from RDEPENDS/PACKAGES namespace)
392*4882a593Smuzhiyun        """
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun        if re_match_strings(item, dataCache.ignored_dependencies):
395*4882a593Smuzhiyun            return
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun        if self.have_runtime_target(item):
398*4882a593Smuzhiyun            return
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun        all_p = bb.providers.getRuntimeProviders(dataCache, item)
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun        if not all_p:
403*4882a593Smuzhiyun            bb.event.fire(bb.event.NoProvider(item, runtime=True, dependees=self.get_rdependees(item), reasons=self.get_reasons(item, True)), cfgData)
404*4882a593Smuzhiyun            raise bb.providers.NoRProvider(item)
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun        eligible, numberPreferred = bb.providers.filterProvidersRunTime(all_p, item, cfgData, dataCache)
407*4882a593Smuzhiyun        eligible = [p for p in eligible if not p in self.failed_fns]
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun        if not eligible:
410*4882a593Smuzhiyun            bb.event.fire(bb.event.NoProvider(item, runtime=True, dependees=self.get_rdependees(item), reasons=["No eligible RPROVIDERs exist for '%s'" % item]), cfgData)
411*4882a593Smuzhiyun            raise bb.providers.NoRProvider(item)
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun        if len(eligible) > 1 and numberPreferred == 0:
414*4882a593Smuzhiyun            if item not in self.consider_msgs_cache:
415*4882a593Smuzhiyun                providers_list = []
416*4882a593Smuzhiyun                for fn in eligible:
417*4882a593Smuzhiyun                    providers_list.append(dataCache.pkg_fn[fn])
418*4882a593Smuzhiyun                bb.event.fire(bb.event.MultipleProviders(item, providers_list, runtime=True), cfgData)
419*4882a593Smuzhiyun            self.consider_msgs_cache.append(item)
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun        if numberPreferred > 1:
422*4882a593Smuzhiyun            if item not in self.consider_msgs_cache:
423*4882a593Smuzhiyun                providers_list = []
424*4882a593Smuzhiyun                for fn in eligible:
425*4882a593Smuzhiyun                    providers_list.append(dataCache.pkg_fn[fn])
426*4882a593Smuzhiyun                bb.event.fire(bb.event.MultipleProviders(item, providers_list, runtime=True), cfgData)
427*4882a593Smuzhiyun            self.consider_msgs_cache.append(item)
428*4882a593Smuzhiyun            raise bb.providers.MultipleRProvider(item)
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun        # run through the list until we find one that we can build
431*4882a593Smuzhiyun        for fn in eligible:
432*4882a593Smuzhiyun            if fn in self.failed_fns:
433*4882a593Smuzhiyun                continue
434*4882a593Smuzhiyun            logger.debug2("adding '%s' to satisfy runtime '%s'", fn, item)
435*4882a593Smuzhiyun            self.add_runtime_target(fn, item)
436*4882a593Smuzhiyun            self.add_tasks(fn, dataCache)
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun    def fail_fn(self, fn, missing_list=None):
439*4882a593Smuzhiyun        """
440*4882a593Smuzhiyun        Mark a file as failed (unbuildable)
441*4882a593Smuzhiyun        Remove any references from build and runtime provider lists
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun        missing_list, A list of missing requirements for this target
444*4882a593Smuzhiyun        """
445*4882a593Smuzhiyun        if fn in self.failed_fns:
446*4882a593Smuzhiyun            return
447*4882a593Smuzhiyun        if not missing_list:
448*4882a593Smuzhiyun            missing_list = []
449*4882a593Smuzhiyun        logger.debug("File '%s' is unbuildable, removing...", fn)
450*4882a593Smuzhiyun        self.failed_fns.append(fn)
451*4882a593Smuzhiyun        for target in self.build_targets:
452*4882a593Smuzhiyun            if fn in self.build_targets[target]:
453*4882a593Smuzhiyun                self.build_targets[target].remove(fn)
454*4882a593Smuzhiyun                if not self.build_targets[target]:
455*4882a593Smuzhiyun                    self.remove_buildtarget(target, missing_list)
456*4882a593Smuzhiyun        for target in self.run_targets:
457*4882a593Smuzhiyun            if fn in self.run_targets[target]:
458*4882a593Smuzhiyun                self.run_targets[target].remove(fn)
459*4882a593Smuzhiyun                if not self.run_targets[target]:
460*4882a593Smuzhiyun                    self.remove_runtarget(target, missing_list)
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun    def remove_buildtarget(self, target, missing_list=None):
463*4882a593Smuzhiyun        """
464*4882a593Smuzhiyun        Mark a build target as failed (unbuildable)
465*4882a593Smuzhiyun        Trigger removal of any files that have this as a dependency
466*4882a593Smuzhiyun        """
467*4882a593Smuzhiyun        if not missing_list:
468*4882a593Smuzhiyun            missing_list = [target]
469*4882a593Smuzhiyun        else:
470*4882a593Smuzhiyun            missing_list = [target] + missing_list
471*4882a593Smuzhiyun        logger.verbose("Target '%s' is unbuildable, removing...\nMissing or unbuildable dependency chain was: %s", target, missing_list)
472*4882a593Smuzhiyun        self.failed_deps.append(target)
473*4882a593Smuzhiyun        dependees = self.get_dependees(target)
474*4882a593Smuzhiyun        for fn in dependees:
475*4882a593Smuzhiyun            self.fail_fn(fn, missing_list)
476*4882a593Smuzhiyun        for tid in self.taskentries:
477*4882a593Smuzhiyun            for (idepend, idependtask) in self.taskentries[tid].idepends:
478*4882a593Smuzhiyun                if idepend == target:
479*4882a593Smuzhiyun                    fn = tid.rsplit(":",1)[0]
480*4882a593Smuzhiyun                    self.fail_fn(fn, missing_list)
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun        if self.halt and target in self.external_targets:
483*4882a593Smuzhiyun            logger.error("Required build target '%s' has no buildable providers.\nMissing or unbuildable dependency chain was: %s", target, missing_list)
484*4882a593Smuzhiyun            raise bb.providers.NoProvider(target)
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun    def remove_runtarget(self, target, missing_list=None):
487*4882a593Smuzhiyun        """
488*4882a593Smuzhiyun        Mark a run target as failed (unbuildable)
489*4882a593Smuzhiyun        Trigger removal of any files that have this as a dependency
490*4882a593Smuzhiyun        """
491*4882a593Smuzhiyun        if not missing_list:
492*4882a593Smuzhiyun            missing_list = [target]
493*4882a593Smuzhiyun        else:
494*4882a593Smuzhiyun            missing_list = [target] + missing_list
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun        logger.info("Runtime target '%s' is unbuildable, removing...\nMissing or unbuildable dependency chain was: %s", target, missing_list)
497*4882a593Smuzhiyun        self.failed_rdeps.append(target)
498*4882a593Smuzhiyun        dependees = self.get_rdependees(target)
499*4882a593Smuzhiyun        for fn in dependees:
500*4882a593Smuzhiyun            self.fail_fn(fn, missing_list)
501*4882a593Smuzhiyun        for tid in self.taskentries:
502*4882a593Smuzhiyun            for (idepend, idependtask) in self.taskentries[tid].irdepends:
503*4882a593Smuzhiyun                if idepend == target:
504*4882a593Smuzhiyun                    fn = tid.rsplit(":",1)[0]
505*4882a593Smuzhiyun                    self.fail_fn(fn, missing_list)
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun    def add_unresolved(self, cfgData, dataCache):
508*4882a593Smuzhiyun        """
509*4882a593Smuzhiyun        Resolve all unresolved build and runtime targets
510*4882a593Smuzhiyun        """
511*4882a593Smuzhiyun        logger.info("Resolving any missing task queue dependencies")
512*4882a593Smuzhiyun        while True:
513*4882a593Smuzhiyun            added = 0
514*4882a593Smuzhiyun            for target in self.get_unresolved_build_targets(dataCache):
515*4882a593Smuzhiyun                try:
516*4882a593Smuzhiyun                    self.add_provider_internal(cfgData, dataCache, target)
517*4882a593Smuzhiyun                    added = added + 1
518*4882a593Smuzhiyun                except bb.providers.NoProvider:
519*4882a593Smuzhiyun                    if self.halt and target in self.external_targets and not self.allowincomplete:
520*4882a593Smuzhiyun                        raise
521*4882a593Smuzhiyun                    if not self.allowincomplete:
522*4882a593Smuzhiyun                        self.remove_buildtarget(target)
523*4882a593Smuzhiyun            for target in self.get_unresolved_run_targets(dataCache):
524*4882a593Smuzhiyun                try:
525*4882a593Smuzhiyun                    self.add_rprovider(cfgData, dataCache, target)
526*4882a593Smuzhiyun                    added = added + 1
527*4882a593Smuzhiyun                except (bb.providers.NoRProvider, bb.providers.MultipleRProvider):
528*4882a593Smuzhiyun                    self.remove_runtarget(target)
529*4882a593Smuzhiyun            logger.debug("Resolved " + str(added) + " extra dependencies")
530*4882a593Smuzhiyun            if added == 0:
531*4882a593Smuzhiyun                break
532*4882a593Smuzhiyun        # self.dump_data()
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun    def get_providermap(self, prefix=None):
535*4882a593Smuzhiyun        provmap = {}
536*4882a593Smuzhiyun        for name in self.build_targets:
537*4882a593Smuzhiyun            if prefix and not name.startswith(prefix):
538*4882a593Smuzhiyun                continue
539*4882a593Smuzhiyun            if self.have_build_target(name):
540*4882a593Smuzhiyun                provider = self.get_provider(name)
541*4882a593Smuzhiyun                if provider:
542*4882a593Smuzhiyun                    provmap[name] = provider[0]
543*4882a593Smuzhiyun        return provmap
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun    def get_mcdepends(self):
546*4882a593Smuzhiyun        return self.mcdepends
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun    def dump_data(self):
549*4882a593Smuzhiyun        """
550*4882a593Smuzhiyun        Dump some debug information on the internal data structures
551*4882a593Smuzhiyun        """
552*4882a593Smuzhiyun        logger.debug3("build_names:")
553*4882a593Smuzhiyun        logger.debug3(", ".join(self.build_targets))
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun        logger.debug3("run_names:")
556*4882a593Smuzhiyun        logger.debug3(", ".join(self.run_targets))
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun        logger.debug3("build_targets:")
559*4882a593Smuzhiyun        for target in self.build_targets:
560*4882a593Smuzhiyun            targets = "None"
561*4882a593Smuzhiyun            if target in self.build_targets:
562*4882a593Smuzhiyun                targets = self.build_targets[target]
563*4882a593Smuzhiyun            logger.debug3(" %s: %s", target, targets)
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun        logger.debug3("run_targets:")
566*4882a593Smuzhiyun        for target in self.run_targets:
567*4882a593Smuzhiyun            targets = "None"
568*4882a593Smuzhiyun            if target in self.run_targets:
569*4882a593Smuzhiyun                targets = self.run_targets[target]
570*4882a593Smuzhiyun            logger.debug3(" %s: %s", target, targets)
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun        logger.debug3("tasks:")
573*4882a593Smuzhiyun        for tid in self.taskentries:
574*4882a593Smuzhiyun            logger.debug3(" %s: %s %s %s",
575*4882a593Smuzhiyun                       tid,
576*4882a593Smuzhiyun                       self.taskentries[tid].idepends,
577*4882a593Smuzhiyun                       self.taskentries[tid].irdepends,
578*4882a593Smuzhiyun                       self.taskentries[tid].tdepends)
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun        logger.debug3("dependency ids (per fn):")
581*4882a593Smuzhiyun        for fn in self.depids:
582*4882a593Smuzhiyun            logger.debug3(" %s: %s", fn, self.depids[fn])
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun        logger.debug3("runtime dependency ids (per fn):")
585*4882a593Smuzhiyun        for fn in self.rdepids:
586*4882a593Smuzhiyun            logger.debug3(" %s: %s", fn, self.rdepids[fn])
587