summaryrefslogtreecommitdiffstats
path: root/Source/cmFileCommand.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmFileCommand.cxx')
-rw-r--r--Source/cmFileCommand.cxx382
1 files changed, 364 insertions, 18 deletions
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index e36abdc..7101e22 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -16,13 +16,14 @@
#include <cm/memory>
#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include <cm3p/kwiml/int.h>
#include "cmsys/FStream.hxx"
#include "cmsys/Glob.hxx"
#include "cmsys/RegularExpression.hxx"
-#include "cm_kwiml.h"
-#include "cm_static_string_view.hxx"
#include "cm_sys_stat.h"
#include "cmAlgorithms.h"
@@ -33,12 +34,14 @@
#include "cmFileInstaller.h"
#include "cmFileLockPool.h"
#include "cmFileTimes.h"
+#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
#include "cmHexFileConverter.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmNewLineStyle.h"
#include "cmPolicies.h"
#include "cmRange.h"
#include "cmRuntimeDependencyArchive.h"
@@ -47,10 +50,11 @@
#include "cmSubcommandTable.h"
#include "cmSystemTools.h"
#include "cmTimestamp.h"
+#include "cmWorkingDirectory.h"
#include "cmake.h"
#if !defined(CMAKE_BOOTSTRAP)
-# include "cm_curl.h"
+# include <cm3p/curl/curl.h>
# include "cmCurl.h"
# include "cmFileLockResult.h"
@@ -672,12 +676,12 @@ bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse,
}
}
+ cmake* cm = status.GetMakefile().GetCMakeInstance();
std::vector<std::string> files;
bool configureDepends = false;
bool warnConfigureLate = false;
bool warnFollowedSymlinks = false;
- const cmake::WorkingMode workingMode =
- status.GetMakefile().GetCMakeInstance()->GetWorkingMode();
+ const cmake::WorkingMode workingMode = cm->GetWorkingMode();
while (i != args.end()) {
if (*i == "LIST_DIRECTORIES") {
++i; // skip LIST_DIRECTORIES
@@ -765,12 +769,17 @@ bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse,
MessageType::AUTHOR_WARNING,
"Cyclic recursion detected while globbing for '" + *i + "':\n" +
globMessage.content);
- } else {
+ } else if (globMessage.type == cmsys::Glob::error) {
status.GetMakefile().IssueMessage(
MessageType::FATAL_ERROR,
"Error has occurred while globbing for '" + *i + "' - " +
globMessage.content);
shouldExit = true;
+ } else if (cm->GetDebugOutput() || cm->GetTrace()) {
+ status.GetMakefile().IssueMessage(
+ MessageType::LOG,
+ cmStrCat("Globbing for\n ", *i, "\nEncountered an error:\n ",
+ globMessage.content));
}
}
if (shouldExit) {
@@ -790,7 +799,7 @@ bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse,
std::sort(foundFiles.begin(), foundFiles.end());
foundFiles.erase(std::unique(foundFiles.begin(), foundFiles.end()),
foundFiles.end());
- status.GetMakefile().GetCMakeInstance()->AddGlobCacheEntry(
+ cm->AddGlobCacheEntry(
recurse, (recurse ? g.GetRecurseListDirs() : g.GetListDirs()),
(recurse ? g.GetRecurseThroughSymlinks() : false),
(g.GetRelative() ? g.GetRelative() : ""), expr, foundFiles, variable,
@@ -1606,7 +1615,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
if (i != args.end()) {
tls_verify = cmIsOn(*i);
} else {
- status.SetError("TLS_VERIFY missing bool value.");
+ status.SetError("DOWNLOAD missing bool value for TLS_VERIFY.");
return false;
}
} else if (*i == "TLS_CAINFO") {
@@ -1614,7 +1623,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
if (i != args.end()) {
cainfo = i->c_str();
} else {
- status.SetError("TLS_CAFILE missing file value.");
+ status.SetError("DOWNLOAD missing file value for TLS_CAINFO.");
return false;
}
} else if (*i == "NETRC_FILE") {
@@ -1756,11 +1765,12 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
// check to see if TLS verification is requested
if (tls_verify) {
res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
- check_curl_result(res, "Unable to set TLS/SSL Verify on: ");
+ check_curl_result(res, "DOWNLOAD cannot set TLS/SSL Verify on: ");
} else {
res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
- check_curl_result(res, "Unable to set TLS/SSL Verify off: ");
+ check_curl_result(res, "DOWNLOAD cannot set TLS/SSL Verify off: ");
}
+
// check to see if a CAINFO file has been specified
// command arg comes first
std::string const& cainfo_err = cmCurlSetCAInfo(curl, cainfo);
@@ -1925,6 +1935,8 @@ bool HandleUploadCommand(std::vector<std::string> const& args,
std::string logVar;
std::string statusVar;
bool showProgress = false;
+ bool tls_verify = status.GetMakefile().IsOn("CMAKE_TLS_VERIFY");
+ const char* cainfo = status.GetMakefile().GetDefinition("CMAKE_TLS_CAINFO");
std::string userpwd;
std::string netrc_level =
status.GetMakefile().GetSafeDefinition("CMAKE_NETRC");
@@ -1966,6 +1978,22 @@ bool HandleUploadCommand(std::vector<std::string> const& args,
statusVar = *i;
} else if (*i == "SHOW_PROGRESS") {
showProgress = true;
+ } else if (*i == "TLS_VERIFY") {
+ ++i;
+ if (i != args.end()) {
+ tls_verify = cmIsOn(*i);
+ } else {
+ status.SetError("UPLOAD missing bool value for TLS_VERIFY.");
+ return false;
+ }
+ } else if (*i == "TLS_CAINFO") {
+ ++i;
+ if (i != args.end()) {
+ cainfo = i->c_str();
+ } else {
+ status.SetError("UPLOAD missing file value for TLS_CAINFO.");
+ return false;
+ }
} else if (*i == "NETRC_FILE") {
++i;
if (i != args.end()) {
@@ -2051,8 +2079,18 @@ bool HandleUploadCommand(std::vector<std::string> const& args,
cmFileCommandCurlDebugCallback);
check_curl_result(res, "UPLOAD cannot set debug function: ");
- // make sure default CAInfo is set
- std::string const& cainfo_err = cmCurlSetCAInfo(curl, nullptr);
+ // check to see if TLS verification is requested
+ if (tls_verify) {
+ res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
+ check_curl_result(res, "UPLOAD cannot set TLS/SSL Verify on: ");
+ } else {
+ res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
+ check_curl_result(res, "UPLOAD cannot set TLS/SSL Verify off: ");
+ }
+
+ // check to see if a CAINFO file has been specified
+ // command arg comes first
+ std::string const& cainfo_err = cmCurlSetCAInfo(curl, cainfo);
if (!cainfo_err.empty()) {
status.SetError(cainfo_err);
return false;
@@ -2330,12 +2368,9 @@ bool HandleLockCommand(std::vector<std::string> const& args,
path += "/cmake.lock";
}
- if (!cmsys::SystemTools::FileIsFullPath(path)) {
- path = status.GetMakefile().GetCurrentSourceDirectory() + "/" + path;
- }
-
// Unify path (remove '//', '/../', ...)
- path = cmSystemTools::CollapseFullPath(path);
+ path = cmSystemTools::CollapseFullPath(
+ path, status.GetMakefile().GetCurrentSourceDirectory());
// Create file and directories if needed
std::string parentDir = cmSystemTools::GetParentDirectory(path);
@@ -2783,6 +2818,314 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
return true;
}
+bool HandleConfigureCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 5) {
+ status.SetError("Incorrect arguments to CONFIGURE subcommand.");
+ return false;
+ }
+ if (args[1] != "OUTPUT") {
+ status.SetError("Incorrect arguments to CONFIGURE subcommand.");
+ return false;
+ }
+ if (args[3] != "CONTENT") {
+ status.SetError("Incorrect arguments to CONFIGURE subcommand.");
+ return false;
+ }
+
+ std::string errorMessage;
+ cmNewLineStyle newLineStyle;
+ if (!newLineStyle.ReadFromArguments(args, errorMessage)) {
+ status.SetError(cmStrCat("CONFIGURE ", errorMessage));
+ return false;
+ }
+
+ bool escapeQuotes = false;
+ bool atOnly = false;
+ for (unsigned int i = 5; i < args.size(); ++i) {
+ if (args[i] == "@ONLY") {
+ atOnly = true;
+ } else if (args[i] == "ESCAPE_QUOTES") {
+ escapeQuotes = true;
+ } else if (args[i] == "NEWLINE_STYLE" || args[i] == "LF" ||
+ args[i] == "UNIX" || args[i] == "CRLF" || args[i] == "WIN32" ||
+ args[i] == "DOS") {
+ /* Options handled by NewLineStyle member above. */
+ } else {
+ status.SetError(
+ cmStrCat("CONFIGURE Unrecognized argument \"", args[i], "\""));
+ return false;
+ }
+ }
+
+ // Check for generator expressions
+ const std::string input = args[4];
+ std::string outputFile = cmSystemTools::CollapseFullPath(
+ args[2], status.GetMakefile().GetCurrentBinaryDirectory());
+
+ std::string::size_type pos = input.find_first_of("<>");
+ if (pos != std::string::npos) {
+ status.SetError(cmStrCat("CONFIGURE called with CONTENT containing a \"",
+ input[pos],
+ "\". This character is not allowed."));
+ return false;
+ }
+
+ pos = outputFile.find_first_of("<>");
+ if (pos != std::string::npos) {
+ status.SetError(cmStrCat("CONFIGURE called with OUTPUT containing a \"",
+ outputFile[pos],
+ "\". This character is not allowed."));
+ return false;
+ }
+
+ cmMakefile& makeFile = status.GetMakefile();
+ if (!makeFile.CanIWriteThisFile(outputFile)) {
+ cmSystemTools::Error("Attempt to write file: " + outputFile +
+ " into a source directory.");
+ return false;
+ }
+
+ cmSystemTools::ConvertToUnixSlashes(outputFile);
+
+ // Re-generate if non-temporary outputs are missing.
+ // when we finalize the configuration we will remove all
+ // output files that now don't exist.
+ makeFile.AddCMakeOutputFile(outputFile);
+
+ // Create output directory
+ const std::string::size_type slashPos = outputFile.rfind('/');
+ if (slashPos != std::string::npos) {
+ const std::string path = outputFile.substr(0, slashPos);
+ cmSystemTools::MakeDirectory(path);
+ }
+
+ std::string newLineCharacters;
+ bool open_with_binary_flag = false;
+ if (newLineStyle.IsValid()) {
+ open_with_binary_flag = true;
+ newLineCharacters = newLineStyle.GetCharacters();
+ }
+
+ cmGeneratedFileStream fout;
+ fout.Open(outputFile, false, open_with_binary_flag);
+ if (!fout) {
+ cmSystemTools::Error("Could not open file for write in copy operation " +
+ outputFile);
+ cmSystemTools::ReportLastSystemError("");
+ return false;
+ }
+ fout.SetCopyIfDifferent(true);
+
+ // copy intput to output and expand variables from input at the same time
+ std::stringstream sin(input, std::ios::in);
+ std::string inLine;
+ std::string outLine;
+ while (cmSystemTools::GetLineFromStream(sin, inLine)) {
+ outLine.clear();
+ makeFile.ConfigureString(inLine, outLine, atOnly, escapeQuotes);
+ fout << outLine << newLineCharacters;
+ }
+
+ // close file before attempting to copy
+ fout.close();
+
+ return true;
+}
+
+bool HandleArchiveCreateCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ struct Arguments
+ {
+ std::string Output;
+ std::string Format;
+ std::string Compression;
+ std::string MTime;
+ bool Verbose = false;
+ std::vector<std::string> Paths;
+ };
+
+ static auto const parser = cmArgumentParser<Arguments>{}
+ .Bind("OUTPUT"_s, &Arguments::Output)
+ .Bind("FORMAT"_s, &Arguments::Format)
+ .Bind("COMPRESSION"_s, &Arguments::Compression)
+ .Bind("MTIME"_s, &Arguments::MTime)
+ .Bind("VERBOSE"_s, &Arguments::Verbose)
+ .Bind("PATHS"_s, &Arguments::Paths);
+
+ std::vector<std::string> unrecognizedArguments;
+ std::vector<std::string> keywordsMissingValues;
+ auto parsedArgs =
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
+ &keywordsMissingValues);
+ auto argIt = unrecognizedArguments.begin();
+ if (argIt != unrecognizedArguments.end()) {
+ status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\""));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ const std::vector<std::string> LIST_ARGS = { "OUTPUT", "FORMAT",
+ "COMPRESSION", "MTIME",
+ "PATHS" };
+ auto kwbegin = keywordsMissingValues.cbegin();
+ auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
+ if (kwend != kwbegin) {
+ status.SetError(cmStrCat("Keywords missing values:\n ",
+ cmJoin(cmMakeRange(kwbegin, kwend), "\n ")));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ const char* knownFormats[] = {
+ "7zip", "gnutar", "pax", "paxr", "raw", "zip"
+ };
+
+ if (!parsedArgs.Format.empty() &&
+ !cm::contains(knownFormats, parsedArgs.Format)) {
+ status.SetError(
+ cmStrCat("archive format ", parsedArgs.Format, " not supported"));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ const char* zipFileFormats[] = { "7zip", "zip" };
+ if (!parsedArgs.Compression.empty() &&
+ cm::contains(zipFileFormats, parsedArgs.Format)) {
+ status.SetError(cmStrCat("archive format ", parsedArgs.Format,
+ " does not support COMPRESSION arguments"));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ static std::map<std::string, cmSystemTools::cmTarCompression>
+ compressionTypeMap = { { "None", cmSystemTools::TarCompressNone },
+ { "BZip2", cmSystemTools::TarCompressBZip2 },
+ { "GZip", cmSystemTools::TarCompressGZip },
+ { "XZ", cmSystemTools::TarCompressXZ },
+ { "Zstd", cmSystemTools::TarCompressZstd } };
+
+ cmSystemTools::cmTarCompression compress = cmSystemTools::TarCompressNone;
+ auto typeIt = compressionTypeMap.find(parsedArgs.Compression);
+ if (typeIt != compressionTypeMap.end()) {
+ compress = typeIt->second;
+ } else if (!parsedArgs.Compression.empty()) {
+ status.SetError(cmStrCat("compression type ", parsedArgs.Compression,
+ " is not supported"));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (parsedArgs.Paths.empty()) {
+ status.SetError("ARCHIVE_CREATE requires a non-empty list of PATHS");
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!cmSystemTools::CreateTar(parsedArgs.Output, parsedArgs.Paths, compress,
+ parsedArgs.Verbose, parsedArgs.MTime,
+ parsedArgs.Format)) {
+ status.SetError(cmStrCat("failed to compress: ", parsedArgs.Output));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ return true;
+}
+
+bool HandleArchiveExtractCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ struct Arguments
+ {
+ std::string Input;
+ bool Verbose = false;
+ bool ListOnly = false;
+ std::string Destination;
+ std::vector<std::string> Patterns;
+ };
+
+ static auto const parser = cmArgumentParser<Arguments>{}
+ .Bind("INPUT"_s, &Arguments::Input)
+ .Bind("VERBOSE"_s, &Arguments::Verbose)
+ .Bind("LIST_ONLY"_s, &Arguments::ListOnly)
+ .Bind("DESTINATION"_s, &Arguments::Destination)
+ .Bind("PATTERNS"_s, &Arguments::Patterns);
+
+ std::vector<std::string> unrecognizedArguments;
+ std::vector<std::string> keywordsMissingValues;
+ auto parsedArgs =
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
+ &keywordsMissingValues);
+ auto argIt = unrecognizedArguments.begin();
+ if (argIt != unrecognizedArguments.end()) {
+ status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\""));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ const std::vector<std::string> LIST_ARGS = { "INPUT", "DESTINATION",
+ "PATTERNS" };
+ auto kwbegin = keywordsMissingValues.cbegin();
+ auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
+ if (kwend != kwbegin) {
+ status.SetError(cmStrCat("Keywords missing values:\n ",
+ cmJoin(cmMakeRange(kwbegin, kwend), "\n ")));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ std::string inFile = parsedArgs.Input;
+
+ if (parsedArgs.ListOnly) {
+ if (!cmSystemTools::ListTar(inFile, parsedArgs.Patterns,
+ parsedArgs.Verbose)) {
+ status.SetError(cmStrCat("failed to list: ", inFile));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ } else {
+ std::string destDir = status.GetMakefile().GetCurrentBinaryDirectory();
+ if (!parsedArgs.Destination.empty()) {
+ if (cmSystemTools::FileIsFullPath(parsedArgs.Destination)) {
+ destDir = parsedArgs.Destination;
+ } else {
+ destDir = cmStrCat(destDir, "/", parsedArgs.Destination);
+ }
+
+ if (!cmSystemTools::MakeDirectory(destDir)) {
+ status.SetError(cmStrCat("failed to create directory: ", destDir));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!cmSystemTools::FileIsFullPath(inFile)) {
+ inFile =
+ cmStrCat(cmSystemTools::GetCurrentWorkingDirectory(), "/", inFile);
+ }
+ }
+
+ cmWorkingDirectory workdir(destDir);
+ if (workdir.Failed()) {
+ status.SetError(
+ cmStrCat("failed to change working directory to: ", destDir));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!cmSystemTools::ExtractTar(inFile, parsedArgs.Patterns,
+ parsedArgs.Verbose)) {
+ status.SetError(cmStrCat("failed to extract: ", inFile));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+
+ return true;
+}
+
} // namespace
bool cmFileCommand(std::vector<std::string> const& args,
@@ -2836,6 +3179,9 @@ bool cmFileCommand(std::vector<std::string> const& args,
{ "READ_SYMLINK"_s, HandleReadSymlinkCommand },
{ "CREATE_LINK"_s, HandleCreateLinkCommand },
{ "GET_RUNTIME_DEPENDENCIES"_s, HandleGetRuntimeDependenciesCommand },
+ { "CONFIGURE"_s, HandleConfigureCommand },
+ { "ARCHIVE_CREATE"_s, HandleArchiveCreateCommand },
+ { "ARCHIVE_EXTRACT"_s, HandleArchiveExtractCommand },
};
return subcommand(args[0], args, status);