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