cf82befe23b511fcf695acd4c55c2645c9a6ae33
[webgit] / src / object_commit.c
1 /*
2     cehtehs git web frontend
3
4   Copyright (C)
5     2007, 2008,         Christian Thaeter <ct@pipapo.org>
6
7   This program is free software: you can redistribute it and/or modify
8   it under the terms of the GNU Affero General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU Affero General Public License for more details.
16
17   You should have received a copy of the GNU Affero General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "object.h"
22 #include "repo.h"
23 #include "actions.h"
24 #include "summary.h"
25
26 char*
27 webgit_object_commit_tree_parse (struct commit* commit)
28 {
29   char* tree = strstr (commit->buffer, "tree ");
30   if (!tree)
31     return NULL;
32   return tree + 5;
33 }
34
35 time_t
36 webgit_object_commit_author_date_parse (struct commit* commit, struct tm* tm)
37 {
38   struct tm tmp;
39   if (!tm)
40     tm = &tmp;
41
42   char* author = strstr (commit->buffer, "author ");
43   if (!author)
44     return (time_t)-1;
45
46   char* beg = strchr (author, '>');
47   if (!beg)
48     return (time_t)-1;
49
50   if (!strptime (beg + 2, "%s %Z", tm))
51     return (time_t)-1;
52
53   return mktime (tm);
54 }
55
56 Html
57 webgit_object_commit_author_name_parse (struct commit* commit)
58 {
59   char* author = strstr (commit->buffer, "author ");
60   if (!author)
61     return NULL;
62
63   char* end = strchr (author, '<');
64   if (!end)
65     return NULL;
66
67   return html_fmt ("%.*s", end-author-8, author+7);
68 }
69
70 Html
71 webgit_object_commit_author_email_parse (struct commit* commit)
72 {
73   char* author = strstr (commit->buffer, "author ");
74   if (!author)
75     return NULL;
76
77   char* beg = strchr (author, '<');
78   if (!beg)
79     return NULL;
80
81   char* end = strchr (beg, '>');
82   if (!end)
83     return NULL;
84
85
86   return html_fmt ("%.*s", end-beg-1, beg+1);
87 }
88
89 time_t
90 webgit_object_commit_committer_date_parse (struct commit* commit, struct tm* tm)
91 {
92   struct tm tmp;
93   if (!tm)
94     tm = &tmp;
95
96   char* committer = strstr (commit->buffer, "committer ");
97   if (!committer)
98     return (time_t)-1;
99
100   char* beg = strchr (committer, '>');
101   if (!beg)
102     return (time_t)-1;
103
104   if (!strptime (beg + 2, "%s %Z", tm))
105     return (time_t)-1;
106
107   return mktime (tm);
108 }
109
110 Html
111 webgit_object_commit_committer_name_parse (struct commit* commit)
112 {
113   char* committer = strstr (commit->buffer, "committer ");
114   if (!committer)
115     return NULL;
116
117   char* end = strchr (committer, '<');
118   if (!end)
119     return NULL;
120
121   return html_fmt ("%.*s", end-committer-11, committer+10);
122 }
123
124 Html
125 webgit_object_commit_committer_email_parse (struct commit* commit)
126 {
127   char* committer = strstr (commit->buffer, "committer ");
128   if (!committer)
129     return NULL;
130
131   char* beg = strchr (committer, '<');
132   if (!beg)
133     return NULL;
134
135   char* end = strchr (beg, '>');
136   if (!end)
137     return NULL;
138
139
140   return html_fmt ("%.*s", end-beg-1, beg+1);
141 }
142
143 Html
144 webgit_object_commit_header_parse (struct commit* commit)
145 {
146   char* header = strstr (commit->buffer, "\n\n");
147   if (!header)
148     return NULL;
149
150   char* end = strchr (header+2, '\n');
151   if (!end)
152     end = header + strlen (header+2);
153   else
154     --end;
155
156   return html_fmt ("%.*s", end-header, header+2);
157 }
158
159 Html
160 webgit_object_commit_message_parse (struct commit* commit)
161 {
162   char* header = strstr (commit->buffer, "\n\n");
163   if (!header)
164     return NULL;
165
166   header = strchr (header+2, '\n');
167   if (!header)
168     return html ();
169   else
170     ++header;
171
172   return html_fmt ("%.*s", strlen (header), header);
173 }
174
175
176 /*
177   Display commits
178 */
179
180 static Html
181 webgit_object_commit_menu_action (struct webgit_repo_info* repo, unsigned char* sha1, void* buf, unsigned long size)
182 {
183   (void) repo;
184   (void) sha1;
185   (void) buf;
186   (void) size;
187   return html (html_tag ("div"),
188                webgit_repo_logo (repo), "<br />",
189                // TODO: "diff against.. <br />",
190                // TODO: "log <br />",
191                // TODO: "create branch <br />",
192                // TODO: "cherry pick? <br />",
193                // TODO: "log <br />",
194                webgit_summary_link (repo->query, repo, html("Summary")), "<br />",
195                webgit_main_link (repo->query, html ("Main"))
196                );
197 }
198
199 static Html
200 webgit_object_commit_content_action (struct webgit_repo_info* repo, unsigned char* sha1, void* buf, unsigned long size)
201 {
202 /*
203   TODO pass commit objects instead buf/size, use parsers from above
204 */
205   (void) sha1;
206
207   Html tree = html_list ();
208   Html parents = html_list ();
209   Html author_text = html_list ();
210   Html author = html_list ();
211   Html committer = html_list ();
212
213   const char* author_beg = NULL;
214   const char* author_end = NULL;
215
216   const char* i = buf;
217   while (i && (void*)i < buf+size)
218     {
219       if (*i == '\n')
220         {
221           while (*i == '\n')
222             ++i;
223           break; /* message */
224         }
225       if (!strncmp (i, "tree ", 5))
226         {
227           html_list_append (tree,
228                             "Tree: ",
229                             webgit_object_link (repo->query,
230                                                 repo->name, strlen (repo->name),
231                                                 i+5, 40,
232                                                 NULL,
233                                                 NULL,
234                                                 html_fmt ("%.40s", i+5))
235                             );
236           if ((i = strchr (i, '\n')))
237             ++i;
238           continue;
239         }
240       else if (!strncmp (i, "parent ", 7))
241         {
242           html_list_append (parents, html (
243                                            "Parent: ",
244                                            webgit_object_link (repo->query,
245                                                                repo->name, strlen (repo->name),
246                                                                i+7, 40,
247                                                                NULL,
248                                                                NULL,
249                                                                html_fmt ("%.40s", i+7))
250                                            )
251                             );
252           if ((i = strchr (i, '\n')))
253             ++i;
254           continue;
255         }
256       else if (!strncmp (i, "author ", 7))
257         {
258           char* email_beg = strchr (i, '<');
259           char* email_end = strchr (email_beg, '>');
260
261           author_beg = i+7;
262           author_end = strchr (author_beg, '\n');
263
264           Html name = html_strndup (i+7, email_beg - i - 8);
265           Html email = html_strndup (email_beg + 1, email_end - email_beg - 1);
266
267           struct tm tm;
268           strptime (email_end + 2, "%s %Z", &tm);
269           char pretty_date[256];
270           strftime (pretty_date, 255, "%c", &tm);
271
272           html_list_append (author_text, "Author");
273
274           html_list_append (author, html (
275                                           html ( author_text ), /*BUG: libcwa bug, must be wraped in html()*/
276                                           webgit_email_link (name, email),
277                                           html_strndup (pretty_date, 255)
278                                           )
279                             );
280           if ((i = strchr (i, '\n')))
281             ++i;
282           continue;
283         }
284       else if (!strncmp (i, "committer ", 10))
285         {
286           char* email_beg = strchr (i, '<');
287           char* email_end = strchr (email_beg, '>');
288
289           if (author_beg && author_end && strncmp (i + 10, author_beg, author_end - author_beg))
290             {
291               Html name = html_strndup (i+10, email_beg - i - 11);
292               Html email = html_strndup (email_beg + 1, email_end - email_beg - 1);
293
294               struct tm tm;
295               strptime (email_end + 2, "%s %Z", &tm);
296               char pretty_date[256];
297               strftime (pretty_date, 255, "%c", &tm);
298
299               html_list_append (committer, html ("Committer: ",
300                                                  webgit_email_link (name, email),
301                                                  html_strndup (pretty_date, 255)
302                                                  )
303                                 );
304             }
305           else
306             html_list_append (author_text, " and Committer");
307
308           if ((i = strchr (i, '\n')))
309             ++i;
310           continue;
311         }
312       ++i;
313     }
314
315   html_list_append (author_text, ": ");
316
317   Html headline = html_list ();
318   Html message = html_list ();
319
320   if (i)
321     {
322       const char* message_beg = strchr (i, '\n');
323
324       if (message_beg)
325         {
326           html_list_append (headline,
327                             html_strndup (i, message_beg - i)
328                             );
329
330           while (*message_beg == '\n')
331             ++message_beg;
332
333           html_list_append (message,
334                             html_strndup (message_beg, SIZE_MAX)
335                             );
336         }
337       else
338         {
339           html_list_append (headline,
340                             html_strndup (i, SIZE_MAX)
341                             );
342           html_list_append (message,
343                             html_strndup (i, SIZE_MAX)
344                             );
345         }
346     }
347
348   /* TODO: diffstat */
349
350
351   return html (
352                html (html_tag ("h3"), headline),
353                html (html_tag ("div"), tree), html_nl (),
354                html (html_tag ("div"), parents), html_nl (),
355                html (html_tag ("div"), author), html_nl (),
356                html (html_tag ("div"), committer), html_nl (),
357                html (html_tag ("pre"), message)
358                );
359 }
360
361 Html
362 webgit_object_commit_action (struct webgit_repo_info* repo, unsigned char* sha1)
363 {
364   void* buf;
365   unsigned long size;
366
367   buf = read_object_with_reference (sha1, "commit", &size, NULL);
368
369   return html(
370               html (html_tag("div", html_attr ("id", "sub-menu")),
371                     webgit_object_commit_menu_action (repo, sha1, buf, size)
372                     ), html_nl (),
373               html (html_tag("div", html_attr ("id", "object-commit")),
374                     webgit_object_commit_content_action (repo, sha1, buf, size)
375                     ), html_nl ()
376               );
377 }
378
379 /*
380 //      Local Variables:
381 //      mode: C
382 //      c-file-style: "gnu"
383 //      indent-tabs-mode: nil
384 //      End:
385 */