Files
Breeze/breeze/cmake/GitignoreSync.cmake
T
2026-10-24 09:53:48 -03:00

115 lines
5.4 KiB
CMake

# =============================================================================
# .gitignore sync
#
# Keeps a marked block in .gitignore in sync with the actual, current
# values of the path variables above -- every configure, automatically.
# Nothing outside that block (e.g. the Visual Studio template this
# project's .gitignore starts from) is ever touched. This is what makes
# this file the real source of truth for these paths specifically: change
# OUT_DIR (or override it with -DOUT_DIR=...) and .gitignore updates on
# the next configure instead of silently drifting out of sync with what
# actually gets generated.
#
# If .gitignore doesn't exist yet, it's created with just this block. If
# it exists but has no markers yet, the block is appended. If the markers
# are already there, only the content between them is replaced. The file
# is only rewritten when the computed content actually differs, so a
# normal reconfigure doesn't spuriously touch it (or its mtime).
#
# A path is only added if it resolves inside the repo (CMAKE_SOURCE_DIR)
# -- e.g. an overridden TOOLCACHE_DIR pointing somewhere else entirely is
# silently skipped, since .gitignore has nothing meaningful to say about
# a location outside the repository it lives in.
#
# Skipped entirely in query mode -- see "How scripts read this file"
# above.
# =============================================================================
include_guard(GLOBAL)
# out/dist/ is reserved (see the output layout in project/Configuration.cmake) and
# nothing writes to it yet, so it is created eagerly here -- otherwise it simply
# would not exist until something populates it, which could easily read as "this
# was never wired up" rather than "intentionally reserved for later". A file
# system side effect, so it lives here and not in the settings file: a script's
# query of those settings runs far more often than a real configure.
file(MAKE_DIRECTORY "${DIST_OUTPUT_DIR}")
set(_pmn_gitignore_begin "# >>> Configuration.cmake generated paths -- BEGIN (do not edit by hand; edit Configuration.cmake and reconfigure) >>>")
set(_pmn_gitignore_end "# <<< Configuration.cmake generated paths -- END <<<")
function(_pmn_gitignore_relpath ABSOLUTE_VALUE OUT_VAR)
file(RELATIVE_PATH _pmn_rel "${CMAKE_SOURCE_DIR}" "${ABSOLUTE_VALUE}")
if(_pmn_rel MATCHES "^\\.\\.")
set(${OUT_VAR} "" PARENT_SCOPE)
else()
set(${OUT_VAR} "${_pmn_rel}" PARENT_SCOPE)
endif()
endfunction()
set(_pmn_gitignore_entries "")
foreach(_pmn_dir_var OUT_DIR BUILD_OUTPUT_DIR DIST_OUTPUT_DIR INSTALL_OUTPUT_DIR DOCS_OUTPUT_DIR TOOLCACHE_DIR)
_pmn_gitignore_relpath("${${_pmn_dir_var}}" _pmn_rel)
if(_pmn_rel)
list(APPEND _pmn_gitignore_entries "${_pmn_rel}/")
endif()
endforeach()
_pmn_gitignore_relpath("${COMPILE_COMMANDS_DESTINATION}" _pmn_cc_rel)
if(_pmn_cc_rel)
list(APPEND _pmn_gitignore_entries "${_pmn_cc_rel}")
endif()
# breeze/scripts/run.sh keeps the wine prefixes it creates in .cache/wine/ -- a
# fixed place, not one of the path variables above. Listed here rather
# than added to .gitignore by hand: this block is rewritten on every
# configure, which silently deleted a hand-added line.
list(APPEND _pmn_gitignore_entries ".cache/wine/")
# Likewise the target sysroots breeze/cmake/toolchains/_common.cmake looks for
# in .cache/sysroots/linux-<arch> (see pmn_find_sysroot there): root
# filesystems for cross builds, hundreds of megabytes, never to commit.
list(APPEND _pmn_gitignore_entries ".cache/sysroots/")
list(REMOVE_DUPLICATES _pmn_gitignore_entries)
list(SORT _pmn_gitignore_entries)
set(_pmn_gitignore_block_content "")
foreach(_pmn_entry ${_pmn_gitignore_entries})
string(APPEND _pmn_gitignore_block_content "${_pmn_entry}\n")
endforeach()
set(_pmn_gitignore_path "${CMAKE_SOURCE_DIR}/.gitignore")
set(_pmn_gitignore_new_block "${_pmn_gitignore_begin}\n${_pmn_gitignore_block_content}${_pmn_gitignore_end}")
if(EXISTS "${_pmn_gitignore_path}")
file(READ "${_pmn_gitignore_path}" _pmn_gitignore_content)
else()
set(_pmn_gitignore_content "")
endif()
string(FIND "${_pmn_gitignore_content}" "${_pmn_gitignore_begin}" _pmn_gitignore_begin_pos)
string(FIND "${_pmn_gitignore_content}" "${_pmn_gitignore_end}" _pmn_gitignore_end_pos)
if(_pmn_gitignore_begin_pos GREATER -1 AND _pmn_gitignore_end_pos GREATER -1
AND _pmn_gitignore_end_pos GREATER _pmn_gitignore_begin_pos)
# Replace only the content between the existing markers.
string(SUBSTRING "${_pmn_gitignore_content}" 0 ${_pmn_gitignore_begin_pos} _pmn_gitignore_before)
string(LENGTH "${_pmn_gitignore_end}" _pmn_gitignore_end_marker_len)
math(EXPR _pmn_gitignore_after_start "${_pmn_gitignore_end_pos} + ${_pmn_gitignore_end_marker_len}")
string(SUBSTRING "${_pmn_gitignore_content}" ${_pmn_gitignore_after_start} -1 _pmn_gitignore_after)
set(_pmn_gitignore_final "${_pmn_gitignore_before}${_pmn_gitignore_new_block}${_pmn_gitignore_after}")
else()
# No markers yet -- append (trimming trailing blank lines first so we
# don't accumulate extra blank lines across repeated appends).
string(REGEX REPLACE "\n+$" "" _pmn_gitignore_trimmed "${_pmn_gitignore_content}")
if(_pmn_gitignore_trimmed STREQUAL "")
set(_pmn_gitignore_final "${_pmn_gitignore_new_block}\n")
else()
set(_pmn_gitignore_final "${_pmn_gitignore_trimmed}\n\n${_pmn_gitignore_new_block}\n")
endif()
endif()
if(NOT _pmn_gitignore_final STREQUAL _pmn_gitignore_content)
file(WRITE "${_pmn_gitignore_path}" "${_pmn_gitignore_final}")
endif()