Warning, /frameworks/extra-cmake-modules/modules/ECMWinResolveSymlinks.cmake is written in an unsupported language. File is not indexed.

0001 # SPDX-FileCopyrightText: 2016 Gleb Popov <6yearold@gmail.com>
0002 #
0003 # SPDX-License-Identifier: BSD-3-Clause
0004 
0005 #[=======================================================================[.rst:
0006 ECMWinResolveSymlinks
0007 --------------------------
0008 
0009 Resolve pseudo-symlinks created by git when cloning on Windows.
0010 
0011 ::
0012 
0013   ecm_win_resolve_symlinks(<dir>)
0014 
0015 When git checks out a repository with UNIX symlinks on Windows machine,
0016 it creates a text file for each symlink, containing a relative path to the
0017 real file.
0018 This function would recursively walk over specified directory and replace
0019 pseudo-symlinks with corresponding real file's contents. It would then run
0020 ``git update-index --assume-unchanged`` on them to trick git.
0021 
0022 This is useful for projects like "breeze-icons" that contain many identical
0023 icons implemented as symlinks.
0024 
0025 Since 5.28
0026 #]=======================================================================]
0027 
0028 function(ECM_WIN_RESOLVE_SYMLINKS _dir)
0029   get_filename_component(dir ${_dir} ABSOLUTE)
0030   find_program(GIT_EXECUTABLE git)
0031   if(NOT GIT_EXECUTABLE)
0032     message(SEND_ERROR "Git executable not found!")
0033   endif()
0034 
0035   message(STATUS "Resolving symlinks in ${dir}...")
0036   _find_symlinks(${dir} symlinks)
0037   _portioned_list(symlinks ${symlinks})
0038   foreach(s IN LISTS symlinks)
0039     string(REPLACE ":" ";" s ${s})
0040     _assume_unchanged(NO ${dir} "${s}")
0041     _checkout_symlinks(${dir} "${s}")
0042     _resolve_symlinks(${dir} "${s}")
0043     _assume_unchanged(YES ${dir} "${s}")
0044   endforeach()
0045   message(STATUS "Resolving symlinks in ${dir}... Done.")
0046 
0047   # touch cache every build to force CMake to re-run these functions every time
0048   if(NOT TARGET wrs_touch_cache)
0049     add_custom_target(wrs_touch_cache ALL
0050       COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/CMakeCache.txt
0051     )
0052   endif()
0053 endfunction()
0054 
0055 function(_assume_unchanged mode dir symlinks)
0056   if(mode)
0057     set(flag --assume-unchanged)
0058   else()
0059     set(flag --no-assume-unchanged)
0060   endif()
0061 
0062   execute_process(COMMAND ${GIT_EXECUTABLE} update-index ${flag} ${symlinks}
0063     WORKING_DIRECTORY ${dir}
0064   )
0065 endfunction()
0066 
0067 function(_find_symlinks dir outvar)
0068   execute_process(COMMAND ${GIT_EXECUTABLE} ls-files -s
0069     WORKING_DIRECTORY ${dir}
0070     OUTPUT_VARIABLE out
0071     OUTPUT_STRIP_TRAILING_WHITESPACE
0072   )
0073 
0074   set(${outvar})
0075   if(out)
0076     string(REPLACE "\n" ";" out ${out})
0077 
0078     foreach(f IN LISTS out)
0079       # 120000 0db97052931e18484b6705f3bc644484ef9403b0 0 <tab> icons-dark/actions/16/CVnamespace.svg
0080       string(REPLACE "\t" ";" f "${f}")
0081       string(REPLACE " " ";" f "${f}")
0082       list(GET f 0 mode)
0083       if(mode STREQUAL "120000")
0084         list(GET f 3 symlink)
0085         list(APPEND ${outvar} ${symlink})
0086       endif()
0087     endforeach()
0088   endif()
0089   set(${outvar} ${${outvar}} PARENT_SCOPE)
0090 endfunction()
0091 
0092 # In functions like _checkout_symlinks() the command line can become too lengthy for Windows.
0093 # So we partition it, but in a hacky way due to CMake doesn't have list of lists.
0094 function(_portioned_list outvar)
0095   list(LENGTH ARGN arglen)
0096 
0097   if(arglen EQUAL 0)
0098     set(${outvar} "" PARENT_SCOPE)
0099     return()
0100   endif()
0101 
0102   set(init)
0103   set(tail)
0104   math(EXPR range "${arglen} - 1")
0105   foreach(i RANGE ${range})
0106     list(GET ARGN ${i} v)
0107     string(LENGTH "${init}" initlen)
0108     string(LENGTH ${v} vlen)
0109     math(EXPR sumlen "${initlen} + ${vlen}")
0110     if(sumlen LESS 8192)
0111       list(APPEND init ${v})
0112     else()
0113       list(APPEND tail ${v})
0114     endif()
0115   endforeach()
0116 
0117   _portioned_list(tail_portioned ${tail})
0118   string(REPLACE ";" ":" init "${init}") # Generally this is not safe, because filepath can contain ':' character. But not on Windows. Phew.
0119   set(${outvar} ${init} ${tail_portioned} PARENT_SCOPE)
0120 endfunction()
0121 
0122 function(_checkout_symlinks dir symlinks)
0123   execute_process(COMMAND ${GIT_EXECUTABLE} checkout ${symlinks}
0124     WORKING_DIRECTORY ${dir}
0125   )
0126 endfunction()
0127 
0128 function(_resolve_symlinks dir symlinks)
0129   foreach(s IN LISTS symlinks)
0130     file(READ ${dir}/${s} sdata)
0131     get_filename_component(sdir ${dir}/${s} DIRECTORY)
0132     set(f "${sdir}/${sdata}")
0133     file(READ ${f} fdata)
0134     file(WRITE ${dir}/${s} ${fdata})
0135   endforeach()
0136 endfunction()