Commit b05fbba394b9f2befea8b50817fd64209538e384

Nika Layzell 2018-03-17T18:14:31

mailmap: Make everything a bit more style conforming

diff --git a/include/git2/mailmap.h b/include/git2/mailmap.h
index 0f582c2..a80ecb9 100644
--- a/include/git2/mailmap.h
+++ b/include/git2/mailmap.h
@@ -8,7 +8,7 @@
 #define INCLUDE_git_mailmap_h__
 
 #include "common.h"
-#include "tree.h"
+#include "types.h"
 
 /**
  * @file git2/mailmap.h
@@ -19,24 +19,27 @@
  */
 GIT_BEGIN_DECL
 
-typedef struct git_mailmap git_mailmap;
-
 /**
  * A single entry parsed from a mailmap.
  */
-typedef struct git_mailmap_entry {
+struct git_mailmap_entry {
+	unsigned int version;
+
 	const char *real_name; /**< the real name (may be NULL) */
 	const char *real_email; /**< the real email (may be NULL) */
 	const char *replace_name; /**< the name to replace (may be NULL) */
 	const char *replace_email; /**< the email to replace */
-} git_mailmap_entry;
+};
+
+#define GIT_MAILMAP_ENTRY_VERSION 1
+#define GIT_MAILMAP_ENTRY_INIT {GIT_MAILMAP_ENTRY_VERSION}
 
 /**
  * Create a mailmap object by parsing a mailmap file.
  *
  * The mailmap must be freed with 'git_mailmap_free'.
  *
- * @param out Pointer to store the mailmap
+ * @param out pointer to store the mailmap
  * @param data raw data buffer to parse
  * @param size size of the raw data buffer
  * @return 0 on success
@@ -47,35 +50,26 @@ GIT_EXTERN(int) git_mailmap_parse(
 	size_t size);
 
 /**
- * Create a mailmap object by parsing the ".mailmap" file in the tree root.
+ * Create a mailmap object from the given repository.
  *
- * The mailmap must be freed with 'git_mailmap_free'.
+ * If the repository is not bare, the repository's working directory root will
+ * be checked for the '.mailmap' file to be parsed.
  *
- * @param out pointer to store the mailmap
- * @param treeish root object that can be peeled to a tree
- * @return 0 on success; GIT_ENOTFOUND if .mailmap does not exist.
- */
-GIT_EXTERN(int) git_mailmap_from_tree(
-	git_mailmap **out,
-	const git_object *treeish);
-
-/**
- * Create a mailmap object by parsing the ".mailmap" file in the repository's
- * HEAD's tree root.
+ * If the repository is bare, the repository's HEAD commit's tree root will be
+ * searched for the '.mailmap' file to be parsed.
  *
  * The mailmap must be freed with 'git_mailmap_free'.
  *
  * @param out pointer to store the mailmap
  * @param repo repository to find the .mailmap in
- * @return 0 on success; GIT_ENOTFOUND if .mailmap does not exist.
+ * @return 0 on success; GIT_ENOTFOUND if .mailmap could not be found.
  */
 GIT_EXTERN(int) git_mailmap_from_repo(
 	git_mailmap **out,
 	git_repository *repo);
 
 /**
- * Free a mailmap created by 'git_mailmap_parse', 'git_mailmap_from_tree' or
- * 'git_mailmap_from_repo'.
+ * Free a mailmap created by 'git_mailmap_parse' or 'git_mailmap_from_repo'.
  */
 GIT_EXTERN(void) git_mailmap_free(git_mailmap *mailmap);
 
@@ -86,38 +80,45 @@ GIT_EXTERN(void) git_mailmap_free(git_mailmap *mailmap);
  *             You should NOT free this value.
  * @param email_out either 'email' or the real email to use,
  *             You should NOT free this value.
- * @param mailmap the mailmap to perform the lookup in.
+ * @param mailmap the mailmap to perform the lookup in. (may be NULL)
  * @param name the name to resolve.
  * @param email the email to resolve.
  */
 GIT_EXTERN(void) git_mailmap_resolve(
 	const char **name_out,
 	const char **email_out,
-	git_mailmap *mailmap,
+	const git_mailmap *mailmap,
 	const char *name,
 	const char *email);
 
 /**
- * Get the number of mailmap entries.
+ * Get the number of mailmap entries in this mailmap.
  */
