Explorar o código

cmake: Add '-E env' command-line tool

Extend the cmake command-line interface to support

 cmake -E env [--unset=NAME]... [NAME=VALUE]... COMMAND [ARG]...

This will be useful to run processes with modified environments
without using a shell or a full "cmake -P" script to wrap it.

Extend the RunCMake.CommandLine test to cover success and failure cases.

Inspired-by: Jonathan Bohren <[email protected]>
Brad King %!s(int64=11) %!d(string=hai) anos
pai
achega
7abd574798

+ 1 - 1
Help/manual/cmake.1.rst

@@ -38,7 +38,7 @@ Options
  For true platform independence, CMake provides a list of commands
  that can be used on all systems.  Run with -E help for the usage
  information.  Commands available are: chdir, compare_files, copy,
- copy_directory, copy_if_different, echo, echo_append, environment,
+ copy_directory, copy_if_different, echo, echo_append, env, environment,
  make_directory, md5sum, remove, remove_directory, rename, sleep, tar, time,
  touch, touch_nocreate.  In addition, some platform specific commands
  are available.  On Windows: delete_regv, write_regv.  On

+ 4 - 0
Help/release/dev/cmake-E-env.rst

@@ -0,0 +1,4 @@
+cmake-E-env
+-----------
+
+* The :manual:`cmake(1)` ``-E`` option learned a new ``env`` command.

+ 51 - 0
Source/cmcmd.cxx

@@ -61,6 +61,8 @@ void CMakeCommandUsage(const char* program)
     << "  echo [string]...          - displays arguments as text\n"
     << "  echo_append [string]...   - displays arguments as text but no new "
        "line\n"
+    << "  env [--unset=NAME]... [NAME=VALUE]... COMMAND [ARG]...\n"
+    << "                            - run command in a modified environment\n"
     << "  environment               - display the current environment\n"
     << "  make_directory dir        - create a directory\n"
     << "  md5sum file1 [...]        - compute md5sum of files\n"
@@ -190,6 +192,55 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
       return 0;
       }
 
+    else if (args[1] == "env" )
+      {
+      std::vector<std::string>::const_iterator ai = args.begin() + 2;
+      std::vector<std::string>::const_iterator ae = args.end();
+      for(; ai != ae; ++ai)
+        {
+        std::string const& a = *ai;
+        if(cmHasLiteralPrefix(a, "--unset="))
+          {
+          // Unset environment variable.
+          cmSystemTools::UnPutEnv(a.c_str() + 8);
+          }
+        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;
+          return 1;
+          }
+        else if(a.find("=") != a.npos)
+          {
+          // Set environment variable.
+          cmSystemTools::PutEnv(a.c_str());
+          }
+        else
+          {
+          // This is the beginning of the command.
+          break;
+          }
+        }
+
+      if(ai == ae)
+        {
+        std::cerr << "cmake -E env: no command given" << std::endl;
+        return 1;
+        }
+
+      // Execute command from remaining arguments.
+      std::vector<std::string> cmd(ai, ae);
+      int retval;
+      if(cmSystemTools::RunSingleCommand(
+           cmd, 0, &retval, NULL, cmSystemTools::OUTPUT_PASSTHROUGH))
+        {
+        return retval;
+        }
+      return 1;
+      }
+
 #if defined(CMAKE_BUILD_WITH_CMAKE)
     // Command to create a symbolic link.  Fails on platforms not
     // supporting them.

+ 1 - 0
Tests/RunCMake/CommandLine/E_env-bad-arg1-result.txt

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

+ 1 - 0
Tests/RunCMake/CommandLine/E_env-bad-arg1-stderr.txt

@@ -0,0 +1 @@
+^cmake -E env: unknown option '-bad-arg1'$

+ 1 - 0
Tests/RunCMake/CommandLine/E_env-no-command0-result.txt

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

+ 1 - 0
Tests/RunCMake/CommandLine/E_env-no-command0-stderr.txt

@@ -0,0 +1 @@
+^cmake -E env: no command given$

+ 1 - 0
Tests/RunCMake/CommandLine/E_env-no-command1-result.txt

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

+ 1 - 0
Tests/RunCMake/CommandLine/E_env-no-command1-stderr.txt

@@ -0,0 +1 @@
+^cmake -E env: no command given$

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

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

+ 5 - 0
Tests/RunCMake/CommandLine/E_env-set.cmake

@@ -0,0 +1,5 @@
+if(DEFINED ENV{TEST_ENV})
+  message(STATUS "TEST_ENV is correctly set in environment: $ENV{TEST_ENV}")
+else()
+  message(FATAL_ERROR "TEST_ENV is incorrectly not set in environment")
+endif()

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

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

+ 5 - 0
Tests/RunCMake/CommandLine/E_env-unset.cmake

@@ -0,0 +1,5 @@
+if(DEFINED ENV{TEST_ENV})
+  message(FATAL_ERROR "TEST_ENV is incorrectly set in environment")
+else()
+  message(STATUS "TEST_ENV is correctly not set in environment")
+endif()

+ 6 - 0
Tests/RunCMake/CommandLine/RunCMakeTest.cmake

@@ -31,6 +31,12 @@ if(UNIX)
     )
 endif()
 
+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)
+run_cmake_command(E_env-set   ${CMAKE_COMMAND} -E env TEST_ENV=1 ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-set.cmake)
+run_cmake_command(E_env-unset ${CMAKE_COMMAND} -E env TEST_ENV=1 ${CMAKE_COMMAND} -E env --unset=TEST_ENV ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-unset.cmake)
+
 run_cmake_command(E_sleep-no-args ${CMAKE_COMMAND} -E sleep)
 run_cmake_command(E_sleep-bad-arg1 ${CMAKE_COMMAND} -E sleep x)
 run_cmake_command(E_sleep-bad-arg2 ${CMAKE_COMMAND} -E sleep 1 -1)