]>
git.proxmox.com Git - libgit2.git/blob - src/tag.c
b4a5015dfb7529446638c3351311bc26752f6658
2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
11 #include "signature.h"
13 #include "git2/object.h"
14 #include "git2/repository.h"
15 #include "git2/signature.h"
16 #include "git2/odb_backend.h"
18 void git_tag__free(void *_tag
)
21 git_signature_free(tag
->tagger
);
22 git__free(tag
->message
);
23 git__free(tag
->tag_name
);
27 int git_tag_target(git_object
**target
, const git_tag
*t
)
30 return git_object_lookup(target
, t
->object
.repo
, &t
->target
, t
->type
);
33 const git_oid
*git_tag_target_id(const git_tag
*t
)
39 git_object_t
git_tag_target_type(const git_tag
*t
)
45 const char *git_tag_name(const git_tag
*t
)
51 const git_signature
*git_tag_tagger(const git_tag
*t
)
56 const char *git_tag_message(const git_tag
*t
)
62 static int tag_error(const char *str
)
64 git_error_set(GIT_ERROR_TAG
, "failed to parse tag: %s", str
);
68 static int tag_parse(git_tag
*tag
, const char *buffer
, const char *buffer_end
)
70 static const char *tag_types
[] = {
71 NULL
, "commit\n", "tree\n", "blob\n", "tag\n"
73 size_t text_len
, alloc_len
;
77 if (git_oid__parse(&tag
->target
, &buffer
, buffer_end
, "object ") < 0)
78 return tag_error("object field invalid");
80 if (buffer
+ 5 >= buffer_end
)
81 return tag_error("object too short");
83 if (memcmp(buffer
, "type ", 5) != 0)
84 return tag_error("type field not found");
87 tag
->type
= GIT_OBJECT_INVALID
;
89 for (i
= 1; i
< ARRAY_SIZE(tag_types
); ++i
) {
90 size_t type_length
= strlen(tag_types
[i
]);
92 if (buffer
+ type_length
>= buffer_end
)
93 return tag_error("object too short");
95 if (memcmp(buffer
, tag_types
[i
], type_length
) == 0) {
97 buffer
+= type_length
;
102 if (tag
->type
== GIT_OBJECT_INVALID
)
103 return tag_error("invalid object type");
105 if (buffer
+ 4 >= buffer_end
)
106 return tag_error("object too short");
108 if (memcmp(buffer
, "tag ", 4) != 0)
109 return tag_error("tag field not found");
113 search
= memchr(buffer
, '\n', buffer_end
- buffer
);
115 return tag_error("object too short");
117 text_len
= search
- buffer
;
119 GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len
, text_len
, 1);
120 tag
->tag_name
= git__malloc(alloc_len
);
121 GIT_ERROR_CHECK_ALLOC(tag
->tag_name
);
123 memcpy(tag
->tag_name
, buffer
, text_len
);
124 tag
->tag_name
[text_len
] = '\0';
129 if (buffer
< buffer_end
&& *buffer
!= '\n') {
130 tag
->tagger
= git__malloc(sizeof(git_signature
));
131 GIT_ERROR_CHECK_ALLOC(tag
->tagger
);
133 if (git_signature__parse(tag
->tagger
, &buffer
, buffer_end
, "tagger ", '\n') < 0)
138 if (buffer
< buffer_end
) {
139 /* If we're not at the end of the header, search for it */
140 if(*buffer
!= '\n') {
141 search
= git__memmem(buffer
, buffer_end
- buffer
,
146 return tag_error("tag contains no message");
149 text_len
= buffer_end
- ++buffer
;
151 GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len
, text_len
, 1);
152 tag
->message
= git__malloc(alloc_len
);
153 GIT_ERROR_CHECK_ALLOC(tag
->message
);
155 memcpy(tag
->message
, buffer
, text_len
);
156 tag
->message
[text_len
] = '\0';
162 int git_tag__parse_raw(void *_tag
, const char *data
, size_t size
)
164 return tag_parse(_tag
, data
, data
+ size
);
167 int git_tag__parse(void *_tag
, git_odb_object
*odb_obj
)
170 const char *buffer
= git_odb_object_data(odb_obj
);
171 const char *buffer_end
= buffer
+ git_odb_object_size(odb_obj
);
173 return tag_parse(tag
, buffer
, buffer_end
);
176 static int retrieve_tag_reference(
177 git_reference
**tag_reference_out
,
178 git_buf
*ref_name_out
,
179 git_repository
*repo
,
180 const char *tag_name
)
182 git_reference
*tag_ref
;
185 *tag_reference_out
= NULL
;
187 if (git_buf_joinpath(ref_name_out
, GIT_REFS_TAGS_DIR
, tag_name
) < 0)
190 error
= git_reference_lookup(&tag_ref
, repo
, ref_name_out
->ptr
);
192 return error
; /* Be it not foundo or corrupted */
194 *tag_reference_out
= tag_ref
;
199 static int retrieve_tag_reference_oid(
201 git_buf
*ref_name_out
,
202 git_repository
*repo
,
203 const char *tag_name
)
205 if (git_buf_joinpath(ref_name_out
, GIT_REFS_TAGS_DIR
, tag_name
) < 0)
208 return git_reference_name_to_id(oid
, repo
, ref_name_out
->ptr
);
211 static int write_tag_annotation(
213 git_repository
*repo
,
214 const char *tag_name
,
215 const git_object
*target
,
216 const git_signature
*tagger
,
219 git_buf tag
= GIT_BUF_INIT
;
222 git_oid__writebuf(&tag
, "object ", git_object_id(target
));
223 git_buf_printf(&tag
, "type %s\n", git_object_type2string(git_object_type(target
)));
224 git_buf_printf(&tag
, "tag %s\n", tag_name
);
225 git_signature__writebuf(&tag
, "tagger ", tagger
);
226 git_buf_putc(&tag
, '\n');
228 if (git_buf_puts(&tag
, message
) < 0)
231 if (git_repository_odb__weakptr(&odb
, repo
) < 0)
234 if (git_odb_write(oid
, odb
, tag
.ptr
, tag
.size
, GIT_OBJECT_TAG
) < 0)
237 git_buf_dispose(&tag
);
241 git_buf_dispose(&tag
);
242 git_error_set(GIT_ERROR_OBJECT
, "failed to create tag annotation");
246 static int git_tag_create__internal(
248 git_repository
*repo
,
249 const char *tag_name
,
250 const git_object
*target
,
251 const git_signature
*tagger
,
253 int allow_ref_overwrite
,
254 int create_tag_annotation
)
256 git_reference
*new_ref
= NULL
;
257 git_buf ref_name
= GIT_BUF_INIT
;
261 assert(repo
&& tag_name
&& target
);
262 assert(!create_tag_annotation
|| (tagger
&& message
));
264 if (git_object_owner(target
) != repo
) {
265 git_error_set(GIT_ERROR_INVALID
, "the given target does not belong to this repository");
269 error
= retrieve_tag_reference_oid(oid
, &ref_name
, repo
, tag_name
);
270 if (error
< 0 && error
!= GIT_ENOTFOUND
)
273 /** Ensure the tag name doesn't conflict with an already existing
274 * reference unless overwriting has explicitly been requested **/
275 if (error
== 0 && !allow_ref_overwrite
) {
276 git_buf_dispose(&ref_name
);
277 git_error_set(GIT_ERROR_TAG
, "tag already exists");
281 if (create_tag_annotation
) {
282 if (write_tag_annotation(oid
, repo
, tag_name
, target
, tagger
, message
) < 0)
285 git_oid_cpy(oid
, git_object_id(target
));
287 error
= git_reference_create(&new_ref
, repo
, ref_name
.ptr
, oid
, allow_ref_overwrite
, NULL
);
290 git_reference_free(new_ref
);
291 git_buf_dispose(&ref_name
);
297 git_repository
*repo
,
298 const char *tag_name
,
299 const git_object
*target
,
300 const git_signature
*tagger
,
302 int allow_ref_overwrite
)
304 return git_tag_create__internal(oid
, repo
, tag_name
, target
, tagger
, message
, allow_ref_overwrite
, 1);
307 int git_tag_annotation_create(
309 git_repository
*repo
,
310 const char *tag_name
,
311 const git_object
*target
,
312 const git_signature
*tagger
,
315 assert(oid
&& repo
&& tag_name
&& target
&& tagger
&& message
);
317 return write_tag_annotation(oid
, repo
, tag_name
, target
, tagger
, message
);
320 int git_tag_create_lightweight(
322 git_repository
*repo
,
323 const char *tag_name
,
324 const git_object
*target
,
325 int allow_ref_overwrite
)
327 return git_tag_create__internal(oid
, repo
, tag_name
, target
, NULL
, NULL
, allow_ref_overwrite
, 0);
330 int git_tag_create_frombuffer(git_oid
*oid
, git_repository
*repo
, const char *buffer
, int allow_ref_overwrite
)
335 git_odb_stream
*stream
;
336 git_odb_object
*target_obj
;
338 git_reference
*new_ref
= NULL
;
339 git_buf ref_name
= GIT_BUF_INIT
;
341 assert(oid
&& buffer
);
343 memset(&tag
, 0, sizeof(tag
));
345 if (git_repository_odb__weakptr(&odb
, repo
) < 0)
348 /* validate the buffer */
349 if (tag_parse(&tag
, buffer
, buffer
+ strlen(buffer
)) < 0)
352 /* validate the target */
353 if (git_odb_read(&target_obj
, odb
, &tag
.target
) < 0)
356 if (tag
.type
!= target_obj
->cached
.type
) {
357 git_error_set(GIT_ERROR_TAG
, "the type for the given target is invalid");
361 error
= retrieve_tag_reference_oid(oid
, &ref_name
, repo
, tag
.tag_name
);
362 if (error
< 0 && error
!= GIT_ENOTFOUND
)
365 /* We don't need these objects after this */
366 git_signature_free(tag
.tagger
);
367 git__free(tag
.tag_name
);
368 git__free(tag
.message
);
369 git_odb_object_free(target_obj
);
371 /** Ensure the tag name doesn't conflict with an already existing
372 * reference unless overwriting has explicitly been requested **/
373 if (error
== 0 && !allow_ref_overwrite
) {
374 git_error_set(GIT_ERROR_TAG
, "tag already exists");
378 /* write the buffer */
379 if ((error
= git_odb_open_wstream(
380 &stream
, odb
, strlen(buffer
), GIT_OBJECT_TAG
)) < 0)
383 if (!(error
= git_odb_stream_write(stream
, buffer
, strlen(buffer
))))
384 error
= git_odb_stream_finalize_write(oid
, stream
);
386 git_odb_stream_free(stream
);
389 git_buf_dispose(&ref_name
);
393 error
= git_reference_create(
394 &new_ref
, repo
, ref_name
.ptr
, oid
, allow_ref_overwrite
, NULL
);
396 git_reference_free(new_ref
);
397 git_buf_dispose(&ref_name
);
402 git_signature_free(tag
.tagger
);
403 git__free(tag
.tag_name
);
404 git__free(tag
.message
);
405 git_odb_object_free(target_obj
);
409 int git_tag_delete(git_repository
*repo
, const char *tag_name
)
411 git_reference
*tag_ref
;
412 git_buf ref_name
= GIT_BUF_INIT
;
415 error
= retrieve_tag_reference(&tag_ref
, &ref_name
, repo
, tag_name
);
417 git_buf_dispose(&ref_name
);
422 error
= git_reference_delete(tag_ref
);
424 git_reference_free(tag_ref
);
430 git_repository
*repo
;
431 git_tag_foreach_cb cb
;
435 static int tags_cb(const char *ref
, void *data
)
439 tag_cb_data
*d
= (tag_cb_data
*)data
;
441 if (git__prefixcmp(ref
, GIT_REFS_TAGS_DIR
) != 0)
442 return 0; /* no tag */
444 if (!(error
= git_reference_name_to_id(&oid
, d
->repo
, ref
))) {
445 if ((error
= d
->cb(ref
, &oid
, d
->cb_data
)) != 0)
446 git_error_set_after_callback_function(error
, "git_tag_foreach");
452 int git_tag_foreach(git_repository
*repo
, git_tag_foreach_cb cb
, void *cb_data
)
459 data
.cb_data
= cb_data
;
462 return git_reference_foreach_name(repo
, &tags_cb
, &data
);
470 #define GIT_REFS_TAGS_DIR_LEN strlen(GIT_REFS_TAGS_DIR)
472 static int tag_list_cb(const char *tag_name
, git_oid
*oid
, void *data
)
474 tag_filter_data
*filter
= (tag_filter_data
*)data
;
477 if (!*filter
->pattern
||
478 p_fnmatch(filter
->pattern
, tag_name
+ GIT_REFS_TAGS_DIR_LEN
, 0) == 0)
480 char *matched
= git__strdup(tag_name
+ GIT_REFS_TAGS_DIR_LEN
);
481 GIT_ERROR_CHECK_ALLOC(matched
);
483 return git_vector_insert(filter
->taglist
, matched
);
489 int git_tag_list_match(git_strarray
*tag_names
, const char *pattern
, git_repository
*repo
)
492 tag_filter_data filter
;
495 assert(tag_names
&& repo
&& pattern
);
497 if ((error
= git_vector_init(&taglist
, 8, NULL
)) < 0)
500 filter
.taglist
= &taglist
;
501 filter
.pattern
= pattern
;
503 error
= git_tag_foreach(repo
, &tag_list_cb
, (void *)&filter
);
506 git_vector_free(&taglist
);
509 (char **)git_vector_detach(&tag_names
->count
, NULL
, &taglist
);
514 int git_tag_list(git_strarray
*tag_names
, git_repository
*repo
)
516 return git_tag_list_match(tag_names
, "", repo
);
519 int git_tag_peel(git_object
**tag_target
, const git_tag
*tag
)
521 return git_object_peel(tag_target
, (const git_object
*)tag
, GIT_OBJECT_ANY
);