aboutsummaryrefslogtreecommitdiff
path: root/notes.h
blob: 3848c2fb3f03510c1d0e1bd23ef6fbb3060b89c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
#ifndef NOTES_H
#define NOTES_H

#include "string-list.h"

/*
 * Function type for combining two notes annotating the same object.
 *
 * When adding a new note annotating the same object as an existing note, it is
 * up to the caller to decide how to combine the two notes. The decision is
 * made by passing in a function of the following form. The function accepts
 * two SHA1s -- of the existing note and the new note, respectively. The
 * function then combines the notes in whatever way it sees fit, and writes the
 * resulting SHA1 into the first SHA1 argument (cur_sha1). A non-zero return
 * value indicates failure.
 *
 * The two given SHA1s shall both be non-NULL and different from each other.
 * Either of them (but not both) may be == null_sha1, which indicates an
 * empty/non-existent note. If the resulting SHA1 (cur_sha1) is == null_sha1,
 * the note will be removed from the notes tree.
 *
 * The default combine_notes function (you get this when passing NULL) is
 * combine_notes_concatenate(), which appends the contents of the new note to
 * the contents of the existing note.
 */
typedef int (*combine_notes_fn)(unsigned char *cur_sha1, const unsigned char *new_sha1);

/* Common notes combinators */
int combine_notes_concatenate(unsigned char *cur_sha1, const unsigned char *new_sha1);
int combine_notes_overwrite(unsigned char *cur_sha1, const unsigned char *new_sha1);
int combine_notes_ignore(unsigned char *cur_sha1, const unsigned char *new_sha1);
int combine_notes_cat_sort_uniq(unsigned char *cur_sha1, const unsigned char *new_sha1);

/*
 * Notes tree object
 *
 * Encapsulates the internal notes tree structure associated with a notes ref.
 * Whenever a struct notes_tree pointer is required below, you may pass NULL in
 * order to use the default/internal notes tree. E.g. you only need to pass a
 * non-NULL value if you need to refer to several different notes trees
 * simultaneously.
 */
extern struct notes_tree {
	struct int_node *root;
	struct non_note *first_non_note, *prev_non_note;
	char *ref;
	char *update_ref;
	combine_notes_fn combine_notes;
	int initialized;
	int dirty;
} default_notes_tree;

/*
 * Return the default notes ref.
 *
 * The default notes ref is the notes ref that is used when notes_ref == NULL
 * is passed to init_notes().
 *
 * This the first of the following to be defined:
 * 1. The '--ref' option to 'git notes', if given
 * 2. The $GIT_NOTES_REF environment variable, if set
 * 3. The value of the core.notesRef config variable, if set
 * 4. GIT_NOTES_DEFAULT_REF (i.e. "refs/notes/commits")
 */
const char *default_notes_ref(void);

/*
 * Flags controlling behaviour of notes tree initialization
 *
 * Default behaviour is to initialize the notes tree from the tree object
 * specified by the given (or default) notes ref.
 */
#define NOTES_INIT_EMPTY 1

/*
 * By default, the notes tree is only readable, and the notes ref can be
 * any treeish. The notes tree can however be made writable with this flag,
 * in which case only strict ref names can be used.
 */
#define NOTES_INIT_WRITABLE 2

/*
 * Initialize the given notes_tree with the notes tree structure at the given
 * ref. If given ref is NULL, the value of the $GIT_NOTES_REF environment
 * variable is used, and if that is missing, the default notes ref is used
 * ("refs/notes/commits").
 *
 * If you need to re-initialize a notes_tree structure (e.g. when switching from
 * one notes ref to another), you must first de-initialize the notes_tree
 * structure by calling free_notes(struct notes_tree *).
 *
 * If you pass t == NULL, the default internal notes_tree will be initialized.
 *
 * The combine_notes function that is passed becomes the default combine_notes
 * function for the given notes_tree. If NULL is passed, the default
 * combine_notes function is combine_notes_concatenate().
 *
 * Precondition: The notes_tree structure is zeroed (this can be achieved with
 * memset(t, 0, sizeof(struct notes_tree)))
 */
