mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-04 21:00:17 -06:00
cmake: tar: Allow selective extracting and listing of archives
This commit is contained in:
committed by
Brad King
parent
f03a80aefd
commit
c8e217e0a7
@@ -528,16 +528,22 @@ Available commands are:
|
||||
``sleep <number>...``
|
||||
Sleep for given number of seconds.
|
||||
|
||||
``tar [cxt][vf][zjJ] file.tar [<options>] [--] [<file>...]``
|
||||
``tar [cxt][vf][zjJ] file.tar [<options>] [--] [<pathname>...]``
|
||||
Create or extract a tar or zip archive. Options are:
|
||||
|
||||
``c``
|
||||
Create a new archive containing the specified files.
|
||||
If used, the <file> argument is mandatory.
|
||||
If used, the ``<pathname>...`` argument is mandatory.
|
||||
``x``
|
||||
Extract to disk from the archive.
|
||||
The ``<pathname>...`` argument could be used to extract only selected files
|
||||
or directories.
|
||||
When extracting selected files or directories, you must provide their exact
|
||||
names including the path, as printed by list (``-t``).
|
||||
``t``
|
||||
List archive contents to stdout.
|
||||
List archive contents.
|
||||
The ``<pathname>...`` argument could be used to list only selected files
|
||||
or directories.
|
||||
``v``
|
||||
Produce verbose output.
|
||||
``z``
|
||||
|
||||
8
Help/release/dev/cmake-e-tar-extract-specific-files.rst
Normal file
8
Help/release/dev/cmake-e-tar-extract-specific-files.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
cmake-e-tar-extract-specific-files
|
||||
----------------------------------
|
||||
|
||||
* The :manual:`cmake(1)` ``-E tar`` tool allow for extract (``-x``) or list
|
||||
(``-t``) only specific files or directories. To select pathnames append
|
||||
a space-separated list of file names or directories.
|
||||
When extracting selected files or directories, you must provide their exact
|
||||
pathname, as printed by list (``-t``)
|
||||
@@ -1757,7 +1757,9 @@ bool copy_data(struct archive* ar, struct archive* aw)
|
||||
# endif
|
||||
}
|
||||
|
||||
bool extract_tar(const char* outFileName, bool verbose, bool extract)
|
||||
bool extract_tar(const char* outFileName,
|
||||
const std::vector<std::string>& files, bool verbose,
|
||||
bool extract)
|
||||
{
|
||||
cmLocaleRAII localeRAII;
|
||||
static_cast<void>(localeRAII);
|
||||
@@ -1766,6 +1768,21 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
|
||||
archive_read_support_filter_all(a);
|
||||
archive_read_support_format_all(a);
|
||||
struct archive_entry* entry;
|
||||
|
||||
struct archive* matching = archive_match_new();
|
||||
if (matching == nullptr) {
|
||||
cmSystemTools::Error("Out of memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& filename : files) {
|
||||
if (archive_match_include_pattern(matching, filename.c_str()) !=
|
||||
ARCHIVE_OK) {
|
||||
cmSystemTools::Error("Failed to add to inclusion list: " + filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int r = cm_archive_read_open_file(a, outFileName, 10240);
|
||||
if (r) {
|
||||
ArchiveError("Problem with archive_read_open_file(): ", a);
|
||||
@@ -1782,6 +1799,11 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
|
||||
ArchiveError("Problem with archive_read_next_header(): ", a);
|
||||
break;
|
||||
}
|
||||
|
||||
if (archive_match_excluded(matching, entry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
if (extract) {
|
||||
cmSystemTools::Stdout("x ");
|
||||
@@ -1827,6 +1849,27 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool error_occured = false;
|
||||
if (matching != nullptr) {
|
||||
const char* p;
|
||||
int ar;
|
||||
|
||||
while ((ar = archive_match_path_unmatched_inclusions_next(matching, &p)) ==
|
||||
ARCHIVE_OK) {
|
||||
cmSystemTools::Error("tar: " + std::string(p) +
|
||||
": Not found in archive");
|
||||
error_occured = true;
|
||||
}
|
||||
if (error_occured) {
|
||||
return false;
|
||||
}
|
||||
if (ar == ARCHIVE_FATAL) {
|
||||
cmSystemTools::Error("tar: Out of memory");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
archive_match_free(matching);
|
||||
archive_write_free(ext);
|
||||
archive_read_close(a);
|
||||
archive_read_free(a);
|
||||
@@ -1835,23 +1878,29 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
|
||||
}
|
||||
#endif
|
||||
|
||||
bool cmSystemTools::ExtractTar(const char* outFileName, bool verbose)
|
||||
bool cmSystemTools::ExtractTar(const char* outFileName,
|
||||
const std::vector<std::string>& files,
|
||||
bool verbose)
|
||||
{
|
||||
#if defined(CMAKE_BUILD_WITH_CMAKE)
|
||||
return extract_tar(outFileName, verbose, true);
|
||||
return extract_tar(outFileName, files, verbose, true);
|
||||
#else
|
||||
(void)outFileName;
|
||||
(void)files;
|
||||
(void)verbose;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool cmSystemTools::ListTar(const char* outFileName, bool verbose)
|
||||
bool cmSystemTools::ListTar(const char* outFileName,
|
||||
const std::vector<std::string>& files,
|
||||
bool verbose)
|
||||
{
|
||||
#if defined(CMAKE_BUILD_WITH_CMAKE)
|
||||
return extract_tar(outFileName, verbose, false);
|
||||
return extract_tar(outFileName, files, verbose, false);
|
||||
#else
|
||||
(void)outFileName;
|
||||
(void)files;
|
||||
(void)verbose;
|
||||
return false;
|
||||
#endif
|
||||
|
||||
@@ -450,13 +450,15 @@ public:
|
||||
TarCompressNone
|
||||
};
|
||||
|
||||
static bool ListTar(const char* outFileName, bool verbose);
|
||||
static bool ListTar(const char* outFileName,
|
||||
const std::vector<std::string>& files, bool verbose);
|
||||
static bool CreateTar(const char* outFileName,
|
||||
const std::vector<std::string>& files,
|
||||
cmTarCompression compressType, bool verbose,
|
||||
std::string const& mtime = std::string(),
|
||||
std::string const& format = std::string());
|
||||
static bool ExtractTar(const char* inFileName, bool verbose);
|
||||
static bool ExtractTar(const char* inFileName,
|
||||
const std::vector<std::string>& files, bool verbose);
|
||||
// This should be called first thing in main
|
||||
// it will keep child processes from inheriting the
|
||||
// stdin and stdout of this process. This is important
|
||||
|
||||
@@ -1127,7 +1127,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args)
|
||||
return 1;
|
||||
}
|
||||
if (action == cmSystemTools::TarActionList) {
|
||||
if (!cmSystemTools::ListTar(outFile.c_str(), verbose)) {
|
||||
if (!cmSystemTools::ListTar(outFile.c_str(), files, verbose)) {
|
||||
cmSystemTools::Error("Problem listing tar: " + outFile);
|
||||
return 1;
|
||||
}
|
||||
@@ -1142,7 +1142,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args)
|
||||
return 1;
|
||||
}
|
||||
} else if (action == cmSystemTools::TarActionExtract) {
|
||||
if (!cmSystemTools::ExtractTar(outFile.c_str(), verbose)) {
|
||||
if (!cmSystemTools::ExtractTar(outFile.c_str(), files, verbose)) {
|
||||
cmSystemTools::Error("Problem extracting tar: " + outFile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -30,3 +30,6 @@ run_cmake(pax-xz)
|
||||
run_cmake(paxr)
|
||||
run_cmake(paxr-bz2)
|
||||
run_cmake(zip)
|
||||
|
||||
# Extracting only selected files or directories
|
||||
run_cmake(zip-filtered)
|
||||
|
||||
@@ -47,7 +47,11 @@ file(REMOVE_RECURSE ${FULL_DECOMPRESS_DIR})
|
||||
file(MAKE_DIRECTORY ${FULL_DECOMPRESS_DIR})
|
||||
|
||||
run_tar(${CMAKE_CURRENT_BINARY_DIR} ${COMPRESSION_FLAGS} ${FULL_OUTPUT_NAME} ${COMPRESSION_OPTIONS} ${COMPRESS_DIR})
|
||||
run_tar(${FULL_DECOMPRESS_DIR} ${DECOMPRESSION_FLAGS} ${FULL_OUTPUT_NAME} ${DECOMPRESSION_OPTIONS})
|
||||
run_tar(${FULL_DECOMPRESS_DIR} ${DECOMPRESSION_FLAGS} ${FULL_OUTPUT_NAME} ${DECOMPRESSION_OPTIONS} -- ${DECOMPRESSION_PATHNAMES})
|
||||
|
||||
if(CUSTOM_CHECK_FILES)
|
||||
set(CHECK_FILES ${CUSTOM_CHECK_FILES})
|
||||
endif()
|
||||
|
||||
foreach(file ${CHECK_FILES})
|
||||
set(input ${FULL_COMPRESS_DIR}/${file})
|
||||
@@ -69,6 +73,14 @@ foreach(file ${CHECK_FILES})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(file ${NOT_EXISTING_FILES_CHECK})
|
||||
set(output ${FULL_DECOMPRESS_DIR}/${COMPRESS_DIR}/${file})
|
||||
|
||||
if(EXISTS ${output})
|
||||
message(SEND_ERROR "File ${output} exists but it shouldn't")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
function(check_magic EXPECTED)
|
||||
file(READ ${FULL_OUTPUT_NAME} ACTUAL
|
||||
${ARGN}
|
||||
|
||||
28
Tests/RunCMake/CommandLineTar/zip-filtered.cmake
Normal file
28
Tests/RunCMake/CommandLineTar/zip-filtered.cmake
Normal file
@@ -0,0 +1,28 @@
|
||||
set(OUTPUT_NAME "test.zip")
|
||||
|
||||
set(COMPRESSION_FLAGS cvf)
|
||||
set(COMPRESSION_OPTIONS --format=zip)
|
||||
|
||||
set(DECOMPRESSION_FLAGS xvf)
|
||||
set(LIST_ARCHIVE TRUE)
|
||||
set(DECOMPRESSION_PATHNAMES
|
||||
compress_dir/f1.txt # Decompress only file
|
||||
compress_dir/d1 # and whole directory
|
||||
)
|
||||
|
||||
set(CUSTOM_CHECK_FILES
|
||||
"f1.txt"
|
||||
"d1/f1.txt"
|
||||
)
|
||||
|
||||
# This files shouldn't exists
|
||||
set(NOT_EXISTING_FILES_CHECK
|
||||
"d 2/f1.txt"
|
||||
"d + 3/f1.txt"
|
||||
"d_4/f1.txt"
|
||||
"d-4/f1.txt"
|
||||
)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake)
|
||||
|
||||
check_magic("504b0304" LIMIT 4 HEX)
|
||||
Reference in New Issue
Block a user