]> git.proxmox.com Git - libgit2.git/blame - src/commit.c
I broke your bindings
[libgit2.git] / src / commit.c
CommitLineData
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
47static 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
59void 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 72const 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
78int 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
108int 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
139int 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
167int 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 238int 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 301int 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
314GIT_COMMIT_GETTER(const git_signature *, author, commit->author)
315GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer)
316GIT_COMMIT_GETTER(const char *, message, commit->message)
317GIT_COMMIT_GETTER(const char *, message_short, commit->message_short)
318GIT_COMMIT_GETTER(time_t, time, commit->committer->when.time)
319GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset)
320GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length)
321
322
323int 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 329int 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