Skip to content

Commit ac37fc9

Browse files
committed
cmake: Update GetGitRevisionDescription.cmake from upstream.
- Fixes operation when in a submodule or a secondary worktree. - Avoids potential issue where it would look for a git dir above CMAKE_SOURCE_DIR. - Update maintainer name/contact. Signed-off-by: Rylie Pavlik <rylie.pavlik@collabora.com>
1 parent d188e07 commit ac37fc9

File tree

2 files changed

+269
-95
lines changed

2 files changed

+269
-95
lines changed

cmake/GetGitRevisionDescription.cmake

Lines changed: 244 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# These functions force a re-configure on each git commit so that you can
44
# trust the values of the variables in your build system.
55
#
6-
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
6+
# get_git_head_revision(<refspecvar> <hashvar> [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR])
77
#
88
# Returns the refspec and sha hash of the current head revision
99
#
@@ -12,112 +12,276 @@
1212
# Returns the results of git describe on the source tree, and adjusting
1313
# the output so that it tests false if an error occurs.
1414
#
15+
# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
16+
#
17+
# Returns the results of git describe on the working tree (--dirty option),
18+
# and adjusting the output so that it tests false if an error occurs.
19+
#
1520
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
1621
#
1722
# Returns the results of git describe --exact-match on the source tree,
1823
# and adjusting the output so that it tests false if there was no exact
1924
# matching tag.
2025
#
26+
# git_local_changes(<var>)
27+
#
28+
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
29+
# Uses the return code of "git diff-index --quiet HEAD --".
30+
# Does not regard untracked files.
31+
#
2132
# Requires CMake 2.6 or newer (uses the 'function' command)
2233
#
2334
# Original Author:
24-
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
25-
# http://academic.cleardefinition.com
26-
# Iowa State University HCI Graduate Program/VRAC
35+
# 2009-2020 Rylie Pavlik <rylie@ryliepavlik.com>
36+
# https://ryliepavlik.com/
37+
#
38+
# Copyright 2009-2013, Iowa State University.
39+
# Copyright 2013-2020, Rylie Pavlik
40+
# Copyright 2013-2020, Contributors
41+
#
42+
# SPDX-License-Identifier: BSL-1.0
2743
#
28-
# Copyright Iowa State University 2009-2010.
2944
# Distributed under the Boost Software License, Version 1.0.
3045
# (See accompanying file LICENSE_1_0.txt or copy at
3146
# http://www.boost.org/LICENSE_1_0.txt)
3247

3348
if(__get_git_revision_description)
34-
return()
49+
return()
3550
endif()
3651
set(__get_git_revision_description YES)
3752

3853
# We must run the following at "include" time, not at function call time,
3954
# to find the path to this module rather than the path to a calling list file
4055
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
4156

