]>
git.proxmox.com Git - libgit2.git/blob - src/tag.c
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 "wildmatch.h"
14 #include "git2/object.h"
15 #include "git2/repository.h"
16 #include "git2/signature.h"
17 #include "git2/odb_backend.h"
19 void git_tag__free(void *_tag
)
22 git_signature_free(tag
->tagger
);
23 git__free(tag
->message
);
24 git__free(tag
->tag_name
);
28 int git_tag_target(git_object
**target
, const git_tag
*t
)
31 return git_object_lookup(target
, t
->object
.repo
, &t
->target
, t
->type
);
34 const git_oid
*git_tag_target_id(const git_tag
*t
)
40 git_object_t
git_tag_target_type(const git_tag
*t
)
46 const char *git_tag_name(const git_tag
*t
)
52 const git_signature
*git_tag_tagger(const git_tag
*t
)
57 const char *git_tag_message(const git_tag
*t
)
63 static int tag_error(const char *str
)
65 git_error_set(GIT_ERROR_TAG
, "failed to parse tag: %s", str
);
69 static int tag_parse(git_tag
*tag
, const char *buffer
, const char *buffer_end
)
71 static const char *tag_types
[] = {
72 NULL
, "commit\n", "tree\n", "blob\n", "tag\n"
74 size_t text_len
, alloc_len
;
78 if (git_oid__parse(&tag
->target
, &buffer
, buffer_end
, "object ") < 0)
79 return tag_error("object field invalid");
81 if (buffer
+ 5 >= buffer_end
)
82 return tag_error("object too short");
84 if (memcmp(buffer
, "type ", 5) != 0)
85 return tag_error("type field not found");
88 tag
->type
= GIT_OBJECT_INVALID
;
90 for (i
= 1; i
< ARRAY_SIZE(tag_types
); ++i
) {
91 size_t type_length
= strlen(tag_types
[i
]);
93 if (buffer
+ type_length
>= buffer_end
)
94 return tag_error("object too short");
96 if (memcmp(buffer
, tag_types
[i
], type_length
) == 0) {
98 buffer
+= type_length
;
103 if (tag
->type
== GIT_OBJECT_INVALID
)
104 return tag_error("invalid object type");
106 if (buffer
+ 4 >= buffer_end
)
107 return tag_error("object too short");
109 if (memcmp(buffer
, "tag ", 4) != 0)
110 return tag_error("tag field not found");
114 search
= memchr(buffer
, '\n', buffer_end
- buffer
);
116 return tag_error("object too short");
118 text_len
= search
- buffer
;
120 GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len
, text_len
, 1);
121 tag
->tag_name
= git__malloc(alloc_len
);
122 GIT_ERROR_CHECK_ALLOC(tag
->tag_name
);
124 memcpy(tag
->tag_name
, buffer
, text_len
);
125 tag
->tag_name
[text_len
] = '\0';
130 if (buffer
< buffer_end
&& *buffer
!= '\n') {
131 tag
->tagger
= git__malloc(sizeof(git_signature
));
132 GIT_ERROR_CHECK_ALLOC(tag
->tagger
);
134 if (git_signature__parse(tag
->tagger
, &buffer
, buffer_end
, "tagger ", '\n') < 0)
139 if (buffer
< buffer_end
) {
140 /* If we're not at the end of the header, search for it */
141 if(*buffer
!= '\n') {
142 search
= git__memmem(buffer
, buffer_end
- buffer
,
147 return tag_error("tag contains no message");
150 text_len
= buffer_end
- ++buffer
;
152 GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len
, text_len
, 1);
153 tag
->message
= git__malloc(alloc_len
);
154 GIT_ERROR_CHECK_ALLOC(tag
->message
);
156 memcpy(tag
->message
, buffer
, text_len
);
157 tag
->message
[text_len
] = '\0';
163 int git_tag__parse_raw(void *_tag
, const char *data
, size_t size
)
165 return tag_parse(_tag
, data
, data
+ size
);
168 int git_tag__parse(void *_tag
, git_odb_object
*odb_obj
)
171 const char *buffer
= git_odb_object_data(odb_obj
);
172 const char *buffer_end
= buffer
+ git_odb_object_size(odb_obj
);
174 return tag_parse(tag
, buffer
, buffer_end
);
177 static int retrieve_tag_reference(
178 git_reference
**tag_reference_out
,
179 git_buf
*ref_name_out
,
180 git_repository
*repo
,
181 const char *tag_name
)
183 git_reference
*tag_ref
;
186 *tag_reference_out
= NULL
;
188 if (git_buf_joinpath(ref_name_out
, GIT_REFS_TAGS_DIR
, tag_name
) < 0)
191 error
= git_reference_lookup(&tag_ref
, repo
, ref_name_out
->ptr
);
193 return error
; /* Be it not foundo or corrupted */
195 *tag_reference_out
= tag_ref
;
200 static int retrieve_tag_reference_oid(
202 git_buf
*ref_name_out
,
203 git_repository
*repo
,
204 const char *tag_name
)
206 if (git_buf_joinpath(ref_name_out
, GIT_REFS_TAGS_DIR
, tag_name
) < 0)
209 return git_reference_name_to_id(oid
, repo
, ref_name_out
->ptr
);
212 static int write_tag_annotation(
214 git_repository
*repo
,
215 const char *tag_name
,
216 const git_object
*target
,
217 const git_signature
*tagger
,
220 git_buf tag
= GIT_BUF_INIT
;
223 git_oid__writebuf(&tag
, "object ", git_object_id(target
));
224 git_buf_printf(&tag
, "type %s\n", git_object_type2string(git_object_type(target
)));
225 git_buf_printf(&tag
, "tag %s\n", tag_name
);
226 git_signature__writebuf(&tag
, "tagger ", tagger
);
227 git_buf_putc(&tag
, '\n');
229 if (git_buf_puts(&tag
, message
) < 0)
232 if (git_repository_odb__weakptr(&odb
, repo
) < 0)
235 if (git_odb_write(oid
, odb
, tag
.ptr
, tag
.size
, GIT_OBJECT_TAG
) < 0)
238 git_buf_dispose(&tag
);
242 git_buf_dispose(&tag
);
243 git_error_set(GIT_ERROR_OBJECT
, "failed to create tag annotation");
247 static int git_tag_create__internal(
249 git_repository
*repo
,
250 const char *tag_name
,
251 const git_object
*target
,
252 const git_signature
*tagger
,
254 int allow_ref_overwrite
,
255 int create_tag_annotation
)
257 git_reference
*new_ref
= NULL
;
258 git_buf ref_name
= GIT_BUF_INIT
;
262 assert(repo
&& tag_name
&& target
);
263 assert(!create_tag_annotation
|| (tagger
&& message
));
265 if (git_object_owner(target
) != repo
) {
266 git_error_set(GIT_ERROR_INVALID
, "the given target does not belong to this repository");
270 error
= retrieve_tag_reference_oid(oid
, &ref_name
, repo
, tag_name
);
271 if (error
< 0 && error
!= GIT_ENOTFOUND
)
274 /** Ensure the tag name doesn't conflict with an already existing
275 * reference unless overwriting has explicitly been requested **/
276 if (error
== 0 && !allow_ref_overwrite
) {
277 git_buf_dispose(&ref_name
);
278 git_error_set(GIT_ERROR_TAG
, "tag already exists");
282 if (create_tag_annotation
) {
283 if (write_tag_annotation(oid
, repo
, tag_name
, target
, tagger
, message
) < 0)
286 git_oid_cpy(oid
, git_object_id(target
));
288 error
= git_reference_create(&new_ref
, repo
, ref_name
.ptr
, oid
, allow_ref_overwrite
, NULL
);
291 git_reference_free(new_ref
);
292 git_buf_dispose(&ref_name
);
298 git_repository
*repo
,
299 const char *tag_name
,
300 const git_object
*target
,
301 const git_signature
*tagger
,
303 int allow_ref_overwrite
)
305 return git_tag_create__internal(oid
, repo
, tag_name
, target
, tagger
, message
, allow_ref_overwrite
, 1);
308 int git_tag_annotation_create(
310 git_repository
*repo
,
311 const char *tag_name
,
312 const git_object
*target
,
313 const git_signature
*tagger
,
316 assert(oid
&& repo
&& tag_name
&& target
&& tagger
&& message
);
318 return write_tag_annotation(oid
, repo
, tag_name
, target
, tagger
, message
);
321 int git_tag_create_lightweight(
323 git_repository
*repo
,
324 const char *tag_name
,
325 const git_object
*target
,
326 int allow_ref_overwrite
)
328 return git_tag_create__internal(oid
, repo
, tag_name
, target
, NULL
, NULL
, allow_ref_overwrite
, 0);
331 int git_tag_create_from_buffer(git_oid
*oid
, git_repository
*repo
, const char *buffer
, int allow_ref_overwrite
)
336 git_odb_stream
*stream
;
337 git_odb_object
*target_obj
;
339 git_reference
*new_ref
= NULL
;
340 git_buf ref_name
= GIT_BUF_INIT
;
342 assert(oid
&& buffer
);
344 memset(&tag
, 0, sizeof(tag
));
346 if (git_repository_odb__weakptr(&odb
, repo
) < 0)
349 /* validate the buffer */
350 if (tag_parse(&tag
, buffer
, buffer
+ strlen(buffer
)) < 0)
353 /* validate the target */
354 if (git_odb_read(&target_obj
, odb
, &tag
.target
) < 0)
357 if (tag
.type
!= target_obj
->cached
.type
) {
358 git_error_set(GIT_ERROR_TAG
, "the type for the given target is invalid");
362 error
= retrieve_tag_reference_oid(oid
, &ref_name
, repo
, tag
.tag_name
);
363 if (error
< 0 && error
!= GIT_ENOTFOUND
)
366 /* We don't need these objects after this */
367 git_signature_free(tag
.tagger
);
368 git__free(tag
.tag_name
);
369 git__free(tag
.message
);
370 git_odb_object_free(target_obj
);
372 /** Ensure the tag name doesn't conflict with an already existing
373 * reference unless overwriting has explicitly been requested **/
374 if (error
== 0 && !allow_ref_overwrite
) {
375 git_error_set(GIT_ERROR_TAG
, "tag already exists");
379 /* write the buffer */
380 if ((error
= git_odb_open_wstream(
381 &stream
, odb
, strlen(buffer
), GIT_OBJECT_TAG
)) < 0)
384 if (!(error
= git_odb_stream_write(stream
, buffer
, strlen(buffer
))))
385 error
= git_odb_stream_finalize_write(oid
, stream
);
387 git_odb_stream_free(stream
);
390 git_buf_dispose(&ref_name
);
394 error
= git_reference_create(
395 &new_ref
, repo
, ref_name
.ptr
, oid
, allow_ref_overwrite
, NULL
);
397 git_reference_free(new_ref
);
398 git_buf_dispose(&ref_name
);
403 git_signature_free(tag
.tagger
);
404 git__free(tag
.tag_name
);
405 git__free(tag
.message
);
406 git_odb_object_free(target_obj
);
410 int git_tag_delete(git_repository
*repo
, const char *tag_name
)
412 git_reference
*tag_ref
;
413 git_buf ref_name
= GIT_BUF_INIT
;
416 error
= retrieve_tag_reference(&tag_ref
, &ref_name
, repo
, tag_name
);
418 git_buf_dispose(&ref_name
);
423 error
= git_reference_delete(tag_ref
);
425 git_reference_free(tag_ref
);
431 git_repository
*repo
;
432 git_tag_foreach_cb cb
;
436 static int tags_cb(const char *ref
, void *data
)
440 tag_cb_data
*d
= (tag_cb_data
*)data
;
442 if (git__prefixcmp(ref
, GIT_REFS_TAGS_DIR
) != 0)
443 return 0; /* no tag */
445 if (!(error
= git_reference_name_to_id(&oid
, d
->repo
, ref
))) {
446 if ((error
= d
->cb(ref
, &oid
, d
->cb_data
)) != 0)
447 git_error_set_after_callback_function(error
, "git_tag_foreach");
453 int git_tag_foreach(git_repository
*repo
, git_tag_foreach_cb cb
, void *cb_data
)
460 data
.cb_data
= cb_data
;
463 return git_reference_foreach_name(repo
, &tags_cb
, &data
);
471 #define GIT_REFS_TAGS_DIR_LEN strlen(GIT_REFS_TAGS_DIR)
473 static int tag_list_cb(const char *tag_name
, git_oid
*oid
, void *data
)
475 tag_filter_data
*filter
= (tag_filter_data
*)data
;
478 if (!*filter
->pattern
||
479 wildmatch(filter
->pattern
, tag_name
+ GIT_REFS_TAGS_DIR_LEN
, 0) == 0)
481 char *matched
= git__strdup(tag_name
+ GIT_REFS_TAGS_DIR_LEN
);
482 GIT_ERROR_CHECK_ALLOC(matched
);
484 return git_vector_insert(filter
->taglist
, matched
);
490 int git_tag_list_match(git_strarray
*tag_names
, const char *pattern
, git_repository
*repo
)
493 tag_filter_data filter
;
496 assert(tag_names
&& repo
&& pattern
);
498 if ((error
= git_vector_init(&taglist
, 8, NULL
)) < 0)
501 filter
.taglist
= &taglist
;
502 filter
.pattern
= pattern
;
504 error
= git_tag_foreach(repo
, &tag_list_cb
, (void *)&filter
);
507 git_vector_free(&taglist
);
510 (char **)git_vector_detach(&tag_names
->count
, NULL
, &taglist
);
515 int git_tag_list(git_strarray
*tag_names
, git_repository
*repo
)
517 return git_tag_list_match(tag_names
, "", repo
);
520 int git_tag_peel(git_object
**tag_target
, const git_tag
*tag
)
522 return git_object_peel(tag_target
, (const git_object
*)tag
, GIT_OBJECT_ANY
);
525 /* Deprecated Functions */
527 #ifndef GIT_DEPRECATE_HARD
528 int git_tag_create_frombuffer(git_oid
*oid
, git_repository
*repo
, const char *buffer
, int allow_ref_overwrite
)
530 return git_tag_create_from_buffer(oid
, repo
, buffer
, allow_ref_overwrite
);