webgit_tree_action() dereferences an treeish to the tree object
[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                                           webgit_email_link (name, email),
131                                           html_strndup (pretty_date, 255)
132                                           )
133                             );
134           (i = strchr (i, '\n')) && ++i;
135           continue;
136         }
137       else if (!strncmp (i, "committer ", 10))
138         {
139           char* email_beg = strchr (i, '<');
140           char* email_end = strchr (email_beg, '>');
141
142           if (author_beg && author_end && strncmp (i + 10, author_beg, author_end - author_beg))
143             {
144               Html name = html_strndup (i+10, email_beg - i - 11);
145               Html email = html_strndup (email_beg + 1, email_end - email_beg - 1);
146
147               struct tm tm;
148               strptime (email_end + 2, "%s %Z", &tm);
149               char pretty_date[256];
150               strftime (pretty_date, 255, "%c", &tm);
151
152               html_list_append (committer, html ("Committer: ",
153                                                  webgit_email_link (name, email),
154                                                  html_strndup (pretty_date, 255)
155                                                  )
156                                 );
157             }
158           else
159             html_list_append (author_text, " and Committer");
160
161           (i = strchr (i, '\n')) && ++i;
162           continue;
163         }
164       ++i;
165     }
166
167   html_list_append (author_text, ": ");
168
169   Html headline = html_list ();
170   Html message = html_list ();
171
172   if (i)
173     {
174       const char* message_beg = strchr (i, '\n');
175
176       if (message_beg)
177         {
178           html_list_append (headline,
179                             html_strndup (i, message_beg - i)
180                             );
181
182           while (*message_beg == '\n')
183             ++message_beg;
184
185           html_list_append (message,
186                             html_strndup (message_beg, SIZE_MAX)
187                             );
188         }
189       else
190         {
191           html_list_append (headline,
192                             html_strndup (i, SIZE_MAX)
193                             );
194           html_list_append (message,
195                             html_strndup (i, SIZE_MAX)
196                             );
197         }
198     }
199
200   /* TODO: diffstat */
201
202
203   return html (
204                html (html_tag ("h3"), headline),
205                html (html_tag ("div"), tree), html_nl (),
206                html (html_tag ("div"), parents), html_nl (),
207                html (html_tag ("div"), author), html_nl (),
208                html (html_tag ("div"), committer), html_nl (),
209                html (html_tag ("pre"), message)
210                );
211 }
212
213 Html
214 webgit_object_commit_action (struct webgit_query* query, unsigned char* sha1)
215 {
216   void* buf;
217   unsigned long size;
218
219   buf = read_object_with_reference (sha1, "commit", &size, NULL);
220
221   return html(
222               html(html_tag("div"), webgit_object_commit_menu_action (query, sha1, buf, size)), html_nl (),
223               html(html_tag("div"), webgit_object_commit_content_action (query, sha1, buf, size)), html_nl ()
224               );
225 }
226
227
228 /*
229   Display trees
230 */
231
232 static Html
233 webgit_object_tree_menu_action (struct webgit_query* query, unsigned char* sha1, struct tree *tree)
234 {
235   return html ("TODO: tree-object sidebar");
236 }
237
238 static const char*
239 pretty_mode (unsigned mode)
240 {
241   if (S_ISGITLINK (mode))
242     return "m---------";
243   else if (S_ISDIR (mode & S_IFMT))
244     return "drwxr-xr-x";
245   else if (S_ISLNK (mode))
246     return "lrwxrwxrwx";
247   else if (S_ISREG (mode))
248     {
249       if (mode & S_IXUSR)
250         return "-rwxr-xr-x";
251       else
252         return "-rw-r--r--";
253     }
254   else
255     return "----------";
256 }
257
258 /* callback has no user-data pointer! */
259 static struct webgit_query* query_in_flight = NULL;
260 static Html tree_in_flight = NULL;
261
262 static int
263 webgit_html_tree (const unsigned char *sha1, const char *base, int baselen,
264                  const char *pathname, unsigned mode, int stage)
265 {
266   if (S_ISGITLINK(mode))
267     {
268       html_list_append (tree_in_flight, html (
269                                               html (
270                                                     html_tag ("tr"),
271                                                     html (html_tag ("td"), pretty_mode (mode)),
272                                                     html (html_tag ("td"),
273                                                           webgit_repo_link (query_in_flight,
274                                                                             query_in_flight->repo,
275                                                                             strlen (query_in_flight->repo),
276                                                                             pathname, strlen (pathname),
277                                                                             sha1_to_hex (sha1), 40,
278                                                                             "tree",
279                                                                             html_strndup (pathname, SIZE_MAX))
280                                                           ),
281                                                     html (html_tag ("td"), "history summary")
282                                                     ),
283                                               html_nl ()
284                                               )
285                         );
286     }
287   else if (S_ISDIR(mode))
288     {
289       html_list_append (tree_in_flight, html (
290                                               html (html_tag ("tr"),
291                                                     html (html_tag ("td"), pretty_mode (mode)),
292                                                     html (html_tag ("td"),
293                                                           webgit_object_link (query_in_flight,
294                                                                              query_in_flight->repo,
295                                                                              strlen (query_in_flight->repo),
296                                                                              sha1_to_hex (sha1), 40,
297                                                                              html_strndup (pathname, SIZE_MAX))
298                                                           ),
299                                                   html (html_tag ("td"), "history snap")
300                                                   ),
301                                              html_nl ()
302                                              )
303                         );
304     }
305   else
306     {
307       html_list_append (tree_in_flight, html (
308                                               html (html_tag ("tr"),
309                                                     html (html_tag ("td"), pretty_mode (mode)),
310                                                     html (html_tag ("td"),
311                                                           webgit_object_link (query_in_flight,
312                                                                              query_in_flight->repo,
313                                                                              strlen (query_in_flight->repo),
314                                                                              sha1_to_hex (sha1), 40,
315                                                                              html_strndup (pathname, SIZE_MAX))
316                                                           ),
317                                                     html (html_tag ("td"), "history raw edit")
318                                                     ),
319                                               html_nl()
320                                               )
321                         );
322     }
323
324   return 0;
325 }
326
327
328 static Html
329 webgit_object_tree_content_action (struct webgit_query* query, unsigned char* sha1, struct tree *tree)
330 {
331   query_in_flight = query;
332   tree_in_flight = html_list ();
333
334   read_tree_recursive (tree, "", 0, 0, NULL, webgit_html_tree);
335
336   return html (html_tag ("table"), tree_in_flight);
337 }
338
339 Html
340 webgit_object_tree_action (struct webgit_query* query, unsigned char* sha1)
341 {
342   struct tree *tree;
343
344   tree = parse_tree_indirect (sha1);
345   if (!tree)
346     die("not a tree object");
347
348   return html(
349               html(html_tag("div"), webgit_object_tree_menu_action (query, sha1, tree)), html_nl (),
350               html(html_tag("div"), webgit_object_tree_content_action (query, sha1, tree)), html_nl ()
351               );
352 }
353
354
355 /*
356   Display blobs
357 */
358
359 static Html
360 webgit_object_blob_menu_action (struct webgit_query* query, unsigned char* sha1, void* buf, unsigned long size)
361 {
362   return html ("TODO: blob-object sidebar");
363 }
364
365 static Html
366 webgit_object_blob_content_action (struct webgit_query* query, unsigned char* sha1, void* buf, unsigned long size)
367 {
368   if (!memchr(buf, 0, size>8192 ? 8192 : size))
369     {
370       return html (html_tag ("pre"), html_strndup (buf, size));
371     }
372   else
373     {
374       return html ("binary blob");
375     }
376 }
377
378
379 Html
380 webgit_object_blob_action (struct webgit_query* query, unsigned char* sha1)
381 {
382   void* buf;
383   unsigned long size;
384
385   buf = read_object_with_reference (sha1, "blob", &size, NULL);
386
387   return html(
388               html(html_tag("div"), webgit_object_blob_menu_action (query, sha1, buf, size)), html_nl (),
389               html(html_tag("div"), webgit_object_blob_content_action (query, sha1, buf, size)), html_nl ()
390               );
391 }
392
393
394
395
396 /*pretty printer for sourcecode*/
397 //Html
398 //webgit_object_blob_dispatch (struct webgit_query* query, const char *sha1);