CMake/Source/CTest/cmCTestSubmitHandler.cxx

1523 lines
56 KiB
C++
Raw Normal View History

Simplify CMake per-source license notices Per-source copyright/license notice headers that spell out copyright holder names and years are hard to maintain and often out-of-date or plain wrong. Precise contributor information is already maintained automatically by the version control tool. Ultimately it is the receiver of a file who is responsible for determining its licensing status, and per-source notices are merely a convenience. Therefore it is simpler and more accurate for each source to have a generic notice of the license name and references to more detailed information on copyright holders and full license terms. Our `Copyright.txt` file now contains a list of Contributors whose names appeared source-level copyright notices. It also references version control history for more precise information. Therefore we no longer need to spell out the list of Contributors in each source file notice. Replace CMake per-source copyright/license notice headers with a short description of the license and links to `Copyright.txt` and online information available from "https://cmake.org/licensing". The online URL also handles cases of modules being copied out of our source into other projects, so we can drop our notices about replacing links with full license text. Run the `Utilities/Scripts/filter-notices.bash` script to perform the majority of the replacements mechanically. Manually fix up shebang lines and trailing newlines in a few files. Manually update the notices in a few files that the script does not handle.
2016-09-27 22:01:08 +03:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestSubmitHandler.h"
#include "cmCTest.h"
#include "cmCTestCurl.h"
#include "cmCTestScriptHandler.h"
#include "cmCurl.h"
#include "cmGeneratedFileStream.h"
#include "cmState.h"
2003-01-07 07:07:24 +03:00
#include "cmSystemTools.h"
#include "cmXMLParser.h"
#include "cmake.h"
2003-01-07 07:07:24 +03:00
#include <cm_curl.h>
#include <cm_jsoncpp_reader.h>
#include <cm_jsoncpp_value.h>
#include <cmsys/Process.h>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#if defined(CTEST_USE_XMLRPC)
#include "cmVersion.h"
#include <cm_xmlrpc.h>
2003-01-08 06:24:45 +03:00
#include <sys/stat.h>
#endif
2003-01-08 06:24:45 +03:00
#define SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT 120
typedef std::vector<char> cmCTestSubmitHandlerVectorOfChar;
class cmCTestSubmitHandler::ResponseParser : public cmXMLParser
{
public:
ResponseParser() { this->Status = STATUS_OK; }
2016-06-27 22:25:27 +03:00
~ResponseParser() CM_OVERRIDE {}
public:
enum StatusType
{
STATUS_OK,
STATUS_WARNING,
STATUS_ERROR
};
StatusType Status;
std::string CDashVersion;
std::string Filename;
std::string MD5;
std::string Message;
private:
std::vector<char> CurrentValue;
std::string GetCurrentValue()
{
std::string val;
if (!this->CurrentValue.empty()) {
2010-06-03 21:52:48 +04:00
val.assign(&this->CurrentValue[0], this->CurrentValue.size());
}
return val;
}
void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
{
this->CurrentValue.clear();
if (name == "cdash") {
this->CDashVersion = this->FindAttribute(atts, "version");
}
}
void CharacterDataHandler(const char* data, int length) CM_OVERRIDE
{
this->CurrentValue.insert(this->CurrentValue.end(), data, data + length);
}
void EndElement(const std::string& name) CM_OVERRIDE
{
if (name == "status") {
std::string status = cmSystemTools::UpperCase(this->GetCurrentValue());
if (status == "OK" || status == "SUCCESS") {
this->Status = STATUS_OK;
} else if (status == "WARNING") {
this->Status = STATUS_WARNING;
} else {
this->Status = STATUS_ERROR;
}
} else if (name == "filename") {
this->Filename = this->GetCurrentValue();
} else if (name == "md5") {
this->MD5 = this->GetCurrentValue();
} else if (name == "message") {
this->Message = this->GetCurrentValue();
}
}
};
static size_t cmCTestSubmitHandlerWriteMemoryCallback(void* ptr, size_t size,
size_t nmemb, void* data)
{
int realsize = (int)(size * nmemb);
cmCTestSubmitHandlerVectorOfChar* vec =
static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
const char* chPtr = static_cast<char*>(ptr);
vec->insert(vec->end(), chPtr, chPtr + realsize);
return realsize;
}
static size_t cmCTestSubmitHandlerCurlDebugCallback(CURL* /*unused*/,
curl_infotype /*unused*/,
char* chPtr, size_t size,
void* data)
2005-06-02 22:48:10 +04:00
{
cmCTestSubmitHandlerVectorOfChar* vec =
static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
2005-06-02 22:48:10 +04:00
vec->insert(vec->end(), chPtr, chPtr + size);
return size;
}
cmCTestSubmitHandler::cmCTestSubmitHandler()
: HTTPProxy()
, FTPProxy()
{
this->Initialize();
}
void cmCTestSubmitHandler::Initialize()
{
// We submit all available parts by default.
for (cmCTest::Part p = cmCTest::PartStart; p != cmCTest::PartCount;
p = cmCTest::Part(p + 1)) {
this->SubmitPart[p] = true;
}
2008-02-29 22:58:33 +03:00
this->CDash = false;
this->HasWarnings = false;
this->HasErrors = false;
this->Superclass::Initialize();
2006-03-10 23:03:09 +03:00
this->HTTPProxy = "";
this->HTTPProxyType = 0;
this->HTTPProxyAuth = "";
this->FTPProxy = "";
this->FTPProxyType = 0;
2016-06-27 23:44:16 +03:00
this->LogFile = CM_NULLPTR;
this->Files.clear();
}
bool cmCTestSubmitHandler::SubmitUsingFTP(const std::string& localprefix,
const std::set<std::string>& files,
const std::string& remoteprefix,
const std::string& url)
2003-01-07 07:07:24 +03:00
{
CURL* curl;
2003-01-08 06:24:45 +03:00
CURLcode res;
FILE* ftpfile;
char error_buffer[1024];
2003-01-08 06:24:45 +03:00
/* In windows, this will init the winsock stuff */
::curl_global_init(CURL_GLOBAL_ALL);
2003-05-02 21:54:05 +04:00
2006-03-10 23:03:09 +03:00
cmCTest::SetOfStrings::const_iterator file;
for (file = files.begin(); file != files.end(); ++file) {
/* get a curl handle */
curl = curl_easy_init();
if (curl) {
// Using proxy
if (this->FTPProxyType > 0) {
2006-03-10 23:03:09 +03:00
curl_easy_setopt(curl, CURLOPT_PROXY, this->FTPProxy.c_str());
switch (this->FTPProxyType) {
case 2:
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
break;
case 3:
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
break;
default:
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
}
}
2003-08-11 20:19:46 +04:00
// enable uploading
::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
// if there is little to no activity for too long stop submitting
::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME,
SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
2003-08-11 20:19:46 +04:00
std::string local_file = *file;
if (!cmSystemTools::FileExists(local_file.c_str())) {
local_file = localprefix + "/" + *file;
}
std::string upload_as =
url + "/" + remoteprefix + cmSystemTools::GetFilenameName(*file);
if (!cmSystemTools::FileExists(local_file.c_str())) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Cannot find file: " << local_file << std::endl);
::curl_easy_cleanup(curl);
2006-03-09 19:17:10 +03:00
::curl_global_cleanup();
2003-01-08 06:24:45 +03:00
return false;
}
2014-11-23 13:05:50 +03:00
unsigned long filelen = cmSystemTools::FileLength(local_file);
2003-01-08 06:24:45 +03:00
ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
*this->LogFile << "\tUpload file: " << local_file << " to " << upload_as
<< std::endl;
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" Upload file: " << local_file << " to "
<< upload_as << std::endl,
this->Quiet);
2003-01-08 06:24:45 +03:00
2005-06-02 22:48:10 +04:00
::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
2003-01-08 06:24:45 +03:00
// specify target
::curl_easy_setopt(curl, CURLOPT_URL, upload_as.c_str());
2003-08-11 20:19:46 +04:00
2003-01-08 06:24:45 +03:00
// now specify which file to upload
::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
// and give the size of the upload (optional)
::curl_easy_setopt(curl, CURLOPT_INFILESIZE, static_cast<long>(filelen));
// and give curl the buffer for errors
::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
2003-01-08 06:24:45 +03:00
// specify handler for output
2006-03-09 19:17:10 +03:00
::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
cmCTestSubmitHandlerWriteMemoryCallback);
2006-03-09 19:17:10 +03:00
::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
cmCTestSubmitHandlerCurlDebugCallback);
/* we pass our 'chunk' struct to the callback function */
cmCTestSubmitHandlerVectorOfChar chunk;
2005-06-02 22:48:10 +04:00
cmCTestSubmitHandlerVectorOfChar chunkDebug;
::curl_easy_setopt(curl, CURLOPT_FILE, (void*)&chunk);
::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void*)&chunkDebug);
2003-01-08 06:24:45 +03:00
// Now run off and do what you've been told!
res = ::curl_easy_perform(curl);
if (!chunk.empty()) {
cmCTestOptionalLog(this->CTest, DEBUG, "CURL output: ["
<< cmCTestLogWrite(&*chunk.begin(), chunk.size())
<< "]" << std::endl,
this->Quiet);
}
if (!chunkDebug.empty()) {
cmCTestOptionalLog(
this->CTest, DEBUG, "CURL debug output: ["
<< cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
<< std::endl,
this->Quiet);
}
2003-01-08 06:24:45 +03:00
fclose(ftpfile);
if (res) {
cmCTestLog(this->CTest, ERROR_MESSAGE, " Error when uploading file: "
<< local_file << std::endl);
2006-03-10 23:03:09 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Error message was: " << error_buffer << std::endl);
*this->LogFile << " Error when uploading file: " << local_file
<< std::endl
<< " Error message was: " << error_buffer << std::endl
<< " Curl output was: ";
// avoid dereference of empty vector
if (!chunk.empty()) {
*this->LogFile << cmCTestLogWrite(&*chunk.begin(), chunk.size());
cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
<< cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
<< std::endl);
}
*this->LogFile << std::endl;
2003-01-08 06:24:45 +03:00
::curl_easy_cleanup(curl);
2006-03-09 19:17:10 +03:00
::curl_global_cleanup();
2003-01-08 06:24:45 +03:00
return false;
}
// always cleanup
::curl_easy_cleanup(curl);
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Uploaded: " + local_file << std::endl,
this->Quiet);
2003-01-07 07:07:24 +03:00
}
}
2006-03-09 19:17:10 +03:00
::curl_global_cleanup();
2003-01-08 06:24:45 +03:00
return true;
}
// Uploading files is simpler
bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix,
const std::set<std::string>& files,
const std::string& remoteprefix,
const std::string& url)
{
CURL* curl;
CURLcode res;
FILE* ftpfile;
2004-04-01 23:11:17 +04:00
char error_buffer[1024];
struct curl_slist* headers =
2016-06-27 23:44:16 +03:00
::curl_slist_append(CM_NULLPTR, "Content-Type: text/xml");
/* In windows, this will init the winsock stuff */
::curl_global_init(CURL_GLOBAL_ALL);
std::string dropMethod(this->CTest->GetCTestConfiguration("DropMethod"));
std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
std::vector<std::string> args;
cmSystemTools::ExpandListArgument(curlopt, args);
bool verifyPeerOff = false;
bool verifyHostOff = false;
for (std::vector<std::string>::iterator i = args.begin(); i != args.end();
++i) {
if (*i == "CURLOPT_SSL_VERIFYPEER_OFF") {
verifyPeerOff = true;
}
if (*i == "CURLOPT_SSL_VERIFYHOST_OFF") {
verifyHostOff = true;
}
}
std::string::size_type kk;
2006-03-10 23:03:09 +03:00
cmCTest::SetOfStrings::const_iterator file;
for (file = files.begin(); file != files.end(); ++file) {
2003-01-16 20:30:02 +03:00
/* get a curl handle */
curl = curl_easy_init();
if (curl) {
cmCurlSetCAInfo(curl);
if (verifyPeerOff) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" Set CURLOPT_SSL_VERIFYPEER to off\n",
this->Quiet);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
}
if (verifyHostOff) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" Set CURLOPT_SSL_VERIFYHOST to off\n",
this->Quiet);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
}
2003-01-16 20:30:02 +03:00
// Using proxy
if (this->HTTPProxyType > 0) {
2006-03-10 23:03:09 +03:00
curl_easy_setopt(curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
switch (this->HTTPProxyType) {
case 2:
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
break;
case 3:
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
break;
default:
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
if (!this->HTTPProxyAuth.empty()) {
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
this->HTTPProxyAuth.c_str());
}
}
}
if (this->CTest->ShouldUseHTTP10()) {
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
}
// enable HTTP ERROR parsing
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
2003-01-16 20:30:02 +03:00
/* enable uploading */
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
2003-01-16 20:30:02 +03:00
// if there is little to no activity for too long stop submitting
::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME,
SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
2003-01-16 20:30:02 +03:00
/* HTTP PUT please */
2005-06-02 22:48:10 +04:00
::curl_easy_setopt(curl, CURLOPT_PUT, 1);
::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
2003-01-16 20:30:02 +03:00
// Be sure to set Content-Type to satisfy fussy modsecurity rules
::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
std::string local_file = *file;
if (!cmSystemTools::FileExists(local_file.c_str())) {
local_file = localprefix + "/" + *file;
}
std::string remote_file =
remoteprefix + cmSystemTools::GetFilenameName(*file);
2004-04-01 23:11:17 +04:00
*this->LogFile << "\tUpload file: " << local_file << " to "
<< remote_file << std::endl;
2004-04-01 23:11:17 +04:00
std::string ofile = "";
for (kk = 0; kk < remote_file.size(); kk++) {
2003-01-16 20:30:02 +03:00
char c = remote_file[kk];
2005-06-24 17:41:01 +04:00
char hexCh[4] = { 0, 0, 0, 0 };
hexCh[0] = c;
switch (c) {
case '+':
case '?':
case '/':
case '\\':
case '&':
case ' ':
case '=':
case '%':
sprintf(hexCh, "%%%02X", (int)c);
ofile.append(hexCh);
break;
default:
ofile.append(hexCh);
2003-01-16 20:30:02 +03:00
}
}
std::string upload_as = url +
((url.find('?') == std::string::npos) ? '?' : '&') + "FileName=" +
ofile;
2003-01-16 20:30:02 +03:00
upload_as += "&MD5=";
2010-06-10 20:25:49 +04:00
if (cmSystemTools::IsOn(this->GetOption("InternalTest"))) {
2010-06-10 20:25:49 +04:00
upload_as += "bad_md5sum";
} else {
2010-06-10 20:25:49 +04:00
char md5[33];
cmSystemTools::ComputeFileMD5(local_file, md5);
2010-06-10 20:25:49 +04:00
md5[32] = 0;
upload_as += md5;
}
if (!cmSystemTools::FileExists(local_file.c_str())) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Cannot find file: " << local_file << std::endl);
::curl_easy_cleanup(curl);
::curl_slist_free_all(headers);
2006-03-09 19:17:10 +03:00
::curl_global_cleanup();
2003-01-16 20:30:02 +03:00
return false;
}
2014-11-23 13:05:50 +03:00
unsigned long filelen = cmSystemTools::FileLength(local_file);
2003-01-16 20:30:02 +03:00
ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" Upload file: " << local_file << " to "
<< upload_as << " Size: "
<< filelen << std::endl,
this->Quiet);
2003-01-16 20:30:02 +03:00
// specify target
::curl_easy_setopt(curl, CURLOPT_URL, upload_as.c_str());
2003-01-16 20:30:02 +03:00
// now specify which file to upload
::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
// and give the size of the upload (optional)
::curl_easy_setopt(curl, CURLOPT_INFILESIZE, static_cast<long>(filelen));
2003-01-16 20:30:02 +03:00
2004-04-01 23:11:17 +04:00
// and give curl the buffer for errors
::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
// specify handler for output
2006-03-09 19:17:10 +03:00
::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
cmCTestSubmitHandlerWriteMemoryCallback);
2006-03-09 19:17:10 +03:00
::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
cmCTestSubmitHandlerCurlDebugCallback);
/* we pass our 'chunk' struct to the callback function */
cmCTestSubmitHandlerVectorOfChar chunk;
2005-06-02 22:48:10 +04:00
cmCTestSubmitHandlerVectorOfChar chunkDebug;
::curl_easy_setopt(curl, CURLOPT_FILE, (void*)&chunk);
::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void*)&chunkDebug);
// Now run off and do what you've been told!
res = ::curl_easy_perform(curl);
if (cmSystemTools::IsOn(this->GetOption("InternalTest")) &&
cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
this->CTest->GetCDashVersion().c_str(),
"1.7")) {
// mock failure output for internal test case
std::string mock_output =
"<cdash version=\"1.7.0\">\n"
" <status>ERROR</status>\n"
" <message>Checksum failed for file.</message>\n"
"</cdash>\n";
chunk.clear();
chunk.assign(mock_output.begin(), mock_output.end());
}
if (!chunk.empty()) {
cmCTestOptionalLog(this->CTest, DEBUG, "CURL output: ["
<< cmCTestLogWrite(&*chunk.begin(), chunk.size())
<< "]" << std::endl,
this->Quiet);
this->ParseResponse(chunk);
}
if (!chunkDebug.empty()) {
cmCTestOptionalLog(
this->CTest, DEBUG, "CURL debug output: ["
<< cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
<< std::endl,
this->Quiet);
}
// If curl failed for any reason, or checksum fails, wait and retry
//
if (res != CURLE_OK || this->HasErrors) {
2016-06-27 23:44:16 +03:00
std::string retryDelay = this->GetOption("RetryDelay") == CM_NULLPTR
? ""
: this->GetOption("RetryDelay");
2016-06-27 23:44:16 +03:00
std::string retryCount = this->GetOption("RetryCount") == CM_NULLPTR
? ""
: this->GetOption("RetryCount");
int delay = retryDelay == ""
? atoi(this->CTest->GetCTestConfiguration("CTestSubmitRetryDelay")
.c_str())
: atoi(retryDelay.c_str());
int count = retryCount == ""
? atoi(this->CTest->GetCTestConfiguration("CTestSubmitRetryCount")
.c_str())
: atoi(retryCount.c_str());
for (int i = 0; i < count; i++) {
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Submit failed, waiting " << delay
<< " seconds...\n",
this->Quiet);
2010-06-10 20:25:49 +04:00
double stop = cmSystemTools::GetTime() + delay;
while (cmSystemTools::GetTime() < stop) {
2010-06-10 20:25:49 +04:00
cmSystemTools::Delay(100);
}
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Retry submission: Attempt "
<< (i + 1) << " of " << count << std::endl,
this->Quiet);
::fclose(ftpfile);
ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
chunk.clear();
chunkDebug.clear();
this->HasErrors = false;
res = ::curl_easy_perform(curl);
if (!chunk.empty()) {
cmCTestOptionalLog(
this->CTest, DEBUG, "CURL output: ["
<< cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
<< std::endl,
this->Quiet);
this->ParseResponse(chunk);
}
if (res == CURLE_OK && !this->HasErrors) {
break;
}
}
}
2003-01-16 20:30:02 +03:00
fclose(ftpfile);
if (res) {
cmCTestLog(this->CTest, ERROR_MESSAGE, " Error when uploading file: "
<< local_file << std::endl);
2006-03-10 23:03:09 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Error message was: " << error_buffer << std::endl);
*this->LogFile << " Error when uploading file: " << local_file
<< std::endl
2011-03-11 16:04:58 +03:00
<< " Error message was: " << error_buffer
<< std::endl;
// avoid deref of begin for zero size array
if (!chunk.empty()) {
*this->LogFile << " Curl output was: "
<< cmCTestLogWrite(&*chunk.begin(), chunk.size())
<< std::endl;
cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
<< cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
<< std::endl);
}
::curl_easy_cleanup(curl);
::curl_slist_free_all(headers);
2006-03-09 19:17:10 +03:00
::curl_global_cleanup();
return false;
}
2003-01-16 20:30:02 +03:00
// always cleanup
::curl_easy_cleanup(curl);
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Uploaded: " + local_file << std::endl,
this->Quiet);
}
}
::curl_slist_free_all(headers);
2006-03-09 19:17:10 +03:00
::curl_global_cleanup();
return true;
2003-01-07 07:07:24 +03:00
}
void cmCTestSubmitHandler::ParseResponse(
cmCTestSubmitHandlerVectorOfChar chunk)
{
std::string output = "";
output.append(chunk.begin(), chunk.end());
if (output.find("<cdash") != output.npos) {
ResponseParser parser;
parser.Parse(output.c_str());
if (parser.Status != ResponseParser::STATUS_OK) {
this->HasErrors = true;
cmCTestLog(this->CTest, HANDLER_OUTPUT,
" Submission failed: " << parser.Message << std::endl);
return;
}
}
2010-06-10 20:25:49 +04:00
output = cmSystemTools::UpperCase(output);
if (output.find("WARNING") != std::string::npos) {
2010-06-10 20:25:49 +04:00
this->HasWarnings = true;
}
if (output.find("ERROR") != std::string::npos) {
2010-06-10 20:25:49 +04:00
this->HasErrors = true;
}
if (this->HasWarnings || this->HasErrors) {
cmCTestLog(this->CTest, HANDLER_OUTPUT, " Server Response:\n"
<< cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "\n");
}
}
bool cmCTestSubmitHandler::TriggerUsingHTTP(const std::set<std::string>& files,
const std::string& remoteprefix,
const std::string& url)
2003-01-12 05:47:35 +03:00
{
CURL* curl;
2004-04-01 23:11:17 +04:00
char error_buffer[1024];
2003-01-12 05:47:35 +03:00
/* In windows, this will init the winsock stuff */
::curl_global_init(CURL_GLOBAL_ALL);
2003-08-11 20:19:46 +04:00
2006-03-10 23:03:09 +03:00
cmCTest::SetOfStrings::const_iterator file;
for (file = files.begin(); file != files.end(); ++file) {
2003-01-16 21:02:11 +03:00
/* get a curl handle */
curl = curl_easy_init();
if (curl) {
2003-01-16 21:02:11 +03:00
// Using proxy
if (this->HTTPProxyType > 0) {
2006-03-10 23:03:09 +03:00
curl_easy_setopt(curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
switch (this->HTTPProxyType) {
case 2:
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
break;
case 3:
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
break;
default:
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
if (!this->HTTPProxyAuth.empty()) {
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
this->HTTPProxyAuth.c_str());
}
2003-01-16 20:45:24 +03:00
}
}
2003-01-16 20:45:24 +03:00
2005-06-02 22:48:10 +04:00
::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
2004-04-01 23:11:17 +04:00
// and give curl the buffer for errors
::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
// specify handler for output
2006-03-09 19:17:10 +03:00
::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
cmCTestSubmitHandlerWriteMemoryCallback);
2006-03-09 19:17:10 +03:00
::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
cmCTestSubmitHandlerCurlDebugCallback);
/* we pass our 'chunk' struct to the callback function */
cmCTestSubmitHandlerVectorOfChar chunk;
2005-06-02 22:48:10 +04:00
cmCTestSubmitHandlerVectorOfChar chunkDebug;
::curl_easy_setopt(curl, CURLOPT_FILE, (void*)&chunk);
::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void*)&chunkDebug);
std::string rfile = remoteprefix + cmSystemTools::GetFilenameName(*file);
std::string ofile = "";
std::string::iterator kk;
for (kk = rfile.begin(); kk < rfile.end(); ++kk) {
char c = *kk;
2005-06-24 17:41:01 +04:00
char hexCh[4] = { 0, 0, 0, 0 };
hexCh[0] = c;
switch (c) {
case '+':
case '?':
case '/':
case '\\':
case '&':
case ' ':
case '=':
case '%':
sprintf(hexCh, "%%%02X", (int)c);
ofile.append(hexCh);
break;
default:
ofile.append(hexCh);
2003-01-12 05:47:35 +03:00
}
}
std::string turl = url +
((url.find('?') == std::string::npos) ? '?' : '&') + "xmlfile=" +
ofile;
*this->LogFile << "Trigger url: " << turl << std::endl;
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" Trigger url: " << turl << std::endl, this->Quiet);
2009-03-31 23:24:50 +04:00
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
2003-01-12 05:47:35 +03:00
curl_easy_setopt(curl, CURLOPT_URL, turl.c_str());
if (curl_easy_perform(curl)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Error when triggering: " << turl << std::endl);
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Error message was: " << error_buffer << std::endl);
*this->LogFile << "\tTriggering failed with error: " << error_buffer
<< std::endl
2011-03-11 16:04:58 +03:00
<< " Error message was: " << error_buffer
<< std::endl;
if (!chunk.empty()) {
*this->LogFile << " Curl output was: "
<< cmCTestLogWrite(&*chunk.begin(), chunk.size())
<< std::endl;
cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
<< cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
<< std::endl);
}
2003-01-12 05:47:35 +03:00
::curl_easy_cleanup(curl);
2006-03-09 19:17:10 +03:00
::curl_global_cleanup();
2003-01-12 05:47:35 +03:00
return false;
}
if (!chunk.empty()) {
cmCTestOptionalLog(this->CTest, DEBUG, "CURL output: ["
<< cmCTestLogWrite(&*chunk.begin(), chunk.size())
<< "]" << std::endl,
this->Quiet);
}
if (!chunkDebug.empty()) {
cmCTestOptionalLog(
this->CTest, DEBUG, "CURL debug output: ["
<< cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
<< std::endl,
this->Quiet);
}
2003-01-16 21:02:11 +03:00
// always cleanup
::curl_easy_cleanup(curl);
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl,
this->Quiet);
2003-01-12 05:47:35 +03:00
}
}
2006-03-09 19:17:10 +03:00
::curl_global_cleanup();
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Dart server triggered..." << std::endl, this->Quiet);
2003-01-12 05:47:35 +03:00
return true;
}
bool cmCTestSubmitHandler::SubmitUsingSCP(const std::string& scp_command,
const std::string& localprefix,
const std::set<std::string>& files,
const std::string& remoteprefix,
const std::string& url)
2003-01-07 07:07:24 +03:00
{
if (scp_command.empty() || localprefix.empty() || files.empty() ||
remoteprefix.empty() || url.empty()) {
2004-06-02 21:39:25 +04:00
return 0;
}
2004-06-02 21:39:25 +04:00
std::vector<const char*> argv;
argv.push_back(scp_command.c_str()); // Scp command
argv.push_back(scp_command.c_str()); // Dummy string for file
argv.push_back(scp_command.c_str()); // Dummy string for remote url
2016-06-27 23:44:16 +03:00
argv.push_back(CM_NULLPTR);
2004-06-02 21:39:25 +04:00
cmsysProcess* cp = cmsysProcess_New();
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
// cmsysProcess_SetTimeout(cp, timeout);
2004-06-02 21:39:25 +04:00
int problems = 0;
2006-03-10 23:03:09 +03:00
cmCTest::SetOfStrings::const_iterator file;
for (file = files.begin(); file != files.end(); ++file) {
2004-06-07 16:51:20 +04:00
int retVal;
2004-06-02 21:39:25 +04:00
std::string lfname = localprefix;
cmSystemTools::ConvertToUnixSlashes(lfname);
lfname += "/" + *file;
2004-06-02 21:39:25 +04:00
lfname = cmSystemTools::ConvertToOutputPath(lfname.c_str());
argv[1] = lfname.c_str();
std::string rfname = url + "/" + remoteprefix + *file;
2004-06-02 21:39:25 +04:00
argv[2] = rfname.c_str();
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Execute \""
<< argv[0] << "\" \"" << argv[1] << "\" \"" << argv[2]
<< "\"" << std::endl,
this->Quiet);
2006-03-10 23:03:09 +03:00
*this->LogFile << "Execute \"" << argv[0] << "\" \"" << argv[1] << "\" \""
<< argv[2] << "\"" << std::endl;
2004-06-02 21:39:25 +04:00
cmsysProcess_SetCommand(cp, &*argv.begin());
cmsysProcess_Execute(cp);
char* data;
int length;
2016-06-27 23:44:16 +03:00
while (cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR)) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
cmCTestLogWrite(data, length), this->Quiet);
}
2016-06-27 23:44:16 +03:00
cmsysProcess_WaitForExit(cp, CM_NULLPTR);
2004-06-02 21:39:25 +04:00
int result = cmsysProcess_GetState(cp);
if (result == cmsysProcess_State_Exited) {
2004-06-02 21:39:25 +04:00
retVal = cmsysProcess_GetExitValue(cp);
if (retVal != 0) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"\tSCP returned: " << retVal << std::endl,
this->Quiet);
2006-03-10 23:03:09 +03:00
*this->LogFile << "\tSCP returned: " << retVal << std::endl;
problems++;
2004-06-02 21:39:25 +04:00
}
} else if (result == cmsysProcess_State_Exception) {
2004-06-02 21:39:25 +04:00
retVal = cmsysProcess_GetExitException(cp);
cmCTestLog(this->CTest, ERROR_MESSAGE,
"\tThere was an exception: " << retVal << std::endl);
2006-03-10 23:03:09 +03:00
*this->LogFile << "\tThere was an exception: " << retVal << std::endl;
problems++;
} else if (result == cmsysProcess_State_Expired) {
2006-03-10 23:03:09 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was a timeout"
<< std::endl);
2006-03-10 23:03:09 +03:00
*this->LogFile << "\tThere was a timeout" << std::endl;
problems++;
} else if (result == cmsysProcess_State_Error) {
2006-03-10 23:03:09 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE, "\tError executing SCP: "
<< cmsysProcess_GetErrorString(cp) << std::endl);
2006-03-10 23:03:09 +03:00
*this->LogFile << "\tError executing SCP: "
<< cmsysProcess_GetErrorString(cp) << std::endl;
problems++;
2004-06-02 21:39:25 +04:00
}
}
2004-06-02 21:39:25 +04:00
cmsysProcess_Delete(cp);
return problems == 0;
2003-01-07 07:07:24 +03:00
}
bool cmCTestSubmitHandler::SubmitUsingCP(const std::string& localprefix,
const std::set<std::string>& files,
const std::string& remoteprefix,
const std::string& destination)
2009-03-31 23:24:50 +04:00
{
if (localprefix.empty() || files.empty() || remoteprefix.empty() ||
destination.empty()) {
/* clang-format off */
2011-03-11 16:04:58 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
2009-03-31 23:24:50 +04:00
"Missing arguments for submit via cp:\n"
<< "\tlocalprefix: " << localprefix << "\n"
<< "\tNumber of files: " << files.size() << "\n"
<< "\tremoteprefix: " << remoteprefix << "\n"
<< "\tdestination: " << destination << std::endl);
/* clang-format on */
2009-03-31 23:24:50 +04:00
return 0;
}
2009-03-31 23:24:50 +04:00
cmCTest::SetOfStrings::const_iterator file;
for (file = files.begin(); file != files.end(); ++file) {
2009-03-31 23:24:50 +04:00
std::string lfname = localprefix;
cmSystemTools::ConvertToUnixSlashes(lfname);
lfname += "/" + *file;
std::string rfname = destination + "/" + remoteprefix + *file;
cmSystemTools::CopyFileAlways(lfname, rfname);
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Copy file: "
<< lfname << " to " << rfname << std::endl,
this->Quiet);
}
2009-03-31 23:24:50 +04:00
std::string tagDoneFile = destination + "/" + remoteprefix + "DONE";
cmSystemTools::Touch(tagDoneFile, true);
2009-03-31 23:24:50 +04:00
return true;
}
#if defined(CTEST_USE_XMLRPC)
bool cmCTestSubmitHandler::SubmitUsingXMLRPC(
const std::string& localprefix, const std::set<std::string>& files,
const std::string& remoteprefix, const std::string& url)
{
xmlrpc_env env;
char ctestString[] = "CTest";
std::string ctestVersionString = cmVersion::GetCMakeVersion();
char* ctestVersion = const_cast<char*>(ctestVersionString.c_str());
std::string realURL = url + "/" + remoteprefix + "/Command/";
/* Start up our XML-RPC client library. */
xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, ctestString, ctestVersion);
/* Initialize our error-handling environment. */
xmlrpc_env_init(&env);
/* Call the famous server at UserLand. */
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Submitting to: "
<< realURL << " (" << remoteprefix << ")" << std::endl,
this->Quiet);
2006-03-10 23:03:09 +03:00
cmCTest::SetOfStrings::const_iterator file;
for (file = files.begin(); file != files.end(); ++file) {
xmlrpc_value* result;
2005-03-06 16:51:08 +03:00
std::string local_file = *file;
if (!cmSystemTools::FileExists(local_file.c_str())) {
local_file = localprefix + "/" + *file;
}
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Submit file: " << local_file << std::endl,
this->Quiet);
struct stat st;
if (::stat(local_file.c_str(), &st)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Cannot find file: " << local_file << std::endl);
return false;
}
// off_t can be bigger than size_t. fread takes size_t.
// make sure the file is not too big.
if (static_cast<off_t>(static_cast<size_t>(st.st_size)) !=
static_cast<off_t>(st.st_size)) {
cmCTestLog(this->CTest, ERROR_MESSAGE, " File too big: " << local_file
<< std::endl);
return false;
}
size_t fileSize = static_cast<size_t>(st.st_size);
FILE* fp = cmsys::SystemTools::Fopen(local_file.c_str(), "rb");
if (!fp) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Cannot open file: " << local_file << std::endl);
return false;
}
2005-03-06 16:51:08 +03:00
unsigned char* fileBuffer = new unsigned char[fileSize];
if (fread(fileBuffer, 1, fileSize, fp) != fileSize) {
delete[] fileBuffer;
fclose(fp);
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Cannot read file: " << local_file << std::endl);
2005-03-06 16:51:08 +03:00
return false;
}
fclose(fp);
char remoteCommand[] = "Submit.put";
char* pRealURL = const_cast<char*>(realURL.c_str());
result = xmlrpc_client_call(&env, pRealURL, remoteCommand, "(6)",
fileBuffer, (xmlrpc_int32)fileSize);
delete[] fileBuffer;
if (env.fault_occurred) {
2006-03-10 23:03:09 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE, " Submission problem: "
<< env.fault_string << " (" << env.fault_code << ")"
<< std::endl);
xmlrpc_env_clean(&env);
xmlrpc_client_cleanup();
return false;
}
2005-03-06 16:51:08 +03:00
/* Dispose of our result value. */
xmlrpc_DECREF(result);
}
/* Clean up our error-handling environment. */
xmlrpc_env_clean(&env);
/* Shutdown our XML-RPC client library. */
xmlrpc_client_cleanup();
return true;
}
#else
bool cmCTestSubmitHandler::SubmitUsingXMLRPC(
std::string const& /*unused*/, std::set<std::string> const& /*unused*/,
std::string const& /*unused*/, std::string const& /*unused*/)
{
return false;
}
#endif
void cmCTestSubmitHandler::ConstructCDashURL(std::string& dropMethod,
std::string& url)
{
dropMethod = this->CTest->GetCTestConfiguration("DropMethod");
url = dropMethod;
url += "://";
if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) {
url += this->CTest->GetCTestConfiguration("DropSiteUser");
cmCTestOptionalLog(
this->CTest, HANDLER_OUTPUT,
this->CTest->GetCTestConfiguration("DropSiteUser").c_str(), this->Quiet);
if (!this->CTest->GetCTestConfiguration("DropSitePassword").empty()) {
url += ":" + this->CTest->GetCTestConfiguration("DropSitePassword");
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, ":******", this->Quiet);
}
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->GetState()->GetGlobalProperty("SubProject");
// TODO: Encode values for a URL instead of trusting caller.
std::ostringstream str;
str << "project="
<< curl.Escape(this->CTest->GetCTestConfiguration("ProjectName")) << "&";
if (subproject) {
str << "subproject=" << curl.Escape(subproject) << "&";
}
str << "stamp=" << curl.Escape(this->CTest->GetCurrentTag()) << "-"
<< curl.Escape(this->CTest->GetTestModelString()) << "&"
<< "model=" << curl.Escape(this->CTest->GetTestModelString()) << "&"
<< "build="
<< curl.Escape(this->CTest->GetCTestConfiguration("BuildName")) << "&"
<< "site=" << curl.Escape(this->CTest->GetCTestConfiguration("Site"))
<< "&"
<< "track=" << curl.Escape(this->CTest->GetTestModelString()) << "&"
<< "starttime=" << (int)cmSystemTools::GetTime() << "&"
<< "endtime=" << (int)cmSystemTools::GetTime() << "&"
<< "datafilesmd5[0]=" << md5sum << "&"
<< "type=" << curl.Escape(typeString);
std::string fields = str.str();
cmCTestOptionalLog(this->CTest, DEBUG,
"fields: " << fields << "\nurl:" << url
<< "\nfile: " << file << "\n",
this->Quiet);
std::string response;
if (!curl.HttpRequest(url, fields, response)) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Error in HttpRequest\n"
<< response);
return -1;
}
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Request upload response: [" << response << "]\n",
this->Quiet);
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) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"File already exists on CDash, skip upload " << file
<< "\n",
this->Quiet);
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=" << curl.Escape(typeString) << "&"
<< "md5=" << md5sum << "&"
<< "filename=" << curl.Escape(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;
}
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Upload file response: [" << response << "]\n",
this->Quiet);
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);
}
2008-02-29 22:58:33 +03:00
std::string iscdash = this->CTest->GetCTestConfiguration("IsCDash");
// cdash does not need to trigger so just return true
if (!iscdash.empty()) {
2008-02-29 22:58:33 +03:00
this->CDash = true;
}
2008-02-29 22:58:33 +03:00
const std::string& buildDirectory =
this->CTest->GetCTestConfiguration("BuildDirectory");
if (buildDirectory.empty()) {
2006-03-10 23:03:09 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Cannot find BuildDirectory key in the DartConfiguration.tcl"
<< std::endl);
return -1;
}
if (getenv("HTTP_PROXY")) {
2006-03-10 23:03:09 +03:00
this->HTTPProxyType = 1;
this->HTTPProxy = getenv("HTTP_PROXY");
if (getenv("HTTP_PROXY_PORT")) {
2006-03-10 23:03:09 +03:00
this->HTTPProxy += ":";
this->HTTPProxy += getenv("HTTP_PROXY_PORT");
}
if (getenv("HTTP_PROXY_TYPE")) {
std::string type = getenv("HTTP_PROXY_TYPE");
// HTTP/SOCKS4/SOCKS5
if (type == "HTTP") {
2006-03-10 23:03:09 +03:00
this->HTTPProxyType = 1;
} else if (type == "SOCKS4") {
2006-03-10 23:03:09 +03:00
this->HTTPProxyType = 2;
} else if (type == "SOCKS5") {
2006-03-10 23:03:09 +03:00
this->HTTPProxyType = 3;
}
}
if (getenv("HTTP_PROXY_USER")) {
2006-03-10 23:03:09 +03:00
this->HTTPProxyAuth = getenv("HTTP_PROXY_USER");
}
if (getenv("HTTP_PROXY_PASSWD")) {
2006-03-10 23:03:09 +03:00
this->HTTPProxyAuth += ":";
this->HTTPProxyAuth += getenv("HTTP_PROXY_PASSWD");
}
}
if (getenv("FTP_PROXY")) {
2006-03-10 23:03:09 +03:00
this->FTPProxyType = 1;
this->FTPProxy = getenv("FTP_PROXY");
if (getenv("FTP_PROXY_PORT")) {
2006-03-10 23:03:09 +03:00
this->FTPProxy += ":";
this->FTPProxy += getenv("FTP_PROXY_PORT");
}
if (getenv("FTP_PROXY_TYPE")) {
std::string type = getenv("FTP_PROXY_TYPE");
// HTTP/SOCKS4/SOCKS5
if (type == "HTTP") {
2006-03-10 23:03:09 +03:00
this->FTPProxyType = 1;
} else if (type == "SOCKS4") {
2006-03-10 23:03:09 +03:00
this->FTPProxyType = 2;
} else if (type == "SOCKS5") {
2006-03-10 23:03:09 +03:00
this->FTPProxyType = 3;
}
}
}
if (!this->HTTPProxy.empty()) {
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Use HTTP Proxy: " << this->HTTPProxy << std::endl,
this->Quiet);
}
if (!this->FTPProxy.empty()) {
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Use FTP Proxy: " << this->FTPProxy << std::endl,
this->Quiet);
}
cmGeneratedFileStream ofs;
this->StartLogFile("Submit", ofs);
cmCTest::SetOfStrings files;
std::string prefix = this->GetSubmitResultsPrefix();
if (!this->Files.empty()) {
// Submit the explicitly selected files:
//
files.insert(this->Files.begin(), this->Files.end());
}
// Add to the list of files to submit from any selected, existing parts:
//
// TODO:
// Check if test is enabled
this->CTest->AddIfExists(cmCTest::PartUpdate, "Update.xml");
this->CTest->AddIfExists(cmCTest::PartConfigure, "Configure.xml");
this->CTest->AddIfExists(cmCTest::PartBuild, "Build.xml");
this->CTest->AddIfExists(cmCTest::PartTest, "Test.xml");
if (this->CTest->AddIfExists(cmCTest::PartCoverage, "Coverage.xml")) {
std::vector<std::string> gfiles;
std::string gpath =
buildDirectory + "/Testing/" + this->CTest->GetCurrentTag();
std::string::size_type glen = gpath.size() + 1;
gpath = gpath + "/CoverageLog*";
cmCTestOptionalLog(this->CTest, DEBUG,
"Globbing for: " << gpath << std::endl, this->Quiet);
if (cmSystemTools::SimpleGlob(gpath, gfiles, 1)) {
size_t cc;
for (cc = 0; cc < gfiles.size(); cc++) {
gfiles[cc] = gfiles[cc].substr(glen);
cmCTestOptionalLog(this->CTest, DEBUG,
"Glob file: " << gfiles[cc] << std::endl,
this->Quiet);
this->CTest->AddSubmitFile(cmCTest::PartCoverage, gfiles[cc].c_str());
}
} else {
2006-03-10 23:03:09 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem globbing" << std::endl);
}
}
this->CTest->AddIfExists(cmCTest::PartMemCheck, "DynamicAnalysis.xml");
this->CTest->AddIfExists(cmCTest::PartMemCheck, "Purify.xml");
this->CTest->AddIfExists(cmCTest::PartNotes, "Notes.xml");
2011-02-18 20:11:51 +03:00
this->CTest->AddIfExists(cmCTest::PartUpload, "Upload.xml");
// Query parts for files to submit.
for (cmCTest::Part p = cmCTest::PartStart; p != cmCTest::PartCount;
p = cmCTest::Part(p + 1)) {
// Skip parts we are not submitting.
if (!this->SubmitPart[p]) {
continue;
}
// Submit files from this part.
std::vector<std::string> const& pfiles = this->CTest->GetSubmitFiles(p);
files.insert(pfiles.begin(), pfiles.end());
}
if (ofs) {
ofs << "Upload files:" << std::endl;
int cnt = 0;
cmCTest::SetOfStrings::iterator it;
for (it = files.begin(); it != files.end(); ++it) {
ofs << cnt << "\t" << *it << std::endl;
cnt++;
}
}
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "Submit files (using "
<< this->CTest->GetCTestConfiguration("DropMethod")
<< ")" << std::endl,
this->Quiet);
const char* specificTrack = this->CTest->GetSpecificTrack();
if (specificTrack) {
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Send to track: " << specificTrack << std::endl,
this->Quiet);
}
this->SetLogFile(&ofs);
std::string dropMethod(this->CTest->GetCTestConfiguration("DropMethod"));
if (dropMethod == "" || dropMethod == "ftp") {
ofs << "Using drop method: FTP" << std::endl;
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Using FTP submit method" << std::endl
<< " Drop site: ftp://",
this->Quiet);
std::string url = "ftp://";
2006-03-09 19:17:10 +03:00
url += cmCTest::MakeURLSafe(
this->CTest->GetCTestConfiguration("DropSiteUser")) +
":" + cmCTest::MakeURLSafe(
this->CTest->GetCTestConfiguration("DropSitePassword")) +
"@" + this->CTest->GetCTestConfiguration("DropSite") +
cmCTest::MakeURLSafe(this->CTest->GetCTestConfiguration("DropLocation"));
if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) {
cmCTestOptionalLog(
this->CTest, HANDLER_OUTPUT,
this->CTest->GetCTestConfiguration("DropSiteUser").c_str(),
this->Quiet);
if (!this->CTest->GetCTestConfiguration("DropSitePassword").empty()) {
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, ":******",
this->Quiet);
}
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "@", this->Quiet);
}
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
this->CTest->GetCTestConfiguration("DropSite")
<< this->CTest->GetCTestConfiguration("DropLocation")
<< std::endl,
this->Quiet);
if (!this->SubmitUsingFTP(buildDirectory + "/Testing/" +
this->CTest->GetCurrentTag(),
files, prefix, url)) {
2006-03-10 23:03:09 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Problems when submitting via FTP" << std::endl);
ofs << " Problems when submitting via FTP" << std::endl;
return -1;
}
if (!this->CDash) {
cmCTestOptionalLog(
this->CTest, HANDLER_OUTPUT, " Using HTTP trigger method"
<< std::endl
<< " Trigger site: "
<< this->CTest->GetCTestConfiguration("TriggerSite") << std::endl,
this->Quiet);
if (!this->TriggerUsingHTTP(
files, prefix,
this->CTest->GetCTestConfiguration("TriggerSite"))) {
2008-02-29 22:58:33 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Problems when triggering via HTTP" << std::endl);
ofs << " Problems when triggering via HTTP" << std::endl;
return -1;
}
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Submission successful" << std::endl, this->Quiet);
2008-02-29 22:58:33 +03:00
ofs << " Submission successful" << std::endl;
return 0;
}
} else if (dropMethod == "http" || dropMethod == "https") {
std::string url = dropMethod;
url += "://";
ofs << "Using drop method: " << dropMethod << std::endl;
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Using HTTP submit method" << std::endl
<< " Drop site:" << url,
this->Quiet);
if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) {
2006-03-10 23:03:09 +03:00
url += this->CTest->GetCTestConfiguration("DropSiteUser");
cmCTestOptionalLog(
this->CTest, HANDLER_OUTPUT,
this->CTest->GetCTestConfiguration("DropSiteUser").c_str(),
this->Quiet);
if (!this->CTest->GetCTestConfiguration("DropSitePassword").empty()) {
2006-03-10 23:03:09 +03:00
url += ":" + this->CTest->GetCTestConfiguration("DropSitePassword");
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, ":******",
this->Quiet);
}
url += "@";
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "@", this->Quiet);
}
2006-03-10 23:03:09 +03:00
url += this->CTest->GetCTestConfiguration("DropSite") +
this->CTest->GetCTestConfiguration("DropLocation");
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
this->CTest->GetCTestConfiguration("DropSite")
<< this->CTest->GetCTestConfiguration("DropLocation")
<< std::endl,
this->Quiet);
if (!this->SubmitUsingHTTP(buildDirectory + "/Testing/" +
this->CTest->GetCurrentTag(),
files, prefix, url)) {
2006-03-10 23:03:09 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Problems when submitting via HTTP" << std::endl);
ofs << " Problems when submitting via HTTP" << std::endl;
return -1;
}
if (!this->CDash) {
cmCTestOptionalLog(
this->CTest, HANDLER_OUTPUT, " Using HTTP trigger method"
<< std::endl
<< " Trigger site: "
<< this->CTest->GetCTestConfiguration("TriggerSite") << std::endl,
this->Quiet);
if (!this->TriggerUsingHTTP(
files, prefix,
this->CTest->GetCTestConfiguration("TriggerSite"))) {
2008-02-29 22:58:33 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Problems when triggering via HTTP" << std::endl);
ofs << " Problems when triggering via HTTP" << std::endl;
return -1;
}
}
if (this->HasErrors) {
cmCTestLog(this->CTest, HANDLER_OUTPUT, " Errors occurred during "
"submission."
<< std::endl);
ofs << " Errors occurred during submission. " << std::endl;
} else {
cmCTestOptionalLog(
this->CTest, HANDLER_OUTPUT, " Submission successful"
<< (this->HasWarnings ? ", with warnings." : "") << std::endl,
this->Quiet);
ofs << " Submission successful"
<< (this->HasWarnings ? ", with warnings." : "") << std::endl;
}
return 0;
} else if (dropMethod == "xmlrpc") {
#if defined(CTEST_USE_XMLRPC)
ofs << "Using drop method: XML-RPC" << std::endl;
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Using XML-RPC submit method" << std::endl,
this->Quiet);
2006-03-10 23:03:09 +03:00
std::string url = this->CTest->GetCTestConfiguration("DropSite");
prefix = this->CTest->GetCTestConfiguration("DropLocation");
if (!this->SubmitUsingXMLRPC(buildDirectory + "/Testing/" +
this->CTest->GetCurrentTag(),
files, prefix, url)) {
2006-03-10 23:03:09 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Problems when submitting via XML-RPC" << std::endl);
ofs << " Problems when submitting via XML-RPC" << std::endl;
return -1;
}
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Submission successful" << std::endl, this->Quiet);
ofs << " Submission successful" << std::endl;
return 0;
#else
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Submission method \"xmlrpc\" not compiled into CTest!"
<< std::endl);
return -1;
#endif
} else if (dropMethod == "scp") {
std::string url;
std::string oldWorkingDirectory;
if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) {
2006-03-10 23:03:09 +03:00
url += this->CTest->GetCTestConfiguration("DropSiteUser") + "@";
}
2006-03-10 23:03:09 +03:00
url += this->CTest->GetCTestConfiguration("DropSite") + ":" +
this->CTest->GetCTestConfiguration("DropLocation");
// change to the build directory so that we can uses a relative path
// on windows since scp dosn't support "c:" a drive in the path
oldWorkingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
cmSystemTools::ChangeDirectory(buildDirectory);
if (!this->SubmitUsingSCP(this->CTest->GetCTestConfiguration("ScpCommand"),
"Testing/" + this->CTest->GetCurrentTag(), files,
prefix, url)) {
cmSystemTools::ChangeDirectory(oldWorkingDirectory);
2006-03-10 23:03:09 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Problems when submitting via SCP" << std::endl);
ofs << " Problems when submitting via SCP" << std::endl;
return -1;
}
cmSystemTools::ChangeDirectory(oldWorkingDirectory);
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Submission successful" << std::endl, this->Quiet);
ofs << " Submission successful" << std::endl;
2005-06-24 21:29:22 +04:00
return 0;
} else if (dropMethod == "cp") {
std::string location = this->CTest->GetCTestConfiguration("DropLocation");
2009-03-31 23:24:50 +04:00
// change to the build directory so that we can uses a relative path
// on windows since scp dosn't support "c:" a drive in the path
std::string oldWorkingDirectory =
cmSystemTools::GetCurrentWorkingDirectory();
cmSystemTools::ChangeDirectory(buildDirectory);
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" Change directory: " << buildDirectory << std::endl,
this->Quiet);
if (!this->SubmitUsingCP("Testing/" + this->CTest->GetCurrentTag(), files,
prefix, location)) {
cmSystemTools::ChangeDirectory(oldWorkingDirectory);
2009-03-31 23:24:50 +04:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Problems when submitting via CP" << std::endl);
2009-03-31 23:24:50 +04:00
ofs << " Problems when submitting via cp" << std::endl;
return -1;
}
cmSystemTools::ChangeDirectory(oldWorkingDirectory);
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" Submission successful" << std::endl, this->Quiet);
2009-03-31 23:24:50 +04:00
ofs << " Submission successful" << std::endl;
return 0;
}
2006-03-10 23:03:09 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE, " Unknown submission method: \""
<< dropMethod << "\"" << std::endl);
return -1;
}
std::string cmCTestSubmitHandler::GetSubmitResultsPrefix()
{
std::string buildname =
cmCTest::SafeBuildIdField(this->CTest->GetCTestConfiguration("BuildName"));
std::string name = this->CTest->GetCTestConfiguration("Site") + "___" +
buildname + "___" + this->CTest->GetCurrentTag() + "-" +
2006-03-10 23:03:09 +03:00
this->CTest->GetTestModelString() + "___XML___";
return name;
}
void cmCTestSubmitHandler::SelectParts(std::set<cmCTest::Part> const& parts)
{
// Check whether each part is selected.
for (cmCTest::Part p = cmCTest::PartStart; p != cmCTest::PartCount;
p = cmCTest::Part(p + 1)) {
this->SubmitPart[p] =
(std::set<cmCTest::Part>::const_iterator(parts.find(p)) != parts.end());
}
}
void cmCTestSubmitHandler::SelectFiles(cmCTest::SetOfStrings const& files)
{
this->Files.insert(files.begin(), files.end());
}