Skip to content

Commit 7a16939

Browse files
emiliomystor
authored andcommitted
mailmap: WIP mailmap support
1 parent 23c6e89 commit 7a16939

File tree

3 files changed

+248
-0
lines changed

3 files changed

+248
-0
lines changed

include/git2.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "git2/ignore.h"
3030
#include "git2/index.h"
3131
#include "git2/indexer.h"
32+
#include "git2/mailmap.h"
3233
#include "git2/merge.h"
3334
#include "git2/message.h"
3435
#include "git2/net.h"

include/git2/mailmap.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
#ifndef INCLUDE_mailmap_h__
8+
#define INCLUDE_mailmap_h__
9+
10+
#include "common.h"
11+
#include "repository.h"
12+
13+
/**
14+
* @file git2/mailmap.h
15+
* @brief Mailmap access subroutines.
16+
* @defgroup git_rebase Git merge routines
17+
* @ingroup Git
18+
* @{
19+
*/
20+
GIT_BEGIN_DECL
21+
22+
typedef struct git_mailmap git_mailmap;
23+
24+
struct git_mailmap_entry {
25+
const char* name;
26+
const char* email;
27+
};
28+
29+
GIT_EXTERN(int) git_mailmap_create(git_mailmap**, git_repository*);
30+
GIT_EXTERN(void) git_mailmap_free(git_mailmap*);
31+
GIT_EXTERN(struct git_mailmap_entry) git_mailmap_lookup(
32+
git_mailmap* map,
33+
const char* name,
34+
const char* email);
35+
36+
/** @} */
37+
GIT_END_DECL
38+
39+
#endif

src/mailmap.c

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#include "git2/mailmap.h"
9+
10+
#include "blob.h"
11+
#include "commit.h"
12+
#include "git2/common.h"
13+
#include "git2/repository.h"
14+
#include "git2/revparse.h"
15+
#include "git2/sys/commit.h"
16+
17+
struct mailmap_entry {
18+
char* to_name;
19+
char* to_email;
20+
char* from_name;
21+
char* from_email;
22+
};
23+
24+
struct git_mailmap {
25+
git_vector lines;
26+
};
27+
28+
// Returns -1 on failure, length of the string scanned successfully on success,
29+
// guaranteed to be less that `length`.
30+
ssize_t parse_name_and_email(
31+
const char *line,
32+
size_t length,
33+
const char** name,
34+
size_t* name_len,
35+
const char** email,
36+
size_t* email_len,
37+
bool allow_empty_email)
38+
{
39+
const char* email_start;
40+
const char* email_end;
41+
const char* name_start;
42+
const char* name_end;
43+
44+
email_start = memchr(line, '<', length);
45+
if (!email_start)
46+
return -1;
47+
email_end = memchr(email_start, '>', length - (email_start - line));
48+
if (!email_end)
49+
return -1;
50+
assert(email_end > email_start);
51+
52+
*email_len = email_end - email_start - 1;
53+
*email = email_start + 1;
54+
if (*email == email_end && !allow_empty_email)
55+
return -1;
56+
57+
// Now look for the name.
58+
name_start = line;
59+
while (name_start < email_start && isspace(*name_start))
60+
++name_start;
61+
62+
*name = name_start;
63+
64+
name_end = email_start;
65+
while (name_end > name_start && isspace(*(name_end - 1)))
66+
name_end--;
67+
68+
assert(name_end >= name_start);
69+
*name_len = name_end - name_start;
70+
71+
return email_end - line;
72+
}
73+
74+
static void git_mailmap_parse_line(
75+
git_mailmap* mailmap,
76+
const char* contents,
77+
size_t size)
78+
{
79+
struct mailmap_entry* entry;
80+
81+
const char* to_name;
82+
size_t to_name_length;
83+
84+
const char* to_email;
85+
size_t to_email_length;
86+
87+
const char* from_name;
88+
size_t from_name_length;
89+
90+
const char* from_email;
91+
size_t from_email_length;
92+
93+
ssize_t ret;
94+
95+
if (!size)
96+
return;
97+
if (contents[0] == '#')
98+
return;
99+
100+
ret = parse_name_and_email(
101+
contents,
102+
size,
103+
&to_name,
104+
&to_name_length,
105+
&to_email,
106+
&to_email_length,
107+
false);
108+
if (ret < 0)
109+
return;
110+
111+
ret = parse_name_and_email(
112+
contents + ret + 1,
113+
size - ret - 1,
114+
&from_name,
115+
&from_name_length,
116+
&from_email,
117+
&from_email_length,
118+
true);
119+
if (ret < 0)
120+
return;
121+
122+
entry = git__malloc(sizeof(struct mailmap_entry));
123+
124+
entry->to_name = git__strndup(to_name, to_name_length);
125+
entry->to_email = git__strndup(to_email, to_email_length);
126+
entry->from_name = git__strndup(from_name, from_name_length);
127+
entry->from_email = git__strndup(from_email, from_email_length);
128+
129+
printf("%s <%s> \"%s\" <%s>\n",
130+
entry->to_name,
131+
entry->to_email,
132+
entry->from_name,
133+
entry->from_email);
134+
135+
git_vector_insert(&mailmap->lines, entry);
136+
}
137+
138+
static void git_mailmap_parse(
139+
git_mailmap* mailmap,
140+
const char* contents,
141+
size_t size)
142+
{
143+
size_t start = 0;
144+
size_t i;
145+
for (i = 0; i < size; ++i) {
146+
if (contents[i] != '\n')
147+
continue;
148+
git_mailmap_parse_line(mailmap, contents + start, i - start);
149+
start = i + 1;
150+
}
151+
}
152+
153+
int git_mailmap_create(git_mailmap** mailmap, git_repository* repo)
154+
{
155+
git_commit* head = NULL;
156+
git_blob* mailmap_blob = NULL;
157+
git_off_t size = 0;
158+
const char* contents = NULL;
159+
int ret;
160+
161+
*mailmap = git__malloc(sizeof(struct git_mailmap));
162+
git_vector_init(&(*mailmap)->lines, 0, NULL);
163+
164+
ret = git_revparse_single((git_object **)&head, repo, "HEAD");
165+
if (ret)
166+
goto error;
167+
168+
ret = git_object_lookup_bypath(
169+
(git_object**) &mailmap_blob,
170+
(const git_object*) head,
171+
".mailmap",
172+
GIT_OBJ_BLOB);
173+
if (ret)
174+
goto error;
175+
176+
contents = git_blob_rawcontent(mailmap_blob);
177+
size = git_blob_rawsize(mailmap_blob);
178+
179+
git_mailmap_parse(*mailmap, contents, size);
180+
181+
return 0;
182+
183+
error:
184+
assert(ret);
185+
186+
if (mailmap_blob)
187+
git_blob_free(mailmap_blob);
188+
if (head)
189+
git_commit_free(head);
190+
git_mailmap_free(*mailmap);
191+
return ret;
192+
}
193+
194+
void git_mailmap_free(struct git_mailmap* mailmap)
195+
{
196+
size_t i;
197+
struct mailmap_entry* line;
198+
git_vector_foreach(&mailmap->lines, i, line) {
199+
git__free((char*)line->to_name);
200+
git__free((char*)line->to_email);
201+
git__free((char*)line->from_name);
202+
git__free((char*)line->from_email);
203+
git__free(line);
204+
}
205+
206+
git_vector_clear(&mailmap->lines);
207+
git__free(mailmap);
208+
}

0 commit comments

Comments
 (0)