1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4cmake_minimum_required(VERSION 3.5)
5
6function(check_file_hash has_hash hash_is_good)
7  if("${has_hash}" STREQUAL "")
8    message(FATAL_ERROR "has_hash Can't be empty")
9  endif()
10
11  if("${hash_is_good}" STREQUAL "")
12    message(FATAL_ERROR "hash_is_good Can't be empty")
13  endif()
14
15  if("@ALGO@" STREQUAL "")
16    # No check
17    set("${has_hash}" FALSE PARENT_SCOPE)
18    set("${hash_is_good}" FALSE PARENT_SCOPE)
19    return()
20  endif()
21
22  set("${has_hash}" TRUE PARENT_SCOPE)
23
24  message(STATUS "verifying file...
25       file='@LOCAL@'")
26
27  file("@ALGO@" "@LOCAL@" actual_value)
28
29  if(NOT "${actual_value}" STREQUAL "@EXPECT_VALUE@")
30    set("${hash_is_good}" FALSE PARENT_SCOPE)
31    message(STATUS "@ALGO@ hash of
32    @LOCAL@
33  does not match expected value
34    expected: '@EXPECT_VALUE@'
35      actual: '${actual_value}'")
36  else()
37    set("${hash_is_good}" TRUE PARENT_SCOPE)
38  endif()
39endfunction()
40
41function(sleep_before_download attempt)
42  if(attempt EQUAL 0)
43    return()
44  endif()
45
46  if(attempt EQUAL 1)
47    message(STATUS "Retrying...")
48    return()
49  endif()
50
51  set(sleep_seconds 0)
52
53  if(attempt EQUAL 2)
54    set(sleep_seconds 5)
55  elseif(attempt EQUAL 3)
56    set(sleep_seconds 5)
57  elseif(attempt EQUAL 4)
58    set(sleep_seconds 15)
59  elseif(attempt EQUAL 5)
60    set(sleep_seconds 60)
61  elseif(attempt EQUAL 6)
62    set(sleep_seconds 90)
63  elseif(attempt EQUAL 7)
64    set(sleep_seconds 300)
65  else()
66    set(sleep_seconds 1200)
67  endif()
68
69  message(STATUS "Retry after ${sleep_seconds} seconds (attempt #${attempt}) ...")
70
71  execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep "${sleep_seconds}")
72endfunction()
73
74if("@LOCAL@" STREQUAL "")
75  message(FATAL_ERROR "LOCAL can't be empty")
76endif()
77
78if("@REMOTE@" STREQUAL "")
79  message(FATAL_ERROR "REMOTE can't be empty")
80endif()
81
82if(EXISTS "@LOCAL@")
83  check_file_hash(has_hash hash_is_good)
84  if(has_hash)
85    if(hash_is_good)
86      message(STATUS "File already exists and hash match (skip download):
87  file='@LOCAL@'
88  @ALGO@='@EXPECT_VALUE@'"
89      )
90      return()
91    else()
92      message(STATUS "File already exists but hash mismatch. Removing...")
93      file(REMOVE "@LOCAL@")
94    endif()
95  else()
96    message(STATUS "File already exists but no hash specified (use URL_HASH):
97  file='@LOCAL@'
98Old file will be removed and new file downloaded from URL."
99    )
100    file(REMOVE "@LOCAL@")
101  endif()
102endif()
103
104set(retry_number 5)
105
106message(STATUS "Downloading...
107   dst='@LOCAL@'
108   timeout='@TIMEOUT_MSG@'
109   inactivity timeout='@INACTIVITY_TIMEOUT_MSG@'"
110)
111set(download_retry_codes 7 6 8 15)
112set(skip_url_list)
113set(status_code)
114foreach(i RANGE ${retry_number})
115  if(status_code IN_LIST download_retry_codes)
116    sleep_before_download(${i})
117  endif()
118  foreach(url @REMOTE@)
119    if(NOT url IN_LIST skip_url_list)
120      message(STATUS "Using src='${url}'")
121
122      @TLS_VERIFY_CODE@
123      @TLS_CAINFO_CODE@
124      @NETRC_CODE@
125      @NETRC_FILE_CODE@
126
127      file(
128        DOWNLOAD
129        "${url}" "@LOCAL@"
130        @SHOW_PROGRESS@
131        @TIMEOUT_ARGS@
132        @INACTIVITY_TIMEOUT_ARGS@
133        STATUS status
134        LOG log
135        @USERPWD_ARGS@
136        @HTTP_HEADERS_ARGS@
137        )
138
139      list(GET status 0 status_code)
140      list(GET status 1 status_string)
141
142      if(status_code EQUAL 0)
143        check_file_hash(has_hash hash_is_good)
144        if(has_hash AND NOT hash_is_good)
145          message(STATUS "Hash mismatch, removing...")
146          file(REMOVE "@LOCAL@")
147        else()
148          message(STATUS "Downloading... done")
149          return()
150        endif()
151      else()
152        string(APPEND logFailedURLs "error: downloading '${url}' failed
153        status_code: ${status_code}
154        status_string: ${status_string}
155        log:
156        --- LOG BEGIN ---
157        ${log}
158        --- LOG END ---
159        "
160        )
161      if(NOT status_code IN_LIST download_retry_codes)
162        list(APPEND skip_url_list "${url}")
163        break()
164      endif()
165    endif()
166  endif()
167  endforeach()
168endforeach()
169
170message(FATAL_ERROR "Each download failed!
171  ${logFailedURLs}
172  "
173)
174