diff options
Diffstat (limited to 'Source/cmFileCommand.cxx')
| -rw-r--r-- | Source/cmFileCommand.cxx | 382 |
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); |
