summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/parse
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/parse')
-rw-r--r--bitbake/lib/bb/parse/__init__.py19
-rw-r--r--bitbake/lib/bb/parse/ast.py60
-rw-r--r--bitbake/lib/bb/parse/parse_py/BBHandler.py33
-rw-r--r--bitbake/lib/bb/parse/parse_py/ConfHandler.py14
-rw-r--r--bitbake/lib/bb/parse/parse_py/__init__.py8
5 files changed, 59 insertions, 75 deletions
diff --git a/bitbake/lib/bb/parse/__init__.py b/bitbake/lib/bb/parse/__init__.py
index 2a7897cdf2..95f372b00b 100644
--- a/bitbake/lib/bb/parse/__init__.py
+++ b/bitbake/lib/bb/parse/__init__.py
@@ -24,11 +24,10 @@ File parsers for the BitBake build tools.
24# 24#
25# Based on functions from the base bb module, Copyright 2003 Holger Schurig 25# Based on functions from the base bb module, Copyright 2003 Holger Schurig
26 26
27__all__ = [ 'ParseError', 'SkipPackage', 'cached_mtime', 'mark_dependency',
28 'supports', 'handle', 'init' ]
29handlers = [] 27handlers = []
30 28
31import bb, os 29import bb, os
30import bb.utils
32 31
33class ParseError(Exception): 32class ParseError(Exception):
34 """Exception raised when parsing fails""" 33 """Exception raised when parsing fails"""
@@ -38,12 +37,12 @@ class SkipPackage(Exception):
38 37
39__mtime_cache = {} 38__mtime_cache = {}
40def cached_mtime(f): 39def cached_mtime(f):
41 if not __mtime_cache.has_key(f): 40 if f not in __mtime_cache:
42 __mtime_cache[f] = os.stat(f)[8] 41 __mtime_cache[f] = os.stat(f)[8]
43 return __mtime_cache[f] 42 return __mtime_cache[f]
44 43
45def cached_mtime_noerror(f): 44def cached_mtime_noerror(f):
46 if not __mtime_cache.has_key(f): 45 if f not in __mtime_cache:
47 try: 46 try:
48 __mtime_cache[f] = os.stat(f)[8] 47 __mtime_cache[f] = os.stat(f)[8]
49 except OSError: 48 except OSError:
@@ -57,8 +56,8 @@ def update_mtime(f):
57def mark_dependency(d, f): 56def mark_dependency(d, f):
58 if f.startswith('./'): 57 if f.startswith('./'):
59 f = "%s/%s" % (os.getcwd(), f[2:]) 58 f = "%s/%s" % (os.getcwd(), f[2:])
60 deps = bb.data.getVar('__depends', d) or [] 59 deps = bb.data.getVar('__depends', d) or set()
61 deps.append( (f, cached_mtime(f)) ) 60 deps.update([(f, cached_mtime(f))])
62 bb.data.setVar('__depends', deps, d) 61 bb.data.setVar('__depends', deps, d)
63 62
64def supports(fn, data): 63def supports(fn, data):
@@ -82,9 +81,11 @@ def init(fn, data):
82 81
83def resolve_file(fn, d): 82def resolve_file(fn, d):
84 if not os.path.isabs(fn): 83 if not os.path.isabs(fn):
85 fn = bb.which(bb.data.getVar("BBPATH", d, 1), fn) 84 bbpath = bb.data.getVar("BBPATH", d, True)
86 if not fn: 85 newfn = bb.which(bbpath, fn)
87 raise IOError("file %s not found" % fn) 86 if not newfn:
87 raise IOError("file %s not found in %s" % (fn, bbpath))
88 fn = newfn
88 89
89 bb.msg.debug(2, bb.msg.domain.Parsing, "LOAD %s" % fn) 90 bb.msg.debug(2, bb.msg.domain.Parsing, "LOAD %s" % fn)
90 return fn 91 return fn
diff --git a/bitbake/lib/bb/parse/ast.py b/bitbake/lib/bb/parse/ast.py
index 59aa44bee0..dae2e11154 100644
--- a/bitbake/lib/bb/parse/ast.py
+++ b/bitbake/lib/bb/parse/ast.py
@@ -21,8 +21,11 @@
21# with this program; if not, write to the Free Software Foundation, Inc., 21# with this program; if not, write to the Free Software Foundation, Inc.,
22# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 23
24from __future__ import absolute_import
25from future_builtins import filter
24import bb, re, string 26import bb, re, string
25from itertools import chain 27from bb import methodpool
28import itertools
26 29
27__word__ = re.compile(r"\S+") 30__word__ = re.compile(r"\S+")
28__parsed_methods__ = bb.methodpool.get_parsed_dict() 31__parsed_methods__ = bb.methodpool.get_parsed_dict()
@@ -30,7 +33,8 @@ _bbversions_re = re.compile(r"\[(?P<from>[0-9]+)-(?P<to>[0-9]+)\]")
30 33
31class StatementGroup(list): 34class StatementGroup(list):
32 def eval(self, data): 35 def eval(self, data):
33 map(lambda x: x.eval(data), self) 36 for statement in self:
37 statement.eval(data)
34 38
35class AstNode(object): 39class AstNode(object):
36 pass 40 pass
@@ -103,7 +107,6 @@ class DataNode(AstNode):
103 val = groupd["value"] 107 val = groupd["value"]
104 108
105 if 'flag' in groupd and groupd['flag'] != None: 109 if 'flag' in groupd and groupd['flag'] != None:
106 bb.msg.debug(3, bb.msg.domain.Parsing, "setVarFlag(%s, %s, %s, data)" % (key, groupd['flag'], val))
107 bb.data.setVarFlag(key, groupd['flag'], val, data) 110 bb.data.setVarFlag(key, groupd['flag'], val, data)
108 elif groupd["lazyques"]: 111 elif groupd["lazyques"]:
109 assigned = bb.data.getVar("__lazy_assigned", data) or [] 112 assigned = bb.data.getVar("__lazy_assigned", data) or []
@@ -143,7 +146,7 @@ class PythonMethodNode(AstNode):
143 # Note we will add root to parsedmethods after having parse 146 # Note we will add root to parsedmethods after having parse
144 # 'this' file. This means we will not parse methods from 147 # 'this' file. This means we will not parse methods from
145 # bb classes twice 148 # bb classes twice
146 if not self.root in __parsed_methods__: 149 if not bb.methodpool.parsed_module(self.root):
147 text = '\n'.join(self.body) 150 text = '\n'.join(self.body)
148 bb.methodpool.insert_method(self.root, text, self.fn) 151 bb.methodpool.insert_method(self.root, text, self.fn)
149 152
@@ -254,7 +257,7 @@ class InheritNode(AstNode):
254 257
255 def eval(self, data): 258 def eval(self, data):
256 bb.parse.BBHandler.inherit(self.n, data) 259 bb.parse.BBHandler.inherit(self.n, data)
257 260
258def handleInclude(statements, m, fn, lineno, force): 261def handleInclude(statements, m, fn, lineno, force):
259 statements.append(IncludeNode(m.group(1), fn, lineno, force)) 262 statements.append(IncludeNode(m.group(1), fn, lineno, force))
260 263
@@ -293,7 +296,7 @@ def handleInherit(statements, m):
293 n = __word__.findall(files) 296 n = __word__.findall(files)
294 statements.append(InheritNode(m.group(1))) 297 statements.append(InheritNode(m.group(1)))
295 298
296def finalise(fn, d): 299def finalize(fn, d):
297 for lazykey in bb.data.getVar("__lazy_assigned", d) or (): 300 for lazykey in bb.data.getVar("__lazy_assigned", d) or ():
298 if bb.data.getVar(lazykey, d) is None: 301 if bb.data.getVar(lazykey, d) is None:
299 val = bb.data.getVarFlag(lazykey, "defaultval", d) 302 val = bb.data.getVarFlag(lazykey, "defaultval", d)
@@ -301,35 +304,16 @@ def finalise(fn, d):
301 304
302 bb.data.expandKeys(d) 305 bb.data.expandKeys(d)
303 bb.data.update_data(d) 306 bb.data.update_data(d)
304 anonqueue = bb.data.getVar("__anonqueue", d, 1) or [] 307 code = []
305 body = [x['content'] for x in anonqueue] 308 for funcname in bb.data.getVar("__BBANONFUNCS", d) or []:
306 flag = { 'python' : 1, 'func' : 1 } 309 code.append("%s(d)" % funcname)
307 bb.data.setVar("__anonfunc", "\n".join(body), d) 310 bb.utils.simple_exec("\n".join(code), {"d": d})
308 bb.data.setVarFlags("__anonfunc", flag, d)
309 from bb import build
310 try:
311 t = bb.data.getVar('T', d)
312 bb.data.setVar('T', '${TMPDIR}/anonfunc/', d)
313 anonfuncs = bb.data.getVar('__BBANONFUNCS', d) or []
314 code = ""
315 for f in anonfuncs:
316 code = code + " %s(d)\n" % f
317 bb.data.setVar("__anonfunc", code, d)
318 build.exec_func("__anonfunc", d)
319 bb.data.delVar('T', d)
320 if t:
321 bb.data.setVar('T', t, d)
322 except Exception, e:
323 bb.msg.debug(1, bb.msg.domain.Parsing, "Exception when executing anonymous function: %s" % e)
324 raise
325 bb.data.delVar("__anonqueue", d)
326 bb.data.delVar("__anonfunc", d)
327 bb.data.update_data(d) 311 bb.data.update_data(d)
328 312
329 all_handlers = {} 313 all_handlers = {}
330 for var in bb.data.getVar('__BBHANDLERS', d) or []: 314 for var in bb.data.getVar('__BBHANDLERS', d) or []:
331 # try to add the handler 315 # try to add the handler
332 handler = bb.data.getVar(var,d) 316 handler = bb.data.getVar(var, d)
333 bb.event.register(var, handler) 317 bb.event.register(var, handler)
334 318
335 tasklist = bb.data.getVar('__BBTASKS', d) or [] 319 tasklist = bb.data.getVar('__BBTASKS', d) or []
@@ -360,7 +344,7 @@ def _expand_versions(versions):
360 versions = iter(versions) 344 versions = iter(versions)
361 while True: 345 while True:
362 try: 346 try:
363 version = versions.next() 347 version = next(versions)
364 except StopIteration: 348 except StopIteration:
365 break 349 break
366 350
@@ -370,14 +354,14 @@ def _expand_versions(versions):
370 else: 354 else:
371 newversions = expand_one(version, int(range_ver.group("from")), 355 newversions = expand_one(version, int(range_ver.group("from")),
372 int(range_ver.group("to"))) 356 int(range_ver.group("to")))
373 versions = chain(newversions, versions) 357 versions = itertools.chain(newversions, versions)
374 358
375def multi_finalize(fn, d): 359def multi_finalize(fn, d):
376 safe_d = d 360 safe_d = d
377 361
378 d = bb.data.createCopy(safe_d) 362 d = bb.data.createCopy(safe_d)
379 try: 363 try:
380 finalise(fn, d) 364 finalize(fn, d)
381 except bb.parse.SkipPackage: 365 except bb.parse.SkipPackage:
382 bb.data.setVar("__SKIPPED", True, d) 366 bb.data.setVar("__SKIPPED", True, d)
383 datastores = {"": safe_d} 367 datastores = {"": safe_d}
@@ -420,7 +404,7 @@ def multi_finalize(fn, d):
420 d = bb.data.createCopy(safe_d) 404 d = bb.data.createCopy(safe_d)
421 verfunc(pv, d, safe_d) 405 verfunc(pv, d, safe_d)
422 try: 406 try:
423 finalise(fn, d) 407 finalize(fn, d)
424 except bb.parse.SkipPackage: 408 except bb.parse.SkipPackage:
425 bb.data.setVar("__SKIPPED", True, d) 409 bb.data.setVar("__SKIPPED", True, d)
426 410
@@ -436,15 +420,15 @@ def multi_finalize(fn, d):
436 safe_d.setVar("BBCLASSEXTEND", extended) 420 safe_d.setVar("BBCLASSEXTEND", extended)
437 _create_variants(datastores, extended.split(), extendfunc) 421 _create_variants(datastores, extended.split(), extendfunc)
438 422
439 for variant, variant_d in datastores.items(): 423 for variant, variant_d in datastores.iteritems():
440 if variant: 424 if variant:
441 try: 425 try:
442 finalise(fn, variant_d) 426 finalize(fn, variant_d)
443 except bb.parse.SkipPackage: 427 except bb.parse.SkipPackage:
444 bb.data.setVar("__SKIPPED", True, variant_d) 428 bb.data.setVar("__SKIPPED", True, variant_d)
445 429
446 if len(datastores) > 1: 430 if len(datastores) > 1:
447 variants = filter(None, datastores.keys()) 431 variants = filter(None, datastores.iterkeys())
448 safe_d.setVar("__VARIANTS", " ".join(variants)) 432 safe_d.setVar("__VARIANTS", " ".join(variants))
449 433
450 datastores[""] = d 434 datastores[""] = d
diff --git a/bitbake/lib/bb/parse/parse_py/BBHandler.py b/bitbake/lib/bb/parse/parse_py/BBHandler.py
index 262c883c95..bb56174881 100644
--- a/bitbake/lib/bb/parse/parse_py/BBHandler.py
+++ b/bitbake/lib/bb/parse/parse_py/BBHandler.py
@@ -11,7 +11,7 @@
11 11
12# Copyright (C) 2003, 2004 Chris Larson 12# Copyright (C) 2003, 2004 Chris Larson
13# Copyright (C) 2003, 2004 Phil Blundell 13# Copyright (C) 2003, 2004 Phil Blundell
14# 14#
15# This program is free software; you can redistribute it and/or modify 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 16# it under the terms of the GNU General Public License version 2 as
17# published by the Free Software Foundation. 17# published by the Free Software Foundation.
@@ -25,15 +25,17 @@
25# with this program; if not, write to the Free Software Foundation, Inc., 25# with this program; if not, write to the Free Software Foundation, Inc.,
26# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 26# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 27
28import re, bb, os, sys, time, string 28from __future__ import absolute_import
29import re, bb, os
29import bb.fetch, bb.build, bb.utils 30import bb.fetch, bb.build, bb.utils
30from bb import data, fetch 31from bb import data
31 32
32from ConfHandler import include, init 33from . import ConfHandler
33from bb.parse import ParseError, resolve_file, ast 34from .. import resolve_file, ast
35from .ConfHandler import include, init
34 36
35# For compatibility 37# For compatibility
36from bb.parse import vars_from_file 38bb.deprecate_import(__name__, "bb.parse", ["vars_from_file"])
37 39
38__func_start_regexp__ = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" ) 40__func_start_regexp__ = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" )
39__inherit_regexp__ = re.compile( r"inherit\s+(.+)" ) 41__inherit_regexp__ = re.compile( r"inherit\s+(.+)" )
@@ -68,8 +70,8 @@ def inherit(files, d):
68 __inherit_cache = data.getVar('__inherit_cache', d) or [] 70 __inherit_cache = data.getVar('__inherit_cache', d) or []
69 fn = "" 71 fn = ""
70 lineno = 0 72 lineno = 0
71 files = data.expand(files, d)
72 for file in files: 73 for file in files:
74 file = data.expand(file, d)
73 if file[0] != "/" and file[-8:] != ".bbclass": 75 if file[0] != "/" and file[-8:] != ".bbclass":
74 file = os.path.join('classes', '%s.bbclass' % file) 76 file = os.path.join('classes', '%s.bbclass' % file)
75 77
@@ -80,17 +82,17 @@ def inherit(files, d):
80 include(fn, file, d, "inherit") 82 include(fn, file, d, "inherit")
81 __inherit_cache = data.getVar('__inherit_cache', d) or [] 83 __inherit_cache = data.getVar('__inherit_cache', d) or []
82 84
83def get_statements(filename, absolsute_filename, base_name): 85def get_statements(filename, absolute_filename, base_name):
84 global cached_statements 86 global cached_statements
85 87
86 try: 88 try:
87 return cached_statements[absolsute_filename] 89 return cached_statements[absolute_filename]
88 except KeyError: 90 except KeyError:
89 file = open(absolsute_filename, 'r') 91 file = open(absolute_filename, 'r')
90 statements = ast.StatementGroup() 92 statements = ast.StatementGroup()
91 93
92 lineno = 0 94 lineno = 0
93 while 1: 95 while True:
94 lineno = lineno + 1 96 lineno = lineno + 1
95 s = file.readline() 97 s = file.readline()
96 if not s: break 98 if not s: break
@@ -101,7 +103,7 @@ def get_statements(filename, absolsute_filename, base_name):
101 feeder(IN_PYTHON_EOF, "", filename, base_name, statements) 103 feeder(IN_PYTHON_EOF, "", filename, base_name, statements)
102 104
103 if filename.endswith(".bbclass") or filename.endswith(".inc"): 105 if filename.endswith(".bbclass") or filename.endswith(".inc"):
104 cached_statements[absolsute_filename] = statements 106 cached_statements[absolute_filename] = statements
105 return statements 107 return statements
106 108
107def handle(fn, d, include): 109def handle(fn, d, include):
@@ -118,7 +120,7 @@ def handle(fn, d, include):
118 bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data, include)") 120 bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data, include)")
119 121
120 (root, ext) = os.path.splitext(os.path.basename(fn)) 122 (root, ext) = os.path.splitext(os.path.basename(fn))
121 base_name = "%s%s" % (root,ext) 123 base_name = "%s%s" % (root, ext)
122 init(d) 124 init(d)
123 125
124 if ext == ".bbclass": 126 if ext == ".bbclass":
@@ -164,7 +166,7 @@ def handle(fn, d, include):
164 return d 166 return d
165 167
166def feeder(lineno, s, fn, root, statements): 168def feeder(lineno, s, fn, root, statements):
167 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__,__infunc__, __body__, classes, bb, __residue__ 169 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__, __infunc__, __body__, classes, bb, __residue__
168 if __infunc__: 170 if __infunc__:
169 if s == '}': 171 if s == '}':
170 __body__.append('') 172 __body__.append('')
@@ -231,10 +233,9 @@ def feeder(lineno, s, fn, root, statements):
231 ast.handleInherit(statements, m) 233 ast.handleInherit(statements, m)
232 return 234 return
233 235
234 from bb.parse import ConfHandler
235 return ConfHandler.feeder(lineno, s, fn, statements) 236 return ConfHandler.feeder(lineno, s, fn, statements)
236 237
237# Add us to the handlers list 238# Add us to the handlers list
238from bb.parse import handlers 239from .. import handlers
239handlers.append({'supports': supports, 'handle': handle, 'init': init}) 240handlers.append({'supports': supports, 'handle': handle, 'init': init})
240del handlers 241del handlers
diff --git a/bitbake/lib/bb/parse/parse_py/ConfHandler.py b/bitbake/lib/bb/parse/parse_py/ConfHandler.py
index f4f85de245..9128a2ef8f 100644
--- a/bitbake/lib/bb/parse/parse_py/ConfHandler.py
+++ b/bitbake/lib/bb/parse/parse_py/ConfHandler.py
@@ -10,7 +10,7 @@
10 10
11# Copyright (C) 2003, 2004 Chris Larson 11# Copyright (C) 2003, 2004 Chris Larson
12# Copyright (C) 2003, 2004 Phil Blundell 12# Copyright (C) 2003, 2004 Phil Blundell
13# 13#
14# This program is free software; you can redistribute it and/or modify 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 15# it under the terms of the GNU General Public License version 2 as
16# published by the Free Software Foundation. 16# published by the Free Software Foundation.
@@ -24,7 +24,8 @@
24# with this program; if not, write to the Free Software Foundation, Inc., 24# with this program; if not, write to the Free Software Foundation, Inc.,
25# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 25# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 26
27import re, bb.data, os, sys 27import re, bb.data, os
28import bb.utils
28from bb.parse import ParseError, resolve_file, ast 29from bb.parse import ParseError, resolve_file, ast
29 30
30#__config_regexp__ = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}]+)\s*(?P<colon>:)?(?P<ques>\?)?=\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$") 31#__config_regexp__ = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}]+)\s*(?P<colon>:)?(?P<ques>\?)?=\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$")
@@ -36,10 +37,7 @@ __export_regexp__ = re.compile( r"export\s+(.+)" )
36def init(data): 37def init(data):
37 topdir = bb.data.getVar('TOPDIR', data) 38 topdir = bb.data.getVar('TOPDIR', data)
38 if not topdir: 39 if not topdir:
39 topdir = os.getcwd() 40 bb.data.setVar('TOPDIR', os.getcwd(), data)
40 bb.data.setVar('TOPDIR', topdir, data)
41 if not bb.data.getVar('BBPATH', data):
42 bb.fatal("The BBPATH environment variable must be set")
43 41
44 42
45def supports(fn, d): 43def supports(fn, d):
@@ -60,7 +58,7 @@ def include(oldfn, fn, data, error_out):
60 if not os.path.isabs(fn): 58 if not os.path.isabs(fn):
61 dname = os.path.dirname(oldfn) 59 dname = os.path.dirname(oldfn)
62 bbpath = "%s:%s" % (dname, bb.data.getVar("BBPATH", data, 1)) 60 bbpath = "%s:%s" % (dname, bb.data.getVar("BBPATH", data, 1))
63 abs_fn = bb.which(bbpath, fn) 61 abs_fn = bb.utils.which(bbpath, fn)
64 if abs_fn: 62 if abs_fn:
65 fn = abs_fn 63 fn = abs_fn
66 64
@@ -88,7 +86,7 @@ def handle(fn, data, include):
88 86
89 statements = ast.StatementGroup() 87 statements = ast.StatementGroup()
90 lineno = 0 88 lineno = 0
91 while 1: 89 while True:
92 lineno = lineno + 1 90 lineno = lineno + 1
93 s = f.readline() 91 s = f.readline()
94 if not s: break 92 if not s: break
diff --git a/bitbake/lib/bb/parse/parse_py/__init__.py b/bitbake/lib/bb/parse/parse_py/__init__.py
index 9e0e00adda..3e658d0de9 100644
--- a/bitbake/lib/bb/parse/parse_py/__init__.py
+++ b/bitbake/lib/bb/parse/parse_py/__init__.py
@@ -25,9 +25,9 @@ File parsers for the BitBake build tools.
25# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 25# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26# 26#
27# Based on functions from the base bb module, Copyright 2003 Holger Schurig 27# Based on functions from the base bb module, Copyright 2003 Holger Schurig
28__version__ = '1.0'
29 28
30__all__ = [ 'ConfHandler', 'BBHandler'] 29from __future__ import absolute_import
30from . import ConfHandler
31from . import BBHandler
31 32
32import ConfHandler 33__version__ = '1.0'
33import BBHandler