]> git.proxmox.com Git - libgit2.git/blame - src/tag.c
index.h: Add IDXENTRY flags needed for index operations
[libgit2.git] / src / tag.c
CommitLineData
f8758044
VM
1/*
2 * This file is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2,
4 * as published by the Free Software Foundation.
5 *
6 * In addition to the permissions in the GNU General Public License,
7 * the authors give you unlimited permission to link the compiled
8 * version of this file into combinations with other programs,
9 * and to distribute those combinations without any restriction
10 * coming from the use of this file. (The General Public License
11 * restrictions do apply in other respects; for example, they cover
12 * modification of the file, and distribution when not linked into
13 * a combined executable.)
14 *
15 * This file is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; see the file COPYING. If not, write to
22 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26#include "common.h"
27#include "commit.h"
28#include "tag.h"
638c2ca4 29#include "signature.h"
44908fe7
VM
30#include "git2/object.h"
31#include "git2/repository.h"
638c2ca4 32#include "git2/signature.h"
f8758044
VM
33
34void git_tag__free(git_tag *tag)
35{
638c2ca4 36 git_signature_free(tag->tagger);
f8758044
VM
37 free(tag->message);
38 free(tag->tag_name);
f8758044
VM
39 free(tag);
40}
41
d45b4a9a
VM
42const git_oid *git_tag_id(git_tag *c)
43{
44 return git_object_id((git_object *)c);
f8758044
VM
45}
46
6b2a1941 47int git_tag_target(git_object **target, git_tag *t)
f8758044 48{
58519018 49 assert(t);
6b2a1941 50 return git_object_lookup(target, t->object.repo, &t->target, t->type);
f8758044
VM
51}
52
6b2a1941 53const git_oid *git_tag_target_oid(git_tag *t)
ec25391d 54{
6b2a1941
VM
55 assert(t);
56 return &t->target;
57}
58
f8758044
VM
59git_otype git_tag_type(git_tag *t)
60{
58519018 61 assert(t);
f8758044
VM
62 return t->type;
63}
64
f8758044
VM
65const char *git_tag_name(git_tag *t)
66{
58519018 67 assert(t);
f8758044
VM
68 return t->tag_name;
69}
70
638c2ca4 71const git_signature *git_tag_tagger(git_tag *t)
f8758044 72{
f8758044
VM
73 return t->tagger;
74}
75
76const char *git_tag_message(git_tag *t)
77{
58519018 78 assert(t);
f8758044
VM
79 return t->message;
80}
81
720d5472 82static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer_end)
f8758044
VM
83{
84 static const char *tag_types[] = {
85 NULL, "commit\n", "tree\n", "blob\n", "tag\n"
86 };
87
f8758044
VM
88 unsigned int i, text_len;
89 char *search;
1795f879 90 int error;
f8758044 91
6b2a1941 92 if ((error = git__parse_oid(&tag->target, &buffer, buffer_end, "object ")) < 0)
1795f879 93 return error;
f8758044
VM
94
95 if (buffer + 5 >= buffer_end)
96 return GIT_EOBJCORRUPTED;
97
98 if (memcmp(buffer, "type ", 5) != 0)
99 return GIT_EOBJCORRUPTED;
100 buffer += 5;
101
102 tag->type = GIT_OBJ_BAD;
103
104 for (i = 1; i < ARRAY_SIZE(tag_types); ++i) {
105 size_t type_length = strlen(tag_types[i]);
106
107 if (buffer + type_length >= buffer_end)
108 return GIT_EOBJCORRUPTED;
109
110 if (memcmp(buffer, tag_types[i], type_length) == 0) {
111 tag->type = i;
112 buffer += type_length;
113 break;
114 }
115 }
116
117 if (tag->type == GIT_OBJ_BAD)
118 return GIT_EOBJCORRUPTED;
119
f8758044
VM
120 if (buffer + 4 >= buffer_end)
121 return GIT_EOBJCORRUPTED;
122
123 if (memcmp(buffer, "tag ", 4) != 0)
124 return GIT_EOBJCORRUPTED;
125 buffer += 4;
126
127 search = memchr(buffer, '\n', buffer_end - buffer);
128 if (search == NULL)
129 return GIT_EOBJCORRUPTED;
130
131 text_len = search - buffer;
132
f8758044
VM
133 tag->tag_name = git__malloc(text_len + 1);
134 memcpy(tag->tag_name, buffer, text_len);
135 tag->tag_name[text_len] = '\0';
136
137 buffer = search + 1;
138
638c2ca4 139 tag->tagger = git__malloc(sizeof(git_signature));
f8758044 140
720d5472
VM
141 if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ")) != 0) {
142 free(tag->tag_name);
143 git_signature_free(tag->tagger);
144 return error;
145 }
f8758044 146
ec25391d 147 text_len = buffer_end - ++buffer;
f8758044 148
f8758044
VM
149 tag->message = git__malloc(text_len + 1);
150 memcpy(tag->message, buffer, text_len);
151 tag->message[text_len] = '\0';
152
6f02c3ba 153 return GIT_SUCCESS;
f8758044
VM
154}
155
9e680bcc 156static int retreive_tag_reference(git_reference **tag_reference_out, char *ref_name_out, git_repository *repo, const char *tag_name)
ec25391d 157{
9e680bcc 158 git_reference *tag_ref;
159 int error;
160
161 git__joinpath(ref_name_out, GIT_REFS_TAGS_DIR, tag_name);
162 error = git_reference_lookup(&tag_ref, repo, ref_name_out);
163 if (error < GIT_SUCCESS)
164 return error;
165
3e3e4631 166 *tag_reference_out = tag_ref;
9e680bcc 167
168 return GIT_SUCCESS;
72a3fe42 169}
ec25391d 170
a50c1458 171static int tag_create(
72a3fe42
VM
172 git_oid *oid,
173 git_repository *repo,
174 const char *tag_name,
175 const git_oid *target,
176 git_otype target_type,
177 const git_signature *tagger,
a50c1458 178 const char *message,
179 int allow_ref_overwrite)
72a3fe42
VM
180{
181 size_t final_size = 0;
182 git_odb_stream *stream;
ec25391d 183
72a3fe42
VM
184 const char *type_str;
185 char *tagger_str;
bf4c39f9 186 git_reference *new_ref;
187
188 char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
ec25391d 189
72a3fe42 190 int type_str_len, tag_name_len, tagger_str_len, message_len;
a50c1458 191 int error, should_update_ref = 0;
72a3fe42 192
a50c1458 193 /** Ensure the tag name doesn't conflict with an already existing
194 reference unless overwriting has explictly been requested **/
9e680bcc 195 error = retreive_tag_reference(&new_ref, ref_name, repo, tag_name);
a50c1458 196
197 switch (error) {
198 case GIT_SUCCESS:
199 if (!allow_ref_overwrite)
200 return GIT_EEXISTS;
201 should_update_ref = 1;
202
203 /* Fall trough */
204
205 case GIT_ENOTFOUND:
206 break;
207
208 default:
209 return error;
210 }
72a3fe42 211
72a3fe42
VM
212 type_str = git_object_type2string(target_type);
213
214 tagger_str_len = git_signature__write(&tagger_str, "tagger", tagger);
215
216 type_str_len = strlen(type_str);
217 tag_name_len = strlen(tag_name);
218 message_len = strlen(message);
219
220 final_size += GIT_OID_LINE_LENGTH("object");
221 final_size += STRLEN("type ") + type_str_len + 1;
222 final_size += STRLEN("tag ") + tag_name_len + 1;
223 final_size += tagger_str_len;
224 final_size += 1 + message_len;
225
226 if ((error = git_odb_open_wstream(&stream, repo->db, final_size, GIT_OBJ_TAG)) < GIT_SUCCESS)
227 return error;
228
229 git__write_oid(stream, "object", target);
230
231 stream->write(stream, "type ", STRLEN("type "));
232 stream->write(stream, type_str, type_str_len);
233
234 stream->write(stream, "\ntag ", STRLEN("\ntag "));
235 stream->write(stream, tag_name, tag_name_len);
236 stream->write(stream, "\n", 1);
237
238 stream->write(stream, tagger_str, tagger_str_len);
239 free(tagger_str);
240
241 stream->write(stream, "\n", 1);
242 stream->write(stream, message, message_len);
243
244
245 error = stream->finalize_write(oid, stream);
246 stream->free(stream);
247
bf4c39f9 248 if (error < GIT_SUCCESS)
249 return error;
72a3fe42 250
a50c1458 251 if (!should_update_ref)
252 error = git_reference_create_oid(&new_ref, repo, ref_name, oid);
253 else
254 error = git_reference_set_oid(new_ref, oid);
255
72a3fe42 256 return error;
ec25391d
VM
257}
258
7b4a16e2
CMN
259int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *buffer)
260{
261 git_tag tag;
262 int error;
7b4a16e2
CMN
263 git_object *obj;
264
265 assert(oid && buffer);
266
267 memset(&tag, 0, sizeof(tag));
268
720d5472
VM
269 if ((error = parse_tag_buffer(&tag, buffer, buffer + strlen(buffer))) < GIT_SUCCESS)
270 return error;
7b4a16e2
CMN
271
272 error = git_object_lookup(&obj, repo, &tag.target, tag.type);
720d5472
VM
273 if (error < GIT_SUCCESS)
274 goto cleanup;
7b4a16e2 275
720d5472 276 error = git_tag_create_o(oid, repo, tag.tag_name, obj, tag.tagger, tag.message);
7b4a16e2
CMN
277
278 git_object_close(obj);
279
720d5472 280cleanup:
7b4a16e2
CMN
281 git_signature_free(tag.tagger);
282 free(tag.tag_name);
283 free(tag.message);
7b4a16e2
CMN
284
285 return error;
286}
287
a50c1458 288int git_tag_create_o(
289 git_oid *oid,
290 git_repository *repo,
291 const char *tag_name,
292 const git_object *target,
293 const git_signature *tagger,
294 const char *message)
295{
296 return tag_create(
297 oid, repo, tag_name,
298 git_object_id(target),
299 git_object_type(target),
300 tagger, message, 0);
301}
302
303int git_tag_create(
304 git_oid *oid,
305 git_repository *repo,
306 const char *tag_name,
307 const git_oid *target,
308 git_otype target_type,
309 const git_signature *tagger,
310 const char *message)
311{
312 return tag_create(
313 oid, repo, tag_name,
314 target,
315 target_type,
316 tagger, message, 0);
317}
318
ac26e245 319int git_tag_create_fo(
a50c1458 320 git_oid *oid,
321 git_repository *repo,
322 const char *tag_name,
323 const git_object *target,
324 const git_signature *tagger,
325 const char *message)
326{
327 return tag_create(
328 oid, repo, tag_name,
329 git_object_id(target),
330 git_object_type(target),
331 tagger, message, 1);
ec25391d
VM
332}
333
a50c1458 334int git_tag_create_f(
335 git_oid *oid,
336 git_repository *repo,
337 const char *tag_name,
338 const git_oid *target,
339 git_otype target_type,
340 const git_signature *tagger,
341 const char *message)
342{
343 return tag_create(
344 oid, repo, tag_name,
345 target,
346 target_type,
347 tagger, message, 1);
348}
ec25391d 349
9e680bcc 350int git_tag_delete(git_repository *repo, const char *tag_name)
351{
352 int error;
353 git_reference *tag_ref;
354 char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
355
356 error = retreive_tag_reference(&tag_ref, ref_name, repo, tag_name);
357 if (error < GIT_SUCCESS)
358 return error;
359
360 return git_reference_delete(tag_ref);
361}
362
72a3fe42 363int git_tag__parse(git_tag *tag, git_odb_object *obj)
f8758044 364{
72a3fe42
VM
365 assert(tag);
366 return parse_tag_buffer(tag, obj->raw.data, (char *)obj->raw.data + obj->raw.len);
f8758044
VM
367}
368