]>
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 "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_otype
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 giterr_set(GITERR_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"
75 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_OBJ_BAD
;
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_OBJ_BAD
)
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 GITERR_CHECK_ALLOC_ADD(&alloc_len
, text_len
, 1);
121 tag
->tag_name
= git__malloc(alloc_len
);
122 GITERR_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 GITERR_CHECK_ALLOC(tag
->tagger
);
134 if (git_signature__parse(tag
->tagger
, &buffer
, buffer_end
, "tagger ", '\n') < 0)
139 if (buffer
< buffer_end
) {
140 if( *buffer
!= '\n' )
141 return tag_error("No new line before message");
143 text_len
= buffer_end
- ++buffer
;
145 GITERR_CHECK_ALLOC_ADD(&alloc_len
, text_len
, 1);
146 tag
->message
= git__malloc(alloc_len
);
147 GITERR_CHECK_ALLOC(tag
->message
);
149 memcpy(tag
->message
, buffer
, text_len
);
150 tag
->message
[text_len
] = '\0';
156 int git_tag__parse(void *_tag
, git_odb_object
*odb_obj
)
159 const char *buffer
= git_odb_object_data(odb_obj
);
160 const char *buffer_end
= buffer
+ git_odb_object_size(odb_obj
);
162 return tag_parse(tag
, buffer
, buffer_end
);
165 static int retrieve_tag_reference(
166 git_reference
**tag_reference_out
,
167 git_buf
*ref_name_out
,
168 git_repository
*repo
,
169 const char *tag_name
)
171 git_reference
*tag_ref
;
174 *tag_reference_out
= NULL
;
176 if (git_buf_joinpath(ref_name_out
, GIT_REFS_TAGS_DIR
, tag_name
) < 0)
179 error
= git_reference_lookup(&tag_ref
, repo
, ref_name_out
->ptr
);
181 return error
; /* Be it not foundo or corrupted */
183 *tag_reference_out
= tag_ref
;
188 static int retrieve_tag_reference_oid(
190 git_buf
*ref_name_out
,
191 git_repository
*repo
,
192 const char *tag_name
)
194 if (git_buf_joinpath(ref_name_out
, GIT_REFS_TAGS_DIR
, tag_name
) < 0)
197 return git_reference_name_to_id(oid
, repo
, ref_name_out
->ptr
);
200 static int write_tag_annotation(
202 git_repository
*repo
,
203 const char *tag_name
,
204 const git_object
*target
,
205 const git_signature
*tagger
,
208 git_buf tag
= GIT_BUF_INIT
;
211 git_oid__writebuf(&tag
, "object ", git_object_id(target
));
212 git_buf_printf(&tag
, "type %s\n", git_object_type2string(git_object_type(target
)));
213 git_buf_printf(&tag
, "tag %s\n", tag_name
);
214 git_signature__writebuf(&tag
, "tagger ", tagger
);
215 git_buf_putc(&tag
, '\n');
217 if (git_buf_puts(&tag
, message
) < 0)
220 if (git_repository_odb__weakptr(&odb
, repo
) < 0)
223 if (git_odb_write(oid
, odb
, tag
.ptr
, tag
.size
, GIT_OBJ_TAG
) < 0)
231 giterr_set(GITERR_OBJECT
, "Failed to create tag annotation.");
235 static int git_tag_create__internal(
237 git_repository
*repo
,
238 const char *tag_name
,
239 const git_object
*target
,
240 const git_signature
*tagger
,
242 int allow_ref_overwrite
,
243 int create_tag_annotation
)
245 git_reference
*new_ref
= NULL
;
246 git_buf ref_name
= GIT_BUF_INIT
;
250 assert(repo
&& tag_name
&& target
);
251 assert(!create_tag_annotation
|| (tagger
&& message
));
253 if (git_object_owner(target
) != repo
) {
254 giterr_set(GITERR_INVALID
, "The given target does not belong to this repository");
258 error
= retrieve_tag_reference_oid(oid
, &ref_name
, repo
, tag_name
);
259 if (error
< 0 && error
!= GIT_ENOTFOUND
)
262 /** Ensure the tag name doesn't conflict with an already existing
263 * reference unless overwriting has explicitly been requested **/
264 if (error
== 0 && !allow_ref_overwrite
) {
265 git_buf_free(&ref_name
);
266 giterr_set(GITERR_TAG
, "Tag already exists");
270 if (create_tag_annotation
) {
271 if (write_tag_annotation(oid
, repo
, tag_name
, target
, tagger
, message
) < 0)
274 git_oid_cpy(oid
, git_object_id(target
));
276 error
= git_reference_create(&new_ref
, repo
, ref_name
.ptr
, oid
, allow_ref_overwrite
, NULL
);
279 git_reference_free(new_ref
);
280 git_buf_free(&ref_name
);
286 git_repository
*repo
,
287 const char *tag_name
,
288 const git_object
*target
,
289 const git_signature
*tagger
,
291 int allow_ref_overwrite
)
293 return git_tag_create__internal(oid
, repo
, tag_name
, target
, tagger
, message
, allow_ref_overwrite
, 1);
296 int git_tag_annotation_create(
298 git_repository
*repo
,
299 const char *tag_name
,
300 const git_object
*target
,
301 const git_signature
*tagger
,
304 assert(oid
&& repo
&& tag_name
&& target
&& tagger
&& message
);
306 return write_tag_annotation(oid
, repo
, tag_name
, target
, tagger
, message
);
309 int git_tag_create_lightweight(
311 git_repository
*repo
,
312 const char *tag_name
,
313 const git_object
*target
,
314 int allow_ref_overwrite
)
316 return git_tag_create__internal(oid
, repo
, tag_name
, target
, NULL
, NULL
, allow_ref_overwrite
, 0);
319 int git_tag_create_frombuffer(git_oid
*oid
, git_repository
*repo
, const char *buffer
, int allow_ref_overwrite
)
324 git_odb_stream
*stream
;
325 git_odb_object
*target_obj
;
327 git_reference
*new_ref
= NULL
;
328 git_buf ref_name
= GIT_BUF_INIT
;
330 assert(oid
&& buffer
);
332 memset(&tag
, 0, sizeof(tag
));
334 if (git_repository_odb__weakptr(&odb
, repo
) < 0)
337 /* validate the buffer */
338 if (tag_parse(&tag
, buffer
, buffer
+ strlen(buffer
)) < 0)
341 /* validate the target */
342 if (git_odb_read(&target_obj
, odb
, &tag
.target
) < 0)
345 if (tag
.type
!= target_obj
->cached
.type
) {
346 giterr_set(GITERR_TAG
, "The type for the given target is invalid");
350 error
= retrieve_tag_reference_oid(oid
, &ref_name
, repo
, tag
.tag_name
);
351 if (error
< 0 && error
!= GIT_ENOTFOUND
)
354 /* We don't need these objects after this */
355 git_signature_free(tag
.tagger
);
356 git__free(tag
.tag_name
);
357 git__free(tag
.message
);
358 git_odb_object_free(target_obj
);
360 /** Ensure the tag name doesn't conflict with an already existing
361 * reference unless overwriting has explictly been requested **/
362 if (error
== 0 && !allow_ref_overwrite
) {
363 giterr_set(GITERR_TAG
, "Tag already exists");
367 /* write the buffer */
368 if ((error
= git_odb_open_wstream(
369 &stream
, odb
, strlen(buffer
), GIT_OBJ_TAG
)) < 0)
372 if (!(error
= git_odb_stream_write(stream
, buffer
, strlen(buffer
))))
373 error
= git_odb_stream_finalize_write(oid
, stream
);
375 git_odb_stream_free(stream
);
378 git_buf_free(&ref_name
);
382 error
= git_reference_create(
383 &new_ref
, repo
, ref_name
.ptr
, oid
, allow_ref_overwrite
, NULL
);
385 git_reference_free(new_ref
);
386 git_buf_free(&ref_name
);
391 git_signature_free(tag
.tagger
);
392 git__free(tag
.tag_name
);
393 git__free(tag
.message
);
394 git_odb_object_free(target_obj
);
398 int git_tag_delete(git_repository
*repo
, const char *tag_name
)
400 git_reference
*tag_ref
;
401 git_buf ref_name
= GIT_BUF_INIT
;
404 error
= retrieve_tag_reference(&tag_ref
, &ref_name
, repo
, tag_name
);
406 git_buf_free(&ref_name
);
411 error
= git_reference_delete(tag_ref
);
413 git_reference_free(tag_ref
);
419 git_repository
*repo
;
420 git_tag_foreach_cb cb
;
424 static int tags_cb(const char *ref
, void *data
)
428 tag_cb_data
*d
= (tag_cb_data
*)data
;
430 if (git__prefixcmp(ref
, GIT_REFS_TAGS_DIR
) != 0)
431 return 0; /* no tag */
433 if (!(error
= git_reference_name_to_id(&oid
, d
->repo
, ref
))) {
434 if ((error
= d
->cb(ref
, &oid
, d
->cb_data
)) != 0)
435 giterr_set_after_callback_function(error
, "git_tag_foreach");
441 int git_tag_foreach(git_repository
*repo
, git_tag_foreach_cb cb
, void *cb_data
)
448 data
.cb_data
= cb_data
;
451 return git_reference_foreach_name(repo
, &tags_cb
, &data
);
459 #define GIT_REFS_TAGS_DIR_LEN strlen(GIT_REFS_TAGS_DIR)
461 static int tag_list_cb(const char *tag_name
, git_oid
*oid
, void *data
)
463 tag_filter_data
*filter
= (tag_filter_data
*)data
;
466 if (!*filter
->pattern
||
467 p_fnmatch(filter
->pattern
, tag_name
+ GIT_REFS_TAGS_DIR_LEN
, 0) == 0)
469 char *matched
= git__strdup(tag_name
+ GIT_REFS_TAGS_DIR_LEN
);
470 GITERR_CHECK_ALLOC(matched
);
472 return git_vector_insert(filter
->taglist
, matched
);
478 int git_tag_list_match(git_strarray
*tag_names
, const char *pattern
, git_repository
*repo
)
481 tag_filter_data filter
;
484 assert(tag_names
&& repo
&& pattern
);
486 if ((error
= git_vector_init(&taglist
, 8, NULL
)) < 0)
489 filter
.taglist
= &taglist
;
490 filter
.pattern
= pattern
;
492 error
= git_tag_foreach(repo
, &tag_list_cb
, (void *)&filter
);
495 git_vector_free(&taglist
);
498 (char **)git_vector_detach(&tag_names
->count
, NULL
, &taglist
);
503 int git_tag_list(git_strarray
*tag_names
, git_repository
*repo
)
505 return git_tag_list_match(tag_names
, "", repo
);
508 int git_tag_peel(git_object
**tag_target
, const git_tag
*tag
)
510 return git_object_peel(tag_target
, (const git_object
*)tag
, GIT_OBJ_ANY
);