Merge topic 'cdash_upload_file_mode'

f3e0b6f1 CTestCoverageCollectGCOV: Add module to run gcov
6dd980e0 ctest_submit: Make CDASH_UPLOAD mode arguments more strict
5dc33f89 ctest_submit: Add CDASH_UPLOAD mode to upload files to CDash
This commit is contained in:
Brad King 2015-01-22 11:16:45 -05:00 committed by CMake Topic Stage
commit c0298947ff
28 changed files with 765 additions and 28 deletions

View File

@ -37,3 +37,16 @@ timed-out submission before attempting to re-submit.
The RETRY_COUNT option specifies how many times to retry a timed-out
submission.
Submit to CDash Upload API
^^^^^^^^^^^^^^^^^^^^^^^^^^
::
ctest_submit(CDASH_UPLOAD <file> [CDASH_UPLOAD_TYPE <type>])
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 a content hash 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.

View File

@ -63,6 +63,7 @@ All Modules
/module/CPack
/module/CPackWIX
/module/CTest
/module/CTestCoverageCollectGCOV
/module/CTestScriptMode
/module/CTestUseLaunchers
/module/Dart

View File

@ -0,0 +1 @@
.. cmake-module:: ../../Modules/CTestCoverageCollectGCOV.cmake

View File

@ -0,0 +1,138 @@
#.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 that
# contains the source and build directories for CDash to use in parsing
# the coverage data. In addtion the Labels.json files for targets that
# have coverage information are also put in the tar file for CDash to
# asign the correct labels. 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>
# [SOURCE <source_dir>][BUILD <build_dir>]
# [GCOV_COMMAND <gcov_command>]
# )
#
# Run gcov and package a tar file for CDash. The options are:
#
# ``TARBALL <tarfile>``
# Specify the location of the ``.tar`` file to be created for later
# upload to CDash. Relative paths will be interpreted with respect
# to the top-level build directory.
#
# ``SOURCE <source_dir>``
# Specify the top-level source directory for the build.
# Default is the value of :variable:`CTEST_SOURCE_DIRECTORY`.
#
# ``BUILD <build_dir>``
# Specify the top-level build directory for the build.
# Default is the value of :variable:`CTEST_BINARY_DIRECTORY`.
#
# ``GCOV_COMMAND <gcov_command>``
# Specify the full path to the ``gcov`` command on the machine.
# Default is the value of :variable:`CTEST_COVERAGE_COMMAND`.
#=============================================================================
# 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.json")
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} "${coverage_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()

View File

@ -537,6 +537,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

View File

@ -0,0 +1,271 @@
/*============================================================================
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 "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");
}
}
}

View File

@ -0,0 +1,52 @@
/*============================================================================
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 cmCTestCurl_h
#define cmCTestCurl_h
#include "cmStandardIncludes.h"
#include "cm_curl.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

View File

@ -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,44 +145,75 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
static_cast<cmCTestSubmitHandler*>(handler)->SetOption("InternalTest",
this->InternalTest ? "ON" : "OFF");
if (this->CDashUpload)
{
static_cast<cmCTestSubmitHandler*>(handler)->
SetOption("CDashUploadFile", this->CDashUploadFile.c_str());
static_cast<cmCTestSubmitHandler*>(handler)->
SetOption("CDashUploadType", this->CDashUploadType.c_str());
}
return handler;
}
//----------------------------------------------------------------------------
bool cmCTestSubmitCommand::InitialPass(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
this->CDashUpload = !args.empty() && args[0] == "CDASH_UPLOAD";
return this->cmCTestHandlerCommand::InitialPass(args, status);
}
//----------------------------------------------------------------------------
bool cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg)
{
// Look for arguments specific to this command.
if(arg == "PARTS")
if (this->CDashUpload)
{
this->ArgumentDoing = ArgumentDoingParts;
this->PartsMentioned = true;
return true;
}
if(arg == "CDASH_UPLOAD")
{
this->ArgumentDoing = ArgumentDoingCDashUpload;
return true;
}
if(arg == "FILES")
{
this->ArgumentDoing = ArgumentDoingFiles;
this->FilesMentioned = true;
return true;
if(arg == "CDASH_UPLOAD_TYPE")
{
this->ArgumentDoing = ArgumentDoingCDashUploadType;
return true;
}
}
if(arg == "RETRY_COUNT")
else
{
this->ArgumentDoing = ArgumentDoingRetryCount;
return true;
}
// Look for arguments specific to this command.
if(arg == "PARTS")
{
this->ArgumentDoing = ArgumentDoingParts;
this->PartsMentioned = true;
return true;
}
if(arg == "RETRY_DELAY")
{
this->ArgumentDoing = ArgumentDoingRetryDelay;
return true;
}
if(arg == "FILES")
{
this->ArgumentDoing = ArgumentDoingFiles;
this->FilesMentioned = true;
return true;
}
if(arg == "INTERNAL_TEST_CHECKSUM")
{
this->InternalTest = true;
return true;
if(arg == "RETRY_COUNT")
{
this->ArgumentDoing = ArgumentDoingRetryCount;
return true;
}
if(arg == "RETRY_DELAY")
{
this->ArgumentDoing = ArgumentDoingRetryDelay;
return true;
}
if(arg == "INTERNAL_TEST_CHECKSUM")
{
this->InternalTest = true;
return true;
}
}
// Look for other arguments.
@ -240,6 +272,20 @@ bool cmCTestSubmitCommand::CheckArgumentValue(std::string const& arg)
return true;
}
if(this->ArgumentDoing == ArgumentDoingCDashUpload)
{
this->ArgumentDoing = ArgumentDoingNone;
this->CDashUploadFile = arg;
return true;
}
if(this->ArgumentDoing == ArgumentDoingCDashUploadType)
{
this->ArgumentDoing = ArgumentDoingNone;
this->CDashUploadType = arg;
return true;
}
// Look for other arguments.
return this->Superclass::CheckArgumentValue(arg);
}

View File

@ -32,6 +32,7 @@ public:
this->InternalTest = false;
this->RetryCount = "";
this->RetryDelay = "";
this->CDashUpload = false;
}
/**
@ -45,6 +46,9 @@ public:
return ni;
}
virtual bool InitialPass(std::vector<std::string> const& args,
cmExecutionStatus &status);
/**
* The name of the command as specified in CMakeList.txt.
*/
@ -64,6 +68,8 @@ protected:
ArgumentDoingFiles,
ArgumentDoingRetryDelay,
ArgumentDoingRetryCount,
ArgumentDoingCDashUpload,
ArgumentDoingCDashUploadType,
ArgumentDoingLast2
};
@ -74,6 +80,9 @@ protected:
cmCTest::SetOfStrings Files;
std::string RetryCount;
std::string RetryDelay;
bool CDashUpload;
std::string CDashUploadFile;
std::string CDashUploadType;
};

