diff options
author | Brad King <brad.king@kitware.com> | 2022-11-15 14:14:00 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2022-11-15 14:14:07 (GMT) |
commit | eda68d229d6c5e46411c56c213a873962eb41e7a (patch) | |
tree | 2e81e108809b8e463f031c6c907b603d4a7a4c33 | |
parent | cf0f7046837113926779befa209024e616ec7d38 (diff) | |
parent | 8d9069e5b667e1b6d7f1eaea52ae88eb31d7d0df (diff) | |
download | CMake-eda68d229d6c5e46411c56c213a873962eb41e7a.zip CMake-eda68d229d6c5e46411c56c213a873962eb41e7a.tar.gz CMake-eda68d229d6c5e46411c56c213a873962eb41e7a.tar.bz2 |
Merge topic 'cmake-E-copy-t-mode'
8d9069e5b6 cmake -E copy: Add support for -t argument
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !7913
-rw-r--r-- | Help/manual/cmake.1.rst | 14 | ||||
-rw-r--r-- | Help/release/dev/cmake-E-copy-t-arg.rst | 4 | ||||
-rw-r--r-- | Source/cmCommandLineArgument.h | 11 | ||||
-rw-r--r-- | Source/cmcmd.cxx | 57 | ||||
-rw-r--r-- | Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-result.txt | 1 | ||||
-rw-r--r-- | Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-stderr.txt | 1 | ||||
-rw-r--r-- | Tests/RunCMake/CommandLine/RunCMakeTest.cmake | 6 |
7 files changed, 82 insertions, 12 deletions
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index daa2e58..dc51383 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -848,17 +848,21 @@ Available commands are: .. program:: cmake-E -.. option:: copy <file>... <destination> +.. option:: copy <file>... <destination>, copy -t <destination> <file>... Copy files to ``<destination>`` (either file or directory). - If multiple files are specified, the ``<destination>`` must be - directory and it must exist. Wildcards are not supported. - ``copy`` does follow symlinks. That means it does not copy symlinks, - but the files or directories it point to. + If multiple files are specified, or if ``-t`` is specified, the + ``<destination>`` must be directory and it must exist. If ``-t`` is not + specified, the last argument is assumed to be the ``<destination>``. + Wildcards are not supported. ``copy`` does follow symlinks. That means it + does not copy symlinks, but the files or directories it point to. .. versionadded:: 3.5 Support for multiple input files. + .. versionadded:: 3.26 + Support for ``-t`` argument. + .. option:: copy_directory <dir>... <destination> Copy content of ``<dir>...`` directories to ``<destination>`` directory. diff --git a/Help/release/dev/cmake-E-copy-t-arg.rst b/Help/release/dev/cmake-E-copy-t-arg.rst new file mode 100644 index 0000000..ca897d3 --- /dev/null +++ b/Help/release/dev/cmake-E-copy-t-arg.rst @@ -0,0 +1,4 @@ +cmake-E-copy-t-arg +------------------ + +* The :option:`cmake -E copy <cmake-E copy>` argument now supports a ``-t`` argument. diff --git a/Source/cmCommandLineArgument.h b/Source/cmCommandLineArgument.h index 33c91bc..003e972 100644 --- a/Source/cmCommandLineArgument.h +++ b/Source/cmCommandLineArgument.h @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once +#include <cm/optional> + #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -250,6 +252,15 @@ private: return true; }; } + + static std::function<bool(const std::string&, CallState...)> + generateSetToValue(cm::optional<std::string>& value1) + { + return [&value1](const std::string& arg, CallState&&...) -> bool { + value1 = arg; + return true; + }; + } }; std::string extract_single_value(std::string const& input, diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 67394f9..06bceb4 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -2,11 +2,15 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmcmd.h" +#include <functional> + +#include <cm/optional> #include <cmext/algorithm> #include <cm3p/uv.h> #include <fcntl.h> +#include "cmCommandLineArgument.h" #include "cmConsoleBuf.h" #include "cmDuration.h" #include "cmGlobalGenerator.h" @@ -640,20 +644,59 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, if (args.size() > 1) { // Copy file if (args[1] == "copy" && args.size() > 3) { + using CommandArgument = + cmCommandLineArgument<bool(const std::string& value)>; + + cm::optional<std::string> targetArg; + std::vector<CommandArgument> argParsers{ + { "-t", CommandArgument::Values::One, + CommandArgument::setToValue(targetArg) }, + }; + + std::vector<std::string> files; + for (decltype(args.size()) i = 2; i < args.size(); i++) { + const std::string& arg = args[i]; + bool matched = false; + for (auto const& m : argParsers) { + if (m.matches(arg)) { + matched = true; + if (m.parse(arg, i, args)) { + break; + } + return 1; // failed to parse + } + } + if (!matched) { + files.push_back(arg); + } + } + // If multiple source files specified, // then destination must be directory - if ((args.size() > 4) && - (!cmSystemTools::FileIsDirectory(args.back()))) { - std::cerr << "Error: Target (for copy command) \"" << args.back() + if (files.size() > 2 && !targetArg) { + targetArg = files.back(); + files.pop_back(); + } + if (targetArg && (!cmSystemTools::FileIsDirectory(*targetArg))) { + std::cerr << "Error: Target (for copy command) \"" << *targetArg << "\" is not a directory.\n"; return 1; } + if (!targetArg) { + if (files.size() < 2) { + std::cerr + << "Error: No files or target specified (for copy command).\n"; + return 1; + } + targetArg = files.back(); + files.pop_back(); + } // If error occurs we want to continue copying next files. bool return_value = false; - for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) { - if (!cmsys::SystemTools::CopyFileAlways(arg, args.back())) { - std::cerr << "Error copying file \"" << arg << "\" to \"" - << args.back() << "\".\n"; + for (auto const& file : files) { + if (!cmsys::SystemTools::CopyFileAlways(file, *targetArg)) { + std::cerr << "Error copying file \"" << file << "\" to \"" + << *targetArg << "\".\n"; return_value = true; } } diff --git a/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-result.txt b/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-stderr.txt b/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-stderr.txt new file mode 100644 index 0000000..9504216 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-stderr.txt @@ -0,0 +1 @@ +^Error: Target \(for copy command\).* is not a directory.$ diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index a38b146..08c5a49 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -576,6 +576,12 @@ run_cmake_command(E_copy-three-source-files-target-is-file ${CMAKE_COMMAND} -E copy ${in}/f1.txt ${in}/f2.txt ${in}/f3.txt ${out}/f1.txt) run_cmake_command(E_copy-two-good-and-one-bad-source-files-target-is-directory ${CMAKE_COMMAND} -E copy ${in}/f1.txt ${in}/not_existing_file.bad ${in}/f3.txt ${out}) +run_cmake_command(E_copy-t-argument + ${CMAKE_COMMAND} -E copy ${in}/f1.txt -t ${out} ${in}/f3.txt) +run_cmake_command(E_copy-t-argument-target-is-file + ${CMAKE_COMMAND} -E copy ${in}/f1.txt -t ${out}/f1.txt ${in}/f3.txt) +run_cmake_command(E_copy-t-argument-no-source-files + ${CMAKE_COMMAND} -E copy -t ${out}) run_cmake_command(E_copy_if_different-one-source-directory-target-is-directory ${CMAKE_COMMAND} -E copy_if_different ${in}/f1.txt ${out}) run_cmake_command(E_copy_if_different-three-source-files-target-is-directory |