浏览代码

Merge topic 'cmake-E-env-modify'

c9d70a7cc3 cmake -E env: Add --modify flag

Acked-by: Kitware Robot <[email protected]>
Acked-by: buildbot <[email protected]>
Merge-request: !7571
Brad King 3 年之前
父节点
当前提交
36d35d4eb1

+ 20 - 2
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

+ 5 - 0
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.

+ 6 - 1
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();

+ 3 - 0
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.

+ 35 - 3
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;

+ 15 - 0
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 ()

+ 1 - 0
Tests/RunCMake/CommandLine/E_env_modify-bad-operation-result.txt

@@ -0,0 +1 @@
+1

+ 3 - 0
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:$

+ 1 - 0
Tests/RunCMake/CommandLine/E_env_modify-cmake_list-stdout.txt

@@ -0,0 +1 @@
+^-- TEST_ENV is correctly set in environment: exp;ect;ed$

+ 1 - 0
Tests/RunCMake/CommandLine/E_env_modify-path_list-stdout.txt

@@ -0,0 +1 @@
+^-- TEST_ENV is correctly set in environment: exp[;:]ect[;:]ed$

+ 1 - 0
Tests/RunCMake/CommandLine/E_env_modify-reset-stdout.txt

@@ -0,0 +1 @@
+^-- TEST_ENV is correctly set in environment: expected$

+ 1 - 0
Tests/RunCMake/CommandLine/E_env_modify-reset-to-unset-stdout.txt

@@ -0,0 +1 @@
+^-- TEST_ENV is correctly not set in environment$

+ 1 - 0
Tests/RunCMake/CommandLine/E_env_modify-set-stdout.txt

@@ -0,0 +1 @@
+^-- TEST_ENV is correctly set in environment: 1$

+ 1 - 0
Tests/RunCMake/CommandLine/E_env_modify-string-stdout.txt

@@ -0,0 +1 @@
+^-- TEST_ENV is correctly set in environment: expected$

+ 1 - 0
Tests/RunCMake/CommandLine/E_env_modify-unset-stdout.txt

@@ -0,0 +1 @@
+^-- TEST_ENV is correctly not set in environment$

+ 1 - 0
Tests/RunCMake/CommandLine/E_env_modify-with-double-dash-result.txt

@@ -0,0 +1 @@
+0

+ 1 - 0
Tests/RunCMake/CommandLine/E_env_modify-without-double-dash-result.txt

@@ -0,0 +1 @@
+1

+ 1 - 0
Tests/RunCMake/CommandLine/E_env_modify-without-double-dash-stderr.txt

@@ -0,0 +1 @@
+.*

+ 54 - 0
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 .)