-GIT_EXTERN(size_t) git_mailmap_entry_count(git_mailmap *mailmap);
+GIT_EXTERN(size_t) git_mailmap_entry_count(const git_mailmap *mailmap);
 
 /**
  * Lookup a mailmap entry by index.
  *
  * Do not free the mailmap entry, it is owned by the mailmap.
+ *
+ * @return the mailmap entry at index, or NULL if it cannot be found.
  */
-GIT_EXTERN(git_mailmap_entry *) git_mailmap_entry_byindex(
-	git_mailmap *mailmap,
+GIT_EXTERN(const git_mailmap_entry *) git_mailmap_entry_byindex(
+	const git_mailmap *mailmap,
 	size_t idx);
 
 /**
  * Lookup a mailmap entry by name/email pair.
  *
  * Do not free the mailmap entry, it is owned by the mailmap.
+ *
+ * @param mailmap the mailmap to perform the lookup in. (may be NULL)
+ * @param name the name to perform the lookup with.
+ * @param email the email to perform the lookup with.
+ * @return the corresponding mailmap entry, or NULL if it cannot be found.
  */
-GIT_EXTERN(git_mailmap_entry *) git_mailmap_entry_lookup(
-	git_mailmap *mailmap,
+GIT_EXTERN(const git_mailmap_entry *) git_mailmap_entry_lookup(
+	const git_mailmap *mailmap,
 	const char *name,
 	const char *email);
 
diff --git a/src/mailmap.c b/src/mailmap.c
index dfff47d..aaf5446 100644
--- a/src/mailmap.c
+++ b/src/mailmap.c
@@ -135,7 +135,8 @@ static int git_mailmap_parse_single(
 			*real_name = name_a;
 
 		if (two_emails) {
-			*real_email = email_a;
+			if (email_a.len > 0)
+				*real_email = email_a;
 			*replace_email = email_b;
 
 			if (name_b.len > 0)
@@ -158,6 +159,9 @@ int git_mailmap_parse(
 	git_mailmap_entry* entry = NULL;
 	int error = 0;
 
+	if (memchr(data, '\0', size) != NULL)
+		return -1; /* data may not contain '\0's */
+
 	*mailmap = git__calloc(1, sizeof(git_mailmap));
 	if (!*mailmap)
 		return -1;
@@ -194,6 +198,7 @@ int git_mailmap_parse(
 			error = -1;
 			goto cleanup;
 		}
+		entry->version = GIT_MAILMAP_ENTRY_VERSION;
 
 		buf = (char*)(entry + 1);
 		entry->real_name = range_copyz(&buf, NULL, real_name);
@@ -209,9 +214,8 @@ int git_mailmap_parse(
 	}
 
 cleanup:
-	if (entry)
-		git__free(entry);
-	if (error < 0 && *mailmap) {
+	git__free(entry);
+	if (error < 0)
 		git_mailmap_free(*mailmap);
 		*mailmap = NULL;
 	}
@@ -220,6 +224,9 @@ cleanup:
 
 void git_mailmap_free(git_mailmap *mailmap)
 {
+	if (!mailmap)
+		return;
+
 	git_vector_free_deep(&mailmap->entries);
 	git__free(mailmap);
 }
@@ -227,15 +234,19 @@ void git_mailmap_free(git_mailmap *mailmap)
 void git_mailmap_resolve(
 	const char **name_out,
 	const char **email_out,
-	git_mailmap *mailmap,
+	const git_mailmap *mailmap,
 	const char *name,
 	const char *email)
 {
-	git_mailmap_entry *entry = NULL;
+	const git_mailmap_entry *entry = NULL;
+	assert(name && email);
 
 	*name_out = name;
 	*email_out = email;
 
+	if (!mailmap)
+		return;
+
 	entry = git_mailmap_entry_lookup(mailmap, name, email);
 	if (entry) {
 		if (entry->real_name)
@@ -245,14 +256,17 @@ void git_mailmap_resolve(
 	}
 }
 
-git_mailmap_entry *git_mailmap_entry_lookup(
-	git_mailmap *mailmap,
+const git_mailmap_entry *git_mailmap_entry_lookup(
+	const git_mailmap *mailmap,
 	const char *name,
 	const char *email)
 {
 	size_t i;
 	git_mailmap_entry *entry;
-	assert(mailmap && name && email);
+	assert(name && email);
+
+	if (!mailmap)
+		return NULL;
 
 	git_vector_foreach(&mailmap->entries, i, entry) {
 		if (!git__strcmp(email, entry->replace_email) &&
@@ -264,26 +278,42 @@ git_mailmap_entry *git_mailmap_entry_lookup(
 	return NULL;
 }
 
-git_mailmap_entry *git_mailmap_entry_byindex(git_mailmap *mailmap, size_t idx)
+const git_mailmap_entry *git_mailmap_entry_byindex(
+	const git_mailmap *mailmap, size_t idx)
 {
-	return git_vector_get(&mailmap->entries, idx);
+	if (mailmap)
+		return git_vector_get(&mailmap->entries, idx);
+	return NULL;
 }
 
-size_t git_mailmap_entry_count(git_mailmap *mailmap)
+size_t git_mailmap_entry_count(const git_mailmap *mailmap)
 {
-	return git_vector_length(&mailmap->entries);
+	if (mailmap)
+		return git_vector_length(&mailmap->entries);
+	return 0;
 }
 
-int git_mailmap_from_tree(
+static int git_mailmap_from_bare_repo(
 	git_mailmap **mailmap,
-	const git_object *treeish)
+	git_repository *repo)
 {
+	git_reference *head = NULL;
+	git_object *tree = NULL;
 	git_blob *blob = NULL;
 	const char *content = NULL;
 	git_off_t size = 0;
 	int error;
 
-	*mailmap = NULL;
+	assert(git_repository_is_bare(repo));
+
+	/* In bare repositories, fall back to reading from HEAD's tree */
+	error = git_repository_head(&head, repo);
+	if (error < 0)
+		goto cleanup;
+
+	error = git_reference_peel(&tree, head, GIT_OBJ_TREE);
+	if (error < 0)
+		goto cleanup;
 
 	error = git_object_lookup_bypath(
 		(git_object **) &blob,
@@ -297,28 +327,55 @@ int git_mailmap_from_tree(
 	size = git_blob_rawsize(blob);
 
 	error = git_mailmap_parse(mailmap, content, size);
+	if (error < 0)
+		goto cleanup;
 
 cleanup:
-	if (blob != NULL)
-		git_blob_free(blob);
+	git_reference_free(head);
+	git_object_free(tree);
+	git_blob_free(blob);
+
 	return error;
 }
 
-int git_mailmap_from_repo(git_mailmap **mailmap, git_repository *repo)
+static int git_mailmap_from_workdir_repo(
+	git_mailmap **mailmap,
+	git_repository *repo)
 {
-	git_object *head = NULL;
+	git_buf path = GIT_BUF_INIT;
+	git_buf data = GIT_BUF_INIT;
 	int error;
 
-	*mailmap = NULL;
+	assert(!git_repository_is_bare(repo));
 
-	error = git_revparse_single(&head, repo, "HEAD");
+	/* In non-bare repositories, .mailmap should be read from the workdir */
+	error = git_buf_joinpath(&path, git_repository_workdir(repo), ".mailmap");
 	if (error < 0)
 		goto cleanup;
 
-	error = git_mailmap_from_tree(mailmap, head);
+	error = git_futils_readbuffer(&data, git_buf_cstr(&path));
+	if (error < 0)
+		goto cleanup;
+
+	error = git_mailmap_parse(mailmap, data.ptr, data.size);
+	if (error < 0)
+		goto cleanup;
 
 cleanup:
-	if (head)
-		git_object_free(head);
+	git_buf_free(&path);
+	git_buf_free(&data);
+
 	return error;
 }
+
+int git_mailmap_from_repo(git_mailmap **mailmap, git_repository *repo)
+{
+	assert(mailmap && repo);
+
+	*mailmap = NULL;
+
+	if (git_repository_is_bare(repo))
+		return git_mailmap_from_bare_repo(mailmap, repo);
+	else
+		return git_mailmap_from_workdir_repo(mailmap, repo);
+}