diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index 822a33171d..b03c7c185c 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -1497,6 +1497,17 @@ Available commands are: Specify modification time recorded in tarball entries. + .. option:: --cmake-tar-compression-level= + + .. versionadded:: 4.3 + + The ```` should be between ``0`` and ``9``, with the + default being ``0``. The compression algorithm must be selected when + the ``--cmake-tar-compression-level`` option is given. + + The ```` of the ``Zstd`` algorithm can be set + between ``0`` and ``19``. + .. option:: --cmake-tar-threads= .. versionadded:: 4.3 diff --git a/Help/release/dev/cli-tar-compression-level.rst b/Help/release/dev/cli-tar-compression-level.rst new file mode 100644 index 0000000000..41959c25a5 --- /dev/null +++ b/Help/release/dev/cli-tar-compression-level.rst @@ -0,0 +1,5 @@ +cli-tar-compression-level +------------------------- + +* The :manual:`cmake(1)` ``-E tar`` tool supports specifying compression level + via ``--cmake-tar-compression-level`` option diff --git a/Help/release/dev/cli-tar-multithread.rst b/Help/release/dev/cli-tar-multithread.rst index af47b8d260..e4e9342486 100644 --- a/Help/release/dev/cli-tar-multithread.rst +++ b/Help/release/dev/cli-tar-multithread.rst @@ -2,5 +2,6 @@ cli-tar-multithread ------------------- * The :manual:`cmake(1)` ``-E tar`` tool supports multithreading operations + via ``--cmake-tar-threads`` option * The :command:`file(ARCHIVE_CREATE)` command supports multithreading via the ``THREADS`` option diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 4b03e44009..9f992174d2 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -1584,6 +1584,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector const& args, std::string mtime; std::string format; int numThreads = 1; + int compressionLevel = 0; + bool compressionLevelFlagPassed = false; cmSystemTools::cmTarExtractTimestamps extractTimestamps = cmSystemTools::cmTarExtractTimestamps::Yes; cmSystemTools::cmTarCompression compress = @@ -1627,6 +1629,34 @@ int cmcmd::ExecuteCMakeCommand(std::vector const& args, } numThreads = static_cast(numThreadsLong); + } else if (cmHasLiteralPrefix(arg, + "--cmake-tar-compression-level=")) { + std::string const& compressionLevelStr = arg.substr(30); + long compressionLevelLong = 0; + if (!cmStrToLong(compressionLevelStr, &compressionLevelLong)) { + cmSystemTools::Error( + cmStrCat("Invalid --cmake-tar-compression-level value: '", + compressionLevelStr, "' - not a number")); + return 1; + } + if (compressionLevelLong > + std::numeric_limits::max()) { + cmSystemTools::Error( + cmStrCat("Invalid --cmake-tar-compression-level value: '", + compressionLevelStr, "' - too large")); + return 1; + } + if (compressionLevelLong < + std::numeric_limits::min()) { + cmSystemTools::Error( + cmStrCat("Invalid --cmake-tar-compression-level value: '", + compressionLevelStr, "' - too small")); + return 1; + } + + compressionLevel = + static_cast(compressionLevelLong); + compressionLevelFlagPassed = true; } else if (cmHasLiteralPrefix(arg, "--files-from=")) { std::string const& files_from = arg.substr(13); if (!cmTarFilesFrom(files_from, files)) { @@ -1697,6 +1727,30 @@ int cmcmd::ExecuteCMakeCommand(std::vector const& args, "at most one flag of z, j, or J may be used"); return 1; } + if (compressionLevelFlagPassed) { + if (nCompress == 0) { + cmSystemTools::Error("Can not use --cmake-tar-compression-level " + "without compression algorithm selection"); + return 1; + } + + constexpr int minCompressionLevel = 0; + int maxCompressionLevel = 9; + if (compress == cmSystemTools::TarCompressZstd) { + maxCompressionLevel = 19; + } + + if (compressionLevel < minCompressionLevel || + compressionLevel > maxCompressionLevel) { + cmSystemTools::Error( + cmStrCat("Compression level must be between ", + std::to_string(minCompressionLevel), " and ", + std::to_string(maxCompressionLevel), ". Got ", + std::to_string(compressionLevel))); + return 1; + } + } + if (action == cmSystemTools::TarActionList) { if (!cmSystemTools::ListTar(outFile, files, verbose)) { cmSystemTools::Error("Problem listing tar: " + outFile); @@ -1707,7 +1761,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector const& args, std::cerr << "tar: No files or directories specified\n"; } if (!cmSystemTools::CreateTar(outFile, files, {}, compress, verbose, - mtime, format, 0, numThreads)) { + mtime, format, compressionLevel, + numThreads)) { cmSystemTools::Error("Problem creating tar: " + outFile); return 1; } diff --git a/Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake b/Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake index ecfb78a57f..f051587482 100644 --- a/Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake @@ -43,6 +43,19 @@ run_cmake(threads-xz) run_cmake(threads-zstd) run_cmake(threads-zip) +# Check the --cmake-tar-compression-level option +external_command_test(bad-compression-level-no-compression tar cvf bad.tar --cmake-tar-compression-level=1 .) +external_command_test(bad-compression-level-not-a-number tar cvjf bad.tar --cmake-tar-compression-level=nan .) +external_command_test(bad-compression-level-bz2 tar cvjf bad.tar --cmake-tar-compression-level=10 .) +external_command_test(bad-compression-level-gz tar cvzf bad.tar --cmake-tar-compression-level=10 .) +external_command_test(bad-compression-level-xz tar cvJf bad.tar --cmake-tar-compression-level=10 .) +external_command_test(bad-compression-level-zstd tar cvf bad.tar --zstd --cmake-tar-compression-level=20 .) + +run_cmake(compression-level-bz2) +run_cmake(compression-level-gz) +run_cmake(compression-level-xz) +run_cmake(compression-level-zstd) + # Extracting only selected files or directories run_cmake(zip-filtered) diff --git a/Tests/RunCMake/CommandLineTar/bad-compression-level-bz2-result.txt b/Tests/RunCMake/CommandLineTar/bad-compression-level-bz2-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/bad-compression-level-bz2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLineTar/bad-compression-level-bz2-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-compression-level-bz2-stderr.txt new file mode 100644 index 0000000000..4850505f6b --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/bad-compression-level-bz2-stderr.txt @@ -0,0 +1 @@ +^CMake Error: Compression level must be between 0 and 9. Got 10$ diff --git a/Tests/RunCMake/CommandLineTar/bad-compression-level-gz-result.txt b/Tests/RunCMake/CommandLineTar/bad-compression-level-gz-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/bad-compression-level-gz-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLineTar/bad-compression-level-gz-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-compression-level-gz-stderr.txt new file mode 100644 index 0000000000..4850505f6b --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/bad-compression-level-gz-stderr.txt @@ -0,0 +1 @@ +^CMake Error: Compression level must be between 0 and 9. Got 10$ diff --git a/Tests/RunCMake/CommandLineTar/bad-compression-level-no-compression-result.txt b/Tests/RunCMake/CommandLineTar/bad-compression-level-no-compression-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/bad-compression-level-no-compression-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLineTar/bad-compression-level-no-compression-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-compression-level-no-compression-stderr.txt new file mode 100644 index 0000000000..d8ca602afc --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/bad-compression-level-no-compression-stderr.txt @@ -0,0 +1 @@ +^CMake Error: Can not use --cmake-tar-compression-level without compression algorithm selection$ diff --git a/Tests/RunCMake/CommandLineTar/bad-compression-level-not-a-number-result.txt b/Tests/RunCMake/CommandLineTar/bad-compression-level-not-a-number-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/bad-compression-level-not-a-number-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLineTar/bad-compression-level-not-a-number-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-compression-level-not-a-number-stderr.txt new file mode 100644 index 0000000000..b4c8a120d0 --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/bad-compression-level-not-a-number-stderr.txt @@ -0,0 +1 @@ +^CMake Error: Invalid --cmake-tar-compression-level value: 'nan' - not a number$ diff --git a/Tests/RunCMake/CommandLineTar/bad-compression-level-xz-result.txt b/Tests/RunCMake/CommandLineTar/bad-compression-level-xz-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/bad-compression-level-xz-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLineTar/bad-compression-level-xz-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-compression-level-xz-stderr.txt new file mode 100644 index 0000000000..4850505f6b --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/bad-compression-level-xz-stderr.txt @@ -0,0 +1 @@ +^CMake Error: Compression level must be between 0 and 9. Got 10$ diff --git a/Tests/RunCMake/CommandLineTar/bad-compression-level-zstd-result.txt b/Tests/RunCMake/CommandLineTar/bad-compression-level-zstd-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/bad-compression-level-zstd-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLineTar/bad-compression-level-zstd-stderr.txt b/Tests/RunCMake/CommandLineTar/bad-compression-level-zstd-stderr.txt new file mode 100644 index 0000000000..5cc4c16240 --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/bad-compression-level-zstd-stderr.txt @@ -0,0 +1 @@ +^CMake Error: Compression level must be between 0 and 19. Got 20$ diff --git a/Tests/RunCMake/CommandLineTar/compression-level-bz2.cmake b/Tests/RunCMake/CommandLineTar/compression-level-bz2.cmake new file mode 100644 index 0000000000..1080394410 --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/compression-level-bz2.cmake @@ -0,0 +1,10 @@ +set(OUTPUT_NAME "test.tar.bz2") + +set(COMPRESSION_FLAGS cvjf) +set(COMPRESSION_OPTIONS --cmake-tar-threads=9) + +set(DECOMPRESSION_FLAGS xvjf) + +include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake) + +check_magic("425a68" LIMIT 3 HEX) diff --git a/Tests/RunCMake/CommandLineTar/compression-level-gz.cmake b/Tests/RunCMake/CommandLineTar/compression-level-gz.cmake new file mode 100644 index 0000000000..e42e1b2f21 --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/compression-level-gz.cmake @@ -0,0 +1,10 @@ +set(OUTPUT_NAME "test.tar.gz") + +set(COMPRESSION_FLAGS -cvzf) +set(COMPRESSION_OPTIONS --cmake-tar-compression-level=9) + +set(DECOMPRESSION_FLAGS -xvzf) + +include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake) + +check_magic("1f8b" LIMIT 2 HEX) diff --git a/Tests/RunCMake/CommandLineTar/compression-level-xz.cmake b/Tests/RunCMake/CommandLineTar/compression-level-xz.cmake new file mode 100644 index 0000000000..231beeb55a --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/compression-level-xz.cmake @@ -0,0 +1,10 @@ +set(OUTPUT_NAME "test.tar.xz") + +set(COMPRESSION_FLAGS cvJf) +set(COMPRESSION_OPTIONS --cmake-tar-compression-level=9) + +set(DECOMPRESSION_FLAGS xvJf) + +include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake) + +check_magic("fd377a585a00" LIMIT 6 HEX) diff --git a/Tests/RunCMake/CommandLineTar/compression-level-zstd.cmake b/Tests/RunCMake/CommandLineTar/compression-level-zstd.cmake new file mode 100644 index 0000000000..bc32faaa71 --- /dev/null +++ b/Tests/RunCMake/CommandLineTar/compression-level-zstd.cmake @@ -0,0 +1,11 @@ +set(OUTPUT_NAME "test.tar.zstd") + +set(COMPRESSION_FLAGS cvf) +set(COMPRESSION_OPTIONS --zstd --cmake-tar-compression-level=19) + +set(DECOMPRESSION_FLAGS xvf) + +include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake) + +# libarchive 3.8.2 enables a checksum feature; older versions do not. +check_magic("^28b52ffd0[04][56]8$" LIMIT 6 HEX) diff --git a/Tests/RunCMake/File_Archive/RunCMakeTest.cmake b/Tests/RunCMake/File_Archive/RunCMakeTest.cmake index 91cac696c1..e6def15b49 100644 --- a/Tests/RunCMake/File_Archive/RunCMakeTest.cmake +++ b/Tests/RunCMake/File_Archive/RunCMakeTest.cmake @@ -14,7 +14,7 @@ run_cmake(zip) run_cmake(working-directory) -# Check the --cmake-tar-threads option +# Check the THREADS option run_cmake(argument-validation-threads) run_cmake(threads-bz2) run_cmake(threads-gz)