Big rename! ctgit is dead, long live webgit
[webgit] / src / object.c
1 /*
2     cehtehs git web frontend
3
4   Copyright (C)
5     2007,               Christian Thaeter <ct@pipapo.org>
6
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License as
9   published by the Free Software Foundation; either version 2 of the
10   License, or (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 General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "object.h"
23 #include "repo.h"
24
25 #define SHA1_HEADER <openssl/sha.h>
26 #include "git/cache.h"
27 #include "git/object.h"
28
29
30 Html
31 webgit_object_link (struct webgit_query* query,
32                    const char* repo,
33                    int repo_len,
34                    const char* object,
35                    int object_len,
36                    Html text)
37 {
38   return html (
39                html_tag ("a",
40                          html_attr ("href", html_fmt ("%s?repo=%.*s&object=%.*s",
41                                                       query->request->script_name,
42                                                       repo_len, repo,
43                                                       object_len, object)
44                                     )
45                          ),
46                text
47                );
48 }
49
50
51
52 /*
53   Display commits
54 */
55
56 static Html
57 webgit_object_commit_menu_action (struct webgit_query* query, unsigned char* sha1, void* buf, unsigned long size)
58 {
59   return html ("TODO: commit-object sidebar");
60 }
61
62 static Html
63 webgit_object_commit_content_action (struct webgit_query* query, unsigned char* sha1, void* buf, unsigned long size)
64 {
65   Html tree = html_list ();
66   Html parents = html_list ();
67   Html author_text = html_list ();
68   Html author = html_list ();
69   Html committer = html_list ();
70
71   const char* author_beg = NULL;
72   const char* author_end = NULL;
73
74   const char* i = buf;
75   while (i && i < buf+size)
76     {
77       if (*i == '\n')
78         {
79           while (*i == '\n')
80             ++i;
81           break; /* message */
82         }
83       if (!strncmp (i, "tree ", 5))
84         {
85
86           html_list_append (tree,
87                             "Tree: ",
88                             webgit_object_link (query,
89                                                query->repo, strlen (query->repo),
90                                                i+5, 40,
91                                                html_fmt ("%.40s", i+5))
92                             );
93
94           (i = strchr (i, '\n')) && ++i;
95           continue;
96         }
97       else if (!strncmp (i, "parent ", 7))
98         {
99           html_list_append (parents, html (
100                                            "Parent: ",
101                                            webgit_object_link (query,
102                                                               query->repo, strlen (query->repo),
103                                                               i+7, 40,
104                                                               html_fmt ("%.40s", i+7))
105                                            )
106                             );
107           (i = strchr (i, '\n')) && ++i;
108           continue;
109         }
110       else if (!strncmp (i, "author ", 7))
111         {
112           char* email_beg = strchr (i, '<');
113           char* email_end = strchr (email_beg, '>');
114
115           author_beg = i+7;
116           author_end = strchr (author_beg, '\n');
117
118           Html name = html_strndup (i+7, email_beg - i - 8);
119           Html email = html_strndup (email_beg + 1, email_end - email_beg - 1);
120
121           struct tm tm;
122           strptime (email_end + 2, "%s %Z", &tm);
123           char pretty_date[256];
124           strftime (pretty_date, 255, "%c", &tm);
125
126           html_list_append (author_text, "Author");
127
128           html_list_append (author, html (
129                                           html ( author_text ), /*BUG: libcwa bug, must be wraped in html()*/
130                                           html (
131                                                 html_tag("a",
132                                                          html_attr ("href",
133                                                                     html ("mailto:", email))
134                                                          ),
135                                                 name
136                                                 ),
137                                           html_strndup (pretty_date, 255)
138                                           )
139                             );
140           (i = strchr (i, '\n')) && ++i;
141           continue;
142         }
143       else if (!strncmp (i, "committer ", 10))
144         {
145           char* email_beg = strchr (i, '<');
146           char* email_end = strchr (email_beg, '>');
147
148           if (author_beg && author_end && strncmp (i + 10, author_beg, author_end - author_beg))
149             {
150               Html name = html_strndup (i+10, email_beg - i - 11);
151               Html email = html_strndup (email_beg + 1, email_end - email_beg - 1);
152
153               struct tm tm;
154               strptime (email_end + 2, "%s %Z", &tm);
155               char pretty_date[256];
156               strftime (pretty_date, 255, "%c", &tm);
157
158               html_list_append (committer, html ("Committer: ",
159                                                  html(
160                                                       html_tag("a",
161                                                                html_attr("href",
162                                                                          html ("mailto:", email))
163                                                                ),
164                                                       name
165                                                       ),
166                                                  html_strndup (pretty_date, 255)
167                                                  )
168                                 );
169             }
170           else
171             html_list_append (author_text, " and Committer");
172
173           (i = strchr (i, '\n')) && ++i;
174           continue;
175         }
176       ++i;
177     }
178
179   html_list_append (author_text, ": ");
180
181   Html headline = html_list ();
182   Html message = html_list ();
183
184   if (i)
185     {
186       const char* message_beg = strchr (i, '\n');
187
188       if (message_beg)
189         {
190           html_list_append (headline,
191                             html_strndup (i, message_beg - i)
192                             );
193
194           while (*message_beg == '\n')
195             ++message_beg;
196
197           html_list_append (message,
198                             html_strndup (message_beg, SIZE_MAX)
199                             );
200         }
201       else
202         {
203           html_list_append (headline,
204                             html_strndup (i, SIZE_MAX)
205                             );
206           html_list_append (message,
207                             html_strndup (i, SIZE_MAX)
208                             );
209         }
210     }
211
212   /* TODO: diffstat */
213
214
215   return html (
216                html (html_tag ("h3"), headline),
217                html (html_tag ("div"), tree), html_nl (),
218                html (html_tag ("div"), parents), html_nl (),
219                html (html_tag ("div"), author), html_nl (),
220                html (html_tag ("div"), committer), html_nl (),
221                html (html_tag ("pre"), message)
222                );
223 }
224
225 Html
226 webgit_object_commit_action (struct webgit_query* query, unsigned char* sha1)
227 {
228   void* buf;
229   unsigned long size;
230
231   buf = read_object_with_reference (sha1, "commit", &size, NULL);
232
233   return html(
234               html(html_tag("div"), webgit_object_commit_menu_action (query, sha1, buf, size)), html_nl (),
235               html(html_tag("div"), webgit_object_commit_content_action (query, sha1, buf, size)), html_nl ()
236               );
237 }
238
239
240 /*
241   Display trees
242 */
243
244 static Html
245 webgit_object_tree_menu_action (struct webgit_query* query, unsigned char* sha1, struct tree *tree)
246 {
247   return html ("TODO: tree-object sidebar");
248 }
249
250 static const char*
251 pretty_mode (unsigned mode)
252 {
253   if (S_ISGITLINK (mode))
254     return "m---------";
255   else if (S_ISDIR (mode & S_IFMT))
256     return "drwxr-xr-x";
257   else if (S_ISLNK (mode))
258     return "lrwxrwxrwx";
259   else if (S_ISREG (mode))
260     {
261       if (mode & S_IXUSR)
262         return "-rwxr-xr-x";
263       else
264         return "-rw-r--r--";
265     }
266   else
267     return "----------";
268 }
269
270 /* callback has no user-data pointer! */
271 static struct webgit_query* query_in_flight = NULL;
272 static Html tree_in_flight = NULL;
273
274 static int
275 webgit_html_tree (const unsigned char *sha1, const char *base, int baselen,
276                  const char *pathname, unsigned mode, int stage)
277 {
278   if (S_ISGITLINK(mode))
279     {
280       html_list_append (tree_in_flight, html (
281                                               html (
282                                                     html_tag ("tr"),
283                                                     html (html_tag ("td"), pretty_mode (mode)),
284                                                     html (html_tag ("td"),
285                                                           webgit_repo_link (query_in_flight,
286                                                                            query_in_flight->repo,
287                                                                            strlen (query_in_flight->repo),
288                                                                            pathname, strlen (pathname),
289                                                                            NULL, 0,
290                                                                            "summary",
291                                                                            html_strndup (pathname, SIZE_MAX))
292                                                           ),
293                                                     html (html_tag ("td"), "history")
294                                                     ),
295                                               html_nl ()
296                                               )
297                         );
298     }
299   else if (S_ISDIR(mode))
300     {
301       html_list_append (tree_in_flight, html (
302                                               html (html_tag ("tr"),
303                                                     html (html_tag ("td"), pretty_mode (mode)),
304                                                     html (html_tag ("td"),
305                                                           webgit_object_link (query_in_flight,
306                                                                              query_in_flight->repo,
307                                                                              strlen (query_in_flight->repo),
308                                                                              sha1_to_hex (sha1), 40,
309                                                                              html_strndup (pathname, SIZE_MAX))
310                                                           ),
311                                                   html (html_tag ("td"), "history snap")
312                                                   ),
313                                              html_nl ()
314                                              )
315                         );
316     }
317   else
318     {
319       html_list_append (tree_in_flight, html (
320                                               html (html_tag ("tr"),
321                                                     html (html_tag ("td"), pretty_mode (mode)),
322                                                     html (html_tag ("td"),
323                                                           webgit_object_link (query_in_flight,
324                                                                              query_in_flight->repo,
325                                                                              strlen (query_in_flight->repo),
326                                                                              sha1_to_hex (sha1), 40,
327                                                                              html_strndup (pathname, SIZE_MAX))
328                                                           ),
329                                                     html (html_tag ("td"), "history raw edit")
330                                                     ),
331                                               html_nl()
332                                               )
333                         );
334     }
335
336   return 0;
337 }
338
339
340 static Html
341 webgit_object_tree_content_action (struct webgit_query* query, unsigned char* sha1, struct tree *tree)
342 {
343   query_in_flight = query;
344   tree_in_flight = html_list ();
345
346   read_tree_recursive (tree, "", 0, 0, NULL, webgit_html_tree);
347
348   return html (html_tag ("table"), tree_in_flight);
349 }
350
351 Html
352 webgit_object_tree_action (struct webgit_query* query, unsigned char* sha1)
353 {
354   struct tree *tree;
355
356   tree = parse_tree_indirect (sha1);
357   if (!tree)
358     die("not a tree object");
359
360   return html(
361               html(html_tag("div"), webgit_object_tree_menu_action (query, sha1, tree)), html_nl (),
362               html(html_tag("div"), webgit_object_tree_content_action (query, sha1, tree)), html_nl ()
363               );
364 }
365
366
367 /*
368   Display blobs
369 */
370
371 static Html
372 webgit_object_blob_menu_action (struct webgit_query* query, unsigned char* sha1, void* buf, unsigned long size)
373 {
374   return html ("TODO: blob-object sidebar");
375 }
376
377 static Html
378 webgit_object_blob_content_action (struct webgit_query* query, unsigned char* sha1, void* buf, unsigned long size)
379 {
380   if (!memchr(buf, 0, size>8192 ? 8192 : size))
381     {
382       return html (html_tag ("pre"), html_strndup (buf, size));
383     }
384   else
385     {
386       return html ("binary blob");
387     }
388 }
389
390
391 Html
392 webgit_object_blob_action (struct webgit_query* query, unsigned char* sha1)
393 {
394   void* buf;
395   unsigned long size;
396
397   buf = read_object_with_reference (sha1, "blob", &size, NULL);
398
399   return html(
400               html(html_tag("div"), webgit_object_blob_menu_action (query, sha1, buf, size)), html_nl (),
401               html(html_tag("div"), webgit_object_blob_content_action (query, sha1, buf, size)), html_nl ()
402               );
403 }
404
405
406
407
408 /*pretty printer for sourcecode*/
409 //Html
410 //webgit_object_blob_dispatch (struct webgit_query* query, const char *sha1);