ENH: add DOWNLOAD option to FILE command

This commit is contained in:
Bill Hoffman 2008-02-06 09:35:02 -05:00
parent 0c3607eafc
commit 7dfcc3fc12
3 changed files with 182 additions and 2 deletions

View File

@ -267,7 +267,8 @@ ENDIF (WIN32)
ADD_LIBRARY(CMakeLib ${SRCS})
TARGET_LINK_LIBRARIES(CMakeLib cmsys
${CMAKE_EXPAT_LIBRARIES} ${CMAKE_ZLIB_LIBRARIES}
${CMAKE_TAR_LIBRARIES} ${CMAKE_COMPRESS_LIBRARIES})
${CMAKE_TAR_LIBRARIES} ${CMAKE_COMPRESS_LIBRARIES}
${CMAKE_CURL_LIBRARIES})
# On Apple we need Carbon
IF(APPLE)

View File

@ -19,6 +19,11 @@
#include "cmHexFileConverter.h"
#include "cmFileTimeComparison.h"
#if defined(CMAKE_BUILD_WITH_CMAKE)
#include "cm_curl.h"
#endif
#undef GetCurrentDirectory
#include <sys/types.h>
#include <sys/stat.h>
@ -71,6 +76,10 @@ bool cmFileCommand
{
return this->HandleWriteCommand(args, true);
}
else if ( subCommand == "DOWNLOAD" )
{
return this->HandleDownloadCommand(args);
}
else if ( subCommand == "READ" )
{
return this->HandleReadCommand(args);
@ -1869,5 +1878,168 @@ bool cmFileCommand::HandleCMakePathCommand(std::vector<std::string>
this->Makefile->AddDefinition(var, value.c_str());
return true;
}
#if defined(CMAKE_BUILD_WITH_CMAKE)
// Stuff for curl download
typedef std::vector<char> cmFileCommandVectorOfChar;
namespace{
size_t
cmFileCommandWriteMemoryCallback(void *ptr, size_t size, size_t nmemb,
void *data)
{
register int realsize = (int)(size * nmemb);
std::ofstream* fout = static_cast<std::ofstream*>(data);
const char* chPtr = static_cast<char*>(ptr);
fout->write(chPtr, realsize);
return realsize;
}
static size_t
cmFileCommandCurlDebugCallback(CURL *, curl_infotype, char *chPtr,
size_t size, void *data)
{
cmFileCommandVectorOfChar *vec
= static_cast<cmFileCommandVectorOfChar*>(data);
vec->insert(vec->end(), chPtr, chPtr + size);
return size;
}
}
#endif
bool
cmFileCommand::HandleDownloadCommand(std::vector<std::string>
const& args)
{
#if defined(CMAKE_BUILD_WITH_CMAKE)
std::vector<std::string>::const_iterator i = args.begin();
if(args.size() < 3)
{
std::cout << args.size() << "\n";
this->SetError("FILE(DOWNLOAD url file) must be called with "
"at least three arguments.");
return false;
}
i++; // Get rid of subcommand
std::string url = *i;
i++;
std::string file = *i;
i++;
double timeout = 0;
std::string verboseLog;
std::string statusVar;
while(i != args.end())
{
if(*i == "TIMEOUT")
{
i++;
if(i != args.end())
{
timeout = atof(i->c_str());
}
else
{
this->SetError("FILE(DOWNLOAD url file TIMEOUT time) missing "
"time for TIMEOUT.");
return false;
}
}
else if(*i == "LOG")
{
i++;
if( i == args.end())
{
this->SetError("FILE(DOWNLOAD url file LOG VAR) missing "
"VAR for LOG.");
return false;
}
verboseLog = *i;
}
else if(*i == "STATUS")
{
i++;
if( i == args.end())
{
this->SetError("FILE(DOWNLOAD url file STATUS VAR) missing "
"VAR for STATUS.");
return false;
}
statusVar = *i;
}
i++;
}
std::cout << "log var: [" << verboseLog << "]\n";
std::cout << "Url: [" << url << "]\n";
std::cout << "file: [" << file << "]\n";
std::cout << "timeout: [" << timeout << "]\n";
std::ofstream fout(file.c_str());
if(!fout)
{
this->SetError("FILE(DOWNLOAD url file TIMEOUT time) can not open "
"file for write.");
return false;
}
CURL *curl;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(!curl)
{
this->SetError("FILE(DOWNLOAD ) error "
"initializing curl.");
return false;
}
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
cmFileCommandWriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
cmFileCommandCurlDebugCallback);
cmFileCommandVectorOfChar chunkDebug;
::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&fout);
::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
if(verboseLog.size())
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
}
if(timeout > 0)
{
curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout );
}
CURLcode res = curl_easy_perform(curl);
std::cout << "res = " << res << "\n";
/* always cleanup */
curl_easy_cleanup(curl);
if(statusVar.size())
{
this->Makefile->AddDefinition(statusVar.c_str(),
curl_easy_strerror(res));
}
curl_global_cleanup();
if(chunkDebug.size())
{
chunkDebug.push_back(0);
if(CURLE_OPERATION_TIMEOUTED == res)
{
std::string output = &*chunkDebug.begin();
if(verboseLog.size())
{
this->Makefile->AddDefinition(verboseLog.c_str(),
&*chunkDebug.begin());
}
}
this->Makefile->AddDefinition(verboseLog.c_str(),
&*chunkDebug.begin());
}
return true;
#else
this->SetError("FILE(DOWNLOAD ) "
"not supported in bootstrap cmake ");
return false;
#endif
}

View File

@ -84,6 +84,7 @@ public:
" file(RELATIVE_PATH variable directory file)\n"
" file(TO_CMAKE_PATH path result)\n"
" file(TO_NATIVE_PATH path result)\n"
" file(DOWNLOAD url file [TIMEOUT timeout] [STATUS status] [LOG log])\n"
"WRITE will write a message into a file called 'filename'. It "
"overwrites the file if it already exists, and creates the file "
"if it does not exist.\n"
@ -145,7 +146,12 @@ public:
" one argument.\n"
"TO_NATIVE_PATH works just like TO_CMAKE_PATH, but will convert from "
" a cmake style path into the native path style \\ for windows and / "
"for UNIX.";
"for UNIX.\n"
"DOWNLOAD will download the givin URL to the given file. "
"If LOG var is specified a log of the download will be put in var. "
"If STATUS var is specified the status of the operation will"
" be put in var. If TIMEOUT time is specified, the operation will "
"timeout after time seconds, time can be specified as a float.\n";
}
cmTypeMacro(cmFileCommand, cmCommand);
@ -180,6 +186,7 @@ protected:
const std::vector<std::string>& files,
const bool optional
);
bool HandleDownloadCommand(std::vector<std::string> const& args);
void GetTargetTypeFromString(const std::string& stype, int& itype) const;
bool HandleInstallDestination(cmFileInstaller& installer,
std::string& destination);