cmake: Teach "-E tar" command a "--mtime=" option

Add an option to set the mtime of entries in a tarball so that one can
create a tarball with a consistent content hash (e.g. MD5) for a given
set of files regardless of their current timestamps on disk.  This will
be useful for submission of tarballs to CDash, which tracks content
hashes to avoid duplication.

Inspired-by: Bill Hoffman <bill.hoffman@kitware.com>
This commit is contained in:
Brad King 2015-01-14 13:22:29 -05:00
parent 90f9c42732
commit 3a60c899fc
16 changed files with 112 additions and 6 deletions

View File

@ -0,0 +1,6 @@
cmake-E-tar-mtime
-----------------
* The :manual:`cmake(1)` ``-E tar`` command learned a new
``--mtime=<date>`` option to specify the modification time
recorded in tarball entries.

View File

@ -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

View File

@ -16,6 +16,7 @@
#include <cmsys/Directory.hxx>
#include <cmsys/FStream.hxx>
#include <cm_libarchive.h>
#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);

View File

@ -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

View File

@ -1469,7 +1469,7 @@ bool cmSystemTools::IsPathToFramework(const char* path)
bool cmSystemTools::CreateTar(const char* outFileName,
const std::vector<std::string>& 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<std::string>::const_iterator i = files.begin();
i != files.end(); ++i)

View File

@ -394,9 +394,9 @@ public:
bool verbose);
static bool CreateTar(const char* outFileName,
const std::vector<std::string>& 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

16
Source/cm_get_date.c Normal file
View File

@ -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"

28
Source/cm_get_date.h Normal file
View File

@ -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 <time.h>
#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

View File

@ -729,9 +729,31 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
std::string flags = args[2];
std::string outFile = args[3];
std::vector<std::string> 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<std::string>& 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;

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
^CMake Error: unable to parse mtime 'bad'
CMake Error: Problem creating tar: bad.tar$

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1 @@
^CMake Error: Unknown option to -E tar: --bad$

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
^CMake Error: archive_read_disk_entry_from_file '--bad':.*
CMake Error: Problem creating tar: bad.tar$

View File

@ -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