diff --git a/Help/release/dev/cpack.hash_computing.rst b/Help/release/dev/cpack.hash_computing.rst new file mode 100644 index 000000000..9780bb286 --- /dev/null +++ b/Help/release/dev/cpack.hash_computing.rst @@ -0,0 +1,5 @@ +cpack.hash_computing +-------------------- + +* CPack gained a new :variable:`CPACK_PACKAGE_CHECKSUM` variable to + enable generation of a checksum file for each package file. diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake index 675b38ba6..70ae7f72a 100644 --- a/Modules/CPack.cmake +++ b/Modules/CPack.cmake @@ -116,6 +116,15 @@ # A branding image that will be displayed inside the installer (used by GUI # installers). # +# .. variable:: CPACK_PACKAGE_CHECKSUM +# +# An algorithm that will be used to generate additional file with checksum +# of the package. Output file name will be:: +# +# ${CPACK_PACKAGE_FILE_NAME}.${CPACK_PACKAGE_CHECKSUM} +# +# Current supported alogorithms: MD5|SHA1|SHA224|SHA256|SHA384|SHA512. +# # .. variable:: CPACK_PROJECT_CONFIG_FILE # # CPack-time project CPack configuration file. This file included at cpack diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index d6b58f2c3..e6aba899e 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -14,6 +14,7 @@ #include "cmCPackComponentGroup.h" #include "cmCPackLog.h" +#include "cmCryptoHash.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" @@ -163,6 +164,14 @@ int cmCPackGenerator::PrepareNames() << std::endl); return 0; } + const char* algoSignature = this->GetOption("CPACK_PACKAGE_CHECKSUM"); + if (algoSignature) { + if (cmCryptoHash::New(algoSignature).get() == CM_NULLPTR) { + cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot recognize algorithm: " + << algoSignature << std::endl); + return 0; + } + } this->SetOptionIfNotSet("CPACK_REMOVE_TOPLEVEL_DIRECTORY", "1"); @@ -980,6 +989,10 @@ int cmCPackGenerator::DoPackage() return 0; } + /* Prepare checksum algorithm*/ + const char* algo = this->GetOption("CPACK_PACKAGE_CHECKSUM"); + CM_AUTO_PTR crypto = cmCryptoHash::New(algo ? algo : ""); + /* * Copy the generated packages to final destination * - there may be several of them @@ -992,8 +1005,9 @@ int cmCPackGenerator::DoPackage() /* now copy package one by one */ for (it = packageFileNames.begin(); it != packageFileNames.end(); ++it) { std::string tmpPF(this->GetOption("CPACK_OUTPUT_FILE_PREFIX")); + std::string filename(cmSystemTools::GetFilenameName(*it)); tempPackageFileName = it->c_str(); - tmpPF += "/" + cmSystemTools::GetFilenameName(*it); + tmpPF += "/" + filename; const char* packageFileName = tmpPF.c_str(); cmCPackLogger(cmCPackLog::LOG_DEBUG, "Copy final package(s): " << (tempPackageFileName ? tempPackageFileName : "(NULL)") @@ -1009,6 +1023,23 @@ int cmCPackGenerator::DoPackage() } cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- package: " << packageFileName << " generated." << std::endl); + + /* Generate checksum file */ + if (crypto.get() != CM_NULLPTR) { + std::string hashFile(this->GetOption("CPACK_OUTPUT_FILE_PREFIX")); + hashFile += + "/" + filename.substr(0, filename.rfind(this->GetOutputExtension())); + hashFile += "." + cmSystemTools::LowerCase(algo); + cmsys::ofstream outF(hashFile.c_str()); + if (!outF) { + cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot create checksum file: " + << hashFile << std::endl); + return 0; + } + outF << crypto->HashFile(packageFileName) << " " << filename << "\n"; + cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- checksum file: " + << hashFile << " generated." << std::endl); + } } return 1; diff --git a/Tests/RunCMake/CPack/PACKAGE_CHECKSUM.cmake b/Tests/RunCMake/CPack/PACKAGE_CHECKSUM.cmake new file mode 100644 index 000000000..5ca288ca4 --- /dev/null +++ b/Tests/RunCMake/CPack/PACKAGE_CHECKSUM.cmake @@ -0,0 +1,4 @@ +install(FILES CMakeLists.txt DESTINATION foo) + +set(CPACK_PACKAGE_NAME "package_checksum") +set(CPACK_PACKAGE_CHECKSUM ${RunCMake_SUBTEST_SUFFIX}) diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake index a3029cfd8..abad58b32 100644 --- a/Tests/RunCMake/CPack/RunCMakeTest.cmake +++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake @@ -18,3 +18,4 @@ run_cpack_test(DEB_GENERATE_SHLIBS "DEB" true) run_cpack_test(DEB_GENERATE_SHLIBS_LDCONFIG "DEB" true) run_cpack_test(DEBUGINFO "RPM" true) run_cpack_test(LONG_FILENAMES "DEB" false) +run_cpack_test_subtests(PACKAGE_CHECKSUM "invalid;MD5;SHA1;SHA224;SHA256;SHA384;SHA512" "TGZ" false) diff --git a/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-ExpectedFiles.cmake b/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-ExpectedFiles.cmake new file mode 100644 index 000000000..205dcd8d8 --- /dev/null +++ b/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-ExpectedFiles.cmake @@ -0,0 +1,9 @@ +set(whitespaces_ "[\t\n\r ]*") + +set(EXPECTED_FILES_COUNT "0") + +if (NOT ${RunCMake_SUBTEST_SUFFIX} MATCHES "invalid") + set(EXPECTED_FILES_COUNT "1") + set(EXPECTED_FILE_1 "package_checksum*.tar.gz") + set(EXPECTED_FILE_CONTENT_1 "^[^\n]*package_checksum*-[^\n]*/foo/\n[^\n]*package_checksum-[^\n]*/foo/CMakeLists.txt$") +endif() diff --git a/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-VerifyResult.cmake b/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-VerifyResult.cmake new file mode 100644 index 000000000..e9e65d6dc --- /dev/null +++ b/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-VerifyResult.cmake @@ -0,0 +1,14 @@ +if(NOT ${RunCMake_SUBTEST_SUFFIX} MATCHES "invalid") + string(TOLOWER ${RunCMake_SUBTEST_SUFFIX} EXTENSION) + file(GLOB PACKAGE RELATIVE ${bin_dir} "*.tar.gz") + file(GLOB CSUMFILE RELATIVE ${bin_dir} "*.${EXTENSION}") + file(STRINGS ${CSUMFILE} CHSUM_VALUE) + file(${RunCMake_SUBTEST_SUFFIX} ${PACKAGE} expected_value ) + set(expected_value "${expected_value} ${PACKAGE}") + + if(NOT expected_value STREQUAL CHSUM_VALUE) + message(FATAL_ERROR "Generated checksum is not valid! Expected [${expected_value}] Got [${CHSUM_VALUE}]") + endif() +else() + message(${error}) +endif() diff --git a/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-invalid-stderr.txt b/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-invalid-stderr.txt new file mode 100644 index 000000000..abf6d8c88 --- /dev/null +++ b/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-invalid-stderr.txt @@ -0,0 +1,2 @@ +^CPack Error: Cannot recognize algorithm: invalid +CPack Error: Error when generating package: package_checksum$