diff options
Diffstat (limited to 'bitbake/lib/bb/main.py')
| -rwxr-xr-x | bitbake/lib/bb/main.py | 230 |
1 files changed, 77 insertions, 153 deletions
diff --git a/bitbake/lib/bb/main.py b/bitbake/lib/bb/main.py index 29e391162e..1edf56f41b 100755 --- a/bitbake/lib/bb/main.py +++ b/bitbake/lib/bb/main.py | |||
| @@ -28,6 +28,8 @@ import logging | |||
| 28 | import optparse | 28 | import optparse |
| 29 | import warnings | 29 | import warnings |
| 30 | import fcntl | 30 | import fcntl |
| 31 | import time | ||
| 32 | import traceback | ||
| 31 | 33 | ||
| 32 | import bb | 34 | import bb |
| 33 | from bb import event | 35 | from bb import event |
| @@ -37,6 +39,9 @@ from bb import ui | |||
| 37 | from bb import server | 39 | from bb import server |
| 38 | from bb import cookerdata | 40 | from bb import cookerdata |
| 39 | 41 | ||
| 42 | import bb.server.process | ||
| 43 | import bb.server.xmlrpcclient | ||
| 44 | |||
| 40 | logger = logging.getLogger("BitBake") | 45 | logger = logging.getLogger("BitBake") |
| 41 | 46 | ||
| 42 | class BBMainException(Exception): | 47 | class BBMainException(Exception): |
| @@ -58,9 +63,6 @@ class BitbakeHelpFormatter(optparse.IndentedHelpFormatter): | |||
| 58 | if option.dest == 'ui': | 63 | if option.dest == 'ui': |
| 59 | valid_uis = list_extension_modules(bb.ui, 'main') | 64 | valid_uis = list_extension_modules(bb.ui, 'main') |
| 60 | option.help = option.help.replace('@CHOICES@', present_options(valid_uis)) | 65 | option.help = option.help.replace('@CHOICES@', present_options(valid_uis)) |
| 61 | elif option.dest == 'servertype': | ||
| 62 | valid_server_types = list_extension_modules(bb.server, 'BitBakeServer') | ||
| 63 | option.help = option.help.replace('@CHOICES@', present_options(valid_server_types)) | ||
| 64 | 66 | ||
| 65 | return optparse.IndentedHelpFormatter.format_option(self, option) | 67 | return optparse.IndentedHelpFormatter.format_option(self, option) |
| 66 | 68 | ||
| @@ -238,11 +240,6 @@ class BitBakeConfigParameters(cookerdata.ConfigParameters): | |||
| 238 | default=os.environ.get('BITBAKE_UI', 'knotty'), | 240 | default=os.environ.get('BITBAKE_UI', 'knotty'), |
| 239 | help="The user interface to use (@CHOICES@ - default %default).") | 241 | help="The user interface to use (@CHOICES@ - default %default).") |
| 240 | 242 | ||
| 241 | # @CHOICES@ is substituted out by BitbakeHelpFormatter above | ||
| 242 | parser.add_option("-t", "--servertype", action="store", dest="servertype", | ||
| 243 | default=["process", "xmlrpc"]["BBSERVER" in os.environ], | ||
| 244 | help="Choose which server type to use (@CHOICES@ - default %default).") | ||
| 245 | |||
| 246 | parser.add_option("", "--token", action="store", dest="xmlrpctoken", | 243 | parser.add_option("", "--token", action="store", dest="xmlrpctoken", |
| 247 | default=os.environ.get("BBTOKEN"), | 244 | default=os.environ.get("BBTOKEN"), |
| 248 | help="Specify the connection token to be used when connecting " | 245 | help="Specify the connection token to be used when connecting " |
| @@ -258,14 +255,11 @@ class BitBakeConfigParameters(cookerdata.ConfigParameters): | |||
| 258 | help="Run bitbake without a UI, only starting a server " | 255 | help="Run bitbake without a UI, only starting a server " |
| 259 | "(cooker) process.") | 256 | "(cooker) process.") |
| 260 | 257 | ||
| 261 | parser.add_option("", "--foreground", action="store_true", | ||
| 262 | help="Run bitbake server in foreground.") | ||
| 263 | |||
| 264 | parser.add_option("-B", "--bind", action="store", dest="bind", default=False, | 258 | parser.add_option("-B", "--bind", action="store", dest="bind", default=False, |
| 265 | help="The name/address for the bitbake server to bind to.") | 259 | help="The name/address for the bitbake xmlrpc server to bind to.") |
| 266 | 260 | ||
| 267 | parser.add_option("-T", "--idle-timeout", type=int, | 261 | parser.add_option("-T", "--idle-timeout", type=float, dest="server_timeout", |
| 268 | default=int(os.environ.get("BBTIMEOUT", "0")), | 262 | default=float(os.environ.get("BB_SERVER_TIMEOUT", 0)) or None, |
| 269 | help="Set timeout to unload bitbake server due to inactivity") | 263 | help="Set timeout to unload bitbake server due to inactivity") |
| 270 | 264 | ||
| 271 | parser.add_option("", "--no-setscene", action="store_true", | 265 | parser.add_option("", "--no-setscene", action="store_true", |
| @@ -283,7 +277,7 @@ class BitBakeConfigParameters(cookerdata.ConfigParameters): | |||
| 283 | 277 | ||
| 284 | parser.add_option("-m", "--kill-server", action="store_true", | 278 | parser.add_option("-m", "--kill-server", action="store_true", |
| 285 | dest="kill_server", default=False, | 279 | dest="kill_server", default=False, |
| 286 | help="Terminate the remote server.") | 280 | help="Terminate the bitbake server.") |
| 287 | 281 | ||
| 288 | parser.add_option("", "--observe-only", action="store_true", | 282 | parser.add_option("", "--observe-only", action="store_true", |
| 289 | dest="observe_only", default=False, | 283 | dest="observe_only", default=False, |
| @@ -322,70 +316,20 @@ class BitBakeConfigParameters(cookerdata.ConfigParameters): | |||
| 322 | eventlog = "bitbake_eventlog_%s.json" % datetime.now().strftime("%Y%m%d%H%M%S") | 316 | eventlog = "bitbake_eventlog_%s.json" % datetime.now().strftime("%Y%m%d%H%M%S") |
| 323 | options.writeeventlog = eventlog | 317 | options.writeeventlog = eventlog |
| 324 | 318 | ||
| 325 | # if BBSERVER says to autodetect, let's do that | 319 | if options.bind: |
| 326 | if options.remote_server: | 320 | try: |
| 327 | port = -1 | 321 | #Checking that the port is a number and is a ':' delimited value |
| 328 | if options.remote_server != 'autostart': | 322 | (host, port) = options.bind.split(':') |
| 329 | host, port = options.remote_server.split(":", 2) | ||
| 330 | port = int(port) | 323 | port = int(port) |
| 331 | # use automatic port if port set to -1, means read it from | 324 | except (ValueError,IndexError): |
| 332 | # the bitbake.lock file; this is a bit tricky, but we always expect | 325 | raise BBMainException("FATAL: Malformed host:port bind parameter") |
| 333 | # to be in the base of the build directory if we need to have a | 326 | options.xmlrpcinterface = (host, port) |
| 334 | # chance to start the server later, anyway | 327 | else: |
| 335 | if port == -1: | 328 | options.xmlrpcinterface = (None, 0) |
| 336 | lock_location = "./bitbake.lock" | ||
| 337 | # we try to read the address at all times; if the server is not started, | ||
| 338 | # we'll try to start it after the first connect fails, below | ||
| 339 | try: | ||
| 340 | lf = open(lock_location, 'r') | ||
| 341 | remotedef = lf.readline() | ||
| 342 | [host, port] = remotedef.split(":") | ||
| 343 | port = int(port) | ||
| 344 | lf.close() | ||
| 345 | options.remote_server = remotedef | ||
| 346 | except Exception as e: | ||
| 347 | if options.remote_server != 'autostart': | ||
| 348 | raise BBMainException("Failed to read bitbake.lock (%s), invalid port" % str(e)) | ||
| 349 | 329 | ||
| 350 | return options, targets[1:] | 330 | return options, targets[1:] |
| 351 | 331 | ||
| 352 | 332 | ||
| 353 | def start_server(servermodule, configParams, configuration, features): | ||
| 354 | server = servermodule.BitBakeServer() | ||
| 355 | single_use = not configParams.server_only and os.getenv('BBSERVER') != 'autostart' | ||
| 356 | if configParams.bind: | ||
| 357 | (host, port) = configParams.bind.split(':') | ||
| 358 | server.initServer((host, int(port)), single_use=single_use, | ||
| 359 | idle_timeout=configParams.idle_timeout) | ||
| 360 | configuration.interface = [server.serverImpl.host, server.serverImpl.port] | ||
| 361 | else: | ||
| 362 | server.initServer(single_use=single_use) | ||
| 363 | configuration.interface = [] | ||
| 364 | |||
| 365 | try: | ||
| 366 | configuration.setServerRegIdleCallback(server.getServerIdleCB()) | ||
| 367 | |||
| 368 | cooker = bb.cooker.BBCooker(configuration, features) | ||
| 369 | |||
| 370 | server.addcooker(cooker) | ||
| 371 | server.saveConnectionDetails() | ||
| 372 | except Exception as e: | ||
| 373 | while hasattr(server, "event_queue"): | ||
| 374 | import queue | ||
| 375 | try: | ||
| 376 | event = server.event_queue.get(block=False) | ||
| 377 | except (queue.Empty, IOError): | ||
| 378 | break | ||
| 379 | if isinstance(event, logging.LogRecord): | ||
| 380 | logger.handle(event) | ||
| 381 | raise | ||
| 382 | if not configParams.foreground: | ||
| 383 | server.detach() | ||
| 384 | cooker.shutdown() | ||
| 385 | cooker.lock.close() | ||
| 386 | return server | ||
| 387 | |||
| 388 | |||
| 389 | def bitbake_main(configParams, configuration): | 333 | def bitbake_main(configParams, configuration): |
| 390 | 334 | ||
| 391 | # Python multiprocessing requires /dev/shm on Linux | 335 | # Python multiprocessing requires /dev/shm on Linux |
| @@ -406,45 +350,15 @@ def bitbake_main(configParams, configuration): | |||
| 406 | 350 | ||
| 407 | configuration.setConfigParameters(configParams) | 351 | configuration.setConfigParameters(configParams) |
| 408 | 352 | ||
| 409 | if configParams.server_only: | 353 | if configParams.server_only and configParams.remote_server: |
| 410 | if configParams.servertype != "xmlrpc": | ||
| 411 | raise BBMainException("FATAL: If '--server-only' is defined, we must set the " | ||
| 412 | "servertype as 'xmlrpc'.\n") | ||
| 413 | if not configParams.bind: | ||
| 414 | raise BBMainException("FATAL: The '--server-only' option requires a name/address " | ||
| 415 | "to bind to with the -B option.\n") | ||
| 416 | else: | ||
| 417 | try: | ||
| 418 | #Checking that the port is a number | ||
| 419 | int(configParams.bind.split(":")[1]) | ||
| 420 | except (ValueError,IndexError): | ||
| 421 | raise BBMainException( | ||
| 422 | "FATAL: Malformed host:port bind parameter") | ||
| 423 | if configParams.remote_server: | ||
| 424 | raise BBMainException("FATAL: The '--server-only' option conflicts with %s.\n" % | 354 | raise BBMainException("FATAL: The '--server-only' option conflicts with %s.\n" % |
| 425 | ("the BBSERVER environment variable" if "BBSERVER" in os.environ \ | 355 | ("the BBSERVER environment variable" if "BBSERVER" in os.environ \ |
| 426 | else "the '--remote-server' option")) | 356 | else "the '--remote-server' option")) |
| 427 | 357 | ||
| 428 | elif configParams.foreground: | ||
| 429 | raise BBMainException("FATAL: The '--foreground' option can only be used " | ||
| 430 | "with --server-only.\n") | ||
| 431 | |||
| 432 | if configParams.bind and configParams.servertype != "xmlrpc": | ||
| 433 | raise BBMainException("FATAL: If '-B' or '--bind' is defined, we must " | ||
| 434 | "set the servertype as 'xmlrpc'.\n") | ||
| 435 | |||
| 436 | if configParams.remote_server and configParams.servertype != "xmlrpc": | ||
| 437 | raise BBMainException("FATAL: If '--remote-server' is defined, we must " | ||
| 438 | "set the servertype as 'xmlrpc'.\n") | ||
| 439 | |||
| 440 | if configParams.observe_only and (not configParams.remote_server or configParams.bind): | 358 | if configParams.observe_only and (not configParams.remote_server or configParams.bind): |
| 441 | raise BBMainException("FATAL: '--observe-only' can only be used by UI clients " | 359 | raise BBMainException("FATAL: '--observe-only' can only be used by UI clients " |
| 442 | "connecting to a server.\n") | 360 | "connecting to a server.\n") |
| 443 | 361 | ||
| 444 | if configParams.kill_server and not configParams.remote_server: | ||
| 445 | raise BBMainException("FATAL: '--kill-server' can only be used to " | ||
| 446 | "terminate a remote server") | ||
| 447 | |||
| 448 | if "BBDEBUG" in os.environ: | 362 | if "BBDEBUG" in os.environ: |
| 449 | level = int(os.environ["BBDEBUG"]) | 363 | level = int(os.environ["BBDEBUG"]) |
| 450 | if level > configuration.debug: | 364 | if level > configuration.debug: |
| @@ -453,7 +367,7 @@ def bitbake_main(configParams, configuration): | |||
| 453 | bb.msg.init_msgconfig(configParams.verbose, configuration.debug, | 367 | bb.msg.init_msgconfig(configParams.verbose, configuration.debug, |
| 454 | configuration.debug_domains) | 368 | configuration.debug_domains) |
| 455 | 369 | ||
| 456 | server, server_connection, ui_module = setup_bitbake(configParams, configuration) | 370 | server_connection, ui_module = setup_bitbake(configParams, configuration) |
| 457 | if server_connection is None and configParams.kill_server: | 371 | if server_connection is None and configParams.kill_server: |
| 458 | return 0 | 372 | return 0 |
| 459 | 373 | ||
| @@ -463,16 +377,15 @@ def bitbake_main(configParams, configuration): | |||
| 463 | return 0 | 377 | return 0 |
| 464 | 378 | ||
| 465 | try: | 379 | try: |
| 380 | for event in bb.event.ui_queue: | ||
| 381 | server_connection.events.queue_event(event) | ||
| 382 | bb.event.ui_queue = [] | ||
| 383 | |||
| 466 | return ui_module.main(server_connection.connection, server_connection.events, | 384 | return ui_module.main(server_connection.connection, server_connection.events, |
| 467 | configParams) | 385 | configParams) |
| 468 | finally: | 386 | finally: |
| 469 | bb.event.ui_queue = [] | ||
| 470 | server_connection.terminate() | 387 | server_connection.terminate() |
| 471 | else: | 388 | else: |
| 472 | print("Bitbake server address: %s, server port: %s" % (server.serverImpl.host, | ||
| 473 | server.serverImpl.port)) | ||
| 474 | if configParams.foreground: | ||
| 475 | server.serverImpl.serve_forever() | ||
| 476 | return 0 | 389 | return 0 |
| 477 | 390 | ||
| 478 | return 1 | 391 | return 1 |
| @@ -495,58 +408,69 @@ def setup_bitbake(configParams, configuration, extrafeatures=None, setup_logging | |||
| 495 | # Collect the feature set for the UI | 408 | # Collect the feature set for the UI |
| 496 | featureset = getattr(ui_module, "featureSet", []) | 409 | featureset = getattr(ui_module, "featureSet", []) |
| 497 | 410 | ||
| 498 | if configParams.server_only: | ||
| 499 | for param in ('prefile', 'postfile'): | ||
| 500 | value = getattr(configParams, param) | ||
| 501 | if value: | ||
| 502 | setattr(configuration, "%s_server" % param, value) | ||
| 503 | param = "%s_server" % param | ||
| 504 | |||
| 505 | if extrafeatures: | 411 | if extrafeatures: |
| 506 | for feature in extrafeatures: | 412 | for feature in extrafeatures: |
| 507 | if not feature in featureset: | 413 | if not feature in featureset: |
| 508 | featureset.append(feature) | 414 | featureset.append(feature) |
| 509 | 415 | ||
| 510 | servermodule = import_extension_module(bb.server, | 416 | server_connection = None |
| 511 | configParams.servertype, | 417 | |
| 512 | 'BitBakeServer') | ||
| 513 | if configParams.remote_server: | 418 | if configParams.remote_server: |
| 514 | if os.getenv('BBSERVER') == 'autostart': | 419 | # Connect to a remote XMLRPC server |
| 515 | if configParams.remote_server == 'autostart' or \ | 420 | server_connection = bb.server.xmlrpcclient.connectXMLRPC(configParams.remote_server, featureset, |
| 516 | not servermodule.check_connection(configParams.remote_server, timeout=2): | 421 | configParams.observe_only, configParams.xmlrpctoken) |
| 517 | configParams.bind = 'localhost:0' | ||
| 518 | srv = start_server(servermodule, configParams, configuration, featureset) | ||
| 519 | configParams.remote_server = '%s:%d' % tuple(configuration.interface) | ||
| 520 | bb.event.ui_queue = [] | ||
| 521 | # we start a stub server that is actually a XMLRPClient that connects to a real server | ||
| 522 | from bb.server.xmlrpc import BitBakeXMLRPCClient | ||
| 523 | server = servermodule.BitBakeXMLRPCClient(configParams.observe_only, | ||
| 524 | configParams.xmlrpctoken) | ||
| 525 | server.saveConnectionDetails(configParams.remote_server) | ||
| 526 | else: | 422 | else: |
| 527 | # we start a server with a given configuration | 423 | retries = 8 |
| 528 | server = start_server(servermodule, configParams, configuration, featureset) | 424 | while retries: |
| 425 | try: | ||
| 426 | topdir, lock = lockBitbake() | ||
| 427 | sockname = topdir + "/bitbake.sock" | ||
| 428 | if lock: | ||
| 429 | # we start a server with a given configuration | ||
| 430 | logger.info("Starting bitbake server...") | ||
| 431 | server = bb.server.process.BitBakeServer(lock, sockname, configuration, featureset) | ||
| 432 | # The server will handle any events already in the queue | ||
| 433 | bb.event.ui_queue = [] | ||
| 434 | else: | ||
| 435 | logger.info("Reconnecting to bitbake server...") | ||
| 436 | if not os.path.exists(sockname): | ||
| 437 | print("Previous bitbake instance shutting down?, waiting to retry...") | ||
| 438 | time.sleep(5) | ||
| 439 | raise bb.server.process.ProcessTimeout("Bitbake still shutting down as socket exists but no lock?") | ||
| 440 | if not configParams.server_only: | ||
| 441 | server_connection = bb.server.process.connectProcessServer(sockname, featureset) | ||
| 442 | if server_connection: | ||
| 443 | break | ||
| 444 | except (Exception, bb.server.process.ProcessTimeout) as e: | ||
| 445 | if not retries: | ||
| 446 | raise | ||
| 447 | retries -= 1 | ||
| 448 | if isinstance(e, (bb.server.process.ProcessTimeout, BrokenPipeError)): | ||
| 449 | logger.info("Retrying server connection...") | ||
| 450 | else: | ||
| 451 | logger.info("Retrying server connection... (%s)" % traceback.format_exc()) | ||
| 452 | if not retries: | ||
| 453 | bb.fatal("Unable to connect to bitbake server, or start one") | ||
| 454 | if retries < 5: | ||
| 455 | time.sleep(5) | ||
| 456 | |||
| 457 | if configParams.kill_server: | ||
| 458 | server_connection.connection.terminateServer() | ||
| 459 | server_connection.terminate() | ||
| 529 | bb.event.ui_queue = [] | 460 | bb.event.ui_queue = [] |
| 461 | logger.info("Terminated bitbake server.") | ||
| 462 | return None, None | ||
| 530 | 463 | ||
| 531 | if configParams.server_only: | 464 | # Restore the environment in case the UI needs it |
| 532 | server_connection = None | 465 | for k in cleanedvars: |
| 533 | else: | 466 | os.environ[k] = cleanedvars[k] |
| 534 | try: | ||
| 535 | server_connection = server.establishConnection(featureset) | ||
| 536 | except Exception as e: | ||
| 537 | bb.fatal("Could not connect to server %s: %s" % (configParams.remote_server, str(e))) | ||
| 538 | |||
| 539 | if configParams.kill_server: | ||
| 540 | server_connection.connection.terminateServer() | ||
| 541 | bb.event.ui_queue = [] | ||
| 542 | return None, None, None | ||
| 543 | 467 | ||
| 544 | server_connection.setupEventQueue() | 468 | logger.removeHandler(handler) |
| 545 | 469 | ||
| 546 | # Restore the environment in case the UI needs it | 470 | return server_connection, ui_module |
| 547 | for k in cleanedvars: | ||
| 548 | os.environ[k] = cleanedvars[k] | ||
| 549 | 471 | ||
| 550 | logger.removeHandler(handler) | 472 | def lockBitbake(): |
| 473 | topdir = bb.cookerdata.findTopdir() | ||
| 474 | lockfile = topdir + "/bitbake.lock" | ||
| 475 | return topdir, bb.utils.lockfile(lockfile, False, False) | ||
| 551 | 476 | ||
| 552 | return server, server_connection, ui_module | ||