View File

@ -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,171 @@ 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 (file.empty())
{
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Upload file not specified\n");
return -1;
}
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);
// TODO: Encode values for a URL instead of trusting caller.
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(cdashUploadFile, cdashUploadType);
}
std::string iscdash = this->CTest->GetCTestConfiguration("IsCDash");
// cdash does not need to trigger so just return true
if(!iscdash.empty())

View File

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

View File

@ -0,0 +1 @@
(-1|255)

View File

@ -0,0 +1,2 @@
CMake Error at .*/Tests/RunCMake/CTestSubmit/CDashUploadFILES/test.cmake:[0-9]+ \(ctest_submit\):
ctest_submit called with unknown argument "FILES".

View File

@ -0,0 +1 @@
(-1|255)

View File

@ -0,0 +1 @@
Only http and https are supported for CDASH_UPLOAD

View File

@ -0,0 +1 @@
(-1|255)

View File

@ -0,0 +1 @@
Upload file not specified

View File

@ -0,0 +1 @@
(-1|255)

View File

@ -0,0 +1,2 @@
CMake Error at .*/Tests/RunCMake/CTestSubmit/CDashUploadPARTS/test.cmake:[0-9]+ \(ctest_submit\):
ctest_submit called with unknown argument "PARTS".

View File

@ -0,0 +1 @@
(-1|255)

View File

@ -0,0 +1,2 @@
CMake Error at .*/Tests/RunCMake/CTestSubmit/CDashUploadRETRY_COUNT/test.cmake:[0-9]+ \(ctest_submit\):
ctest_submit called with unknown argument "RETRY_COUNT".

View File

@ -0,0 +1 @@
(-1|255)

View File

@ -0,0 +1,2 @@
CMake Error at .*/Tests/RunCMake/CTestSubmit/CDashUploadRETRY_DELAY/test.cmake:[0-9]+ \(ctest_submit\):
ctest_submit called with unknown argument "RETRY_DELAY".

View File

@ -0,0 +1 @@
(-1|255)

View File

@ -0,0 +1,2 @@
CMake Error at .*/Tests/RunCMake/CTestSubmit/PARTSCDashUpload/test.cmake:[0-9]+ \(ctest_submit\):
Part name "CDASH_UPLOAD" is invalid.

View File

@ -0,0 +1 @@
(-1|255)

View File

@ -0,0 +1,2 @@
CMake Error at .*/Tests/RunCMake/CTestSubmit/PARTSCDashUploadType/test.cmake:[0-9]+ \(ctest_submit\):
Part name "CDASH_UPLOAD_TYPE" is invalid.

View File

@ -33,6 +33,19 @@ run_ctest_submit(BadArg bad-arg)
run_ctest_submit(BadPARTS PARTS bad-part)
run_ctest_submit(BadFILES FILES bad-file)
run_ctest_submit(RepeatRETURN_VALUE RETURN_VALUE res RETURN_VALUE res)
run_ctest_submit(PARTSCDashUpload PARTS Configure CDASH_UPLOAD)
run_ctest_submit(PARTSCDashUploadType PARTS Configure CDASH_UPLOAD_TYPE)
run_ctest_submit(CDashUploadPARTS CDASH_UPLOAD bad-upload PARTS)
run_ctest_submit(CDashUploadFILES CDASH_UPLOAD bad-upload FILES)
run_ctest_submit(CDashUploadRETRY_COUNT CDASH_UPLOAD bad-upload RETRY_COUNT)
run_ctest_submit(CDashUploadRETRY_DELAY CDASH_UPLOAD bad-upload RETRY_DELAY)
run_ctest_submit(CDashUploadNone CDASH_UPLOAD)
function(run_ctest_CDashUploadFTP)
set(CASE_DROP_METHOD ftp)
run_ctest_submit(CDashUploadFTP CDASH_UPLOAD ${CMAKE_CURRENT_LIST_FILE})
endfunction()
run_ctest_CDashUploadFTP()
#-----------------------------------------------------------------------------
# Test failed drops by various protocols