[Cmake-commits] CMake branch, next, updated. v3.1.0-2172-g85f6c64
Brad King
brad.king at kitware.com
Mon Jan 19 11:18:18 EST 2015
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".
The branch, next has been updated
via 85f6c64358e1a1077d01b77b93c09d8d964375c9 (commit)
via bf7096c4adc4e1642353a57bfdec509693586697 (commit)
via 941a1dfb85a96e778d666e4d823729d292a64d20 (commit)
from 9a96401774c4afc6bc12cde06cf6d6306b2f5b22 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=85f6c64358e1a1077d01b77b93c09d8d964375c9
commit 85f6c64358e1a1077d01b77b93c09d8d964375c9
Merge: 9a96401 bf7096c
Author: Brad King <brad.king at kitware.com>
AuthorDate: Mon Jan 19 11:18:17 2015 -0500
Commit: CMake Topic Stage <kwrobot at kitware.com>
CommitDate: Mon Jan 19 11:18:17 2015 -0500
Merge topic 'cdash_upload_file_mode' into next
bf7096c4 cmake: Generate an internal 'Labels.json' file next to 'Labels.txt'
941a1dfb Add support to ctest_submit to upload files to cdash with CDASH_UPLOAD.
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bf7096c4adc4e1642353a57bfdec509693586697
commit bf7096c4adc4e1642353a57bfdec509693586697
Author: Brad King <brad.king at kitware.com>
AuthorDate: Fri Jan 16 15:35:36 2015 -0500
Commit: Brad King <brad.king at kitware.com>
CommitDate: Mon Jan 19 11:17:18 2015 -0500
cmake: Generate an internal 'Labels.json' file next to 'Labels.txt'
In each internal target directory we generate a "Labels.txt" file
containing labels for that target and its sources, but it uses an
internal format. In order to make the list of labels easier to
publish, use a json format and call it "Labels.json".
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 78bef91..4ce601d 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -500,7 +500,9 @@ add_library(CMakeLib ${SRCS})
target_link_libraries(CMakeLib cmsys
${CMAKE_EXPAT_LIBRARIES} ${CMAKE_ZLIB_LIBRARIES}
${CMAKE_TAR_LIBRARIES} ${CMAKE_COMPRESS_LIBRARIES}
- ${CMAKE_CURL_LIBRARIES} )
+ ${CMAKE_CURL_LIBRARIES}
+ cmjsoncpp
+ )
# On Apple we need CoreFoundation
if(APPLE)
@@ -584,7 +586,7 @@ set(CTEST_SRCS cmCTest.cxx
# Build CTestLib
add_library(CTestLib ${CTEST_SRCS})
-target_link_libraries(CTestLib CMakeLib ${CMAKE_CURL_LIBRARIES} ${CMAKE_XMLRPC_LIBRARIES} cmjsoncpp)
+target_link_libraries(CTestLib CMakeLib ${CMAKE_CURL_LIBRARIES} ${CMAKE_XMLRPC_LIBRARIES})
#
# Sources for CPack
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 1745d9a..dd3b1ec 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -38,6 +38,8 @@
#if defined(CMAKE_BUILD_WITH_CMAKE)
# include <cmsys/MD5.h>
+# include "cm_jsoncpp_value.h"
+# include "cm_jsoncpp_writer.h"
#endif
#include <stdlib.h> // required for atof
@@ -2911,10 +2913,21 @@ void cmGlobalGenerator::WriteSummary(cmTarget* target)
std::string dir = target->GetSupportDirectory();
std::string file = dir;
file += "/Labels.txt";
+ std::string json_file = dir + "/Labels.json";
+#ifdef CMAKE_BUILD_WITH_CMAKE
// Check whether labels are enabled for this target.
if(const char* value = target->GetProperty("LABELS"))
{
+ Json::Value lj_root(Json::objectValue);
+ Json::Value& lj_target =
+ lj_root["target"] = Json::objectValue;
+ lj_target["name"] = target->GetName();
+ Json::Value& lj_target_labels =
+ lj_target["labels"] = Json::arrayValue;
+ Json::Value& lj_sources =
+ lj_root["sources"] = Json::arrayValue;
+
cmSystemTools::MakeDirectory(dir.c_str());
cmGeneratedFileStream fout(file.c_str());
@@ -2929,6 +2942,7 @@ void cmGlobalGenerator::WriteSummary(cmTarget* target)
li != labels.end(); ++li)
{
fout << " " << *li << "\n";
+ lj_target_labels.append(*li);
}
}
@@ -2954,23 +2968,33 @@ void cmGlobalGenerator::WriteSummary(cmTarget* target)
{
continue;
}
+ Json::Value& lj_source = lj_sources.append(Json::objectValue);
cmSourceFile* sf = *si;
- fout << sf->GetFullPath() << "\n";
+ std::string const& sfp = sf->GetFullPath();
+ fout << sfp << "\n";
+ lj_source["file"] = sfp;
if(const char* svalue = sf->GetProperty("LABELS"))
{
labels.clear();
+ Json::Value& lj_source_labels =
+ lj_source["labels"] = Json::arrayValue;
cmSystemTools::ExpandListArgument(svalue, labels);
for(std::vector<std::string>::const_iterator li = labels.begin();
li != labels.end(); ++li)
{
fout << " " << *li << "\n";
+ lj_source_labels.append(*li);
}
}
}
+ cmGeneratedFileStream json_fout(json_file.c_str());
+ json_fout << lj_root;
}
else
+#endif
{
cmSystemTools::RemoveFile(file);
+ cmSystemTools::RemoveFile(json_file);
}
}
diff --git a/Utilities/cm_jsoncpp_value.h b/Utilities/cm_jsoncpp_value.h
new file mode 100644
index 0000000..15e1088
--- /dev/null
+++ b/Utilities/cm_jsoncpp_value.h
@@ -0,0 +1,18 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 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 cm_jsoncpp_value_h
+#define cm_jsoncpp_value_h
+
+/* Use the jsoncpp library configured for CMake. */
+#include <cmjsoncpp/include/json/value.h>
+
+#endif
diff --git a/Utilities/cm_jsoncpp_writer.h b/Utilities/cm_jsoncpp_writer.h
new file mode 100644
index 0000000..c410369
--- /dev/null
+++ b/Utilities/cm_jsoncpp_writer.h
@@ -0,0 +1,18 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 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 cm_jsoncpp_writer_h
+#define cm_jsoncpp_writer_h
+
+/* Use the jsoncpp library configured for CMake. */
+#include <cmjsoncpp/include/json/writer.h>
+
+#endif
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=941a1dfb85a96e778d666e4d823729d292a64d20
commit 941a1dfb85a96e778d666e4d823729d292a64d20
Author: Bill Hoffman <bill.hoffman at kitware.com>
AuthorDate: Tue Dec 23 11:03:14 2014 -0500
Commit: Brad King <brad.king at kitware.com>
CommitDate: Mon Jan 19 11:17:17 2015 -0500
Add support to ctest_submit to upload files to cdash with CDASH_UPLOAD.
This adds support for the new cdash API where arbitrary files can be
uploaded to the CDash server. This CDash API communicates via json
files so the json parser jsoncpp was added to the Utilities directory.
In addition since CDash tracks the md5 sum of the files uploaded the
--mtime option was added to cmake -E tar so that tar files could be
created that would have the same md5sum with the same content. The first
supported file upload type to CDash is a GCOV with branches coverage tar
file. To support this a Modules/CTestCoverageCollectGCOV.cmake was added
to run gcov for a project via a CMake function.
diff --git a/Help/command/ctest_submit.rst b/Help/command/ctest_submit.rst
index d9b0b78..316a43d 100644
--- a/Help/command/ctest_submit.rst
+++ b/Help/command/ctest_submit.rst
@@ -37,3 +37,14 @@ timed-out submission before attempting to re-submit.
The RETRY_COUNT option specifies how many times to retry a timed-out
submission.
+
+::
+
+ ctest_submit([CDASH_UPLOAD file]
+ [CDASH_UPLOAD_TYPE type_string])
+
+This second signature is used to upload files to CDash via the CDash
+file upload API. The api first sends a request to upload to CDash along
+with the md5 sum of the file. If CDash does not already have the file,
+then it is uploaded. Along with the file, a CDash type string is specified
+to tell CDash which handler to use to process the data.
diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst
index 0a0ca23..db56010 100644
--- a/Help/manual/cmake-modules.7.rst
+++ b/Help/manual/cmake-modules.7.rst
@@ -63,6 +63,7 @@ All Modules
/module/CPack
/module/CPackWIX
/module/CTest
+ /module/CTestCoverageCollectGCOV
/module/CTestScriptMode
/module/CTestUseLaunchers
/module/Dart
diff --git a/Help/module/CTestCoverageCollectGCOV.rst b/Help/module/CTestCoverageCollectGCOV.rst
new file mode 100644
index 0000000..4c5deca
--- /dev/null
+++ b/Help/module/CTestCoverageCollectGCOV.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CTestCoverageCollectGCOV.cmake
diff --git a/Modules/CTestCoverageCollectGCOV.cmake b/Modules/CTestCoverageCollectGCOV.cmake
new file mode 100644
index 0000000..29fd504
--- /dev/null
+++ b/Modules/CTestCoverageCollectGCOV.cmake
@@ -0,0 +1,123 @@
+#.rst:
+# CTestCoverageCollectGCOV
+# ------------------------
+#
+# This module provides the function ``ctest_coverage_collect_gcov``.
+# The function will run gcov on the .gcda files in a binary tree and then
+# package all of the .gcov files into a tar file with a data.json.
+# This file can be sent to a CDash server for display with the
+# :command:`ctest_submit(CDASH_UPLOAD)` command.
+#
+# .. command:: cdash_coverage_collect_gcov
+#
+# ::
+#
+# ctest_coverage_collect_gcov(
+# TARBALL <tarfile> # required
+# SOURCE <source_dir> # optional, else CTEST_SOURCE_DIRECTORY
+# BUILD <build_dir> # optional, else CTEST_BINARY_DIRECTORY
+# GCOV_COMMAND <gcov_command> # optional, else CTEST_COVERAGE_COMMAND
+# )
+#
+# Run gcov and package a tar file for cdash. ``<tarfile>`` is the name
+# of the tarfile that is created and it will be placed in ``<binary_dir>``.
+# ``<source_dir>`` is the source directory for the build and ``<binary_dir>``
+# is the binary directory for the build. The ``<gcov_command>`` is a full
+# path to ``gcov`` for the machine.
+
+#=============================================================================
+# Copyright 2014-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.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+include(CMakeParseArguments)
+function(ctest_coverage_collect_gcov)
+ set(options "")
+ set(oneValueArgs TARBALL SOURCE BUILD GCOV_COMMAND)
+ set(multiValueArgs "")
+ cmake_parse_arguments(GCOV "${options}" "${oneValueArgs}"
+ "${multiValueArgs}" "" ${ARGN} )
+ if(NOT DEFINED GCOV_TARBALL)
+ message(FATAL_ERROR
+ "TARBALL must be specified. for ctest_coverage_collect_gcov")
+ endif()
+ if(NOT DEFINED GCOV_SOURCE)
+ set(source_dir "${CTEST_SOURCE_DIRECTORY}")
+ else()
+ set(source_dir "${GCOV_SOURCE}")
+ endif()
+ if(NOT DEFINED GCOV_BUILD)
+ set(binary_dir "${CTEST_BINARY_DIRECTORY}")
+ else()
+ set(binary_dir "${GCOV_BUILD}")
+ endif()
+ if(NOT DEFINED GCOV_GCOV_COMMAND)
+ set(gcov_command "${CTEST_COVERAGE_COMMAND}")
+ else()
+ set(gcov_command "${GCOV_GCOV_COMMAND}")
+ endif()
+ # run gcov on each gcda file in the binary tree
+ set(gcda_files)
+ set(label_files)
+ # look for gcda files in the target directories
+ # could do a glob from the top of the binary tree but
+ # this will be faster and only look where the files will be
+ file(STRINGS "${binary_dir}/CMakeFiles/TargetDirectories.txt" target_dirs)
+ foreach(target_dir ${target_dirs})
+ file(GLOB_RECURSE gfiles RELATIVE ${binary_dir} "${target_dir}/*.gcda")
+ list(LENGTH gfiles len)
+ # if we have gcda files then also grab the labels file for that target
+ if(${len} GREATER 0)
+ file(GLOB_RECURSE lfiles RELATIVE ${binary_dir}
+ "${target_dir}/Labels.txt")
+ list(APPEND gcda_files ${gfiles})
+ list(APPEND label_files ${lfiles})
+ endif()
+ endforeach()
+ # return early if no coverage files were found
+ list(LENGTH gcda_files len)
+ if(len EQUAL 0)
+ message("ctest_coverage_collect_gcov: No .gcda files found, "
+ "ignoring coverage request.")
+ return()
+ endif()
+ # setup the dir for the coverage files
+ set(coverage_dir "${binary_dir}/Testing/CoverageInfo")
+ file(MAKE_DIRECTORY "${coverage_dir}")
+ # call gcov on each .gcda file
+ foreach (gcda_file ${gcda_files})
+ # get the directory of the gcda file
+ get_filename_component(gcda_file ${binary_dir}/${gcda_file} ABSOLUTE)
+ get_filename_component(gcov_dir ${gcda_file} DIRECTORY)
+ # run gcov, this will produce the .gcov file in the current
+ # working directory
+ execute_process(COMMAND
+ ${gcov_command} -b -o ${gcov_dir} ${gcda_file}
+ OUTPUT_VARIABLE out
+ WORKING_DIRECTORY ${coverage_dir})
+ endforeach()
+ # create json file with project information
+ file(WRITE ${coverage_dir}/data.json
+ "{
+ \"Source\": \"${source_dir}\",
+ \"Binary\": \"${binary_dir}\"
+}")
+ # collect the gcov files
+ set(gcov_files)
+ file(GLOB_RECURSE gcov_files RELATIVE ${binary_dir} "${binary_dir}/*.gcov")
+ # tar up the coverage info with the same date so that the md5
+ # sum will be the same for the tar file independent of file time
+ # stamps
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E tar cvfj ${GCOV_TARBALL}
+ --mtime=1970-01-01\ 0:0:0\ UTC ${gcov_files}
+ ${coverage_dir}/data.json ${label_files}
+ WORKING_DIRECTORY ${binary_dir})
+endfunction()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 96f4709..78bef91 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -533,6 +533,7 @@ set(CTEST_SRCS cmCTest.cxx
CTest/cmCTestConfigureHandler.cxx
CTest/cmCTestCoverageCommand.cxx
CTest/cmCTestCoverageHandler.cxx
+ CTest/cmCTestCurl.cxx
CTest/cmParseMumpsCoverage.cxx
CTest/cmParseCacheCoverage.cxx
CTest/cmParseGTMCoverage.cxx
@@ -583,7 +584,7 @@ set(CTEST_SRCS cmCTest.cxx
# Build CTestLib
add_library(CTestLib ${CTEST_SRCS})
-target_link_libraries(CTestLib CMakeLib ${CMAKE_CURL_LIBRARIES} ${CMAKE_XMLRPC_LIBRARIES})
+target_link_libraries(CTestLib CMakeLib ${CMAKE_CURL_LIBRARIES} ${CMAKE_XMLRPC_LIBRARIES} cmjsoncpp)
#
# Sources for CPack
diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx
new file mode 100644
index 0000000..b354592
--- /dev/null
+++ b/Source/CTest/cmCTestCurl.cxx
@@ -0,0 +1,258 @@
+#include "cmCTestCurl.h"
+#include "cmSystemTools.h"
+#include "cmCTest.h"
+
+cmCTestCurl::cmCTestCurl(cmCTest* ctest)
+{
+ this->CTest = ctest;
+ this->SetProxyType();
+ this->UseHttp10 = false;
+ // In windows, this will init the winsock stuff
+ ::curl_global_init(CURL_GLOBAL_ALL);
+ // default is to verify https
+ this->VerifyPeerOff = false;
+ this->VerifyHostOff = false;
+ this->TimeOutSeconds = 0;
+}
+
+namespace
+{
+static size_t
+curlWriteMemoryCallback(void *ptr, size_t size, size_t nmemb,
+ void *data)
+{
+ int realsize = (int)(size * nmemb);
+
+ std::vector<char> *vec
+ = static_cast<std::vector<char>* >(data);
+ const char* chPtr = static_cast<char*>(ptr);
+ vec->insert(vec->end(), chPtr, chPtr + realsize);
+ return realsize;
+}
+
+static size_t
+curlDebugCallback(CURL *, curl_infotype, char *chPtr,
+ size_t size, void *data)
+{
+ std::vector<char> *vec
+ = static_cast<std::vector<char>* >(data);
+ vec->insert(vec->end(), chPtr, chPtr + size);
+
+ return size;
+}
+
+}
+void cmCTestCurl::SetCurlOptions(std::vector<std::string> const& args)
+{
+ for( std::vector<std::string>::const_iterator i = args.begin();
+ i != args.end(); ++i)
+ {
+ if(*i == "CURLOPT_SSL_VERIFYPEER_OFF")
+ {
+ this->VerifyPeerOff = true;
+ }
+ if(*i == "CURLOPT_SSL_VERIFYHOST_OFF")
+ {
+ this->VerifyHostOff = true;
+ }
+ }
+}
+
+bool cmCTestCurl::InitCurl()
+{
+ this->Curl = curl_easy_init();
+ if(!this->Curl)
+ {
+ return false;
+ }
+ if(this->VerifyPeerOff)
+ {
+ curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYPEER, 0);
+ }
+ if(this->VerifyHostOff)
+ {
+ curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYHOST, 0);
+ }
+ if(this->HTTPProxy.size())
+ {
+ curl_easy_setopt(this->Curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
+ curl_easy_setopt(this->Curl, CURLOPT_PROXYTYPE, this->HTTPProxyType);
+ if (this->HTTPProxyAuth.size() > 0)
+ {
+ curl_easy_setopt(this->Curl, CURLOPT_PROXYUSERPWD,
+ this->HTTPProxyAuth.c_str());
+ }
+ }
+ if(this->UseHttp10)
+ {
+ curl_easy_setopt(this->Curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ }
+ // enable HTTP ERROR parsing
+ curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+ return true;
+}
+
+
+bool cmCTestCurl::UploadFile(std::string const& local_file,
+ std::string const& url,
+ std::string const& fields,
+ std::string& response)
+{
+ response = "";
+ if(!this->InitCurl())
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
+ return false;
+ }
+ /* enable uploading */
+ curl_easy_setopt(this->Curl, CURLOPT_UPLOAD, 1);
+ // if there is little to no activity for too long stop submitting
+ if(this->TimeOutSeconds)
+ {
+ ::curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_LIMIT, 1);
+ ::curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_TIME,
+ this->TimeOutSeconds);
+ }
+ /* HTTP PUT please */
+ ::curl_easy_setopt(this->Curl, CURLOPT_PUT, 1);
+ ::curl_easy_setopt(this->Curl, CURLOPT_VERBOSE, 1);
+
+ FILE* ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
+ if(!ftpfile)
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Could not open file for upload: " << local_file << "\n");
+ return false;
+ }
+ // set the url
+ std::string upload_url = url;
+ upload_url += "?";
+ upload_url += fields;
+ ::curl_easy_setopt(this->Curl, CURLOPT_URL, upload_url.c_str());
+ // now specify which file to upload
+ ::curl_easy_setopt(this->Curl, CURLOPT_INFILE, ftpfile);
+ unsigned long filelen = cmSystemTools::FileLength(local_file);
+ // and give the size of the upload (optional)
+ ::curl_easy_setopt(this->Curl, CURLOPT_INFILESIZE,
+ static_cast<long>(filelen));
+ ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
+ curlWriteMemoryCallback);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION,
+ curlDebugCallback);
+ std::vector<char> responseData;
+ std::vector<char> debugData;
+ ::curl_easy_setopt(this->Curl, CURLOPT_FILE, (void *)&responseData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, (void *)&debugData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+ // Now run off and do what you've been told!
+ ::curl_easy_perform(this->Curl);
+ ::fclose(ftpfile);
+ ::curl_global_cleanup();
+
+ if ( responseData.size() > 0 )
+ {
+ response = std::string(responseData.begin(), responseData.end());
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Curl response: [" << response << "]\n");
+ }
+ std::string curlDebug;
+ if ( debugData.size() > 0 )
+ {
+ curlDebug = std::string(debugData.begin(), debugData.end());
+ cmCTestLog(this->CTest, DEBUG, "Curl debug: [" << curlDebug << "]\n");
+ }
+ if(response.size() == 0)
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "No response from server.\n" <<
+ curlDebug);
+ return false;
+ }
+ return true;
+}
+
+bool cmCTestCurl::HttpRequest(std::string const& url,
+ std::string const& fields,
+ std::string& response)
+{
+ response = "";
+ cmCTestLog(this->CTest, DEBUG, "HttpRequest\n"
+ << "url: " << url << "\n"
+ << "fields " << fields << "\n");
+ if(!this->InitCurl())
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
+ return false;
+ }
+ curl_easy_setopt(this->Curl, CURLOPT_POST, 1);
+ curl_easy_setopt(this->Curl, CURLOPT_POSTFIELDS, fields.c_str());
+ ::curl_easy_setopt(this->Curl, CURLOPT_URL, url.c_str());
+ ::curl_easy_setopt(this->Curl, CURLOPT_FOLLOWLOCATION, 1);
+ //set response options
+ ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
+ curlWriteMemoryCallback);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION,
+ curlDebugCallback);
+ std::vector<char> responseData;
+ std::vector<char> debugData;
+ ::curl_easy_setopt(this->Curl, CURLOPT_FILE, (void *)&responseData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, (void *)&debugData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+
+ CURLcode res = ::curl_easy_perform(this->Curl);
+
+ ::curl_easy_cleanup(this->Curl);
+ ::curl_global_cleanup();
+ if ( responseData.size() > 0 )
+ {
+ response = std::string(responseData.begin(), responseData.end());
+ cmCTestLog(this->CTest, DEBUG, "Curl response: [" << response << "]\n");
+ }
+ if ( debugData.size() > 0 )
+ {
+ std::string curlDebug = std::string(debugData.begin(), debugData.end());
+ cmCTestLog(this->CTest, DEBUG, "Curl debug: [" << curlDebug << "]\n");
+ }
+ cmCTestLog(this->CTest, DEBUG, "Curl res: " << res << "\n");
+ return (res == 0);
+}
+
+void cmCTestCurl::SetProxyType()
+{
+ if ( cmSystemTools::GetEnv("HTTP_PROXY") )
+ {
+ this->HTTPProxy = cmSystemTools::GetEnv("HTTP_PROXY");
+ if ( cmSystemTools::GetEnv("HTTP_PROXY_PORT") )
+ {
+ this->HTTPProxy += ":";
+ this->HTTPProxy += cmSystemTools::GetEnv("HTTP_PROXY_PORT");
+ }
+ if ( cmSystemTools::GetEnv("HTTP_PROXY_TYPE") )
+ {
+ // this is the default
+ this->HTTPProxyType = CURLPROXY_HTTP;
+ std::string type = cmSystemTools::GetEnv("HTTP_PROXY_TYPE");
+ // HTTP/SOCKS4/SOCKS5
+ if ( type == "HTTP" )
+ {
+ this->HTTPProxyType = CURLPROXY_HTTP;
+ }
+ else if ( type == "SOCKS4" )
+ {
+ this->HTTPProxyType = CURLPROXY_SOCKS4;
+ }
+ else if ( type == "SOCKS5" )
+ {
+ this->HTTPProxyType = CURLPROXY_SOCKS5;
+ }
+ }
+ if ( cmSystemTools::GetEnv("HTTP_PROXY_USER") )
+ {
+ this->HTTPProxyAuth = cmSystemTools::GetEnv("HTTP_PROXY_USER");
+ }
+ if ( cmSystemTools::GetEnv("HTTP_PROXY_PASSWD") )
+ {
+ this->HTTPProxyAuth += ":";
+ this->HTTPProxyAuth += cmSystemTools::GetEnv("HTTP_PROXY_PASSWD");
+ }
+ }
+}
diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h
new file mode 100644
index 0000000..bb5c74a
--- /dev/null
+++ b/Source/CTest/cmCTestCurl.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 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 cmCTestCurl_h
+#define cmCTestCurl_h
+#include "cm_curl.h"
+#include "cmStandardIncludes.h"
+class cmCTest;
+
+class cmCTestCurl
+{
+public:
+ cmCTestCurl(cmCTest*);
+ bool UploadFile(std::string const& url,
+ std::string const& file,
+ std::string const& fields,
+ std::string& response);
+ bool HttpRequest(std::string const& url,
+ std::string const& fields,
+ std::string& response);
+ // currently only supports CURLOPT_SSL_VERIFYPEER_OFF
+ // and CURLOPT_SSL_VERIFYHOST_OFF
+ void SetCurlOptions(std::vector<std::string> const& args);
+ void SetUseHttp10On() { this->UseHttp10 = true;}
+ void SetTimeOutSeconds(int s) { this->TimeOutSeconds = s;}
+protected:
+ void SetProxyType();
+ bool InitCurl();
+private:
+ cmCTest* CTest;
+ CURL* Curl;
+ std::string HTTPProxyAuth;
+ std::string HTTPProxy;
+ curl_proxytype HTTPProxyType;
+ bool VerifyHostOff;
+ bool VerifyPeerOff;
+ bool UseHttp10;
+ int TimeOutSeconds;
+};
+
+
+#endif
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
index 4005a63..dcd7982 100644
--- a/Source/CTest/cmCTestSubmitCommand.cxx
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -27,7 +27,8 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
= this->Makefile->GetDefinition("CTEST_TRIGGER_SITE");
bool ctestDropSiteCDash
= this->Makefile->IsOn("CTEST_DROP_SITE_CDASH");
-
+ const char* ctestProjectName
+ = this->Makefile->GetDefinition("CTEST_PROJECT_NAME");
if ( !ctestDropMethod )
{
ctestDropMethod = "http";
@@ -43,7 +44,7 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
// error: CDash requires CTEST_DROP_LOCATION definition
// in CTestConfig.cmake
}
-
+ this->CTest->SetCTestConfiguration("ProjectName", ctestProjectName);
this->CTest->SetCTestConfiguration("DropMethod", ctestDropMethod);
this->CTest->SetCTestConfiguration("DropSite", ctestDropSite);
this->CTest->SetCTestConfiguration("DropLocation", ctestDropLocation);
@@ -144,6 +145,13 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
static_cast<cmCTestSubmitHandler*>(handler)->SetOption("InternalTest",
this->InternalTest ? "ON" : "OFF");
+ if(this->CDashUploadFile.size())
+ {
+ static_cast<cmCTestSubmitHandler*>(handler)->
+ SetOption("CDashUploadFile", this->CDashUploadFile.c_str());
+ static_cast<cmCTestSubmitHandler*>(handler)->
+ SetOption("CDashUploadType", this->CDashUploadType.c_str());
+ }
return handler;
}
@@ -178,6 +186,16 @@ bool cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg)
return true;
}
+ if(arg == "CDASH_UPLOAD")
+ {
+ this->ArgumentDoing = ArgumentDoingCDashUpload;
+ return true;
+ }
+ if(arg == "CDASH_UPLOAD_TYPE")
+ {
+ this->ArgumentDoing = ArgumentDoingCDashUploadType;
+ return true;
+ }
if(arg == "INTERNAL_TEST_CHECKSUM")
{
this->InternalTest = true;
@@ -240,6 +258,17 @@ bool cmCTestSubmitCommand::CheckArgumentValue(std::string const& arg)
return true;
}
+ if(this->ArgumentDoing == ArgumentDoingCDashUpload)
+ {
+ this->CDashUploadFile = arg;
+ return true;
+ }
+ if(this->ArgumentDoing == ArgumentDoingCDashUploadType)
+ {
+ this->CDashUploadType = arg;
+ return true;
+ }
+
// Look for other arguments.
return this->Superclass::CheckArgumentValue(arg);
}
diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h
index 3673fbd..cb0ac61 100644
--- a/Source/CTest/cmCTestSubmitCommand.h
+++ b/Source/CTest/cmCTestSubmitCommand.h
@@ -64,6 +64,8 @@ protected:
ArgumentDoingFiles,
ArgumentDoingRetryDelay,
ArgumentDoingRetryCount,
+ ArgumentDoingCDashUpload,
+ ArgumentDoingCDashUploadType,
ArgumentDoingLast2
};
@@ -74,6 +76,8 @@ protected:
cmCTest::SetOfStrings Files;
std::string RetryCount;
std::string RetryDelay;
+ std::string CDashUploadFile;
+ std::string CDashUploadType;
};
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index bc6fb31..0e19259 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -10,7 +10,8 @@
See the License for more information.
============================================================================*/
#include "cmCTestSubmitHandler.h"
-
+#include "cmCTestScriptHandler.h"
+#include "cmake.h"
#include "cmSystemTools.h"
#include "cmVersion.h"
#include "cmGeneratedFileStream.h"
@@ -23,8 +24,10 @@
// For XML-RPC submission
#include "cm_xmlrpc.h"
+#include <cm_jsoncpp_reader.h>
// For curl submission
#include "cm_curl.h"
+#include "cmCTestCurl.h"
#include <sys/stat.h>
@@ -1055,9 +1058,165 @@ bool cmCTestSubmitHandler::SubmitUsingXMLRPC(std::string const&,
}
#endif
+void cmCTestSubmitHandler::ConstructCDashURL(std::string& dropMethod,
+ std::string& url)
+{
+ dropMethod = this->CTest->GetCTestConfiguration("DropMethod");
+ url = dropMethod;
+ url += "://";
+ if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
+ {
+ url += this->CTest->GetCTestConfiguration("DropSiteUser");
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetCTestConfiguration("DropSiteUser").c_str());
+ if ( this->CTest->GetCTestConfiguration("DropSitePassword").size() > 0 )
+ {
+ url += ":" + this->CTest->GetCTestConfiguration("DropSitePassword");
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, ":******");
+ }
+ url += "@";
+ }
+ url += this->CTest->GetCTestConfiguration("DropSite") +
+ this->CTest->GetCTestConfiguration("DropLocation");
+}
+
+
+int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file,
+ std::string const& typeString)
+{
+ if(!cmSystemTools::FileExists(file))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Upload file not found: " << file << "\n");
+ return -1;
+ }
+ cmCTestCurl curl(this->CTest);
+ std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
+ std::vector<std::string> args;
+ cmSystemTools::ExpandListArgument(curlopt, args);
+ curl.SetCurlOptions(args);
+ curl.SetTimeOutSeconds(SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
+ std::string dropMethod;
+ std::string url;
+ this->ConstructCDashURL(dropMethod, url);
+ std::string::size_type pos = url.find("submit.php?");
+ url = url.substr(0, pos+10);
+ if ( ! (dropMethod == "http" || dropMethod == "https" ) )
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Only http and https are supported for CDASH_UPLOAD\n");
+ return -1;
+ }
+ char md5sum[33];
+ md5sum[32] = 0;
+ cmSystemTools::ComputeFileMD5(file, md5sum);
+ // 1. request the buildid and check to see if the file
+ // has already been uploaded
+ // TODO I added support for subproject. You would need to add
+ // a "&subproject=subprojectname" to the first POST.
+ cmCTestScriptHandler* ch =
+ static_cast<cmCTestScriptHandler*>(this->CTest->GetHandler("script"));
+ cmake* cm = ch->GetCMake();
+ const char* subproject = cm->GetProperty("SubProject", cmProperty::GLOBAL);
+ std::ostringstream str;
+ str << "project="
+ << this->CTest->GetCTestConfiguration("ProjectName") << "&";
+ if(subproject)
+ {
+ str << "subproject=" << subproject << "&";
+ }
+ str << "stamp=" << this->CTest->GetCurrentTag() << "-"
+ << this->CTest->GetTestModelString() << "&"
+ << "model=" << this->CTest->GetTestModelString() << "&"
+ << "build=" << this->CTest->GetCTestConfiguration("BuildName") << "&"
+ << "site=" << this->CTest->GetCTestConfiguration("Site") << "&"
+ << "track=" << this->CTest->GetTestModelString() << "&"
+ << "starttime=" << (int)cmSystemTools::GetTime() << "&"
+ << "endtime=" << (int)cmSystemTools::GetTime() << "&"
+ << "datafilesmd5[0]=" << md5sum << "&"
+ << "type=" << typeString;
+ std::string fields = str.str();
+ cmCTestLog(this->CTest, DEBUG, "fields: " << fields << "\nurl:"
+ << url << "\nfile: " << file << "\n");
+ std::string response;
+ if(!curl.HttpRequest(url, fields, response))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error in HttpRequest\n" << response);
+ return -1;
+ }
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Request upload response: [" << response << "]\n");
+ Json::Value json;
+ Json::Reader reader;
+ if(!reader.parse(response, json))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "error parsing json string [" << response << "]\n"
+ << reader.getFormattedErrorMessages() << "\n");
+ return -1;
+ }
+ if(json["status"].asInt() != 0)
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Bad status returned from CDash: "
+ << json["status"].asInt());
+ return -1;
+ }
+ if(json["datafilesmd5"].isArray())
+ {
+ int datares = json["datafilesmd5"][0].asInt();
+ if(datares == 1)
+ {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "File already exists on CDash, skip upload "
+ << file << "\n");
+ return 0;
+ }
+ }
+ else
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "bad datafilesmd5 value in response "
+ << response << "\n");
+ return -1;
+ }
+
+ std::string upload_as = cmSystemTools::GetFilenameName(file);
+ std::ostringstream fstr;
+ fstr << "type=" << typeString << "&"
+ << "md5=" << md5sum << "&"
+ << "filename=" << upload_as << "&"
+ << "buildid=" << json["buildid"].asString();
+ if(!curl.UploadFile(file, url, fstr.str(), response))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "error uploading to CDash. "
+ << file << " " << url << " " << fstr.str());
+ return -1;
+ }
+ if(!reader.parse(response, json))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "error parsing json string [" << response << "]\n"
+ << reader.getFormattedErrorMessages() << "\n");
+ return -1;
+ }
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Upload file response: [" << response << "]\n");
+ return 0;
+}
+
//----------------------------------------------------------------------------
int cmCTestSubmitHandler::ProcessHandler()
{
+ const char* cdashUploadFile = this->GetOption("CDashUploadFile");
+ const char* cdashUploadType = this->GetOption("CDashUploadType");
+ if(cdashUploadFile && cdashUploadType)
+ {
+ return this->HandleCDashUploadFile(std::string(cdashUploadFile),
+ std::string(cdashUploadType));
+ }
std::string iscdash = this->CTest->GetCTestConfiguration("IsCDash");
// cdash does not need to trigger so just return true
if(!iscdash.empty())
diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h
index accabd1..f9cd894 100644
--- a/Source/CTest/cmCTestSubmitHandler.h
+++ b/Source/CTest/cmCTestSubmitHandler.h
@@ -41,6 +41,11 @@ public:
/** Specify a set of files to submit. */
void SelectFiles(cmCTest::SetOfStrings const& files);
+ // handle the cdash file upload protocol
+ int HandleCDashUploadFile(std::string const& file, std::string const& type);
+
+ void ConstructCDashURL(std::string& dropMethod, std::string& url);
+
private:
void SetLogFile(std::ostream* ost) { this->LogFile = ost; }
diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx
index a2aecac..fc4c40d 100644
--- a/Source/cmArchiveWrite.cxx
+++ b/Source/cmArchiveWrite.cxx
@@ -247,6 +247,11 @@ bool cmArchiveWrite::AddPath(const char* path,
return true;
}
+// function from libarchive
+extern "C"
+{
+ time_t __archive_get_date(time_t, const char*);
+}
//----------------------------------------------------------------------------
bool cmArchiveWrite::AddFile(const char* file,
size_t skip, const char* prefix)
@@ -275,6 +280,17 @@ bool cmArchiveWrite::AddFile(const char* file,
this->Error += cm_archive_error_string(this->Disk);
return false;
}
+ if(this->MTime.size())
+ {
+ time_t t = __archive_get_date(0, this->MTime.c_str());
+ if (t == -1)
+ {
+ this->Error = "__archive_get_date: Unable to parse mtime: ";
+ this->Error += "[" + this->MTime + "]";
+ 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 a6dcc0e..987e95c 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(const char* t) { if(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 7d938c5..d8a5631 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<std::string>& files,
cmTarCompression compressType,
- bool verbose)
+ bool verbose, const char* mtime)
{
#if defined(CMAKE_BUILD_WITH_CMAKE)
std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
@@ -1501,6 +1501,10 @@ bool cmSystemTools::CreateTar(const char* outFileName,
}
cmArchiveWrite a(fout, compress,
cmArchiveWrite::TypeTAR);
+ if(mtime)
+ {
+ a.SetMTime(mtime);
+ }
a.SetVerbose(verbose);
for(std::vector<std::string>::const_iterator i = files.begin();
i != files.end(); ++i)
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 09ceea6..1c7208f 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<std::string>& files,
- cmTarCompression compressType, bool verbose);
- static bool ExtractTar(const char* inFileName,
- bool verbose);
+ cmTarCompression compressType, bool verbose,
+ const char* mtime=0);
+ 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/cmcmd.cxx b/Source/cmcmd.cxx
index ecf4650..f6c13bb 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -729,9 +729,21 @@ 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;
for (std::string::size_type cc = 4; cc < args.size(); cc ++)
{
- files.push_back(args[cc]);
+ // if the first 8 chars of an arg are --mtime= and that arg
+ // is not a file on disk, treat it is the --mtime= flag and
+ // not a file
+ if( (args[cc].substr(0, 8) == "--mtime=") &&
+ !cmSystemTools::FileExists(args[cc]))
+ {
+ mtime = args[cc].substr(8);
+ }
+ else
+ {
+ files.push_back(args[cc]);
+ }
}
cmSystemTools::cmTarCompression compress =
cmSystemTools::TarCompressNone;
@@ -773,8 +785,13 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
}
else if ( flags.find_first_of('c') != flags.npos )
{
+ const char* mtimestr = 0;
+ if(mtime.size())
+ {
+ mtimestr = mtime.c_str();
+ }
if ( !cmSystemTools::CreateTar(
- outFile.c_str(), files, compress, verbose) )
+ outFile.c_str(), files, compress, verbose, mtimestr) )
{
cmSystemTools::Error("Problem creating tar: ", outFile.c_str());
return 1;
-----------------------------------------------------------------------
Summary of changes:
hooks/post-receive
--
CMake
More information about the Cmake-commits
mailing list