From f3133e945e909fa48cac55376f895d436c8a9a35 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Thu, 11 Jan 2018 13:57:53 -0700 Subject: [PATCH] Rework configuration file loading to be more consistent. Any configuration file can be set (or disabled) with --xxx-config=. --config= overrides all configuration files. --- doc/src/overview.xml | 34 ++++++++ src/build-system.jam | 185 +++++++++++++++++++++++++++++------------- src/build/project.jam | 4 +- test/configuration.py | 69 ++++++++++++++++ 4 files changed, 235 insertions(+), 57 deletions(-) diff --git a/doc/src/overview.xml b/doc/src/overview.xml index b5501d351..65aa966b0 100644 --- a/doc/src/overview.xml +++ b/doc/src/overview.xml @@ -449,6 +449,8 @@ actions create-file-from-another + Any of these files may also be overridden on the command line + You can use the --debug-configuration option to @@ -785,6 +787,38 @@ b2 toolset=gcc variant=debug optimization=space + + + + config + Override all configuration files + + + + + + + site-config.jam + Override the default site-config.jam + + + + + + + user-config.jam + Override the default user-config.jam + + + + + + + project-config.jam + Override the default project-config.jam + + + diff --git a/src/build-system.jam b/src/build-system.jam index a2f64f624..c111a2312 100644 --- a/src/build-system.jam +++ b/src/build-system.jam @@ -272,6 +272,35 @@ local rule load-config ( module-name : filename : path + : must-find ? ) return $(where) ; } +# Parses options of the form --xxx-config=path/to/config.jam +# and environmental variables of the form BOOST_BUILD_XXX_CONFIG. +# If not found, returns an empty list. The option may be +# explicitly set to the empty string, in which case, handle-config-option +# will return "". +# +local rule handle-config-option ( name : env ? ) +{ + local result = [ MATCH ^--$(name)=(.*)$ : $(.argv) ] ; + if ! $(result)-is-defined && $(env) + { + result = [ os.environ $(env) ] ; + } + # Special handling for the case when the OS does not strip the quotes + # around the file name, as is the case when using Cygwin bash. + result = [ utility.unquote $(result[-1]) ] ; + if ! $(result) + { + return $(result) ; + } + # Treat explicitly entered user paths as native OS path + # references and, if non-absolute, root them at the current + # working directory. + result = [ path.make $(result) ] ; + result = [ path.root $(result) [ path.pwd ] ] ; + result = [ path.native $(result) ] ; + return $(result) ; +} + # Loads all the configuration files used by Boost Build in the following order: # @@ -282,11 +311,21 @@ local rule load-config ( module-name : filename : path + : must-find ? ) # files will not be. If a relative path is specified, file is searched for in # the current folder. # +# -- all-config -- +# Loaded only if specified on the command-line using the --config command +# line option. If a file name is specified, it must exist and replaces all +# other configuration files. If an empty file name is passed, no configuration +# files will be loaded. +# # -- site-config -- -# Always named site-config.jam. Will only be found if located on the system -# root path (Windows), /etc (non-Windows), user's home folder or the Boost Build -# path, in that order. Not loaded in case the test-config configuration file is -# loaded or the --ignore-site-config command-line option is specified. +# Named site-config.jam by default or may be named explicitly using the +# --site-config command-line option. If named explicitly, the file is found +# relative to the current working directory and must exist. If the default one +# is used then it is searched for in the system root path (Windows), +# /etc (non-Windows), user's home folder or the Boost Build path, in that +# order. Not loaded in case the test-config configuration file is loaded, +# the file is explicitly set to the empty string or the --ignore-site-config +# command-line option is specified. # # -- user-config -- # Named user-config.jam by default or may be named explicitly using the @@ -299,8 +338,12 @@ local rule load-config ( module-name : filename : path + : must-find ? ) # file must exist. # # -- project-config -- -# Always named project-config.jam. Looked up in the current working folder and -# then upwards through its parents up to the root folder. +# Named project-config.jam. Looked up in the current working folder and +# then upwards through its parents up to the root folder. It may also be +# named explicitly using the --project-config command-line option. If a file +# is specified explicitly, it is found relative to the current working +# directory and must exist. If an empty file name is passed, project-config +# will not be loaded. # # Test configurations have been added primarily for use by Boost Build's # internal unit testing system but may be used freely in other places as well. @@ -310,14 +353,11 @@ local rule load-configuration-files # Flag indicating that site configuration should not be loaded. local ignore-site-config = [ MATCH ^(--ignore-site-config)$ : $(.argv) ] ; + local ignore-user-config ; + local ignore-project-config ; initialize-config-module test-config ; - local test-config = [ MATCH ^--test-config=(.*)$ : $(.argv) ] ; - local uq = [ MATCH \"(.*)\" : $(test-config) ] ; - if $(uq) - { - test-config = $(uq) ; - } + local test-config = [ handle-config-option test-config ] ; if $(test-config) { local where = [ load-config test-config : $(test-config:BS) : @@ -330,12 +370,32 @@ local rule load-configuration-files ECHO "notice: be ignored due to the test configuration being" "loaded." ; } + ignore-site-config = true ; + ignore-user-config = true ; } - else + } + + initialize-config-module all-config ; + local all-config = [ handle-config-option config ] ; + if $(all-config) + { + load-config all-config : $(all-config:D=) : $(all-config:D) : required ; + if $(.debug-config) { - test-config = ; + ECHO "notice: Regular configuration files will be ignored due" ; + ECHO "notice: to the global configuration being loaded." ; } } + if $(all-config)-is-defined + { + if $(.debug-config) && ! $(all-config) + { + ECHO "notice: Configuration file loading explicitly disabled." ; + } + ignore-site-config = true ; + ignore-user-config = true ; + ignore-project-config = true ; + } local user-path = [ os.home-directories ] [ os.environ BOOST_BUILD_PATH ] ; local site-path = /etc $(user-path) ; @@ -344,55 +404,52 @@ local rule load-configuration-files site-path = [ modules.peek : SystemRoot ] $(user-path) ; } - if $(.debug-config) && ! $(test-config) && $(ignore-site-config) + if $(.debug-config) && $(ignore-site-config) = --ignore-site-config { ECHO "notice: Site configuration files will be ignored due to the" ; ECHO "notice: --ignore-site-config command-line option." ; } initialize-config-module site-config ; - if ! $(test-config) && ! $(ignore-site-config) + if ! $(ignore-site-config) { - load-config site-config : site-config.jam : $(site-path) ; + local site-config = [ handle-config-option site-config ] ; + if $(site-config) + { + load-config site-config : $(site-config:D=) : $(site-config:D) + : must-exist ; + } + else if ! $(site-config)-is-defined + { + load-config site-config : site-config.jam : $(site-path) ; + } + else if $(.debug-config) + { + ECHO notice: Site configuration file loading explicitly disabled. ; + } } initialize-config-module user-config ; - if ! $(test-config) + if ! $(ignore-user-config) { - local user-config = [ MATCH ^--user-config=(.*)$ : $(.argv) ] ; - user-config = $(user-config[-1]) ; - user-config ?= [ os.environ BOOST_BUILD_USER_CONFIG ] ; - # Special handling for the case when the OS does not strip the quotes - # around the file name, as is the case when using Cygwin bash. - user-config = [ utility.unquote $(user-config) ] ; - local explicitly-requested = $(user-config) ; - user-config ?= user-config.jam ; + local user-config = + [ handle-config-option user-config : BOOST_BUILD_USER_CONFIG ] ; if $(user-config) { - if $(explicitly-requested) + if $(.debug-config) { - # Treat explicitly entered user paths as native OS path - # references and, if non-absolute, root them at the current - # working directory. - user-config = [ path.make $(user-config) ] ; - user-config = [ path.root $(user-config) [ path.pwd ] ] ; - user-config = [ path.native $(user-config) ] ; - - if $(.debug-config) - { - ECHO notice: Loading explicitly specified user configuration - file: ; - ECHO " $(user-config)" ; - } - - load-config user-config : $(user-config:BS) : $(user-config:D) - : must-exist ; - } - else - { - load-config user-config : $(user-config) : $(user-path) ; + ECHO notice: Loading explicitly specified user configuration + file: ; + ECHO " $(user-config)" ; } + + load-config user-config : $(user-config:D=) : $(user-config:D) + : must-exist ; + } + else if ! $(user-config)-is-defined + { + load-config user-config : user-config.jam : $(user-path) ; } else if $(.debug-config) { @@ -406,15 +463,33 @@ local rule load-configuration-files # - We need to load project-config.jam before Jamroot # - We probably need to load project-config.jam even if there is no Jamroot # - e.g. to implement automake-style out-of-tree builds. - local file = [ path.glob "." : project-config.jam ] ; - if ! $(file) + if ! $(ignore-project-config) { - file = [ path.glob-in-parents "." : project-config.jam ] ; - } - if $(file) - { - initialize-config-module project-config : $(file:D) ; - load-config project-config : project-config.jam : $(file:D) ; + local project-config = [ handle-config-option project-config ] ; + if $(project-config) + { + initialize-config-module project-config : $(project-config:D=) ; + load-config project-config : $(project-config:D=) + : $(project-config:D) : must-exist ; + } + else if ! $(project-config)-is-defined + { + local file = [ path.glob "." : project-config.jam ] ; + if ! $(file) + { + file = [ path.glob-in-parents "." : project-config.jam ] ; + } + if $(file) + { + initialize-config-module project-config : $(file:D) ; + load-config project-config : project-config.jam : $(file:D) ; + } + } + else if $(.debug-config) + { + ECHO notice: Project configuration file loading explicitly + disabled. ; + } } project.end-load ; diff --git a/src/build/project.jam b/src/build/project.jam index d02240a4f..803574052 100644 --- a/src/build/project.jam +++ b/src/build/project.jam @@ -441,7 +441,7 @@ rule initialize ( local jamroot ; local parent-module ; - if $(module-name) = test-config + if $(module-name) in test-config all-config { # No parent. } @@ -502,7 +502,7 @@ rule initialize ( } else { - local cfgs = project site test user ; + local cfgs = project site test user all ; if ! $(module-name) in $(cfgs)-config { # This is a standalone project with known location. Set its diff --git a/test/configuration.py b/test/configuration.py index 724ecd7c9..0a9df6a6c 100755 --- a/test/configuration.py +++ b/test/configuration.py @@ -8,6 +8,7 @@ # Test Boost Build configuration file handling. import BoostBuild +import TestCmd import os import os.path @@ -316,6 +317,71 @@ for x in $(names) t.cleanup() +def test_site_config(): + # Ignore user-config, just in case it depends on the user's site-config.jam + t = BoostBuild.Tester(["--user-config="], use_test_config=False, + pass_toolset=0) + # We can immediately exit after we finish loading the config files + t.write("Jamroot", "EXIT Done : 0 ;") + t.write("my-site-config.jam", "ECHO Loaded my-site-config ;") + + t.run_build_system(["--site-config=my-site-config.jam"], + stdout="Loaded my-site-config\nDone\n") + + t.run_build_system(["--ignore-site-config", "--debug-configuration"]) + t.expect_output_lines("""\ +notice: Site configuration files will be ignored due to the +notice: --ignore-site-config command-line option.""") + + t.run_build_system(["--site-config=", "--debug-configuration"]) + t.expect_output_lines("""\ +notice: Site configuration file loading explicitly disabled.""") + + t.cleanup() + +def test_global_config(): + t = BoostBuild.Tester(use_test_config=False, pass_toolset=0) + t.write("my-config.jam", "ECHO Loading my-config ;") + t.write("Jamroot", "EXIT Done : 0 ;") + t.write("project-config.jam", "ECHO bad ;") + t.run_build_system(["--config=my-config.jam", "--debug-configuration"], + match=TestCmd.match_re, stdout= +r"""notice: found boost-build\.jam at .* +notice: loading Boost\.Build from .* +notice: Searching '.*' for all-config configuration file 'my-config\.jam'\. +notice: Loading all-config configuration file 'my-config\.jam' from '.*'\. +Loading my-config +notice: Regular configuration files will be ignored due +notice: to the global configuration being loaded\. +Done +""") + t.run_build_system(["--config=", "--debug-configuration"], + match=TestCmd.match_re, stdout= +r"""notice: found boost-build\.jam at .* +notice: loading Boost\.Build from .* +notice: Configuration file loading explicitly disabled. +Done +""") + t.cleanup() + +def test_project_config(): + t = BoostBuild.Tester(["--user-config=", "--site-config="], + use_test_config=False, pass_toolset=False) + t.write("Jamroot", "EXIT Done : 0 ;") + t.write("project-config.jam", "ECHO Loading Root ;") + t.write("my-project-config.jam", "ECHO Loading explicit ;") + t.write("sub/project-config.jam", "ECHO Loading subdir ;") + t.write("sub/Jamfile", "") + + t.run_build_system(stdout="Loading Root\nDone\n") + t.run_build_system(subdir="sub", stdout="Loading subdir\nDone\n") + t.rm("sub/project-config.jam") + t.run_build_system(subdir="sub", stdout="Loading Root\nDone\n") + t.run_build_system(["--project-config=my-project-config.jam"], + stdout="Loading explicit\nDone\n") + + t.cleanup() + ############################################################################### # # main() @@ -326,3 +392,6 @@ for x in $(names) canSetEmptyEnvironmentVariable = _canSetEmptyEnvironmentVariable() test_user_configuration() +test_site_config() +test_global_config() +test_project_config()