summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/parse/parse_py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/parse/parse_py')
-rw-r--r--bitbake/lib/bb/parse/parse_py/BBHandler.py125
-rw-r--r--bitbake/lib/bb/parse/parse_py/ConfHandler.py58
2 files changed, 125 insertions, 58 deletions
diff --git a/bitbake/lib/bb/parse/parse_py/BBHandler.py b/bitbake/lib/bb/parse/parse_py/BBHandler.py
index f8988b8631..008fec2308 100644
--- a/bitbake/lib/bb/parse/parse_py/BBHandler.py
+++ b/bitbake/lib/bb/parse/parse_py/BBHandler.py
@@ -19,14 +19,12 @@ from . import ConfHandler
19from .. import resolve_file, ast, logger, ParseError 19from .. import resolve_file, ast, logger, ParseError
20from .ConfHandler import include, init 20from .ConfHandler import include, init
21 21
22# For compatibility 22__func_start_regexp__ = re.compile(r"(((?P<py>python(?=(\s|\()))|(?P<fr>fakeroot(?=\s)))\s*)*(?P<func>[\w\.\-\+\{\}\$:]+)?\s*\(\s*\)\s*{$" )
23bb.deprecate_import(__name__, "bb.parse", ["vars_from_file"])
24
25__func_start_regexp__ = re.compile(r"(((?P<py>python(?=(\s|\()))|(?P<fr>fakeroot(?=\s)))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" )
26__inherit_regexp__ = re.compile(r"inherit\s+(.+)" ) 23__inherit_regexp__ = re.compile(r"inherit\s+(.+)" )
24__inherit_def_regexp__ = re.compile(r"inherit_defer\s+(.+)" )
27__export_func_regexp__ = re.compile(r"EXPORT_FUNCTIONS\s+(.+)" ) 25__export_func_regexp__ = re.compile(r"EXPORT_FUNCTIONS\s+(.+)" )
28__addtask_regexp__ = re.compile(r"addtask\s+(?P<func>\w+)\s*((before\s*(?P<before>((.*(?=after))|(.*))))|(after\s*(?P<after>((.*(?=before))|(.*)))))*") 26__addtask_regexp__ = re.compile(r"addtask\s+([^#\n]+)(?P<comment>#.*|.*?)")
29__deltask_regexp__ = re.compile(r"deltask\s+(.+)") 27__deltask_regexp__ = re.compile(r"deltask\s+([^#\n]+)(?P<comment>#.*|.*?)")
30__addhandler_regexp__ = re.compile(r"addhandler\s+(.+)" ) 28__addhandler_regexp__ = re.compile(r"addhandler\s+(.+)" )
31__def_regexp__ = re.compile(r"def\s+(\w+).*:" ) 29__def_regexp__ = re.compile(r"def\s+(\w+).*:" )
32__python_func_regexp__ = re.compile(r"(\s+.*)|(^$)|(^#)" ) 30__python_func_regexp__ = re.compile(r"(\s+.*)|(^$)|(^#)" )
@@ -36,6 +34,7 @@ __infunc__ = []
36__inpython__ = False 34__inpython__ = False
37__body__ = [] 35__body__ = []
38__classname__ = "" 36__classname__ = ""
37__residue__ = []
39 38
40cached_statements = {} 39cached_statements = {}
41 40
@@ -43,31 +42,56 @@ def supports(fn, d):
43 """Return True if fn has a supported extension""" 42 """Return True if fn has a supported extension"""
44 return os.path.splitext(fn)[-1] in [".bb", ".bbclass", ".inc"] 43 return os.path.splitext(fn)[-1] in [".bb", ".bbclass", ".inc"]
45 44
46def inherit(files, fn, lineno, d): 45def inherit_defer(expression, fn, lineno, d):
46 inherit = (expression, fn, lineno)
47 inherits = d.getVar('__BBDEFINHERITS', False) or []
48 inherits.append(inherit)
49 d.setVar('__BBDEFINHERITS', inherits)
50
51def inherit(files, fn, lineno, d, deferred=False):
47 __inherit_cache = d.getVar('__inherit_cache', False) or [] 52 __inherit_cache = d.getVar('__inherit_cache', False) or []
53 #if "${" in files and not deferred:
54 # bb.warn("%s:%s has non deferred conditional inherit" % (fn, lineno))
48 files = d.expand(files).split() 55 files = d.expand(files).split()
49 for file in files: 56 for file in files:
50 if not os.path.isabs(file) and not file.endswith(".bbclass"): 57 defer = (d.getVar("BB_DEFER_BBCLASSES") or "").split()
51 file = os.path.join('classes', '%s.bbclass' % file) 58 if not deferred and file in defer:
52 59 inherit_defer(file, fn, lineno, d)
53 if not os.path.isabs(file): 60 continue
54 bbpath = d.getVar("BBPATH") 61 classtype = d.getVar("__bbclasstype", False)
55 abs_fn, attempts = bb.utils.which(bbpath, file, history=True) 62 origfile = file
56 for af in attempts: 63 for t in ["classes-" + classtype, "classes"]:
57 if af != abs_fn: 64 file = origfile
58 bb.parse.mark_dependency(d, af) 65 if not os.path.isabs(file) and not file.endswith(".bbclass"):
59 if abs_fn: 66 file = os.path.join(t, '%s.bbclass' % file)
60 file = abs_fn 67
68 if not os.path.isabs(file):
69 bbpath = d.getVar("BBPATH")
70 abs_fn, attempts = bb.utils.which(bbpath, file, history=True)
71 for af in attempts:
72 if af != abs_fn:
73 bb.parse.mark_dependency(d, af)
74 if abs_fn:
75 file = abs_fn
76
77 if os.path.exists(file):
78 break
79
80 if not os.path.exists(file):
81 raise ParseError("Could not inherit file %s" % (file), fn, lineno)
61 82
62 if not file in __inherit_cache: 83 if not file in __inherit_cache:
63 logger.debug("Inheriting %s (from %s:%d)" % (file, fn, lineno)) 84 logger.debug("Inheriting %s (from %s:%d)" % (file, fn, lineno))
64 __inherit_cache.append( file ) 85 __inherit_cache.append( file )
65 d.setVar('__inherit_cache', __inherit_cache) 86 d.setVar('__inherit_cache', __inherit_cache)
66 include(fn, file, lineno, d, "inherit") 87 try:
88 bb.parse.handle(file, d, True)
89 except (IOError, OSError) as exc:
90 raise ParseError("Could not inherit file %s: %s" % (fn, exc.strerror), fn, lineno)
67 __inherit_cache = d.getVar('__inherit_cache', False) or [] 91 __inherit_cache = d.getVar('__inherit_cache', False) or []
68 92
69def get_statements(filename, absolute_filename, base_name): 93def get_statements(filename, absolute_filename, base_name):
70 global cached_statements 94 global cached_statements, __residue__, __body__
71 95
72 try: 96 try:
73 return cached_statements[absolute_filename] 97 return cached_statements[absolute_filename]
@@ -87,12 +111,17 @@ def get_statements(filename, absolute_filename, base_name):
87 # add a blank line to close out any python definition 111 # add a blank line to close out any python definition
88 feeder(lineno, "", filename, base_name, statements, eof=True) 112 feeder(lineno, "", filename, base_name, statements, eof=True)
89 113
114 if __residue__:
115 raise ParseError("Unparsed lines %s: %s" % (filename, str(__residue__)), filename, lineno)
116 if __body__:
117 raise ParseError("Unparsed lines from unclosed function %s: %s" % (filename, str(__body__)), filename, lineno)
118
90 if filename.endswith(".bbclass") or filename.endswith(".inc"): 119 if filename.endswith(".bbclass") or filename.endswith(".inc"):
91 cached_statements[absolute_filename] = statements 120 cached_statements[absolute_filename] = statements
92 return statements 121 return statements
93 122
94def handle(fn, d, include): 123def handle(fn, d, include, baseconfig=False):
95 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __residue__, __classname__ 124 global __infunc__, __body__, __residue__, __classname__
96 __body__ = [] 125 __body__ = []
97 __infunc__ = [] 126 __infunc__ = []
98 __classname__ = "" 127 __classname__ = ""
@@ -144,7 +173,7 @@ def handle(fn, d, include):
144 return d 173 return d
145 174
146def feeder(lineno, s, fn, root, statements, eof=False): 175def feeder(lineno, s, fn, root, statements, eof=False):
147 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__, __infunc__, __body__, bb, __residue__, __classname__ 176 global __inpython__, __infunc__, __body__, __residue__, __classname__
148 177
149 # Check tabs in python functions: 178 # Check tabs in python functions:
150 # - def py_funcname(): covered by __inpython__ 179 # - def py_funcname(): covered by __inpython__
@@ -181,10 +210,10 @@ def feeder(lineno, s, fn, root, statements, eof=False):
181 210
182 if s and s[0] == '#': 211 if s and s[0] == '#':
183 if len(__residue__) != 0 and __residue__[0][0] != "#": 212 if len(__residue__) != 0 and __residue__[0][0] != "#":
184 bb.fatal("There is a comment on line %s of file %s (%s) which is in the middle of a multiline expression.\nBitbake used to ignore these but no longer does so, please fix your metadata as errors are likely as a result of this change." % (lineno, fn, s)) 213 bb.fatal("There is a comment on line %s of file %s:\n'''\n%s\n'''\nwhich is in the middle of a multiline expression. This syntax is invalid, please correct it." % (lineno, fn, s))
185 214
186 if len(__residue__) != 0 and __residue__[0][0] == "#" and (not s or s[0] != "#"): 215 if len(__residue__) != 0 and __residue__[0][0] == "#" and (not s or s[0] != "#"):
187 bb.fatal("There is a confusing multiline, partially commented expression on line %s of file %s (%s).\nPlease clarify whether this is all a comment or should be parsed." % (lineno, fn, s)) 216 bb.fatal("There is a confusing multiline partially commented expression on line %s of file %s:\n%s\nPlease clarify whether this is all a comment or should be parsed." % (lineno - len(__residue__), fn, "\n".join(__residue__)))
188 217
189 if s and s[-1] == '\\': 218 if s and s[-1] == '\\':
190 __residue__.append(s[:-1]) 219 __residue__.append(s[:-1])
@@ -220,29 +249,38 @@ def feeder(lineno, s, fn, root, statements, eof=False):
220 249
221 m = __addtask_regexp__.match(s) 250 m = __addtask_regexp__.match(s)
222 if m: 251 if m:
223 if len(m.group().split()) == 2: 252 after = ""
224 # Check and warn for "addtask task1 task2" 253 before = ""
225 m2 = re.match(r"addtask\s+(?P<func>\w+)(?P<ignores>.*)", s) 254
226 if m2 and m2.group('ignores'): 255 # This code splits on 'before' and 'after' instead of on whitespace so we can defer
227 logger.warning('addtask ignored: "%s"' % m2.group('ignores')) 256 # evaluation to as late as possible.
228 257 tasks = m.group(1).split(" before ")[0].split(" after ")[0]
229 # Check and warn for "addtask task1 before task2 before task3", the 258
230 # similar to "after" 259 for exp in m.group(1).split(" before "):
231 taskexpression = s.split() 260 exp2 = exp.split(" after ")
232 for word in ('before', 'after'): 261 if len(exp2) > 1:
233 if taskexpression.count(word) > 1: 262 after = after + " ".join(exp2[1:])
234 logger.warning("addtask contained multiple '%s' keywords, only one is supported" % word)
235 263
236 # Check and warn for having task with exprssion as part of task name 264 for exp in m.group(1).split(" after "):
265 exp2 = exp.split(" before ")
266 if len(exp2) > 1:
267 before = before + " ".join(exp2[1:])
268
269 # Check and warn for having task with a keyword as part of task name
270 taskexpression = s.split()
237 for te in taskexpression: 271 for te in taskexpression:
238 if any( ( "%s_" % keyword ) in te for keyword in bb.data_smart.__setvar_keyword__ ): 272 if any( ( "%s_" % keyword ) in te for keyword in bb.data_smart.__setvar_keyword__ ):
239 raise ParseError("Task name '%s' contains a keyword which is not recommended/supported.\nPlease rename the task not to include the keyword.\n%s" % (te, ("\n".join(map(str, bb.data_smart.__setvar_keyword__)))), fn) 273 raise ParseError("Task name '%s' contains a keyword which is not recommended/supported.\nPlease rename the task not to include the keyword.\n%s" % (te, ("\n".join(map(str, bb.data_smart.__setvar_keyword__)))), fn)
240 ast.handleAddTask(statements, fn, lineno, m) 274
275 if tasks is not None:
276 ast.handleAddTask(statements, fn, lineno, tasks, before, after)
241 return 277 return
242 278
243 m = __deltask_regexp__.match(s) 279 m = __deltask_regexp__.match(s)
244 if m: 280 if m:
245 ast.handleDelTask(statements, fn, lineno, m) 281 task = m.group(1)
282 if task is not None:
283 ast.handleDelTask(statements, fn, lineno, task)
246 return 284 return
247 285
248 m = __addhandler_regexp__.match(s) 286 m = __addhandler_regexp__.match(s)
@@ -255,7 +293,12 @@ def feeder(lineno, s, fn, root, statements, eof=False):
255 ast.handleInherit(statements, fn, lineno, m) 293 ast.handleInherit(statements, fn, lineno, m)
256 return 294 return
257 295
258 return ConfHandler.feeder(lineno, s, fn, statements) 296 m = __inherit_def_regexp__.match(s)
297 if m:
298 ast.handleInheritDeferred(statements, fn, lineno, m)
299 return
300
301 return ConfHandler.feeder(lineno, s, fn, statements, conffile=False)
259 302
260# Add us to the handlers list 303# Add us to the handlers list
261from .. import handlers 304from .. import handlers
diff --git a/bitbake/lib/bb/parse/parse_py/ConfHandler.py b/bitbake/lib/bb/parse/parse_py/ConfHandler.py
index f171c5c932..9ddbae123d 100644
--- a/bitbake/lib/bb/parse/parse_py/ConfHandler.py
+++ b/bitbake/lib/bb/parse/parse_py/ConfHandler.py
@@ -20,10 +20,10 @@ from bb.parse import ParseError, resolve_file, ast, logger, handle
20__config_regexp__ = re.compile( r""" 20__config_regexp__ = re.compile( r"""
21 ^ 21 ^
22 (?P<exp>export\s+)? 22 (?P<exp>export\s+)?
23 (?P<var>[a-zA-Z0-9\-_+.${}/~]+?) 23 (?P<var>[a-zA-Z0-9\-_+.${}/~:]*?)
24 (\[(?P<flag>[a-zA-Z0-9\-_+.]+)\])? 24 (\[(?P<flag>[a-zA-Z0-9\-_+.][a-zA-Z0-9\-_+.@/]*)\])?
25 25
26 \s* ( 26 (?P<whitespace>\s*) (
27 (?P<colon>:=) | 27 (?P<colon>:=) |
28 (?P<lazyques>\?\?=) | 28 (?P<lazyques>\?\?=) |
29 (?P<ques>\?=) | 29 (?P<ques>\?=) |
@@ -32,7 +32,7 @@ __config_regexp__ = re.compile( r"""
32 (?P<predot>=\.) | 32 (?P<predot>=\.) |
33 (?P<postdot>\.=) | 33 (?P<postdot>\.=) |
34 = 34 =
35 ) \s* 35 ) (?P<whitespace2>\s*)
36 36
37 (?!'[^']*'[^']*'$) 37 (?!'[^']*'[^']*'$)
38 (?!\"[^\"]*\"[^\"]*\"$) 38 (?!\"[^\"]*\"[^\"]*\"$)
@@ -43,15 +43,15 @@ __config_regexp__ = re.compile( r"""
43 """, re.X) 43 """, re.X)
44__include_regexp__ = re.compile( r"include\s+(.+)" ) 44__include_regexp__ = re.compile( r"include\s+(.+)" )
45__require_regexp__ = re.compile( r"require\s+(.+)" ) 45__require_regexp__ = re.compile( r"require\s+(.+)" )
46__includeall_regexp__ = re.compile( r"include_all\s+(.+)" )
46__export_regexp__ = re.compile( r"export\s+([a-zA-Z0-9\-_+.${}/~]+)$" ) 47__export_regexp__ = re.compile( r"export\s+([a-zA-Z0-9\-_+.${}/~]+)$" )
47__unset_regexp__ = re.compile( r"unset\s+([a-zA-Z0-9\-_+.${}/~]+)$" ) 48__unset_regexp__ = re.compile( r"unset\s+([a-zA-Z0-9\-_+.${}/~]+)$" )
48__unset_flag_regexp__ = re.compile( r"unset\s+([a-zA-Z0-9\-_+.${}/~]+)\[([a-zA-Z0-9\-_+.]+)\]$" ) 49__unset_flag_regexp__ = re.compile( r"unset\s+([a-zA-Z0-9\-_+.${}/~]+)\[([a-zA-Z0-9\-_+.][a-zA-Z0-9\-_+.@]+)\]$" )
50__addpylib_regexp__ = re.compile(r"addpylib\s+(.+)\s+(.+)" )
51__addfragments_regexp__ = re.compile(r"addfragments\s+(.+)\s+(.+)\s+(.+)\s+(.+)" )
49 52
50def init(data): 53def init(data):
51 topdir = data.getVar('TOPDIR', False) 54 return
52 if not topdir:
53 data.setVar('TOPDIR', os.getcwd())
54
55 55
56def supports(fn, d): 56def supports(fn, d):
57 return fn[-5:] == ".conf" 57 return fn[-5:] == ".conf"
@@ -105,12 +105,12 @@ def include_single_file(parentfn, fn, lineno, data, error_out):
105# We have an issue where a UI might want to enforce particular settings such as 105# We have an issue where a UI might want to enforce particular settings such as
106# an empty DISTRO variable. If configuration files do something like assigning 106# an empty DISTRO variable. If configuration files do something like assigning
107# a weak default, it turns out to be very difficult to filter out these changes, 107# a weak default, it turns out to be very difficult to filter out these changes,
108# particularly when the weak default might appear half way though parsing a chain 108# particularly when the weak default might appear half way though parsing a chain
109# of configuration files. We therefore let the UIs hook into configuration file 109# of configuration files. We therefore let the UIs hook into configuration file
110# parsing. This turns out to be a hard problem to solve any other way. 110# parsing. This turns out to be a hard problem to solve any other way.
111confFilters = [] 111confFilters = []
112 112
113def handle(fn, data, include): 113def handle(fn, data, include, baseconfig=False):
114 init(data) 114 init(data)
115 115
116 if include == 0: 116 if include == 0:
@@ -128,21 +128,26 @@ def handle(fn, data, include):
128 s = f.readline() 128 s = f.readline()
129 if not s: 129 if not s:
130 break 130 break
131 origlineno = lineno
132 origline = s
131 w = s.strip() 133 w = s.strip()
132 # skip empty lines 134 # skip empty lines
133 if not w: 135 if not w:
134 continue 136 continue
135 s = s.rstrip() 137 s = s.rstrip()
136 while s[-1] == '\\': 138 while s[-1] == '\\':
137 s2 = f.readline().rstrip() 139 line = f.readline()
140 origline += line
141 s2 = line.rstrip()
138 lineno = lineno + 1 142 lineno = lineno + 1
139 if (not s2 or s2 and s2[0] != "#") and s[0] == "#" : 143 if (not s2 or s2 and s2[0] != "#") and s[0] == "#" :
140 bb.fatal("There is a confusing multiline, partially commented expression on line %s of file %s (%s).\nPlease clarify whether this is all a comment or should be parsed." % (lineno, fn, s)) 144 bb.fatal("There is a confusing multiline, partially commented expression starting on line %s of file %s:\n%s\nPlease clarify whether this is all a comment or should be parsed." % (origlineno, fn, origline))
145
141 s = s[:-1] + s2 146 s = s[:-1] + s2
142 # skip comments 147 # skip comments
143 if s[0] == '#': 148 if s[0] == '#':
144 continue 149 continue
145 feeder(lineno, s, abs_fn, statements) 150 feeder(lineno, s, abs_fn, statements, baseconfig=baseconfig)
146 151
147 # DONE WITH PARSING... time to evaluate 152 # DONE WITH PARSING... time to evaluate
148 data.setVar('FILE', abs_fn) 153 data.setVar('FILE', abs_fn)
@@ -150,17 +155,21 @@ def handle(fn, data, include):
150 if oldfile: 155 if oldfile:
151 data.setVar('FILE', oldfile) 156 data.setVar('FILE', oldfile)
152 157
153 f.close()
154
155 for f in confFilters: 158 for f in confFilters:
156 f(fn, data) 159 f(fn, data)
157 160
158 return data 161 return data
159 162
160def feeder(lineno, s, fn, statements): 163# baseconfig is set for the bblayers/layer.conf cookerdata config parsing
164# The function is also used by BBHandler, conffile would be False
165def feeder(lineno, s, fn, statements, baseconfig=False, conffile=True):
161 m = __config_regexp__.match(s) 166 m = __config_regexp__.match(s)
162 if m: 167 if m:
163 groupd = m.groupdict() 168 groupd = m.groupdict()
169 if groupd['var'] == "":
170 raise ParseError("Empty variable name in assignment: '%s'" % s, fn, lineno);
171 if not groupd['whitespace'] or not groupd['whitespace2']:
172 logger.warning("%s:%s has a lack of whitespace around the assignment: '%s'" % (fn, lineno, s))
164 ast.handleData(statements, fn, lineno, groupd) 173 ast.handleData(statements, fn, lineno, groupd)
165 return 174 return
166 175
@@ -174,6 +183,11 @@ def feeder(lineno, s, fn, statements):
174 ast.handleInclude(statements, fn, lineno, m, True) 183 ast.handleInclude(statements, fn, lineno, m, True)
175 return 184 return
176 185
186 m = __includeall_regexp__.match(s)
187 if m:
188 ast.handleIncludeAll(statements, fn, lineno, m)
189 return
190
177 m = __export_regexp__.match(s) 191 m = __export_regexp__.match(s)
178 if m: 192 if m:
179 ast.handleExport(statements, fn, lineno, m) 193 ast.handleExport(statements, fn, lineno, m)
@@ -189,6 +203,16 @@ def feeder(lineno, s, fn, statements):
189 ast.handleUnsetFlag(statements, fn, lineno, m) 203 ast.handleUnsetFlag(statements, fn, lineno, m)
190 return 204 return
191 205
206 m = __addpylib_regexp__.match(s)
207 if baseconfig and conffile and m:
208 ast.handlePyLib(statements, fn, lineno, m)
209 return
210
211 m = __addfragments_regexp__.match(s)
212 if m:
213 ast.handleAddFragments(statements, fn, lineno, m)
214 return
215
192 raise ParseError("unparsed line: '%s'" % s, fn, lineno); 216 raise ParseError("unparsed line: '%s'" % s, fn, lineno);
193 217
194# Add us to the handlers list 218# Add us to the handlers list