-
Notifications
You must be signed in to change notification settings - Fork 16
/
RevisionTools.cmake
283 lines (261 loc) · 9.67 KB
/
RevisionTools.cmake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# ============================================================================
# Copyright (c) 2011-2012 University of Pennsylvania
# Copyright (c) 2013-2014 Andreas Schuh
# All rights reserved.
#
# See COPYING file for license information or visit
# http://opensource.andreasschuh.com/cmake-basis/download.html#license
# ============================================================================
##############################################################################
# @file RevisionTools.cmake
# @brief CMake functions and macros related to revision control systems.
#
# @ingroup CMakeTools
##############################################################################
if (__BASIS_REVISIONTOOLS_INCLUDED)
return ()
else ()
set (__BASIS_REVISIONTOOLS_INCLUDED TRUE)
endif ()
# ============================================================================
# required commands
# ============================================================================
find_package (Subversion QUIET)
find_package (Git QUIET)
## @addtogroup CMakeUtilities
# @{
# ============================================================================
# Subversion
# ============================================================================
# ----------------------------------------------------------------------------
## @brief Get current revision of file or directory.
#
# @param [in] URL Absolute path to directory or file. May also be a URL to the
# directory or file in the repository. A leading "file://" is
# automatically removed such that the svn command treats it as a
# local path.
# @param [out] REV The revision number of URL. If URL is not under revision
# control or Subversion_SVN_EXECUTABLE is invalid, "0" is returned.
#
# @returns Sets @p REV to the revision of the working copy/repository
# at URL @p URL.
function (basis_svn_get_revision URL REV)
set (OUT 0)
if (Subversion_SVN_EXECUTABLE)
# remove "file://" from URL
string (REGEX REPLACE "file://" "" TMP "${URL}")
# retrieve SVN info
execute_process (
COMMAND "${Subversion_SVN_EXECUTABLE}" info "${TMP}"
OUTPUT_VARIABLE OUT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (BASIS_DEBUG)
message ("** basis_svn_get_revision()")
message ("** svn info: ${OUT}")
endif ()
# extract revision
if (OUT MATCHES "^(.*\n)?Revision: ([^\n]+).*" AND NOT CMAKE_MATCH_2 STREQUAL "")
set (OUT "${CMAKE_MATCH_2}")
else ()
set (OUT 0)
endif ()
endif ()
# return
set ("${REV}" "${OUT}" PARENT_SCOPE)
endfunction ()
# ----------------------------------------------------------------------------
## @brief Get revision number when directory or file was last changed.
#
# @param [in] URL Absolute path to directory or file. May also be a URL to the
# directory or file in the repository. A leading "file://" is
# automatically removed such that the svn command treats it as a
# local path.
# @param [out] REV Revision number when URL was last modified. If URL is not
# under Subversion control or Subversion_SVN_EXECUTABLE is invalid,
# "0" is returned.
#
# @returns Sets @p REV to revision number at which the working copy/repository
# specified by the URL @p URL was last modified.
function (basis_svn_get_last_changed_revision URL REV)
set (OUT 0)
if (Subversion_SVN_EXECUTABLE)
# remove "file://" from URL
string (REGEX REPLACE "file://" "" TMP "${URL}")
# retrieve SVN info
execute_process (
COMMAND "${Subversion_SVN_EXECUTABLE}" info "${TMP}"
OUTPUT_VARIABLE OUT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (BASIS_DEBUG)
message ("** basis_svn_get_revision()")
message ("** svn info: ${OUT}")
endif ()
# extract last changed revision
if (OUT MATCHES "^(.*\n)?Last Changed Rev: ([^\n]+).*" AND NOT CMAKE_MATCH_2 STREQUAL "")
set (OUT "${CMAKE_MATCH_2}")
else ()
set (OUT 0)
endif ()
endif ()
# return
set ("${REV}" "${OUT}" PARENT_SCOPE)
endfunction ()
# ----------------------------------------------------------------------------
## @brief Get status of revision controlled file.
#
# @param [in] URL Absolute path to directory or file. May also be a URL to
# the directory or file in the repository.
# A leading "file://" will be removed such that the svn
# command treats it as a local path.
# @param [out] STATUS The status of URL as returned by 'svn status'.
# If the local directory or file is unmodified, an
# empty string is returned. An empty string is also
# returned when Subversion_SVN_EXECUTABLE is invalid.
#
# @returns Sets @p STATUS to the output of the <tt>svn info</tt> command.
function (basis_svn_status URL STATUS)
if (Subversion_SVN_EXECUTABLE)
# remove "file://" from URL
string (REGEX REPLACE "file://" "" TMP "${URL}")
# retrieve SVN status of URL
execute_process (
COMMAND "${Subversion_SVN_EXECUTABLE}" status "${TMP}"
OUTPUT_VARIABLE OUT
ERROR_QUIET
)
# return
set ("${STATUS}" "${OUT}" PARENT_SCOPE)
else ()
set ("${STATUS}" "" PARENT_SCOPE)
endif ()
endfunction ()
# ============================================================================
# Git
# ============================================================================
# ----------------------------------------------------------------------------
# @brief Determine whether or not a given directory is a Git repository
function (basis_is_git_repository FLAG DIR)
if (GITCOMMAND AND NOT GIT_EXECUTABLE)
set (GIT_EXECUTABLE GITCOMMAND)
endif ()
if (GIT_EXECUTABLE)
execute_process (
COMMAND "${GIT_EXECUTABLE}" rev-parse
WORKING_DIRECTORY "${DIR}"
RESULT_VARIABLE RETVAL
OUTPUT_QUIET
ERROR_QUIET
)
else ()
set (RETVAL 1)
endif ()
if (RETVAL EQUAL 0)
set (${FLAG} "TRUE" PARENT_SCOPE)
else ()
set (${FLAG} "FALSE" PARENT_SCOPE)
endif ()
endfunction ()
# ----------------------------------------------------------------------------
## @brief Get HEAD commit SHA of file or directory.
#
# @param [in] URL Absolute path to repository directory or single file.
# @param [out] REV The short commit SHA when URL was last modified. If URL
# is not under Git control or GIT_EXECUTABLE is invalid,
# "0" is returned.
# @param [in] ARGN Length of commit SHA to return.
#
# @returns Sets @p REV either to the HEAD commit SHA of the repository at
# directory @p URL or the last commit which modified the file.
function (basis_git_get_revision URL REV)
if (ARGC GREATER 3)
message (FATAL_ERROR "basis_git_get_revision: Too many arguments")
endif ()
set (OUT 0)
if (GITCOMMAND AND NOT GIT_EXECUTABLE)
set (GIT_EXECUTABLE GITCOMMAND)
endif ()
if (GIT_EXECUTABLE)
# remove "file://" from URL
string (REGEX REPLACE "file://" "" DIR "${URL}")
# retrieve Git commit SHA of HEAD
if (IS_DIRECTORY "${DIR}")
execute_process (
COMMAND "${GIT_EXECUTABLE}" rev-parse HEAD
WORKING_DIRECTORY "${DIR}"
OUTPUT_VARIABLE OUT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (BASIS_DEBUG)
message ("** basis_git_get_revision()")
message ("** DIR: ${DIR}")
message ("** OUT: ${OUT}")
endif ()
# retrieve Git commit SHA when file was last modified
else ()
basis_get_filename_component(OBJ "${DIR}" NAME)
basis_get_filename_component(DIR "${DIR}" PATH)
execute_process (
COMMAND "${GIT_EXECUTABLE}" log -n 1 -- "${OBJ}"
WORKING_DIRECTORY "${DIR}"
OUTPUT_VARIABLE OUT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (BASIS_DEBUG)
message ("** basis_git_get_revision()")
message ("** DIR: ${DIR}")
message ("** OBJ: ${OBJ}")
message ("** OUT: ${OUT}")
endif ()
# extract commit SHA
if (OUT MATCHES "commit ([0-9a-f]+).*" AND NOT CMAKE_MATCH_1 STREQUAL "")
set (OUT "${CMAKE_MATCH_1}")
else ()
set (OUT 0)
endif ()
endif ()
endif ()
if (ARGC EQUAL 3)
string (SUBSTRING "${OUT}" 0 "${ARGV2}" OUT)
endif ()
# return
set ("${REV}" "${OUT}" PARENT_SCOPE)
endfunction ()
# ============================================================================
# Meta
# ============================================================================
# ----------------------------------------------------------------------------
## @brief Get revision of file or directory.
#
# @param [in] URL Absolute path to directory or single file.
# @param [out] REV Revision number when directory / repository or file was
# last modified, "0" is returned when no known revision
# control system is used or revision command not found.
#
# @returns Revision when directory of file was last modified.
function (basis_get_revision URL REV)
# remove "file://" from URL
string (REGEX REPLACE "file://" "" DIR "${URL}")
# get directory path
if (NOT IS_DIRECTORY "${URL}")
basis_get_filename_component (DIR "${URL}" PATH)
else ()
set (DIR "${URL}")
endif ()
# check if directory is part of a Git repository
basis_is_git_repository (IS_GIT_REPOSITORY "${DIR}")
if (IS_GIT_REPOSITORY)
basis_git_get_revision ("${URL}" OUT 7)
else ()
basis_svn_get_last_changed_revision ("${URL}" OUT)
endif ()
# return revision
set ("${REV}" "${OUT}" PARENT_SCOPE)
endfunction ()
## @}
# end of Doxygen group