Merge branch 'org.openembedded.dev' of ssh+git://git@git.openembedded.net/openembedde...
[openembedded.git] / classes / recipe_sanity.bbclass
1 def __note(msg, d):
2     bb.note("%s: recipe_sanity: %s" % (d.getVar("P", 1), msg))
3
4 __recipe_sanity_badruntimevars = "RDEPENDS RPROVIDES RRECOMMENDS RCONFLICTS"
5 def bad_runtime_vars(cfgdata, d):
6     if bb.data.inherits_class("native", d) or \
7        bb.data.inherits_class("cross", d):
8         return
9
10     for var in d.getVar("__recipe_sanity_badruntimevars", 1).split():
11         val = d.getVar(var, 0)
12         if val and val != cfgdata.get(var):
13             __note("%s should be %s_${PN}" % (var, var), d)
14
15 __recipe_sanity_reqvars = "DESCRIPTION"
16 __recipe_sanity_reqdiffvars = "LICENSE"
17 def req_vars(cfgdata, d):
18     for var in d.getVar("__recipe_sanity_reqvars", 1).split():
19         if not d.getVar(var, 0):
20             __note("%s should be set" % var, d)
21
22     for var in d.getVar("__recipe_sanity_reqdiffvars", 1).split():
23         val = d.getVar(var, 0)
24         cfgval = cfgdata.get(var)
25
26         # Hardcoding is bad, but I'm lazy.  We don't care about license being
27         # unset if the recipe has no sources!
28         if var == "LICENSE" and d.getVar("SRC_URI", 1) == cfgdata.get("SRC_URI"):
29             continue
30
31         if not val:
32             __note("%s should be set" % var, d)
33         elif val == cfgval:
34             __note("%s should be defined to something other than default (%s)" % (var, cfgval), d)
35
36 def var_renames_overwrite(cfgdata, d):
37     renames = d.getVar("__recipe_sanity_renames", 0)
38     if renames:
39         for (key, newkey, oldvalue, newvalue) in renames:
40             if oldvalue != newvalue and oldvalue != cfgdata.get(newkey):
41                 __note("rename of variable '%s' to '%s' overwrote existing value '%s' with '%s'." % (key, newkey, oldvalue, newvalue), d)
42
43 def incorrect_nonempty_PACKAGES(cfgdata, d):
44     if bb.data.inherits_class("native", d) or \
45        bb.data.inherits_class("cross", d):
46         if d.getVar("PACKAGES", 1):
47             return True
48
49 def can_use_autotools_base(cfgdata, d):
50     cfg = d.getVar("do_configure", 1)
51     if not bb.data.inherits_class("autotools", d):
52         return False
53
54     for i in ["autoreconf"] + ["%s_do_configure" % cls for cls in ["gnome", "e", "autotools", "autotools_stage", "efl", "gpephone", "openmoko", "openmoko2", "xfce", "xlibs"]]:
55         if cfg.find(i) != -1:
56             return False
57
58     import os
59     for clsfile in d.getVar("__inherit_cache", 0):
60         (base, _) = os.path.splitext(os.path.basename(clsfile))
61         if cfg.find("%s_do_configure" % base) != -1:
62             __note("autotools_base usage needs verification, spotted %s_do_configure" % base, d)
63
64     return True
65
66 def can_remove_FILESPATH(cfgdata, d):
67     expected = cfgdata.get("FILESPATH")
68     #expected = "${@':'.join([os.path.normpath(os.path.join(fp, p, o)) for fp in d.getVar('FILESPATHBASE', 1).split(':') for p in d.getVar('FILESPATHPKG', 1).split(':') for o in (d.getVar('OVERRIDES', 1) + ':').split(':') if os.path.exists(os.path.join(fp, p, o))])}:${FILESDIR}"
69     expectedpaths = bb.data.expand(expected, d)
70     unexpanded = d.getVar("FILESPATH", 0)
71     filespath = d.getVar("FILESPATH", 1).split(":")
72     filespath = [os.path.normpath(f) for f in filespath if os.path.exists(f)]
73     for fp in filespath:
74         if not fp in expectedpaths:
75             # __note("Path %s in FILESPATH not in the expected paths %s" %
76             # (fp, expectedpaths), d)
77             return False
78     return expected != unexpanded
79
80 def can_remove_FILESDIR(cfgdata, d):
81     expected = cfgdata.get("FILESDIR")
82     #expected = "${@bb.which(d.getVar('FILESPATH', 1), '.')}"
83     unexpanded = d.getVar("FILESDIR", 0)
84     if unexpanded is None:
85         return False
86
87     expanded = os.path.normpath(d.getVar("FILESDIR", 1))
88     filespath = d.getVar("FILESPATH", 1).split(":")
89     filespath = [os.path.normpath(f) for f in filespath if os.path.exists(f)]
90
91     return unexpanded != expected and \
92            os.path.exists(expanded) and \
93            (expanded in filespath or
94             expanded == bb.data.expand(expected, d))
95
96 def can_remove_others(p, cfgdata, d):
97     for k in ["S", "PV", "PN", "DESCRIPTION", "LICENSE", "DEPENDS",
98               "SECTION", "PACKAGES", "EXTRA_OECONF", "EXTRA_OEMAKE"]:
99     #for k in cfgdata:
100         unexpanded = d.getVar(k, 0)
101         cfgunexpanded = cfgdata.get(k)
102         if not cfgunexpanded:
103             continue
104
105         try:
106             expanded = d.getVar(k, 1)
107             cfgexpanded = bb.data.expand(cfgunexpanded, d)
108         except bb.fetch.ParameterError:
109             continue
110
111         if unexpanded != cfgunexpanded and \
112            cfgexpanded == expanded:
113            __note("candidate for removal of %s" % k, d)
114            bb.debug(1, "%s: recipe_sanity:   cfg's '%s' and d's '%s' both expand to %s" %
115                        (p, cfgunexpanded, unexpanded, expanded))
116
117 python do_recipe_sanity () {
118     p = d.getVar("P", 1)
119     p = "%s %s %s" % (d.getVar("PN", 1), d.getVar("PV", 1), d.getVar("PR", 1))
120
121     sanitychecks = [
122         (can_remove_FILESDIR, "candidate for removal of FILESDIR"),
123         (can_remove_FILESPATH, "candidate for removal of FILESPATH"),
124         #(can_use_autotools_base, "candidate for use of autotools_base"),
125         (incorrect_nonempty_PACKAGES, "native or cross recipe with non-empty PACKAGES"),
126     ]
127     cfgdata = d.getVar("__recipe_sanity_cfgdata", 0)
128
129     for (func, msg) in sanitychecks:
130         if func(cfgdata, d):
131             __note(msg, d)
132
133     can_remove_others(p, cfgdata, d)
134     var_renames_overwrite(cfgdata, d)
135     req_vars(cfgdata, d)
136     bad_runtime_vars(cfgdata, d)
137 }
138 do_recipe_sanity[nostamp] = "1"
139 #do_recipe_sanity[recrdeptask] = "do_recipe_sanity"
140 addtask recipe_sanity
141
142 do_recipe_sanity_all[nostamp] = "1"
143 do_recipe_sanity_all[recrdeptask] = "do_recipe_sanity"
144 do_recipe_sanity_all () {
145     :
146 }
147 addtask recipe_sanity_all after do_recipe_sanity
148
149 python recipe_sanity_eh () {
150     from bb.event import getName
151
152     if getName(e) != "ConfigParsed":
153         return NotHandled
154
155     d = e.data
156
157     cfgdata = {}
158     for k in d.keys():
159     #for k in ["S", "PR", "PV", "PN", "DESCRIPTION", "LICENSE", "DEPENDS",
160     #          "SECTION"]:
161         cfgdata[k] = d.getVar(k, 0)
162
163     d.setVar("__recipe_sanity_cfgdata", cfgdata)
164     #d.setVar("__recipe_sanity_cfgdata", d)
165
166     # Sick, very sick..
167     from bb.data_smart import DataSmart
168     old = DataSmart.renameVar
169     def myrename(self, key, newkey):
170         oldvalue = self.getVar(newkey, 0)
171         old(self, key, newkey)
172         newvalue = self.getVar(newkey, 0)
173         if oldvalue:
174             renames = self.getVar("__recipe_sanity_renames", 0) or set()
175             renames.add((key, newkey, oldvalue, newvalue))
176             self.setVar("__recipe_sanity_renames", renames)
177     DataSmart.renameVar = myrename
178 }
179 addhandler recipe_sanity_eh