Merge branch 'improve-file-download'
Conflicts: Modules/ExternalProject.cmake
This commit is contained in:
commit
0d07e4379e
|
@ -21,6 +21,7 @@
|
||||||
# [GIT_REPOSITORY url] # URL of git repo
|
# [GIT_REPOSITORY url] # URL of git repo
|
||||||
# [GIT_TAG tag] # Git branch name, commit id or tag
|
# [GIT_TAG tag] # Git branch name, commit id or tag
|
||||||
# [URL /.../src.tgz] # Full path or URL of source
|
# [URL /.../src.tgz] # Full path or URL of source
|
||||||
|
# [URL_MD5 md5] # MD5 checksum of file at URL
|
||||||
# [TIMEOUT seconds] # Time allowed for file download operations
|
# [TIMEOUT seconds] # Time allowed for file download operations
|
||||||
# #--Update/Patch step----------
|
# #--Update/Patch step----------
|
||||||
# [UPDATE_COMMAND cmd...] # Source work-tree update command
|
# [UPDATE_COMMAND cmd...] # Source work-tree update command
|
||||||
|
@ -115,19 +116,19 @@
|
||||||
# License text for the above reference.)
|
# License text for the above reference.)
|
||||||
|
|
||||||
# Pre-compute a regex to match documented keywords for each command.
|
# Pre-compute a regex to match documented keywords for each command.
|
||||||
file(STRINGS "${CMAKE_CURRENT_LIST_FILE}" lines LIMIT_COUNT 100
|
file(STRINGS "${CMAKE_CURRENT_LIST_FILE}" lines LIMIT_COUNT 103
|
||||||
REGEX "^# ( \\[[A-Z_]+ [^]]*\\] +#.*$|[A-Za-z_]+\\()")
|
REGEX "^# ( \\[[A-Z0-9_]+ [^]]*\\] +#.*$|[A-Za-z0-9_]+\\()")
|
||||||
foreach(line IN LISTS lines)
|
foreach(line IN LISTS lines)
|
||||||
if("${line}" MATCHES "^# [A-Za-z_]+\\(")
|
if("${line}" MATCHES "^# [A-Za-z0-9_]+\\(")
|
||||||
if(_ep_func)
|
if(_ep_func)
|
||||||
set(_ep_keywords_${_ep_func} "${_ep_keywords_${_ep_func}})$")
|
set(_ep_keywords_${_ep_func} "${_ep_keywords_${_ep_func}})$")
|
||||||
endif()
|
endif()
|
||||||
string(REGEX REPLACE "^# ([A-Za-z_]+)\\(.*" "\\1" _ep_func "${line}")
|
string(REGEX REPLACE "^# ([A-Za-z0-9_]+)\\(.*" "\\1" _ep_func "${line}")
|
||||||
#message("function [${_ep_func}]")
|
#message("function [${_ep_func}]")
|
||||||
set(_ep_keywords_${_ep_func} "^(")
|
set(_ep_keywords_${_ep_func} "^(")
|
||||||
set(_ep_keyword_sep)
|
set(_ep_keyword_sep)
|
||||||
else()
|
else()
|
||||||
string(REGEX REPLACE "^# \\[([A-Z_]+) .*" "\\1" _ep_key "${line}")
|
string(REGEX REPLACE "^# \\[([A-Z0-9_]+) .*" "\\1" _ep_key "${line}")
|
||||||
#message(" keyword [${_ep_key}]")
|
#message(" keyword [${_ep_key}]")
|
||||||
set(_ep_keywords_${_ep_func}
|
set(_ep_keywords_${_ep_func}
|
||||||
"${_ep_keywords_${_ep_func}}${_ep_keyword_sep}${_ep_key}")
|
"${_ep_keywords_${_ep_func}}${_ep_keyword_sep}${_ep_key}")
|
||||||
|
@ -152,7 +153,7 @@ function(_ep_parse_arguments f name ns args)
|
||||||
foreach(arg IN LISTS args)
|
foreach(arg IN LISTS args)
|
||||||
set(is_value 1)
|
set(is_value 1)
|
||||||
|
|
||||||
if(arg MATCHES "^[A-Z][A-Z_][A-Z_]+$" AND
|
if(arg MATCHES "^[A-Z][A-Z0-9_][A-Z0-9_]+$" AND
|
||||||
NOT ((arg STREQUAL "${key}") AND (key STREQUAL "COMMAND")) AND
|
NOT ((arg STREQUAL "${key}") AND (key STREQUAL "COMMAND")) AND
|
||||||
NOT arg MATCHES "^(TRUE|FALSE)$")
|
NOT arg MATCHES "^(TRUE|FALSE)$")
|
||||||
if(_ep_keywords_${f} AND arg MATCHES "${_ep_keywords_${f}}")
|
if(_ep_keywords_${f} AND arg MATCHES "${_ep_keywords_${f}}")
|
||||||
|
@ -264,7 +265,7 @@ endif()
|
||||||
endfunction(_ep_write_gitclone_script)
|
endfunction(_ep_write_gitclone_script)
|
||||||
|
|
||||||
|
|
||||||
function(_ep_write_downloadfile_script script_filename remote local timeout)
|
function(_ep_write_downloadfile_script script_filename remote local timeout md5)
|
||||||
if(timeout)
|
if(timeout)
|
||||||
set(timeout_args TIMEOUT ${timeout})
|
set(timeout_args TIMEOUT ${timeout})
|
||||||
set(timeout_msg "${timeout} seconds")
|
set(timeout_msg "${timeout} seconds")
|
||||||
|
@ -273,6 +274,12 @@ function(_ep_write_downloadfile_script script_filename remote local timeout)
|
||||||
set(timeout_msg "none")
|
set(timeout_msg "none")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(md5)
|
||||||
|
set(md5_args EXPECTED_MD5 ${md5})
|
||||||
|
else()
|
||||||
|
set(md5_args "# no EXPECTED_MD5")
|
||||||
|
endif()
|
||||||
|
|
||||||
file(WRITE ${script_filename}
|
file(WRITE ${script_filename}
|
||||||
"message(STATUS \"downloading...
|
"message(STATUS \"downloading...
|
||||||
src='${remote}'
|
src='${remote}'
|
||||||
|
@ -282,6 +289,8 @@ function(_ep_write_downloadfile_script script_filename remote local timeout)
|
||||||
file(DOWNLOAD
|
file(DOWNLOAD
|
||||||
\"${remote}\"
|
\"${remote}\"
|
||||||
\"${local}\"
|
\"${local}\"
|
||||||
|
SHOW_PROGRESS
|
||||||
|
${md5_args}
|
||||||
${timeout_args}
|
${timeout_args}
|
||||||
STATUS status
|
STATUS status
|
||||||
LOG log)
|
LOG log)
|
||||||
|
@ -304,6 +313,51 @@ message(STATUS \"downloading... done\")
|
||||||
endfunction(_ep_write_downloadfile_script)
|
endfunction(_ep_write_downloadfile_script)
|
||||||
|
|
||||||
|
|
||||||
|
function(_ep_write_verifyfile_script script_filename local md5)
|
||||||
|
file(WRITE ${script_filename}
|
||||||
|
"message(STATUS \"verifying file...
|
||||||
|
file='${local}'\")
|
||||||
|
|
||||||
|
set(verified 0)
|
||||||
|
|
||||||
|
# If an expected md5 checksum exists, compare against it:
|
||||||
|
#
|
||||||
|
if(NOT \"${md5}\" STREQUAL \"\")
|
||||||
|
execute_process(COMMAND \${CMAKE_COMMAND} -E md5sum \"${local}\"
|
||||||
|
OUTPUT_VARIABLE ov
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
RESULT_VARIABLE rv)
|
||||||
|
|
||||||
|
if(NOT rv EQUAL 0)
|
||||||
|
message(FATAL_ERROR \"error: computing md5sum of '${local}' failed\")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(REGEX MATCH \"^([0-9A-Fa-f]+)\" md5_actual \"\${ov}\")
|
||||||
|
|
||||||
|
string(TOLOWER \"\${md5_actual}\" md5_actual)
|
||||||
|
string(TOLOWER \"${md5}\" md5)
|
||||||
|
|
||||||
|
if(NOT \"\${md5}\" STREQUAL \"\${md5_actual}\")
|
||||||
|
message(FATAL_ERROR \"error: md5sum of '${local}' does not match expected value
|
||||||
|
md5_expected: \${md5}
|
||||||
|
md5_actual: \${md5_actual}
|
||||||
|
\")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(verified 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(verified)
|
||||||
|
message(STATUS \"verifying file... done\")
|
||||||
|
else()
|
||||||
|
message(STATUS \"verifying file... warning: did not verify file - no URL_MD5 checksum argument? corrupt file?\")
|
||||||
|
endif()
|
||||||
|
"
|
||||||
|
)
|
||||||
|
|
||||||
|
endfunction(_ep_write_verifyfile_script)
|
||||||
|
|
||||||
|
|
||||||
function(_ep_write_extractfile_script script_filename filename directory)
|
function(_ep_write_extractfile_script script_filename filename directory)
|
||||||
set(args "")
|
set(args "")
|
||||||
|
|
||||||
|
@ -797,9 +851,10 @@ function(_ep_add_download_command name)
|
||||||
list(APPEND depends ${stamp_dir}/${name}-gitinfo.txt)
|
list(APPEND depends ${stamp_dir}/${name}-gitinfo.txt)
|
||||||
elseif(url)
|
elseif(url)
|
||||||
get_filename_component(work_dir "${source_dir}" PATH)
|
get_filename_component(work_dir "${source_dir}" PATH)
|
||||||
|
get_property(md5 TARGET ${name} PROPERTY _EP_URL_MD5)
|
||||||
set(repository "external project URL")
|
set(repository "external project URL")
|
||||||
set(module "${url}")
|
set(module "${url}")
|
||||||
set(tag "")
|
set(tag "${md5}")
|
||||||
configure_file(
|
configure_file(
|
||||||
"${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
|
"${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
|
||||||
"${stamp_dir}/${name}-urlinfo.txt"
|
"${stamp_dir}/${name}-urlinfo.txt"
|
||||||
|
@ -820,14 +875,16 @@ function(_ep_add_download_command name)
|
||||||
endif()
|
endif()
|
||||||
set(file ${download_dir}/${fname})
|
set(file ${download_dir}/${fname})
|
||||||
get_property(timeout TARGET ${name} PROPERTY _EP_TIMEOUT)
|
get_property(timeout TARGET ${name} PROPERTY _EP_TIMEOUT)
|
||||||
_ep_write_downloadfile_script("${stamp_dir}/download-${name}.cmake" "${url}" "${file}" "${timeout}")
|
_ep_write_downloadfile_script("${stamp_dir}/download-${name}.cmake" "${url}" "${file}" "${timeout}" "${md5}")
|
||||||
set(cmd ${CMAKE_COMMAND} -P ${stamp_dir}/download-${name}.cmake
|
set(cmd ${CMAKE_COMMAND} -P ${stamp_dir}/download-${name}.cmake
|
||||||
COMMAND)
|
COMMAND)
|
||||||
set(comment "Performing download step (download and extract) for '${name}'")
|
set(comment "Performing download step (download, verify and extract) for '${name}'")
|
||||||
else()
|
else()
|
||||||
set(file "${url}")
|
set(file "${url}")
|
||||||
set(comment "Performing download step (extract) for '${name}'")
|
set(comment "Performing download step (verify and extract) for '${name}'")
|
||||||
endif()
|
endif()
|
||||||
|
_ep_write_verifyfile_script("${stamp_dir}/verify-${name}.cmake" "${file}" "${md5}")
|
||||||
|
list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/verify-${name}.cmake)
|
||||||
# TODO: Support other archive formats.
|
# TODO: Support other archive formats.
|
||||||
_ep_write_extractfile_script("${stamp_dir}/extract-${name}.cmake" "${file}" "${source_dir}")
|
_ep_write_extractfile_script("${stamp_dir}/extract-${name}.cmake" "${file}" "${source_dir}")
|
||||||
list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/extract-${name}.cmake)
|
list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/extract-${name}.cmake)
|
||||||
|
|
|
@ -2450,7 +2450,8 @@ namespace{
|
||||||
fout->write(chPtr, realsize);
|
fout->write(chPtr, realsize);
|
||||||
return realsize;
|
return realsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
cmFileCommandCurlDebugCallback(CURL *, curl_infotype, char *chPtr,
|
cmFileCommandCurlDebugCallback(CURL *, curl_infotype, char *chPtr,
|
||||||
size_t size, void *data)
|
size_t size, void *data)
|
||||||
|
@ -2463,6 +2464,72 @@ namespace{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class cURLProgressHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cURLProgressHelper(cmFileCommand *fc)
|
||||||
|
{
|
||||||
|
this->CurrentPercentage = -1;
|
||||||
|
this->FileCommand = fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UpdatePercentage(double value, double total, std::string &status)
|
||||||
|
{
|
||||||
|
int OldPercentage = this->CurrentPercentage;
|
||||||
|
|
||||||
|
if (0.0 == total)
|
||||||
|
{
|
||||||
|
this->CurrentPercentage = 100;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->CurrentPercentage = static_cast<int>(value/total*100.0 + 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool updated = (OldPercentage != this->CurrentPercentage);
|
||||||
|
|
||||||
|
if (updated)
|
||||||
|
{
|
||||||
|
cmOStringStream oss;
|
||||||
|
oss << "[download " << this->CurrentPercentage << "% complete]";
|
||||||
|
status = oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmFileCommand *GetFileCommand()
|
||||||
|
{
|
||||||
|
return this->FileCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int CurrentPercentage;
|
||||||
|
cmFileCommand *FileCommand;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmFileCommandCurlProgressCallback(void *clientp,
|
||||||
|
double dltotal, double dlnow,
|
||||||
|
double ultotal, double ulnow)
|
||||||
|
{
|
||||||
|
cURLProgressHelper *helper =
|
||||||
|
reinterpret_cast<cURLProgressHelper *>(clientp);
|
||||||
|
|
||||||
|
static_cast<void>(ultotal);
|
||||||
|
static_cast<void>(ulnow);
|
||||||
|
|
||||||
|
std::string status;
|
||||||
|
if (helper->UpdatePercentage(dlnow, dltotal, status))
|
||||||
|
{
|
||||||
|
cmFileCommand *fc = helper->GetFileCommand();
|
||||||
|
cmMakefile *mf = fc->GetMakefile();
|
||||||
|
mf->DisplayStatus(status.c_str(), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2476,8 +2543,8 @@ namespace {
|
||||||
cURLEasyGuard(CURL * easy)
|
cURLEasyGuard(CURL * easy)
|
||||||
: Easy(easy)
|
: Easy(easy)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~cURLEasyGuard(void)
|
~cURLEasyGuard(void)
|
||||||
{
|
{
|
||||||
if (this->Easy)
|
if (this->Easy)
|
||||||
{
|
{
|
||||||
|
@ -2498,6 +2565,7 @@ namespace {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
cmFileCommand::HandleDownloadCommand(std::vector<std::string>
|
cmFileCommand::HandleDownloadCommand(std::vector<std::string>
|
||||||
const& args)
|
const& args)
|
||||||
|
@ -2515,9 +2583,13 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
|
||||||
++i;
|
++i;
|
||||||
std::string file = *i;
|
std::string file = *i;
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
long timeout = 0;
|
long timeout = 0;
|
||||||
std::string verboseLog;
|
std::string verboseLog;
|
||||||
std::string statusVar;
|
std::string statusVar;
|
||||||
|
std::string expectedMD5sum;
|
||||||
|
bool showProgress = false;
|
||||||
|
|
||||||
while(i != args.end())
|
while(i != args.end())
|
||||||
{
|
{
|
||||||
if(*i == "TIMEOUT")
|
if(*i == "TIMEOUT")
|
||||||
|
@ -2556,9 +2628,65 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
|
||||||
}
|
}
|
||||||
statusVar = *i;
|
statusVar = *i;
|
||||||
}
|
}
|
||||||
|
else if(*i == "EXPECTED_MD5")
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
if( i == args.end())
|
||||||
|
{
|
||||||
|
this->SetError("FILE(DOWNLOAD url file EXPECTED_MD5 sum) missing "
|
||||||
|
"sum value for EXPECTED_MD5.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
expectedMD5sum = cmSystemTools::LowerCase(*i);
|
||||||
|
}
|
||||||
|
else if(*i == "SHOW_PROGRESS")
|
||||||
|
{
|
||||||
|
showProgress = true;
|
||||||
|
}
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If file exists already, and caller specified an expected md5 sum,
|
||||||
|
// and the existing file already has the expected md5 sum, then simply
|
||||||
|
// return.
|
||||||
|
//
|
||||||
|
if(cmSystemTools::FileExists(file.c_str()) &&
|
||||||
|
!expectedMD5sum.empty())
|
||||||
|
{
|
||||||
|
char computedMD5[32];
|
||||||
|
|
||||||
|
if (!cmSystemTools::ComputeFileMD5(file.c_str(), computedMD5))
|
||||||
|
{
|
||||||
|
this->SetError("FILE(DOWNLOAD ) error; cannot compute MD5 sum on "
|
||||||
|
"pre-existing file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string actualMD5sum = cmSystemTools::LowerCase(
|
||||||
|
std::string(computedMD5, 32));
|
||||||
|
|
||||||
|
if (expectedMD5sum == actualMD5sum)
|
||||||
|
{
|
||||||
|
this->Makefile->DisplayStatus(
|
||||||
|
"FILE(DOWNLOAD ) returning early: file already exists with "
|
||||||
|
"expected MD5 sum", -1);
|
||||||
|
|
||||||
|
if(statusVar.size())
|
||||||
|
{
|
||||||
|
cmOStringStream result;
|
||||||
|
result << (int)0 << ";\""
|
||||||
|
"returning early: file already exists with expected MD5 sum\"";
|
||||||
|
this->Makefile->AddDefinition(statusVar.c_str(),
|
||||||
|
result.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure parent directory exists so we can write to the file
|
||||||
|
// as we receive downloaded bits from curl...
|
||||||
|
//
|
||||||
std::string dir = cmSystemTools::GetFilenamePath(file.c_str());
|
std::string dir = cmSystemTools::GetFilenamePath(file.c_str());
|
||||||
if(!cmSystemTools::FileExists(dir.c_str()) &&
|
if(!cmSystemTools::FileExists(dir.c_str()) &&
|
||||||
!cmSystemTools::MakeDirectory(dir.c_str()))
|
!cmSystemTools::MakeDirectory(dir.c_str()))
|
||||||
|
@ -2577,6 +2705,7 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
|
||||||
"file for write.");
|
"file for write.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
::CURL *curl;
|
::CURL *curl;
|
||||||
::curl_global_init(CURL_GLOBAL_DEFAULT);
|
::curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
curl = ::curl_easy_init();
|
curl = ::curl_easy_init();
|
||||||
|
@ -2592,28 +2721,31 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
|
||||||
::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||||
if (res != CURLE_OK)
|
if (res != CURLE_OK)
|
||||||
{
|
{
|
||||||
std::string errstring = "FILE(DOWNLOAD ) error; cannot set url: ";
|
std::string errstring = "FILE(DOWNLOAD ) error; cannot set url: ";
|
||||||
errstring += ::curl_easy_strerror(res);
|
errstring += ::curl_easy_strerror(res);
|
||||||
|
this->SetError(errstring.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
|
res = ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
|
||||||
cmFileCommandWriteMemoryCallback);
|
cmFileCommandWriteMemoryCallback);
|
||||||
if (res != CURLE_OK)
|
if (res != CURLE_OK)
|
||||||
{
|
{
|
||||||
std::string errstring =
|
std::string errstring =
|
||||||
"FILE(DOWNLOAD ) error; cannot set write function: ";
|
"FILE(DOWNLOAD ) error; cannot set write function: ";
|
||||||
errstring += ::curl_easy_strerror(res);
|
errstring += ::curl_easy_strerror(res);
|
||||||
|
this->SetError(errstring.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
|
res = ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
|
||||||
cmFileCommandCurlDebugCallback);
|
cmFileCommandCurlDebugCallback);
|
||||||
if (res != CURLE_OK)
|
if (res != CURLE_OK)
|
||||||
{
|
{
|
||||||
std::string errstring =
|
std::string errstring =
|
||||||
"FILE(DOWNLOAD ) error; cannot set debug function: ";
|
"FILE(DOWNLOAD ) error; cannot set debug function: ";
|
||||||
errstring += ::curl_easy_strerror(res);
|
errstring += ::curl_easy_strerror(res);
|
||||||
|
this->SetError(errstring.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2625,14 +2757,25 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
|
||||||
{
|
{
|
||||||
std::string errstring = "FILE(DOWNLOAD ) error; cannot set write data: ";
|
std::string errstring = "FILE(DOWNLOAD ) error; cannot set write data: ";
|
||||||
errstring += ::curl_easy_strerror(res);
|
errstring += ::curl_easy_strerror(res);
|
||||||
|
this->SetError(errstring.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
|
res = ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
|
||||||
if (res != CURLE_OK)
|
if (res != CURLE_OK)
|
||||||
{
|
{
|
||||||
std::string errstring = "FILE(DOWNLOAD ) error; cannot set write data: ";
|
std::string errstring = "FILE(DOWNLOAD ) error; cannot set debug data: ";
|
||||||
errstring += ::curl_easy_strerror(res);
|
errstring += ::curl_easy_strerror(res);
|
||||||
|
this->SetError(errstring.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
if (res != CURLE_OK)
|
||||||
|
{
|
||||||
|
std::string errstring = "FILE(DOWNLOAD ) error; cannot set follow-redirect option: ";
|
||||||
|
errstring += ::curl_easy_strerror(res);
|
||||||
|
this->SetError(errstring.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2644,24 +2787,70 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
|
||||||
{
|
{
|
||||||
std::string errstring = "FILE(DOWNLOAD ) error; cannot set verbose: ";
|
std::string errstring = "FILE(DOWNLOAD ) error; cannot set verbose: ";
|
||||||
errstring += ::curl_easy_strerror(res);
|
errstring += ::curl_easy_strerror(res);
|
||||||
|
this->SetError(errstring.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(timeout > 0)
|
if(timeout > 0)
|
||||||
{
|
{
|
||||||
res = ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout );
|
res = ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout );
|
||||||
|
|
||||||
if (res != CURLE_OK)
|
if (res != CURLE_OK)
|
||||||
{
|
{
|
||||||
std::string errstring = "FILE(DOWNLOAD ) error; cannot set verbose: ";
|
std::string errstring = "FILE(DOWNLOAD ) error; cannot set timeout: ";
|
||||||
errstring += ::curl_easy_strerror(res);
|
errstring += ::curl_easy_strerror(res);
|
||||||
|
this->SetError(errstring.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Need the progress helper's scope to last through the duration of
|
||||||
|
// the curl_easy_perform call... so this object is declared at function
|
||||||
|
// scope intentionally, rather than inside the "if(showProgress)"
|
||||||
|
// block...
|
||||||
|
//
|
||||||
|
cURLProgressHelper helper(this);
|
||||||
|
|
||||||
|
if(showProgress)
|
||||||
|
{
|
||||||
|
res = ::curl_easy_setopt(curl,
|
||||||
|
CURLOPT_NOPROGRESS, 0);
|
||||||
|
if (res != CURLE_OK)
|
||||||
|
{
|
||||||
|
std::string errstring = "FILE(DOWNLOAD ) error; cannot set noprogress value: ";
|
||||||
|
errstring += ::curl_easy_strerror(res);
|
||||||
|
this->SetError(errstring.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ::curl_easy_setopt(curl,
|
||||||
|
CURLOPT_PROGRESSFUNCTION, cmFileCommandCurlProgressCallback);
|
||||||
|
if (res != CURLE_OK)
|
||||||
|
{
|
||||||
|
std::string errstring = "FILE(DOWNLOAD ) error; cannot set progress function: ";
|
||||||
|
errstring += ::curl_easy_strerror(res);
|
||||||
|
this->SetError(errstring.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ::curl_easy_setopt(curl,
|
||||||
|
CURLOPT_PROGRESSDATA, reinterpret_cast<void*>(&helper));
|
||||||
|
if (res != CURLE_OK)
|
||||||
|
{
|
||||||
|
std::string errstring = "FILE(DOWNLOAD ) error; cannot set progress data: ";
|
||||||
|
errstring += ::curl_easy_strerror(res);
|
||||||
|
this->SetError(errstring.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res = ::curl_easy_perform(curl);
|
res = ::curl_easy_perform(curl);
|
||||||
|
|
||||||
/* always cleanup */
|
/* always cleanup */
|
||||||
g_curl.release();
|
g_curl.release();
|
||||||
::curl_easy_cleanup(curl);
|
::curl_easy_cleanup(curl);
|
||||||
|
|
||||||
if(statusVar.size())
|
if(statusVar.size())
|
||||||
{
|
{
|
||||||
cmOStringStream result;
|
cmOStringStream result;
|
||||||
|
@ -2669,7 +2858,44 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
|
||||||
this->Makefile->AddDefinition(statusVar.c_str(),
|
this->Makefile->AddDefinition(statusVar.c_str(),
|
||||||
result.str().c_str());
|
result.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
::curl_global_cleanup();
|
::curl_global_cleanup();
|
||||||
|
|
||||||
|
// Explicitly flush/close so we can measure the md5 accurately.
|
||||||
|
//
|
||||||
|
fout.flush();
|
||||||
|
fout.close();
|
||||||
|
|
||||||
|
// Verify MD5 sum if requested:
|
||||||
|
//
|
||||||
|
if (!expectedMD5sum.empty())
|
||||||
|
{
|
||||||
|
char computedMD5[32];
|
||||||
|
|
||||||
|
if (!cmSystemTools::ComputeFileMD5(file.c_str(), computedMD5))
|
||||||
|
{
|
||||||
|
this->SetError("FILE(DOWNLOAD ) error; cannot compute MD5 sum on "
|
||||||
|
"downloaded file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string actualMD5sum = cmSystemTools::LowerCase(
|
||||||
|
std::string(computedMD5, 32));
|
||||||
|
|
||||||
|
if (expectedMD5sum != actualMD5sum)
|
||||||
|
{
|
||||||
|
cmOStringStream oss;
|
||||||
|
oss << "FILE(DOWNLOAD ) error; expected and actual MD5 sums differ"
|
||||||
|
<< std::endl
|
||||||
|
<< " for file: [" << file << "]" << std::endl
|
||||||
|
<< " expected MD5 sum: [" << expectedMD5sum << "]" << std::endl
|
||||||
|
<< " actual MD5 sum: [" << actualMD5sum << "]" << std::endl
|
||||||
|
;
|
||||||
|
this->SetError(oss.str().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(chunkDebug.size())
|
if(chunkDebug.size())
|
||||||
{
|
{
|
||||||
chunkDebug.push_back(0);
|
chunkDebug.push_back(0);
|
||||||
|
@ -2687,6 +2913,7 @@ cmFileCommand::HandleDownloadCommand(std::vector<std::string>
|
||||||
this->Makefile->AddDefinition(verboseLog.c_str(),
|
this->Makefile->AddDefinition(verboseLog.c_str(),
|
||||||
&*chunkDebug.begin());
|
&*chunkDebug.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
this->SetError("FILE(DOWNLOAD ) "
|
this->SetError("FILE(DOWNLOAD ) "
|
||||||
|
|
|
@ -80,7 +80,8 @@ public:
|
||||||
" file(RELATIVE_PATH variable directory file)\n"
|
" file(RELATIVE_PATH variable directory file)\n"
|
||||||
" file(TO_CMAKE_PATH path result)\n"
|
" file(TO_CMAKE_PATH path result)\n"
|
||||||
" file(TO_NATIVE_PATH path result)\n"
|
" file(TO_NATIVE_PATH path result)\n"
|
||||||
" file(DOWNLOAD url file [TIMEOUT timeout] [STATUS status] [LOG log])\n"
|
" file(DOWNLOAD url file [TIMEOUT timeout] [STATUS status] [LOG log]\n"
|
||||||
|
" [EXPECTED_MD5 sum] [SHOW_PROGRESS])\n"
|
||||||
"WRITE will write a message into a file called 'filename'. It "
|
"WRITE will write a message into a file called 'filename'. It "
|
||||||
"overwrites the file if it already exists, and creates the file "
|
"overwrites the file if it already exists, and creates the file "
|
||||||
"if it does not exist.\n"
|
"if it does not exist.\n"
|
||||||
|
@ -152,7 +153,12 @@ public:
|
||||||
"and the second element is a string value for the error. A 0 "
|
"and the second element is a string value for the error. A 0 "
|
||||||
"numeric error means no error in the operation. "
|
"numeric error means no error in the operation. "
|
||||||
"If TIMEOUT time is specified, the operation will "
|
"If TIMEOUT time is specified, the operation will "
|
||||||
"timeout after time seconds, time should be specified as an integer."
|
"timeout after time seconds, time should be specified as an integer. "
|
||||||
|
"If EXPECTED_MD5 sum is specified, the operation will verify that the "
|
||||||
|
"downloaded file's actual md5 sum matches the expected value. If it "
|
||||||
|
"does not match, the operation fails with an error. "
|
||||||
|
"If SHOW_PROGRESS is specified, progress information will be printed "
|
||||||
|
"as status messages until the operation is complete."
|
||||||
"\n"
|
"\n"
|
||||||
"The file() command also provides COPY and INSTALL signatures:\n"
|
"The file() command also provides COPY and INSTALL signatures:\n"
|
||||||
" file(<COPY|INSTALL> files... DESTINATION <dir>\n"
|
" file(<COPY|INSTALL> files... DESTINATION <dir>\n"
|
||||||
|
|
|
@ -28,6 +28,11 @@ AddCMakeTest(Math "")
|
||||||
AddCMakeTest(CMakeMinimumRequired "")
|
AddCMakeTest(CMakeMinimumRequired "")
|
||||||
AddCMakeTest(CompilerIdVendor "")
|
AddCMakeTest(CompilerIdVendor "")
|
||||||
|
|
||||||
|
AddCMakeTest(FileDownload "")
|
||||||
|
set_property(TEST CMake.FileDownload PROPERTY
|
||||||
|
PASS_REGULAR_EXPRESSION "file already exists with expected MD5 sum"
|
||||||
|
)
|
||||||
|
|
||||||
if(HAVE_ELF_H)
|
if(HAVE_ELF_H)
|
||||||
AddCMakeTest(ELF "")
|
AddCMakeTest(ELF "")
|
||||||
endif()
|
endif()
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 358 B |
|
@ -0,0 +1,41 @@
|
||||||
|
set(url "file://@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png")
|
||||||
|
set(dir "@CMAKE_CURRENT_BINARY_DIR@/downloads")
|
||||||
|
|
||||||
|
message(STATUS "FileDownload:1")
|
||||||
|
file(DOWNLOAD
|
||||||
|
${url}
|
||||||
|
${dir}/file1.png
|
||||||
|
TIMEOUT 2
|
||||||
|
)
|
||||||
|
|
||||||
|
message(STATUS "FileDownload:2")
|
||||||
|
file(DOWNLOAD
|
||||||
|
${url}
|
||||||
|
${dir}/file2.png
|
||||||
|
TIMEOUT 2
|
||||||
|
SHOW_PROGRESS
|
||||||
|
)
|
||||||
|
|
||||||
|
# Two calls in a row, exactly the same arguments.
|
||||||
|
# Since downloaded file should exist already for 2nd call,
|
||||||
|
# the 2nd call will short-circuit and return early...
|
||||||
|
#
|
||||||
|
if(EXISTS ${dir}/file3.png)
|
||||||
|
file(REMOVE ${dir}/file3.png)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "FileDownload:3")
|
||||||
|
file(DOWNLOAD
|
||||||
|
${url}
|
||||||
|
${dir}/file3.png
|
||||||
|
TIMEOUT 2
|
||||||
|
EXPECTED_MD5 d16778650db435bda3a8c3435c3ff5d1
|
||||||
|
)
|
||||||
|
|
||||||
|
message(STATUS "FileDownload:4")
|
||||||
|
file(DOWNLOAD
|
||||||
|
${url}
|
||||||
|
${dir}/file3.png
|
||||||
|
TIMEOUT 2
|
||||||
|
EXPECTED_MD5 d16778650db435bda3a8c3435c3ff5d1
|
||||||
|
)
|
|
@ -64,7 +64,9 @@ ExternalProject_Add(${proj}
|
||||||
SVN_REPOSITORY ""
|
SVN_REPOSITORY ""
|
||||||
SVN_REVISION ""
|
SVN_REVISION ""
|
||||||
TEST_COMMAND ""
|
TEST_COMMAND ""
|
||||||
|
TIMEOUT ""
|
||||||
URL ""
|
URL ""
|
||||||
|
URL_MD5 ""
|
||||||
UPDATE_COMMAND ""
|
UPDATE_COMMAND ""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -95,6 +97,7 @@ endif()
|
||||||
set(proj TutorialStep1-LocalTAR)
|
set(proj TutorialStep1-LocalTAR)
|
||||||
ExternalProject_Add(${proj}
|
ExternalProject_Add(${proj}
|
||||||
URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1.tar"
|
URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1.tar"
|
||||||
|
URL_MD5 a87c5b47c0201c09ddfe1d5738fdb1e3
|
||||||
LIST_SEPARATOR ::
|
LIST_SEPARATOR ::
|
||||||
PATCH_COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/Step1Patch.cmake
|
PATCH_COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/Step1Patch.cmake
|
||||||
CMAKE_GENERATOR "${CMAKE_GENERATOR}"
|
CMAKE_GENERATOR "${CMAKE_GENERATOR}"
|
||||||
|
@ -106,6 +109,7 @@ ExternalProject_Add(${proj}
|
||||||
set(proj TutorialStep1-LocalNoDirTAR)
|
set(proj TutorialStep1-LocalNoDirTAR)
|
||||||
ExternalProject_Add(${proj}
|
ExternalProject_Add(${proj}
|
||||||
URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1NoDir.tar"
|
URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1NoDir.tar"
|
||||||
|
URL_MD5 d09e3d370c5c908fa035c30939ee438e
|
||||||
LIST_SEPARATOR @@
|
LIST_SEPARATOR @@
|
||||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
|
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
|
||||||
-DTEST_LIST:STRING=1@@2@@3
|
-DTEST_LIST:STRING=1@@2@@3
|
||||||
|
@ -125,6 +129,7 @@ ExternalProject_Add_Step(${proj} mypatch
|
||||||
set(proj TutorialStep1-LocalTGZ)
|
set(proj TutorialStep1-LocalTGZ)
|
||||||
ExternalProject_Add(${proj}
|
ExternalProject_Add(${proj}
|
||||||
URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1.tgz"
|
URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1.tgz"
|
||||||
|
URL_MD5 38c648e817339c356f6be00eeed79bd0
|
||||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
|
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
|
||||||
INSTALL_COMMAND ""
|
INSTALL_COMMAND ""
|
||||||
)
|
)
|
||||||
|
@ -132,6 +137,7 @@ ExternalProject_Add(${proj}
|
||||||
set(proj TutorialStep1-LocalNoDirTGZ)
|
set(proj TutorialStep1-LocalNoDirTGZ)
|
||||||
ExternalProject_Add(${proj}
|
ExternalProject_Add(${proj}
|
||||||
URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1NoDir.tgz"
|
URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1NoDir.tgz"
|
||||||
|
URL_MD5 0b8182edcecdf40bf1c9d71d7d259f78
|
||||||
CMAKE_GENERATOR "${CMAKE_GENERATOR}"
|
CMAKE_GENERATOR "${CMAKE_GENERATOR}"
|
||||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||||
INSTALL_COMMAND ""
|
INSTALL_COMMAND ""
|
||||||
|
@ -210,6 +216,7 @@ if(do_cvs_tests)
|
||||||
ExternalProject_Add(${proj}
|
ExternalProject_Add(${proj}
|
||||||
SOURCE_DIR ${local_cvs_repo}
|
SOURCE_DIR ${local_cvs_repo}
|
||||||
URL ${CMAKE_CURRENT_SOURCE_DIR}/cvsrepo.tgz
|
URL ${CMAKE_CURRENT_SOURCE_DIR}/cvsrepo.tgz
|
||||||
|
URL_MD5 55fc85825ffdd9ed2597123c68b79f7e
|
||||||
BUILD_COMMAND ""
|
BUILD_COMMAND ""
|
||||||
CONFIGURE_COMMAND "${CVS_EXECUTABLE}" --version
|
CONFIGURE_COMMAND "${CVS_EXECUTABLE}" --version
|
||||||
INSTALL_COMMAND ""
|
INSTALL_COMMAND ""
|
||||||
|
@ -308,6 +315,7 @@ if(do_svn_tests)
|
||||||
ExternalProject_Add(${proj}
|
ExternalProject_Add(${proj}
|
||||||
SOURCE_DIR ${local_svn_repo}
|
SOURCE_DIR ${local_svn_repo}
|
||||||
URL ${CMAKE_CURRENT_SOURCE_DIR}/svnrepo.tgz
|
URL ${CMAKE_CURRENT_SOURCE_DIR}/svnrepo.tgz
|
||||||
|
URL_MD5 2f468be4ed1fa96377fca0cc830819c4
|
||||||
BUILD_COMMAND ""
|
BUILD_COMMAND ""
|
||||||
CONFIGURE_COMMAND "${Subversion_SVN_EXECUTABLE}" --version
|
CONFIGURE_COMMAND "${Subversion_SVN_EXECUTABLE}" --version
|
||||||
INSTALL_COMMAND ""
|
INSTALL_COMMAND ""
|
||||||
|
|
Loading…
Reference in New Issue