From 62ae805751f9097f99b14d952a424df1cde9f6d8 Mon Sep 17 00:00:00 2001 From: Rafael Kitover Date: Thu, 10 Feb 2022 15:23:00 +0000 Subject: [PATCH] build: add nuget_install() in cmake/NuGet.cmake This function downloads nuget.exe to out_dir/nuget if necessary and installs the passed-in NuGet package to that directory. If the package contains a tools/bin directory, it is added to CMAKE_PROGRAM_PATH for find_program() to find any utilities. Add the supporting function file_download() to cmake/Utilities.cmake, which is a wrapper for the cmake file(DOWNLOAD ...) that takes a REQUIRED parameter to throw a fatal error if there are any problems. Signed-off-by: Rafael Kitover --- contrib/buildsystems/cmake/NuGet.cmake | 73 ++++++++++++++++++++++ contrib/buildsystems/cmake/Utilities.cmake | 40 ++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 contrib/buildsystems/cmake/NuGet.cmake diff --git a/contrib/buildsystems/cmake/NuGet.cmake b/contrib/buildsystems/cmake/NuGet.cmake new file mode 100644 index 00000000000000..f4bd588596a1cd --- /dev/null +++ b/contrib/buildsystems/cmake/NuGet.cmake @@ -0,0 +1,73 @@ +include(Utilities) + +# +# nuget_install([pkg_name] [QUIET]) +# +# Installs nuget.exe in the output directory if not already present +# and uses it to install pkg_name if provided. +# +# If the package contains a 'tools/bin' directory, it will be +# appended to CMAKE_PROGRAM_PATH. +# +# With the QUIET option, no status messages will be printed. +# +# Throws a fatal error if any problems are encountered. +# +function(nuget_install pkg) + if(ARGV1 STREQUAL QUIET) + set(quiet TRUE) + endif() + + if(NOT EXISTS "${CMAKE_BINARY_DIR}/nuget/nuget.exe") + file_download("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" "${CMAKE_BINARY_DIR}/nuget/nuget.exe" REQUIRED) + + # Add nuget package source if not already present. + execute_process( + COMMAND nuget sources add -Name "NuGet official package source" -Source "https://api.nuget.org/v3/index.json" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/nuget" + OUTPUT_QUIET + ERROR_QUIET + ) + endif() + + if("${pkg}" STREQUAL "") + return() + endif() + + execute_process( + COMMAND nuget.exe install "${pkg}" -OutputDirectory "${CMAKE_BINARY_DIR}/nuget" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/nuget" + OUTPUT_VARIABLE install_output + RESULT_VARIABLE install_exit_status + ) + + if(NOT install_exit_status EQUAL 0) + message(FATAL_ERROR "NuGet installation of package '${pkg}' failed, exit code: ${install_exit_status}") + endif() + + string(REGEX REPLACE ".* package '[^0-9]+([0-9.]+)'.*" "\\1" pkg_ver "${install_output}") + + set(pkg_dir "${CMAKE_BINARY_DIR}/nuget/${pkg}.${pkg_ver}") + + if(NOT IS_DIRECTORY "${pkg_dir}") + message(FATAL_ERROR "NuGet installation of package '${pkg}' failed, package directory '${pkg_dir}' does not exist.") + endif() + + if(NOT quiet) + message(STATUS "Installed NuGet package '${pkg}' successfully.") + endif() + + set(pkg_bin "${pkg_dir}/tools/bin") + + if(IS_DIRECTORY "${pkg_bin}") + list(APPEND CMAKE_PROGRAM_PATH "${pkg_bin}") + set(CMAKE_PROGRAM_PATH "${CMAKE_PROGRAM_PATH}" PARENT_SCOPE) + set(CMAKE_PROGRAM_PATH "${CMAKE_PROGRAM_PATH}" CACHE STRING "External Program Search Path" FORCE) + + if(NOT quiet) + message(STATUS "Added tools/bin from NuGet package '${pkg}' to CMAKE_PROGRAM_PATH.") + endif() + endif() +endfunction() + +# vim:set sw=8 ts=8 noet: diff --git a/contrib/buildsystems/cmake/Utilities.cmake b/contrib/buildsystems/cmake/Utilities.cmake index 33481a881f2fba..257290247ceae8 100644 --- a/contrib/buildsystems/cmake/Utilities.cmake +++ b/contrib/buildsystems/cmake/Utilities.cmake @@ -1,3 +1,43 @@ +# +# file_download( +# url dest_path +# [STATUS status_out_var] +# [REQUIRED] +# ) +# +# Wrapper for cmake file(DOWNLOAD ...) with optional error +# checking. If REQUIRED is passed in, a fatal error will be thrown +# on failure. Otherwise if STATUS is passed in, it will store the +# status list in the out var just like file(DOWNLOAD ...). +# +function(file_download url dest_path) + if(NOT url OR NOT dest_path) + message(FATAL_ERROR "file_download: syntax: file_download(url destination_path [OPTIONS]") + endif() + + file(DOWNLOAD "${url}" "${dest_path}" STATUS status_list) + list(GET status_list 0 status) + + if("STATUS" IN_LIST ARGN) + list(FIND ARGN STATUS status_idx) + math(EXPR out_var_idx "${status_idx} + 1") + list(GET ARGN "${out_var_idx}" out_var) + + if("${out_var}" STREQUAL "") + message(FATAL_ERROR "STATUS must be followed by output variable name for the status list.") + endif() + + set("${out_var}" "${status_list}" PARENT_SCOPE) + endif() + + if ("REQUIRED" IN_LIST ARGN) + if(NOT status EQUAL 0) + list(GET status_list 1 error_str) + message(FATAL_ERROR "Download of '${url}' failed: ${error_str}") + endif() + endif() +endfunction() + # # build_option( # opt_name type help_string [default]