## # vcpkg_download_distfile ## ## Download and cache a file needed for this port. ## ## This helper should always be used instead of CMake's built-in `file(DOWNLOAD)` command. ## ## ## Usage ## ```cmake ## vcpkg_download_distfile( ## ## URLS ... ## FILENAME ## SHA512 <5981de...> ## ) ## ``` ## ## Parameters ## ### OUT_VARIABLE ## This variable will be set to the full path to the downloaded file. This can then immediately be passed in to [`vcpkg_extract_source_archive`](vcpkg_extract_source_archive.md) for sources. ## ## ### URLS ## A list of URLs to be consulted. They will be tried in order until one of the downloaded files successfully matches the SHA512 given. ## ## ### FILENAME ## The local name for the file. Files are shared between ports, so the file may need to be renamed to make it clearly attributed to this port and avoid conflicts. ## ## ### SHA512 ## The expected hash for the file. ## ## If this doesn't match the downloaded version, the build will be terminated with a message describing the mismatch. ## ## ### QUIET ## Suppress output on cache hit ## ## ### SKIP_SHA512 ## Skip SHA512 hash check for file. ## ## This switch is only valid when building with the `--head` command line flag. ## ## ### HEADERS ## A list of headers to append to the download request. This can be used for authentication during a download. ## ## Headers should be specified as ": ". ## ## ## Notes ## The helper [`vcpkg_from_github`](vcpkg_from_github.md) should be used for downloading from GitHub projects. ## ## ## Examples ## ## * [apr](https://github.com/Microsoft/vcpkg/blob/master/ports/apr/portfile.cmake) ## * [fontconfig](https://github.com/Microsoft/vcpkg/blob/master/ports/fontconfig/portfile.cmake) ## * [freetype](https://github.com/Microsoft/vcpkg/blob/master/ports/freetype/portfile.cmake) include(vcpkg_execute_in_download_mode) function(vcpkg_download_distfile VAR) set(options SKIP_SHA512 SILENT_EXIT QUIET) set(oneValueArgs FILENAME SHA512) set(multipleValuesArgs URLS HEADERS) # parse parameters such that semicolons in options arguments to COMMAND don't get erased cmake_parse_arguments(PARSE_ARGV 1 vcpkg_download_distfile "${options}" "${oneValueArgs}" "${multipleValuesArgs}") if(NOT DEFINED vcpkg_download_distfile_URLS) message(FATAL_ERROR "vcpkg_download_distfile requires a URLS argument.") endif() if(NOT DEFINED vcpkg_download_distfile_FILENAME) message(FATAL_ERROR "vcpkg_download_distfile requires a FILENAME argument.") endif() if(NOT _VCPKG_INTERNAL_NO_HASH_CHECK) if(NOT vcpkg_download_distfile_SKIP_SHA512 AND NOT DEFINED vcpkg_download_distfile_SHA512) message(FATAL_ERROR "vcpkg_download_distfile requires a SHA512 argument. If you do not know the SHA512, add it as 'SHA512 0' and re-run this command.") endif() if(vcpkg_download_distfile_SKIP_SHA512 AND DEFINED vcpkg_download_distfile_SHA512) message(FATAL_ERROR "vcpkg_download_distfile must not be passed both SHA512 and SKIP_SHA512.") endif() endif() set(downloaded_file_path ${DOWNLOADS}/${vcpkg_download_distfile_FILENAME}) set(download_file_path_part "${DOWNLOADS}/temp/${vcpkg_download_distfile_FILENAME}") # Works around issue #3399 if(IS_DIRECTORY "${DOWNLOADS}/temp") # Delete "temp0" directory created by the old version of vcpkg file(REMOVE_RECURSE "${DOWNLOADS}/temp0") file(GLOB temp_files "${DOWNLOADS}/temp") file(REMOVE_RECURSE ${temp_files}) else() file(MAKE_DIRECTORY "${DOWNLOADS}/temp") endif() function(test_hash FILE_PATH FILE_KIND CUSTOM_ERROR_ADVICE) if(_VCPKG_INTERNAL_NO_HASH_CHECK) # When using the internal hash skip, do not output an explicit message. return() endif() if(vcpkg_download_distfile_SKIP_SHA512) message(STATUS "Skipping hash check for ${FILE_PATH}.") return() endif() file(SHA512 ${FILE_PATH} FILE_HASH) if(NOT FILE_HASH STREQUAL vcpkg_download_distfile_SHA512) message(FATAL_ERROR "\nFile does not have expected hash:\n" " File path: [ ${FILE_PATH} ]\n" " Expected hash: [ ${vcpkg_download_distfile_SHA512} ]\n" " Actual hash: [ ${FILE_HASH} ]\n" "${CUSTOM_ERROR_ADVICE}\n") endif() endfunction() if(EXISTS "${downloaded_file_path}") if(NOT vcpkg_download_distfile_QUIET) message(STATUS "Using cached ${downloaded_file_path}") endif() test_hash("${downloaded_file_path}" "cached file" "Please delete the file and retry if this file should be downloaded again.") else() if(_VCPKG_NO_DOWNLOADS) message(FATAL_ERROR "Downloads are disabled, but '${downloaded_file_path}' does not exist.") endif() # Tries to download the file. list(GET vcpkg_download_distfile_URLS 0 SAMPLE_URL) if(_VCPKG_DOWNLOAD_TOOL STREQUAL "ARIA2" AND NOT SAMPLE_URL MATCHES "aria2") vcpkg_find_acquire_program("ARIA2") message(STATUS "Downloading ${vcpkg_download_distfile_FILENAME}...") if(vcpkg_download_distfile_HEADERS) foreach(header ${vcpkg_download_distfile_HEADERS}) list(APPEND request_headers "--header=${header}") endforeach() endif() vcpkg_execute_in_download_mode( COMMAND ${ARIA2} ${vcpkg_download_distfile_URLS} -o temp/${vcpkg_download_distfile_FILENAME} -l download-${vcpkg_download_distfile_FILENAME}-detailed.log ${request_headers} OUTPUT_FILE download-${vcpkg_download_distfile_FILENAME}-out.log ERROR_FILE download-${vcpkg_download_distfile_FILENAME}-err.log RESULT_VARIABLE error_code WORKING_DIRECTORY ${DOWNLOADS} ) if (NOT "${error_code}" STREQUAL "0") message(STATUS "Downloading ${vcpkg_download_distfile_FILENAME}... Failed.\n" " Exit Code: ${error_code}\n" " See logs for more information:\n" " ${DOWNLOADS}/download-${vcpkg_download_distfile_FILENAME}-out.log\n" " ${DOWNLOADS}/download-${vcpkg_download_distfile_FILENAME}-err.log\n" " ${DOWNLOADS}/download-${vcpkg_download_distfile_FILENAME}-detailed.log\n" ) set(download_success 0) else() file(REMOVE ${DOWNLOADS}/download-${vcpkg_download_distfile_FILENAME}-out.log ${DOWNLOADS}/download-${vcpkg_download_distfile_FILENAME}-err.log ${DOWNLOADS}/download-${vcpkg_download_distfile_FILENAME}-detailed.log ) set(download_success 1) endif() else() foreach(url IN LISTS vcpkg_download_distfile_URLS) message(STATUS "Downloading ${url}...") if(vcpkg_download_distfile_HEADERS) foreach(header ${vcpkg_download_distfile_HEADERS}) list(APPEND request_headers HTTPHEADER ${header}) endforeach() endif() file(DOWNLOAD "${url}" "${download_file_path_part}" STATUS download_status ${request_headers}) list(GET download_status 0 status_code) if (NOT "${status_code}" STREQUAL "0") message(STATUS "Downloading ${url}... Failed. Status: ${download_status}") set(download_success 0) else() set(download_success 1) break() endif() endforeach(url) endif() if (NOT vcpkg_download_distfile_SILENT_EXIT) if (NOT download_success) message(FATAL_ERROR " \n" " Failed to download file.\n" " If you use a proxy, please set the HTTPS_PROXY and HTTP_PROXY environment\n" " variables to \"https://user:password@your-proxy-ip-address:port/\".\n" " Otherwise, please submit an issue at https://github.com/Microsoft/vcpkg/issues\n") else() test_hash("${download_file_path_part}" "downloaded file" "The file may have been corrupted in transit. This can be caused by proxies. If you use a proxy, please set the HTTPS_PROXY and HTTP_PROXY environment variables to \"https://user:password@your-proxy-ip-address:port/\".\n") get_filename_component(downloaded_file_dir "${downloaded_file_path}" DIRECTORY) file(MAKE_DIRECTORY "${downloaded_file_dir}") file(RENAME ${download_file_path_part} ${downloaded_file_path}) endif() else() if (NOT download_success) message(WARNING " \n" " Failed to download file.\n") else() test_hash("${download_file_path_part}" "downloaded file" "The file may have been corrupted in transit. This can be caused by proxies. If you use a proxy, please set the HTTPS_PROXY and HTTP_PROXY environment variables to \"https://user:password@your-proxy-ip-address:port/\".\n") get_filename_component(downloaded_file_dir "${downloaded_file_path}" DIRECTORY) file(MAKE_DIRECTORY "${downloaded_file_dir}") file(RENAME ${download_file_path_part} ${downloaded_file_path}) endif() endif() endif() set(${VAR} ${downloaded_file_path} PARENT_SCOPE) endfunction()