summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Fuller <afuller@teradici.com>2018-07-20 01:14:40 (GMT)
committerAndrew Fuller <afuller@teradici.com>2018-07-25 20:39:07 (GMT)
commit548ac51d8ea319c65abefa0a771636893c45014c (patch)
tree90e75a26ef74a701937f24bc03495b684d765fb2
parent8dc86970c86ec53513a17f4cdb28f2a0be3ee505 (diff)
downloadCMake-548ac51d8ea319c65abefa0a771636893c45014c.zip
CMake-548ac51d8ea319c65abefa0a771636893c45014c.tar.gz
CMake-548ac51d8ea319c65abefa0a771636893c45014c.tar.bz2
CPack/Deb: Support SOURCE_DATE_EPOCH when packaging files
-rw-r--r--Help/cpack_gen/deb.rst8
-rw-r--r--Help/release/dev/cpack-deb-source-date-epoch.rst6
-rw-r--r--Source/cmArchiveWrite.cxx28
-rw-r--r--Tests/RunCMake/CPack/CPackTestHelpers.cmake6
-rw-r--r--Tests/RunCMake/CPack/DEB/Helpers.cmake2
-rw-r--r--Tests/RunCMake/CPack/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/CPack/tests/TIMESTAMPS/ExpectedFiles.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/TIMESTAMPS/VerifyResult.cmake58
-rw-r--r--Tests/RunCMake/CPack/tests/TIMESTAMPS/test.cmake3
9 files changed, 112 insertions, 4 deletions
diff --git a/Help/cpack_gen/deb.rst b/Help/cpack_gen/deb.rst
index c5923be..37d750d 100644
--- a/Help/cpack_gen/deb.rst
+++ b/Help/cpack_gen/deb.rst
@@ -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.
diff --git a/Help/release/dev/cpack-deb-source-date-epoch.rst b/Help/release/dev/cpack-deb-source-date-epoch.rst
new file mode 100644
index 0000000..b276569
--- /dev/null
+++ b/Help/release/dev/cpack-deb-source-date-epoch.rst
@@ -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.
diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx
index 1dd7734..6031781 100644
--- a/Source/cmArchiveWrite.cxx
+++ b/Source/cmArchiveWrite.cxx
@@ -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)
diff --git a/Tests/RunCMake/CPack/CPackTestHelpers.cmake b/Tests/RunCMake/CPack/CPackTestHelpers.cmake
index 8c9f4b4..d00ef3b 100644
--- a/Tests/RunCMake/CPack/CPackTestHelpers.cmake
+++ b/Tests/RunCMake/CPack/CPackTestHelpers.cmake
@@ -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"
diff --git a/Tests/RunCMake/CPack/DEB/Helpers.cmake b/Tests/RunCMake/CPack/DEB/Helpers.cmake
index f7c5c84..e01f81d 100644
--- a/Tests/RunCMake/CPack/DEB/Helpers.cmake
+++ b/Tests/RunCMake/CPack/DEB/Helpers.cmake
@@ -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)
diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake
index 33ffa14..b273c1e 100644
--- a/Tests/RunCMake/CPack/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake
@@ -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")
diff --git a/Tests/RunCMake/CPack/tests/TIMESTAMPS/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/TIMESTAMPS/ExpectedFiles.cmake
new file mode 100644
index 0000000..d1a3a5f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/TIMESTAMPS/ExpectedFiles.cmake
@@ -0,0 +1,2 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/TIMESTAMPS/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/TIMESTAMPS/VerifyResult.cmake
new file mode 100644
index 0000000..e7e2645
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/TIMESTAMPS/VerifyResult.cmake
@@ -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()
diff --git a/Tests/RunCMake/CPack/tests/TIMESTAMPS/test.cmake b/Tests/RunCMake/CPack/tests/TIMESTAMPS/test.cmake
new file mode 100644
index 0000000..a193852
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/TIMESTAMPS/test.cmake
@@ -0,0 +1,3 @@
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+
+set(CPACK_COMPONENTS_ALL test)