summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Help/manual/cmake.1.rst22
-rw-r--r--Help/release/dev/cmake-E-env-modify.rst5
-rw-r--r--Source/cmSystemTools.cxx7
-rw-r--r--Source/cmSystemTools.h3
-rw-r--r--Source/cmcmd.cxx38
-rw-r--r--Tests/RunCMake/CommandLine/E_env-equal.cmake15
-rw-r--r--Tests/RunCMake/CommandLine/E_env_modify-bad-operation-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env_modify-bad-operation-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/E_env_modify-cmake_list-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env_modify-path_list-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env_modify-reset-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env_modify-reset-to-unset-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env_modify-set-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env_modify-string-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env_modify-unset-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env_modify-with-double-dash-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env_modify-without-double-dash-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env_modify-without-double-dash-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/RunCMakeTest.cmake54
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 .)