Imported Upstream version 3.23.2
[platform/upstream/cmake.git] / Modules / Internal / CPack / CPackNuGet.cmake
1 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2 # file Copyright.txt or https://cmake.org/licensing for details.
3
4 # Author: Alex Turbov
5
6 if(CMAKE_BINARY_DIR)
7   message(FATAL_ERROR "CPackNuGet.cmake may only be used by CPack internally.")
8 endif()
9
10 function(_cpack_nuget_debug)
11     if(CPACK_NUGET_PACKAGE_DEBUG)
12         message("CPackNuGet:Debug: " ${ARGN})
13     endif()
14 endfunction()
15
16 function(_cpack_nuget_debug_var NAME)
17     if(CPACK_NUGET_PACKAGE_DEBUG)
18         message("CPackNuGet:Debug: ${NAME}=`${${NAME}}`")
19     endif()
20 endfunction()
21
22 function(_cpack_nuget_variable_fallback OUTPUT_VAR_NAME NUGET_VAR_NAME)
23     if(ARGN)
24         list(JOIN ARGN "`, `" _va_args)
25         set(_va_args ", ARGN: `${_va_args}`")
26     endif()
27     _cpack_nuget_debug(
28         "_cpack_nuget_variable_fallback: "
29         "OUTPUT_VAR_NAME=`${OUTPUT_VAR_NAME}`, "
30         "NUGET_VAR_NAME=`${NUGET_VAR_NAME}`"
31         "${_va_args}"
32       )
33
34     set(_options USE_CDATA)
35     set(_one_value_args LIST_GLUE)
36     set(_multi_value_args FALLBACK_VARS)
37     cmake_parse_arguments(PARSE_ARGV 0 _args "${_options}" "${_one_value_args}" "${_multi_value_args}")
38
39     if(CPACK_NUGET_PACKAGE_COMPONENT)
40         string(
41             TOUPPER "${CPACK_NUGET_PACKAGE_COMPONENT}"
42             CPACK_NUGET_PACKAGE_COMPONENT_UPPER
43           )
44     endif()
45
46     if(CPACK_NUGET_PACKAGE_COMPONENT
47       AND CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}
48       )
49         set(
50             _result
51             "${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}}"
52           )
53         _cpack_nuget_debug(
54             "  CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}: "
55             "OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
56           )
57
58     elseif(CPACK_NUGET_PACKAGE_COMPONENT_UPPER
59       AND CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}
60       )
61         set(
62             _result
63             "${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}}"
64           )
65         _cpack_nuget_debug(
66             "  CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}: "
67             "OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
68           )
69
70     elseif(CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME})
71         set(_result "${CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME}}")
72         _cpack_nuget_debug(
73             "  CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME}: "
74             "OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
75           )
76
77     else()
78         foreach(_var IN LISTS _args_FALLBACK_VARS)
79             _cpack_nuget_debug("  Fallback: ${_var} ...")
80             if(${_var})
81                 _cpack_nuget_debug("            ${_var}=`${${_var}}`")
82                 set(_result "${${_var}}")
83                 _cpack_nuget_debug(
84                     "  ${_var}: OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
85                   )
86                 break()
87             endif()
88         endforeach()
89     endif()
90
91     if(_result)
92         if(_args_USE_CDATA)
93             set(_value_before "<![CDATA[")
94             set(_value_after "]]>")
95         endif()
96
97         list(LENGTH _result _result_len)
98         if(_result_len GREATER 1 AND _args_LIST_GLUE)
99             list(JOIN _result "${_args_LIST_GLUE}" _result)
100         endif()
101
102         set(${OUTPUT_VAR_NAME} "${_value_before}${_result}${_value_after}" PARENT_SCOPE)
103     endif()
104
105 endfunction()
106
107 function(_cpack_nuget_variable_fallback_and_wrap_into_element ELEMENT NUGET_VAR_NAME)
108     set(_options)
109     set(_one_value_args)
110     set(_multi_value_args FALLBACK_VARS ATTRIBUTES)
111     cmake_parse_arguments(PARSE_ARGV 2 _args "${_options}" "${_one_value_args}" "${_multi_value_args}")
112
113     if(_args_ATTRIBUTES)
114         list(JOIN _args_ATTRIBUTES " " _attributes)
115         string(PREPEND _attributes " ")
116     endif()
117
118     _cpack_nuget_variable_fallback(_value ${NUGET_VAR_NAME} ${ARGN} USE_CDATA)
119
120     string(TOUPPER "${ELEMENT}" _ELEMENT_UP)
121     if(_value)
122         set(
123             _CPACK_NUGET_${_ELEMENT_UP}_TAG
124             "<${ELEMENT}${_attributes}>${_value}</${ELEMENT}>"
125             PARENT_SCOPE
126           )
127     elseif(_attributes)
128         set(
129             _CPACK_NUGET_${_ELEMENT_UP}_TAG
130             "<${ELEMENT}${_attributes} />"
131             PARENT_SCOPE
132           )
133     endif()
134 endfunction()
135
136 # Warn of obsolete nuspec fields, referencing CMake variables and suggested
137 # replacement, if any
138 function(_cpack_nuget_deprecation_warning NUGET_ELEMENT VARNAME REPLACEMENT)
139     if(${VARNAME})
140         if(REPLACEMENT)
141             message(DEPRECATION "nuspec element `${NUGET_ELEMENT}` is deprecated in NuGet; consider replacing `${VARNAME}` with `${REPLACEMENT}`")
142         else()
143             message(DEPRECATION "nuspec element `${NUGET_ELEMENT}` is deprecated in NuGet; consider removing `${VARNAME}`")
144         endif()
145     endif()
146 endfunction()
147
148 # Print some debug info
149 _cpack_nuget_debug("---[CPack NuGet Input Variables]---")
150 _cpack_nuget_debug_var(CPACK_PACKAGE_NAME)
151 _cpack_nuget_debug_var(CPACK_PACKAGE_VERSION)
152 _cpack_nuget_debug_var(CPACK_TOPLEVEL_TAG)
153 _cpack_nuget_debug_var(CPACK_TOPLEVEL_DIRECTORY)
154 _cpack_nuget_debug_var(CPACK_TEMPORARY_DIRECTORY)
155 _cpack_nuget_debug_var(CPACK_NUGET_GROUPS)
156 if(CPACK_NUGET_GROUPS)
157     foreach(_group IN LISTS CPACK_NUGET_GROUPS)
158         string(MAKE_C_IDENTIFIER "${_group}" _group_up)
159         string(TOUPPER "${_group_up}" _group_up)
160         _cpack_nuget_debug_var(CPACK_NUGET_${_group_up}_GROUP_COMPONENTS)
161     endforeach()
162 endif()
163 _cpack_nuget_debug_var(CPACK_NUGET_COMPONENTS)
164 _cpack_nuget_debug_var(CPACK_NUGET_ALL_IN_ONE)
165 _cpack_nuget_debug_var(CPACK_NUGET_ORDINAL_MONOLITIC)
166 _cpack_nuget_debug("-----------------------------------")
167
168 function(_cpack_nuget_render_spec)
169     # Make a variable w/ upper-cased component name
170     if(CPACK_NUGET_PACKAGE_COMPONENT)
171         string(TOUPPER "${CPACK_NUGET_PACKAGE_COMPONENT}" CPACK_NUGET_PACKAGE_COMPONENT_UPPER)
172     endif()
173
174     # Set mandatory variables (not wrapped into XML elements)
175     # https://docs.microsoft.com/en-us/nuget/reference/nuspec#required-metadata-elements
176     if(CPACK_NUGET_PACKAGE_COMPONENT)
177         if(CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_NAME)
178             set(
179                 CPACK_NUGET_PACKAGE_NAME
180                 "${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_NAME}"
181               )
182         elseif(NOT CPACK_NUGET_PACKAGE_COMPONENT STREQUAL "Unspecified")
183             set(
184                 CPACK_NUGET_PACKAGE_NAME
185                 "${CPACK_PACKAGE_NAME}.${CPACK_NUGET_PACKAGE_COMPONENT}"
186               )
187         else()
188             set(CPACK_NUGET_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")
189         endif()
190     elseif(NOT CPACK_NUGET_PACKAGE_NAME)
191         set(CPACK_NUGET_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")
192     endif()
193
194     # Warn about deprecated nuspec elements; warnings only display if
195     # variable is set
196     # Note that while nuspec's "summary" element is deprecated, there
197     # is no suggested replacement so (for now) no deprecation warning
198     # is shown for `CPACK_NUGET_*_DESCRIPTION_SUMMARY`
199     _cpack_nuget_deprecation_warning("licenseUrl" CPACK_NUGET_PACKAGE_LICENSEURL
200         "CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME or CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION")
201     _cpack_nuget_deprecation_warning("licenseUrl" CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSEURL
202         "CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSE_FILE_NAME or CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSE_EXPRESSION")
203     _cpack_nuget_deprecation_warning("iconUrl" CPACK_NUGET_PACKAGE_ICONURL
204         "CPACK_NUGET_PACKAGE_ICON")
205     _cpack_nuget_deprecation_warning("iconUrl" CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_ICONURL
206         "CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_ICON")
207
208     # Set nuspec fields
209     _cpack_nuget_variable_fallback(
210         CPACK_NUGET_PACKAGE_VERSION VERSION
211         FALLBACK_VARS
212             CPACK_PACKAGE_VERSION
213       )
214     _cpack_nuget_variable_fallback(
215         CPACK_NUGET_PACKAGE_DESCRIPTION DESCRIPTION
216         FALLBACK_VARS
217             CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT}_DESCRIPTION
218             CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DESCRIPTION
219             CPACK_COMPONENT_GROUP_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DESCRIPTION
220             CPACK_PACKAGE_DESCRIPTION
221         USE_CDATA
222       )
223     _cpack_nuget_variable_fallback(
224         CPACK_NUGET_PACKAGE_AUTHORS AUTHORS
225         FALLBACK_VARS
226             CPACK_PACKAGE_VENDOR
227         USE_CDATA
228         LIST_GLUE ","
229       )
230
231     # Set optional variables (wrapped into XML elements)
232     # https://docs.microsoft.com/en-us/nuget/reference/nuspec#optional-metadata-elements
233     _cpack_nuget_variable_fallback_and_wrap_into_element(
234         title
235         TITLE
236         FALLBACK_VARS
237             CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT}_DISPLAY_NAME
238             CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DISPLAY_NAME
239             CPACK_COMPONENT_GROUP_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DISPLAY_NAME
240       )
241     _cpack_nuget_variable_fallback_and_wrap_into_element(owners OWNERS LIST_GLUE ",")
242     _cpack_nuget_variable_fallback_and_wrap_into_element(
243         projectUrl
244         HOMEPAGE_URL
245         FALLBACK_VARS
246             CPACK_PACKAGE_HOMEPAGE_URL
247       )
248
249     # "licenseUrl" is deprecated in favor of "license"
250     _cpack_nuget_variable_fallback_and_wrap_into_element(licenseUrl LICENSEURL)
251
252     # "iconUrl" is deprecated in favor of "icon"
253     _cpack_nuget_variable_fallback_and_wrap_into_element(iconUrl ICONURL)
254
255     # "license" takes a "type" attribute of either "file" or "expression"
256     # "file" refers to a file path of a .txt or .md file relative to the installation root
257     # "expression" refers to simple or compound expression of license identifiers
258     # listed at https://spdx.org/licenses/
259     # Note that only one of CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME and
260     # CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION may be specified. If both are specified,
261     # CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME takes precedence and CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION is ignored.
262     if(CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME)
263         _cpack_nuget_variable_fallback_and_wrap_into_element(
264             license LICENSE_FILE_NAME
265             ATTRIBUTES [[type="file"]]
266           )
267     elseif(CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION)
268         _cpack_nuget_variable_fallback_and_wrap_into_element(
269             license LICENSE_EXPRESSION
270             ATTRIBUTES [[type="expression"]]
271           )
272     endif()
273
274     # "icon" refers to a file path relative to the installation root
275     _cpack_nuget_variable_fallback_and_wrap_into_element(icon ICON)
276     # "summary" is deprecated in favor of "description"
277     _cpack_nuget_variable_fallback_and_wrap_into_element(
278         summary DESCRIPTION_SUMMARY
279         FALLBACK_VARS
280             CPACK_PACKAGE_DESCRIPTION_SUMMARY
281       )
282     if(CPACK_NUGET_PACKAGE_REQUIRE_LICENSE_ACCEPTANCE)
283         set(
284             _CPACK_NUGET_REQUIRELICENSEACCEPTANCE_TAG
285             "<requireLicenseAcceptance>true</requireLicenseAcceptance>"
286           )
287     endif()
288     _cpack_nuget_variable_fallback_and_wrap_into_element(releaseNotes RELEASE_NOTES)
289     _cpack_nuget_variable_fallback_and_wrap_into_element(copyright COPYRIGHT)
290     # "language" is a locale identifier such as "en_CA"
291     _cpack_nuget_variable_fallback_and_wrap_into_element(language LANGUAGE)
292     _cpack_nuget_variable_fallback_and_wrap_into_element(tags TAGS LIST_GLUE " ")
293     # "repository" holds repository metadata consisting of four optional
294     # attributes: "type", "url", "branch", and "commit". While all fields are
295     # considered optional, they are not independent. Currently unsupported.
296
297     # Handle dependencies
298     _cpack_nuget_variable_fallback(_deps DEPENDENCIES)
299     set(_collected_deps)
300     foreach(_dep IN LISTS _deps)
301         _cpack_nuget_debug("  checking dependency `${_dep}`")
302
303         _cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep}_VERSION)
304
305         if(NOT _ver)
306             string(TOUPPER "${_dep}" _dep_upper)
307             _cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep_upper}_VERSION)
308         endif()
309
310         if(_ver)
311             _cpack_nuget_debug("  got `${_dep}` dependency version ${_ver}")
312             string(CONCAT _collected_deps "${_collected_deps}" "            <dependency id=\"${_dep}\" version=\"${_ver}\" />\n")
313         endif()
314     endforeach()
315
316     # Render deps into the variable
317     if(_collected_deps)
318         string(CONCAT _CPACK_NUGET_DEPENDENCIES_TAG "<dependencies>\n" "${_collected_deps}" "        </dependencies>")
319     endif()
320
321     # Render the spec file
322     # NOTE The spec filename doesn't matter. Being included into a package,
323     # NuGet will name it properly.
324     _cpack_nuget_debug("Rendering `${CPACK_TEMPORARY_DIRECTORY}/CPack.NuGet.nuspec` file...")
325     configure_file(
326         "${CMAKE_ROOT}/Modules/Internal/CPack/CPack.NuGet.nuspec.in"
327         "${CPACK_TEMPORARY_DIRECTORY}/CPack.NuGet.nuspec"
328         @ONLY
329       )
330 endfunction()
331
332 function(_cpack_nuget_make_files_tag)
333     set(_files)
334     foreach(_comp IN LISTS ARGN)
335         cmake_path(APPEND _comp "**")
336         cmake_path(NATIVE_PATH _comp _comp)
337         string(APPEND _files "        <file src=\"${_comp}\" target=\".\" />\n")
338     endforeach()
339     set(_CPACK_NUGET_FILES_TAG "<files>\n${_files}    </files>" PARENT_SCOPE)
340 endfunction()
341
342 find_program(NUGET_EXECUTABLE nuget)
343 _cpack_nuget_debug_var(NUGET_EXECUTABLE)
344 if(NOT NUGET_EXECUTABLE)
345     message(FATAL_ERROR "NuGet executable not found")
346 endif()
347
348 # Add details for debug run
349 if(CPACK_NUGET_PACKAGE_DEBUG)
350     list(APPEND CPACK_NUGET_PACK_ADDITIONAL_OPTIONS "-Verbosity" "detailed")
351 endif()
352
353 # Case one: ordinal all-in-one package
354 if(CPACK_NUGET_ORDINAL_MONOLITIC)
355     # This variable `CPACK_NUGET_ALL_IN_ONE` set by C++ code:
356     # Meaning to pack all installed files into a single package
357     _cpack_nuget_debug("---[Making an ordinal monolitic package]---")
358     _cpack_nuget_render_spec()
359     execute_process(
360         COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
361         WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
362         RESULT_VARIABLE _nuget_result
363       )
364     if(NOT _nuget_result EQUAL 0)
365         message(FATAL_ERROR "Nuget pack failed")
366     endif()
367
368 elseif(CPACK_NUGET_ALL_IN_ONE)
369     # This variable `CPACK_NUGET_ALL_IN_ONE` set by C++ code:
370     # Meaning to pack all installed components into a single package
371     _cpack_nuget_debug("---[Making a monolitic package from installed components]---")
372
373     # Prepare the `files` element which include files from several components
374     _cpack_nuget_make_files_tag(${CPACK_NUGET_COMPONENTS})
375     _cpack_nuget_render_spec()
376     execute_process(
377         COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
378         WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
379         RESULT_VARIABLE _nuget_result
380       )
381     if(NOT _nuget_result EQUAL 0)
382         message(FATAL_ERROR "Nuget pack failed")
383     endif()
384
385 else()
386     # Is there any grouped component?
387     if(CPACK_NUGET_GROUPS)
388         _cpack_nuget_debug("---[Making grouped component(s) package(s)]---")
389         foreach(_group IN LISTS CPACK_NUGET_GROUPS)
390             _cpack_nuget_debug("Starting to make the package for group `${_group}`")
391             string(MAKE_C_IDENTIFIER "${_group}" _group_up)
392             string(TOUPPER "${_group_up}" _group_up)
393
394             # Render a spec file which includes all components in the current group
395             unset(_CPACK_NUGET_FILES_TAG)
396             _cpack_nuget_make_files_tag(${CPACK_NUGET_${_group_up}_GROUP_COMPONENTS})
397             # Temporary set `CPACK_NUGET_PACKAGE_COMPONENT` to the group name
398             # to properly collect various per group settings
399             set(CPACK_NUGET_PACKAGE_COMPONENT ${_group})
400             _cpack_nuget_render_spec()
401             unset(CPACK_NUGET_PACKAGE_COMPONENT)
402             execute_process(
403                 COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
404                 WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
405                 RESULT_VARIABLE _nuget_result
406               )
407             if(NOT _nuget_result EQUAL 0)
408                 message(FATAL_ERROR "Nuget pack failed")
409             endif()
410         endforeach()
411     endif()
412     # Is there any single component package needed?
413     if(CPACK_NUGET_COMPONENTS)
414         _cpack_nuget_debug("---[Making single-component(s) package(s)]---")
415         foreach(_comp IN LISTS CPACK_NUGET_COMPONENTS)
416             _cpack_nuget_debug("Starting to make the package for component `${_comp}`")
417             # Render a spec file which includes only given component
418             unset(_CPACK_NUGET_FILES_TAG)
419             _cpack_nuget_make_files_tag(${_comp})
420             # Temporary set `CPACK_NUGET_PACKAGE_COMPONENT` to the current
421             # component name to properly collect various per group settings
422             set(CPACK_NUGET_PACKAGE_COMPONENT ${_comp})
423             _cpack_nuget_render_spec()
424             unset(CPACK_NUGET_PACKAGE_COMPONENT)
425             execute_process(
426                 COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
427                 WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
428                 RESULT_VARIABLE _nuget_result
429               )
430             if(NOT _nuget_result EQUAL 0)
431                 message(FATAL_ERROR "Nuget pack failed")
432             endif()
433         endforeach()
434     endif()
435 endif()
436
437 file(GLOB_RECURSE GEN_CPACK_OUTPUT_FILES "${CPACK_TEMPORARY_DIRECTORY}/*.nupkg")
438 if(NOT GEN_CPACK_OUTPUT_FILES)
439     message(FATAL_ERROR "NuGet package was not generated at `${CPACK_TEMPORARY_DIRECTORY}`!")
440 endif()
441
442 _cpack_nuget_debug("Generated files: ${GEN_CPACK_OUTPUT_FILES}")