void init_notes(struct notes_tree *t, const char *notes_ref,
		combine_notes_fn combine_notes, int flags);

/*
 * Add the given note object to the given notes_tree structure
 *
 * If there already exists a note for the given object_sha1, the given
 * combine_notes function is invoked to break the tie. If not given (i.e.
 * combine_notes == NULL), the default combine_notes function for the given
 * notes_tree is used.
 *
 * Passing note_sha1 == null_sha1 indicates the addition of an
 * empty/non-existent note. This is a (potentially expensive) no-op unless
 * there already exists a note for the given object_sha1, AND combining that
 * note with the empty note (using the given combine_notes function) results
 * in a new/changed note.
 *
 * Returns zero on success; non-zero means combine_notes failed.
 *
 * IMPORTANT: The changes made by add_note() to the given notes_tree structure
 * are not persistent until a subsequent call to write_notes_tree() returns
 * zero.
 */
int add_note(struct notes_tree *t, const struct object_id *object_oid,
		const struct object_id *note_oid, combine_notes_fn combine_notes);

/*
 * Remove the given note object from the given notes_tree structure
 *
 * IMPORTANT: The changes made by remove_note() to the given notes_tree
 * structure are not persistent until a subsequent call to write_notes_tree()
 * returns zero.
 *
 * Return 0 if a note was removed; 1 if there was no note to remove.
 */
int remove_note(struct notes_tree *t, const unsigned char *object_sha1);

/*
 * Get the note object SHA1 containing the note data for the given object
 *
 * Return NULL if the given object has no notes.
 */
const struct object_id *get_note(struct notes_tree *t,
		const struct object_id *object_oid);

/*
 * Copy a note from one object to another in the given notes_tree.
 *
 * Returns 1 if the to_obj already has a note and 'force' is false. Otherwise,
 * returns non-zero if 'force' is true, but the given combine_notes function
 * failed to combine from_obj's note with to_obj's existing note.
 * Returns zero on success.
 *
 * IMPORTANT: The changes made by copy_note() to the given notes_tree structure
 * are not persistent until a subsequent call to write_notes_tree() returns
 * zero.
 */
int copy_note(struct notes_tree *t,
	      const struct object_id *from_obj, const struct object_id *to_obj,
	      int force, combine_notes_fn combine_notes);

/*
 * Flags controlling behaviour of for_each_note()
 *
 * Default behaviour of for_each_note() is to traverse every single note object
 * in the given notes tree, unpacking subtree entries along the way.
 * The following flags can be used to alter the default behaviour:
 *
 * - DONT_UNPACK_SUBTREES causes for_each_note() NOT to unpack and recurse into
 *   subtree entries while traversing the notes tree. This causes notes within
 *   those subtrees NOT to be passed to the callback. Use this flag if you
 *   don't want to traverse _all_ notes, but only want to traverse the parts
 *   of the notes tree that have already been unpacked (this includes at least
 *   all notes that have been added/changed).
 *
 * - YIELD_SUBTREES causes any subtree entries that are encountered to be
 *   passed to the callback, before recursing into them. Subtree entries are
 *   not note objects, but represent intermediate directories in the notes
 *   tree. When passed to the callback, subtree entries will have a trailing
 *   slash in their path, which the callback may use to differentiate between
 *   note entries and subtree entries. Note that already-unpacked subtree
 *   entries are not part of the notes tree, and will therefore not be yielded.
 *   If this flag is used together with DONT_UNPACK_SUBTREES, for_each_note()
 *   will yield the subtree entry, but not recurse into it.
 */
#define FOR_EACH_NOTE_DONT_UNPACK_SUBTREES 1
#define FOR_EACH_NOTE_YIELD_SUBTREES 2