57+
# Function _git_find_closest_git_dir finds the next closest .git directory
58+
# that is part of any directory in the path defined by _start_dir.
59+
# The result is returned in the parent scope variable whose name is passed
60+
# as variable _git_dir_var. If no .git directory can be found, the
61+
# function returns an empty string via _git_dir_var.
62+
#
63+
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
64+
# neither foo nor bar contain a file/directory .git. This wil return
65+
# C:/bla/.git
66+
#
67+
function(_git_find_closest_git_dir _start_dir _git_dir_var)
68+
set(cur_dir "${_start_dir}")
69+
set(git_dir "${_start_dir}/.git")
70+
while(NOT EXISTS "${git_dir}")
71+
# .git dir not found, search parent directories
72+
set(git_previous_parent "${cur_dir}")
73+
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
74+
if(cur_dir STREQUAL git_previous_parent)
75+
# We have reached the root directory, we are not in git
76+
set(${_git_dir_var}
77+
""
78+
PARENT_SCOPE)
79+
return()
80+
endif()
81+
set(git_dir "${cur_dir}/.git")
82+
endwhile()
83+
set(${_git_dir_var}
84+
"${git_dir}"
85+
PARENT_SCOPE)
86+
endfunction()
87+
4288
function(get_git_head_revision _refspecvar _hashvar)
43-
set(GIT_PARENT_DIR "${CMAKE_SOURCE_DIR}")
44-
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
45-
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
46-
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
47-
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
48-
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
49-
# We have reached the root directory, we are not in git
50-
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
51-
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
52-
return()
53-
endif()
54-
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
55-
endwhile()
56-
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
57-
if(NOT EXISTS "${GIT_DATA}")
58-
file(MAKE_DIRECTORY "${GIT_DATA}")
59-
endif()
60-
61-
if(NOT EXISTS "${GIT_DIR}/HEAD")
62-
return()
63-
endif()
64-
set(HEAD_FILE "${GIT_DATA}/HEAD")
65-
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
66-
67-
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
68-
"${GIT_DATA}/grabRef.cmake"
69-
@ONLY)
70-
include("${GIT_DATA}/grabRef.cmake")
71-
72-
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
73-
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
89+
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
90+
91+
if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR")
92+
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE)
93+
else()
94+
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE)
95+
endif()
96+
if(NOT "${GIT_DIR}" STREQUAL "")
97+
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
98+
"${GIT_DIR}")
99+
if("${_relative_to_source_dir}" MATCHES "[.][.]"
100+
AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
101+
# We've gone above the CMake root dir.
102+
set(GIT_DIR "")
103+
endif()
104+
endif()
105+
if("${GIT_DIR}" STREQUAL "")
106+
set(${_refspecvar}
107+
"GITDIR-NOTFOUND"
108+
PARENT_SCOPE)
109+
set(${_hashvar}
110+
"GITDIR-NOTFOUND"
111+
PARENT_SCOPE)
112+
return()
113+
endif()
114+
115+
# Check if the current source dir is a git submodule or a worktree.
116+
# In both cases .git is a file instead of a directory.
117+
#
118+
if(NOT IS_DIRECTORY ${GIT_DIR})
119+
# The following git command will return a non empty string that
120+
# points to the super project working tree if the current
121+
# source dir is inside a git submodule.
122+
# Otherwise the command will return an empty string.
123+
#
124+
execute_process(
125+
COMMAND "${GIT_EXECUTABLE}" rev-parse
126+
--show-superproject-working-tree
127+
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
128+
OUTPUT_VARIABLE out
129+
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
130+
if(NOT "${out}" STREQUAL "")
131+
# If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
132+
file(READ ${GIT_DIR} submodule)
133+
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
134+
${submodule})
135+
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
136+
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
137+
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
138+
ABSOLUTE)
139+
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
140+
else()
141+
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
142+
file(READ ${GIT_DIR} worktree_ref)
143+
# The .git directory contains a path to the worktree information directory
144+
# inside the parent git repo of the worktree.
145+
#
146+
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
147+
${worktree_ref})
148+
string(STRIP ${git_worktree_dir} git_worktree_dir)
149+
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
150+
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
151+
endif()
152+
else()
153+
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
154+
endif()
155+
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
156+
if(NOT EXISTS "${GIT_DATA}")
157+
file(MAKE_DIRECTORY "${GIT_DATA}")
158+
endif()
159+
160+
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
161+
return()
162+
endif()
163+
set(HEAD_FILE "${GIT_DATA}/HEAD")
164+
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
165+
166+
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
167+
"${GIT_DATA}/grabRef.cmake" @ONLY)
168+
include("${GIT_DATA}/grabRef.cmake")
169+
170+
set(${_refspecvar}
171+
"${HEAD_REF}"
172+
PARENT_SCOPE)
173+
set(${_hashvar}
174+
"${HEAD_HASH}"
175+
PARENT_SCOPE)
74176
endfunction()
75177

