summaryrefslogtreecommitdiffstats
path: root/Modules/ExternalProject-download.cmake.in
diff options
context:
space:
mode:
authorRuslan Baratov <ruslan_baratov@yahoo.com>2016-05-19 13:35:01 (GMT)
committerBrad King <brad.king@kitware.com>2016-05-19 15:20:50 (GMT)
commit89113e125d95fc24eaaec59edaa00b6d428111f5 (patch)
treeacd7056658794f514a5d041fef18fb8d409721eb /Modules/ExternalProject-download.cmake.in
parente7d5e4b4bf864fa779e2fc90dfb352588bf82246 (diff)
downloadCMake-89113e125d95fc24eaaec59edaa00b6d428111f5.zip
CMake-89113e125d95fc24eaaec59edaa00b6d428111f5.tar.gz
CMake-89113e125d95fc24eaaec59edaa00b6d428111f5.tar.bz2
ExternalProject: Re-implement download logic as a dedicated script
Move the content to a `ExternalProject-download.cmake.in` file and use `configure_file` to generate the final script. Retry logic was not working before because similar script trigger FATAL_ERROR if 'file(DOWNLOAD ...)' exits with nonzero 'status_code'. FATAL_ERROR makes the whole chain of commands stop and '_ep_write_verifyfile_script' retry logic was not used in fact. Default retry number set to 5 with pauses 0, 5, 5, 15, 60 seconds. Some space left for future improvements if needed (90, 300, 1200=20min). Can be controlled by user.
Diffstat (limited to 'Modules/ExternalProject-download.cmake.in')
-rw-r--r--Modules/ExternalProject-download.cmake.in161
1 files changed, 161 insertions, 0 deletions
diff --git a/Modules/ExternalProject-download.cmake.in b/Modules/ExternalProject-download.cmake.in
new file mode 100644
index 0000000..5b73cd8
--- /dev/null
+++ b/Modules/ExternalProject-download.cmake.in
@@ -0,0 +1,161 @@
+#=============================================================================
+# Copyright 2008-2013 Kitware, Inc.
+# Copyright 2016 Ruslan Baratov
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+cmake_minimum_required(VERSION 3.5)
+
+function(check_file_hash has_hash hash_is_good)
+ if("${has_hash}" STREQUAL "")
+ message(FATAL_ERROR "has_hash Can't be empty")
+ endif()
+
+ if("${hash_is_good}" STREQUAL "")
+ message(FATAL_ERROR "hash_is_good Can't be empty")
+ endif()
+
+ if("@ALGO@" STREQUAL "")
+ # No check
+ set("${has_hash}" FALSE PARENT_SCOPE)
+ set("${hash_is_good}" FALSE PARENT_SCOPE)
+ return()
+ endif()
+
+ set("${has_hash}" TRUE PARENT_SCOPE)
+
+ message(STATUS "verifying file...
+ file='@LOCAL@'")
+
+ file("@ALGO@" "@LOCAL@" actual_value)
+
+ if(NOT "${actual_value}" STREQUAL "@EXPECT_VALUE@")
+ set("${hash_is_good}" FALSE PARENT_SCOPE)
+ message(STATUS "@ALGO@ hash of
+ @LOCAL@
+ does not match expected value
+ expected: '@EXPECT_VALUE@'
+ actual: '${actual_value}'")
+ else()
+ set("${hash_is_good}" TRUE PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(sleep_before_download attempt)
+ if(attempt EQUAL 0)
+ return()
+ endif()
+
+ if(attempt EQUAL 1)
+ message(STATUS "Retrying...")
+ return()
+ endif()
+
+ set(sleep_seconds 0)
+
+ if(attempt EQUAL 2)
+ set(sleep_seconds 5)
+ elseif(attempt EQUAL 3)
+ set(sleep_seconds 5)
+ elseif(attempt EQUAL 4)
+ set(sleep_seconds 15)
+ elseif(attempt EQUAL 5)
+ set(sleep_seconds 60)
+ elseif(attempt EQUAL 6)
+ set(sleep_seconds 90)
+ elseif(attempt EQUAL 7)
+ set(sleep_seconds 300)
+ else()
+ set(sleep_seconds 1200)
+ endif()
+
+ message(STATUS "Retry after ${sleep_seconds} seconds (attempt #${attempt}) ...")
+
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep "${sleep_seconds}")
+endfunction()
+
+if("@LOCAL@" STREQUAL "")
+ message(FATAL_ERROR "LOCAL can't be empty")
+endif()
+
+if("@REMOTE@" STREQUAL "")
+ message(FATAL_ERROR "REMOTE can't be empty")
+endif()
+
+if(EXISTS "@LOCAL@")
+ check_file_hash(has_hash hash_is_good)
+ if(has_hash)
+ if(hash_is_good)
+ message(STATUS "File already exists and hash match (skip download):
+ file='@LOCAL@'
+ @ALGO@='@EXPECT_VALUE@'"
+ )
+ return()
+ else()
+ message(STATUS "File already exists but hash mismatch. Removing...")
+ file(REMOVE "@LOCAL@")
+ endif()
+ else()
+ message(STATUS "File already exists but no hash specified (use URL_HASH):
+ file='@LOCAL@'
+Old file will be removed and new file downloaded from URL."
+ )
+ file(REMOVE "@LOCAL@")
+ endif()
+endif()
+
+set(retry_number 5)
+
+foreach(i RANGE ${retry_number})
+ sleep_before_download(${i})
+
+ message(STATUS "downloading...
+ src='@REMOTE@'
+ dst='@LOCAL@'
+ timeout='@TIMEOUT_MSG@'")
+
+ @TLS_VERIFY_CODE@
+ @TLS_CAINFO_CODE@
+
+ file(
+ DOWNLOAD
+ "@REMOTE@" "@LOCAL@"
+ @SHOW_PROGRESS@
+ @TIMEOUT_ARGS@
+ STATUS status
+ LOG log
+ )
+
+ 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@")
+ else()
+ message(STATUS "Downloading... done")
+ return()
+ endif()
+ else()
+ message("error: downloading '@REMOTE@' failed
+ status_code: ${status_code}
+ status_string: ${status_string}
+ log:
+ --- LOG BEGIN ---
+ ${log}
+ --- LOG END ---"
+ )
+ endif()
+endforeach()
+
+message(FATAL_ERROR "Downloading failed")