Browse Source

cmcmd: add end of options delimiter to cmake -E commands

Implements a -- delimiter, that indicates the end of options (starting
with a dash -) of a command and separates them from the subsequent
operands (positional arguments).

The following commands are affected:
- env: Implemented the -- delimiter.
- cat: The -- delimiter was already kind of considered, but its
  occurence did not stop the options parsing.
- rm: Here the command already implemented the -- delimiter as
  specified, but it was not documented.

Fixes #22970
pull/348/head
Peter Würth 4 years ago
parent
commit
b10930040d
  1. 21
      Help/manual/cmake.1.rst
  2. 7
      Help/release/dev/cmcmd-end-of-options-delimiter.rst
  3. 23
      Source/cmcmd.cxx
  4. 3
      Tests/RunCMake/CMakeLists.txt
  5. 1
      Tests/RunCMake/CommandLine/E_cat-with-double-dash-stdout.txt
  6. 1
      Tests/RunCMake/CommandLine/E_cat-without-double-dash-result.txt
  7. 1
      Tests/RunCMake/CommandLine/E_cat-without-double-dash-stderr.txt
  8. 1
      Tests/RunCMake/CommandLine/E_env-with-double-dash-result.txt
  9. 1
      Tests/RunCMake/CommandLine/E_env-without-double-dash-result.txt
  10. 1
      Tests/RunCMake/CommandLine/E_env-without-double-dash-stderr.txt
  11. 18
      Tests/RunCMake/CommandLine/RunCMakeTest.cmake

21
Help/manual/cmake.1.rst

@ -646,11 +646,17 @@ Available commands are:
``true`` if cmake supports server-mode and ``false`` otherwise.
Always false since CMake 3.20.
``cat <files>...``
``cat [--] <files>...``
.. versionadded:: 3.18
Concatenate files and print on the standard output.
.. versionadded:: 3.24
Added support for the double dash argument ``--``. This basic implementation
of ``cat`` does not support any options, so using a option starting with
``-`` will result in an error. Use ``--`` to indicate the end of options, in
case a file starts with ``-``.
``chdir <dir> <cmd> [<arg>...]``
Change the current working directory and run a command.
@ -719,11 +725,16 @@ Available commands are:
``echo_append [<string>...]``
Displays arguments as text but no new line.
``env [--unset=NAME]... [NAME=VALUE]... COMMAND [ARG]...``
``env [--unset=NAME ...] [NAME=VALUE ...] [--] <command> [<arg>...]``
.. versionadded:: 3.1
Run command in a modified environment.
.. versionadded:: 3.24
Added support for the double dash argument ``--``. Use ``--`` to stop
interpreting options/environment variables and treat the next argument as
the command, even if it start with ``-`` or contains a ``=``.
``environment``
Display the current environment variables.
@ -816,16 +827,16 @@ Available commands are:
Rename a file or directory (on one volume). If file with the ``<newname>`` name
already exists, then it will be silently replaced.
``rm [-rRf] <file> <dir>...``
``rm [-rRf] [--] <file|dir>...``
.. versionadded:: 3.17
Remove the files ``<file>`` or directories ``<dir>``.
Use ``-r`` or ``-R`` to remove directories and their contents recursively.
If any of the listed files/directories do not exist, the command returns a
non-zero exit code, but no message is logged. The ``-f`` option changes
the behavior to return a zero exit code (i.e. success) in such
situations instead.
situations instead. Use ``--`` to stop interpreting options and treat all
remaining arguments as paths, even if they start with ``-``.
``server``
Launch :manual:`cmake-server(7)` mode.

7
Help/release/dev/cmcmd-end-of-options-delimiter.rst

@ -0,0 +1,7 @@
cmcmd-end-of-options-delimiter
------------------------------
* The :manual:`cmake(1)` ``-E`` commands ``cat`` and ``env`` learned to respect
a double dash (``--``) argument that acts as a delimiter indicating the end of
options. Any following arguments are treated as operands/positional arguments,
even if they begin with a dash ``-`` character.

23
Source/cmcmd.cxx

