diff options
19 files changed, 152 insertions, 6 deletions
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index 1f91a2520b..7eaf3fa801 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -862,11 +862,29 @@ Available commands are: Displays arguments as text but no new line. -.. option:: env [--unset=NAME ...] [NAME=VALUE ...] [--] <command> [<arg>...] +.. option:: env [<options>] [--] <command> [<arg>...] .. versionadded:: 3.1 - Run command in a modified environment. + Run command in a modified environment. Options are: + + ``NAME=VALUE`` + Replaces the current value of ``NAME`` with ``VALUE``. + + ``--unset=NAME`` + Unsets the current value of ``NAME``. + + ``--modify ENVIRONMENT_MODIFICATION`` + .. versionadded:: 3.25 + + Apply a single :prop_test:`ENVIRONMENT_MODIFICATION` operation to the + modified environment. + + The ``NAME=VALUE`` and ``--unset=NAME`` options are equivalent to + ``--modify NAME=set:VALUE`` and ``--modify NAME=unset:``, respectively. + Note that ``--modify NAME=reset:`` resets ``NAME`` to the value it had + when ``cmake`` launched (or unsets it), not to the most recent + ``NAME=VALUE`` option. .. versionadded:: 3.24 Added support for the double dash argument ``--``. Use ``--`` to stop diff --git a/Help/release/dev/cmake-E-env-modify.rst b/Help/release/dev/cmake-E-env-modify.rst new file mode 100644 index 0000000000..ea4a622809 --- /dev/null +++ b/Help/release/dev/cmake-E-env-modify.rst @@ -0,0 +1,5 @@ +cmake-E-env-modify +------------------ + +* A new ``--modify`` flag was added to :option:`cmake -E env <cmake_E env>` to support :prop_test:`ENVIRONMENT_MODIFICATION` + operations. diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 2c32f09544..3c4e709547 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1578,10 +1578,15 @@ void cmSystemTools::EnvDiff::PutEnv(const std::string& env) std::string name = env.substr(0, eq_loc); diff[name] = env.substr(eq_loc + 1); } else { - diff[env] = {}; + this->UnPutEnv(env); } } +void cmSystemTools::EnvDiff::UnPutEnv(const std::string& env) +{ + diff[env] = {}; +} + bool cmSystemTools::EnvDiff::ParseOperation(const std::string& envmod) { char path_sep = GetSystemPathlistSeparator(); diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index e8c04b1a0e..48bbe238b1 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -397,6 +397,9 @@ public: */ void PutEnv(const std::string& env); + /** Remove a single variable from the current environment diff. */ + void UnPutEnv(const std::string& env); + /** * Apply an ENVIRONMENT_MODIFICATION operation to this diff. Returns * false and issues an error on parse failure. diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index b1f1bcfe3c..00c9bda633 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -791,6 +791,10 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, } if (args[1] == "env") { +#ifndef CMAKE_BOOTSTRAP + cmSystemTools::EnvDiff env; +#endif + auto ai = args.cbegin() + 2; auto ae = args.cend(); for (; ai != ae; ++ai) { @@ -803,16 +807,40 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, } if (cmHasLiteralPrefix(a, "--unset=")) { // Unset environment variable. +#ifdef CMAKE_BOOTSTRAP cmSystemTools::UnPutEnv(a.substr(8)); +#else + env.UnPutEnv(a.substr(8)); +#endif + } else if (a == "--modify") { +#ifdef CMAKE_BOOTSTRAP + std::cerr + << "cmake -E env: --modify not available during bootstrapping\n"; + return 1; +#else + if (++ai == ae) { + std::cerr << "cmake -E env: --modify missing a parameter\n"; + return 1; + } + std::string const& op = *ai; + if (!env.ParseOperation(op)) { + std::cerr << "cmake -E env: invalid parameter to --modify: " << op + << '\n'; + return 1; + } +#endif } else if (!a.empty() && a[0] == '-') { // Environment variable and command names cannot start in '-', // so this must be an unknown option. - std::cerr << "cmake -E env: unknown option '" << a << '\'' - << std::endl; + std::cerr << "cmake -E env: unknown option '" << a << "'\n"; return 1; } else if (a.find('=') != std::string::npos) { // Set environment variable. +#ifdef CMAKE_BOOTSTRAP cmSystemTools::PutEnv(a); +#else + env.PutEnv(a); +#endif } else { // This is the beginning of the command. break; @@ -820,10 +848,14 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, } if (ai == ae) { - std::cerr << "cmake -E env: no command given" << std::endl; + std::cerr << "cmake -E env: no command given\n"; return 1; } +#ifndef CMAKE_BOOTSTRAP + env.ApplyToCurrentEnv(); +#endif + // Execute command from remaining arguments. std::vector<std::string> cmd(ai, ae); int retval; diff --git a/Tests/RunCMake/CommandLine/E_env-equal.cmake b/Tests/RunCMake/CommandLine/E_env-equal.cmake new file mode 100644 index 0000000000..3f18bb65f7 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env-equal.cmake @@ -0,0 +1,15 @@ +if (NOT DEFINED ENV{TEST_ENV_EXPECTED}) + if (NOT DEFINED ENV{TEST_ENV}) + message(STATUS "TEST_ENV is correctly not set in environment") + else () + message(FATAL_ERROR "TEST_ENV is incorrectly set in environment") + endif () +else () + if (NOT DEFINED ENV{TEST_ENV}) + message(FATAL_ERROR "TEST_ENV is incorrectly not set in environment") + elseif ("$ENV{TEST_ENV}" STREQUAL "$ENV{TEST_ENV_EXPECTED}") + message(STATUS "TEST_ENV is correctly set in environment: $ENV{TEST_ENV}") + else () + message(FATAL_ERROR "TEST_ENV is incorrectly set in environment!\n\tactual: $ENV{TEST_ENV}\n\texpected: $ENV{TEST_ENV_EXPECTED}") + endif () +endif () diff --git a/Tests/RunCMake/CommandLine/E_env_modify-bad-operation-result.txt b/Tests/RunCMake/CommandLine/E_env_modify-bad-operation-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env_modify-bad-operation-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_env_modify-bad-operation-stderr.txt b/Tests/RunCMake/CommandLine/E_env_modify-bad-operation-stderr.txt new file mode 100644 index 0000000000..ccfdeab3df --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env_modify-bad-operation-stderr.txt @@ -0,0 +1,3 @@ +^CMake Error: Error: Unrecognized environment manipulation argument: unknown + +cmake -E env: invalid parameter to --modify: TEST_ENV=unknown:$ diff --git a/Tests/RunCMake/CommandLine/E_env_modify-cmake_list-stdout.txt b/Tests/RunCMake/CommandLine/E_env_modify-cmake_list-stdout.txt new file mode 100644 index 0000000000..ad42f56937 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env_modify-cmake_list-stdout.txt @@ -0,0 +1 @@ +^-- TEST_ENV is correctly set in environment: exp;ect;ed$ diff --git a/Tests/RunCMake/CommandLine/E_env_modify-path_list-stdout.txt b/Tests/RunCMake/CommandLine/E_env_modify-path_list-stdout.txt new file mode 100644 index 0000000000..49572a3d38 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env_modify-path_list-stdout.txt @@ -0,0 +1 @@ +^-- TEST_ENV is correctly set in environment: exp[;:]ect[;:]ed$ diff --git a/Tests/RunCMake/CommandLine/E_env_modify-reset-stdout.txt b/Tests/RunCMake/CommandLine/E_env_modify-reset-stdout.txt new file mode 100644 index 0000000000..a60f1bf302 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env_modify-reset-stdout.txt @@ -0,0 +1 @@ +^-- TEST_ENV is correctly set in environment: expected$ diff --git a/Tests/RunCMake/CommandLine/E_env_modify-reset-to-unset-stdout.txt b/Tests/RunCMake/CommandLine/E_env_modify-reset-to-unset-stdout.txt new file mode 100644 index 0000000000..a1d5c01083 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env_modify-reset-to-unset-stdout.txt @@ -0,0 +1 @@ +^-- TEST_ENV is correctly not set in environment$ diff --git a/Tests/RunCMake/CommandLine/E_env_modify-set-stdout.txt b/Tests/RunCMake/CommandLine/E_env_modify-set-stdout.txt new file mode 100644 index 0000000000..feff1176ea --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env_modify-set-stdout.txt @@ -0,0 +1 @@ +^-- TEST_ENV is correctly set in environment: 1$ diff --git a/Tests/RunCMake/CommandLine/E_env_modify-string-stdout.txt b/Tests/RunCMake/CommandLine/E_env_modify-string-stdout.txt new file mode 100644 index 0000000000..a60f1bf302 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env_modify-string-stdout.txt @@ -0,0 +1 @@ +^-- TEST_ENV is correctly set in environment: expected$ diff --git a/Tests/RunCMake/CommandLine/E_env_modify-unset-stdout.txt b/Tests/RunCMake/CommandLine/E_env_modify-unset-stdout.txt new file mode 100644 index 0000000000..a1d5c01083 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env_modify-unset-stdout.txt @@ -0,0 +1 @@ +^-- TEST_ENV is correctly not set in environment$ diff --git a/Tests/RunCMake/CommandLine/E_env_modify-with-double-dash-result.txt b/Tests/RunCMake/CommandLine/E_env_modify-with-double-dash-result.txt new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env_modify-with-double-dash-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/CommandLine/E_env_modify-without-double-dash-result.txt b/Tests/RunCMake/CommandLine/E_env_modify-without-double-dash-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env_modify-without-double-dash-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_env_modify-without-double-dash-stderr.txt b/Tests/RunCMake/CommandLine/E_env_modify-without-double-dash-stderr.txt new file mode 100644 index 0000000000..8d98f9debd --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env_modify-without-double-dash-stderr.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 39d7858c23..7da0f8d82c 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -744,6 +744,10 @@ run_cmake_command(E_cat-without-double-dash ${CMAKE_COMMAND} -E cat "-file-start unset(RunCMake_TEST_COMMAND_WORKING_DIRECTORY) unset(out) +# Unset environment variables that are used for testing cmake -E +unset(ENV{TEST_ENV}) +unset(ENV{TEST_ENV_EXPECTED}) + run_cmake_command(E_env-no-command0 ${CMAKE_COMMAND} -E env) run_cmake_command(E_env-no-command1 ${CMAKE_COMMAND} -E env TEST_ENV=1) run_cmake_command(E_env-bad-arg1 ${CMAKE_COMMAND} -E env -bad-arg1) @@ -758,6 +762,56 @@ file(COPY_FILE "${EXIT_CODE_EXE}" "${RunCMake_BINARY_DIR}/env=${exit_code}") run_cmake_command(E_env-with-double-dash ${CMAKE_COMMAND} -E env TEST_ENV=1 -- "${RunCMake_BINARY_DIR}/env=${exit_code}" zero_exit) run_cmake_command(E_env-without-double-dash ${CMAKE_COMMAND} -E env TEST_ENV=1 "${RunCMake_BINARY_DIR}/env=${exit_code}" zero_exit) +## Tests of env --modify +# Repeat the same tests as above +run_cmake_command(E_env_modify-set ${CMAKE_COMMAND} -E env --modify TEST_ENV=set:1 ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-set.cmake) +run_cmake_command(E_env_modify-unset ${CMAKE_COMMAND} -E env --modify TEST_ENV=set:1 ${CMAKE_COMMAND} -E env --modify TEST_ENV=unset: ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-unset.cmake) +run_cmake_command(E_env_modify-with-double-dash ${CMAKE_COMMAND} -E env --modify TEST_ENV=set:1 -- "${RunCMake_BINARY_DIR}/env=${exit_code}" zero_exit) +run_cmake_command(E_env_modify-without-double-dash ${CMAKE_COMMAND} -E env --modify TEST_ENV=set:1 "${RunCMake_BINARY_DIR}/env=${exit_code}" zero_exit) + +# Test environment modification commands +run_cmake_command(E_env_modify-reset + ${CMAKE_COMMAND} -E env TEST_ENV=expected + ${CMAKE_COMMAND} -E env TEST_ENV_EXPECTED=expected TEST_ENV=bad_value --modify TEST_ENV=reset: + ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-equal.cmake) + +run_cmake_command(E_env_modify-reset-to-unset + ${CMAKE_COMMAND} -E env --unset=TEST_ENV --unset=TEST_ENV_EXPECTED + ${CMAKE_COMMAND} -E env TEST_ENV=bad_value --modify TEST_ENV=reset: + ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-equal.cmake) + +run_cmake_command(E_env_modify-string + ${CMAKE_COMMAND} -E env TEST_ENV_EXPECTED=expected + --modify TEST_ENV=unset: + --modify TEST_ENV=string_append:ect + --modify TEST_ENV=string_prepend:exp + --modify TEST_ENV=string_append:ed + ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-equal.cmake) + +if (WIN32) + set(SEP "\\;") +else () + set(SEP ":") +endif () + +run_cmake_command(E_env_modify-path_list + ${CMAKE_COMMAND} -E env "TEST_ENV_EXPECTED=exp${SEP}ect${SEP}ed" + --modify TEST_ENV=unset: + --modify TEST_ENV=path_list_append:ect + --modify TEST_ENV=path_list_prepend:exp + --modify TEST_ENV=path_list_append:ed + ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-equal.cmake) + +run_cmake_command(E_env_modify-cmake_list + ${CMAKE_COMMAND} -E env "TEST_ENV_EXPECTED=exp\\;ect\\;ed" + --modify TEST_ENV=unset: + --modify TEST_ENV=cmake_list_append:ect + --modify TEST_ENV=cmake_list_prepend:exp + --modify TEST_ENV=cmake_list_append:ed + ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-equal.cmake) + +run_cmake_command(E_env_modify-bad-operation ${CMAKE_COMMAND} -E env --modify TEST_ENV=unknown:) + run_cmake_command(E_md5sum-dir ${CMAKE_COMMAND} -E md5sum .) run_cmake_command(E_sha1sum-dir ${CMAKE_COMMAND} -E sha1sum .) run_cmake_command(E_sha224sum-dir ${CMAKE_COMMAND} -E sha224sum .) |