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
|
#include <stdio.h>
#include <time.h>
#include <git2.h>
struct datever
{
int year;
int month;
int day;
int revision;
};
static int must(const char* msg, int err);
static struct datever find_latest(git_repository* repo);
static struct datever datever_init();
static struct datever datever_from_time(time_t time);
static int datever_is_valid(const struct datever* ver);
static int datever_compare(const struct datever* lhs, const struct datever* rhs);
int
main()
{
git_libgit2_init();
git_repository* repo = NULL;
must("open repository", git_repository_open_ext(&repo, NULL, GIT_REPOSITORY_OPEN_FROM_ENV, NULL));
const struct datever ver = find_latest(repo);
printf("%d%02d%02d.%d\n", ver.year, ver.month, ver.day, ver.revision);
}
/// If [[err]] is considered erroneous, print [[msg]] and the last libgit2 error to standard error and then terminate
/// current process.
int
must(const char* const msg, const int err)
{
if (0 > err) {
const git_error* const e = git_error_last();
if (NULL != msg)
dprintf(2, "%s: ", msg);
dprintf(2, "%s\n", e->message);
exit(1);
}
return err;
}
struct datever
find_latest(git_repository* const repo)
{
git_revwalk* walker = NULL;
must("walk revisions", git_revwalk_new(&walker, repo));
must("find HEAD", git_revwalk_push_head(walker));
git_oid oid;
git_commit* commit;
struct datever prev = datever_init();
struct datever ver = datever_init();
while (0 == git_revwalk_next(&oid, walker)) {
must("find commit", git_commit_lookup(&commit, repo, &oid));
ver = datever_from_time(git_commit_time(commit));
if (datever_is_valid(&prev)) {
if (0 == datever_compare(&prev, &ver))
ver.revision++;
else break;
}
prev = ver;
git_commit_free(commit);
}
git_commit_free(commit);
return prev;
}
/// Initialize empty, and thus invalid, version.
struct datever
datever_init()
{
return (struct datever){
.year = -1,
.month = -1,
.day = -1,
.revision = -1,
};
}
struct datever
datever_from_time(const time_t time)
{
const struct tm* tm = gmtime(&time);
return (struct datever){
.year = tm->tm_year + 1900,
.month = tm->tm_mon + 1,
.day = tm->tm_mday,
.revision = 1,
};
}
int
datever_is_valid(const struct datever* const ver)
{
return 0 <= ver->year && 0 <= ver->month && 0 <= ver->day && 0 <= ver->revision;
}
/// Compares two versions date-wise ignoring revision count. Returns similarly to strcmp(3).
int
datever_compare(const struct datever* const lhs, const struct datever* const rhs)
{
if (lhs->year > rhs->year) return -1;
if (lhs->year < rhs->year) return 1;
if (lhs->month > rhs->month) return -1;
if (lhs->month < rhs->month) return 1;
if (lhs->day > rhs->day) return -1;
if (lhs->day < rhs->day) return 1;
return 0;
}
|