@ -97,7 +97,8 @@ void CMakeCommandUsage(std::string const& program)
<< "Available commands: \n"
<< " capabilities - Report capabilities built into cmake "
"in JSON format\n"
<< " cat <files>... - concat the files and print them to the standard output\n"
<< " cat [--] <files>... - concat the files and print them to the "
"standard output\n"
<< " chdir dir cmd [args...] - run command in a given directory\n"
<< " compare_files [--ignore-eol] file1 file2\n"
<< " - check if file1 is same as file2\n"
@ -110,7 +111,7 @@ void CMakeCommandUsage(std::string const& 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"
<< " 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 parent and <dir> directories\n"
@ -125,8 +126,9 @@ void CMakeCommandUsage(std::string const& program)
<< " remove_directory <dir>... - remove directories and their contents (deprecated: use rm instead)\n"
<< " rename oldname newname - rename a file or directory "
"(on one volume)\n"
<< " rm [-rRf] <file/dir>... - remove files or directories, use -f to "
"force it, r or R to remove directories and their contents recursively\n"
<< " rm [-rRf] [--] <file/dir>... - remove files or directories, use -f "
"to force it, r or R to remove directories and their contents "
"recursively\n"
<< " sleep <number>... - sleep for given number of seconds\n"
<< " tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n"
<< " - create or extract a tar or zip archive\n"
@ -793,6 +795,12 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
auto ae = args.cend();
for (; ai != ae; ++ai) {
std::string const& a = *ai;
if (a == "--") {
// Stop parsing options/environment variables; the next argument
// should be the command.
++ai;
break;
}
if (cmHasLiteralPrefix(a, "--unset=")) {
// Unset environment variable.
cmSystemTools::UnPutEnv(a.substr(8));
@ -1051,9 +1059,12 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
// Command to concat files into one
if (args[1] == "cat" && args.size() >= 3) {
int return_value = 0;
bool doing_options = true;
for (auto const& arg : cmMakeRange(args).advance(2)) {
if (cmHasLiteralPrefix(arg, "-")) {
if (arg != "--") {
if (doing_options && cmHasLiteralPrefix(arg, "-")) {
if (arg == "--") {
doing_options = false;
} else {
cmSystemTools::Error(arg + ": option not handled");
return_value = 1;
}

3
Tests/RunCMake/CMakeLists.txt

@ -703,7 +703,8 @@ endif()
add_executable(pseudo_llvm-rc pseudo_llvm-rc.c)
add_RunCMake_test(CommandLine -DLLVM_RC=$<TARGET_FILE:pseudo_llvm-rc> -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
-DCYGWIN=${CYGWIN} -DMSYS=${MSYS} -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE})
-DCYGWIN=${CYGWIN} -DMSYS=${MSYS} -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
-DEXIT_CODE_EXE=$<TARGET_FILE:exit_code>)
add_RunCMake_test(CommandLineTar)
if(CMAKE_PLATFORM_NO_VERSIONED_SONAME OR (NOT CMAKE_SHARED_LIBRARY_SONAME_FLAG AND NOT CMAKE_SHARED_LIBRARY_SONAME_C_FLAG))

1
Tests/RunCMake/CommandLine/E_cat-with-double-dash-stdout.txt

@ -0,0 +1 @@
file starting with dash, not an option

1
Tests/RunCMake/CommandLine/E_cat-without-double-dash-result.txt

@ -0,0 +1 @@
1

1
Tests/RunCMake/CommandLine/E_cat-without-double-dash-stderr.txt

@ -0,0 +1 @@
^CMake Error: -file-starting-with-dash.txt: option not handled$

1
Tests/RunCMake/CommandLine/E_env-with-double-dash-result.txt

@ -0,0 +1 @@
0

1
Tests/RunCMake/CommandLine/E_env-without-double-dash-result.txt

@ -0,0 +1 @@
1

1
Tests/RunCMake/CommandLine/E_env-without-double-dash-stderr.txt

@ -0,0 +1 @@
.*

18
Tests/RunCMake/CommandLine/RunCMakeTest.cmake

@ -676,17 +676,33 @@ file(WRITE "${out}/empty_file.txt" "")
file(WRITE "${out}/unicode_file.txt" "àéùç - 한국어") # Korean in Korean
run_cmake_command(E_cat_good_cat
${CMAKE_COMMAND} -E cat "${out}/first_file.txt" "${out}/second_file.txt" "${out}/empty_file.txt" "${out}/unicode_file.txt")
unset(out)
run_cmake_command(E_cat_good_binary_cat
${CMAKE_COMMAND} -E cat "${RunCMake_SOURCE_DIR}/E_cat_binary_files/binary.obj" "${RunCMake_SOURCE_DIR}/E_cat_binary_files/binary.obj")
# To test whether the double dash (--) works, we need to control the working directory
# in order to be able to pass a relative path that starts with a dash.
file(WRITE "${out}/-file-starting-with-dash.txt" "file starting with dash, not an option\n")
set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${out}")
run_cmake_command(E_cat-with-double-dash ${CMAKE_COMMAND} -E cat -- "-file-starting-with-dash.txt")
run_cmake_command(E_cat-without-double-dash ${CMAKE_COMMAND} -E cat "-file-starting-with-dash.txt")
unset(RunCMake_TEST_COMMAND_WORKING_DIRECTORY)
unset(out)
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)
# To test whether the double dash (--) works for the env command, we need a command that e.g. contains an equals sign (=)
# and would normally be interpreted as an NAME=VALUE environment variable.
# Ensuring such a command is done by simply copying the trivial exit_code executable with a different name.
cmake_path(GET EXIT_CODE_EXE FILENAME exit_code)
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)
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 .)

Loading…
Cancel
Save