diff --git a/Help/release/dev/cmake-E-tar-mtime.rst b/Help/release/dev/cmake-E-tar-mtime.rst new file mode 100644 index 000000000..6496577e3 --- /dev/null +++ b/Help/release/dev/cmake-E-tar-mtime.rst @@ -0,0 +1,6 @@ +cmake-E-tar-mtime +----------------- + +* The :manual:`cmake(1)` ``-E tar`` command learned a new + ``--mtime=`` option to specify the modification time + recorded in tarball entries. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 96f470938..caabd43f2 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -335,6 +335,8 @@ set(SRCS cmake.cxx cmake.h + cm_get_date.h + cm_get_date.c cm_sha2.h cm_sha2.c cm_utf8.h diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index 16f67f49d..c24c68e4d 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx @@ -16,6 +16,7 @@ #include #include #include +#include "cm_get_date.h" //---------------------------------------------------------------------------- static std::string cm_archive_error_string(struct archive* a) @@ -277,6 +278,20 @@ bool cmArchiveWrite::AddFile(const char* file, this->Error += cm_archive_error_string(this->Disk); return false; } + if (!this->MTime.empty()) + { + time_t now; + time(&now); + time_t t = cm_get_date(now, this->MTime.c_str()); + if (t == -1) + { + this->Error = "unable to parse mtime '"; + this->Error += this->MTime; + this->Error += "'"; + return false; + } + archive_entry_set_mtime(e, t, 0); + } // Clear acl and xattr fields not useful for distribution. archive_entry_acl_clear(e); archive_entry_xattr_clear(e); diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h index a6dcc0e4e..17357b45d 100644 --- a/Source/cmArchiveWrite.h +++ b/Source/cmArchiveWrite.h @@ -74,6 +74,7 @@ public: // std::cout. void SetVerbose(bool v) { this->Verbose = v; } + void SetMTime(std::string const& t) { this->MTime = t; } private: bool Okay() const { return this->Error.empty(); } bool AddPath(const char* path, size_t skip, const char* prefix); @@ -90,6 +91,7 @@ private: struct archive* Disk; bool Verbose; std::string Error; + std::string MTime; }; #endif diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 7d938c569..e9735ed41 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1469,7 +1469,7 @@ bool cmSystemTools::IsPathToFramework(const char* path) bool cmSystemTools::CreateTar(const char* outFileName, const std::vector& files, cmTarCompression compressType, - bool verbose) + bool verbose, std::string const& mtime) { #if defined(CMAKE_BUILD_WITH_CMAKE) std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); @@ -1501,6 +1501,7 @@ bool cmSystemTools::CreateTar(const char* outFileName, } cmArchiveWrite a(fout, compress, cmArchiveWrite::TypeTAR); + a.SetMTime(mtime); a.SetVerbose(verbose); for(std::vector::const_iterator i = files.begin(); i != files.end(); ++i) diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 09ceea6e8..361f42e60 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -394,9 +394,9 @@ public: bool verbose); static bool CreateTar(const char* outFileName, const std::vector& files, - cmTarCompression compressType, bool verbose); - static bool ExtractTar(const char* inFileName, - bool verbose); + cmTarCompression compressType, bool verbose, + std::string const& mtime = std::string()); + static bool ExtractTar(const char* inFileName, 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 diff --git a/Source/cm_get_date.c b/Source/cm_get_date.c new file mode 100644 index 000000000..2e0d4bdd8 --- /dev/null +++ b/Source/cm_get_date.c @@ -0,0 +1,16 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2015 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cm_get_date.h" + +#define __archive_get_date cm_get_date + +#include "../Utilities/cmlibarchive/libarchive/archive_getdate.c" diff --git a/Source/cm_get_date.h b/Source/cm_get_date.h new file mode 100644 index 000000000..d5f6d3e0a --- /dev/null +++ b/Source/cm_get_date.h @@ -0,0 +1,28 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2015 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cm_get_date_h +#define cm_get_date_h + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Parse a date/time string. Treat relative times with respect to 'now'. */ +time_t cm_get_date(time_t now, const char *str); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index ecf46508f..7ca3eb3ac 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -729,9 +729,31 @@ int cmcmd::ExecuteCMakeCommand(std::vector& args) std::string flags = args[2]; std::string outFile = args[3]; std::vector files; + std::string mtime; + bool doing_options = true; for (std::string::size_type cc = 4; cc < args.size(); cc ++) { - files.push_back(args[cc]); + std::string const& arg = args[cc]; + if (doing_options && cmHasLiteralPrefix(arg, "--")) + { + if (arg == "--") + { + doing_options = false; + } + else if (cmHasLiteralPrefix(arg, "--mtime=")) + { + mtime = arg.substr(8); + } + else + { + cmSystemTools::Error("Unknown option to -E tar: ", arg.c_str()); + return 1; + } + } + else + { + files.push_back(arg); + } } cmSystemTools::cmTarCompression compress = cmSystemTools::TarCompressNone; @@ -774,7 +796,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector& args) else if ( flags.find_first_of('c') != flags.npos ) { if ( !cmSystemTools::CreateTar( - outFile.c_str(), files, compress, verbose) ) + outFile.c_str(), files, compress, verbose, mtime) ) { cmSystemTools::Error("Problem creating tar: ", outFile.c_str()); return 1; diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-mtime1-result.txt b/Tests/RunCMake/CommandLine/E_tar-bad-mtime1-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_tar-bad-mtime1-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-mtime1-stderr.txt b/Tests/RunCMake/CommandLine/E_tar-bad-mtime1-stderr.txt new file mode 100644 index 000000000..ca925f160 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_tar-bad-mtime1-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: unable to parse mtime 'bad' +CMake Error: Problem creating tar: bad.tar$ diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-opt1-result.txt b/Tests/RunCMake/CommandLine/E_tar-bad-opt1-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_tar-bad-opt1-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-opt1-stderr.txt b/Tests/RunCMake/CommandLine/E_tar-bad-opt1-stderr.txt new file mode 100644 index 000000000..35133c80d --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_tar-bad-opt1-stderr.txt @@ -0,0 +1 @@ +^CMake Error: Unknown option to -E tar: --bad$ diff --git a/Tests/RunCMake/CommandLine/E_tar-end-opt1-result.txt b/Tests/RunCMake/CommandLine/E_tar-end-opt1-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_tar-end-opt1-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_tar-end-opt1-stderr.txt b/Tests/RunCMake/CommandLine/E_tar-end-opt1-stderr.txt new file mode 100644 index 000000000..1fddf6d2d --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_tar-end-opt1-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: archive_read_disk_entry_from_file '--bad':.* +CMake Error: Problem creating tar: bad.tar$ diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 0c43c20b8..2994f160f 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -1,5 +1,11 @@ include(RunCMake) +run_cmake_command(E_tar-bad-opt1 ${CMAKE_COMMAND} -E tar cvf bad.tar --bad) +run_cmake_command(E_tar-bad-mtime1 ${CMAKE_COMMAND} -E tar cvf bad.tar --mtime=bad .) +run_cmake_command(E_tar-end-opt1 ${CMAKE_COMMAND} -E tar cvf bad.tar -- --bad) +run_cmake_command(E_tar-end-opt2 ${CMAKE_COMMAND} -E tar cvf bad.tar --) +run_cmake_command(E_tar-mtime ${CMAKE_COMMAND} -E tar cvf bad.tar "--mtime=1970-01-01 00:00:00 UTC") + run_cmake_command(build-no-cache ${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR}) run_cmake_command(build-no-generator