| |
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 } |