first crude blob display
[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 ctgit_object_link (struct ctgit_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   Display committs
53 */
54
55 static Html
56 ctgit_object_commit_menu_action (struct ctgit_query* query, unsigned char* sha1, void* buf, unsigned long size)
57 {
58   return html ("TODO: commit-object sidebar");
59 }
60
61 static Html
62 ctgit_object_commit_content_action (struct ctgit_query* query, unsigned char* sha1, void* buf, unsigned long size)
63 {
64   Html tree = html_list ();
65   Html parents = html_list ();
66   Html author_text = html_list ();
67   Html author = html_list ();
68   Html committer = html_list ();
69
70   const char* author_beg = NULL;
71   const char* author_end = NULL;
72
73   const char* i = buf;
74   while (i && i < buf+size)
75     {
76       if (*i == '\n')
77         {
78           while (*i == '\n')
79             ++i;
80           break; /* message */
81         }
82       if (!strncmp (i, "tree ", 5))
83         {
84
85           html_list_append (tree,
86                             "Tree: ",
87                             ctgit_object_link (query,
88                                                query->repo, strlen (query->repo),
89                                                i+5, 40,
90                                                html_fmt ("%.40s", i+5))
91                             );
92
93           (i = strchr (i, '\n')) && ++i;
94           continue;
95         }
96       else if (!strncmp (i, "parent ", 7))
97         {
98           html_list_append (parents, html (
99                                            "Parent: ",
100                                            ctgit_object_link (query,
101                                                               query->repo, strlen (query->repo),
102                                                               i+7, 40,
103                                                               html_fmt ("%.40s", i+7))
104                                            )
105                             );
106           (i = strchr (i, '\n')) && ++i;
107           continue;
108         }
109       else if (!strncmp (i, "author ", 7))
110         {
111           char* email_beg = strchr (i, '<');
112           char* email_end = strchr (email_beg, '>');
113
114           author_beg = i+7;
115           author_end = strchr (author_beg, '\n');
116
117           Html name = html_strndup (i+7, email_beg - i - 8);
118           Html email = html_strndup (email_beg + 1, email_end - email_beg - 1);
119
120           struct tm tm;
121           strptime (email_end + 2, "%s %Z", &tm);
122           char pretty_date[256];
123           strftime (pretty_date, 255, "%c", &tm);
124
125           html_list_append (author_text, "Author");
126
127           html_list_append (author, html (
128                                           html ( author_text ), /*BUG: libcwa bug, must be wraped in html()*/
129                                           html (
130                                                 html_tag("a",
131                                                          html_attr ("href",
132                                                                     html ("mailto:", email))
133                                                          ),
134                                                 name
135                                                 ),
136                                           html_strndup (pretty_date, 255)
137                                           )
138                             );
139           (i = strchr (i, '\n')) && ++i;
140           continue;
141         }
142       else if (!strncmp (i, "committer ", 10))
143         {
144           char* email_beg = strchr (i, '<');
145           char* email_end = strchr (email_beg, '>');
146
147           if (author_beg && author_end && strncmp (i + 10, author_beg, author_end - author_beg))
148             {
149               Html name = html_strndup (i+10, email_beg - i - 11);
150               Html email = html_strndup (email_beg + 1, email_end - email_beg - 1);
151
152               struct tm tm;
153               strptime (email_end + 2, "%s %Z", &tm);
154               char pretty_date[256];
155               strftime (pretty_date, 255, "%c", &tm);
156
157               html_list_append (committer, html ("Committer: ",
158                                                  html(
159                                                       html_tag("a",
160                                                                html_attr("href",
161                                                                          html ("mailto:", email))
162                                                                ),
163                                                       name
164                                                       ),
165                                                  html_strndup (pretty_date, 255)
166                                                  )
167                                 );
168             }
169           else
170             html_list_append (author_text, " and Committer");
171
172           (i = strchr (i, '\n')) && ++i;
173           continue;
174         }
175       ++i;
176     }
177
178   html_list_append (author_text, ": ");
179
180
181
182   Html headline = html_list ();
183   Html message = html_list ();
184
185   if (i)
186     {
187       const char* message_beg = strchr (i, '\n');
188
189       if (message_beg)
190         {
191           html_list_append (headline,
192                             html_strndup (i, message_beg - i)
193                             );
194
195           while (*message_beg == '\n')
196             ++message_beg;
197
198           html_list_append (message,
199                             html_strndup (message_beg, SIZE_MAX)
200                             );
201         }
202       else
203         {
204           html_list_append (headline,
205                             html_strndup (i, SIZE_MAX)
206                             );
207           html_list_append (message,
208                             html_strndup (i, SIZE_MAX)
209                             );
210         }
211     }
212
213   /* diffstat */
214
215
216   return html (
217                html (html_tag ("h3"), headline),
218                html (html_tag ("div"), tree), html_nl (),
219                html (html_tag ("div"), parents), html_nl (),
220                html (html_tag ("div"), author), html_nl (),
221                html (html_tag ("div"), committer), html_nl (),
222                html (html_tag ("pre"), message)
223                );
224 }
225
226 Html
227 ctgit_object_commit_action (struct ctgit_query* query, unsigned char* sha1)
228 {
229   void* buf;
230   unsigned long size;
231
232   buf = read_object_with_reference (sha1, "commit", &size, NULL);
233
234   return html(
235               html(html_tag("div"), ctgit_object_commit_menu_action (query, sha1, buf, size)), html_nl (),
236               html(html_tag("div"), ctgit_object_commit_content_action (query, sha1, buf, size)), html_nl ()
237               );
238 }
239
240 /*
241   Display trees
242 */
243
244 static Html
245 ctgit_object_tree_menu_action (struct ctgit_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 ctgit_query* query_in_flight = NULL;
272 static Html tree_in_flight = NULL;
273
274 static int
275 ctgit_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                                                           ctgit_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                                                           ctgit_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                                                           ctgit_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
341 static Html
342 ctgit_object_tree_content_action (struct ctgit_query* query, unsigned char* sha1, struct tree *tree)
343 {
344   query_in_flight = query;
345   tree_in_flight = html_list ();
346
347   read_tree_recursive (tree, "", 0, 0, NULL, ctgit_html_tree);
348
349   return html (html_tag ("table"), tree_in_flight);
350 }
351
352 Html
353 ctgit_object_tree_action (struct ctgit_query* query, unsigned char* sha1)
354 {
355   struct tree *tree;
356
357   tree = parse_tree_indirect (sha1);
358   if (!tree)
359     die("not a tree object");
360
361   return html(
362               html(html_tag("div"), ctgit_object_tree_menu_action (query, sha1, tree)), html_nl (),
363               html(html_tag("div"), ctgit_object_tree_content_action (query, sha1, tree)), html_nl ()
364               );
365 }
366
367 /*
368   Display blobs
369 */
370
371 static Html
372 ctgit_object_blob_menu_action (struct ctgit_query* query, unsigned char* sha1, void* buf, unsigned long size)
373 {
374   return html ("TODO: blob-object sidebar");
375 }
376
377 static Html
378 ctgit_object_blob_content_action (struct ctgit_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 ctgit_object_blob_action (struct ctgit_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"), ctgit_object_blob_menu_action (query, sha1, buf, size)), html_nl (),
401               html(html_tag("div"), ctgit_object_blob_content_action (query, sha1, buf, size)), html_nl ()
402               );
403 }
404
405
406
407
408
409 /*pretty printer for sourcecode*/
410 //Html
411 //ctgit_object_blob_dispatch (struct ctgit_query* query, const char *sha1);