aboutsummaryrefslogtreecommitdiff
path: root/cmake.deps/cmake/DownloadAndExtractFile.cmake
blob: abb1ddc81aba23bce125b05abb536b3ed7273a12 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
if(NOT DEFINED PREFIX)
  message(FATAL_ERROR "PREFIX must be defined.")
endif()

if(NOT DEFINED URL)
  message(FATAL_ERROR "URL must be defined.")
endif()

if(NOT DEFINED DOWNLOAD_DIR)
  message(FATAL_ERROR "DOWNLOAD_DIR must be defined.")
endif()

if(NOT DEFINED EXPECTED_SHA256)
  message(FATAL_ERROR "EXPECTED_SHA256 must be defined.")
endif()

if(NOT DEFINED TARGET)
  message(FATAL_ERROR "TARGET must be defined.")
endif()

if(NOT DEFINED SRC_DIR)
  set(SRC_DIR ${PREFIX}/src/${TARGET})
endif()
set(BINARY_DIR ${PREFIX}/src/${TARGET}-build)

# Check whether the source has been downloaded. If true, skip it.
# Useful for external downloads like homebrew.
if(USE_EXISTING_SRC_DIR)
  if(EXISTS "${SRC_DIR}" AND IS_DIRECTORY "${SRC_DIR}")
    file(GLOB EXISTED_FILES "${SRC_DIR}/*")
    if(EXISTED_FILES)
      message(STATUS "${SRC_DIR} is found and not empty, skipping download and extraction. ")
      return()
    endif()
  endif()
  message(FATAL_ERROR "USE_EXISTING_SRC_DIR set to ON, but '${SRC_DIR}' does not exist or is empty.")
endif()

# Taken from ExternalProject_Add.  Let's hope we can drop this one day when
# ExternalProject_Add allows you to disable SHOW_PROGRESS on the file download.
if(TIMEOUT)
  set(timeout_args TIMEOUT ${timeout})
  set(timeout_msg "${timeout} seconds")
else()
  set(timeout_args "")
  set(timeout_msg "none")
endif()

string(REGEX MATCH "[^/\\?]*$" fname "${URL}")
if(NOT "${fname}" MATCHES "(\\.|=)(bz2|tar|tgz|tar\\.gz|zip)$")
  string(REGEX MATCH "([^/\\?]+(\\.|=)(bz2|tar|tgz|tar\\.gz|zip))/.*$" match_result "${URL}")
  set(fname "${CMAKE_MATCH_1}")
endif()
if(NOT "${fname}" MATCHES "(\\.|=)(bz2|tar|tgz|tar\\.gz|zip)$")
  message(FATAL_ERROR "Could not extract tarball filename from url:\n  ${url}")
endif()
string(REPLACE ";" "-" fname "${fname}")

set(file ${DOWNLOAD_DIR}/${fname})
message(STATUS "file: ${file}")

set(EXISTING_SHA256 "")
if(EXISTS ${file})
  file(SHA256 ${file} EXISTING_SHA256)
endif()

