summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2022-11-15 14:14:00 (GMT)
committerKitware Robot <kwrobot@kitware.com>2022-11-15 14:14:07 (GMT)
commiteda68d229d6c5e46411c56c213a873962eb41e7a (patch)
tree2e81e108809b8e463f031c6c907b603d4a7a4c33
parentcf0f7046837113926779befa209024e616ec7d38 (diff)
parent8d9069e5b667e1b6d7f1eaea52ae88eb31d7d0df (diff)
downloadCMake-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.rst14
-rw-r--r--Help/release/dev/cmake-E-copy-t-arg.rst4
-rw-r--r--Source/cmCommandLineArgument.h11
-rw-r--r--Source/cmcmd.cxx57
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/RunCMakeTest.cmake6
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