ExternalProject: retry download on recoverable errors
In order to shorten the download failure of ExternalProject download
steps, a download retry is only done when a recoverable network
error is encountered.
diff --git a/Modules/ExternalProject-download.cmake.in b/Modules/ExternalProject-download.cmake.in
index 99fb917..587e3cc 100644
--- a/Modules/ExternalProject-download.cmake.in
+++ b/Modules/ExternalProject-download.cmake.in
@@ -107,19 +107,23 @@
dst='@LOCAL@'
timeout='@TIMEOUT_MSG@'"
)
-
+set(download_retry_codes 7 6 8 15)
+set(skip_url_list)
+set(status_code)
foreach(i RANGE ${retry_number})
- sleep_before_download(${i})
-
+ if(status_code IN_LIST download_retry_codes)
+ sleep_before_download(${i})
+ endif()
foreach(url @REMOTE@)
- message(STATUS "Using src='${url}'")
+ if(NOT url IN_LIST skip_url_list)
+ message(STATUS "Using src='${url}'")
- @TLS_VERIFY_CODE@
- @TLS_CAINFO_CODE@
- @NETRC_CODE@
- @NETRC_FILE_CODE@
+ @TLS_VERIFY_CODE@
+ @TLS_CAINFO_CODE@
+ @NETRC_CODE@
+ @NETRC_FILE_CODE@
- file(
+ file(
DOWNLOAD
"${url}" "@LOCAL@"
@SHOW_PROGRESS@
@@ -128,31 +132,36 @@
LOG log
@USERPWD_ARGS@
@HTTP_HEADERS_ARGS@
- )
+ )
- list(GET status 0 status_code)
- list(GET status 1 status_string)
+ list(GET status 0 status_code)
+ list(GET status 1 status_string)
- if(status_code EQUAL 0)
- check_file_hash(has_hash hash_is_good)
- if(has_hash AND NOT hash_is_good)
- message(STATUS "Hash mismatch, removing...")
- file(REMOVE "@LOCAL@")
+ if(status_code EQUAL 0)
+ check_file_hash(has_hash hash_is_good)
+ if(has_hash AND NOT hash_is_good)
+ message(STATUS "Hash mismatch, removing...")
+ file(REMOVE "@LOCAL@")
+ else()
+ message(STATUS "Downloading... done")
+ return()
+ endif()
else()
- message(STATUS "Downloading... done")
- return()
+ string(APPEND logFailedURLs "error: downloading '${url}' failed
+ status_code: ${status_code}
+ status_string: ${status_string}
+ log:
+ --- LOG BEGIN ---
+ ${log}
+ --- LOG END ---
+ "
+ )
+ if(NOT status_code IN_LIST download_retry_codes)
+ list(APPEND skip_url_list "${url}")
+ break()
endif()
- else()
- string(APPEND logFailedURLs "error: downloading '${url}' failed
- status_code: ${status_code}
- status_string: ${status_string}
- log:
- --- LOG BEGIN ---
- ${log}
- --- LOG END ---
- "
- )
endif()
+ endif()
endforeach()
endforeach()
diff --git a/Tests/RunCMake/ExternalProject/DownloadTimeout-build-result.txt b/Tests/RunCMake/ExternalProject/DownloadTimeout-build-result.txt
new file mode 100644
index 0000000..c20fd86
--- /dev/null
+++ b/Tests/RunCMake/ExternalProject/DownloadTimeout-build-result.txt
@@ -0,0 +1 @@
+^[^0]
diff --git a/Tests/RunCMake/ExternalProject/DownloadTimeout-build-stderr.txt b/Tests/RunCMake/ExternalProject/DownloadTimeout-build-stderr.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/ExternalProject/DownloadTimeout-build-stderr.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/ExternalProject/DownloadTimeout.cmake b/Tests/RunCMake/ExternalProject/DownloadTimeout.cmake
new file mode 100644
index 0000000..c90b4ba
--- /dev/null
+++ b/Tests/RunCMake/ExternalProject/DownloadTimeout.cmake
@@ -0,0 +1,5 @@
+include(ExternalProject)
+set(source_dir "${CMAKE_CURRENT_BINARY_DIR}/DownloadTimeout")
+file(REMOVE_RECURSE "${source_dir}")
+file(MAKE_DIRECTORY "${source_dir}")
+ExternalProject_Add(MyProj URL "http://cmake.org/invalid_file.tar.gz")
diff --git a/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake b/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake
index 0d1da26..4d23bf8 100644
--- a/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake
@@ -38,6 +38,7 @@
if(NOT RunCMake_GENERATOR MATCHES "Visual Studio")
__ep_test_with_build(LogOutputOnFailure)
__ep_test_with_build(LogOutputOnFailureMerged)
+ __ep_test_with_build(DownloadTimeout)
endif()
# We can't test the substitution when using the old MSYS due to