summaryrefslogtreecommitdiff
path: root/notes.c
diff options
context:
space:
mode:
authorThomas Rast <trast@student.ethz.ch>2010-03-12 17:04:26 (GMT)
committerJunio C Hamano <gitster@pobox.com>2010-03-13 05:55:39 (GMT)
commit894a9d333e9e2015cad00d95250b7c5d3acea8b6 (patch)
tree2bab79483f959c7661e87ef70b1976ab9aa65bdb /notes.c
parent6ceeaee7ea5bb754c76ce93c5b289f72d69fdb92 (diff)
downloadgit-894a9d333e9e2015cad00d95250b7c5d3acea8b6.zip
git-894a9d333e9e2015cad00d95250b7c5d3acea8b6.tar.gz
git-894a9d333e9e2015cad00d95250b7c5d3acea8b6.tar.bz2
Support showing notes from more than one notes tree
With this patch, you can set notes.displayRef to a glob that points at your favourite notes refs, e.g., [notes] displayRef = refs/notes/* Then git-log and friends will show notes from all trees. Thanks to Junio C Hamano for lots of feedback, which greatly influenced the design of the entire series and this commit in particular. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Acked-by: Johan Herland <johan@herland.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'notes.c')
-rw-r--r--notes.c169
1 files changed, 162 insertions, 7 deletions
diff --git a/notes.c b/notes.c
index 3ba3e6d..225a166 100644
--- a/notes.c
+++ b/notes.c
@@ -5,6 +5,8 @@
#include "utf8.h"
#include "strbuf.h"
#include "tree-walk.h"
+#include "string-list.h"
+#include "refs.h"
/*
* Use a non-balancing simple 16-tree structure with struct int_node as
@@ -68,6 +70,9 @@ struct non_note {
struct notes_tree default_notes_tree;
+static struct string_list display_notes_refs;
+static struct notes_tree **display_notes_trees;
+
static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
struct int_node *node, unsigned int n);
@@ -828,6 +833,83 @@ int combine_notes_ignore(unsigned char *cur_sha1,
return 0;
}
+static int string_list_add_one_ref(const char *path, const unsigned char *sha1,
+ int flag, void *cb)
+{
+ struct string_list *refs = cb;
+ if (!unsorted_string_list_has_string(refs, path))
+ string_list_append(path, refs);
+ return 0;
+}
+
+void string_list_add_refs_by_glob(struct string_list *list, const char *glob)
+{
+ if (has_glob_specials(glob)) {
+ for_each_glob_ref(string_list_add_one_ref, glob, list);
+ } else {
+ unsigned char sha1[20];
+ if (get_sha1(glob, sha1))
+ warning("notes ref %s is invalid", glob);
+ if (!unsorted_string_list_has_string(list, glob))
+ string_list_append(glob, list);
+ }
+}
+
+void string_list_add_refs_from_colon_sep(struct string_list *list,
+ const char *globs)
+{
+ struct strbuf globbuf = STRBUF_INIT;
+ struct strbuf **split;
+ int i;
+
+ strbuf_addstr(&globbuf, globs);
+ split = strbuf_split(&globbuf, ':');
+
+ for (i = 0; split[i]; i++) {
+ if (!split[i]->len)
+ continue;
+ if (split[i]->buf[split[i]->len-1] == ':')
+ strbuf_setlen(split[i], split[i]->len-1);
+ string_list_add_refs_by_glob(list, split[i]->buf);
+ }
+
+ strbuf_list_free(split);
+ strbuf_release(&globbuf);
+}
+
+static int string_list_add_refs_from_list(struct string_list_item *item,
+ void *cb)
+{
+ struct string_list *list = cb;
+ string_list_add_refs_by_glob(list, item->string);
+ return 0;
+}
+
+static int notes_display_config(const char *k, const char *v, void *cb)
+{
+ int *load_refs = cb;
+
+ if (*load_refs && !strcmp(k, "notes.displayref")) {
+ if (!v)
+ config_error_nonbool(k);
+ string_list_add_refs_by_glob(&display_notes_refs, v);
+ }
+
+ return 0;
+}
+
+static const char *default_notes_ref(void)
+{
+ const char *notes_ref = NULL;
+ if (!notes_ref)
+ notes_ref = getenv(GIT_NOTES_REF_ENVIRONMENT);
+ if (!notes_ref)
+ notes_ref = notes_ref_name; /* value of core.notesRef config */
+ if (!notes_ref)
+ notes_ref = GIT_NOTES_DEFAULT_REF;
+ return notes_ref;
+}
+
void init_notes(struct notes_tree *t, const char *notes_ref,
combine_notes_fn combine_notes, int flags)
{
@@ -840,11 +922,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
assert(!t->initialized);
if (!notes_ref)
- notes_ref = getenv(GIT_NOTES_REF_ENVIRONMENT);
- if (!notes_ref)
- notes_ref = notes_ref_name; /* value of core.notesRef config */
- if (!notes_ref)
- notes_ref = GIT_NOTES_DEFAULT_REF;
+ notes_ref = default_notes_ref();
if (!combine_notes)
combine_notes = combine_notes_concatenate;
@@ -868,6 +946,63 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
load_subtree(t, &root_tree, t->root, 0);
}
+struct load_notes_cb_data {
+ int counter;
+ struct notes_tree **trees;
+};
+
+static int load_one_display_note_ref(struct string_list_item *item,
+ void *cb_data)
+{
+ struct load_notes_cb_data *c = cb_data;
+ struct notes_tree *t = xcalloc(1, sizeof(struct notes_tree));
+ init_notes(t, item->string, combine_notes_ignore, 0);
+ c->trees[c->counter++] = t;
+ return 0;
+}
+
+struct notes_tree **load_notes_trees(struct string_list *refs)
+{
+ struct notes_tree **trees;
+ struct load_notes_cb_data cb_data;
+ trees = xmalloc((refs->nr+1) * sizeof(struct notes_tree *));
+ cb_data.counter = 0;
+ cb_data.trees = trees;
+ for_each_string_list(load_one_display_note_ref, refs, &cb_data);
+ trees[cb_data.counter] = NULL;
+ return trees;
+}
+
+void init_display_notes(struct display_notes_opt *opt)
+{
+ char *display_ref_env;
+ int load_config_refs = 0;
+ display_notes_refs.strdup_strings = 1;
+
+ assert(!display_notes_trees);
+
+ if (!opt || !opt->suppress_default_notes) {
+ string_list_append(default_notes_ref(), &display_notes_refs);
+ display_ref_env = getenv(GIT_NOTES_DISPLAY_REF_ENVIRONMENT);
+ if (display_ref_env) {
+ string_list_add_refs_from_colon_sep(&display_notes_refs,
+ display_ref_env);
+ load_config_refs = 0;
+ } else
+ load_config_refs = 1;
+ }
+
+ git_config(notes_display_config, &load_config_refs);
+
+ if (opt && opt->extra_notes_refs)
+ for_each_string_list(string_list_add_refs_from_list,
+ opt->extra_notes_refs,
+ &display_notes_refs);
+
+ display_notes_trees = load_notes_trees(&display_notes_refs);
+ string_list_clear(&display_notes_refs, 0);
+}
+
void add_note(struct notes_tree *t, const unsigned char *object_sha1,
const unsigned char *note_sha1, combine_notes_fn combine_notes)
{
@@ -1016,8 +1151,18 @@ void format_note(struct notes_tree *t, const unsigned char *object_sha1,
if (msglen && msg[msglen - 1] == '\n')
msglen--;
- if (flags & NOTES_SHOW_HEADER)
- strbuf_addstr(sb, "\nNotes:\n");
+ if (flags & NOTES_SHOW_HEADER) {
+ const char *ref = t->ref;
+ if (!ref || !strcmp(ref, GIT_NOTES_DEFAULT_REF)) {
+ strbuf_addstr(sb, "\nNotes:\n");
+ } else {
+ if (!prefixcmp(ref, "refs/"))
+ ref += 5;
+ if (!prefixcmp(ref, "notes/"))
+ ref += 6;
+ strbuf_addf(sb, "\nNotes (%s):\n", ref);
+ }
+ }
for (msg_p = msg; msg_p < msg + msglen; msg_p += linelen + 1) {
linelen = strchrnul(msg_p, '\n') - msg_p;
@@ -1030,3 +1175,13 @@ void format_note(struct notes_tree *t, const unsigned char *object_sha1,
free(msg);
}
+
+void format_display_notes(const unsigned char *object_sha1,
+ struct strbuf *sb, const char *output_encoding, int flags)
+{
+ int i;
+ assert(display_notes_trees);
+ for (i = 0; display_notes_trees[i]; i++)
+ format_note(display_notes_trees[i], object_sha1, sb,
+ output_encoding, flags);
+}