if(NOT EXISTING_SHA256 STREQUAL ${EXPECTED_SHA256})
  message(STATUS "downloading...
       src='${URL}'
       dst='${file}'
       timeout='${timeout_msg}'")
  
  file(DOWNLOAD ${URL} ${file}
    ${timeout_args}
    ${hash_args}
    STATUS status
    LOG log)
  
  list(GET status 0 status_code)
  list(GET status 1 status_string)
  
  if(NOT status_code EQUAL 0)
    # Retry on certain errors, e.g. CURLE_COULDNT_RESOLVE_HOST, which is often
    # seen with libtermkey (www.leonerd.org.uk).
    if((status_code EQUAL 6)  # "Couldn't resolve host name"
      OR (status_code EQUAL 7))  # "Couldn't connect to server"
      message(STATUS "warning: retrying '${URL}' (${status_string}, status ${status_code})")
      execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 10)
      file(DOWNLOAD ${URL} ${file}
        ${timeout_args}
        ${hash_args}
        STATUS status
        LOG log)
      list(GET status 0 status_code)
      list(GET status 1 status_string)
    endif()
    if(NOT status_code EQUAL 0)
      message(FATAL_ERROR "error: downloading '${URL}' failed
    status_code: ${status_code}
    status_string: ${status_string}
    log: ${log}
  ")
    endif()
  endif()
endif()

set(NULL_SHA256 "0000000000000000000000000000000000000000000000000000000000000000")

# Allow users to use "SKIP" or "skip" as the sha256 to skip checking the hash.
# You can still use the all zeros hash too.
if((EXPECTED_SHA256 STREQUAL "SKIP") OR (EXPECTED_SHA256 STREQUAL "skip"))
  set(EXPECTED_SHA256 ${NULL_SHA256})
endif()

# We could avoid computing the SHA256 entirely if a NULL_SHA256 was given,
# but we want to warn users of an empty file.
file(SHA256 ${file} ACTUAL_SHA256)
if(ACTUAL_SHA256 STREQUAL "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
  # File was empty.  It's likely due to lack of SSL support.
  message(FATAL_ERROR
    "Failed to download ${URL}.  The file is empty and likely means CMake "
    "was built without SSL support.  Please use a version of CMake with "
    "proper SSL support.  See "
    "https://github.com/neovim/neovim/wiki/Building-Neovim#build-prerequisites "
    "for more information.")
elseif((NOT EXPECTED_SHA256 STREQUAL NULL_SHA256) AND
       (NOT EXPECTED_SHA256 STREQUAL ACTUAL_SHA256))
  # Wasn't a NULL SHA256 and we didn't match, so we fail.
  message(FATAL_ERROR
    "Failed to download ${URL}.  Expected a SHA256 of "
    "${EXPECTED_SHA256} but got ${ACTUAL_SHA256} instead.")
endif()

message(STATUS "downloading... done")

# Slurped from a generated extract-TARGET.cmake file.
message(STATUS "extracting...
     src='${file}'
     dst='${SRC_DIR}'")

if(NOT EXISTS "${file}")
  message(FATAL_ERROR "error: file to extract does not exist: '${file}'")
endif()

# Prepare a space for extracting:
#
set(i 1234)
while(EXISTS "${SRC_DIR}/../ex-${TARGET}${i}")
  math(EXPR i "${i} + 1")
endwhile()
set(ut_dir "${SRC_DIR}/../ex-${TARGET}${i}")
file(MAKE_DIRECTORY "${ut_dir}")

# Extract it:
#
message(STATUS "extracting... [tar xfz]")
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xfz ${file}
  WORKING_DIRECTORY ${ut_dir}
  RESULT_VARIABLE rv)

if(NOT rv EQUAL 0)
  message(STATUS "extracting... [error clean up]")
  file(REMOVE_RECURSE "${ut_dir}")
  message(FATAL_ERROR "error: extract of '${file}' failed")
endif()

# Analyze what came out of the tar file:
#
message(STATUS "extracting... [analysis]")
file(GLOB contents "${ut_dir}/*")
list(LENGTH contents n)
if(NOT n EQUAL 1 OR NOT IS_DIRECTORY "${contents}")
  set(contents "${ut_dir}")
endif()

# Move "the one" directory to the final directory:
#
message(STATUS "extracting... [rename]")
file(REMOVE_RECURSE ${SRC_DIR})
get_filename_component(contents ${contents} ABSOLUTE)
file(RENAME ${contents} ${SRC_DIR})

# Remove any existing BINARY_DIR, to force a new build.
# Without this a necessary output (e.g. libluv.a) might not be updated/installed.
#
message(STATUS "extracting... [clean binary dir]")
file(REMOVE_RECURSE ${BINARY_DIR})
file(MAKE_DIRECTORY ${BINARY_DIR})

# Clean up:
#
message(STATUS "extracting... [clean up]")
file(REMOVE_RECURSE "${ut_dir}")

message(STATUS "extracting... done")