mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-02 11:49:55 -06:00
CPack/Deb: Support SOURCE_DATE_EPOCH when packaging files
This commit is contained in:
@@ -527,3 +527,11 @@ alternate data stream (ADT) is used.
|
||||
|
||||
When a filesystem without ADT support is used only owner read/write
|
||||
permissions can be preserved.
|
||||
|
||||
Reproducible packages
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The environment variable ``SOURCE_DATE_EPOCH`` may be set to a UNIX
|
||||
timestamp, defined as the number of seconds, excluding leap seconds,
|
||||
since 01 Jan 1970 00:00:00 UTC. If set, the CPack Deb generator will
|
||||
use its value for timestamps in the package.
|
||||
|
||||
6
Help/release/dev/cpack-deb-source-date-epoch.rst
Normal file
6
Help/release/dev/cpack-deb-source-date-epoch.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
cpack-deb-source-date-epoch
|
||||
---------------------------
|
||||
|
||||
* The :cpack_gen:`CPack Deb Generator` learned to honor the ``SOURCE_DATE_EPOCH``
|
||||
environment variable when packaging files. This is useful for generating
|
||||
reproducible packages.
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "cmsys/Encoding.hxx"
|
||||
#include "cmsys/FStream.hxx"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
@@ -94,13 +95,25 @@ cmArchiveWrite::cmArchiveWrite(std::ostream& os, Compress c,
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case CompressGZip:
|
||||
case CompressGZip: {
|
||||
if (archive_write_add_filter_gzip(this->Archive) != ARCHIVE_OK) {
|
||||
this->Error = "archive_write_add_filter_gzip: ";
|
||||
this->Error += cm_archive_error_string(this->Archive);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
std::string source_date_epoch;
|
||||
cmSystemTools::GetEnv("SOURCE_DATE_EPOCH", source_date_epoch);
|
||||
if (!source_date_epoch.empty()) {
|
||||
// We're not able to specify an arbitrary timestamp for gzip.
|
||||
// The next best thing is to omit the timestamp entirely.
|
||||
if (archive_write_set_filter_option(this->Archive, "gzip", "timestamp",
|
||||
nullptr) != ARCHIVE_OK) {
|
||||
this->Error = "archive_write_set_filter_option: ";
|
||||
this->Error += cm_archive_error_string(this->Archive);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case CompressBZip2:
|
||||
if (archive_write_add_filter_bzip2(this->Archive) != ARCHIVE_OK) {
|
||||
this->Error = "archive_write_add_filter_bzip2: ";
|
||||
@@ -243,6 +256,17 @@ bool cmArchiveWrite::AddFile(const char* file, size_t skip, const char* prefix)
|
||||
return false;
|
||||
}
|
||||
archive_entry_set_mtime(e, t, 0);
|
||||
} else {
|
||||
std::string source_date_epoch;
|
||||
cmSystemTools::GetEnv("SOURCE_DATE_EPOCH", source_date_epoch);
|
||||
if (!source_date_epoch.empty()) {
|
||||
std::istringstream iss(source_date_epoch);
|
||||
time_t epochTime;
|
||||
iss >> epochTime;
|
||||
if (iss.eof() && !iss.fail()) {
|
||||
archive_entry_set_mtime(e, epochTime, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// manages the uid/guid of the entry (if any)
|
||||
|
||||
@@ -78,8 +78,12 @@ function(run_cpack_test_common_ TEST_NAME types build SUBTEST_SUFFIX source PACK
|
||||
endif()
|
||||
|
||||
# execute cpack
|
||||
set(SETENV)
|
||||
if(ENVIRONMENT)
|
||||
set(SETENV ${CMAKE_COMMAND} -E env "${ENVIRONMENT}")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${cpack_command_}
|
||||
COMMAND ${SETENV} ${cpack_command_}
|
||||
WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}"
|
||||
RESULT_VARIABLE "result_"
|
||||
OUTPUT_FILE "${RunCMake_TEST_BINARY_DIR}/test_output.txt"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
set(ALL_FILES_GLOB "*.deb")
|
||||
|
||||
function(getPackageContent FILE RESULT_VAR)
|
||||
execute_process(COMMAND ${DPKG_EXECUTABLE} -c "${FILE}"
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E env TZ=Etc/UTC ${DPKG_EXECUTABLE} -c "${FILE}"
|
||||
OUTPUT_VARIABLE package_content_
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
@@ -28,6 +28,9 @@ run_cpack_test(EXTRA_SLASH_IN_PATH "RPM" true "COMPONENT")
|
||||
run_cpack_source_test(SOURCE_PACKAGE "RPM")
|
||||
run_cpack_test(SUGGESTS "RPM" false "MONOLITHIC")
|
||||
run_cpack_test(SYMLINKS "RPM;TGZ" false "MONOLITHIC;COMPONENT")
|
||||
set(ENVIRONMENT "SOURCE_DATE_EPOCH=123456789")
|
||||
run_cpack_test(TIMESTAMPS "DEB;TGZ" false "COMPONENT")
|
||||
unset(ENVIRONMENT)
|
||||
run_cpack_test(USER_FILELIST "RPM" false "MONOLITHIC")
|
||||
run_cpack_test(MD5SUMS "DEB" false "MONOLITHIC;COMPONENT")
|
||||
run_cpack_test(CPACK_INSTALL_SCRIPT "ZIP" false "MONOLITHIC")
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
set(EXPECTED_FILES_COUNT "1")
|
||||
set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
|
||||
58
Tests/RunCMake/CPack/tests/TIMESTAMPS/VerifyResult.cmake
Normal file
58
Tests/RunCMake/CPack/tests/TIMESTAMPS/VerifyResult.cmake
Normal file
@@ -0,0 +1,58 @@
|
||||
macro(getFileMetadata_ FILE RESULT_VAR)
|
||||
if(GENERATOR_TYPE STREQUAL "TGZ")
|
||||
# getPackageContent defined for archives omit the metadata (non-verbose)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E env TZ=Etc/UTC ${CMAKE_COMMAND} -E tar -xtvf ${FILE}
|
||||
OUTPUT_VARIABLE ${RESULT_VAR}
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
else()
|
||||
getPackageContent("${FILE}" ${RESULT_VAR})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
function(checkContentTimestamp FILE REGEX)
|
||||
getFileMetadata_("${FILE}" METADATA_)
|
||||
|
||||
if(NOT METADATA_ MATCHES "${REGEX}")
|
||||
string(REPLACE "\n" "\n " metadata_indented "${METADATA_}")
|
||||
message(FATAL_ERROR
|
||||
"Wrong timestamps in file:\n"
|
||||
" ${FILE}\n"
|
||||
"Expected timestamps to match:\n"
|
||||
" ${REGEX}\n"
|
||||
"Actual timestamps:\n"
|
||||
" ${metadata_indented}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(checkTimestamp FILE_NAME)
|
||||
file(READ ${FILE_NAME} ACTUAL_TIMESTAMP OFFSET 4 LIMIT 4 HEX)
|
||||
|
||||
if(NOT ACTUAL_TIMESTAMP STREQUAL "00000000")
|
||||
message(FATAL_ERROR "${FILE_NAME} contains a timestamp [0x${ACTUAL_TIMESTAMP}]")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Expected timestamp is UNIX time 123456789
|
||||
if(GENERATOR_TYPE STREQUAL "TGZ")
|
||||
set(EXPECTED_TIMESTAMP "29 Nov +1973")
|
||||
set(EXPECTED_FILES foo/ foo/CMakeLists.txt)
|
||||
else()
|
||||
set(EXPECTED_TIMESTAMP "1973-11-29 21:33")
|
||||
set(EXPECTED_FILES ./usr/ ./usr/foo/ ./usr/foo/CMakeLists.txt)
|
||||
endif()
|
||||
|
||||
set(EXPECTED_METADATA)
|
||||
foreach(FILE ${EXPECTED_FILES})
|
||||
list(APPEND EXPECTED_METADATA ".* ${EXPECTED_TIMESTAMP} ${FILE}")
|
||||
endforeach()
|
||||
list(JOIN EXPECTED_METADATA ".*" EXPECTED_REGEX)
|
||||
checkContentTimestamp("${FOUND_FILE_1}" "${EXPECTED_REGEX}")
|
||||
|
||||
if(GENERATOR_TYPE STREQUAL "TGZ")
|
||||
checkTimestamp("${FOUND_FILE_1}")
|
||||
else()
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${FOUND_FILE_1}")
|
||||
checkTimestamp("data.tar.gz")
|
||||
checkTimestamp("control.tar.gz")
|
||||
endif()
|
||||
3
Tests/RunCMake/CPack/tests/TIMESTAMPS/test.cmake
Normal file
3
Tests/RunCMake/CPack/tests/TIMESTAMPS/test.cmake
Normal file
@@ -0,0 +1,3 @@
|
||||
install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
|
||||
|
||||
set(CPACK_COMPONENTS_ALL test)
|
||||
Reference in New Issue
Block a user