source src/notes.c
Line | Flow | Count | Block(s) | Source |
---|---|---|---|---|
1 | - | /* | ||
2 | - | * Copyright (C) the libgit2 contributors. All rights reserved. | ||
3 | - | * | ||
4 | - | * This file is part of libgit2, distributed under the GNU GPL v2 with | ||
5 | - | * a Linking Exception. For full terms see the included COPYING file. | ||
6 | - | */ | ||
7 | - | |||
8 | - | #include "notes.h" | ||
9 | - | |||
10 | - | #include "git2.h" | ||
11 | - | #include "refs.h" | ||
12 | - | #include "config.h" | ||
13 | - | #include "iterator.h" | ||
14 | - | #include "signature.h" | ||
15 | - | #include "blob.h" | ||
16 | - | |||
17 | 58 | 2 | static int note_error_notfound(void) | |
18 | - | { | ||
19 | 58 | 2 | git_error_set(GIT_ERROR_INVALID, "note could not be found"); | |
20 | 58 | 3 | return GIT_ENOTFOUND; | |
21 | - | } | ||
22 | - | |||
23 | 114 | 2 | static int find_subtree_in_current_level( | |
24 | - | git_tree **out, | ||
25 | - | git_repository *repo, | ||
26 | - | git_tree *parent, | ||
27 | - | const char *annotated_object_sha, | ||
28 | - | int fanout) | ||
29 | - | { | ||
30 | - | size_t i; | ||
31 | - | const git_tree_entry *entry; | ||
32 | - | |||
33 | 114 | 2 | *out = NULL; | |
34 | - | |||
35 | 114 | 2 | if (parent == NULL) | |
36 | 24 | 3 | return note_error_notfound(); | |
37 | - | |||
38 | 297 | 4,21-23 | for (i = 0; i < git_tree_entrycount(parent); i++) { | |
39 | 263 | 5 | entry = git_tree_entry_byindex(parent, i); | |
40 | - | |||
41 | 263 | 6-8 | if (!git__ishex(git_tree_entry_name(entry))) | |
42 | ##### | 9 | continue; | |
43 | - | |||
44 | 263 | 10,11 | if (S_ISDIR(git_tree_entry_filemode(entry)) | |
45 | 34 | 12,13 | && strlen(git_tree_entry_name(entry)) == 2 | |
46 | 34 | 14,15 | && !strncmp(git_tree_entry_name(entry), annotated_object_sha + fanout, 2)) | |
47 | 12 | 16,17 | return git_tree_lookup(out, repo, git_tree_entry_id(entry)); | |
48 | - | |||
49 | - | /* Not a DIR, so do we have an already existing blob? */ | ||
50 | 251 | 18,19 | if (!strcmp(git_tree_entry_name(entry), annotated_object_sha + fanout)) | |
51 | 44 | 20 | return GIT_EEXISTS; | |
52 | - | } | ||
53 | - | |||
54 | 34 | 24 | return note_error_notfound(); | |
55 | - | } | ||
56 | - | |||
57 | 46 | 2 | static int find_subtree_r(git_tree **out, git_tree *root, | |
58 | - | git_repository *repo, const char *target, int *fanout) | ||
59 | - | { | ||
60 | - | int error; | ||
61 | 46 | 2 | git_tree *subtree = NULL; | |
62 | - | |||
63 | 46 | 2 | *out = NULL; | |
64 | - | |||
65 | 46 | 2 | error = find_subtree_in_current_level(&subtree, repo, root, target, *fanout); | |
66 | 46 | 3 | if (error == GIT_EEXISTS) | |
67 | 35 | 4,5 | return git_tree_lookup(out, repo, git_tree_id(root)); | |
68 | - | |||
69 | 11 | 6 | if (error < 0) | |
70 | 6 | 7 | return error; | |
71 | - | |||
72 | 5 | 8 | *fanout += 2; | |
73 | 5 | 8 | error = find_subtree_r(out, subtree, repo, target, fanout); | |
74 | 5 | 9 | git_tree_free(subtree); | |
75 | - | |||
76 | 5 | 10 | return error; | |
77 | - | } | ||
78 | - | |||
79 | 35 | 2 | static int find_blob(git_oid *blob, git_tree *tree, const char *target) | |
80 | - | { | ||
81 | - | size_t i; | ||
82 | - | const git_tree_entry *entry; | ||
83 | - | |||
84 | 100 | 2,9-11 | for (i=0; i<git_tree_entrycount(tree); i++) { | |
85 | 100 | 3 | entry = git_tree_entry_byindex(tree, i); | |
86 | - | |||
87 | 100 | 4,5 | if (!strcmp(git_tree_entry_name(entry), target)) { | |
88 | - | /* found matching note object - return */ | ||
89 | - | |||
90 | 35 | 6,7 | git_oid_cpy(blob, git_tree_entry_id(entry)); | |
91 | 35 | 8 | return 0; | |
92 | - | } | ||
93 | - | } | ||
94 | - | |||
95 | ##### | 12 | return note_error_notfound(); | |
96 | - | } | ||
97 | - | |||
98 | 63 | 2 | static int tree_write( | |
99 | - | git_tree **out, | ||
100 | - | git_repository *repo, | ||
101 | - | git_tree *source_tree, | ||
102 | - | const git_oid *object_oid, | ||
103 | - | const char *treeentry_name, | ||
104 | - | unsigned int attributes) | ||
105 | - | { | ||
106 | - | int error; | ||
107 | 63 | 2 | git_treebuilder *tb = NULL; | |
108 | - | const git_tree_entry *entry; | ||
109 | - | git_oid tree_oid; | ||
110 | - | |||
111 | 63 | 2,3 | if ((error = git_treebuilder_new(&tb, repo, source_tree)) < 0) | |
112 | ##### | 4 | goto cleanup; | |
113 | - | |||
114 | 63 | 5 | if (object_oid) { | |
115 | 58 | 6,7 | if ((error = git_treebuilder_insert( | |
116 | - | &entry, tb, treeentry_name, object_oid, attributes)) < 0) | ||
117 | ##### | 8 | goto cleanup; | |
118 | - | } else { | ||
119 | 5 | 9,10 | if ((error = git_treebuilder_remove(tb, treeentry_name)) < 0) | |
120 | ##### | 11 | goto cleanup; | |
121 | - | } | ||
122 | - | |||
123 | 63 | 12,13 | if ((error = git_treebuilder_write(&tree_oid, tb)) < 0) | |
124 | ##### | 14 | goto cleanup; | |
125 | - | |||
126 | 63 | 15 | error = git_tree_lookup(out, repo, &tree_oid); | |
127 | - | |||
128 | - | cleanup: | ||
129 | 63 | 16 | git_treebuilder_free(tb); | |
130 | 63 | 17 | return error; | |
131 | - | } | ||
132 | - | |||
133 | 68 | 2 | static int manipulate_note_in_tree_r( | |
134 | - | git_tree **out, | ||
135 | - | git_repository *repo, | ||
136 | - | git_tree *parent, | ||
137 | - | git_oid *note_oid, | ||
138 | - | const char *annotated_object_sha, | ||
139 | - | int fanout, | ||
140 | - | int (*note_exists_cb)( | ||
141 | - | git_tree **out, | ||
142 | - | git_repository *repo, | ||
143 | - | git_tree *parent, | ||
144 | - | git_oid *note_oid, | ||
145 | - | const char *annotated_object_sha, | ||
146 | - | int fanout, | ||
147 | - | int current_error), | ||
148 | - | int (*note_notfound_cb)( | ||
149 | - | git_tree **out, | ||
150 | - | git_repository *repo, | ||
151 | - | git_tree *parent, | ||
152 | - | git_oid *note_oid, | ||
153 | - | const char *annotated_object_sha, | ||
154 | - | int fanout, | ||
155 | - | int current_error)) | ||
156 | - | { | ||
157 | - | int error; | ||
158 | 68 | 2 | git_tree *subtree = NULL, *new = NULL; | |
159 | - | char subtree_name[3]; | ||
160 | - | |||
161 | 68 | 2 | error = find_subtree_in_current_level( | |
162 | - | &subtree, repo, parent, annotated_object_sha, fanout); | ||
163 | - | |||
164 | 68 | 3 | if (error == GIT_EEXISTS) { | |
165 | 9 | 4 | error = note_exists_cb( | |
166 | - | out, repo, parent, note_oid, annotated_object_sha, fanout, error); | ||
167 | 9 | 5 | goto cleanup; | |
168 | - | } | ||
169 | - | |||
170 | 59 | 6 | if (error == GIT_ENOTFOUND) { | |
171 | 52 | 7 | error = note_notfound_cb( | |
172 | - | out, repo, parent, note_oid, annotated_object_sha, fanout, error); | ||
173 | 52 | 8 | goto cleanup; | |
174 | - | } | ||
175 | - | |||
176 | 7 | 9 | if (error < 0) | |
177 | ##### | 10 | goto cleanup; | |
178 | - | |||
179 | - | /* An existing fanout has been found, let's dig deeper */ | ||
180 | 7 | 11 | error = manipulate_note_in_tree_r( | |
181 | - | &new, repo, subtree, note_oid, annotated_object_sha, | ||
182 | - | fanout + 2, note_exists_cb, note_notfound_cb); | ||
183 | - | |||
184 | 7 | 12 | if (error < 0) | |
185 | 2 | 13 | goto cleanup; | |
186 | - | |||
187 | 5 | 14 | strncpy(subtree_name, annotated_object_sha + fanout, 2); | |
188 | 5 | 14 | subtree_name[2] = '\0'; | |
189 | - | |||
190 | 5 | 14,15 | error = tree_write(out, repo, parent, git_tree_id(new), | |
191 | - | subtree_name, GIT_FILEMODE_TREE); | ||
192 | - | |||
193 | - | |||
194 | - | cleanup: | ||
195 | 68 | 16 | git_tree_free(new); | |
196 | 68 | 17 | git_tree_free(subtree); | |
197 | 68 | 18 | return error; | |
198 | - | } | ||
199 | - | |||
200 | 5 | 2 | static int remove_note_in_tree_eexists_cb( | |
201 | - | git_tree **out, | ||
202 | - | git_repository *repo, | ||
203 | - | git_tree *parent, | ||
204 | - | git_oid *note_oid, | ||
205 | - | const char *annotated_object_sha, | ||
206 | - | int fanout, | ||
207 | - | int current_error) | ||
208 | - | { | ||
209 | - | GIT_UNUSED(note_oid); | ||
210 | - | GIT_UNUSED(current_error); | ||
211 | - | |||
212 | 5 | 2 | return tree_write(out, repo, parent, NULL, annotated_object_sha + fanout, 0); | |
213 | - | } | ||
214 | - | |||
215 | 1 | 2 | static int remove_note_in_tree_enotfound_cb( | |
216 | - | git_tree **out, | ||
217 | - | git_repository *repo, | ||
218 | - | git_tree *parent, | ||
219 | - | git_oid *note_oid, | ||
220 | - | const char *annotated_object_sha, | ||
221 | - | int fanout, | ||
222 | - | int current_error) | ||
223 | - | { | ||
224 | - | GIT_UNUSED(out); | ||
225 | - | GIT_UNUSED(repo); | ||
226 | - | GIT_UNUSED(parent); | ||
227 | - | GIT_UNUSED(note_oid); | ||
228 | - | GIT_UNUSED(fanout); | ||
229 | - | |||
230 | 1 | 2 | git_error_set(GIT_ERROR_REPOSITORY, "object '%s' has no note", annotated_object_sha); | |
231 | 1 | 3 | return current_error; | |
232 | - | } | ||
233 | - | |||
234 | 2 | 2 | static int insert_note_in_tree_eexists_cb(git_tree **out, | |
235 | - | git_repository *repo, | ||
236 | - | git_tree *parent, | ||
237 | - | git_oid *note_oid, | ||
238 | - | const char *annotated_object_sha, | ||
239 | - | int fanout, | ||
240 | - | int current_error) | ||
241 | - | { | ||
242 | - | GIT_UNUSED(out); | ||
243 | - | GIT_UNUSED(repo); | ||
244 | - | GIT_UNUSED(parent); | ||
245 | - | GIT_UNUSED(note_oid); | ||
246 | - | GIT_UNUSED(fanout); | ||
247 | - | |||
248 | 2 | 2 | git_error_set(GIT_ERROR_REPOSITORY, "note for '%s' exists already", annotated_object_sha); | |
249 | 2 | 3 | return current_error; | |
250 | - | } | ||
251 | - | |||
252 | 53 | 2 | static int insert_note_in_tree_enotfound_cb(git_tree **out, | |
253 | - | git_repository *repo, | ||
254 | - | git_tree *parent, | ||
255 | - | git_oid *note_oid, | ||
256 | - | const char *annotated_object_sha, | ||
257 | - | int fanout, | ||
258 | - | int current_error) | ||
259 | - | { | ||
260 | - | GIT_UNUSED(current_error); | ||
261 | - | |||
262 | - | /* No existing fanout at this level, insert in place */ | ||
263 | 53 | 2 | return tree_write( | |
264 | - | out, | ||
265 | - | repo, | ||
266 | - | parent, | ||
267 | - | note_oid, | ||
268 | - | annotated_object_sha + fanout, | ||
269 | - | GIT_FILEMODE_BLOB); | ||
270 | - | } | ||
271 | - | |||
272 | 55 | 2 | static int note_write( | |
273 | - | git_oid *notes_commit_out, | ||
274 | - | git_oid *notes_blob_out, | ||
275 | - | git_repository *repo, | ||
276 | - | const git_signature *author, | ||
277 | - | const git_signature *committer, | ||
278 | - | const char *notes_ref, | ||
279 | - | const char *note, | ||
280 | - | git_tree *commit_tree, | ||
281 | - | const char *target, | ||
282 | - | git_commit **parents, | ||
283 | - | int allow_note_overwrite) | ||
284 | - | { | ||
285 | - | int error; | ||
286 | - | git_oid oid; | ||
287 | 55 | 2 | git_tree *tree = NULL; | |
288 | - | |||
289 | - | /* TODO: should we apply filters? */ | ||
290 | - | /* create note object */ | ||
291 | 55 | 2,3 | if ((error = git_blob_create_from_buffer(&oid, repo, note, strlen(note))) < 0) | |
292 | ##### | 4 | goto cleanup; | |
293 | - | |||
294 | 55 | 5-9 | if ((error = manipulate_note_in_tree_r( | |
295 | - | &tree, repo, commit_tree, &oid, target, 0, | ||
296 | - | allow_note_overwrite ? insert_note_in_tree_enotfound_cb : insert_note_in_tree_eexists_cb, | ||
297 | - | insert_note_in_tree_enotfound_cb)) < 0) | ||
298 | 2 | 10 | goto cleanup; | |
299 | - | |||
300 | 53 | 11 | if (notes_blob_out) | |
301 | 45 | 12 | git_oid_cpy(notes_blob_out, &oid); | |
302 | - | |||
303 | - | |||
304 | 53 | 13 | error = git_commit_create(&oid, repo, notes_ref, author, committer, | |
305 | - | NULL, GIT_NOTES_DEFAULT_MSG_ADD, | ||
306 | 53 | 13 | tree, *parents == NULL ? 0 : 1, (const git_commit **) parents); | |
307 | - | |||
308 | 53 | 14 | if (notes_commit_out) | |
309 | 53 | 15 | git_oid_cpy(notes_commit_out, &oid); | |
310 | - | |||
311 | - | cleanup: | ||
312 | 55 | 16 | git_tree_free(tree); | |
313 | 55 | 17 | return error; | |
314 | - | } | ||
315 | - | |||
316 | 35 | 2 | static int note_new( | |
317 | - | git_note **out, | ||
318 | - | git_oid *note_oid, | ||
319 | - | git_commit *commit, | ||
320 | - | git_blob *blob) | ||
321 | - | { | ||
322 | 35 | 2 | git_note *note = NULL; | |
323 | - | git_object_size_t blobsize; | ||
324 | - | |||
325 | 35 | 2 | note = git__malloc(sizeof(git_note)); | |
326 | 35 | 3,4 | GIT_ERROR_CHECK_ALLOC(note); | |
327 | - | |||
328 | 35 | 5 | git_oid_cpy(¬e->id, note_oid); | |
329 | - | |||
330 | 35 | 6-8,11 | if (git_signature_dup(¬e->author, git_commit_author(commit)) < 0 || | |
331 | 35 | 9,10 | git_signature_dup(¬e->committer, git_commit_committer(commit)) < 0) | |
332 | ##### | 12 | return -1; | |
333 | - | |||
334 | 35 | 13 | blobsize = git_blob_rawsize(blob); | |
335 | 35 | 14-17 | GIT_ERROR_CHECK_BLOBSIZE(blobsize); | |
336 | - | |||
337 | 35 | 18,19 | note->message = git__strndup(git_blob_rawcontent(blob), (size_t)blobsize); | |
338 | 35 | 20,21 | GIT_ERROR_CHECK_ALLOC(note->message); | |
339 | - | |||
340 | 35 | 22 | *out = note; | |
341 | 35 | 22 | return 0; | |
342 | - | } | ||
343 | - | |||
344 | 41 | 2 | static int note_lookup( | |
345 | - | git_note **out, | ||
346 | - | git_repository *repo, | ||
347 | - | git_commit *commit, | ||
348 | - | git_tree *tree, | ||
349 | - | const char *target) | ||
350 | - | { | ||
351 | 41 | 2 | int error, fanout = 0; | |
352 | - | git_oid oid; | ||
353 | 41 | 2 | git_blob *blob = NULL; | |
354 | 41 | 2 | git_note *note = NULL; | |
355 | 41 | 2 | git_tree *subtree = NULL; | |
356 | - | |||
357 | 41 | 2,3 | if ((error = find_subtree_r(&subtree, tree, repo, target, &fanout)) < 0) | |
358 | 6 | 4 | goto cleanup; | |
359 | - | |||
360 | 35 | 5,6 | if ((error = find_blob(&oid, subtree, target + fanout)) < 0) | |
361 | ##### | 7 | goto cleanup; | |
362 | - | |||
363 | 35 | 8,9 | if ((error = git_blob_lookup(&blob, repo, &oid)) < 0) | |
364 | ##### | 10 | goto cleanup; | |
365 | - | |||
366 | 35 | 11,12 | if ((error = note_new(¬e, &oid, commit, blob)) < 0) | |
367 | ##### | 13 | goto cleanup; | |
368 | - | |||
369 | 35 | 14 | *out = note; | |
370 | - | |||
371 | - | cleanup: | ||
372 | 41 | 15 | git_tree_free(subtree); | |
373 | 41 | 16 | git_blob_free(blob); | |
374 | 41 | 17 | return error; | |
375 | - | } | ||
376 | - | |||
377 | 6 | 2 | static int note_remove( | |
378 | - | git_oid *notes_commit_out, | ||
379 | - | git_repository *repo, | ||
380 | - | const git_signature *author, const git_signature *committer, | ||
381 | - | const char *notes_ref, git_tree *tree, | ||
382 | - | const char *target, git_commit **parents) | ||
383 | - | { | ||
384 | - | int error; | ||
385 | 6 | 2 | git_tree *tree_after_removal = NULL; | |
386 | - | git_oid oid; | ||
387 | - | |||
388 | 6 | 2,3 | if ((error = manipulate_note_in_tree_r( | |
389 | - | &tree_after_removal, repo, tree, NULL, target, 0, | ||
390 | - | remove_note_in_tree_eexists_cb, remove_note_in_tree_enotfound_cb)) < 0) | ||
391 | 1 | 4 | goto cleanup; | |
392 | - | |||
393 | 5 | 5 | error = git_commit_create(&oid, repo, notes_ref, author, committer, | |
394 | - | NULL, GIT_NOTES_DEFAULT_MSG_RM, | ||
395 | - | tree_after_removal, | ||
396 | 5 | 5 | *parents == NULL ? 0 : 1, | |
397 | - | (const git_commit **) parents); | ||
398 | - | |||
399 | 5 | 6 | if (error < 0) | |
400 | ##### | 7 | goto cleanup; | |
401 | - | |||
402 | 5 | 8 | if (notes_commit_out) | |
403 | 5 | 9 | git_oid_cpy(notes_commit_out, &oid); | |
404 | - | |||
405 | - | cleanup: | ||
406 | 6 | 10 | git_tree_free(tree_after_removal); | |
407 | 6 | 11 | return error; | |
408 | - | } | ||
409 | - | |||
410 | 15 | 2 | static int note_get_default_ref(char **out, git_repository *repo) | |
411 | - | { | ||
412 | - | git_config *cfg; | ||
413 | 15 | 2 | int ret = git_repository_config__weakptr(&cfg, repo); | |
414 | - | |||
415 | 15 | 3-5 | *out = (ret != 0) ? NULL : git_config__get_string_force( | |
416 | - | cfg, "core.notesref", GIT_NOTES_DEFAULT_REF); | ||
417 | - | |||
418 | 15 | 6 | return ret; | |
419 | - | } | ||
420 | - | |||
421 | 97 | 2 | static int normalize_namespace(char **out, git_repository *repo, const char *notes_ref) | |
422 | - | { | ||
423 | 97 | 2 | if (notes_ref) { | |
424 | 85 | 3 | *out = git__strdup(notes_ref); | |
425 | 85 | 4,5 | GIT_ERROR_CHECK_ALLOC(*out); | |
426 | 85 | 6 | return 0; | |
427 | - | } | ||
428 | - | |||
429 | 12 | 7 | return note_get_default_ref(out, repo); | |
430 | - | } | ||
431 | - | |||
432 | 97 | 2 | static int retrieve_note_commit( | |
433 | - | git_commit **commit_out, | ||
434 | - | char **notes_ref_out, | ||
435 | - | git_repository *repo, | ||
436 | - | const char *notes_ref) | ||
437 | - | { | ||
438 | - | int error; | ||
439 | - | git_oid oid; | ||
440 | - | |||
441 | 97 | 2,3 | if ((error = normalize_namespace(notes_ref_out, repo, notes_ref)) < 0) | |
442 | ##### | 4 | return error; | |
443 | - | |||
444 | 97 | 5,6 | if ((error = git_reference_name_to_id(&oid, repo, *notes_ref_out)) < 0) | |
445 | 20 | 7 | return error; | |
446 | - | |||
447 | 77 | 8,9 | if (git_commit_lookup(commit_out, repo, &oid) < 0) | |
448 | ##### | 10 | return error; | |
449 | - | |||
450 | 77 | 11 | return 0; | |
451 | - | } | ||
452 | - | |||
453 | 41 | 2 | int git_note_commit_read( | |
454 | - | git_note **out, | ||
455 | - | git_repository *repo, | ||
456 | - | git_commit *notes_commit, | ||
457 | - | const git_oid *oid) | ||
458 | - | { | ||
459 | - | int error; | ||
460 | 41 | 2 | git_tree *tree = NULL; | |
461 | - | char target[GIT_OID_HEXSZ + 1]; | ||
462 | - | |||
463 | 41 | 2 | git_oid_tostr(target, sizeof(target), oid); | |
464 | - | |||
465 | 41 | 3,4 | if ((error = git_commit_tree(&tree, notes_commit)) < 0) | |
466 | ##### | 5 | goto cleanup; | |
467 | - | |||
468 | 41 | 6 | error = note_lookup(out, repo, notes_commit, tree, target); | |
469 | - | |||
470 | - | cleanup: | ||
471 | 41 | 7 | git_tree_free(tree); | |
472 | 41 | 8 | return error; | |
473 | - | } | ||
474 | - | |||
475 | 37 | 2 | int git_note_read(git_note **out, git_repository *repo, | |
476 | - | const char *notes_ref_in, const git_oid *oid) | ||
477 | - | { | ||
478 | - | int error; | ||
479 | 37 | 2 | char *notes_ref = NULL; | |
480 | 37 | 2 | git_commit *commit = NULL; | |
481 | - | |||
482 | 37 | 2 | error = retrieve_note_commit(&commit, ¬es_ref, repo, notes_ref_in); | |
483 | - | |||
484 | 37 | 3 | if (error < 0) | |
485 | ##### | 4 | goto cleanup; | |
486 | - | |||
487 | 37 | 5 | error = git_note_commit_read(out, repo, commit, oid); | |
488 | - | |||
489 | - | cleanup: | ||
490 | 37 | 6 | git__free(notes_ref); | |
491 | 37 | 7 | git_commit_free(commit); | |
492 | 37 | 8 | return error; | |
493 | - | } | ||
494 | - | |||
495 | 55 | 2 | int git_note_commit_create( | |
496 | - | git_oid *notes_commit_out, | ||
497 | - | git_oid *notes_blob_out, | ||
498 | - | git_repository *repo, | ||
499 | - | git_commit *parent, | ||
500 | - | const git_signature *author, | ||
501 | - | const git_signature *committer, | ||
502 | - | const git_oid *oid, | ||
503 | - | const char *note, | ||
504 | - | int allow_note_overwrite) | ||
505 | - | { | ||
506 | - | int error; | ||
507 | 55 | 2 | git_tree *tree = NULL; | |
508 | - | char target[GIT_OID_HEXSZ + 1]; | ||
509 | - | |||
510 | 55 | 2 | git_oid_tostr(target, sizeof(target), oid); | |
511 | - | |||
512 | 55 | 3-5 | if (parent != NULL && (error = git_commit_tree(&tree, parent)) < 0) | |
513 | ##### | 6 | goto cleanup; | |
514 | - | |||
515 | 55 | 7 | error = note_write(notes_commit_out, notes_blob_out, repo, author, | |
516 | - | committer, NULL, note, tree, target, &parent, allow_note_overwrite); | ||
517 | - | |||
518 | 55 | 8 | if (error < 0) | |
519 | 2 | 9 | goto cleanup; | |
520 | - | |||
521 | - | cleanup: | ||
522 | 55 | 10 | git_tree_free(tree); | |
523 | 55 | 11 | return error; | |
524 | - | } | ||
525 | - | |||
526 | 47 | 2 | int git_note_create( | |
527 | - | git_oid *out, | ||
528 | - | git_repository *repo, | ||
529 | - | const char *notes_ref_in, | ||
530 | - | const git_signature *author, | ||
531 | - | const git_signature *committer, | ||
532 | - | const git_oid *oid, | ||
533 | - | const char *note, | ||
534 | - | int allow_note_overwrite) | ||
535 | - | { | ||
536 | - | int error; | ||
537 | 47 | 2 | char *notes_ref = NULL; | |
538 | 47 | 2 | git_commit *existing_notes_commit = NULL; | |
539 | 47 | 2 | git_reference *ref = NULL; | |
540 | - | git_oid notes_blob_oid, notes_commit_oid; | ||
541 | - | |||
542 | 47 | 2 | error = retrieve_note_commit(&existing_notes_commit, ¬es_ref, | |
543 | - | repo, notes_ref_in); | ||
544 | - | |||
545 | 47 | 3,4 | if (error < 0 && error != GIT_ENOTFOUND) | |
546 | ##### | 5 | goto cleanup; | |
547 | - | |||
548 | 47 | 6 | error = git_note_commit_create(¬es_commit_oid, | |
549 | - | ¬es_blob_oid, | ||
550 | - | repo, existing_notes_commit, author, | ||
551 | - | committer, oid, note, | ||
552 | - | allow_note_overwrite); | ||
553 | 47 | 7 | if (error < 0) | |
554 | 2 | 8 | goto cleanup; | |
555 | - | |||
556 | 45 | 9 | error = git_reference_create(&ref, repo, notes_ref, | |
557 | - | ¬es_commit_oid, 1, NULL); | ||
558 | - | |||
559 | 45 | 10 | if (out != NULL) | |
560 | 45 | 11 | git_oid_cpy(out, ¬es_blob_oid); | |
561 | - | |||
562 | - | cleanup: | ||
563 | 47 | 12 | git__free(notes_ref); | |
564 | 47 | 13 | git_commit_free(existing_notes_commit); | |
565 | 47 | 14 | git_reference_free(ref); | |
566 | 47 | 15 | return error; | |
567 | - | } | ||
568 | - | |||
569 | 6 | 2 | int git_note_commit_remove( | |
570 | - | git_oid *notes_commit_out, | ||
571 | - | git_repository *repo, | ||
572 | - | git_commit *notes_commit, | ||
573 | - | const git_signature *author, | ||
574 | - | const git_signature *committer, | ||
575 | - | const git_oid *oid) | ||
576 | - | { | ||
577 | - | int error; | ||
578 | 6 | 2 | git_tree *tree = NULL; | |
579 | - | char target[GIT_OID_HEXSZ + 1]; | ||
580 | - | |||
581 | 6 | 2 | git_oid_tostr(target, sizeof(target), oid); | |
582 | - | |||
583 | 6 | 3,4 | if ((error = git_commit_tree(&tree, notes_commit)) < 0) | |
584 | ##### | 5 | goto cleanup; | |
585 | - | |||
586 | 6 | 6 | error = note_remove(notes_commit_out, | |
587 | - | repo, author, committer, NULL, tree, target, ¬es_commit); | ||
588 | - | |||
589 | - | cleanup: | ||
590 | 6 | 7 | git_tree_free(tree); | |
591 | 6 | 8 | return error; | |
592 | - | } | ||
593 | - | |||
594 | 4 | 2 | int git_note_remove(git_repository *repo, const char *notes_ref_in, | |
595 | - | const git_signature *author, const git_signature *committer, | ||
596 | - | const git_oid *oid) | ||
597 | - | { | ||
598 | - | int error; | ||
599 | 4 | 2 | char *notes_ref_target = NULL; | |
600 | 4 | 2 | git_commit *existing_notes_commit = NULL; | |
601 | - | git_oid new_notes_commit; | ||
602 | 4 | 2 | git_reference *notes_ref = NULL; | |
603 | - | |||
604 | 4 | 2 | error = retrieve_note_commit(&existing_notes_commit, ¬es_ref_target, | |
605 | - | repo, notes_ref_in); | ||
606 | - | |||
607 | 4 | 3 | if (error < 0) | |
608 | ##### | 4 | goto cleanup; | |
609 | - | |||
610 | 4 | 5 | error = git_note_commit_remove(&new_notes_commit, repo, | |
611 | - | existing_notes_commit, author, committer, oid); | ||
612 | 4 | 6 | if (error < 0) | |
613 | 1 | 7 | goto cleanup; | |
614 | - | |||
615 | 3 | 8 | error = git_reference_create(¬es_ref, repo, notes_ref_target, | |
616 | - | &new_notes_commit, 1, NULL); | ||
617 | - | |||
618 | - | cleanup: | ||
619 | 4 | 9 | git__free(notes_ref_target); | |
620 | 4 | 10 | git_reference_free(notes_ref); | |
621 | 4 | 11 | git_commit_free(existing_notes_commit); | |
622 | 4 | 12 | return error; | |
623 | - | } | ||
624 | - | |||
625 | 3 | 2 | int git_note_default_ref(git_buf *out, git_repository *repo) | |
626 | - | { | ||
627 | - | char *default_ref; | ||
628 | - | int error; | ||
629 | - | |||
630 | 3 | 2-4 | assert(out && repo); | |
631 | - | |||
632 | 3 | 5 | git_buf_sanitize(out); | |
633 | - | |||
634 | 3 | 6,7 | if ((error = note_get_default_ref(&default_ref, repo)) < 0) | |
635 | ##### | 8 | return error; | |
636 | - | |||
637 | 3 | 9 | git_buf_attach(out, default_ref, strlen(default_ref)); | |
638 | 3 | 10 | return 0; | |
639 | - | } | ||
640 | - | |||
641 | ##### | 2 | const git_signature *git_note_committer(const git_note *note) | |
642 | - | { | ||
643 | ##### | 2,3 | assert(note); | |
644 | ##### | 4 | return note->committer; | |
645 | - | } | ||
646 | - | |||
647 | 2 | 2 | const git_signature *git_note_author(const git_note *note) | |
648 | - | { | ||
649 | 2 | 2,3 | assert(note); | |
650 | 2 | 4 | return note->author; | |
651 | - | } | ||
652 | - | |||
653 | 24 | 2 | const char * git_note_message(const git_note *note) | |
654 | - | { | ||
655 | 24 | 2,3 | assert(note); | |
656 | 24 | 4 | return note->message; | |
657 | - | } | ||
658 | - | |||
659 | 8 | 2 | const git_oid * git_note_id(const git_note *note) | |
660 | - | { | ||
661 | 8 | 2,3 | assert(note); | |
662 | 8 | 4 | return ¬e->id; | |
663 | - | } | ||
664 | - | |||
665 | 38 | 2 | void git_note_free(git_note *note) | |
666 | - | { | ||
667 | 38 | 2 | if (note == NULL) | |
668 | 38 | 3,8 | return; | |
669 | - | |||
670 | 35 | 4 | git_signature_free(note->committer); | |
671 | 35 | 5 | git_signature_free(note->author); | |
672 | 35 | 6 | git__free(note->message); | |
673 | 35 | 7 | git__free(note); | |
674 | - | } | ||
675 | - | |||
676 | 17 | 2 | static int process_entry_path( | |
677 | - | const char* entry_path, | ||
678 | - | git_oid *annotated_object_id) | ||
679 | - | { | ||
680 | 17 | 2 | int error = 0; | |
681 | 17 | 2 | size_t i = 0, j = 0, len; | |
682 | 17 | 2 | git_buf buf = GIT_BUF_INIT; | |
683 | - | |||
684 | 17 | 2,3 | if ((error = git_buf_puts(&buf, entry_path)) < 0) | |
685 | ##### | 4 | goto cleanup; | |
686 | - | |||
687 | 17 | 5 | len = git_buf_len(&buf); | |
688 | - | |||
689 | 697 | 6,15 | while (i < len) { | |
690 | 680 | 7 | if (buf.ptr[i] == '/') { | |
691 | ##### | 8 | i++; | |
692 | ##### | 8 | continue; | |
693 | - | } | ||
694 | - | |||
695 | 680 | 9,10 | if (git__fromhex(buf.ptr[i]) < 0) { | |
696 | - | /* This is not a note entry */ | ||
697 | ##### | 11 | goto cleanup; | |
698 | - | } | ||
699 | - | |||
700 | 680 | 12 | if (i != j) | |
701 | ##### | 13 | buf.ptr[j] = buf.ptr[i]; | |
702 | - | |||
703 | 680 | 14 | i++; | |
704 | 680 | 14 | j++; | |
705 | - | } | ||
706 | - | |||
707 | 17 | 16 | buf.ptr[j] = '\0'; | |
708 | 17 | 16 | buf.size = j; | |
709 | - | |||
710 | 17 | 16 | if (j != GIT_OID_HEXSZ) { | |
711 | - | /* This is not a note entry */ | ||
712 | ##### | 17 | goto cleanup; | |
713 | - | } | ||
714 | - | |||
715 | 17 | 18 | error = git_oid_fromstr(annotated_object_id, buf.ptr); | |
716 | - | |||
717 | - | cleanup: | ||
718 | 17 | 19 | git_buf_dispose(&buf); | |
719 | 17 | 20 | return error; | |
720 | - | } | ||
721 | - | |||
722 | 6 | 2 | int git_note_foreach( | |
723 | - | git_repository *repo, | ||
724 | - | const char *notes_ref, | ||
725 | - | git_note_foreach_cb note_cb, | ||
726 | - | void *payload) | ||
727 | - | { | ||
728 | - | int error; | ||
729 | 6 | 2 | git_note_iterator *iter = NULL; | |
730 | - | git_oid note_id, annotated_id; | ||
731 | - | |||
732 | 6 | 2,3 | if ((error = git_note_iterator_new(&iter, repo, notes_ref)) < 0) | |
733 | 1 | 4 | return error; | |
734 | - | |||
735 | 15 | 5,10,11 | while (!(error = git_note_next(¬e_id, &annotated_id, iter))) { | |
736 | 11 | 6,7 | if ((error = note_cb(¬e_id, &annotated_id, payload)) != 0) { | |
737 | 1 | 8 | git_error_set_after_callback(error); | |
738 | 1 | 9 | break; | |
739 | - | } | ||
740 | - | } | ||
741 | - | |||
742 | 5 | 12 | if (error == GIT_ITEROVER) | |
743 | 4 | 13 | error = 0; | |
744 | - | |||
745 | 5 | 14 | git_note_iterator_free(iter); | |
746 | 5 | 15 | return error; | |
747 | - | } | ||
748 | - | |||
749 | 8 | 2 | void git_note_iterator_free(git_note_iterator *it) | |
750 | - | { | ||
751 | 8 | 2 | if (it == NULL) | |
752 | 8 | 3,5 | return; | |
753 | - | |||
754 | 8 | 4 | git_iterator_free(it); | |
755 | - | } | ||
756 | - | |||
757 | 8 | 2 | int git_note_commit_iterator_new( | |
758 | - | git_note_iterator **it, | ||
759 | - | git_commit *notes_commit) | ||
760 | - | { | ||
761 | - | int error; | ||
762 | - | git_tree *tree; | ||
763 | - | |||
764 | 8 | 2,3 | if ((error = git_commit_tree(&tree, notes_commit)) < 0) | |
765 | ##### | 4 | goto cleanup; | |
766 | - | |||
767 | 8 | 5,6 | if ((error = git_iterator_for_tree(it, tree, NULL)) < 0) | |
768 | ##### | 7 | git_iterator_free(*it); | |
769 | - | |||
770 | - | cleanup: | ||
771 | 8 | 8 | git_tree_free(tree); | |
772 | - | |||
773 | 8 | 9 | return error; | |
774 | - | } | ||
775 | - | |||
776 | 9 | 2 | int git_note_iterator_new( | |
777 | - | git_note_iterator **it, | ||
778 | - | git_repository *repo, | ||
779 | - | const char *notes_ref_in) | ||
780 | - | { | ||
781 | - | int error; | ||
782 | 9 | 2 | git_commit *commit = NULL; | |
783 | - | char *notes_ref; | ||
784 | - | |||
785 | 9 | 2 | error = retrieve_note_commit(&commit, ¬es_ref, repo, notes_ref_in); | |
786 | 9 | 3 | if (error < 0) | |
787 | 2 | 4 | goto cleanup; | |
788 | - | |||
789 | 7 | 5 | error = git_note_commit_iterator_new(it, commit); | |
790 | - | |||
791 | - | cleanup: | ||
792 | 9 | 6 | git__free(notes_ref); | |
793 | 9 | 7 | git_commit_free(commit); | |
794 | - | |||
795 | 9 | 8 | return error; | |
796 | - | } | ||
797 | - | |||
798 | 24 | 2 | int git_note_next( | |
799 | - | git_oid* note_id, | ||
800 | - | git_oid* annotated_id, | ||
801 | - | git_note_iterator *it) | ||
802 | - | { | ||
803 | - | int error; | ||
804 | - | const git_index_entry *item; | ||
805 | - | |||
806 | 24 | 2,3 | if ((error = git_iterator_current(&item, it)) < 0) | |
807 | 7 | 4 | return error; | |
808 | - | |||
809 | 17 | 5 | git_oid_cpy(note_id, &item->id); | |
810 | - | |||
811 | 17 | 6,7 | if ((error = process_entry_path(item->path, annotated_id)) < 0) | |
812 | ##### | 8 | return error; | |
813 | - | |||
814 | 17 | 9-11 | if ((error = git_iterator_advance(NULL, it)) < 0 && error != GIT_ITEROVER) | |
815 | ##### | 12 | return error; | |
816 | - | |||
817 | 17 | 13 | return 0; | |
818 | - | } |