From 711e2b3b5c674d4f754b5b214d511be6ce7e8f4d Mon Sep 17 00:00:00 2001 From: Nils Gladitz Date: Fri, 5 Oct 2012 21:55:07 +0200 Subject: CMake: Add TIMESTAMP subcommand to string and file commands --- Source/cmBootstrapCommands.cxx | 1 + Source/cmFileCommand.cxx | 57 +++++++++ Source/cmFileCommand.h | 10 ++ Source/cmStringCommand.cxx | 54 +++++++++ Source/cmStringCommand.h | 30 ++++- Source/cmTimestamp.cxx | 134 +++++++++++++++++++++ Source/cmTimestamp.h | 40 ++++++ Tests/CMakeTests/File-TIMESTAMP-BadArg1.cmake | 1 + Tests/CMakeTests/File-TIMESTAMP-NoFile.cmake | 2 + Tests/CMakeTests/File-TIMESTAMP-NotBogus.cmake | 24 ++++ Tests/CMakeTests/File-TIMESTAMP-Works.cmake | 2 + Tests/CMakeTests/FileTest.cmake.in | 12 ++ .../String-TIMESTAMP-AllSpecifiers.cmake | 11 ++ Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake | 1 + Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake | 1 + Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake | 1 + .../String-TIMESTAMP-CustomFormatLocal.cmake | 2 + .../String-TIMESTAMP-CustomFormatUTC.cmake | 2 + .../String-TIMESTAMP-DefaulFormatUTC.cmake | 2 + .../String-TIMESTAMP-DefaultFormatLocal.cmake | 2 + .../String-TIMESTAMP-DefaultFormatUTC.cmake | 2 + .../String-TIMESTAMP-IncompleteSpecifier.cmake | 2 + .../String-TIMESTAMP-UnknownSpecifier.cmake | 2 + Tests/CMakeTests/StringTest.cmake.in | 30 +++++ 24 files changed, 424 insertions(+), 1 deletion(-) create mode 100644 Source/cmTimestamp.cxx create mode 100644 Source/cmTimestamp.h create mode 100644 Tests/CMakeTests/File-TIMESTAMP-BadArg1.cmake create mode 100644 Tests/CMakeTests/File-TIMESTAMP-NoFile.cmake create mode 100644 Tests/CMakeTests/File-TIMESTAMP-NotBogus.cmake create mode 100644 Tests/CMakeTests/File-TIMESTAMP-Works.cmake create mode 100644 Tests/CMakeTests/String-TIMESTAMP-AllSpecifiers.cmake create mode 100644 Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake create mode 100644 Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake create mode 100644 Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake create mode 100644 Tests/CMakeTests/String-TIMESTAMP-CustomFormatLocal.cmake create mode 100644 Tests/CMakeTests/String-TIMESTAMP-CustomFormatUTC.cmake create mode 100644 Tests/CMakeTests/String-TIMESTAMP-DefaulFormatUTC.cmake create mode 100644 Tests/CMakeTests/String-TIMESTAMP-DefaultFormatLocal.cmake create mode 100644 Tests/CMakeTests/String-TIMESTAMP-DefaultFormatUTC.cmake create mode 100644 Tests/CMakeTests/String-TIMESTAMP-IncompleteSpecifier.cmake create mode 100644 Tests/CMakeTests/String-TIMESTAMP-UnknownSpecifier.cmake diff --git a/Source/cmBootstrapCommands.cxx b/Source/cmBootstrapCommands.cxx index 9097a74..e3a2ad4 100644 --- a/Source/cmBootstrapCommands.cxx +++ b/Source/cmBootstrapCommands.cxx @@ -89,6 +89,7 @@ #include "cmStringCommand.cxx" #include "cmSubdirCommand.cxx" #include "cmTargetLinkLibrariesCommand.cxx" +#include "cmTimestamp.cxx" #include "cmTryCompileCommand.cxx" #include "cmTryRunCommand.cxx" #include "cmUnsetCommand.cxx" diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index b877f3c..42df3a1 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -17,6 +17,8 @@ #include "cmFileTimeComparison.h" #include "cmCryptoHash.h" +#include "cmTimestamp.h" + #if defined(CMAKE_BUILD_WITH_CMAKE) #include "cm_curl.h" #endif @@ -161,6 +163,10 @@ bool cmFileCommand { return this->HandleCMakePathCommand(args, true); } + else if ( subCommand == "TIMESTAMP" ) + { + return this->HandleTimestampCommand(args); + } std::string e = "does not recognize sub-command "+subCommand; this->SetError(e.c_str()); @@ -3241,3 +3247,54 @@ cmFileCommand::HandleUploadCommand(std::vector const& args) return false; #endif } + +//---------------------------------------------------------------------------- +bool cmFileCommand::HandleTimestampCommand( + std::vector const& args) +{ + if(args.size() < 3) + { + this->SetError("sub-command TIMESTAMP requires at least two arguments."); + return false; + } + else if(args.size() > 5) + { + this->SetError("sub-command TIMESTAMP takes at most four arguments."); + return false; + } + + int argsIndex = 1; + + const std::string& filename = args[argsIndex++]; + + const std::string& outputVariable = args[argsIndex++]; + + std::string formatString; + if(args.size() > argsIndex && args[argsIndex] != "UTC") + { + formatString = args[argsIndex++]; + } + + bool utcFlag = false; + if(args.size() > argsIndex) + { + if(args[argsIndex] == "UTC") + { + utcFlag = true; + } + else + { + std::string e = " TIMESTAMP sub-command does not recognize option " + + args[argsIndex] + "."; + this->SetError(e.c_str()); + return false; + } + } + + cmTimestamp timestamp; + std::string result = timestamp.FileModificationTime( + filename.c_str(), formatString, utcFlag); + this->Makefile->AddDefinition(outputVariable.c_str(), result.c_str()); + + return true; +} diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h index a0862ec..5550dbe 100644 --- a/Source/cmFileCommand.h +++ b/Source/cmFileCommand.h @@ -87,6 +87,8 @@ public: " [TLS_VERIFY on|off] [TLS_CAINFO file])\n" " file(UPLOAD filename url [INACTIVITY_TIMEOUT timeout]\n" " [TIMEOUT timeout] [STATUS status] [LOG log] [SHOW_PROGRESS])\n" + " file(TIMESTAMP " + " [] [UTC])\n" "WRITE will write a message into a file called 'filename'. It " "overwrites the file if it already exists, and creates the file " "if it does not exist. (If the file is a build input, use " @@ -200,6 +202,12 @@ public: "If SHOW_PROGRESS is specified, progress information will be printed " "as status messages until the operation is complete." "\n" + "TIMESTAMP will write a string representation of " + "the modification time of to .\n" + "Should the command be unable to obtain a timestamp " + " will be set to the empty string \"\".\n" + "See documentation of the string TIMESTAMP sub-command for more details." + "\n" "The file() command also provides COPY and INSTALL signatures:\n" " file( files... DESTINATION \n" " [FILE_PERMISSIONS permissions...]\n" @@ -260,6 +268,8 @@ protected: bool HandleInstallCommand(std::vector const& args); bool HandleDownloadCommand(std::vector const& args); bool HandleUploadCommand(std::vector const& args); + + bool HandleTimestampCommand(std::vector const& args); }; diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index 0193dc9..c402738 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -19,6 +19,8 @@ #include #include +#include + //---------------------------------------------------------------------------- bool cmStringCommand ::InitialPass(std::vector const& args, cmExecutionStatus &) @@ -87,6 +89,10 @@ bool cmStringCommand { return this->HandleFindCommand(args); } + else if(subCommand == "TIMESTAMP") + { + return this->HandleTimestampCommand(args); + } std::string e = "does not recognize sub-command "+subCommand; this->SetError(e.c_str()); @@ -879,3 +885,51 @@ bool cmStringCommand this->Makefile->AddDefinition(variableName.c_str(), &*result.begin()); return true; } + +//---------------------------------------------------------------------------- +bool cmStringCommand +::HandleTimestampCommand(std::vector const& args) +{ + if(args.size() < 2) + { + this->SetError("sub-command TIMESTAMP requires at least one argument."); + return false; + } + else if(args.size() > 4) + { + this->SetError("sub-command TIMESTAMP takes at most three arguments."); + return false; + } + + int argsIndex = 1; + + const std::string &outputVariable = args[argsIndex++]; + + std::string formatString; + if(args.size() > argsIndex && args[argsIndex] != "UTC") + { + formatString = args[argsIndex++]; + } + + bool utcFlag = false; + if(args.size() > argsIndex) + { + if(args[argsIndex] == "UTC") + { + utcFlag = true; + } + else + { + std::string e = " TIMESTAMP sub-command does not recognize option " + + args[argsIndex] + "."; + this->SetError(e.c_str()); + return false; + } + } + + cmTimestamp timestamp; + std::string result = timestamp.CurrentTime(formatString, utcFlag); + this->Makefile->AddDefinition(outputVariable.c_str(), result.c_str()); + + return true; +} diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h index 728b1bc..7e0694e 100644 --- a/Source/cmStringCommand.h +++ b/Source/cmStringCommand.h @@ -93,6 +93,7 @@ public: " string(RANDOM [LENGTH ] [ALPHABET ]\n" " [RANDOM_SEED ] )\n" " string(FIND [REVERSE])\n" + " string(TIMESTAMP [] [UTC])\n" "REGEX MATCH will match the regular expression once and store the " "match in the output variable.\n" "REGEX MATCHALL will match the regular expression as many times as " @@ -142,7 +143,33 @@ public: " () Saves a matched subexpression, which can be referenced \n" " in the REGEX REPLACE operation. Additionally it is saved\n" " by all regular expression-related commands, including \n" - " e.g. if( MATCHES ), in the variables CMAKE_MATCH_(0..9)."; + " e.g. if( MATCHES ), in the variables CMAKE_MATCH_(0..9).\n" + "TIMESTAMP will write a string representation of " + "the current date and/or time to .\n" + "Should the command be unable to obtain a timestamp " + " will be set to the empty string \"\".\n" + "The optional UTC flag requests the current date/time " + "representation to be in Coordinated Universal Time (UTC) " + "rather than local time.\n" + "The optional may contain the following " + "format specifiers: \n" + " %d The day of the current month (01-31).\n" + " %H The hour on a 24-hour clock (00-23).\n" + " %I The hour on a 12-hour clock (01-12).\n" + " %j The day of the current year (001-366).\n" + " %m The month of the current year (01-12).\n" + " %M The minute of the current hour (00-59).\n" + " %S The second of the current minute.\n" + " 60 represents a leap second. (00-60)\n" + " %U The week number of the current year (00-53).\n" + " %w The day of the current week. 0 is Sunday. (0-6)\n" + " %y The last two digits of the current year (00-99)\n" + " %Y The current year. \n" + "Unknown format specifiers will be ignored " + "and copied to the output as-is.\n" + "If no explicit is given it will default to:\n" + " %Y-%m-%dT%H:%M:%S for local time.\n" + " %Y-%m-%dT%H:%M:%SZ for UTC."; } cmTypeMacro(cmStringCommand, cmCommand); @@ -165,6 +192,7 @@ protected: bool HandleStripCommand(std::vector const& args); bool HandleRandomCommand(std::vector const& args); bool HandleFindCommand(std::vector const& args); + bool HandleTimestampCommand(std::vector const& args); class RegexReplacement { diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx new file mode 100644 index 0000000..f1115e6 --- /dev/null +++ b/Source/cmTimestamp.cxx @@ -0,0 +1,134 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2012 Kitware, Inc., Insight Software Consortium + + 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 "cmTimestamp.h" + +#include + +#include +#include + +//---------------------------------------------------------------------------- +std::string cmTimestamp::CurrentTime( + const std::string& formatString, bool utcFlag) +{ + time_t currentTimeT = time(0); + if(currentTimeT == time_t(-1)) return std::string(); + + return CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag); +} + +std::string cmTimestamp::FileModificationTime(const char* path, + const std::string& formatString, bool utcFlag) +{ +#ifdef _WIN32 + struct _stat info; + std::memset(&info, 0, sizeof(info)); + + if(_stat(path, &info) != 0) + return std::string(); + + time_t currentTimeT = info.st_mtime; +#else + struct stat info; + std::memset(&info, 0, sizeof(info)); + + if(stat(path, &info) != 0) + return std::string(); + + time_t currentTimeT = info.st_mtime; +#endif + + return CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag); +} + +std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT, + std::string formatString, bool utcFlag) +{ + if(formatString.empty()) + { + formatString = "%Y-%m-%dT%H:%M:%S"; + if(utcFlag) formatString += "Z"; + } + + struct tm timeStruct; + std::memset(&timeStruct, 0, sizeof(timeStruct)); + + if(utcFlag) + { + tm* ptr = gmtime(&timeT); + if(ptr == 0) return std::string(); + + timeStruct = *ptr; + } + else + { + struct tm* ptr = localtime(&timeT); + if(ptr == 0) return std::string(); + + timeStruct = *ptr; + } + + std::string result; + for(std::string::size_type i = 0; i < formatString.size(); ++i) + { + char c1 = formatString[i]; + char c2 = (i+1 < formatString.size()) ? + formatString[i+1] : 0; + + if(c1 == '%' && c2 != 0) + { + result += AddTimestampComponent(c2, timeStruct); + ++i; + } + else + { + result += c1; + } + } + + return result; +} + +//---------------------------------------------------------------------------- +std::string cmTimestamp::AddTimestampComponent( + char flag, struct tm& timeStruct) +{ + std::string formatString = "%"; + formatString += flag; + + switch(flag) + { + case 'd': + case 'H': + case 'I': + case 'j': + case 'm': + case 'M': + case 'S': + case 'U': + case 'w': + case 'y': + case 'Y': + break; + default: + { + return formatString; + } + } + + char buffer[16]; + + size_t size = strftime(buffer, sizeof(buffer), + formatString.c_str(), &timeStruct); + + return std::string(buffer, size); +} diff --git a/Source/cmTimestamp.h b/Source/cmTimestamp.h new file mode 100644 index 0000000..24c1869 --- /dev/null +++ b/Source/cmTimestamp.h @@ -0,0 +1,40 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2012 Kitware, Inc., Insight Software Consortium + + 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 cmTimestamp_h +#define cmTimestamp_h + +#include +#include + +/** \class cmTimestamp + * \brief Utility class to generate sting representation of a timestamp + * + */ +class cmTimestamp +{ +public: + cmTimestamp() {} + + std::string CurrentTime(const std::string& formatString, bool utcFlag); + + std::string FileModificationTime(const char* path, + const std::string& formatString, bool utcFlag); + +private: + std::string CreateTimestampFromTimeT(time_t timeT, + std::string formatString, bool utcFlag); + + std::string AddTimestampComponent(char flag, struct tm& timeStruct); +}; + + +#endif diff --git a/Tests/CMakeTests/File-TIMESTAMP-BadArg1.cmake b/Tests/CMakeTests/File-TIMESTAMP-BadArg1.cmake new file mode 100644 index 0000000..cc15c77 --- /dev/null +++ b/Tests/CMakeTests/File-TIMESTAMP-BadArg1.cmake @@ -0,0 +1 @@ +file(TIMESTAMP "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt") diff --git a/Tests/CMakeTests/File-TIMESTAMP-NoFile.cmake b/Tests/CMakeTests/File-TIMESTAMP-NoFile.cmake new file mode 100644 index 0000000..62390e7 --- /dev/null +++ b/Tests/CMakeTests/File-TIMESTAMP-NoFile.cmake @@ -0,0 +1,2 @@ +file(TIMESTAMP "${CMAKE_CURRENT_LIST_DIR}/DoesNotExist.cmake" output) +message("~${output}~") diff --git a/Tests/CMakeTests/File-TIMESTAMP-NotBogus.cmake b/Tests/CMakeTests/File-TIMESTAMP-NotBogus.cmake new file mode 100644 index 0000000..d0e5fe3 --- /dev/null +++ b/Tests/CMakeTests/File-TIMESTAMP-NotBogus.cmake @@ -0,0 +1,24 @@ +set(STAMP_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/FileTimestamp-Stamp") +set(STAMP_FORMAT "%Y-%m-%d") + +string(TIMESTAMP timestamp1 "${STAMP_FORMAT}") + +file(WRITE "${STAMP_FILENAME}" "foo") +file(TIMESTAMP "${STAMP_FILENAME}" timestamp2 "${STAMP_FORMAT}") + +string(TIMESTAMP timestamp3 "${STAMP_FORMAT}") + +message(STATUS "timestamp1 [${timestamp1}]") +message(STATUS "timestamp2 [${timestamp2}]") +message(STATUS "timestamp3 [${timestamp3}]") + +if(timestamp1 STREQUAL timestamp3) + if(NOT timestamp1 STREQUAL timestamp2) + message(FATAL_ERROR + "timestamp mismatch [${timestamp1}] != [${timestamp2}]") + else() + message("all timestamps match") + endif() +else() + message(WARNING "this test may race when run at midnight") +endif() diff --git a/Tests/CMakeTests/File-TIMESTAMP-Works.cmake b/Tests/CMakeTests/File-TIMESTAMP-Works.cmake new file mode 100644 index 0000000..4351b19 --- /dev/null +++ b/Tests/CMakeTests/File-TIMESTAMP-Works.cmake @@ -0,0 +1,2 @@ +file(TIMESTAMP "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt" output UTC) +message("~${output}~") diff --git a/Tests/CMakeTests/FileTest.cmake.in b/Tests/CMakeTests/FileTest.cmake.in index 960d3c1..61523e6 100644 --- a/Tests/CMakeTests/FileTest.cmake.in +++ b/Tests/CMakeTests/FileTest.cmake.in @@ -36,6 +36,14 @@ set(SHA384-Works-RESULT 0) set(SHA384-Works-STDERR "1de9560b4e030e02051ea408200ffc55d70c97ac64ebf822461a5c786f495c36df43259b14483bc8d364f0106f4971ee") set(SHA512-Works-RESULT 0) set(SHA512-Works-STDERR "3982a1b4e651768bec70ab1fb97045cb7a659f4ba7203d501c52ab2e803071f9d5fd272022df15f27727fc67f8cd022e710e29010b2a9c0b467c111e2f6abf51") +set(TIMESTAMP-NoFile-RESULT 0) +set(TIMESTAMP-NoFile-STDERR "~~") +set(TIMESTAMP-BadArg1-RESULT 1) +set(TIMESTAMP-BadArg1-STDERR "file sub-command TIMESTAMP requires at least two arguments") +set(TIMESTAMP-NotBogus-RESULT 0) +set(TIMESTAMP-NotBogus-STDERR "all timestamps match") +set(TIMESTAMP-Works-RESULT 0) +set(TIMESTAMP-Works-STDERR "~[0-9]*-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-6][0-9]Z~") include("@CMAKE_CURRENT_SOURCE_DIR@/CheckCMakeTest.cmake") check_cmake_test(File @@ -58,6 +66,10 @@ check_cmake_test(File SHA256-Works SHA384-Works SHA512-Works + TIMESTAMP-NoFile + TIMESTAMP-BadArg1 + TIMESTAMP-NotBogus + TIMESTAMP-Works ) file(GLOB hum) diff --git a/Tests/CMakeTests/String-TIMESTAMP-AllSpecifiers.cmake b/Tests/CMakeTests/String-TIMESTAMP-AllSpecifiers.cmake new file mode 100644 index 0000000..2d0fcc8 --- /dev/null +++ b/Tests/CMakeTests/String-TIMESTAMP-AllSpecifiers.cmake @@ -0,0 +1,11 @@ +string(TIMESTAMP output "%d;%H;%I;%j;%m;%M;%S;%U;%w;%y;%Y") +message("~${output}~") + +list(LENGTH output output_length) + +set(expected_output_length 11) + +if(NOT output_length EQUAL ${expected_output_length}) + message(FATAL_ERROR "expected ${expected_output_length} entries in output " + "with all specifiers; found ${output_length}") +endif() diff --git a/Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake b/Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake new file mode 100644 index 0000000..8f2d9f8 --- /dev/null +++ b/Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake @@ -0,0 +1 @@ +string(TIMESTAMP) diff --git a/Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake b/Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake new file mode 100644 index 0000000..c1e5126 --- /dev/null +++ b/Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake @@ -0,0 +1 @@ +string(TIMESTAMP output_variable "%Y" UTF) diff --git a/Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake b/Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake new file mode 100644 index 0000000..3d577df --- /dev/null +++ b/Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake @@ -0,0 +1 @@ +string(TIMESTAMP output_variable "%Y" UTC UTC) diff --git a/Tests/CMakeTests/String-TIMESTAMP-CustomFormatLocal.cmake b/Tests/CMakeTests/String-TIMESTAMP-CustomFormatLocal.cmake new file mode 100644 index 0000000..eab2a45 --- /dev/null +++ b/Tests/CMakeTests/String-TIMESTAMP-CustomFormatLocal.cmake @@ -0,0 +1,2 @@ +string(TIMESTAMP output "%S") +message("~${output}~") diff --git a/Tests/CMakeTests/String-TIMESTAMP-CustomFormatUTC.cmake b/Tests/CMakeTests/String-TIMESTAMP-CustomFormatUTC.cmake new file mode 100644 index 0000000..eab2a45 --- /dev/null +++ b/Tests/CMakeTests/String-TIMESTAMP-CustomFormatUTC.cmake @@ -0,0 +1,2 @@ +string(TIMESTAMP output "%S") +message("~${output}~") diff --git a/Tests/CMakeTests/String-TIMESTAMP-DefaulFormatUTC.cmake b/Tests/CMakeTests/String-TIMESTAMP-DefaulFormatUTC.cmake new file mode 100644 index 0000000..dad6a8d --- /dev/null +++ b/Tests/CMakeTests/String-TIMESTAMP-DefaulFormatUTC.cmake @@ -0,0 +1,2 @@ +string(TIMESTAMP output UTC) +message("~${output}~") diff --git a/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatLocal.cmake b/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatLocal.cmake new file mode 100644 index 0000000..d7c7dde --- /dev/null +++ b/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatLocal.cmake @@ -0,0 +1,2 @@ +string(TIMESTAMP output) +message("~${output}~") diff --git a/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatUTC.cmake b/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatUTC.cmake new file mode 100644 index 0000000..dad6a8d --- /dev/null +++ b/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatUTC.cmake @@ -0,0 +1,2 @@ +string(TIMESTAMP output UTC) +message("~${output}~") diff --git a/Tests/CMakeTests/String-TIMESTAMP-IncompleteSpecifier.cmake b/Tests/CMakeTests/String-TIMESTAMP-IncompleteSpecifier.cmake new file mode 100644 index 0000000..ffc5656 --- /dev/null +++ b/Tests/CMakeTests/String-TIMESTAMP-IncompleteSpecifier.cmake @@ -0,0 +1,2 @@ +string(TIMESTAMP output "foobar%") +message("~${output}~") diff --git a/Tests/CMakeTests/String-TIMESTAMP-UnknownSpecifier.cmake b/Tests/CMakeTests/String-TIMESTAMP-UnknownSpecifier.cmake new file mode 100644 index 0000000..0e145e5 --- /dev/null +++ b/Tests/CMakeTests/String-TIMESTAMP-UnknownSpecifier.cmake @@ -0,0 +1,2 @@ +string(TIMESTAMP output "%g") +message("~${output}~") diff --git a/Tests/CMakeTests/StringTest.cmake.in b/Tests/CMakeTests/StringTest.cmake.in index 49e7dc9..a9fe428 100644 --- a/Tests/CMakeTests/StringTest.cmake.in +++ b/Tests/CMakeTests/StringTest.cmake.in @@ -16,6 +16,26 @@ set(SHA384-Works-RESULT 0) set(SHA384-Works-STDERR "1de9560b4e030e02051ea408200ffc55d70c97ac64ebf822461a5c786f495c36df43259b14483bc8d364f0106f4971ee") set(SHA512-Works-RESULT 0) set(SHA512-Works-STDERR "3982a1b4e651768bec70ab1fb97045cb7a659f4ba7203d501c52ab2e803071f9d5fd272022df15f27727fc67f8cd022e710e29010b2a9c0b467c111e2f6abf51") +set(TIMESTAMP-BadArg1-RESULT 1) +set(TIMESTAMP-BadArg1-STDERR "string sub-command TIMESTAMP requires at least one argument") +set(TIMESTAMP-BadArg2-RESULT 1) +set(TIMESTAMP-BadArg2-STDERR "string TIMESTAMP sub-command does not recognize option UTF") +set(TIMESTAMP-BadArg3-RESULT 1) +set(TIMESTAMP-BadArg3-STDERR "string sub-command TIMESTAMP takes at most three arguments") +set(TIMESTAMP-DefaultFormatLocal-RESULT 0) +set(TIMESTAMP-DefaultFormatLocal-STDERR "~[0-9]*-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-6][0-9]~") +set(TIMESTAMP-DefaultFormatUTC-RESULT 0) +set(TIMESTAMP-DefaultFormatUTC-STDERR "~[0-9]*-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-6][0-9]Z~") +set(TIMESTAMP-CustomFormatLocal-RESULT 0) +set(TIMESTAMP-CustomFormatLocal-STDERR "~([0-5][0-9])|60~") +set(TIMESTAMP-CustomFormatUTC-RESULT 0) +set(TIMESTAMP-CustomFormatUTC-STDERR "~([0-5][0-9])|60~") +set(TIMESTAMP-UnknownSpecifier-RESULT 0) +set(TIMESTAMP-UnknownSpecifier-STDERR "~%g~") +set(TIMESTAMP-IncompleteSpecifier-RESULT 0) +set(TIMESTAMP-IncompleteSpecifier-STDERR "~foobar%~") +set(TIMESTAMP-AllSpecifiers-RESULT 0) +set(TIMESTAMP-AllSpecifiers-STDERR "~[0-9]+(;[0-9]+)*~") include("@CMAKE_CURRENT_SOURCE_DIR@/CheckCMakeTest.cmake") check_cmake_test(String @@ -28,6 +48,16 @@ check_cmake_test(String SHA256-Works SHA384-Works SHA512-Works + TIMESTAMP-BadArg1 + TIMESTAMP-BadArg2 + TIMESTAMP-BadArg3 + TIMESTAMP-DefaultFormatLocal + TIMESTAMP-DefaultFormatUTC + TIMESTAMP-CustomFormatLocal + TIMESTAMP-CustomFormatUTC + TIMESTAMP-UnknownSpecifier + TIMESTAMP-IncompleteSpecifier + TIMESTAMP-AllSpecifiers ) # Execute each test listed in StringTestScript.cmake: -- cgit v0.12 From d842d9062297435747117bd74b6e184cedd345cc Mon Sep 17 00:00:00 2001 From: David Cole Date: Wed, 5 Dec 2012 09:55:27 -0500 Subject: CMake: Stylistic changes and documentation tweaks ...for the contributed file and string TIMESTAMP sub-commands. --- Source/cmFileCommand.h | 7 ++- Source/cmStringCommand.h | 4 +- Source/cmTimestamp.cxx | 50 ++++++++++++---------- .../String-TIMESTAMP-DefaulFormatUTC.cmake | 2 - 4 files changed, 33 insertions(+), 30 deletions(-) delete mode 100644 Tests/CMakeTests/String-TIMESTAMP-DefaulFormatUTC.cmake diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h index 5550dbe..5973fa7 100644 --- a/Source/cmFileCommand.h +++ b/Source/cmFileCommand.h @@ -87,8 +87,7 @@ public: " [TLS_VERIFY on|off] [TLS_CAINFO file])\n" " file(UPLOAD filename url [INACTIVITY_TIMEOUT timeout]\n" " [TIMEOUT timeout] [STATUS status] [LOG log] [SHOW_PROGRESS])\n" - " file(TIMESTAMP " - " [] [UTC])\n" + " file(TIMESTAMP filename variable [] [UTC])\n" "WRITE will write a message into a file called 'filename'. It " "overwrites the file if it already exists, and creates the file " "if it does not exist. (If the file is a build input, use " @@ -203,9 +202,9 @@ public: "as status messages until the operation is complete." "\n" "TIMESTAMP will write a string representation of " - "the modification time of to .\n" + "the modification time of filename to variable.\n" "Should the command be unable to obtain a timestamp " - " will be set to the empty string \"\".\n" + "variable will be set to the empty string \"\".\n" "See documentation of the string TIMESTAMP sub-command for more details." "\n" "The file() command also provides COPY and INSTALL signatures:\n" diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h index 7e0694e..4423a90 100644 --- a/Source/cmStringCommand.h +++ b/Source/cmStringCommand.h @@ -145,9 +145,9 @@ public: " by all regular expression-related commands, including \n" " e.g. if( MATCHES ), in the variables CMAKE_MATCH_(0..9).\n" "TIMESTAMP will write a string representation of " - "the current date and/or time to .\n" + "the current date and/or time to the output variable.\n" "Should the command be unable to obtain a timestamp " - " will be set to the empty string \"\".\n" + "the output variable will be set to the empty string \"\".\n" "The optional UTC flag requests the current date/time " "representation to be in Coordinated Universal Time (UTC) " "rather than local time.\n" diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index f1115e6..c3df495 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -21,62 +21,68 @@ std::string cmTimestamp::CurrentTime( const std::string& formatString, bool utcFlag) { time_t currentTimeT = time(0); - if(currentTimeT == time_t(-1)) return std::string(); + if(currentTimeT == time_t(-1)) + { + return std::string(); + } return CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag); } +//---------------------------------------------------------------------------- std::string cmTimestamp::FileModificationTime(const char* path, const std::string& formatString, bool utcFlag) { #ifdef _WIN32 - struct _stat info; - std::memset(&info, 0, sizeof(info)); - - if(_stat(path, &info) != 0) - return std::string(); - - time_t currentTimeT = info.st_mtime; + #define STAT _stat #else - struct stat info; + #define STAT stat +#endif + + struct STAT info; std::memset(&info, 0, sizeof(info)); - if(stat(path, &info) != 0) + if(STAT(path, &info) != 0) + { return std::string(); + } - time_t currentTimeT = info.st_mtime; -#endif - - return CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag); + return CreateTimestampFromTimeT(info.st_mtime, formatString, utcFlag); } +//---------------------------------------------------------------------------- std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT, std::string formatString, bool utcFlag) { if(formatString.empty()) { formatString = "%Y-%m-%dT%H:%M:%S"; - if(utcFlag) formatString += "Z"; + if(utcFlag) + { + formatString += "Z"; + } } struct tm timeStruct; std::memset(&timeStruct, 0, sizeof(timeStruct)); + struct tm* ptr = (struct tm*) 0; if(utcFlag) { - tm* ptr = gmtime(&timeT); - if(ptr == 0) return std::string(); - - timeStruct = *ptr; + ptr = gmtime(&timeT); } else { - struct tm* ptr = localtime(&timeT); - if(ptr == 0) return std::string(); + ptr = localtime(&timeT); + } - timeStruct = *ptr; + if(ptr == 0) + { + return std::string(); } + timeStruct = *ptr; + std::string result; for(std::string::size_type i = 0; i < formatString.size(); ++i) { diff --git a/Tests/CMakeTests/String-TIMESTAMP-DefaulFormatUTC.cmake b/Tests/CMakeTests/String-TIMESTAMP-DefaulFormatUTC.cmake deleted file mode 100644 index dad6a8d..0000000 --- a/Tests/CMakeTests/String-TIMESTAMP-DefaulFormatUTC.cmake +++ /dev/null @@ -1,2 +0,0 @@ -string(TIMESTAMP output UTC) -message("~${output}~") -- cgit v0.12 From 354ecc1e1f28b9f2412fa015064353c6e20cfe92 Mon Sep 17 00:00:00 2001 From: David Cole Date: Wed, 5 Dec 2012 13:14:56 -0500 Subject: CMake: Fix dashboard warnings ...in the new file and string TIMESTAMP sub-commands --- Source/cmFileCommand.cxx | 2 +- Source/cmStringCommand.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 42df3a1..0cdbb82 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -3263,7 +3263,7 @@ bool cmFileCommand::HandleTimestampCommand( return false; } - int argsIndex = 1; + unsigned int argsIndex = 1; const std::string& filename = args[argsIndex++]; diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index c402738..e49edd8 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -901,7 +901,7 @@ bool cmStringCommand return false; } - int argsIndex = 1; + unsigned int argsIndex = 1; const std::string &outputVariable = args[argsIndex++]; -- cgit v0.12 From e28ce2483dbdc620aa92e2ba0d86e8923dcdb296 Mon Sep 17 00:00:00 2001 From: David Cole Date: Wed, 5 Dec 2012 15:16:22 -0500 Subject: CMake: Fix dashboard test failure Eliminate the platform difference in calling stat. We call stat normally in other places in the CMake code base just fine. Works everywhere we work. Will hopefully also fix the Borland Continuous dashboard failure that is occurring with respect to correctly measuring the modification time of a freshly generated file. --- Source/cmTimestamp.cxx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index c3df495..22bb4b7 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -33,16 +33,10 @@ std::string cmTimestamp::CurrentTime( std::string cmTimestamp::FileModificationTime(const char* path, const std::string& formatString, bool utcFlag) { -#ifdef _WIN32 - #define STAT _stat -#else - #define STAT stat -#endif - - struct STAT info; + struct stat info; std::memset(&info, 0, sizeof(info)); - if(STAT(path, &info) != 0) + if(stat(path, &info) != 0) { return std::string(); } -- cgit v0.12 From 12d87c04253bd203a9b8a510b1772291527d441c Mon Sep 17 00:00:00 2001 From: David Cole Date: Thu, 6 Dec 2012 07:20:12 -0500 Subject: CMake: Fix dashboard build errors and warnings memset is not in std:: for VS6, and though quite silly, 0 is not a char --- Source/cmTimestamp.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index 22bb4b7..ac26503 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -34,7 +34,7 @@ std::string cmTimestamp::FileModificationTime(const char* path, const std::string& formatString, bool utcFlag) { struct stat info; - std::memset(&info, 0, sizeof(info)); + memset(&info, 0, sizeof(info)); if(stat(path, &info) != 0) { @@ -58,7 +58,7 @@ std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT, } struct tm timeStruct; - std::memset(&timeStruct, 0, sizeof(timeStruct)); + memset(&timeStruct, 0, sizeof(timeStruct)); struct tm* ptr = (struct tm*) 0; if(utcFlag) @@ -82,7 +82,7 @@ std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT, { char c1 = formatString[i]; char c2 = (i+1 < formatString.size()) ? - formatString[i+1] : 0; + formatString[i+1] : static_cast(0); if(c1 == '%' && c2 != 0) { -- cgit v0.12