Notes API: write_notes_tree(): Store the notes tree in the database
Uses for_each_note() to traverse the notes tree, and produces tree objects on the fly representing the "on-disk" version of the notes tree with appropriate fanout. Signed-off-by: Johan Herland <johan@herland.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Johan Herland committed
Feb 13, 2010 at 22:28 UTC
61a7cca0c6504aee7bae7837582230561bdb81d4
2 files changed
+180
-3
notes.c
+145
@@ -1,5 +1,6 @@
1
#include "cache.h"
2
#include "notes.h"
3
+#include "tree.h"
4
#include "utf8.h"
5
#include "strbuf.h"
6
#include "tree-walk.h"
@@ -540,6 +541,126 @@ redo:
541
return 0;
542
}
543
544
+struct tree_write_stack {
545
+ struct tree_write_stack *next;
546
+ struct strbuf buf;
547
+ char path[2]; /* path to subtree in next, if any */
548
+};
549
+
550
+static inline int matches_tree_write_stack(struct tree_write_stack *tws,
551
+ const char *full_path)
552
+{
553
+ return full_path[0] == tws->path[0] &&
554
+ full_path[1] == tws->path[1] &&
555
+ full_path[2] == '/';
556
+}
557
+
558
+static void write_tree_entry(struct strbuf *buf, unsigned int mode,
559
+ const char *path, unsigned int path_len, const
560
+ unsigned char *sha1)
561
+{
562
+ strbuf_addf(buf, "%06o %.*s%c", mode, path_len, path, '\0');
563
+ strbuf_add(buf, sha1, 20);
564
+}
565
+
566
+static void tree_write_stack_init_subtree(struct tree_write_stack *tws,
567
+ const char *path)
568
+{
569
+ struct tree_write_stack *n;
570
+ assert(!tws->next);
571
+ assert(tws->path[0] == '\0' && tws->path[1] == '\0');
572
+ n = (struct tree_write_stack *)
573
+ xmalloc(sizeof(struct tree_write_stack));
574
+ n->next = NULL;
575
+ strbuf_init(&n->buf, 256 * (32 + 40)); /* assume 256 entries per tree */
576
+ n->path[0] = n->path[1] = '\0';
577
+ tws->next = n;
578
+ tws->path[0] = path[0];
579
+ tws->path[1] = path[1];
580
+}
581
+
582
+static int tree_write_stack_finish_subtree(struct tree_write_stack *tws)
583
+{
584
+ int ret;
585
+ struct tree_write_stack *n = tws->next;
586
+ unsigned char s[20];
587
+ if (n) {
588
+ ret = tree_write_stack_finish_subtree(n);
589
+ if (ret)
590
+ return ret;
591
+ ret = write_sha1_file(n->buf.buf, n->buf.len, tree_type, s);
592
+ if (ret)
593
+ return ret;
594
+ strbuf_release(&n->buf);
595
+ free(n);
596
+ tws->next = NULL;
597
+ write_tree_entry(&tws->buf, 040000, tws->path, 2, s);
598
+ tws->path[0] = tws->path[1] = '\0';
599
+ }
600
+ return 0;
601
+}
602
+
603
+static int write_each_note_helper(struct tree_write_stack *tws,
604
+ const char *path, unsigned int mode,
605
+ const unsigned char *sha1)
606
+{
607
+ size_t path_len = strlen(path);
608
+ unsigned int n = 0;
609
+ int ret;
610
+
611
+ /* Determine common part of tree write stack */
612
+ while (tws && 3 * n < path_len &&
613
+ matches_tree_write_stack(tws, path + 3 * n)) {
614
+ n++;
615
+ tws = tws->next;
616
+ }
617
+
618
+ /* tws point to last matching tree_write_stack entry */
619
+ ret = tree_write_stack_finish_subtree(tws);
620
+ if (ret)
621
+ return ret;
622
+
623
+ /* Start subtrees needed to satisfy path */
624
+ while (3 * n + 2 < path_len && path[3 * n + 2] == '/') {
625
+ tree_write_stack_init_subtree(tws, path + 3 * n);
626
+ n++;
627
+ tws = tws->next;
628
+ }
629
+
630
+ /* There should be no more directory components in the given path */
631
+ assert(memchr(path + 3 * n, '/', path_len - (3 * n)) == NULL);
632
+
633
+ /* Finally add given entry to the current tree object */
634
+ write_tree_entry(&tws->buf, mode, path + 3 * n, path_len - (3 * n),
635
+ sha1);
636
+
637
+ return 0;
638
+}
639
+
640
+struct write_each_note_data {
641
+ struct tree_write_stack *root;
642
+};
643
+
644
+static int write_each_note(const unsigned char *object_sha1,
645
+ const unsigned char *note_sha1, char *note_path,
646
+ void *cb_data)
647
+{
648
+ struct write_each_note_data *d =
649
+ (struct write_each_note_data *) cb_data;
650
+ size_t note_path_len = strlen(note_path);
651
+ unsigned int mode = 0100644;
652
+
653
+ if (note_path[note_path_len - 1] == '/') {
654
+ /* subtree entry */
655
+ note_path_len--;
656
+ note_path[note_path_len] = '\0';
657
+ mode = 040000;
658
+ }
659
+ assert(note_path_len <= 40 + 19);
660
+
661
+ return write_each_note_helper(d->root, note_path, mode, note_sha1);
662
+}
663
+
664
void init_notes(const char *notes_ref, int flags)
665
{
666
unsigned char sha1[20], object_sha1[20];
@@ -604,6 +725,30 @@ int for_each_note(int flags, each_note_fn fn, void *cb_data)
725
return for_each_note_helper(&root_node, 0, 0, flags, fn, cb_data);
726
}
727
728
+int write_notes_tree(unsigned char *result)
729
+{
730
+ struct tree_write_stack root;
731
+ struct write_each_note_data cb_data;
732
+ int ret;
733
+
734
+ assert(initialized);
735
+
736
+ /* Prepare for traversal of current notes tree */
737
+ root.next = NULL; /* last forward entry in list is grounded */
738
+ strbuf_init(&root.buf, 256 * (32 + 40)); /* assume 256 entries */
739
+ root.path[0] = root.path[1] = '\0';
740
+ cb_data.root = &root;
741
+
742
+ /* Write tree objects representing current notes tree */
743
+ ret = for_each_note(FOR_EACH_NOTE_DONT_UNPACK_SUBTREES |
744
+ FOR_EACH_NOTE_YIELD_SUBTREES,
745
+ write_each_note, &cb_data) ||
746
+ tree_write_stack_finish_subtree(&root) ||
747
+ write_sha1_file(root.buf.buf, root.buf.len, tree_type, result);
748
+ strbuf_release(&root.buf);
749
+ return ret;
750
+}
751
+
752
void free_notes(void)
753
{
754
note_tree_free(&root_node);
notes.h
+35
-3
@@ -21,11 +21,23 @@
21
*/
22
void init_notes(const char *notes_ref, int flags);
23
24
-/* Add the given note object to the internal notes tree structure */
24
+/*
25
+ * Add the given note object to the internal notes tree structure
26
+ *
27
+ * IMPORTANT: The changes made by add_note() to the internal notes tree structure
28
+ * are not persistent until a subsequent call to write_notes_tree() returns
29
+ * zero.
30
+ */
31
void add_note(const unsigned char *object_sha1,
32
const unsigned char *note_sha1);
33
28
-/* Remove the given note object from the internal notes tree structure */
34
+/*
35
+ * Remove the given note object from the internal notes tree structure
36
+ *
37
+ * IMPORTANT: The changes made by remove_note() to the internal notes tree
38
+ * structure are not persistent until a subsequent call to write_notes_tree()
39
+ * returns zero.
40
+ */
41
void remove_note(const unsigned char *object_sha1);
42
43
/*
@@ -82,7 +94,27 @@ typedef int each_note_fn(const unsigned char *object_sha1,
94
void *cb_data);
95
int for_each_note(int flags, each_note_fn fn, void *cb_data);
96
85
-/* Free (and de-initialize) the internal notes tree structure */
97
+/*
98
+ * Write the internal notes tree structure to the object database
99
+ *
100
+ * Creates a new tree object encapsulating the current state of the
101
+ * internal notes tree, and stores its SHA1 into the 'result' argument.
102
+ *
103
+ * Returns zero on success, non-zero on failure.
104
+ *
105
+ * IMPORTANT: Changes made to the internal notes tree structure are not
106
+ * persistent until this function has returned zero. Please also remember
107
+ * to create a corresponding commit object, and update the appropriate
108
+ * notes ref.
109
+ */
110
+int write_notes_tree(unsigned char *result);
111
+
112
+/*
113
+ * Free (and de-initialize) the internal notes tree structure
114
+ *
115
+ * IMPORTANT: Changes made to the notes tree since the last, successful
116
+ * call to write_notes_tree() will be lost.
117
+ */
118
void free_notes(void);
119
120
/* Flags controlling how notes are formatted */