]>
Commit | Line | Data |
---|---|---|
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 | |
34 | void 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 |
42 | const git_oid *git_tag_id(git_tag *c) |
43 | { | |
44 | return git_object_id((git_object *)c); | |
f8758044 VM |
45 | } |
46 | ||
6b2a1941 | 47 | int 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 | 53 | const git_oid *git_tag_target_oid(git_tag *t) |
ec25391d | 54 | { |
6b2a1941 VM |
55 | assert(t); |
56 | return &t->target; | |
57 | } | |
58 | ||
f8758044 VM |
59 | git_otype git_tag_type(git_tag *t) |
60 | { | |
58519018 | 61 | assert(t); |
f8758044 VM |
62 | return t->type; |
63 | } | |
64 | ||
f8758044 VM |
65 | const char *git_tag_name(git_tag *t) |
66 | { | |
58519018 | 67 | assert(t); |
f8758044 VM |
68 | return t->tag_name; |
69 | } | |
70 | ||
638c2ca4 | 71 | const git_signature *git_tag_tagger(git_tag *t) |
f8758044 | 72 | { |
f8758044 VM |
73 | return t->tagger; |
74 | } | |
75 | ||
76 | const char *git_tag_message(git_tag *t) | |
77 | { | |
58519018 | 78 | assert(t); |
f8758044 VM |
79 | return t->message; |
80 | } | |
81 | ||
720d5472 | 82 | static 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 | 156 | static 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 | 171 | static 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 |
259 | int 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 | 280 | cleanup: |
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 | 288 | int 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 | ||
303 | int 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 | 319 | int 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 | 334 | int 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 | 350 | int 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 | 363 | int 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 |