b841847527fe100cb7114304badc5987ed28de4e
[webgit] / src / tag.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
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 "tag.h"
23 #include "object.h"
24 #include "age.h"
25 #include "log.h"
26
27 #include <cwa.h>
28
29 #define SHA1_HEADER <openssl/sha.h>
30 #include "git/cache.h"
31 #include "git/tag.h"
32 //#include "git/commit.h"
33 #include "git/refs.h"
34
35 #include <time.h>
36
37 time_t
38 webgit_tag_date_parse (void* buffer, unsigned long size, struct tm* tm)
39 {
40   struct tm tmp;
41   if (!tm)
42     tm = &tmp;
43
44   char* tagger = cwa_memmem (buffer, size, "tagger ", 7);
45   if (!tagger)
46     return (time_t)-1;
47
48   char* beg = strchr (tagger, '>');
49   if (!beg)
50     return (time_t)-1;
51
52   if (!strptime (beg + 2, "%s %Z", tm))
53     return (time_t)-1;
54
55   return mktime (tm);
56 }
57
58
59 int
60 webgit_tag_type_parse (char* dest, void* buffer, unsigned long size)
61 {
62   char* type = cwa_memmem (buffer, size, "type ", 5);
63   if (!type)
64     return -1;
65
66   char* end = strchr (type, '\n');
67   if (!end)
68     return -1;
69
70   return snprintf (dest, 16, "%.*s", end-type-5, type+5);
71 }
72
73
74 Html
75 webgit_tag_name_parse (void* buffer, unsigned long size)
76 {
77   char* tagger = cwa_memmem (buffer, size, "tagger ", 7);
78   if (!tagger)
79     return NULL;
80
81   char* end = strchr (tagger, '<');
82   if (!end)
83     return NULL;
84
85   return html_fmt ("%.*s", end-tagger-8, tagger+7);
86 }
87
88 Html
89 webgit_tag_email_parse (void* buffer, unsigned long size)
90 {
91   char* tagger = cwa_memmem (buffer, size, "tagger ", 7);
92   if (!tagger)
93     return NULL;
94
95   char* beg = strchr (tagger, '<');
96   if (!beg)
97     return NULL;
98
99   char* end = strchr (beg, '>');
100   if (!end)
101     return NULL;
102
103
104   return html_fmt ("%.*s", end-beg-1, beg+1);
105 }
106
107
108 Html
109 webgit_tag_header_parse (void* buffer, unsigned long size)
110 {
111   char* header = cwa_memmem (buffer, size, "\n\n", 2);
112   if (!header)
113     return NULL;
114
115   char* end = strchr (header+2, '\n');
116   if (!end)
117     end = header + strlen (header+2);
118   else
119     --end;
120
121   return html_fmt ("%.*s", end-header, header+2);
122 }
123
124
125 Html
126 webgit_tag_message_parse (void* buffer, unsigned long size)
127 {
128   char* header = cwa_memmem (buffer, size, "\n\n", 2);
129   if (!header)
130     return NULL;
131
132   char* beg = strchr (header+2, '\n');
133   if (!beg)
134     return html ();
135
136   return html_strndup (beg+1, size - (beg-header) - 1);
137 }
138
139
140 struct tag_context
141 {
142   struct webgit_repo_info* repo;
143   Html table;
144   Html cont;
145   const char* start;
146   int count;
147 };
148
149
150 Html
151 webgit_tag_link (struct webgit_repo_info* repo, const char* tag, int count, Html text)
152 {
153   return html (
154                html_tag ("a",
155                          html_attr ("href", html(
156                                                  html_fmt ("%s?repo=%s&action=tag",
157                                                            repo->query->request->script_name,
158                                                            repo->name),
159                                                  tag ? html_fmt("&ref=%s", tag) : html (),
160                                                  count > 0 ? html_fmt("&count=%d",
161                                                                       count) : html ()
162                                                  )
163                                     )
164                          ),
165                text
166                );
167 }
168
169 static int
170 show_tag_ref (const char *refname, const unsigned char *sha1, int flags, void *data)
171 {
172   struct tag_context* ctx = (struct tag_context*) data;
173   struct webgit_repo_info* repo = ctx->repo;
174
175   if (ctx->start)
176     {
177       if (!strcmp (ctx->start, refname))
178         ctx->start = NULL;
179       else
180         return 0;
181     }
182
183   if (!ctx->count--)
184     {
185       /* displayed query->count lines, finish */
186       html_list_append (ctx->cont,
187                         webgit_tag_link (
188                                          repo, refname,
189                                          repo->query->count,
190                                          html ("More..."))
191                         );
192       return 1;
193     }
194
195   struct tag* tag = lookup_tag (sha1);
196
197   enum object_type type;
198   void *buffer;
199   unsigned long size;
200
201   buffer = read_sha1_file (tag->object.sha1, &type, &size);
202
203   if (!tag->object.parsed)
204     parse_tag_buffer (tag, buffer, size);
205
206   unsigned long date =
207     webgit_tag_date_parse (buffer, size, NULL);
208
209   char tagref[256];
210   snprintf (tagref, 256, "refs/tags/%s", refname);
211
212   struct object* derefed = deref_tag ((struct object*)tag, NULL, 0);
213
214   html_list_append (ctx->table,
215                     html (
216                           html_tag ("tr"),
217                           html (
218                                 html_tag ("td"),
219                                 webgit_object_link (repo->query,
220                                                     repo->name, strlen(repo->name),
221                                                     sha1_to_hex (sha1), 40,
222                                                     NULL,
223                                                     NULL,
224                                                     html_strndup (refname, SIZE_MAX))
225                                 ),
226                           html (
227                                 html_tag ("td"),
228                                 webgit_object_link (repo->query,
229                                                     repo->name, strlen(repo->name),
230                                                     sha1_to_hex (derefed->sha1), 40,
231                                                     NULL,
232                                                     NULL,
233                                                     webgit_pretty_age (repo->query->now - date))
234                                 ),
235                           html (
236                                 html_tag ("td"),
237                                 webgit_email_link (
238                                                    webgit_tag_name_parse (buffer, size),
239                                                    webgit_tag_email_parse (buffer, size)
240                                                    )
241                                 ),
242                           html (
243                                 html_tag ("td"),
244                                 webgit_tag_header_parse (buffer, size)
245                                 ),
246                           html (
247                                 html_tag ("td"),
248                                 webgit_log_link (repo->query,
249                                                  repo->name,
250                                                  tagref,
251                                                  NULL, 0,
252                                                  repo->query->count,
253                                                  html ("Log")),
254                                 webgit_object_link (repo->query,
255                                                     repo->name, strlen(repo->name),
256                                                     sha1_to_hex (derefed->sha1), 40,
257                                                     NULL,
258                                                     "tree",
259                                                     html ("Tree")),
260                                 " Snapshot"
261                                 )
262                           )
263                     );
264   return 0;
265 }
266
267
268 Html
269 webgit_tag_table (struct webgit_repo_info* repo, const char* head, int count)
270 {
271   struct tag_context ctx;
272   ctx.repo = repo;
273   ctx.table = html_list ();
274   ctx.cont = html_list ();
275   ctx.count = count;
276   ctx.start = head;
277
278   for_each_tag_ref (show_tag_ref, &ctx);
279
280   return html (html (html_tag ("table"), ctx.table), ctx.cont);
281 }