file: Add ARCHIVE_{CREATE|EXTRACT} subcommands

Fixes: #20443
This commit is contained in:
Cristian Adam
2020-03-13 18:09:14 +01:00
parent 3766633b8a
commit c7e1198a23
23 changed files with 507 additions and 0 deletions

View File

@@ -8,6 +8,7 @@
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iterator>
#include <map>
#include <set>
#include <sstream>
@@ -49,6 +50,7 @@
#include "cmSubcommandTable.h"
#include "cmSystemTools.h"
#include "cmTimestamp.h"
#include "cmWorkingDirectory.h"
#include "cmake.h"
#if !defined(CMAKE_BOOTSTRAP)
@@ -2893,6 +2895,210 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
return true;
}
bool HandleArchiveCreateCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
struct Arguments
{
std::string Output;
std::string Format;
std::string Type;
std::string MTime;
bool Verbose = false;
std::vector<std::string> Files;
std::vector<std::string> Directories;
};
static auto const parser = cmArgumentParser<Arguments>{}
.Bind("OUTPUT"_s, &Arguments::Output)
.Bind("FORMAT"_s, &Arguments::Format)
.Bind("TYPE"_s, &Arguments::Type)
.Bind("MTIME"_s, &Arguments::MTime)
.Bind("VERBOSE"_s, &Arguments::Verbose)
.Bind("FILES"_s, &Arguments::Files)
.Bind("DIRECTORY"_s, &Arguments::Directories);
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", "TYPE", "MTIME", "FILES", "DIRECTORY",
};
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() &&
!cmContains(knownFormats, parsedArgs.Format)) {
status.SetError(
cmStrCat("archive format ", parsedArgs.Format, " not supported"));
cmSystemTools::SetFatalErrorOccured();
return false;
}
const char* zipFileFormats[] = { "7zip", "zip" };
if (!parsedArgs.Type.empty() &&
cmContains(zipFileFormats, parsedArgs.Format)) {
status.SetError(cmStrCat("archive format ", parsedArgs.Format,
" does not support TYPE 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 } };
std::string const& outFile = parsedArgs.Output;
std::vector<std::string> files = parsedArgs.Files;
std::copy(parsedArgs.Directories.begin(), parsedArgs.Directories.end(),
std::back_inserter(files));
cmSystemTools::cmTarCompression compress = cmSystemTools::TarCompressNone;
auto typeIt = compressionTypeMap.find(parsedArgs.Type);
if (typeIt != compressionTypeMap.end()) {
compress = typeIt->second;
} else if (!parsedArgs.Type.empty()) {
status.SetError(
cmStrCat("compression type ", parsedArgs.Type, " is not supported"));
cmSystemTools::SetFatalErrorOccured();
return false;
}
if (files.empty()) {
status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING,
"No files or directories specified");
}
if (!cmSystemTools::CreateTar(outFile, files, compress, parsedArgs.Verbose,
parsedArgs.MTime, parsedArgs.Format)) {
status.SetError(cmStrCat("failed to compress: ", outFile));
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> Files;
std::vector<std::string> Directories;
};
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("FILES"_s, &Arguments::Files)
.Bind("DIRECTORY"_s, &Arguments::Directories);
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",
"FILES",
"DIRECTORY",
};
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;
std::vector<std::string> files = parsedArgs.Files;
std::copy(parsedArgs.Directories.begin(), parsedArgs.Directories.end(),
std::back_inserter(files));
if (parsedArgs.ListOnly) {
if (!cmSystemTools::ListTar(inFile, files, parsedArgs.Verbose)) {
status.SetError(cmStrCat("failed to list: ", inFile));
cmSystemTools::SetFatalErrorOccured();
return false;
}
} else {
std::string destDir = cmSystemTools::GetCurrentWorkingDirectory();
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, files, parsedArgs.Verbose)) {
status.SetError(cmStrCat("failed to extract: ", inFile));
cmSystemTools::SetFatalErrorOccured();
return false;
}
}
return true;
}
} // namespace
bool cmFileCommand(std::vector<std::string> const& args,
@@ -2947,6 +3153,8 @@ bool cmFileCommand(std::vector<std::string> const& args,
{ "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);