|
1 /* updaterevision.c |
|
2 * |
|
3 * Public domain. This program uses git commands command to get |
|
4 * various bits of repository status for a particular directory |
|
5 * and writes it into a header file so that it can be used for a |
|
6 * project's versioning. |
|
7 */ |
|
8 |
|
9 #define _CRT_SECURE_NO_DEPRECATE |
|
10 |
|
11 #include <stdio.h> |
|
12 #include <stdlib.h> |
|
13 #include <string.h> |
|
14 #include <ctype.h> |
|
15 #include <errno.h> |
|
16 |
|
17 #ifdef _WIN32 |
|
18 #define popen _popen |
|
19 #define pclose _pclose |
|
20 #endif |
|
21 |
|
22 // Used to strip newline characters from lines read by fgets. |
|
23 void stripnl(char *str) |
|
24 { |
|
25 if (*str != '\0') |
|
26 { |
|
27 size_t len = strlen(str); |
|
28 if (str[len - 1] == '\n') |
|
29 { |
|
30 str[len - 1] = '\0'; |
|
31 } |
|
32 } |
|
33 } |
|
34 |
|
35 int main(int argc, char **argv) |
|
36 { |
|
37 char vertag[64], lastlog[64], lasthash[64], *hash = NULL; |
|
38 FILE *stream = NULL; |
|
39 int gotrev = 0, needupdate = 1; |
|
40 |
|
41 vertag[0] = '\0'; |
|
42 lastlog[0] = '\0'; |
|
43 |
|
44 if (argc != 2) |
|
45 { |
|
46 fprintf(stderr, "Usage: %s <path to gitinfo.h>\n", argv[0]); |
|
47 return 1; |
|
48 } |
|
49 |
|
50 // Use git describe --tags to get a version string. If we are sitting directly |
|
51 // on a tag, it returns that tag. Otherwise it returns <most recent tag>-<number of |
|
52 // commits since the tag>-<short hash>. |
|
53 // Use git log to get the time of the latest commit in ISO 8601 format and its full hash. |
|
54 stream = popen("git describe --tags && git log -1 --format=%ai*%H", "r"); |
|
55 |
|
56 if (NULL != stream) |
|
57 { |
|
58 if (fgets(vertag, sizeof vertag, stream) == vertag && |
|
59 fgets(lastlog, sizeof lastlog, stream) == lastlog) |
|
60 { |
|
61 stripnl(vertag); |
|
62 stripnl(lastlog); |
|
63 gotrev = 1; |
|
64 } |
|
65 |
|
66 pclose(stream); |
|
67 } |
|
68 |
|
69 if (gotrev) |
|
70 { |
|
71 hash = strchr(lastlog, '*'); |
|
72 if (hash != NULL) |
|
73 { |
|
74 *hash = '\0'; |
|
75 hash++; |
|
76 } |
|
77 } |
|
78 if (hash == NULL) |
|
79 { |
|
80 fprintf(stderr, "Failed to get commit info: %s\n", strerror(errno)); |
|
81 strcpy(vertag, "<unknown version>"); |
|
82 lastlog[0] = '\0'; |
|
83 lastlog[1] = '0'; |
|
84 lastlog[2] = '\0'; |
|
85 hash = lastlog + 1; |
|
86 } |
|
87 |
|
88 stream = fopen (argv[1], "r"); |
|
89 if (stream != NULL) |
|
90 { |
|
91 if (!gotrev) |
|
92 { // If we didn't get a revision but the file does exist, leave it alone. |
|
93 fclose (stream); |
|
94 return 0; |
|
95 } |
|
96 // Read the revision that's in this file already. If it's the same as |
|
97 // what we've got, then we don't need to modify it and can avoid rebuilding |
|
98 // dependant files. |
|
99 if (fgets(lasthash, sizeof lasthash, stream) == lasthash) |
|
100 { |
|
101 stripnl(lasthash); |
|
102 if (strcmp(hash, lasthash + 3) == 0) |
|
103 { |
|
104 needupdate = 0; |
|
105 } |
|
106 } |
|
107 fclose (stream); |
|
108 } |
|
109 |
|
110 if (needupdate) |
|
111 { |
|
112 stream = fopen (argv[1], "w"); |
|
113 if (stream == NULL) |
|
114 { |
|
115 return 1; |
|
116 } |
|
117 fprintf(stream, |
|
118 "// %s\n" |
|
119 "//\n" |
|
120 "// This file was automatically generated by the\n" |
|
121 "// updaterevision tool. Do not edit by hand.\n" |
|
122 "\n" |
|
123 "#define GIT_DESCRIPTION \"%s\"\n" |
|
124 "#define GIT_HASH \"%s\"\n" |
|
125 "#define GIT_TIME \"%s\"\n", |
|
126 hash, vertag, hash, lastlog); |
|
127 fclose(stream); |
|
128 fprintf(stderr, "%s updated to commit %s.\n", argv[1], vertag); |
|
129 } |
|
130 else |
|
131 { |
|
132 fprintf (stderr, "%s is up to date at commit %s.\n", argv[1], vertag); |
|
133 } |
|
134 |
|
135 return 0; |
|
136 } |