]>
Commit | Line | Data |
---|---|---|
f8758044 | 1 | /* |
359fc2d2 | 2 | * Copyright (C) the libgit2 contributors. All rights reserved. |
f8758044 | 3 | * |
bb742ede VM |
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. | |
f8758044 VM |
6 | */ |
7 | ||
f8758044 | 8 | #include "tag.h" |
eae0bfdc PP |
9 | |
10 | #include "commit.h" | |
638c2ca4 | 11 | #include "signature.h" |
458b9450 | 12 | #include "message.h" |
22a2d3d5 | 13 | #include "wildmatch.h" |
44908fe7 VM |
14 | #include "git2/object.h" |
15 | #include "git2/repository.h" | |
638c2ca4 | 16 | #include "git2/signature.h" |
83cc70d9 | 17 | #include "git2/odb_backend.h" |
f8758044 | 18 | |
78606263 | 19 | void git_tag__free(void *_tag) |
f8758044 | 20 | { |
78606263 | 21 | git_tag *tag = _tag; |
638c2ca4 | 22 | git_signature_free(tag->tagger); |
3286c408 VM |
23 | git__free(tag->message); |
24 | git__free(tag->tag_name); | |
25 | git__free(tag); | |
f8758044 VM |
26 | } |
27 | ||
d9023dbe | 28 | int git_tag_target(git_object **target, const git_tag *t) |
f8758044 | 29 | { |
c25aa7cd | 30 | GIT_ASSERT_ARG(t); |
6b2a1941 | 31 | return git_object_lookup(target, t->object.repo, &t->target, t->type); |
f8758044 VM |
32 | } |
33 | ||
d9023dbe | 34 | const git_oid *git_tag_target_id(const git_tag *t) |
ec25391d | 35 | { |
c25aa7cd | 36 | GIT_ASSERT_ARG_WITH_RETVAL(t, NULL); |
6b2a1941 VM |
37 | return &t->target; |
38 | } | |
39 | ||
ac3d33df | 40 | git_object_t git_tag_target_type(const git_tag *t) |
f8758044 | 41 | { |
c25aa7cd | 42 | GIT_ASSERT_ARG_WITH_RETVAL(t, GIT_OBJECT_INVALID); |
f8758044 VM |
43 | return t->type; |
44 | } | |
45 | ||
d9023dbe | 46 | const char *git_tag_name(const git_tag *t) |
f8758044 | 47 | { |
c25aa7cd | 48 | GIT_ASSERT_ARG_WITH_RETVAL(t, NULL); |
f8758044 VM |
49 | return t->tag_name; |
50 | } | |
51 | ||
d9023dbe | 52 | const git_signature *git_tag_tagger(const git_tag *t) |
f8758044 | 53 | { |
f8758044 VM |
54 | return t->tagger; |
55 | } | |
56 | ||
d9023dbe | 57 | const char *git_tag_message(const git_tag *t) |
f8758044 | 58 | { |
c25aa7cd | 59 | GIT_ASSERT_ARG_WITH_RETVAL(t, NULL); |
f8758044 VM |
60 | return t->message; |
61 | } | |
62 | ||
3aa351ea CMN |
63 | static int tag_error(const char *str) |
64 | { | |
ac3d33df | 65 | git_error_set(GIT_ERROR_TAG, "failed to parse tag: %s", str); |
3aa351ea CMN |
66 | return -1; |
67 | } | |
68 | ||
3f27127d | 69 | static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) |
f8758044 VM |
70 | { |
71 | static const char *tag_types[] = { | |
72 | NULL, "commit\n", "tree\n", "blob\n", "tag\n" | |
73 | }; | |
f1453c59 | 74 | size_t text_len, alloc_len; |
6c7cee42 RD |
75 | const char *search; |
76 | unsigned int i; | |
f8758044 | 77 | |
3aa351ea | 78 | if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0) |
909d5494 | 79 | return tag_error("object field invalid"); |
f8758044 VM |
80 | |
81 | if (buffer + 5 >= buffer_end) | |
909d5494 | 82 | return tag_error("object too short"); |
f8758044 VM |
83 | |
84 | if (memcmp(buffer, "type ", 5) != 0) | |
909d5494 | 85 | return tag_error("type field not found"); |
f8758044 VM |
86 | buffer += 5; |
87 | ||
ac3d33df | 88 | tag->type = GIT_OBJECT_INVALID; |
f8758044 VM |
89 | |
90 | for (i = 1; i < ARRAY_SIZE(tag_types); ++i) { | |
91 | size_t type_length = strlen(tag_types[i]); | |
92 | ||
93 | if (buffer + type_length >= buffer_end) | |
909d5494 | 94 | return tag_error("object too short"); |
f8758044 VM |
95 | |
96 | if (memcmp(buffer, tag_types[i], type_length) == 0) { | |
97 | tag->type = i; | |
98 | buffer += type_length; | |
99 | break; | |
100 | } | |
101 | } | |
102 | ||
ac3d33df | 103 | if (tag->type == GIT_OBJECT_INVALID) |
909d5494 | 104 | return tag_error("invalid object type"); |
f8758044 | 105 | |
f8758044 | 106 | if (buffer + 4 >= buffer_end) |
909d5494 | 107 | return tag_error("object too short"); |
f8758044 VM |
108 | |
109 | if (memcmp(buffer, "tag ", 4) != 0) | |
909d5494 | 110 | return tag_error("tag field not found"); |
44dc0d26 | 111 | |
f8758044 VM |
112 | buffer += 4; |
113 | ||
114 | search = memchr(buffer, '\n', buffer_end - buffer); | |
115 | if (search == NULL) | |
909d5494 | 116 | return tag_error("object too short"); |
f8758044 VM |
117 | |
118 | text_len = search - buffer; | |
119 | ||
ac3d33df | 120 | GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, text_len, 1); |
f1453c59 | 121 | tag->tag_name = git__malloc(alloc_len); |
ac3d33df | 122 | GIT_ERROR_CHECK_ALLOC(tag->tag_name); |
076141a1 | 123 | |
f8758044 VM |
124 | memcpy(tag->tag_name, buffer, text_len); |
125 | tag->tag_name[text_len] = '\0'; | |
126 | ||
127 | buffer = search + 1; | |
128 | ||
15b0bed2 | 129 | tag->tagger = NULL; |
24cb87e2 | 130 | if (buffer < buffer_end && *buffer != '\n') { |
15b0bed2 | 131 | tag->tagger = git__malloc(sizeof(git_signature)); |
ac3d33df | 132 | GIT_ERROR_CHECK_ALLOC(tag->tagger); |
15b0bed2 | 133 | |
3aa351ea CMN |
134 | if (git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ", '\n') < 0) |
135 | return -1; | |
15b0bed2 | 136 | } |
f8758044 | 137 | |
6bb9fea1 EZ |
138 | tag->message = NULL; |
139 | if (buffer < buffer_end) { | |
eb39284b | 140 | /* If we're not at the end of the header, search for it */ |
6c7cee42 RD |
141 | if(*buffer != '\n') { |
142 | search = git__memmem(buffer, buffer_end - buffer, | |
143 | "\n\n", 2); | |
eb39284b CMN |
144 | if (search) |
145 | buffer = search + 1; | |
146 | else | |
147 | return tag_error("tag contains no message"); | |
148 | } | |
fbfc7580 | 149 | |
6bb9fea1 | 150 | text_len = buffer_end - ++buffer; |
f8758044 | 151 | |
ac3d33df | 152 | GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, text_len, 1); |
f1453c59 | 153 | tag->message = git__malloc(alloc_len); |
ac3d33df | 154 | GIT_ERROR_CHECK_ALLOC(tag->message); |
076141a1 | 155 | |
6bb9fea1 EZ |
156 | memcpy(tag->message, buffer, text_len); |
157 | tag->message[text_len] = '\0'; | |
158 | } | |
f8758044 | 159 | |
3aa351ea | 160 | return 0; |
f8758044 VM |
161 | } |
162 | ||
ac3d33df JK |
163 | int git_tag__parse_raw(void *_tag, const char *data, size_t size) |
164 | { | |
165 | return tag_parse(_tag, data, data + size); | |
166 | } | |
167 | ||
3f27127d RB |
168 | int git_tag__parse(void *_tag, git_odb_object *odb_obj) |
169 | { | |
170 | git_tag *tag = _tag; | |
171 | const char *buffer = git_odb_object_data(odb_obj); | |
172 | const char *buffer_end = buffer + git_odb_object_size(odb_obj); | |
173 | ||
174 | return tag_parse(tag, buffer, buffer_end); | |
175 | } | |
176 | ||
97769280 RB |
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) | |
ec25391d | 182 | { |
9e680bcc | 183 | git_reference *tag_ref; |
184 | int error; | |
185 | ||
75abd2b9 MS |
186 | *tag_reference_out = NULL; |
187 | ||
3aa351ea CMN |
188 | if (git_buf_joinpath(ref_name_out, GIT_REFS_TAGS_DIR, tag_name) < 0) |
189 | return -1; | |
97769280 RB |
190 | |
191 | error = git_reference_lookup(&tag_ref, repo, ref_name_out->ptr); | |
e172cf08 | 192 | if (error < 0) |
3aa351ea | 193 | return error; /* Be it not foundo or corrupted */ |
9e680bcc | 194 | |
3e3e4631 | 195 | *tag_reference_out = tag_ref; |
9e680bcc | 196 | |
3aa351ea CMN |
197 | return 0; |
198 | } | |
199 | ||
200 | static int retrieve_tag_reference_oid( | |
201 | git_oid *oid, | |
202 | git_buf *ref_name_out, | |
203 | git_repository *repo, | |
204 | const char *tag_name) | |
205 | { | |
206 | if (git_buf_joinpath(ref_name_out, GIT_REFS_TAGS_DIR, tag_name) < 0) | |
207 | return -1; | |
208 | ||
2508cc66 | 209 | return git_reference_name_to_id(oid, repo, ref_name_out->ptr); |
72a3fe42 | 210 | } |
ec25391d | 211 | |
bfbb5562 | 212 | static int write_tag_annotation( |
213 | git_oid *oid, | |
214 | git_repository *repo, | |
215 | const char *tag_name, | |
216 | const git_object *target, | |
217 | const git_signature *tagger, | |
218 | const char *message) | |
219 | { | |
743a4b3b | 220 | git_buf tag = GIT_BUF_INIT; |
9462c471 | 221 | git_odb *odb; |
bfbb5562 | 222 | |
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'); | |
bfbb5562 | 228 | |
743a4b3b | 229 | if (git_buf_puts(&tag, message) < 0) |
3aa351ea | 230 | goto on_error; |
bfbb5562 | 231 | |
3aa351ea CMN |
232 | if (git_repository_odb__weakptr(&odb, repo) < 0) |
233 | goto on_error; | |
9462c471 | 234 | |
ac3d33df | 235 | if (git_odb_write(oid, odb, tag.ptr, tag.size, GIT_OBJECT_TAG) < 0) |
3aa351ea | 236 | goto on_error; |
bfbb5562 | 237 | |
ac3d33df | 238 | git_buf_dispose(&tag); |
3aa351ea | 239 | return 0; |
458b9450 | 240 | |
3aa351ea | 241 | on_error: |
ac3d33df JK |
242 | git_buf_dispose(&tag); |
243 | git_error_set(GIT_ERROR_OBJECT, "failed to create tag annotation"); | |
3aa351ea | 244 | return -1; |
bfbb5562 | 245 | } |
246 | ||
247 | static int git_tag_create__internal( | |
72a3fe42 VM |
248 | git_oid *oid, |
249 | git_repository *repo, | |
250 | const char *tag_name, | |
d5afc039 | 251 | const git_object *target, |
72a3fe42 | 252 | const git_signature *tagger, |
a50c1458 | 253 | const char *message, |
bfbb5562 | 254 | int allow_ref_overwrite, |
255 | int create_tag_annotation) | |
72a3fe42 | 256 | { |
d5afc039 | 257 | git_reference *new_ref = NULL; |
97769280 | 258 | git_buf ref_name = GIT_BUF_INIT; |
ec25391d | 259 | |
3aa351ea | 260 | int error; |
72a3fe42 | 261 | |
c25aa7cd PP |
262 | GIT_ASSERT_ARG(repo); |
263 | GIT_ASSERT_ARG(tag_name); | |
264 | GIT_ASSERT_ARG(target); | |
265 | GIT_ASSERT_ARG(!create_tag_annotation || (tagger && message)); | |
bfbb5562 | 266 | |
3aa351ea | 267 | if (git_object_owner(target) != repo) { |
ac3d33df | 268 | git_error_set(GIT_ERROR_INVALID, "the given target does not belong to this repository"); |
3aa351ea CMN |
269 | return -1; |
270 | } | |
d5afc039 | 271 | |
3aa351ea | 272 | error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag_name); |
904b67e6 | 273 | if (error < 0 && error != GIT_ENOTFOUND) |
18d6f120 | 274 | goto cleanup; |
d5afc039 | 275 | |
932d1baf | 276 | /** Ensure the tag name doesn't conflict with an already existing |
b874629b | 277 | * reference unless overwriting has explicitly been requested **/ |
3aa351ea | 278 | if (error == 0 && !allow_ref_overwrite) { |
ac3d33df JK |
279 | git_buf_dispose(&ref_name); |
280 | git_error_set(GIT_ERROR_TAG, "tag already exists"); | |
904b67e6 | 281 | return GIT_EEXISTS; |
81234673 CMN |
282 | } |
283 | ||
bfbb5562 | 284 | if (create_tag_annotation) { |
3aa351ea CMN |
285 | if (write_tag_annotation(oid, repo, tag_name, target, tagger, message) < 0) |
286 | return -1; | |
bfbb5562 | 287 | } else |
288 | git_oid_cpy(oid, git_object_id(target)); | |
72a3fe42 | 289 | |
659cf202 | 290 | error = git_reference_create(&new_ref, repo, ref_name.ptr, oid, allow_ref_overwrite, NULL); |
932d1baf | 291 | |
18d6f120 | 292 | cleanup: |
75abd2b9 | 293 | git_reference_free(new_ref); |
ac3d33df | 294 | git_buf_dispose(&ref_name); |
97769280 | 295 | return error; |
ec25391d VM |
296 | } |
297 | ||
bfbb5562 | 298 | int git_tag_create( |
3f27127d RB |
299 | git_oid *oid, |
300 | git_repository *repo, | |
301 | const char *tag_name, | |
302 | const git_object *target, | |
303 | const git_signature *tagger, | |
304 | const char *message, | |
305 | int allow_ref_overwrite) | |
bfbb5562 | 306 | { |
307 | return git_tag_create__internal(oid, repo, tag_name, target, tagger, message, allow_ref_overwrite, 1); | |
308 | } | |
309 | ||
b81cc1d6 | 310 | int git_tag_annotation_create( |
311 | git_oid *oid, | |
312 | git_repository *repo, | |
313 | const char *tag_name, | |
314 | const git_object *target, | |
315 | const git_signature *tagger, | |
316 | const char *message) | |
317 | { | |
c25aa7cd PP |
318 | GIT_ASSERT_ARG(oid); |
319 | GIT_ASSERT_ARG(repo); | |
320 | GIT_ASSERT_ARG(tag_name); | |
321 | GIT_ASSERT_ARG(target); | |
322 | GIT_ASSERT_ARG(tagger); | |
323 | GIT_ASSERT_ARG(message); | |
b81cc1d6 | 324 | |
325 | return write_tag_annotation(oid, repo, tag_name, target, tagger, message); | |
326 | } | |
327 | ||
bfbb5562 | 328 | int git_tag_create_lightweight( |
3f27127d RB |
329 | git_oid *oid, |
330 | git_repository *repo, | |
331 | const char *tag_name, | |
332 | const git_object *target, | |
333 | int allow_ref_overwrite) | |
bfbb5562 | 334 | { |
335 | return git_tag_create__internal(oid, repo, tag_name, target, NULL, NULL, allow_ref_overwrite, 0); | |
336 | } | |
337 | ||
22a2d3d5 | 338 | int git_tag_create_from_buffer(git_oid *oid, git_repository *repo, const char *buffer, int allow_ref_overwrite) |
7b4a16e2 CMN |
339 | { |
340 | git_tag tag; | |
3aa351ea | 341 | int error; |
9462c471 | 342 | git_odb *odb; |
ac4fcf17 | 343 | git_odb_stream *stream; |
d5afc039 | 344 | git_odb_object *target_obj; |
932d1baf | 345 | |
75abd2b9 | 346 | git_reference *new_ref = NULL; |
97769280 | 347 | git_buf ref_name = GIT_BUF_INIT; |
932d1baf | 348 | |
c25aa7cd PP |
349 | GIT_ASSERT_ARG(oid); |
350 | GIT_ASSERT_ARG(buffer); | |
932d1baf | 351 | |
7b4a16e2 | 352 | memset(&tag, 0, sizeof(tag)); |
932d1baf | 353 | |
3aa351ea CMN |
354 | if (git_repository_odb__weakptr(&odb, repo) < 0) |
355 | return -1; | |
9462c471 | 356 | |
ac4fcf17 | 357 | /* validate the buffer */ |
3f27127d | 358 | if (tag_parse(&tag, buffer, buffer + strlen(buffer)) < 0) |
3aa351ea | 359 | return -1; |
d5afc039 VM |
360 | |
361 | /* validate the target */ | |
3aa351ea CMN |
362 | if (git_odb_read(&target_obj, odb, &tag.target) < 0) |
363 | goto on_error; | |
d5afc039 | 364 | |
8842c75f | 365 | if (tag.type != target_obj->cached.type) { |
ac3d33df | 366 | git_error_set(GIT_ERROR_TAG, "the type for the given target is invalid"); |
3aa351ea | 367 | goto on_error; |
97769280 | 368 | } |
d5afc039 | 369 | |
3aa351ea | 370 | error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag.tag_name); |
904b67e6 | 371 | if (error < 0 && error != GIT_ENOTFOUND) |
3aa351ea CMN |
372 | goto on_error; |
373 | ||
374 | /* We don't need these objects after this */ | |
375 | git_signature_free(tag.tagger); | |
376 | git__free(tag.tag_name); | |
377 | git__free(tag.message); | |
378 | git_odb_object_free(target_obj); | |
d5afc039 VM |
379 | |
380 | /** Ensure the tag name doesn't conflict with an already existing | |
91f0d186 | 381 | * reference unless overwriting has explicitly been requested **/ |
3aa351ea | 382 | if (error == 0 && !allow_ref_overwrite) { |
ac3d33df | 383 | git_error_set(GIT_ERROR_TAG, "tag already exists"); |
904b67e6 | 384 | return GIT_EEXISTS; |
ac4fcf17 | 385 | } |
932d1baf | 386 | |
ac4fcf17 | 387 | /* write the buffer */ |
a37aa82e | 388 | if ((error = git_odb_open_wstream( |
ac3d33df | 389 | &stream, odb, strlen(buffer), GIT_OBJECT_TAG)) < 0) |
a37aa82e | 390 | return error; |
932d1baf | 391 | |
a37aa82e RB |
392 | if (!(error = git_odb_stream_write(stream, buffer, strlen(buffer)))) |
393 | error = git_odb_stream_finalize_write(oid, stream); | |
932d1baf | 394 | |
376e6c9f | 395 | git_odb_stream_free(stream); |
932d1baf | 396 | |
3aa351ea | 397 | if (error < 0) { |
ac3d33df | 398 | git_buf_dispose(&ref_name); |
a37aa82e | 399 | return error; |
3aa351ea | 400 | } |
d5afc039 | 401 | |
a37aa82e | 402 | error = git_reference_create( |
659cf202 | 403 | &new_ref, repo, ref_name.ptr, oid, allow_ref_overwrite, NULL); |
932d1baf | 404 | |
75abd2b9 | 405 | git_reference_free(new_ref); |
ac3d33df | 406 | git_buf_dispose(&ref_name); |
97769280 | 407 | |
97769280 | 408 | return error; |
3aa351ea CMN |
409 | |
410 | on_error: | |
411 | git_signature_free(tag.tagger); | |
412 | git__free(tag.tag_name); | |
413 | git__free(tag.message); | |
414 | git_odb_object_free(target_obj); | |
415 | return -1; | |
7b4a16e2 CMN |
416 | } |
417 | ||
9e680bcc | 418 | int git_tag_delete(git_repository *repo, const char *tag_name) |
419 | { | |
9e680bcc | 420 | git_reference *tag_ref; |
97769280 | 421 | git_buf ref_name = GIT_BUF_INIT; |
d00d5464 | 422 | int error; |
97769280 RB |
423 | |
424 | error = retrieve_tag_reference(&tag_ref, &ref_name, repo, tag_name); | |
425 | ||
ac3d33df | 426 | git_buf_dispose(&ref_name); |
9e680bcc | 427 | |
3aa351ea | 428 | if (error < 0) |
18d6f120 | 429 | return error; |
9e680bcc | 430 | |
1ad15540 POL |
431 | error = git_reference_delete(tag_ref); |
432 | ||
433 | git_reference_free(tag_ref); | |
9e680bcc | 434 | |
78606263 | 435 | return error; |
f8758044 VM |
436 | } |
437 | ||
2b5af615 | 438 | typedef struct { |
2f05339e MS |
439 | git_repository *repo; |
440 | git_tag_foreach_cb cb; | |
441 | void *cb_data; | |
442 | } tag_cb_data; | |
443 | ||
444 | static int tags_cb(const char *ref, void *data) | |
445 | { | |
dab89f9b | 446 | int error; |
2f05339e MS |
447 | git_oid oid; |
448 | tag_cb_data *d = (tag_cb_data *)data; | |
449 | ||
450 | if (git__prefixcmp(ref, GIT_REFS_TAGS_DIR) != 0) | |
451 | return 0; /* no tag */ | |
452 | ||
dab89f9b | 453 | if (!(error = git_reference_name_to_id(&oid, d->repo, ref))) { |
26c1cb91 | 454 | if ((error = d->cb(ref, &oid, d->cb_data)) != 0) |
ac3d33df | 455 | git_error_set_after_callback_function(error, "git_tag_foreach"); |
dab89f9b | 456 | } |
2f05339e | 457 | |
25e0b157 | 458 | return error; |
2f05339e MS |
459 | } |
460 | ||
461 | int git_tag_foreach(git_repository *repo, git_tag_foreach_cb cb, void *cb_data) | |
462 | { | |
463 | tag_cb_data data; | |
464 | ||
c25aa7cd PP |
465 | GIT_ASSERT_ARG(repo); |
466 | GIT_ASSERT_ARG(cb); | |
2f05339e MS |
467 | |
468 | data.cb = cb; | |
469 | data.cb_data = cb_data; | |
470 | data.repo = repo; | |
dab89f9b | 471 | |
25e0b157 | 472 | return git_reference_foreach_name(repo, &tags_cb, &data); |
2f05339e MS |
473 | } |
474 | ||
475 | typedef struct { | |
476 | git_vector *taglist; | |
477 | const char *pattern; | |
2b5af615 | 478 | } tag_filter_data; |
479 | ||
932669b8 | 480 | #define GIT_REFS_TAGS_DIR_LEN strlen(GIT_REFS_TAGS_DIR) |
2b5af615 | 481 | |
2f05339e | 482 | static int tag_list_cb(const char *tag_name, git_oid *oid, void *data) |
def3fef1 | 483 | { |
2f05339e MS |
484 | tag_filter_data *filter = (tag_filter_data *)data; |
485 | GIT_UNUSED(oid); | |
2b5af615 | 486 | |
dab89f9b | 487 | if (!*filter->pattern || |
22a2d3d5 | 488 | wildmatch(filter->pattern, tag_name + GIT_REFS_TAGS_DIR_LEN, 0) == 0) |
dab89f9b RB |
489 | { |
490 | char *matched = git__strdup(tag_name + GIT_REFS_TAGS_DIR_LEN); | |
ac3d33df | 491 | GIT_ERROR_CHECK_ALLOC(matched); |
25e0b157 | 492 | |
dab89f9b RB |
493 | return git_vector_insert(filter->taglist, matched); |
494 | } | |
def3fef1 | 495 | |
3aa351ea | 496 | return 0; |
def3fef1 VM |
497 | } |
498 | ||
2b5af615 | 499 | int git_tag_list_match(git_strarray *tag_names, const char *pattern, git_repository *repo) |
def3fef1 VM |
500 | { |
501 | int error; | |
2b5af615 | 502 | tag_filter_data filter; |
def3fef1 VM |
503 | git_vector taglist; |
504 | ||
c25aa7cd PP |
505 | GIT_ASSERT_ARG(tag_names); |
506 | GIT_ASSERT_ARG(repo); | |
507 | GIT_ASSERT_ARG(pattern); | |
2b5af615 | 508 | |
dab89f9b RB |
509 | if ((error = git_vector_init(&taglist, 8, NULL)) < 0) |
510 | return error; | |
def3fef1 | 511 | |
2b5af615 | 512 | filter.taglist = &taglist; |
513 | filter.pattern = pattern; | |
514 | ||
2f05339e | 515 | error = git_tag_foreach(repo, &tag_list_cb, (void *)&filter); |
dab89f9b | 516 | |
25e0b157 | 517 | if (error < 0) |
def3fef1 | 518 | git_vector_free(&taglist); |
def3fef1 | 519 | |
25e0b157 RB |
520 | tag_names->strings = |
521 | (char **)git_vector_detach(&tag_names->count, NULL, &taglist); | |
522 | ||
3aa351ea | 523 | return 0; |
def3fef1 | 524 | } |
2b5af615 | 525 | |
526 | int git_tag_list(git_strarray *tag_names, git_repository *repo) | |
527 | { | |
528 | return git_tag_list_match(tag_names, "", repo); | |
d483a911 | 529 | } |
3f46f313 | 530 | |
d9023dbe | 531 | int git_tag_peel(git_object **tag_target, const git_tag *tag) |
3f46f313 | 532 | { |
ac3d33df | 533 | return git_object_peel(tag_target, (const git_object *)tag, GIT_OBJECT_ANY); |
3f46f313 | 534 | } |
22a2d3d5 | 535 | |
c25aa7cd PP |
536 | int git_tag_name_is_valid(int *valid, const char *name) |
537 | { | |
538 | git_buf ref_name = GIT_BUF_INIT; | |
539 | int error = 0; | |
540 | ||
541 | GIT_ASSERT(valid); | |
542 | ||
543 | /* | |
544 | * Discourage tag name starting with dash, | |
545 | * https://github.com/git/git/commit/4f0accd638b8d2 | |
546 | */ | |
547 | if (!name || name[0] == '-') | |
548 | goto done; | |
549 | ||
550 | if ((error = git_buf_puts(&ref_name, GIT_REFS_TAGS_DIR)) < 0 || | |
551 | (error = git_buf_puts(&ref_name, name)) < 0) | |
552 | goto done; | |
553 | ||
554 | error = git_reference_name_is_valid(valid, ref_name.ptr); | |
555 | ||
556 | done: | |
557 | git_buf_dispose(&ref_name); | |
558 | return error; | |
559 | } | |
560 | ||
22a2d3d5 UG |
561 | /* Deprecated Functions */ |
562 | ||
563 | #ifndef GIT_DEPRECATE_HARD | |
564 | int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *buffer, int allow_ref_overwrite) | |
565 | { | |
566 | return git_tag_create_from_buffer(oid, repo, buffer, allow_ref_overwrite); | |
567 | } | |
568 | #endif |