summaryrefslogtreecommitdiff
path: root/notes.c
diff options
context:
space:
mode:
authorJohan Herland <johan@herland.net>2010-02-13 21:28:19 (GMT)
committerJunio C Hamano <gitster@pobox.com>2010-02-14 03:36:13 (GMT)
commit73f464b5f3fe4dd5109b9fb9e58c1fe55393902d (patch)
tree02d1d26e0057bae465de2167ef76e6dfcff3eecc /notes.c
parentcd30539214bb09881b84c796a50d30e409dee3fa (diff)
downloadgit-73f464b5f3fe4dd5109b9fb9e58c1fe55393902d.zip
git-73f464b5f3fe4dd5109b9fb9e58c1fe55393902d.tar.gz
git-73f464b5f3fe4dd5109b9fb9e58c1fe55393902d.tar.bz2
Refactor notes concatenation into a flexible interface for combining notes
When adding a note to an object that already has an existing note, the current solution is to concatenate the contents of the two notes. However, the caller may instead wish to _overwrite_ the existing note with the new note, or maybe even _ignore_ the new note, and keep the existing one. There might also be other ways of combining notes that are only known to the caller. Therefore, instead of unconditionally concatenating notes, we let the caller specify how to combine notes, by passing in a pointer to a function for combining notes. The caller may choose to implement its own function for notes combining, but normally one of the following three conveniently supplied notes combination functions will be sufficient: - combine_notes_concatenate() combines the two notes by appending the contents of the new note to the contents of the existing note. - combine_notes_overwrite() replaces the existing note with the new note. - combine_notes_ignore() keeps the existing note, and ignores the new note. A combine_notes function can be passed to init_notes() to choose a default combine_notes function for that notes tree. If NULL is given, the notes tree falls back to combine_notes_concatenate() as the ultimate default. A combine_notes function can also be passed directly to add_note(), to control the notes combining behaviour for a note addition in particular. If NULL is passed, the combine_notes function registered for the given notes tree is used. Signed-off-by: Johan Herland <johan@herland.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'notes.c')
-rw-r--r--notes.c138
1 files changed, 80 insertions, 58 deletions
diff --git a/notes.c b/notes.c
index 08a369a..dc4e4f6 100644
--- a/notes.c
+++ b/notes.c
@@ -1,5 +1,6 @@
#include "cache.h"
#include "notes.h"
+#include "blob.h"
#include "tree.h"
#include "utf8.h"
#include "strbuf.h"
@@ -127,55 +128,12 @@ static struct leaf_node *note_tree_find(struct int_node *tree, unsigned char n,
return NULL;
}
-/* Create a new blob object by concatenating the two given blob objects */
-static int concatenate_notes(unsigned char *cur_sha1,
- const unsigned char *new_sha1)
-{
- char *cur_msg, *new_msg, *buf;
- unsigned long cur_len, new_len, buf_len;
- enum object_type cur_type, new_type;
- int ret;
-
- /* read in both note blob objects */
- new_msg = read_sha1_file(new_sha1, &new_type, &new_len);
- if (!new_msg || !new_len || new_type != OBJ_BLOB) {
- free(new_msg);
- return 0;
- }
- cur_msg = read_sha1_file(cur_sha1, &cur_type, &cur_len);
- if (!cur_msg || !cur_len || cur_type != OBJ_BLOB) {
- free(cur_msg);
- free(new_msg);
- hashcpy(cur_sha1, new_sha1);
- return 0;
- }
-
- /* we will separate the notes by a newline anyway */
- if (cur_msg[cur_len - 1] == '\n')
- cur_len--;
-
- /* concatenate cur_msg and new_msg into buf */
- buf_len = cur_len + 1 + new_len;
- buf = (char *) xmalloc(buf_len);
- memcpy(buf, cur_msg, cur_len);
- buf[cur_len] = '\n';
- memcpy(buf + cur_len + 1, new_msg, new_len);
-
- free(cur_msg);
- free(new_msg);
-
- /* create a new blob object from buf */
- ret = write_sha1_file(buf, buf_len, "blob", cur_sha1);
- free(buf);
- return ret;
-}
-
/*
* To insert a leaf_node:
* Search to the tree location appropriate for the given leaf_node's key:
* - If location is unused (NULL), store the tweaked pointer directly there
* - If location holds a note entry that matches the note-to-be-inserted, then
- * concatenate the two notes.
+ * combine the two notes (by calling the given combine_notes function).
* - If location holds a note entry that matches the subtree-to-be-inserted,
* then unpack the subtree-to-be-inserted into the location.
* - If location holds a matching subtree entry, unpack the subtree at that
@@ -184,7 +142,8 @@ static int concatenate_notes(unsigned char *cur_sha1,
* node-to-be-inserted, and store the new int_node into the location.
*/
static void note_tree_insert(struct int_node *tree, unsigned char n,
- struct leaf_node *entry, unsigned char type)
+ struct leaf_node *entry, unsigned char type,
+ combine_notes_fn combine_notes)
{
struct int_node *new_node;
struct leaf_node *l;
@@ -205,12 +164,11 @@ static void note_tree_insert(struct int_node *tree, unsigned char n,
if (!hashcmp(l->val_sha1, entry->val_sha1))
return;
- if (concatenate_notes(l->val_sha1,
- entry->val_sha1))
- die("failed to concatenate note %s "
- "into note %s for object %s",
- sha1_to_hex(entry->val_sha1),
+ if (combine_notes(l->val_sha1, entry->val_sha1))
+ die("failed to combine notes %s and %s"
+ " for object %s",
sha1_to_hex(l->val_sha1),
+ sha1_to_hex(entry->val_sha1),
sha1_to_hex(l->key_sha1));
free(entry);
return;
@@ -233,7 +191,7 @@ static void note_tree_insert(struct int_node *tree, unsigned char n,
*p = NULL;
load_subtree(l, tree, n);
free(l);
- note_tree_insert(tree, n, entry, type);
+ note_tree_insert(tree, n, entry, type, combine_notes);
return;
}
break;
@@ -243,9 +201,9 @@ static void note_tree_insert(struct int_node *tree, unsigned char n,
assert(GET_PTR_TYPE(*p) == PTR_TYPE_NOTE ||
GET_PTR_TYPE(*p) == PTR_TYPE_SUBTREE);
new_node = (struct int_node *) xcalloc(sizeof(struct int_node), 1);
- note_tree_insert(new_node, n + 1, l, GET_PTR_TYPE(*p));
+ note_tree_insert(new_node, n + 1, l, GET_PTR_TYPE(*p), combine_notes);
*p = SET_PTR_TYPE(new_node, PTR_TYPE_INTERNAL);
- note_tree_insert(new_node, n + 1, entry, type);
+ note_tree_insert(new_node, n + 1, entry, type, combine_notes);
}
/*
@@ -406,7 +364,8 @@ static void load_subtree(struct leaf_node *subtree, struct int_node *node,
l->key_sha1[19] = (unsigned char) len;
type = PTR_TYPE_SUBTREE;
}
- note_tree_insert(node, n, l, type);
+ note_tree_insert(node, n, l, type,
+ combine_notes_concatenate);
}
}
free(buf);
@@ -659,7 +618,64 @@ static int write_each_note(const unsigned char *object_sha1,
return write_each_note_helper(d->root, note_path, mode, note_sha1);
}
-void init_notes(struct notes_tree *t, const char *notes_ref, int flags)
+int combine_notes_concatenate(unsigned char *cur_sha1,
+ const unsigned char *new_sha1)
+{
+ char *cur_msg = NULL, *new_msg = NULL, *buf;
+ unsigned long cur_len, new_len, buf_len;
+ enum object_type cur_type, new_type;
+ int ret;
+
+ /* read in both note blob objects */
+ if (!is_null_sha1(new_sha1))
+ new_msg = read_sha1_file(new_sha1, &new_type, &new_len);
+ if (!new_msg || !new_len || new_type != OBJ_BLOB) {
+ free(new_msg);
+ return 0;
+ }
+ if (!is_null_sha1(cur_sha1))
+ cur_msg = read_sha1_file(cur_sha1, &cur_type, &cur_len);
+ if (!cur_msg || !cur_len || cur_type != OBJ_BLOB) {
+ free(cur_msg);
+ free(new_msg);
+ hashcpy(cur_sha1, new_sha1);
+ return 0;
+ }
+
+ /* we will separate the notes by a newline anyway */
+ if (cur_msg[cur_len - 1] == '\n')
+ cur_len--;
+
+ /* concatenate cur_msg and new_msg into buf */
+ buf_len = cur_len + 1 + new_len;
+ buf = (char *) xmalloc(buf_len);
+ memcpy(buf, cur_msg, cur_len);
+ buf[cur_len] = '\n';
+ memcpy(buf + cur_len + 1, new_msg, new_len);
+ free(cur_msg);
+ free(new_msg);
+
+ /* create a new blob object from buf */
+ ret = write_sha1_file(buf, buf_len, blob_type, cur_sha1);
+ free(buf);
+ return ret;
+}
+
+int combine_notes_overwrite(unsigned char *cur_sha1,
+ const unsigned char *new_sha1)
+{
+ hashcpy(cur_sha1, new_sha1);
+ return 0;
+}
+
+int combine_notes_ignore(unsigned char *cur_sha1,
+ const unsigned char *new_sha1)
+{
+ return 0;
+}
+
+void init_notes(struct notes_tree *t, const char *notes_ref,
+ combine_notes_fn combine_notes, int flags)
{
unsigned char sha1[20], object_sha1[20];
unsigned mode;
@@ -676,8 +692,12 @@ void init_notes(struct notes_tree *t, const char *notes_ref, int flags)
if (!notes_ref)
notes_ref = GIT_NOTES_DEFAULT_REF;
+ if (!combine_notes)
+ combine_notes = combine_notes_concatenate;
+
t->root = (struct int_node *) xcalloc(sizeof(struct int_node), 1);
t->ref = notes_ref ? xstrdup(notes_ref) : NULL;
+ t->combine_notes = combine_notes;
t->initialized = 1;
if (flags & NOTES_INIT_EMPTY || !notes_ref ||
@@ -693,17 +713,19 @@ void init_notes(struct notes_tree *t, const char *notes_ref, int flags)
}
void add_note(struct notes_tree *t, const unsigned char *object_sha1,
- const unsigned char *note_sha1)
+ const unsigned char *note_sha1, combine_notes_fn combine_notes)
{
struct leaf_node *l;
if (!t)
t = &default_notes_tree;
assert(t->initialized);
+ if (!combine_notes)
+ combine_notes = t->combine_notes;
l = (struct leaf_node *) xmalloc(sizeof(struct leaf_node));
hashcpy(l->key_sha1, object_sha1);
hashcpy(l->val_sha1, note_sha1);
- note_tree_insert(t->root, 0, l, PTR_TYPE_NOTE);
+ note_tree_insert(t->root, 0, l, PTR_TYPE_NOTE, combine_notes);
}
void remove_note(struct notes_tree *t, const unsigned char *object_sha1)
@@ -788,7 +810,7 @@ void format_note(struct notes_tree *t, const unsigned char *object_sha1,
if (!t)
t = &default_notes_tree;
if (!t->initialized)
- init_notes(t, NULL, 0);
+ init_notes(t, NULL, NULL, 0);
sha1 = get_note(t, object_sha1);
if (!sha1)