mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-06 05:40:54 -06:00
@@ -848,17 +848,21 @@ Available commands are:
|
|||||||
|
|
||||||
.. program:: cmake-E
|
.. program:: cmake-E
|
||||||
|
|
||||||
.. option:: copy <file>... <destination>
|
.. option:: copy <file>... <destination>, copy -t <destination> <file>...
|
||||||
|
|
||||||
Copy files to ``<destination>`` (either file or directory).
|
Copy files to ``<destination>`` (either file or directory).
|
||||||
If multiple files are specified, the ``<destination>`` must be
|
If multiple files are specified, or if ``-t`` is specified, the
|
||||||
directory and it must exist. Wildcards are not supported.
|
``<destination>`` must be directory and it must exist. If ``-t`` is not
|
||||||
``copy`` does follow symlinks. That means it does not copy symlinks,
|
specified, the last argument is assumed to be the ``<destination>``.
|
||||||
but the files or directories it point to.
|
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
|
.. versionadded:: 3.5
|
||||||
Support for multiple input files.
|
Support for multiple input files.
|
||||||
|
|
||||||
|
.. versionadded:: 3.26
|
||||||
|
Support for ``-t`` argument.
|
||||||
|
|
||||||
.. option:: copy_directory <dir>... <destination>
|
.. option:: copy_directory <dir>... <destination>
|
||||||
|
|
||||||
Copy content of ``<dir>...`` directories to ``<destination>`` directory.
|
Copy content of ``<dir>...`` directories to ``<destination>`` directory.
|
||||||
|
|||||||
4
Help/release/dev/cmake-E-copy-t-arg.rst
Normal file
4
Help/release/dev/cmake-E-copy-t-arg.rst
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
cmake-E-copy-t-arg
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* The :option:`cmake -E copy <cmake-E copy>` argument now supports a ``-t`` argument.
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cm/optional>
|
||||||
|
|
||||||
#include "cmStringAlgorithms.h"
|
#include "cmStringAlgorithms.h"
|
||||||
#include "cmSystemTools.h"
|
#include "cmSystemTools.h"
|
||||||
|
|
||||||
@@ -250,6 +252,15 @@ private:
|
|||||||
return true;
|
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,
|
std::string extract_single_value(std::string const& input,
|
||||||
|
|||||||
@@ -2,11 +2,15 @@
|
|||||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||||
#include "cmcmd.h"
|
#include "cmcmd.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <cm/optional>
|
||||||
#include <cmext/algorithm>
|
#include <cmext/algorithm>
|
||||||
|
|
||||||
#include <cm3p/uv.h>
|
#include <cm3p/uv.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "cmCommandLineArgument.h"
|
||||||
#include "cmConsoleBuf.h"
|
#include "cmConsoleBuf.h"
|
||||||
#include "cmDuration.h"
|
#include "cmDuration.h"
|
||||||
#include "cmGlobalGenerator.h"
|
#include "cmGlobalGenerator.h"
|
||||||
@@ -640,20 +644,59 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
|
|||||||
if (args.size() > 1) {
|
if (args.size() > 1) {
|
||||||
// Copy file
|
// Copy file
|
||||||
if (args[1] == "copy" && args.size() > 3) {
|
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,
|
// If multiple source files specified,
|
||||||
// then destination must be directory
|
// then destination must be directory
|
||||||
if ((args.size() > 4) &&
|
if (files.size() > 2 && !targetArg) {
|
||||||
(!cmSystemTools::FileIsDirectory(args.back()))) {
|
targetArg = files.back();
|
||||||
std::cerr << "Error: Target (for copy command) \"" << args.back()
|
files.pop_back();
|
||||||
|
}
|
||||||
|
if (targetArg && (!cmSystemTools::FileIsDirectory(*targetArg))) {
|
||||||
|
std::cerr << "Error: Target (for copy command) \"" << *targetArg
|
||||||
<< "\" is not a directory.\n";
|
<< "\" is not a directory.\n";
|
||||||
return 1;
|
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.
|
// If error occurs we want to continue copying next files.
|
||||||
bool return_value = false;
|
bool return_value = false;
|
||||||
for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
|
for (auto const& file : files) {
|
||||||
if (!cmsys::SystemTools::CopyFileAlways(arg, args.back())) {
|
if (!cmsys::SystemTools::CopyFileAlways(file, *targetArg)) {
|
||||||
std::cerr << "Error copying file \"" << arg << "\" to \""
|
std::cerr << "Error copying file \"" << file << "\" to \""
|
||||||
<< args.back() << "\".\n";
|
<< *targetArg << "\".\n";
|
||||||
return_value = true;
|
return_value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
1
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
^Error: Target \(for copy command\).* is not a directory.$
|
||||||
@@ -574,6 +574,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)
|
${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
|
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})
|
${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
|
run_cmake_command(E_copy_if_different-one-source-directory-target-is-directory
|
||||||
${CMAKE_COMMAND} -E copy_if_different ${in}/f1.txt ${out})
|
${CMAKE_COMMAND} -E copy_if_different ${in}/f1.txt ${out})
|
||||||
run_cmake_command(E_copy_if_different-three-source-files-target-is-directory
|
run_cmake_command(E_copy_if_different-three-source-files-target-is-directory
|
||||||
|
|||||||
Reference in New Issue
Block a user