diff options
author | Alexander Kanavin <alex@linutronix.de> | 2025-10-08 18:56:59 +0200 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2025-10-09 16:46:45 +0100 |
commit | 5dda14aa9403c14c26896f6fe6ec8889d215dded (patch) | |
tree | d563975a99f549271b571264cd8099b193e64c93 | |
parent | cfc377635cf5c9a8a8dff9de7c4e2031dee2e2f2 (diff) | |
download | poky-5dda14aa9403c14c26896f6fe6ec8889d215dded.tar.gz |
bitbake: bitbake-setup: rework the settings handling
This is the outcome of various discussions, suggestions and pull
requests on github.
What has specifically changed?
1. The sources for the settings are no longer separated, but are stacked and given priorities,
from highest to lowest:
a. '--setting section key value' on the command line
b. a settings file in the top directory
c. a global settings file in ~/.config/bitbake-setup/ (or in a file pointed to by --global-settings)
Any setting can be in any of these three locations (other than top dir name and prefix which do not
make sense in the settings file in the top directory).
2. A global settings file must contain all of the needed settings, while a settings file
in the top directory can be empty (and this is how they are written out if they do not exist).
Specifically, both dl-dir and registry settings have been relocated to the global file,
and dl-dir defaults to ~/.cache/bitbake-setup/downloads, rather than somewhere in top dir.
3. The file name for both global and top dir settings is now 'settings.conf'.
4. --top-dir-prefix and --top-dir-name options have been removed and superseded by
a generic, universal --setting option.
5. 'install-settings' command has been removed, as it is no longer does anything useful,
and is superseded by the 'setting' command (see below).
'install-global-settings' has been retained, to be able to have a set of global defaults
that can be changed without initializing a build.
6. 'change-setting', 'change-global-setting' and 'install-settings' have all been replaced
by a single 'setting' command that mimics 'git config' in its parameters:
a. Changing a setting: bitbake-setup setting [--global] default dl-dir /path/to/downloads
b. Removing a setting: bitbake-setup setting [--global] --unset default dl-dir
(Bitbake rev: dbf593e4f7441e423ce4f2a8c7b0365a1c93bd23)
Signed-off-by: Alexander Kanavin <alex@linutronix.de>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rwxr-xr-x | bitbake/bin/bitbake-setup | 287 | ||||
-rw-r--r-- | bitbake/lib/bb/tests/setup.py | 12 |
2 files changed, 147 insertions, 152 deletions
diff --git a/bitbake/bin/bitbake-setup b/bitbake/bin/bitbake-setup index 7878cd9394..e9e73a9270 100755 --- a/bitbake/bin/bitbake-setup +++ b/bitbake/bin/bitbake-setup | |||
@@ -32,9 +32,9 @@ logger = bb.msg.logger_create('bitbake-setup', sys.stdout) | |||
32 | def cache_dir(top_dir): | 32 | def cache_dir(top_dir): |
33 | return os.path.join(top_dir, '.bitbake-setup-cache') | 33 | return os.path.join(top_dir, '.bitbake-setup-cache') |
34 | 34 | ||
35 | def init_bb_cache(settings, args): | 35 | def init_bb_cache(top_dir, settings, args): |
36 | dldir = settings["default"]["dl-dir"] | 36 | dldir = settings["default"]["dl-dir"] |
37 | bb_cachedir = os.path.join(cache_dir(args.top_dir), 'bitbake-cache') | 37 | bb_cachedir = os.path.join(cache_dir(top_dir), 'bitbake-cache') |
38 | 38 | ||
39 | d = bb.data.init() | 39 | d = bb.data.init() |
40 | d.setVar("DL_DIR", dldir) | 40 | d.setVar("DL_DIR", dldir) |
@@ -389,7 +389,7 @@ def choose_fragments(possibilities, parameters, non_interactive, skip_selection) | |||
389 | choices[k] = options_enumerated[option_n][1] | 389 | choices[k] = options_enumerated[option_n][1] |
390 | return choices | 390 | return choices |
391 | 391 | ||
392 | def obtain_config(settings, args, source_overrides, d): | 392 | def obtain_config(top_dir, settings, args, source_overrides, d): |
393 | if args.config: | 393 | if args.config: |
394 | config_id = args.config[0] | 394 | config_id = args.config[0] |
395 | config_parameters = args.config[1:] | 395 | config_parameters = args.config[1:] |
@@ -407,7 +407,7 @@ def obtain_config(settings, args, source_overrides, d): | |||
407 | upstream_config = {'type':'network','uri':config_id,'name':get_config_name(config_id),'data':json.load(f)} | 407 | upstream_config = {'type':'network','uri':config_id,'name':get_config_name(config_id),'data':json.load(f)} |
408 | else: | 408 | else: |
409 | print("Looking up config {} in configuration registry".format(config_id)) | 409 | print("Looking up config {} in configuration registry".format(config_id)) |
410 | registry_path = update_registry(settings["default"]["registry"], cache_dir(args.top_dir), d) | 410 | registry_path = update_registry(settings["default"]["registry"], cache_dir(top_dir), d) |
411 | registry_configs = list_registry(registry_path, with_expired=True) | 411 | registry_configs = list_registry(registry_path, with_expired=True) |
412 | if config_id not in registry_configs: | 412 | if config_id not in registry_configs: |
413 | raise Exception("Config {} not found in configuration registry, re-run 'init' without parameters to choose from available configurations.".format(config_id)) | 413 | raise Exception("Config {} not found in configuration registry, re-run 'init' without parameters to choose from available configurations.".format(config_id)) |
@@ -416,7 +416,7 @@ def obtain_config(settings, args, source_overrides, d): | |||
416 | if has_expired(expiry_date): | 416 | if has_expired(expiry_date): |
417 | print("This configuration is no longer supported after {}. Please consider changing to a supported configuration.".format(expiry_date)) | 417 | print("This configuration is no longer supported after {}. Please consider changing to a supported configuration.".format(expiry_date)) |
418 | else: | 418 | else: |
419 | registry_path = update_registry(settings["default"]["registry"], cache_dir(args.top_dir), d) | 419 | registry_path = update_registry(settings["default"]["registry"], cache_dir(top_dir), d) |
420 | registry_configs = list_registry(registry_path, with_expired=True) | 420 | registry_configs = list_registry(registry_path, with_expired=True) |
421 | config_id = choose_config(registry_configs, args.non_interactive) | 421 | config_id = choose_config(registry_configs, args.non_interactive) |
422 | config_parameters = [] | 422 | config_parameters = [] |
@@ -429,7 +429,7 @@ def obtain_config(settings, args, source_overrides, d): | |||
429 | upstream_config['skip-selection'] = args.skip_selection | 429 | upstream_config['skip-selection'] = args.skip_selection |
430 | return upstream_config | 430 | return upstream_config |
431 | 431 | ||
432 | def init_config(settings, args, d): | 432 | def init_config(top_dir, settings, args, d): |
433 | stdout = sys.stdout | 433 | stdout = sys.stdout |
434 | def handle_task_progress(event, d): | 434 | def handle_task_progress(event, d): |
435 | rate = event.rate if event.rate else '' | 435 | rate = event.rate if event.rate else '' |
@@ -437,10 +437,10 @@ def init_config(settings, args, d): | |||
437 | print("{}% {} ".format(progress, rate), file=stdout, end='\r') | 437 | print("{}% {} ".format(progress, rate), file=stdout, end='\r') |
438 | 438 | ||
439 | source_overrides = json.load(open(args.source_overrides)) if args.source_overrides else {'sources':{}} | 439 | source_overrides = json.load(open(args.source_overrides)) if args.source_overrides else {'sources':{}} |
440 | upstream_config = obtain_config(settings, args, source_overrides, d) | 440 | upstream_config = obtain_config(top_dir, settings, args, source_overrides, d) |
441 | print("\nRun 'bitbake-setup init --non-interactive {}' to select this configuration non-interactively.\n".format(" ".join(upstream_config['non-interactive-cmdline-options']))) | 441 | print("\nRun 'bitbake-setup init --non-interactive {}' to select this configuration non-interactively.\n".format(" ".join(upstream_config['non-interactive-cmdline-options']))) |
442 | 442 | ||
443 | builddir = os.path.join(os.path.abspath(args.top_dir), args.build_dir_name or "{}-{}".format(upstream_config['name']," ".join(upstream_config['non-interactive-cmdline-options'][1:]).replace(" ","-").replace("/","_"))) | 443 | builddir = os.path.join(os.path.abspath(top_dir), args.build_dir_name or "{}-{}".format(upstream_config['name']," ".join(upstream_config['non-interactive-cmdline-options'][1:]).replace(" ","-").replace("/","_"))) |
444 | if os.path.exists(os.path.join(builddir, "layers")): | 444 | if os.path.exists(os.path.join(builddir, "layers")): |
445 | print("Build already initialized in {}\nUse 'bitbake-setup status' to check if it needs to be updated or 'bitbake-setup update' to perform the update.".format(builddir)) | 445 | print("Build already initialized in {}\nUse 'bitbake-setup status' to check if it needs to be updated or 'bitbake-setup update' to perform the update.".format(builddir)) |
446 | return | 446 | return |
@@ -511,7 +511,7 @@ def are_layers_changed(layers, layerdir, d): | |||
511 | 511 | ||
512 | return changed | 512 | return changed |
513 | 513 | ||
514 | def build_status(settings, args, d, update=False): | 514 | def build_status(top_dir, settings, args, d, update=False): |
515 | builddir = args.build_dir | 515 | builddir = args.build_dir |
516 | 516 | ||
517 | confdir = os.path.join(builddir, "config") | 517 | confdir = os.path.join(builddir, "config") |
@@ -523,7 +523,7 @@ def build_status(settings, args, d, update=False): | |||
523 | args.non_interactive = True | 523 | args.non_interactive = True |
524 | args.skip_selection = current_upstream_config['skip-selection'] | 524 | args.skip_selection = current_upstream_config['skip-selection'] |
525 | source_overrides = current_upstream_config["source-overrides"] | 525 | source_overrides = current_upstream_config["source-overrides"] |
526 | new_upstream_config = obtain_config(settings, args, source_overrides, d) | 526 | new_upstream_config = obtain_config(top_dir, settings, args, source_overrides, d) |
527 | 527 | ||
528 | write_config(new_upstream_config, confdir) | 528 | write_config(new_upstream_config, confdir) |
529 | config_diff = bb.process.run('git -C {} diff'.format(confdir))[0] | 529 | config_diff = bb.process.run('git -C {} diff'.format(confdir))[0] |
@@ -544,8 +544,8 @@ def build_status(settings, args, d, update=False): | |||
544 | 544 | ||
545 | print("\nConfiguration in {} has not changed.".format(builddir)) | 545 | print("\nConfiguration in {} has not changed.".format(builddir)) |
546 | 546 | ||
547 | def build_update(settings, args, d): | 547 | def build_update(top_dir, settings, args, d): |
548 | build_status(settings, args, d, update=True) | 548 | build_status(top_dir, settings, args, d, update=True) |
549 | 549 | ||
550 | def do_fetch(fetcher, dir): | 550 | def do_fetch(fetcher, dir): |
551 | # git fetcher simply dumps git output to stdout; in bitbake context that is redirected to temp/log.do_fetch | 551 | # git fetcher simply dumps git output to stdout; in bitbake context that is redirected to temp/log.do_fetch |
@@ -595,8 +595,8 @@ def list_registry(registry_path, with_expired): | |||
595 | json_data[config_name] = {"description": config_desc} | 595 | json_data[config_name] = {"description": config_desc} |
596 | return json_data | 596 | return json_data |
597 | 597 | ||
598 | def list_configs(settings, args, d): | 598 | def list_configs(top_dir, settings, args, d): |
599 | registry_path = update_registry(settings["default"]["registry"], cache_dir(args.top_dir), d) | 599 | registry_path = update_registry(settings["default"]["registry"], cache_dir(top_dir), d) |
600 | json_data = list_registry(registry_path, args.with_expired) | 600 | json_data = list_registry(registry_path, args.with_expired) |
601 | print("\nAvailable configurations:") | 601 | print("\nAvailable configurations:") |
602 | for config_name, config_data in json_data.items(): | 602 | for config_name, config_data in json_data.items(): |
@@ -614,7 +614,7 @@ def list_configs(settings, args, d): | |||
614 | json.dump(json_data, f, sort_keys=True, indent=4) | 614 | json.dump(json_data, f, sort_keys=True, indent=4) |
615 | print("Available configurations written into {}".format(args.write_json)) | 615 | print("Available configurations written into {}".format(args.write_json)) |
616 | 616 | ||
617 | def install_buildtools(settings, args, d): | 617 | def install_buildtools(top_dir, settings, args, d): |
618 | buildtools_install_dir = os.path.join(args.build_dir, 'buildtools') | 618 | buildtools_install_dir = os.path.join(args.build_dir, 'buildtools') |
619 | if os.path.exists(buildtools_install_dir): | 619 | if os.path.exists(buildtools_install_dir): |
620 | if not args.force: | 620 | if not args.force: |
@@ -634,117 +634,113 @@ def install_buildtools(settings, args, d): | |||
634 | subprocess.check_call("{} -d {} --downloads-directory {}".format(install_buildtools, buildtools_install_dir, buildtools_download_dir), shell=True) | 634 | subprocess.check_call("{} -d {} --downloads-directory {}".format(install_buildtools, buildtools_install_dir, buildtools_download_dir), shell=True) |
635 | 635 | ||
636 | def default_settings_path(top_dir): | 636 | def default_settings_path(top_dir): |
637 | return os.path.join(top_dir, 'bitbake-setup.conf') | 637 | return os.path.join(top_dir, 'settings.conf') |
638 | 638 | ||
639 | def write_settings(top_dir, force_replace, non_interactive=True): | 639 | def create_settings(top_dir, non_interactive=True): |
640 | settings_path = default_settings_path(top_dir) | 640 | settings_path = default_settings_path(top_dir) |
641 | if not os.path.exists(settings_path) or force_replace: | 641 | settings = configparser.ConfigParser() |
642 | 642 | settings['default'] = { | |
643 | settings = configparser.ConfigParser() | 643 | } |
644 | settings['default'] = { | 644 | os.makedirs(os.path.dirname(settings_path), exist_ok=True) |
645 | 'registry':default_registry, | 645 | |
646 | 'dl-dir':os.path.join(top_dir, '.bitbake-setup-downloads'), | 646 | siteconfpath = os.path.join(top_dir, 'site.conf') |
647 | } | 647 | print('A new empty settings file will be created in (you can add settings to it to override defaults from the global settings file)\n {}\n'.format(settings_path)) |
648 | os.makedirs(os.path.dirname(settings_path), exist_ok=True) | 648 | print('A common site.conf file will be created, please edit or replace before running builds\n {}\n'.format(siteconfpath)) |
649 | 649 | if not non_interactive: | |
650 | siteconfpath = os.path.join(top_dir, 'site.conf') | 650 | y_or_n = input('Bitbake-setup will be configured with the above settings in {}, (y/N): '.format(top_dir)) |
651 | print('Configuration registry set to\n {}\n'.format(settings['default']['registry'])) | 651 | if y_or_n != 'y': |
652 | print('Bitbake-setup download cache (DL_DIR) set to\n {}\n'.format(settings['default']['dl-dir'])) | 652 | print("\nYou can run 'bitbake-setup install-settings' to edit them before setting up builds") |
653 | print('A new settings file will be created in\n {}\n'.format(settings_path)) | 653 | exit() |
654 | print('A common site.conf file will be created, please edit or replace before running builds\n {}\n'.format(siteconfpath)) | 654 | print() |
655 | if not non_interactive: | ||
656 | y_or_n = input('Bitbake-setup will be configured with the above settings in {}, (y/N): '.format(top_dir)) | ||
657 | if y_or_n != 'y': | ||
658 | print("\nYou can run 'bitbake-setup install-settings' to edit them before setting up builds") | ||
659 | exit() | ||
660 | print() | ||
661 | |||
662 | if os.path.exists(settings_path): | ||
663 | backup_conf = settings_path + "-backup.{}".format(time.strftime("%Y%m%d%H%M%S")) | ||
664 | os.rename(settings_path, backup_conf) | ||
665 | print("Previous settings are in {}".format(backup_conf)) | ||
666 | with open(settings_path, 'w') as settingsfile: | ||
667 | settings.write(settingsfile) | ||
668 | |||
669 | if os.path.exists(siteconfpath): | ||
670 | backup_siteconf = siteconfpath + "-backup.{}".format(time.strftime("%Y%m%d%H%M%S")) | ||
671 | os.rename(siteconfpath, backup_siteconf) | ||
672 | print("Previous settings are in {}".format(backup_siteconf)) | ||
673 | with open(siteconfpath, 'w') as siteconffile: | ||
674 | siteconffile.write('# This file is intended for build host-specific bitbake settings\n') | ||
675 | 655 | ||
676 | def load_settings(top_dir, non_interactive): | 656 | if os.path.exists(settings_path): |
677 | # This creates a new settings file if it does not yet exist | 657 | backup_conf = settings_path + "-backup.{}".format(time.strftime("%Y%m%d%H%M%S")) |
678 | write_settings(top_dir, force_replace=False, non_interactive=non_interactive) | 658 | os.rename(settings_path, backup_conf) |
659 | print("Previous settings are in {}".format(backup_conf)) | ||
660 | with open(settings_path, 'w') as settingsfile: | ||
661 | settings.write(settingsfile) | ||
662 | |||
663 | if os.path.exists(siteconfpath): | ||
664 | backup_siteconf = siteconfpath + "-backup.{}".format(time.strftime("%Y%m%d%H%M%S")) | ||
665 | os.rename(siteconfpath, backup_siteconf) | ||
666 | print("Previous settings are in {}".format(backup_siteconf)) | ||
667 | with open(siteconfpath, 'w') as siteconffile: | ||
668 | siteconffile.write('# This file is intended for build host-specific bitbake settings\n') | ||
679 | 669 | ||
670 | def load_settings(top_dir, non_interactive): | ||
680 | settings_path = default_settings_path(top_dir) | 671 | settings_path = default_settings_path(top_dir) |
672 | if not os.path.exists(settings_path): | ||
673 | create_settings(top_dir, non_interactive=non_interactive) | ||
674 | |||
681 | settings = configparser.ConfigParser() | 675 | settings = configparser.ConfigParser() |
682 | print('Loading settings from\n {}\n'.format(settings_path)) | 676 | print('Loading settings from\n {}\n'.format(settings_path)) |
683 | settings.read_file(open(settings_path)) | 677 | settings.read_file(open(settings_path)) |
684 | return settings | 678 | return settings |
685 | 679 | ||
686 | def global_settings_path(args): | 680 | def global_settings_path(args): |
687 | return os.path.abspath(args.global_settings) if args.global_settings else os.path.join(os.path.expanduser('~'), '.config', 'bitbake-setup', 'config') | 681 | return os.path.abspath(args.global_settings) if args.global_settings else os.path.join(os.path.expanduser('~'), '.config', 'bitbake-setup', 'settings.conf') |
688 | 682 | ||
689 | def write_global_settings(settings_path, force_replace, non_interactive=True): | 683 | def create_global_settings(settings_path, non_interactive=True): |
690 | if not os.path.exists(settings_path) or force_replace: | 684 | settings = configparser.ConfigParser() |
691 | 685 | settings['default'] = { | |
692 | settings = configparser.ConfigParser() | 686 | 'top-dir-prefix':os.path.expanduser('~'), |
693 | settings['default'] = { | 687 | 'top-dir-name':'bitbake-builds', |
694 | 'top-dir-prefix':os.path.expanduser('~'), | 688 | 'registry':default_registry, |
695 | 'top-dir-name':'bitbake-builds' | 689 | 'dl-dir':os.path.join(os.path.expanduser('~'), '.cache', 'bitbake-setup', 'downloads'), |
696 | } | 690 | } |
697 | os.makedirs(os.path.dirname(settings_path), exist_ok=True) | 691 | os.makedirs(os.path.dirname(settings_path), exist_ok=True) |
698 | print('Configuring global settings in\n {}\n'.format(settings_path)) | 692 | print('Configuring global settings in\n {}\n'.format(settings_path)) |
699 | print('Top directory prefix (where all top level directories are created) set to\n {}\n'.format(settings['default']['top-dir-prefix'])) | 693 | print('Top directory prefix (where all top level directories are created) set to\n {}\n'.format(settings['default']['top-dir-prefix'])) |
700 | print('Top directory name (this is added to the top directory prefix to form a top directory where builds are set up) set to\n {}\n'.format(settings['default']['top-dir-name'])) | 694 | print('Top directory name (this is added to the top directory prefix to form a top directory where builds are set up) set to\n {}\n'.format(settings['default']['top-dir-name'])) |
701 | if not non_interactive: | 695 | print('Configuration registry set to\n {}\n'.format(settings['default']['registry'])) |
702 | y_or_n = input('Write out the global settings as specified above (y/N)? ') | 696 | print('Bitbake-setup download cache (DL_DIR) set to\n {}\n'.format(settings['default']['dl-dir'])) |
703 | if y_or_n != 'y': | 697 | if not non_interactive: |
704 | print("\nYou can run 'bitbake-setup install-global-settings' to edit them before setting up builds") | 698 | y_or_n = input('Write out the global settings as specified above (y/N)? ') |
705 | exit() | 699 | if y_or_n != 'y': |
706 | print() | 700 | print("\nYou can run 'bitbake-setup install-global-settings' to edit them before setting up builds") |
707 | 701 | exit() | |
708 | if os.path.exists(settings_path): | 702 | print() |
709 | backup_conf = settings_path + "-backup.{}".format(time.strftime("%Y%m%d%H%M%S")) | 703 | |
710 | os.rename(settings_path, backup_conf) | 704 | if os.path.exists(settings_path): |
711 | print("Previous global settings are in {}".format(backup_conf)) | 705 | backup_conf = settings_path + "-backup.{}".format(time.strftime("%Y%m%d%H%M%S")) |
712 | with open(settings_path, 'w') as settingsfile: | 706 | os.rename(settings_path, backup_conf) |
713 | settings.write(settingsfile) | 707 | print("Previous global settings are in {}".format(backup_conf)) |
708 | with open(settings_path, 'w') as settingsfile: | ||
709 | settings.write(settingsfile) | ||
714 | 710 | ||
715 | def load_global_settings(settings_path, non_interactive): | 711 | def load_global_settings(settings_path, non_interactive): |
716 | # This creates a new settings file if it does not yet exist | 712 | if not os.path.exists(settings_path): |
717 | write_global_settings(settings_path, force_replace=False, non_interactive=non_interactive) | 713 | create_global_settings(settings_path, non_interactive=non_interactive) |
718 | 714 | ||
719 | settings = configparser.ConfigParser() | 715 | settings = configparser.ConfigParser() |
720 | print('Loading global settings from\n {}\n'.format(settings_path)) | 716 | print('Loading global settings from\n {}\n'.format(settings_path)) |
721 | settings.read_file(open(settings_path)) | 717 | settings.read_file(open(settings_path)) |
722 | return settings | 718 | return settings |
723 | 719 | ||
724 | def change_settings(top_dir, new_settings): | 720 | def change_setting(settings_path, settings, args): |
725 | settings = load_settings(top_dir, non_interactive=True) | 721 | if args.section and args.key and args.value: |
726 | for section, section_settings in new_settings.items(): | 722 | settings[args.section][args.key] = args.value |
727 | for setting, value in section_settings.items(): | 723 | print("Setting '{}' in section '{}' is changed to '{}'".format(args.key, args.section, args.value)) |
728 | settings[section][setting] = value | 724 | if args.unset: |
729 | print("Setting '{}' in section '{}' is changed to '{}'".format(setting, section, value)) | 725 | section = args.unset[0] |
726 | setting = args.unset[1] | ||
727 | if section in settings.keys() and setting in settings[section].keys(): | ||
728 | del settings[section][setting] | ||
729 | print("Setting '{} in section '{}' is removed".format(setting, section)) | ||
730 | 730 | ||
731 | settings_path = default_settings_path(top_dir) | ||
732 | with open(settings_path, 'w') as settingsfile: | 731 | with open(settings_path, 'w') as settingsfile: |
733 | settings.write(settingsfile) | 732 | settings.write(settingsfile) |
734 | print("New settings written to {}".format(settings_path)) | 733 | print("New settings written to {}".format(settings_path)) |
735 | return settings | ||
736 | 734 | ||
737 | def change_global_settings(settings_path, new_settings): | 735 | def setting_global(args): |
738 | settings = load_global_settings(settings_path, non_interactive=True) | 736 | settings = load_global_settings(global_settings_path(args), args.non_interactive) |
739 | for section, section_settings in new_settings.items(): | 737 | settings_path = global_settings_path(args) |
740 | for setting, value in section_settings.items(): | 738 | change_setting(settings_path, settings, args) |
741 | settings[section][setting] = value | ||
742 | print("Setting '{}' in section '{}' is changed to '{}'".format(setting, section, value)) | ||
743 | 739 | ||
744 | with open(settings_path, 'w') as settingsfile: | 740 | def setting(top_dir, args): |
745 | settings.write(settingsfile) | 741 | settings = load_settings(top_dir, args.non_interactive) |
746 | print("New global settings written to {}".format(settings_path)) | 742 | settings_path = default_settings_path(top_dir) |
747 | return settings | 743 | change_setting(settings_path, settings, args) |
748 | 744 | ||
749 | def get_build_dir_via_bbpath(): | 745 | def get_build_dir_via_bbpath(): |
750 | bbpath = os.environ.get('BBPATH') | 746 | bbpath = os.environ.get('BBPATH') |
@@ -755,7 +751,7 @@ def get_build_dir_via_bbpath(): | |||
755 | return build_dir | 751 | return build_dir |
756 | return None | 752 | return None |
757 | 753 | ||
758 | def get_top_dir(args, global_settings): | 754 | def get_top_dir(args, settings): |
759 | build_dir_via_bbpath = get_build_dir_via_bbpath() | 755 | build_dir_via_bbpath = get_build_dir_via_bbpath() |
760 | if build_dir_via_bbpath: | 756 | if build_dir_via_bbpath: |
761 | top_dir = os.path.dirname(build_dir_via_bbpath) | 757 | top_dir = os.path.dirname(build_dir_via_bbpath) |
@@ -763,20 +759,25 @@ def get_top_dir(args, global_settings): | |||
763 | return top_dir | 759 | return top_dir |
764 | 760 | ||
765 | if hasattr(args, 'build_dir'): | 761 | if hasattr(args, 'build_dir'): |
766 | # commands without --top-dir-prefix/name arguments (status, update) still need to know where | ||
767 | # the top dir is, but it should be auto-deduced as parent of args.build_dir | ||
768 | top_dir = os.path.dirname(os.path.normpath(args.build_dir)) | 762 | top_dir = os.path.dirname(os.path.normpath(args.build_dir)) |
769 | return top_dir | 763 | return top_dir |
770 | 764 | ||
771 | top_dir_prefix = args.top_dir_prefix if args.top_dir_prefix else global_settings['default']['top-dir-prefix'] | 765 | top_dir_prefix = settings['default']['top-dir-prefix'] |
772 | top_dir_name = args.top_dir_name if args.top_dir_name else global_settings['default']['top-dir-name'] | 766 | top_dir_name = settings['default']['top-dir-name'] |
773 | return os.path.join(top_dir_prefix, top_dir_name) | 767 | return os.path.join(top_dir_prefix, top_dir_name) |
774 | 768 | ||
775 | def main(): | 769 | def merge_settings(global_settings, local_settings, cmdline_settings): |
776 | def add_top_dir_arg(parser): | 770 | all_settings = global_settings |
777 | parser.add_argument('--top-dir-prefix', help='Top level directory prefix. This is where all top level directories are created.') | 771 | for section, section_settings in local_settings.items(): |
778 | parser.add_argument('--top-dir-name', help='Top level directory name. Together with the top directory prefix this forms a top directory where builds are set up and downloaded configurations and layers are cached for reproducibility and offline builds.') | 772 | for setting, value in section_settings.items(): |
773 | all_settings[section][setting] = value | ||
774 | |||
775 | for (section, setting, value) in cmdline_settings: | ||
776 | all_settings[section][setting] = value | ||
777 | |||
778 | return all_settings | ||
779 | 779 | ||
780 | def main(): | ||
780 | def add_build_dir_arg(parser): | 781 | def add_build_dir_arg(parser): |
781 | build_dir = get_build_dir_via_bbpath() | 782 | build_dir = get_build_dir_via_bbpath() |
782 | if build_dir: | 783 | if build_dir: |
@@ -792,18 +793,17 @@ def main(): | |||
792 | parser.add_argument('-q', '--quiet', help='Print only errors', action='store_true') | 793 | parser.add_argument('-q', '--quiet', help='Print only errors', action='store_true') |
793 | parser.add_argument('--color', choices=['auto', 'always', 'never'], default='auto', help='Colorize output (where %(metavar)s is %(choices)s)', metavar='COLOR') | 794 | parser.add_argument('--color', choices=['auto', 'always', 'never'], default='auto', help='Colorize output (where %(metavar)s is %(choices)s)', metavar='COLOR') |
794 | parser.add_argument('--no-network', action='store_true', help='Do not check whether configuration repositories and layer repositories have been updated; use only the local cache.') | 795 | parser.add_argument('--no-network', action='store_true', help='Do not check whether configuration repositories and layer repositories have been updated; use only the local cache.') |
795 | parser.add_argument('--global-settings', action='store', help='Path to the global settings file where defaults for top directory prefix and name can be specified') | 796 | parser.add_argument('--global-settings', action='store', help='Path to the global settings file.') |
797 | parser.add_argument('--setting', default=[], action='append', nargs=3, help='Modify a setting (for this bitbake-setup invocation only), for example "--setting default top-dir-prefix /path/to/top/dir".') | ||
796 | 798 | ||
797 | subparsers = parser.add_subparsers() | 799 | subparsers = parser.add_subparsers() |
798 | 800 | ||
799 | parser_list = subparsers.add_parser('list', help='List available configurations') | 801 | parser_list = subparsers.add_parser('list', help='List available configurations') |
800 | add_top_dir_arg(parser_list) | ||
801 | parser_list.add_argument('--with-expired', action='store_true', help='List also configurations that are no longer supported due to reaching their end-of-life dates.') | 802 | parser_list.add_argument('--with-expired', action='store_true', help='List also configurations that are no longer supported due to reaching their end-of-life dates.') |
802 | parser_list.add_argument('--write-json', action='store', help='Write available configurations into a json file so they can be programmatically processed.') | 803 | parser_list.add_argument('--write-json', action='store', help='Write available configurations into a json file so they can be programmatically processed.') |
803 | parser_list.set_defaults(func=list_configs) | 804 | parser_list.set_defaults(func=list_configs) |
804 | 805 | ||
805 | parser_init = subparsers.add_parser('init', help='Select a configuration and initialize a build from it') | 806 | parser_init = subparsers.add_parser('init', help='Select a configuration and initialize a build from it') |
806 | add_top_dir_arg(parser_init) | ||
807 | parser_init.add_argument('config', nargs='*', help="path/URL/id to a configuration file (use 'list' command to get available ids), followed by configuration options. Bitbake-setup will ask to choose from available choices if command line doesn't completely specify them.") | 807 | parser_init.add_argument('config', nargs='*', help="path/URL/id to a configuration file (use 'list' command to get available ids), followed by configuration options. Bitbake-setup will ask to choose from available choices if command line doesn't completely specify them.") |
808 | parser_init.add_argument('--non-interactive', action='store_true', help='Do not ask to interactively choose from available options; if bitbake-setup cannot make a decision it will stop with a failure.') | 808 | parser_init.add_argument('--non-interactive', action='store_true', help='Do not ask to interactively choose from available options; if bitbake-setup cannot make a decision it will stop with a failure.') |
809 | parser_init.add_argument('--source-overrides', action='store', help='Override sources information (repositories/revisions) with values from a local json file.') | 809 | parser_init.add_argument('--source-overrides', action='store', help='Override sources information (repositories/revisions) with values from a local json file.') |
@@ -824,25 +824,16 @@ def main(): | |||
824 | parser_install_buildtools.add_argument('--force', action='store_true', help='Force a reinstall of buildtools over the previous installation.') | 824 | parser_install_buildtools.add_argument('--force', action='store_true', help='Force a reinstall of buildtools over the previous installation.') |
825 | parser_install_buildtools.set_defaults(func=install_buildtools) | 825 | parser_install_buildtools.set_defaults(func=install_buildtools) |
826 | 826 | ||
827 | parser_install_settings = subparsers.add_parser('install-settings', help='Write a settings file with default values into the top level directory (contains the location of build configuration registry, downloads directory and other settings specific to a top directory)') | 827 | parser_install_global_settings = subparsers.add_parser('install-global-settings', help='Write a global settings file with default values') |
828 | add_top_dir_arg(parser_install_settings) | 828 | parser_install_global_settings.set_defaults(func=create_global_settings) |
829 | parser_install_settings.set_defaults(func=write_settings) | ||
830 | |||
831 | parser_install_global_settings = subparsers.add_parser('install-global-settings', help='Write a global settings file with default values (contains the default prefix and name of the top directory)') | ||
832 | parser_install_global_settings.set_defaults(func=write_global_settings) | ||
833 | |||
834 | parser_change_setting = subparsers.add_parser('change-setting', help='Change a setting in the settings file') | ||
835 | add_top_dir_arg(parser_change_setting) | ||
836 | parser_change_setting.add_argument('section', help="Section in a settings file, typically 'default'") | ||
837 | parser_change_setting.add_argument('key', help="Name of the setting") | ||
838 | parser_change_setting.add_argument('value', help="Value of the setting") | ||
839 | parser_change_setting.set_defaults(func=change_settings) | ||
840 | 829 | ||
841 | parser_change_global_setting = subparsers.add_parser('change-global-setting', help='Change a setting in the global settings file') | 830 | parser_setting = subparsers.add_parser('setting', help='Set or unset a setting in a setting file (e.g. the default prefix and name of the top directory, the location of build configuration registry, downloads directory and other settings specific to a top directory)') |
842 | parser_change_global_setting.add_argument('section', help="Section in a global settings file, typically 'default'") | 831 | parser_setting.add_argument('section', nargs='?', help="Section in a settings file, typically 'default'") |
843 | parser_change_global_setting.add_argument('key', help="Name of the setting") | 832 | parser_setting.add_argument('key', nargs='?', help="Name of the setting") |
844 | parser_change_global_setting.add_argument('value', help="Value of the setting") | 833 | parser_setting.add_argument('value', nargs='?', help="Value of the setting") |
845 | parser_change_global_setting.set_defaults(func=change_global_settings) | 834 | parser_setting.add_argument('--global', action='store_true', help="Modify the setting in a global settings file, rather than one specific to a top directory") |
835 | parser_setting.add_argument('--unset', nargs=2, help="Unset a setting, e.g. 'bitbake-setup setting --unset default registry' would revert to the registry setting in a global settings file") | ||
836 | parser_setting.set_defaults(func=setting) | ||
846 | 837 | ||
847 | args = parser.parse_args() | 838 | args = parser.parse_args() |
848 | 839 | ||
@@ -859,11 +850,8 @@ def main(): | |||
859 | level=logger.getEffectiveLevel()) | 850 | level=logger.getEffectiveLevel()) |
860 | 851 | ||
861 | if 'func' in args: | 852 | if 'func' in args: |
862 | if args.func == write_global_settings: | 853 | if args.func == create_global_settings: |
863 | write_global_settings(global_settings_path(args), force_replace=True) | 854 | create_global_settings(global_settings_path(args)) |
864 | return | ||
865 | elif args.func == change_global_settings: | ||
866 | change_global_settings(global_settings_path(args), {args.section:{args.key:args.value}}) | ||
867 | return | 855 | return |
868 | 856 | ||
869 | if hasattr(args, 'build_dir'): | 857 | if hasattr(args, 'build_dir'): |
@@ -874,19 +862,24 @@ def main(): | |||
874 | if not hasattr(args, 'non_interactive'): | 862 | if not hasattr(args, 'non_interactive'): |
875 | args.non_interactive = True | 863 | args.non_interactive = True |
876 | 864 | ||
865 | if args.func == setting and vars(args)['global']: | ||
866 | setting_global(args) | ||
867 | return | ||
868 | |||
877 | global_settings = load_global_settings(global_settings_path(args), args.non_interactive) | 869 | global_settings = load_global_settings(global_settings_path(args), args.non_interactive) |
878 | args.top_dir = get_top_dir(args, global_settings) | 870 | top_dir = get_top_dir(args, merge_settings(global_settings, {}, args.setting)) |
879 | 871 | ||
880 | print('Bitbake-setup is using {} as top directory (can be changed with --top-dir-prefix/name arguments or by setting them in {}).\n'.format(args.top_dir, global_settings_path(args))) | 872 | if args.func == setting: |
881 | if args.func == write_settings: | 873 | setting(top_dir, args) |
882 | write_settings(args.top_dir, force_replace=True) | 874 | return |
883 | elif args.func == change_settings: | 875 | |
884 | change_settings(args.top_dir, {args.section:{args.key:args.value}}) | 876 | print('Bitbake-setup is using {} as top directory (can be changed by setting top dir prefix and name in {}).\n'.format(top_dir, global_settings_path(args))) |
885 | else: | 877 | |
886 | settings = load_settings(args.top_dir, args.non_interactive) | 878 | settings = load_settings(top_dir, args.non_interactive) |
887 | d = init_bb_cache(settings, args) | 879 | settings = merge_settings(global_settings, settings, args.setting) |
888 | args.func(settings, args, d) | 880 | d = init_bb_cache(top_dir, settings, args) |
889 | save_bb_cache() | 881 | args.func(top_dir, settings, args, d) |
882 | save_bb_cache() | ||
890 | else: | 883 | else: |
891 | from argparse import Namespace | 884 | from argparse import Namespace |
892 | parser.print_help() | 885 | parser.print_help() |
diff --git a/bitbake/lib/bb/tests/setup.py b/bitbake/lib/bb/tests/setup.py index 495d1da203..22edda40e4 100644 --- a/bitbake/lib/bb/tests/setup.py +++ b/bitbake/lib/bb/tests/setup.py | |||
@@ -235,16 +235,18 @@ print("BBPATH is {{}}".format(os.environ["BBPATH"])) | |||
235 | out = self.runbbsetup("install-global-settings") | 235 | out = self.runbbsetup("install-global-settings") |
236 | settings_path = "{}/global-config".format(self.tempdir) | 236 | settings_path = "{}/global-config".format(self.tempdir) |
237 | self.assertIn(settings_path, out[0]) | 237 | self.assertIn(settings_path, out[0]) |
238 | out = self.runbbsetup("change-global-setting default top-dir-prefix {}".format(self.tempdir)) | 238 | out = self.runbbsetup("setting --global default top-dir-prefix {}".format(self.tempdir)) |
239 | self.assertIn("Setting 'top-dir-prefix' in section 'default' is changed to", out[0]) | 239 | self.assertIn("Setting 'top-dir-prefix' in section 'default' is changed to", out[0]) |
240 | self.assertIn("New global settings written to".format(settings_path), out[0]) | 240 | self.assertIn("New settings written to".format(settings_path), out[0]) |
241 | out = self.runbbsetup("setting --global default dl-dir {}".format(os.path.join(self.tempdir, 'downloads'))) | ||
242 | self.assertIn("Setting 'dl-dir' in section 'default' is changed to", out[0]) | ||
243 | self.assertIn("New settings written to".format(settings_path), out[0]) | ||
241 | 244 | ||
242 | # check that writing settings works and then adjust them to point to | 245 | # check that writing settings works and then adjust them to point to |
243 | # test registry repo | 246 | # test registry repo |
244 | out = self.runbbsetup("install-settings") | 247 | out = self.runbbsetup("setting default registry 'git://{};protocol=file;branch=master;rev=master'".format(self.registrypath)) |
245 | settings_path = "{}/bitbake-builds/bitbake-setup.conf".format(self.tempdir) | 248 | settings_path = "{}/bitbake-builds/settings.conf".format(self.tempdir) |
246 | self.assertIn(settings_path, out[0]) | 249 | self.assertIn(settings_path, out[0]) |
247 | out = self.runbbsetup("change-setting default registry 'git://{};protocol=file;branch=master;rev=master'".format(self.registrypath)) | ||
248 | self.assertIn("Setting 'registry' in section 'default' is changed to", out[0]) | 250 | self.assertIn("Setting 'registry' in section 'default' is changed to", out[0]) |
249 | self.assertIn("New settings written to".format(settings_path), out[0]) | 251 | self.assertIn("New settings written to".format(settings_path), out[0]) |
250 | 252 | ||