/*
 * Invoke the specified callback function for each note in the given notes_tree
 *
 * If the callback returns nonzero, the note walk is aborted, and the return
 * value from the callback is returned from for_each_note(). Hence, a zero
 * return value from for_each_note() indicates that all notes were walked
 * successfully.
 *
 * IMPORTANT: The callback function is NOT allowed to change the notes tree.
 * In other words, the following functions can NOT be invoked (on the current
 * notes tree) from within the callback:
 * - add_note()
 * - remove_note()
 * - copy_note()
 * - free_notes()
 */
typedef int each_note_fn(const struct object_id *object_oid,
		const struct object_id *note_oid, char *note_path,
		void *cb_data);
int for_each_note(struct notes_tree *t, int flags, each_note_fn fn,
		void *cb_data);

/*
 * Write the given notes_tree structure to the object database
 *
 * Creates a new tree object encapsulating the current state of the given
 * notes_tree, and stores its SHA1 into the 'result' argument.
 *
 * Returns zero on success, non-zero on failure.
 *
 * IMPORTANT: Changes made to the given notes_tree are not persistent until
 * this function has returned zero. Please also remember to create a
 * corresponding commit object, and update the appropriate notes ref.
 */
int write_notes_tree(struct notes_tree *t, unsigned char *result);

/* Flags controlling the operation of prune */
#define NOTES_PRUNE_VERBOSE 1
#define NOTES_PRUNE_DRYRUN 2
/*
 * Remove all notes annotating non-existing objects from the given notes tree
 *
 * All notes in the given notes_tree that are associated with objects that no
 * longer exist in the database, are removed from the notes tree.
 *
 * IMPORTANT: The changes made by prune_notes() to the given notes_tree
 * structure are not persistent until a subsequent call to write_notes_tree()
 * returns zero.
 */
void prune_notes(struct notes_tree *t, int flags);

/*
 * Free (and de-initialize) the given notes_tree structure
 *
 * IMPORTANT: Changes made to the given notes_tree since the last, successful
 * call to write_notes_tree() will be lost.
 */
void free_notes(struct notes_tree *t);

struct string_list;

struct display_notes_opt {
	int use_default_notes;
	struct string_list extra_notes_refs;
};

/*
 * Load the notes machinery for displaying several notes trees.
 *
 * If 'opt' is not NULL, then it specifies additional settings for the
 * displaying:
 *
 * - suppress_default_notes indicates that the notes from
 *   core.notesRef and notes.displayRef should not be loaded.
 *
 * - extra_notes_refs may contain a list of globs (in the same style
 *   as notes.displayRef) where notes should be loaded from.
 */
void init_display_notes(struct display_notes_opt *opt);

/*
 * Append notes for the given 'object_sha1' from all trees set up by
 * init_display_notes() to 'sb'.  The 'flags' are a bitwise
 * combination of
 *
 * - NOTES_SHOW_HEADER: add a 'Notes (refname):' header
 *
 * - NOTES_INDENT: indent the notes by 4 places
 *
 * You *must* call init_display_notes() before using this function.
 */
void format_display_notes(const struct object_id *object_oid,
			  struct strbuf *sb, const char *output_encoding, int raw);

/*
 * Load the notes tree from each ref listed in 'refs'.  The output is
 * an array of notes_tree*, terminated by a NULL.
 */
struct notes_tree **load_notes_trees(struct string_list *refs, int flags);

/*
 * Add all refs that match 'glob' to the 'list'.
 */
void string_list_add_refs_by_glob(struct string_list *list, const char *glob);

/*
 * Add all refs from a colon-separated glob list 'globs' to the end of
 * 'list'.  Empty components are ignored.  This helper is used to
 * parse GIT_NOTES_DISPLAY_REF style environment variables.
 */
void string_list_add_refs_from_colon_sep(struct string_list *list,
					 const char *globs);

/* Expand inplace a note ref like "foo" or "notes/foo" into "refs/notes/foo" */
void expand_notes_ref(struct strbuf *sb);

/*
 * Similar to expand_notes_ref, but will check whether the ref can be located
 * via get_sha1 first, and only falls back to expand_notes_ref in the case
 * where get_sha1 fails.
 */
void expand_loose_notes_ref(struct strbuf *sb);

#endif