def __note(msg, d): bb.note("%s: recipe_sanity: %s" % (d.getVar("P", True), msg)) __recipe_sanity_badruntimevars = "RDEPENDS RPROVIDES RRECOMMENDS RCONFLICTS" def bad_runtime_vars(cfgdata, d): if bb.data.inherits_class("native", d) or \ bb.data.inherits_class("cross", d): return for var in d.getVar("__recipe_sanity_badruntimevars", True).split(): val = d.getVar(var, False) if val and val != cfgdata.get(var): __note("%s should be %s_${PN}" % (var, var), d) __recipe_sanity_reqvars = "DESCRIPTION" __recipe_sanity_reqdiffvars = "" def req_vars(cfgdata, d): for var in d.getVar("__recipe_sanity_reqvars", True).split(): if not d.getVar(var, False): __note("%s should be set" % var, d) for var in d.getVar("__recipe_sanity_reqdiffvars", True).split(): val = d.getVar(var, False) cfgval = cfgdata.get(var) if not val: __note("%s should be set" % var, d) elif val == cfgval: __note("%s should be defined to something other than default (%s)" % (var, cfgval), d) def var_renames_overwrite(cfgdata, d): renames = d.getVar("__recipe_sanity_renames", False) if renames: for (key, newkey, oldvalue, newvalue) in renames: if oldvalue != newvalue and oldvalue != cfgdata.get(newkey): __note("rename of variable '%s' to '%s' overwrote existing value '%s' with '%s'." % (key, newkey, oldvalue, newvalue), d) def incorrect_nonempty_PACKAGES(cfgdata, d): if bb.data.inherits_class("native", d) or \ bb.data.inherits_class("cross", d): if d.getVar("PACKAGES", True): return True def can_use_autotools_base(cfgdata, d): cfg = d.getVar("do_configure", True) if not bb.data.inherits_class("autotools", d): return False for i in ["autoreconf"] + ["%s_do_configure" % cls for cls in ["gnomebase", "gnome", "e", "autotools", "efl", "gpephone", "openmoko", "openmoko2", "xfce", "xlibs"]]: if cfg.find(i) != -1: return False for clsfile in d.getVar("__inherit_cache", False): (base, _) = os.path.splitext(os.path.basename(clsfile)) if cfg.find("%s_do_configure" % base) != -1: __note("autotools_base usage needs verification, spotted %s_do_configure" % base, d) return True def can_delete_FILESPATH(cfgdata, d): expected = cfgdata.get("FILESPATH") expectedpaths = d.expand(expected) unexpanded = d.getVar("FILESPATH", False) filespath = d.getVar("FILESPATH", True).split(":") filespath = [os.path.normpath(f) for f in filespath if os.path.exists(f)] for fp in filespath: if not fp in expectedpaths: # __note("Path %s in FILESPATH not in the expected paths %s" % # (fp, expectedpaths), d) return False return expected != unexpanded def can_delete_FILESDIR(cfgdata, d): expected = cfgdata.get("FILESDIR") #expected = "${@bb.utils.which(d.getVar('FILESPATH', True), '.')}" unexpanded = d.getVar("FILESDIR", False) if unexpanded is None: return False expanded = os.path.normpath(d.getVar("FILESDIR", True)) filespath = d.getVar("FILESPATH", True).split(":") filespath = [os.path.normpath(f) for f in filespath if os.path.exists(f)] return unexpanded != expected and \ os.path.exists(expanded) and \ (expanded in filespath or expanded == d.expand(expected)) def can_delete_others(p, cfgdata, d): for k in ["S", "PV", "PN", "DESCRIPTION", "DEPENDS", "SECTION", "PACKAGES", "EXTRA_OECONF", "EXTRA_OEMAKE"]: #for k in cfgdata: unexpanded = d.getVar(k, False) cfgunexpanded = cfgdata.get(k) if not cfgunexpanded: continue try: expanded = d.getVar(k, True) cfgexpanded = d.expand(cfgunexpanded) except bb.fetch.ParameterError: continue if unexpanded != cfgunexpanded and \ cfgexpanded == expanded: __note("candidate for removal of %s" % k, d) bb.debug(1, "%s: recipe_sanity: cfg's '%s' and d's '%s' both expand to %s" % (p, cfgunexpanded, unexpanded, expanded)) python do_recipe_sanity () { p = d.getVar("P", True) p = "%s %s %s" % (d.getVar("PN", True), d.getVar("PV", True), d.getVar("PR", True)) sanitychecks = [ (can_delete_FILESDIR, "candidate for removal of FILESDIR"), (can_delete_FILESPATH, "candidate for removal of FILESPATH"), #(can_use_autotools_base, "candidate for use of autotools_base"), (incorrect_nonempty_PACKAGES, "native or cross recipe with non-empty PACKAGES"), ] cfgdata = d.getVar("__recipe_sanity_cfgdata", False) for (func, msg) in sanitychecks: if func(cfgdata, d): __note(msg, d) can_delete_others(p, cfgdata, d) var_renames_overwrite(cfgdata, d) req_vars(cfgdata, d) bad_runtime_vars(cfgdata, d) } do_recipe_sanity[nostamp] = "1" addtask recipe_sanity do_recipe_sanity_all[nostamp] = "1" do_recipe_sanity_all[recrdeptask] = "do_recipe_sanity_all do_recipe_sanity" do_recipe_sanity_all () { : } addtask recipe_sanity_all after do_recipe_sanity python recipe_sanity_eh () { d = e.data cfgdata = {} for k in d.keys(): if not isinstance(d.getVar(k, False), bb.data_smart.DataSmart): cfgdata[k] = d.getVar(k, False) d.setVar("__recipe_sanity_cfgdata", cfgdata) #d.setVar("__recipe_sanity_cfgdata", d) # Sick, very sick.. from bb.data_smart import DataSmart old = DataSmart.renameVar def myrename(self, key, newkey): oldvalue = self.getVar(newkey, 0) old(self, key, newkey) newvalue = self.getVar(newkey, 0) if oldvalue: renames = self.getVar("__recipe_sanity_renames", 0) or set() renames.add((key, newkey, oldvalue, newvalue)) self.setVar("__recipe_sanity_renames", renames) DataSmart.renameVar = myrename } addhandler recipe_sanity_eh recipe_sanity_eh[eventmask] = "bb.event.ConfigParsed"