]>
Commit | Line | Data |
---|---|---|
06160502 | 1 | /* |
50298f44 SP |
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. | |
06160502 | 5 | * |
50298f44 SP |
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.) | |
06160502 | 14 | * |
50298f44 SP |
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. | |
06160502 | 19 | * |
50298f44 SP |
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. | |
06160502 SP |
24 | */ |
25 | ||
44908fe7 VM |
26 | #include "git2/common.h" |
27 | #include "git2/object.h" | |
28 | #include "git2/repository.h" | |
638c2ca4 | 29 | #include "git2/signature.h" |
58519018 | 30 | |
64a47c01 | 31 | #include "common.h" |
72a3fe42 | 32 | #include "odb.h" |
4f0adcd0 | 33 | #include "commit.h" |
638c2ca4 | 34 | #include "signature.h" |
06160502 | 35 | |
72a3fe42 VM |
36 | #include <stdarg.h> |
37 | ||
0c3596f1 VM |
38 | #define COMMIT_BASIC_PARSE 0x0 |
39 | #define COMMIT_FULL_PARSE 0x1 | |
40 | ||
1f798df2 | 41 | #define COMMIT_PRINT(commit) {\ |
52f2390b VM |
42 | char oid[41]; oid[40] = 0;\ |
43 | git_oid_fmt(oid, &commit->object.id);\ | |
44 | printf("Oid: %s | In degree: %d | Time: %u\n", oid, commit->in_degree, commit->commit_time);\ | |
1f798df2 VM |
45 | } |
46 | ||
3315782c VM |
47 | static void clear_parents(git_commit *commit) |
48 | { | |
584f49a5 VM |
49 | unsigned int i; |
50 | ||
6b2a1941 VM |
51 | for (i = 0; i < commit->parent_oids.length; ++i) { |
52 | git_oid *parent = git_vector_get(&commit->parent_oids, i); | |
53 | free(parent); | |
584f49a5 VM |
54 | } |
55 | ||
6b2a1941 | 56 | git_vector_clear(&commit->parent_oids); |
3315782c VM |
57 | } |
58 | ||
40721f6b VM |
59 | void git_commit__free(git_commit *commit) |
60 | { | |
3315782c | 61 | clear_parents(commit); |
6b2a1941 | 62 | git_vector_free(&commit->parent_oids); |
52f2390b | 63 | |
638c2ca4 VM |
64 | git_signature_free(commit->author); |
65 | git_signature_free(commit->committer); | |
58519018 | 66 | |
52f2390b VM |
67 | free(commit->message); |
68 | free(commit->message_short); | |
40721f6b VM |
69 | free(commit); |
70 | } | |
71 | ||
6533aadc | 72 | const git_oid *git_commit_id(git_commit *c) |
06160502 | 73 | { |
d45b4a9a | 74 | return git_object_id((git_object *)c); |
06160502 | 75 | } |
417f0abc | 76 | |
72a3fe42 VM |
77 | |
78 | int git_commit_create_v( | |
79 | git_oid *oid, | |
80 | git_repository *repo, | |
81 | const char *update_ref, | |
82 | const git_signature *author, | |
83 | const git_signature *committer, | |
84 | const char *message, | |
85 | const git_oid *tree_oid, | |
86 | int parent_count, | |
87 | ...) | |
0c3596f1 | 88 | { |
72a3fe42 VM |
89 | va_list ap; |
90 | int i, error; | |
91 | const git_oid **oids; | |
0c3596f1 | 92 | |
72a3fe42 | 93 | oids = git__malloc(parent_count * sizeof(git_oid *)); |
0c3596f1 | 94 | |
72a3fe42 VM |
95 | va_start(ap, parent_count); |
96 | for (i = 0; i < parent_count; ++i) | |
97 | oids[i] = va_arg(ap, const git_oid *); | |
98 | va_end(ap); | |
0c3596f1 | 99 | |
72a3fe42 VM |
100 | error = git_commit_create( |
101 | oid, repo, update_ref, author, committer, message, | |
102 | tree_oid, parent_count, oids); | |
103 | ||
104 | free(oids); | |
105 | return error; | |
106 | } | |
107 | ||
108 | int git_commit_create_ov( | |
109 | git_oid *oid, | |
110 | git_repository *repo, | |
111 | const char *update_ref, | |
112 | const git_signature *author, | |
113 | const git_signature *committer, | |
114 | const char *message, | |
115 | const git_tree *tree, | |
116 | int parent_count, | |
117 | ...) | |
118 | { | |
119 | va_list ap; | |
120 | int i, error; | |
121 | const git_oid **oids; | |
122 | ||
123 | oids = git__malloc(parent_count * sizeof(git_oid *)); | |
124 | ||
125 | va_start(ap, parent_count); | |
126 | for (i = 0; i < parent_count; ++i) | |
127 | oids[i] = git_object_id(va_arg(ap, const git_object *)); | |
128 | va_end(ap); | |
129 | ||
130 | error = git_commit_create( | |
131 | oid, repo, update_ref, author, committer, message, | |
132 | git_object_id((git_object *)tree), | |
133 | parent_count, oids); | |
134 | ||
135 | free(oids); | |
136 | return error; | |
137 | } | |
138 | ||
139 | int git_commit_create_o( | |
140 | git_oid *oid, | |
141 | git_repository *repo, | |
142 | const char *update_ref, | |
143 | const git_signature *author, | |
144 | const git_signature *committer, | |
145 | const char *message, | |
146 | const git_tree *tree, | |
147 | int parent_count, | |
148 | const git_commit *parents[]) | |
149 | { | |
150 | int i, error; | |
151 | const git_oid **oids; | |
152 | ||
153 | oids = git__malloc(parent_count * sizeof(git_oid *)); | |
154 | ||
155 | for (i = 0; i < parent_count; ++i) | |
156 | oids[i] = git_object_id((git_object *)parents[i]); | |
157 | ||
158 | error = git_commit_create( | |
159 | oid, repo, update_ref, author, committer, message, | |
160 | git_object_id((git_object *)tree), | |
161 | parent_count, oids); | |
162 | ||
163 | free(oids); | |
164 | return error; | |
165 | } | |
0c3596f1 | 166 | |
72a3fe42 VM |
167 | int git_commit_create( |
168 | git_oid *oid, | |
169 | git_repository *repo, | |
170 | const char *update_ref, | |
171 | const git_signature *author, | |
172 | const git_signature *committer, | |
173 | const char *message, | |
174 | const git_oid *tree_oid, | |
175 | int parent_count, | |
176 | const git_oid *parents[]) | |
177 | { | |
178 | size_t final_size = 0; | |
179 | int message_length, author_length, committer_length; | |
180 | ||
181 | char *author_str, *committer_str; | |
182 | ||
183 | int error, i; | |
184 | git_odb_stream *stream; | |
185 | ||
186 | message_length = strlen(message); | |
187 | author_length = git_signature__write(&author_str, "author", author); | |
188 | committer_length = git_signature__write(&committer_str, "committer", committer); | |
189 | ||
190 | if (author_length < 0 || committer_length < 0) | |
191 | return GIT_ENOMEM; | |
192 | ||
193 | final_size += GIT_OID_LINE_LENGTH("tree"); | |
194 | final_size += GIT_OID_LINE_LENGTH("parent") * parent_count; | |
195 | final_size += author_length; | |
196 | final_size += committer_length; | |
197 | final_size += 1 + message_length; | |
198 | ||
199 | if ((error = git_odb_open_wstream(&stream, repo->db, final_size, GIT_OBJ_COMMIT)) < GIT_SUCCESS) | |
200 | return error; | |
201 | ||
202 | git__write_oid(stream, "tree", tree_oid); | |
0c3596f1 | 203 | |
72a3fe42 VM |
204 | for (i = 0; i < parent_count; ++i) |
205 | git__write_oid(stream, "parent", parents[i]); | |
0c3596f1 | 206 | |
72a3fe42 VM |
207 | stream->write(stream, author_str, author_length); |
208 | free(author_str); | |
0c3596f1 | 209 | |
72a3fe42 VM |
210 | stream->write(stream, committer_str, committer_length); |
211 | free(committer_str); | |
0c3596f1 | 212 | |
72a3fe42 VM |
213 | |
214 | stream->write(stream, "\n", 1); | |
215 | stream->write(stream, message, message_length); | |
216 | ||
217 | error = stream->finalize_write(oid, stream); | |
218 | stream->free(stream); | |
219 | ||
220 | if (error == GIT_SUCCESS && update_ref != NULL) { | |
221 | git_reference *head; | |
222 | ||
223 | error = git_reference_lookup(&head, repo, update_ref); | |
224 | if (error < GIT_SUCCESS) | |
225 | return error; | |
226 | ||
227 | if (git_reference_type(head) == GIT_REF_SYMBOLIC) { | |
228 | if ((error = git_reference_resolve(&head, head)) < GIT_SUCCESS) | |
229 | return error; | |
230 | } | |
231 | ||
232 | error = git_reference_set_oid(head, oid); | |
6b2a1941 | 233 | } |
57450775 | 234 | |
72a3fe42 | 235 | return error; |
0c3596f1 VM |
236 | } |
237 | ||
6b2a1941 | 238 | int commit_parse_buffer(git_commit *commit, void *data, size_t len) |
417f0abc | 239 | { |
9b3577ed VM |
240 | char *buffer = (char *)data; |
241 | const char *buffer_end = (char *)data + len; | |
417f0abc | 242 | |
6b2a1941 | 243 | git_oid parent_oid; |
1795f879 | 244 | int error; |
417f0abc | 245 | |
72a3fe42 | 246 | git_vector_init(&commit->parent_oids, 4, NULL); |
eec95235 | 247 | |
6b2a1941 | 248 | if ((error = git__parse_oid(&commit->tree_oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS) |
1795f879 | 249 | return error; |
225fe215 | 250 | |
9b3577ed | 251 | /* |
9b3577ed VM |
252 | * TODO: commit grafts! |
253 | */ | |
417f0abc | 254 | |
6b2a1941 VM |
255 | while (git__parse_oid(&parent_oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) { |
256 | git_oid *new_oid; | |
417f0abc | 257 | |
6b2a1941 VM |
258 | new_oid = git__malloc(sizeof(git_oid)); |
259 | git_oid_cpy(new_oid, &parent_oid); | |
417f0abc | 260 | |
6b2a1941 | 261 | if (git_vector_insert(&commit->parent_oids, new_oid) < GIT_SUCCESS) |
de141d4b | 262 | return GIT_ENOMEM; |
9b3577ed | 263 | } |
417f0abc | 264 | |
6b2a1941 VM |
265 | commit->author = git__malloc(sizeof(git_signature)); |
266 | if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS) | |
267 | return error; | |
52f2390b | 268 | |
58519018 | 269 | /* Always parse the committer; we need the commit time */ |
638c2ca4 VM |
270 | commit->committer = git__malloc(sizeof(git_signature)); |
271 | if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ")) < GIT_SUCCESS) | |
1795f879 | 272 | return error; |
58519018 | 273 | |
52f2390b VM |
274 | /* parse commit message */ |
275 | while (buffer <= buffer_end && *buffer == '\n') | |
276 | buffer++; | |
277 | ||
6b2a1941 | 278 | if (buffer < buffer_end) { |
69f0295c | 279 | const char *line_end; |
0c3596f1 | 280 | size_t message_len = buffer_end - buffer; |
52f2390b | 281 | |
1081d909 | 282 | /* Long message */ |
0c3596f1 VM |
283 | message_len = buffer_end - buffer; |
284 | commit->message = git__malloc(message_len + 1); | |
285 | memcpy(commit->message, buffer, message_len); | |
286 | commit->message[message_len] = 0; | |
52f2390b | 287 | |
1081d909 CT |
288 | /* Short message */ |
289 | if((line_end = memchr(buffer, '\n', buffer_end - buffer)) == NULL) | |
290 | line_end = buffer_end; | |
0c3596f1 | 291 | message_len = line_end - buffer; |
52f2390b | 292 | |
0c3596f1 VM |
293 | commit->message_short = git__malloc(message_len + 1); |
294 | memcpy(commit->message_short, buffer, message_len); | |
295 | commit->message_short[message_len] = 0; | |
52f2390b | 296 | } |
417f0abc | 297 | |
1795f879 | 298 | return GIT_SUCCESS; |
417f0abc | 299 | } |
4caa8962 | 300 | |
72a3fe42 | 301 | int git_commit__parse(git_commit *commit, git_odb_object *obj) |
58519018 | 302 | { |
72a3fe42 VM |
303 | assert(commit); |
304 | return commit_parse_buffer(commit, obj->raw.data, obj->raw.len); | |
58519018 VM |
305 | } |
306 | ||
6b2a1941 VM |
307 | #define GIT_COMMIT_GETTER(_rvalue, _name, _return) \ |
308 | _rvalue git_commit_##_name(git_commit *commit) \ | |
0c3596f1 | 309 | {\ |
58519018 | 310 | assert(commit); \ |
6b2a1941 | 311 | return _return; \ |
0c3596f1 VM |
312 | } |
313 | ||
6b2a1941 VM |
314 | GIT_COMMIT_GETTER(const git_signature *, author, commit->author) |
315 | GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer) | |
316 | GIT_COMMIT_GETTER(const char *, message, commit->message) | |
317 | GIT_COMMIT_GETTER(const char *, message_short, commit->message_short) | |
318 | GIT_COMMIT_GETTER(time_t, time, commit->committer->when.time) | |
319 | GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset) | |
320 | GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length) | |
321 | ||
322 | ||
323 | int git_commit_tree(git_tree **tree_out, git_commit *commit) | |
324 | { | |
325 | assert(commit); | |
326 | return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_oid); | |
327 | } | |
57450775 | 328 | |
6b2a1941 | 329 | int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n) |
48c27f86 | 330 | { |
6b2a1941 | 331 | git_oid *parent_oid; |
48c27f86 VM |
332 | assert(commit); |
333 | ||
6b2a1941 VM |
334 | parent_oid = git_vector_get(&commit->parent_oids, n); |
335 | if (parent_oid == NULL) | |
336 | return GIT_ENOTFOUND; | |
48c27f86 | 337 | |
6b2a1941 | 338 | return git_commit_lookup(parent, commit->object.repo, parent_oid); |
48c27f86 VM |
339 | } |
340 | ||
0c3596f1 | 341 |