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.py258
-rw-r--r--bitbake/lib/bb/parse/parse_py/ConfHandler.py182
-rw-r--r--bitbake/lib/bb/parse/parse_py/__init__.py33
3 files changed, 473 insertions, 0 deletions
diff --git a/bitbake/lib/bb/parse/parse_py/BBHandler.py b/bitbake/lib/bb/parse/parse_py/BBHandler.py
new file mode 100644
index 0000000000..01f22d3b24
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_py/BBHandler.py
@@ -0,0 +1,258 @@
1#!/usr/bin/env python
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4"""
5 class for handling .bb files
6
7 Reads a .bb file and obtains its metadata
8
9"""
10
11
12# Copyright (C) 2003, 2004 Chris Larson
13# Copyright (C) 2003, 2004 Phil Blundell
14#
15# This program is free software; you can redistribute it and/or modify
16# it under the terms of the GNU General Public License version 2 as
17# published by the Free Software Foundation.
18#
19# This program is distributed in the hope that it will be useful,
20# but WITHOUT ANY WARRANTY; without even the implied warranty of
21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22# GNU General Public License for more details.
23#
24# You should have received a copy of the GNU General Public License along
25# with this program; if not, write to the Free Software Foundation, Inc.,
26# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27
28from __future__ import absolute_import
29import re, bb, os
30import logging
31import bb.build, bb.utils
32from bb import data
33
34from . import ConfHandler
35from .. import resolve_file, ast, logger
36from .ConfHandler import include, init
37
38# For compatibility
39bb.deprecate_import(__name__, "bb.parse", ["vars_from_file"])
40
41__func_start_regexp__ = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" )
42__inherit_regexp__ = re.compile( r"inherit\s+(.+)" )
43__export_func_regexp__ = re.compile( r"EXPORT_FUNCTIONS\s+(.+)" )
44__addtask_regexp__ = re.compile("addtask\s+(?P<func>\w+)\s*((before\s*(?P<before>((.*(?=after))|(.*))))|(after\s*(?P<after>((.*(?=before))|(.*)))))*")
45__addhandler_regexp__ = re.compile( r"addhandler\s+(.+)" )
46__def_regexp__ = re.compile( r"def\s+(\w+).*:" )
47__python_func_regexp__ = re.compile( r"(\s+.*)|(^$)" )
48
49
50__infunc__ = ""
51__inpython__ = False
52__body__ = []
53__classname__ = ""
54
55cached_statements = {}
56
57# We need to indicate EOF to the feeder. This code is so messy that
58# factoring it out to a close_parse_file method is out of question.
59# We will use the IN_PYTHON_EOF as an indicator to just close the method
60#
61# The two parts using it are tightly integrated anyway
62IN_PYTHON_EOF = -9999999999999
63
64
65
66def supports(fn, d):
67 """Return True if fn has a supported extension"""
68 return os.path.splitext(fn)[-1] in [".bb", ".bbclass", ".inc"]
69
70def inherit(files, fn, lineno, d):
71 __inherit_cache = d.getVar('__inherit_cache') or []
72 files = d.expand(files).split()
73 for file in files:
74 if not os.path.isabs(file) and not file.endswith(".bbclass"):
75 file = os.path.join('classes', '%s.bbclass' % file)
76
77 if not os.path.isabs(file):
78 dname = os.path.dirname(fn)
79 bbpath = "%s:%s" % (dname, d.getVar("BBPATH", True))
80 abs_fn = bb.utils.which(bbpath, file)
81 if abs_fn:
82 file = abs_fn
83
84 if not file in __inherit_cache:
85 logger.log(logging.DEBUG -1, "BB %s:%d: inheriting %s", fn, lineno, file)
86 __inherit_cache.append( file )
87 d.setVar('__inherit_cache', __inherit_cache)
88 include(fn, file, lineno, d, "inherit")
89 __inherit_cache = d.getVar('__inherit_cache') or []
90
91def get_statements(filename, absolute_filename, base_name):
92 global cached_statements
93
94 try:
95 return cached_statements[absolute_filename]
96 except KeyError:
97 file = open(absolute_filename, 'r')
98 statements = ast.StatementGroup()
99
100 lineno = 0
101 while True:
102 lineno = lineno + 1
103 s = file.readline()
104 if not s: break
105 s = s.rstrip()
106 feeder(lineno, s, filename, base_name, statements)
107 file.close()
108 if __inpython__:
109 # add a blank line to close out any python definition
110 feeder(IN_PYTHON_EOF, "", filename, base_name, statements)
111
112 if filename.endswith(".bbclass") or filename.endswith(".inc"):
113 cached_statements[absolute_filename] = statements
114 return statements
115
116def handle(fn, d, include):
117 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __residue__, __classname__
118 __body__ = []
119 __infunc__ = ""
120 __classname__ = ""
121 __residue__ = []
122
123
124 if include == 0:
125 logger.debug(2, "BB %s: handle(data)", fn)
126 else:
127 logger.debug(2, "BB %s: handle(data, include)", fn)
128
129 base_name = os.path.basename(fn)
130 (root, ext) = os.path.splitext(base_name)
131 init(d)
132
133 if ext == ".bbclass":
134 __classname__ = root
135 __inherit_cache = d.getVar('__inherit_cache') or []
136 if not fn in __inherit_cache:
137 __inherit_cache.append(fn)
138 d.setVar('__inherit_cache', __inherit_cache)
139
140 if include != 0:
141 oldfile = d.getVar('FILE')
142 else:
143 oldfile = None
144
145 abs_fn = resolve_file(fn, d)
146
147 if include:
148 bb.parse.mark_dependency(d, abs_fn)
149
150 # actual loading
151 statements = get_statements(fn, abs_fn, base_name)
152
153 # DONE WITH PARSING... time to evaluate
154 if ext != ".bbclass":
155 d.setVar('FILE', abs_fn)
156
157 try:
158 statements.eval(d)
159 except bb.parse.SkipPackage:
160 bb.data.setVar("__SKIPPED", True, d)
161 if include == 0:
162 return { "" : d }
163
164 if ext != ".bbclass" and include == 0:
165 return ast.multi_finalize(fn, d)
166
167 if oldfile:
168 d.setVar("FILE", oldfile)
169
170 return d
171
172def feeder(lineno, s, fn, root, statements):
173 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__, __infunc__, __body__, bb, __residue__, __classname__
174 if __infunc__:
175 if s == '}':
176 __body__.append('')
177 ast.handleMethod(statements, fn, lineno, __infunc__, __body__)
178 __infunc__ = ""
179 __body__ = []
180 else:
181 __body__.append(s)
182 return
183
184 if __inpython__:
185 m = __python_func_regexp__.match(s)
186 if m and lineno != IN_PYTHON_EOF:
187 __body__.append(s)
188 return
189 else:
190 ast.handlePythonMethod(statements, fn, lineno, __inpython__,
191 root, __body__)
192 __body__ = []
193 __inpython__ = False
194
195 if lineno == IN_PYTHON_EOF:
196 return
197
198 if s and s[0] == '#':
199 if len(__residue__) != 0 and __residue__[0][0] != "#":
200 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))
201
202 if len(__residue__) != 0 and __residue__[0][0] == "#" and (not s or s[0] != "#"):
203 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))
204
205 if s and s[-1] == '\\':
206 __residue__.append(s[:-1])
207 return
208
209 s = "".join(__residue__) + s
210 __residue__ = []
211
212 # Skip empty lines
213 if s == '':
214 return
215
216 # Skip comments
217 if s[0] == '#':
218 return
219
220 m = __func_start_regexp__.match(s)
221 if m:
222 __infunc__ = m.group("func") or "__anonymous"
223 ast.handleMethodFlags(statements, fn, lineno, __infunc__, m)
224 return
225
226 m = __def_regexp__.match(s)
227 if m:
228 __body__.append(s)
229 __inpython__ = m.group(1)
230
231 return
232
233 m = __export_func_regexp__.match(s)
234 if m:
235 ast.handleExportFuncs(statements, fn, lineno, m, __classname__)
236 return
237
238 m = __addtask_regexp__.match(s)
239 if m:
240 ast.handleAddTask(statements, fn, lineno, m)
241 return
242
243 m = __addhandler_regexp__.match(s)
244 if m:
245 ast.handleBBHandlers(statements, fn, lineno, m)
246 return
247
248 m = __inherit_regexp__.match(s)
249 if m:
250 ast.handleInherit(statements, fn, lineno, m)
251 return
252
253 return ConfHandler.feeder(lineno, s, fn, statements)
254
255# Add us to the handlers list
256from .. import handlers
257handlers.append({'supports': supports, 'handle': handle, 'init': init})
258del handlers
diff --git a/bitbake/lib/bb/parse/parse_py/ConfHandler.py b/bitbake/lib/bb/parse/parse_py/ConfHandler.py
new file mode 100644
index 0000000000..7b30c8acb3
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_py/ConfHandler.py
@@ -0,0 +1,182 @@
1#!/usr/bin/env python
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4"""
5 class for handling configuration data files
6
7 Reads a .conf file and obtains its metadata
8
9"""
10
11# Copyright (C) 2003, 2004 Chris Larson
12# Copyright (C) 2003, 2004 Phil Blundell
13#
14# This program is free software; you can redistribute it and/or modify
15# it under the terms of the GNU General Public License version 2 as
16# published by the Free Software Foundation.
17#
18# This program is distributed in the hope that it will be useful,
19# but WITHOUT ANY WARRANTY; without even the implied warranty of
20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21# GNU General Public License for more details.
22#
23# You should have received a copy of the GNU General Public License along
24# with this program; if not, write to the Free Software Foundation, Inc.,
25# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26
27import re, os
28import logging
29import bb.utils
30from bb.parse import ParseError, resolve_file, ast, logger
31
32__config_regexp__ = re.compile( r"""
33 ^
34 (?P<exp>export\s*)?
35 (?P<var>[a-zA-Z0-9\-~_+.${}/]+?)
36 (\[(?P<flag>[a-zA-Z0-9\-_+.]+)\])?
37
38 \s* (
39 (?P<colon>:=) |
40 (?P<lazyques>\?\?=) |
41 (?P<ques>\?=) |
42 (?P<append>\+=) |
43 (?P<prepend>=\+) |
44 (?P<predot>=\.) |
45 (?P<postdot>\.=) |
46 =
47 ) \s*
48
49 (?!'[^']*'[^']*'$)
50 (?!\"[^\"]*\"[^\"]*\"$)
51 (?P<apo>['\"])
52 (?P<value>.*)
53 (?P=apo)
54 $
55 """, re.X)
56__include_regexp__ = re.compile( r"include\s+(.+)" )
57__require_regexp__ = re.compile( r"require\s+(.+)" )
58__export_regexp__ = re.compile( r"export\s+([a-zA-Z0-9\-_+.${}/]+)$" )
59
60def init(data):
61 topdir = data.getVar('TOPDIR')
62 if not topdir:
63 data.setVar('TOPDIR', os.getcwd())
64
65
66def supports(fn, d):
67 return fn[-5:] == ".conf"
68
69def include(oldfn, fn, lineno, data, error_out):
70 """
71 error_out: A string indicating the verb (e.g. "include", "inherit") to be
72 used in a ParseError that will be raised if the file to be included could
73 not be included. Specify False to avoid raising an error in this case.
74 """
75 if oldfn == fn: # prevent infinite recursion
76 return None
77
78 import bb
79 fn = data.expand(fn)
80 oldfn = data.expand(oldfn)
81
82 if not os.path.isabs(fn):
83 dname = os.path.dirname(oldfn)
84 bbpath = "%s:%s" % (dname, data.getVar("BBPATH", True))
85 abs_fn = bb.utils.which(bbpath, fn)
86 if abs_fn:
87 fn = abs_fn
88
89 from bb.parse import handle
90 try:
91 ret = handle(fn, data, True)
92 except (IOError, OSError):
93 if error_out:
94 raise ParseError("Could not %(error_out)s file %(fn)s" % vars(), oldfn, lineno)
95 logger.debug(2, "CONF file '%s' not found", fn)
96
97# We have an issue where a UI might want to enforce particular settings such as
98# an empty DISTRO variable. If configuration files do something like assigning
99# a weak default, it turns out to be very difficult to filter out these changes,
100# particularly when the weak default might appear half way though parsing a chain
101# of configuration files. We therefore let the UIs hook into configuration file
102# parsing. This turns out to be a hard problem to solve any other way.
103confFilters = []
104
105def handle(fn, data, include):
106 init(data)
107
108 if include == 0:
109 oldfile = None
110 else:
111 oldfile = data.getVar('FILE')
112
113 abs_fn = resolve_file(fn, data)
114 f = open(abs_fn, 'r')
115
116 if include:
117 bb.parse.mark_dependency(data, abs_fn)
118
119 statements = ast.StatementGroup()
120 lineno = 0
121 while True:
122 lineno = lineno + 1
123 s = f.readline()
124 if not s:
125 break
126 w = s.strip()
127 # skip empty lines
128 if not w:
129 continue
130 s = s.rstrip()
131 while s[-1] == '\\':
132 s2 = f.readline().strip()
133 lineno = lineno + 1
134 if (not s2 or s2 and s2[0] != "#") and s[0] == "#" :
135 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))
136 s = s[:-1] + s2
137 # skip comments
138 if s[0] == '#':
139 continue
140 feeder(lineno, s, fn, statements)
141
142 # DONE WITH PARSING... time to evaluate
143 data.setVar('FILE', abs_fn)
144 statements.eval(data)
145 if oldfile:
146 data.setVar('FILE', oldfile)
147
148 f.close()
149
150 for f in confFilters:
151 f(fn, data)
152
153 return data
154
155def feeder(lineno, s, fn, statements):
156 m = __config_regexp__.match(s)
157 if m:
158 groupd = m.groupdict()
159 ast.handleData(statements, fn, lineno, groupd)
160 return
161
162 m = __include_regexp__.match(s)
163 if m:
164 ast.handleInclude(statements, fn, lineno, m, False)
165 return
166
167 m = __require_regexp__.match(s)
168 if m:
169 ast.handleInclude(statements, fn, lineno, m, True)
170 return
171
172 m = __export_regexp__.match(s)
173 if m:
174 ast.handleExport(statements, fn, lineno, m)
175 return
176
177 raise ParseError("unparsed line: '%s'" % s, fn, lineno);
178
179# Add us to the handlers list
180from bb.parse import handlers
181handlers.append({'supports': supports, 'handle': handle, 'init': init})
182del handlers
diff --git a/bitbake/lib/bb/parse/parse_py/__init__.py b/bitbake/lib/bb/parse/parse_py/__init__.py
new file mode 100644
index 0000000000..3e658d0de9
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_py/__init__.py
@@ -0,0 +1,33 @@
1#!/usr/bin/env python
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4"""
5BitBake Parsers
6
7File parsers for the BitBake build tools.
8
9"""
10
11# Copyright (C) 2003, 2004 Chris Larson
12# Copyright (C) 2003, 2004 Phil Blundell
13#
14# This program is free software; you can redistribute it and/or modify
15# it under the terms of the GNU General Public License version 2 as
16# published by the Free Software Foundation.
17#
18# This program is distributed in the hope that it will be useful,
19# but WITHOUT ANY WARRANTY; without even the implied warranty of
20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21# GNU General Public License for more details.
22#
23# You should have received a copy of the GNU General Public License along
24# with this program; if not, write to the Free Software Foundation, Inc.,
25# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26#
27# Based on functions from the base bb module, Copyright 2003 Holger Schurig
28
29from __future__ import absolute_import
30from . import ConfHandler
31from . import BBHandler
32
33__version__ = '1.0'