76178
function(git_describe _var)
77-
if(NOT GIT_FOUND)
78-
find_package(Git QUIET)
79-
endif()
80-
get_git_head_revision(refspec hash)
81-
if(NOT GIT_FOUND)
82-
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
83-
return()
84-
endif()
85-
if(NOT hash)
86-
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
87-
return()
88-
endif()
89-
90-
# TODO sanitize
91-
#if((${ARGN}" MATCHES "&&") OR
92-
# (ARGN MATCHES "||") OR
93-
# (ARGN MATCHES "\\;"))
94-
# message("Please report the following error to the project!")
95-
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
96-
#endif()
97-
98-
#message(STATUS "Arguments to execute_process: ${ARGN}")
99-
100-
execute_process(COMMAND
101-
"${GIT_EXECUTABLE}"
102-
describe
103-
${hash}
104-
${ARGN}
105-
WORKING_DIRECTORY
106-
"${CMAKE_SOURCE_DIR}"
107-
RESULT_VARIABLE
108-
res
109-
OUTPUT_VARIABLE
110-
out
111-
ERROR_QUIET
112-
OUTPUT_STRIP_TRAILING_WHITESPACE)
113-
if(NOT res EQUAL 0)
114-
set(out "${out}-${res}-NOTFOUND")
115-
endif()
116-
117-
set(${_var} "${out}" PARENT_SCOPE)
179+
if(NOT GIT_FOUND)
180+
find_package(Git QUIET)
181+
endif()
182+
get_git_head_revision(refspec hash)
183+
if(NOT GIT_FOUND)
184+
set(${_var}
185+
"GIT-NOTFOUND"
186+
PARENT_SCOPE)
187+
return()
188+
endif()
189+
if(NOT hash)
190+
set(${_var}
191+
"HEAD-HASH-NOTFOUND"
192+
PARENT_SCOPE)
193+
return()
194+
endif()
195+
196+
# TODO sanitize
197+
#if((${ARGN}" MATCHES "&&") OR
198+
# (ARGN MATCHES "||") OR
199+
# (ARGN MATCHES "\\;"))
200+
# message("Please report the following error to the project!")
201+
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
202+
#endif()
203+
204+
#message(STATUS "Arguments to execute_process: ${ARGN}")
205+
206+
execute_process(
207+
COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
208+
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
209+
RESULT_VARIABLE res
210+
OUTPUT_VARIABLE out
211+
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
212+
if(NOT res EQUAL 0)
213+
set(out "${out}-${res}-NOTFOUND")
214+
endif()
215+
216+
set(${_var}
217+
"${out}"
218+
PARENT_SCOPE)
219+
endfunction()
220+
221+
function(git_describe_working_tree _var)
222+
if(NOT GIT_FOUND)
223+
find_package(Git QUIET)
224+
endif()
225+
if(NOT GIT_FOUND)
226+
set(${_var}
227+
"GIT-NOTFOUND"
228+
PARENT_SCOPE)
229+
return()
230+
endif()
231+
232+
execute_process(
233+
COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
234+
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
235+
RESULT_VARIABLE res
236+
OUTPUT_VARIABLE out
237+
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
238+
if(NOT res EQUAL 0)
239+
set(out "${out}-${res}-NOTFOUND")
240+
endif()
241+
242+
set(${_var}
243+
"${out}"
244+
PARENT_SCOPE)
118245
endfunction()
119246

120247
function(git_get_exact_tag _var)
121-
git_describe(out --exact-match ${ARGN})
122-
set(${_var} "${out}" PARENT_SCOPE)
248+
git_describe(out --exact-match ${ARGN})
249+
set(${_var}
250+
"${out}"
251+
PARENT_SCOPE)
252+
endfunction()
253+
254+
function(git_local_changes _var)
255+
if(NOT GIT_FOUND)
256+
find_package(Git QUIET)
257+
endif()
258+
get_git_head_revision(refspec hash)
259+
if(NOT GIT_FOUND)
260+
set(${_var}
261+
"GIT-NOTFOUND"
262+
PARENT_SCOPE)
263+
return()
264+
endif()
265+
if(NOT hash)
266+
set(${_var}
267+
"HEAD-HASH-NOTFOUND"
268+
PARENT_SCOPE)
269+
return()
270+
endif()
271+
272+
execute_process(
273+
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
274+
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
275+
RESULT_VARIABLE res
276+
OUTPUT_VARIABLE out
277+
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
278+
if(res EQUAL 0)
279+
set(${_var}
280+
"CLEAN"
281+
PARENT_SCOPE)
282+
else()
283+
set(${_var}
284+
"DIRTY"
285+
PARENT_SCOPE)
286+
endif()
123287
endfunction()

0 commit comments

Comments
 (0)