]>
Commit | Line | Data |
---|---|---|
c0f9d4b0 FCE |
1 | #!/bin/sh |
2 | # | |
3 | # Generate some basic versioning information which can be piped to a header. | |
4 | # | |
5 | # Copyright (c) 2006-2007 Luc Verhaegen <libv@skynet.be> | |
2899dcf6 FCE |
6 | # Copyright (C) 2007-2008 Hans Ulrich Niedermann <hun@n-dimensional.de> |
7 | # Copyright (C) 2021 Lawrence Sebald | |
c0f9d4b0 FCE |
8 | # |
9 | # Permission is hereby granted, free of charge, to any person obtaining a | |
10 | # copy of this software and associated documentation files (the "Software"), | |
11 | # to deal in the Software without restriction, including without limitation | |
12 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
13 | # and/or sell copies of the Software, and to permit persons to whom the | |
14 | # Software is furnished to do so, subject to the following conditions: | |
15 | # | |
16 | # The above copyright notice and this permission notice shall be included in | |
17 | # all copies or substantial portions of the Software. | |
18 | # | |
19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
22 | # THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
25 | # OTHER DEALINGS IN THE SOFTWARE. | |
26 | # | |
27 | # This script is based on the one written for xf86-video-unichrome by | |
28 | # Luc Verhaegen, but was rewritten almost completely by Hans Ulrich | |
29 | # Niedermann. The script contains a few bug fixes from Egbert Eich, | |
2899dcf6 FCE |
30 | # Matthias Hopf, Joerg Sonnenberger, and possibly others. Later modified |
31 | # for Sylverant by Lawrence Sebald. | |
c0f9d4b0 FCE |
32 | # |
33 | # The author thanks the nice people on #git for the assistance. | |
34 | # | |
35 | # Simple testing of this script: | |
36 | # /sbin/busybox sh git_version.sh --example > moo.c \ | |
37 | # && gcc -Wall -Wextra -Wno-unused -o moo moo.c \ | |
38 | # && ./moo | |
39 | # (bash should also do) | |
40 | # | |
41 | # For how to hook this up to your automake- and/or imake-based build | |
42 | # system, best take a look at how the RadeonHD.am and/or RadeonHD.tmpl | |
43 | # work in the xf86-video-radeonhd build system. For non-recursive make, | |
44 | # you can probably make things a little bit simpler. | |
45 | # | |
2899dcf6 FCE |
46 | # Requires git >= 1.3.0 for the 'git foo' (with space) syntax, |
47 | # and git >= 1.4 for some specific commands. | |
c0f9d4b0 FCE |
48 | |
49 | # Help messages | |
50 | USAGE="[<option>...]" | |
51 | LONG_USAGE="\ | |
52 | Options: | |
53 | -h, --help Print this help message. | |
54 | ||
55 | -k, --keep-if-no-repo Keep old output file if no git repo found. | |
56 | -o, --output FILENAME Set output file name. | |
57 | -q, --quiet Quiet output. | |
58 | -s, --srcdir DIRNAME Set source tree dir name. | |
59 | -x, --example Print complete example program." | |
60 | ||
61 | # The caller may have set these for us | |
62 | SED="${SED-sed}" | |
2899dcf6 | 63 | GIT="${GIT-git}" |
c0f9d4b0 FCE |
64 | |
65 | # Initialize | |
2899dcf6 | 66 | working_dir=`pwd` |
c0f9d4b0 FCE |
67 | |
68 | # Who am I? | |
2899dcf6 | 69 | self=`basename "$0"` |
c0f9d4b0 FCE |
70 | |
71 | # Defaults | |
72 | ifndef_symbol="GIT_VERSION_H" | |
73 | outfile="-" | |
74 | print_example=false | |
75 | keep_if_no_repo=no | |
76 | quiet=false | |
2899dcf6 | 77 | srcdir=`pwd` |
c0f9d4b0 FCE |
78 | |
79 | # Parse command line parameter, affecting defaults | |
80 | while [ "x$1" != "x" ] | |
81 | do | |
82 | case "$1" in | |
83 | -x|--example) | |
84 | print_example=: | |
85 | ;; | |
86 | -o|--output) | |
87 | if shift; then | |
88 | outfile="$1" | |
89 | if [ "x$outfile" = "x-" ]; then | |
90 | : # keep default ifndef_symbol | |
91 | else | |
92 | ifndef_symbol=`basename "$outfile" | $SED 's|\.|_|g; s|[^A-Za-z0-9_]||g' | tr a-z A-Z` | |
93 | fi | |
94 | else | |
95 | echo "$self: Fatal: \"$1\" option requires parameter." >&2 | |
96 | exit 1 | |
97 | fi | |
98 | ;; | |
99 | -q|--quiet) | |
100 | quiet=: | |
101 | ;; | |
102 | -h|--help) | |
103 | echo "Usage: ${self} $USAGE" | |
104 | [ -n "$LONG_USAGE" ] && echo "$LONG_USAGE" | |
105 | exit | |
106 | ;; | |
107 | -k|--keep-if-no-repo) | |
108 | keep_if_no_repo=yes | |
109 | ;; | |
110 | -s|--srcdir) | |
111 | if shift; then | |
112 | if test -d "$1"; then | |
113 | srcdir="$1" | |
114 | else | |
115 | echo "$self: Fatal: \"$1\" not a directory." >&2 | |
116 | exit 1 | |
117 | fi | |
118 | else | |
119 | echo "$self: Fatal: \"$1\" option requires directory parameter." >&2 | |
120 | exit 1 | |
121 | fi | |
122 | ;; | |
123 | *) | |
124 | echo "$self: Fatal: Invalid command line paramenter: \"$1\"" >&2 | |
125 | exit 1 | |
126 | ;; | |
127 | esac | |
128 | shift | |
129 | done | |
130 | ||
2899dcf6 | 131 | # If not printing to stdout, redirect stdout to output file? |
c0f9d4b0 FCE |
132 | rename_new_output=false |
133 | if [ "x$outfile" = "x-" ] | |
134 | then | |
135 | : # keep using stdout | |
136 | else | |
2899dcf6 | 137 | exec 1> "${outfile}.new" |
c0f9d4b0 FCE |
138 | fi |
139 | ||
140 | # Done with creating output files, so we can change to source dir | |
2899dcf6 | 141 | abs_srcdir=`cd "$srcdir" && pwd` |
c0f9d4b0 FCE |
142 | cd "$srcdir" |
143 | ||
144 | # Write program header | |
145 | cat<<EOF | |
146 | /* | |
147 | * Basic versioning gathered from the git repository. | |
148 | * Automatically generated by $0. | |
149 | */ | |
150 | ||
151 | #ifndef ${ifndef_symbol} | |
152 | #define ${ifndef_symbol} 1 | |
153 | ||
2899dcf6 FCE |
154 | #include <stdint.h> |
155 | ||
c0f9d4b0 FCE |
156 | /* whether this is a dist tarball or not */ |
157 | #undef GIT_IS_DIST | |
158 | ||
159 | EOF | |
160 | ||
2899dcf6 | 161 | # Detect git tool (should work with old and new git versions) |
f66e74de FCE |
162 | if type $GIT >/dev/null 2>&1; then |
163 | git_found=yes | |
164 | else | |
165 | git_found="'$GIT' not found" | |
2899dcf6 FCE |
166 | fi |
167 | # If git_found=yes, we can now use $() substitutions (as git does). Hooray! | |
c0f9d4b0 FCE |
168 | |
169 | # Determine git specific defines | |
170 | unset git_errors ||: | |
171 | if [ "x$git_found" = "xyes" ]; then | |
2899dcf6 | 172 | git_version=`$GIT --version` |
c0f9d4b0 | 173 | if [ "x$git_version" = "x" ]; then |
2899dcf6 | 174 | git_errors="${git_errors+${git_errors}; }error running '$GIT --version'" |
c0f9d4b0 FCE |
175 | fi |
176 | fi | |
177 | ||
178 | git_repo=no | |
179 | # "git-rev-parse --git-dir" since git-0.99.7 | |
2899dcf6 | 180 | git_repo_dir="$($GIT rev-parse --git-dir 2> /dev/null || true)" |
c0f9d4b0 | 181 | abs_repo_dir="$(cd "$git_repo_dir" && pwd)" |
a73db1bd FCE |
182 | # Don't be so picky as to only accept the found git repo iff it is in |
183 | # our top srcdir, as determined by comparing absolute pathnames | |
184 | # created by running pwd in the respective dir. That is incompatible | |
185 | # with "git worktree" instances. | |
186 | if [ "x$git_repo_dir" != "x" ]; then # | |
c0f9d4b0 FCE |
187 | git_repo=yes |
188 | if [ "x$git_found" = "xyes" ]; then | |
189 | # git-1.4 and probably earlier understand "git-rev-parse HEAD" | |
2899dcf6 | 190 | git_shaid=`$GIT rev-parse HEAD` |
c0f9d4b0 | 191 | if [ "x$git_shaid" = "x" ]; then |
2899dcf6 FCE |
192 | git_errors="${git_errors+${git_errors}; }error running '$GIT rev-parse HEAD'" |
193 | fi | |
194 | git_shaid_short=`$GIT rev-parse HEAD | $SED -n 's/^\(.\{8\}\).*/\1/p'` | |
195 | if [ "x$git_shaid_short" = "x" ]; then | |
196 | git_errors="${git_errors+${git_errors}; }error running '$GIT rev-parse HEAD'" | |
c0f9d4b0 FCE |
197 | fi |
198 | # git-1.4 and probably earlier understand "git-symbolic-ref HEAD" | |
2899dcf6 | 199 | git_branch=`$GIT symbolic-ref HEAD | $SED -n 's|^refs/heads/||p'` |
c0f9d4b0 FCE |
200 | if [ "x$git_branch" = "x" ]; then |
201 | # This happens, is OK, and "(no branch)" is what "git branch" prints. | |
202 | git_branch="(no branch)" | |
203 | fi | |
204 | git_dirty=yes | |
205 | # git-1.4 does not understand "git-diff-files --quiet" | |
206 | # git-1.4 does not understand "git-diff-index --cached --quiet HEAD" | |
2899dcf6 | 207 | if [ "x$($GIT diff-files)" = "x" ] && [ "x$($GIT diff-index --cached HEAD)" = "x" ]; then |
c0f9d4b0 FCE |
208 | git_dirty=no |
209 | fi | |
2899dcf6 FCE |
210 | # Grab the origin url, stripping out any credentials that might be in it |
211 | git_remote_url=`$GIT config --get remote.origin.url | $SED -nE 's/^(.*:\/\/)(.*\@)?(.*)$/\3/p'` | |
212 | if [ "x$git_remote_url" = "x" ]; then | |
213 | git_remote_url="(no remote)" | |
214 | fi | |
215 | # Grab the linear git revision number | |
216 | git_build=`$GIT log --oneline | wc -l | $SED 's/^[ \t]*//'` | |
4c6771bd | 217 | if [ "x$git_build" = "x" ]; then |
2899dcf6 FCE |
218 | git_errors="${git_errors+${git_errors}; }error running '$GIT log --oneline'" |
219 | fi | |
220 | # Grab the "pretty" revision number | |
f06461a9 | 221 | git_pretty_rev=`$GIT describe --dirty --always --abbrev=8` |
4c6771bd | 222 | if [ "x$git_pretty_rev" = "x" ]; then |
2899dcf6 FCE |
223 | git_errors="${git_errors+${git_errors}; }error running '$GIT describe'" |
224 | fi | |
225 | # Grab the commit timestamp | |
6b17715f | 226 | git_timestamp=`$GIT show -s --format=%ct | tail -1` |
2899dcf6 FCE |
227 | if [ "x$git_timestamp" = "x" ]; then |
228 | git_errors="${git_errors+${git_errors}; }error running '$GIT show -s --format=%ct'" | |
229 | fi | |
c0f9d4b0 FCE |
230 | fi |
231 | fi | |
232 | ||
233 | # Write git specific defines | |
234 | if [ "x$git_errors" = "x" ]; then | |
235 | echo "/* No errors occured while running git */" | |
236 | echo "#undef GIT_ERRORS" | |
237 | else | |
238 | echo "/* Some errors occured while running git */" | |
239 | echo "#define GIT_ERRORS \"${git_errors}\"" | |
240 | fi | |
241 | echo "" | |
242 | ||
243 | if [ "x$git_found" = "xyes" ]; then | |
244 | echo "/* git utilities found */" | |
245 | echo "#undef GIT_NOT_FOUND" | |
246 | echo "#define GIT_VERSION \"${git_version}\"" | |
247 | else | |
248 | echo "/* git utilities not found */" | |
249 | echo "#define GIT_NOT_FOUND \"${git_found}\"" | |
250 | echo "#undef GIT_VERSION" | |
251 | fi | |
252 | echo "" | |
253 | ||
2899dcf6 FCE |
254 | if :; then # debug output |
255 | cat<<EOF | |
256 | /* The following helps debug why we sometimes do not find ".git/": | |
257 | * abs_repo_dir="${abs_repo_dir}" (should be "/path/to/.git") | |
258 | * abs_srcdir="${abs_srcdir}" (absolute top source dir "/path/to") | |
259 | * git_repo_dir="${git_repo_dir}" (usually ".git" or "/path/to/.git") | |
260 | * PWD="${PWD}" | |
261 | * srcdir="${srcdir}" | |
262 | * working_dir="${working_dir}" | |
263 | */ | |
264 | ||
265 | EOF | |
266 | fi | |
267 | ||
c0f9d4b0 FCE |
268 | if [ "x$git_repo" = "xno" ]; then |
269 | echo "/* No git repo found, probably building from dist tarball */" | |
270 | echo "#undef GIT_REPO" | |
271 | else | |
272 | echo "/* git repo found */" | |
273 | echo "#define GIT_REPO 1" | |
274 | echo "" | |
275 | if [ "x$git_found" = "xyes" ]; then | |
2899dcf6 | 276 | echo "/* Full git SHA ID of last commit */" |
c0f9d4b0 FCE |
277 | echo "#define GIT_SHAID \"${git_shaid}\"" |
278 | echo "" | |
279 | ||
2899dcf6 FCE |
280 | echo "/* Short form of the above */" |
281 | echo "#define GIT_SHAID_SHORT \"${git_shaid_short}\"" | |
282 | echo "" | |
283 | ||
c0f9d4b0 FCE |
284 | echo "/* Branch this tree is on */" |
285 | echo "#define GIT_BRANCH \"$git_branch\"" | |
286 | echo "" | |
287 | ||
2899dcf6 FCE |
288 | echo "/* Remote URL this tree was cloned from */" |
289 | echo "#define GIT_REMOTE_URL \"$git_remote_url\"" | |
290 | echo "" | |
291 | ||
292 | echo "/* Linear revision number from the repository */" | |
293 | echo "#define GIT_BUILD \"$git_build\"" | |
294 | echo "" | |
295 | ||
296 | echo "/* Pretty git revision string for presenting to the user */" | |
297 | echo "#define GIT_PRETTY_REV \"$git_pretty_rev\"" | |
298 | echo "" | |
299 | ||
300 | echo "/* Timestamp of the current commit */" | |
301 | echo "#define GIT_TIMESTAMP UINT64_C($git_timestamp)" | |
302 | echo "" | |
303 | ||
c0f9d4b0 FCE |
304 | # Any uncommitted changes we should know about? |
305 | # Or technically: Are the working tree or index dirty? | |
306 | if [ "x$git_dirty" = "xno" ]; then | |
307 | echo "/* SHA-ID uniquely defines the state of this code */" | |
308 | echo "#undef GIT_DIRTY" | |
309 | else | |
310 | echo "/* Local changes might be breaking things */" | |
311 | echo "#define GIT_DIRTY 1" | |
312 | fi | |
313 | fi | |
314 | fi | |
315 | ||
316 | # Define a few immediately useful message strings | |
317 | cat<<EOF | |
318 | ||
319 | /* Define GIT_MESSAGE such that | |
320 | * printf("%s: built from %s", argv[0], GIT_MESSAGE); | |
321 | * forms a proper sentence. | |
322 | */ | |
323 | ||
324 | #ifdef GIT_DIRTY | |
2899dcf6 | 325 | # define GIT_DIRTY_MSG "-dirty" |
c0f9d4b0 FCE |
326 | #else /* !GIT_DIRTY */ |
327 | # define GIT_DIRTY_MSG "" | |
328 | #endif /* GIT_DIRTY */ | |
329 | ||
330 | #ifdef GIT_ERRORS | |
331 | # define GIT_ERROR_MSG " with error: " GIT_ERRORS | |
332 | #else /* !GIT_ERRORS */ | |
333 | # define GIT_ERROR_MSG "" | |
334 | #endif /* GIT_ERRORS */ | |
335 | ||
336 | #ifdef GIT_IS_DIST | |
337 | # define GIT_DIST_MSG "dist of " | |
338 | #else /* !GIT_IS_DIST */ | |
339 | # define GIT_DIST_MSG "" | |
340 | #endif /* GIT_IS_DIST */ | |
341 | ||
342 | #ifdef GIT_REPO | |
343 | # ifdef GIT_NOT_FOUND | |
344 | # define GIT_MESSAGE GIT_DIST_MSG "git sources without git: " GIT_NOT_FOUND | |
345 | # else /* !GIT_NOT_FOUND */ | |
346 | # define GIT_MESSAGE \\ | |
347 | GIT_DIST_MSG \\ | |
2899dcf6 FCE |
348 | "git branch " GIT_BRANCH ", " \\ |
349 | "url " GIT_REMOTE_URL ", " \\ | |
c0f9d4b0 FCE |
350 | "commit " GIT_SHAID GIT_DIRTY_MSG \\ |
351 | GIT_ERROR_MSG | |
352 | # endif /* GIT_NOT_FOUND */ | |
353 | #else /* !GIT_REPO */ | |
354 | # define GIT_MESSAGE GIT_DIST_MSG "non-git sources" GIT_ERROR_MSG | |
355 | #endif /* GIT_REPO */ | |
356 | ||
357 | #endif /* ${ifndef_symbol} */ | |
358 | EOF | |
359 | ||
360 | # Example program | |
361 | if "$print_example" | |
362 | then | |
363 | cat<<EOF | |
364 | ||
365 | /* example program demonstrating the use of git_version.sh output */ | |
366 | #include <stdio.h> | |
367 | #include <string.h> | |
368 | ||
369 | #ifdef HAVE_CONFIG_H | |
370 | # include "config.h" | |
371 | #endif | |
372 | ||
373 | int main(int argc, char *argv[]) | |
374 | { | |
375 | const char *const idx = strrchr(argv[0], '/'); | |
376 | const char *const prog = (idx)?(idx+1):(argv[0]); | |
377 | #ifdef PACKAGE_VERSION | |
378 | printf("%s: version %s, built from %s\n", prog, PACKAGE_VERSION, GIT_MESSAGE); | |
23957b6c | 379 | #elif defined(GIT_MESSAGE) |
c0f9d4b0 FCE |
380 | printf("%s: built from %s\n", prog, GIT_MESSAGE); |
381 | #endif | |
382 | return 0; | |
383 | } | |
384 | EOF | |
385 | fi | |
386 | ||
387 | # Change back to working dir for the remaining output file manipulations. | |
388 | cd "$working_dir" | |
389 | ||
390 | # If necessary, overwrite outdated output file with new one | |
391 | if [ "x$outfile" != "x-" ] | |
392 | then | |
393 | if [ -f "$outfile" ]; then | |
394 | if [ "x$keep_if_no_repo" = "xyes" ] && [ "x$git_repo" = "xno" ]; then | |
395 | "$quiet" || echo "$self: Not a git repo, keeping existing $outfile" >&2 | |
2899dcf6 FCE |
396 | rm -f "$outfile.new" |
397 | elif cmp "$outfile" "$outfile.new" > /dev/null; then | |
c0f9d4b0 | 398 | "$quiet" || echo "$self: Output is unchanged, keeping $outfile" >&2 |
2899dcf6 | 399 | rm -f "$outfile.new" |
c0f9d4b0 FCE |
400 | else |
401 | echo "$self: Output has changed, updating $outfile" >&2 | |
2899dcf6 | 402 | mv -f "$outfile.new" "$outfile" |
c0f9d4b0 FCE |
403 | fi |
404 | else | |
405 | echo "$self: Output is new file, creating $outfile" >&2 | |
2899dcf6 | 406 | mv -f "$outfile.new" "$outfile" |
c0f9d4b0 FCE |
407 | fi |
408 | fi | |
409 | ||
410 | # THE END. |