summaryrefslogtreecommitdiffabout
path: root/cgit.c
authorLars Hjemli <hjemli@gmail.com>2006-12-10 21:31:36 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2006-12-10 21:31:36 (UTC)
commit25105d7ecaba474d4b7c364ebb586aac3dfc5abb (patch) (unidiff)
tree8beb08db1399b8efb8c7fbcd936044ae7fc232e6 /cgit.c
parent856c026e221d8ed82c5b75bc8da4bd65e89ea953 (diff)
downloadcgit-25105d7ecaba474d4b7c364ebb586aac3dfc5abb.zip
cgit-25105d7ecaba474d4b7c364ebb586aac3dfc5abb.tar.gz
cgit-25105d7ecaba474d4b7c364ebb586aac3dfc5abb.tar.bz2
Add caching infrastructure
This enables internal caching of page output. Page requests are split into four groups: 1) repo listing (front page) 2) repo summary 3) repo pages w/symbolic references in query string 4) repo pages w/constant sha1's in query string Each group has a TTL specified in minutes. When a page is requested, a cached filename is stat(2)'ed and st_mtime is compared to time(2). If TTL has expired (or the file didn't exist), the cached file is regenerated. When generating a cached file, locking is used to avoid parallell processing of the request. If multiple processes tries to aquire the same lock, the ones who fail to get the lock serves the (expired) cached file. If the cached file don't exist, the process instead calls sched_yield(2) before restarting the request processing. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (limited to 'cgit.c') (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c117
1 files changed, 102 insertions, 15 deletions
diff --git a/cgit.c b/cgit.c
index 4c14f77..09c857c 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,410 +1,497 @@
1#include "cgit.h" 1#include "cgit.h"
2 2
3static const char cgit_doctype[] = 3static const char cgit_doctype[] =
4"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" 4"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
5" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"; 5" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
6 6
7static const char cgit_error[] = 7static const char cgit_error[] =
8"<div class='error'>%s</div>"; 8"<div class='error'>%s</div>";
9 9
10static const char cgit_lib_error[] = 10static const char cgit_lib_error[] =
11"<div class='error'>%s: %s</div>"; 11"<div class='error'>%s: %s</div>";
12 12
13int htmlfd = 0;
13 14
14char *cgit_root = "/var/git"; 15char *cgit_root = "/usr/src/git";
15char *cgit_root_title = "Git repository browser"; 16char *cgit_root_title = "Git repository browser";
16char *cgit_css = "/cgit.css"; 17char *cgit_css = "/cgit.css";
17char *cgit_logo = "/git-logo.png"; 18char *cgit_logo = "/git-logo.png";
18char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/"; 19char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/";
19char *cgit_virtual_root = NULL; 20char *cgit_virtual_root = NULL;
20 21
22char *cgit_cache_root = "/var/cache/cgit";
23
24int cgit_cache_root_ttl = 5;
25int cgit_cache_repo_ttl = 5;
26int cgit_cache_dynamic_ttl = 5;
27int cgit_cache_static_ttl = -1;
28int cgit_cache_max_create_time = 5;
29
21char *cgit_repo_name = NULL; 30char *cgit_repo_name = NULL;
22char *cgit_repo_desc = NULL; 31char *cgit_repo_desc = NULL;
23char *cgit_repo_owner = NULL; 32char *cgit_repo_owner = NULL;
24 33
34int cgit_query_has_symref = 0;
35int cgit_query_has_sha1 = 0;
36
37char *cgit_querystring = NULL;
25char *cgit_query_repo = NULL; 38char *cgit_query_repo = NULL;
26char *cgit_query_page = NULL; 39char *cgit_query_page = NULL;
27char *cgit_query_head = NULL; 40char *cgit_query_head = NULL;
41char *cgit_query_sha1 = NULL;
42
43struct cacheitem cacheitem;
28 44
29int cgit_parse_query(char *txt, configfn fn) 45int cgit_parse_query(char *txt, configfn fn)
30{ 46{
31 char *t = txt, *value = NULL, c; 47 char *t, *value = NULL, c;
32 48
33 if (!txt) 49 if (!txt)
34 return 0; 50 return 0;
35 51
52 t = txt = xstrdup(txt);
53
36 while((c=*t) != '\0') { 54 while((c=*t) != '\0') {
37 if (c=='=') { 55 if (c=='=') {
38 *t = '\0'; 56 *t = '\0';
39 value = t+1; 57 value = t+1;
40 } else if (c=='&') { 58 } else if (c=='&') {
41 *t = '\0'; 59 *t = '\0';
42 (*fn)(txt, value); 60 (*fn)(txt, value);
43 txt = t+1; 61 txt = t+1;
44 value = NULL; 62 value = NULL;
45 } 63 }
46 t++; 64 t++;
47 } 65 }
48 if (t!=txt) 66 if (t!=txt)
49 (*fn)(txt, value); 67 (*fn)(txt, value);
50 return 0; 68 return 0;
51} 69}
52 70
53void cgit_global_config_cb(const char *name, const char *value) 71void cgit_global_config_cb(const char *name, const char *value)
54{ 72{
55 if (!strcmp(name, "root")) 73 if (!strcmp(name, "root"))
56 cgit_root = xstrdup(value); 74 cgit_root = xstrdup(value);
57 else if (!strcmp(name, "root-title")) 75 else if (!strcmp(name, "root-title"))
58 cgit_root_title = xstrdup(value); 76 cgit_root_title = xstrdup(value);
59 else if (!strcmp(name, "css")) 77 else if (!strcmp(name, "css"))
60 cgit_css = xstrdup(value); 78 cgit_css = xstrdup(value);
61 else if (!strcmp(name, "logo")) 79 else if (!strcmp(name, "logo"))
62 cgit_logo = xstrdup(value); 80 cgit_logo = xstrdup(value);
63 else if (!strcmp(name, "logo-link")) 81 else if (!strcmp(name, "logo-link"))
64 cgit_logo_link = xstrdup(value); 82 cgit_logo_link = xstrdup(value);
65 else if (!strcmp(name, "virtual-root")) 83 else if (!strcmp(name, "virtual-root"))
66 cgit_virtual_root = xstrdup(value); 84 cgit_virtual_root = xstrdup(value);
67} 85}
68 86
69void cgit_repo_config_cb(const char *name, const char *value) 87void cgit_repo_config_cb(const char *name, const char *value)
70{ 88{
71 if (!strcmp(name, "name")) 89 if (!strcmp(name, "name"))
72 cgit_repo_name = xstrdup(value); 90 cgit_repo_name = xstrdup(value);
73 else if (!strcmp(name, "desc")) 91 else if (!strcmp(name, "desc"))
74 cgit_repo_desc = xstrdup(value); 92 cgit_repo_desc = xstrdup(value);
75 else if (!strcmp(name, "owner")) 93 else if (!strcmp(name, "owner"))
76 cgit_repo_owner = xstrdup(value); 94 cgit_repo_owner = xstrdup(value);
77} 95}
78 96
79void cgit_querystring_cb(const char *name, const char *value) 97void cgit_querystring_cb(const char *name, const char *value)
80{ 98{
81 if (!strcmp(name,"r")) 99 if (!strcmp(name,"r"))
82 cgit_query_repo = xstrdup(value); 100 cgit_query_repo = xstrdup(value);
83 else if (!strcmp(name, "p")) 101 else if (!strcmp(name, "p"))
84 cgit_query_page = xstrdup(value); 102 cgit_query_page = xstrdup(value);
85 else if (!strcmp(name, "h")) 103 else if (!strcmp(name, "h")) {
86 cgit_query_head = xstrdup(value); 104 cgit_query_head = xstrdup(value);
105 cgit_query_has_symref = 1;
106 } else if (!strcmp(name, "id")) {
107 cgit_query_sha1 = xstrdup(value);
108 cgit_query_has_sha1 = 1;
109 }
87} 110}
88 111
89char *cgit_repourl(const char *reponame) 112char *cgit_repourl(const char *reponame)
90{ 113{
91 if (cgit_virtual_root) { 114 if (cgit_virtual_root) {
92 return fmt("%s/%s/", cgit_virtual_root, reponame); 115 return fmt("%s/%s/", cgit_virtual_root, reponame);
93 } else { 116 } else {
94 return fmt("?r=%s", reponame); 117 return fmt("?r=%s", reponame);
95 } 118 }
96} 119}
97 120
98char *cgit_pageurl(const char *reponame, const char *pagename, 121char *cgit_pageurl(const char *reponame, const char *pagename,
99 const char *query) 122 const char *query)
100{ 123{
101 if (cgit_virtual_root) { 124 if (cgit_virtual_root) {
102 return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame, 125 return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame,
103 pagename, query); 126 pagename, query);
104 } else { 127 } else {
105 return fmt("?r=%s&p=%s&%s", reponame, pagename, query); 128 return fmt("?r=%s&p=%s&%s", reponame, pagename, query);
106 } 129 }
107} 130}
108 131
109static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1, 132static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1,
110 int flags, void *cb_data) 133 int flags, void *cb_data)
111{ 134{
112 struct commit *commit; 135 struct commit *commit;
113 char buf[256], *url; 136 char buf[256], *url;
114 137
115 commit = lookup_commit(sha1); 138 commit = lookup_commit(sha1);
116 if (commit && !parse_commit(commit)){ 139 if (commit && !parse_commit(commit)){
117 html("<tr><td>"); 140 html("<tr><td>");
118 url = cgit_pageurl(cgit_query_repo, "log", 141 url = cgit_pageurl(cgit_query_repo, "log",
119 fmt("h=%s", refname)); 142 fmt("h=%s", refname));
120 html_link_open(url, NULL, NULL); 143 html_link_open(url, NULL, NULL);
121 strncpy(buf, refname, sizeof(buf)); 144 strncpy(buf, refname, sizeof(buf));
122 html_txt(buf); 145 html_txt(buf);
123 html_link_close(); 146 html_link_close();
124 html("</td><td>"); 147 html("</td><td>");
125 pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, buf, 148 pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, buf,
126 sizeof(buf), 0, NULL, NULL, 0); 149 sizeof(buf), 0, NULL, NULL, 0);
127 html_txt(buf); 150 html_txt(buf);
128 html("</td></tr>\n"); 151 html("</td></tr>\n");
129 } else { 152 } else {
130 html("<tr><td>"); 153 html("<tr><td>");
131 html_txt(buf); 154 html_txt(buf);
132 html("</td><td>"); 155 html("</td><td>");
133 htmlf("*** bad ref %s", sha1_to_hex(sha1)); 156 htmlf("*** bad ref %s", sha1_to_hex(sha1));
134 html("</td></tr>\n"); 157 html("</td></tr>\n");
135 } 158 }
136 return 0; 159 return 0;
137} 160}
138 161
162/* Sun, 06 Nov 1994 08:49:37 GMT */
163static char *http_date(time_t t)
164{
165 static char day[][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
166 static char month[][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
167 "Jul", "Aug", "Sep", "Oct", "Now", "Dec"};
168 struct tm *tm = gmtime(&t);
169 return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday],
170 tm->tm_mday, month[tm->tm_mon], 1900+tm->tm_year,
171 tm->tm_hour, tm->tm_min, tm->tm_sec);
172}
173
174static int ttl_seconds(int ttl)
175{
176 if (ttl<0)
177 return 60 * 60 * 24 * 365;
178 else
179 return ttl * 60;
180}
181
139static void cgit_print_docstart(char *title) 182static void cgit_print_docstart(char *title)
140{ 183{
141 html("Content-Type: text/html; charset=utf-8\n"); 184 html("Content-Type: text/html; charset=utf-8\n");
185 htmlf("Last-Modified: %s\n", http_date(cacheitem.st.st_mtime));
186 htmlf("Expires: %s\n", http_date(cacheitem.st.st_mtime +
187 ttl_seconds(cacheitem.ttl)));
142 html("\n"); 188 html("\n");
143 html(cgit_doctype); 189 html(cgit_doctype);
144 html("<html>\n"); 190 html("<html>\n");
145 html("<head>\n"); 191 html("<head>\n");
146 html("<title>"); 192 html("<title>");
147 html_txt(title); 193 html_txt(title);
148 html("</title>\n"); 194 html("</title>\n");
149 html("<link rel='stylesheet' type='text/css' href='"); 195 html("<link rel='stylesheet' type='text/css' href='");
150 html_attr(cgit_css); 196 html_attr(cgit_css);
151 html("'/>\n"); 197 html("'/>\n");
152 html("</head>\n"); 198 html("</head>\n");
153 html("<body>\n"); 199 html("<body>\n");
154} 200}
155 201
156static void cgit_print_docend() 202static void cgit_print_docend()
157{ 203{
158 html("</body>\n</html>\n"); 204 html("</body>\n</html>\n");
159} 205}
160 206
161static void cgit_print_pageheader(char *title) 207static void cgit_print_pageheader(char *title)
162{ 208{
163 html("<div id='header'>"); 209 html("<div id='header'>");
164 htmlf("<a href='%s'>", cgit_logo_link); 210 htmlf("<a href='%s'>", cgit_logo_link);
165 htmlf("<img id='logo' src='%s'/>\n", cgit_logo); 211 htmlf("<img id='logo' src='%s'/>\n", cgit_logo);
166 htmlf("</a>"); 212 htmlf("</a>");
167 html_txt(title); 213 html_txt(title);
168 html("</div>"); 214 html("</div>");
169} 215}
170 216
171static void cgit_print_repolist() 217static void cgit_print_repolist()
172{ 218{
173 DIR *d; 219 DIR *d;
174 struct dirent *de; 220 struct dirent *de;
175 struct stat st; 221 struct stat st;
176 char *name; 222 char *name;
177 223
224 chdir(cgit_root);
178 cgit_print_docstart(cgit_root_title); 225 cgit_print_docstart(cgit_root_title);
179 cgit_print_pageheader(cgit_root_title); 226 cgit_print_pageheader(cgit_root_title);
180 227
181 if (!(d = opendir("."))) { 228 if (!(d = opendir("."))) {
182 htmlf(cgit_lib_error, "Unable to scan repository directory", 229 htmlf(cgit_lib_error, "Unable to scan repository directory",
183 strerror(errno)); 230 strerror(errno));
184 cgit_print_docend(); 231 cgit_print_docend();
185 return; 232 return;
186 } 233 }
187 234
188 html("<h2>Repositories</h2>\n"); 235 html("<h2>Repositories</h2>\n");
189 html("<table class='list'>"); 236 html("<table class='list'>");
190 html("<tr><th>Name</th><th>Description</th><th>Owner</th></tr>\n"); 237 html("<tr><th>Name</th><th>Description</th><th>Owner</th></tr>\n");
191 while ((de = readdir(d)) != NULL) { 238 while ((de = readdir(d)) != NULL) {
192 if (de->d_name[0] == '.') 239 if (de->d_name[0] == '.')
193 continue; 240 continue;
194 if (stat(de->d_name, &st) < 0) 241 if (stat(de->d_name, &st) < 0)
195 continue; 242 continue;
196 if (!S_ISDIR(st.st_mode)) 243 if (!S_ISDIR(st.st_mode))
197 continue; 244 continue;
198 245
199 cgit_repo_name = cgit_repo_desc = cgit_repo_owner = NULL; 246 cgit_repo_name = cgit_repo_desc = cgit_repo_owner = NULL;
200 name = fmt("%s/.git/info/cgit", de->d_name); 247 name = fmt("%s/info/cgit", de->d_name);
201 if (cgit_read_config(name, cgit_repo_config_cb)) 248 if (cgit_read_config(name, cgit_repo_config_cb))
202 continue; 249 continue;
203 250
204 html("<tr><td>"); 251 html("<tr><td>");
205 html_link_open(cgit_repourl(de->d_name), NULL, NULL); 252 html_link_open(cgit_repourl(de->d_name), NULL, NULL);
206 html_txt(cgit_repo_name); 253 html_txt(cgit_repo_name);
207 html_link_close(); 254 html_link_close();
208 html("</td><td>"); 255 html("</td><td>");
209 html_txt(cgit_repo_desc); 256 html_txt(cgit_repo_desc);
210 html("</td><td>"); 257 html("</td><td>");
211 html_txt(cgit_repo_owner); 258 html_txt(cgit_repo_owner);
212 html("</td></tr>\n"); 259 html("</td></tr>\n");
213 } 260 }
214 closedir(d); 261 closedir(d);
215 html("</table>"); 262 html("</table>");
216 cgit_print_docend(); 263 cgit_print_docend();
217} 264}
218 265
219static void cgit_print_branches() 266static void cgit_print_branches()
220{ 267{
221 html("<table class='list'>"); 268 html("<table class='list'>");
222 html("<tr><th>Branch name</th><th>Head commit</th></tr>\n"); 269 html("<tr><th>Branch name</th><th>Head commit</th></tr>\n");
223 for_each_branch_ref(cgit_print_branch_cb, NULL); 270 for_each_branch_ref(cgit_print_branch_cb, NULL);
224 html("</table>"); 271 html("</table>");
225} 272}
226 273
227static int get_one_line(char *txt) 274static int get_one_line(char *txt)
228{ 275{
229 char *t; 276 char *t;
230 277
231 for(t=txt; *t != '\n' && t != '\0'; t++) 278 for(t=txt; *t != '\n' && t != '\0'; t++)
232 ; 279 ;
233 *t = '\0'; 280 *t = '\0';
234 return t-txt-1; 281 return t-txt-1;
235} 282}
236 283
237static void cgit_print_commit_shortlog(struct commit *commit) 284static void cgit_print_commit_shortlog(struct commit *commit)
238{ 285{
239 char *h, *t, *p; 286 char *h, *t, *p;
240 char *tree = NULL, *author = NULL, *subject = NULL; 287 char *tree = NULL, *author = NULL, *subject = NULL;
241 int len; 288 int len;
242 time_t sec; 289 time_t sec;
243 struct tm *time; 290 struct tm *time;
244 char buf[32]; 291 char buf[32];
245 292
246 h = t = commit->buffer; 293 h = t = commit->buffer;
247 294
248 if (strncmp(h, "tree ", 5)) 295 if (strncmp(h, "tree ", 5))
249 die("Bad commit format: %s", 296 die("Bad commit format: %s",
250 sha1_to_hex(commit->object.sha1)); 297 sha1_to_hex(commit->object.sha1));
251 298
252 len = get_one_line(h); 299 len = get_one_line(h);
253 tree = h+5; 300 tree = h+5;
254 h += len + 2; 301 h += len + 2;
255 302
256 while (!strncmp(h, "parent ", 7)) 303 while (!strncmp(h, "parent ", 7))
257 h += get_one_line(h) + 2; 304 h += get_one_line(h) + 2;
258 305
259 if (!strncmp(h, "author ", 7)) { 306 if (!strncmp(h, "author ", 7)) {
260 author = h+7; 307 author = h+7;
261 h += get_one_line(h) + 2; 308 h += get_one_line(h) + 2;
262 t = author; 309 t = author;
263 while(t!=h && *t!='<') 310 while(t!=h && *t!='<')
264 t++; 311 t++;
265 *t='\0'; 312 *t='\0';
266 p = t; 313 p = t;
267 while(--t!=author && *t==' ') 314 while(--t!=author && *t==' ')
268 *t='\0'; 315 *t='\0';
269 while(++p!=h && *p!='>') 316 while(++p!=h && *p!='>')
270 ; 317 ;
271 while(++p!=h && !isdigit(*p)) 318 while(++p!=h && !isdigit(*p))
272 ; 319 ;
273 320
274 t = p; 321 t = p;
275 while(++p && isdigit(*p)) 322 while(++p && isdigit(*p))
276 ; 323 ;
277 *p = '\0'; 324 *p = '\0';
278 sec = atoi(t); 325 sec = atoi(t);
279 time = gmtime(&sec); 326 time = gmtime(&sec);
280 } 327 }
281 328
282 while((len = get_one_line(h)) > 0) 329 while((len = get_one_line(h)) > 0)
283 h += len+2; 330 h += len+2;
284 331
285 h++; 332 h++;
286 len = get_one_line(h); 333 len = get_one_line(h);
287 334
288 subject = h; 335 subject = h;
289 336
290 html("<tr><td>"); 337 html("<tr><td>");
291 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", time); 338 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", time);
292 html_txt(buf); 339 html_txt(buf);
293 html("</td><td>"); 340 html("</td><td>");
294 char *qry = fmt("h=%s", sha1_to_hex(commit->object.sha1)); 341 char *qry = fmt("id=%s", sha1_to_hex(commit->object.sha1));
295 char *url = cgit_pageurl(cgit_query_repo, "view", qry); 342 char *url = cgit_pageurl(cgit_query_repo, "view", qry);
296 html_link_open(url, NULL, NULL); 343 html_link_open(url, NULL, NULL);
297 html_txt(subject); 344 html_txt(subject);
298 html_link_close(); 345 html_link_close();
299 html("</td><td>"); 346 html("</td><td>");
300 html_txt(author); 347 html_txt(author);
301 html("</td></tr>\n"); 348 html("</td></tr>\n");
302} 349}
303 350
304static void cgit_print_log(const char *tip, int ofs, int cnt) 351static void cgit_print_log(const char *tip, int ofs, int cnt)
305{ 352{
306 struct rev_info rev; 353 struct rev_info rev;
307 struct commit *commit; 354 struct commit *commit;
308 const char *argv[2] = {NULL, tip}; 355 const char *argv[2] = {NULL, tip};
309 int n = 0; 356 int n = 0;
310 357
311 init_revisions(&rev, NULL); 358 init_revisions(&rev, NULL);
312 rev.abbrev = DEFAULT_ABBREV; 359 rev.abbrev = DEFAULT_ABBREV;
313 rev.commit_format = CMIT_FMT_DEFAULT; 360 rev.commit_format = CMIT_FMT_DEFAULT;
314 rev.verbose_header = 1; 361 rev.verbose_header = 1;
315 rev.show_root_diff = 0; 362 rev.show_root_diff = 0;
316 setup_revisions(2, argv, &rev, NULL); 363 setup_revisions(2, argv, &rev, NULL);
317 prepare_revision_walk(&rev); 364 prepare_revision_walk(&rev);
318 365
319 html("<h2>Log</h2>"); 366 html("<h2>Log</h2>");
320 html("<table class='list'>"); 367 html("<table class='list'>");
321 html("<tr><th>Date</th><th>Message</th><th>Author</th></tr>\n"); 368 html("<tr><th>Date</th><th>Message</th><th>Author</th></tr>\n");
322 while ((commit = get_revision(&rev)) != NULL && n++ < 100) { 369 while ((commit = get_revision(&rev)) != NULL && n++ < 100) {
323 cgit_print_commit_shortlog(commit); 370 cgit_print_commit_shortlog(commit);
324 free(commit->buffer); 371 free(commit->buffer);
325 commit->buffer = NULL; 372 commit->buffer = NULL;
326 free_commit_list(commit->parents); 373 free_commit_list(commit->parents);
327 commit->parents = NULL; 374 commit->parents = NULL;
328 } 375 }
329 html("</table>\n"); 376 html("</table>\n");
330} 377}
331 378
332static void cgit_print_repo_summary() 379static void cgit_print_repo_summary()
333{ 380{
334 html("<h2>"); 381 html("<h2>");
335 html_txt("Repo summary page"); 382 html_txt("Repo summary page");
336 html("</h2>"); 383 html("</h2>");
337 cgit_print_branches(); 384 cgit_print_branches();
338} 385}
339 386
340static void cgit_print_object(char *hex) 387static void cgit_print_object(char *hex)
341{ 388{
342 unsigned char sha1[20]; 389 unsigned char sha1[20];
343 //struct object *object; 390 //struct object *object;
344 char type[20]; 391 char type[20];
345 unsigned char *buf; 392 unsigned char *buf;
346 unsigned long size; 393 unsigned long size;
347 394
348 if (get_sha1_hex(hex, sha1)){ 395 if (get_sha1_hex(hex, sha1)){
349 htmlf(cgit_error, "Bad hex value"); 396 htmlf(cgit_error, "Bad hex value");
350 return; 397 return;
351 } 398 }
352 399
353 if (sha1_object_info(sha1, type, NULL)){ 400 if (sha1_object_info(sha1, type, NULL)){
354 htmlf(cgit_error, "Bad object name"); 401 htmlf(cgit_error, "Bad object name");
355 return; 402 return;
356 } 403 }
357 404
358 buf = read_sha1_file(sha1, type, &size); 405 buf = read_sha1_file(sha1, type, &size);
359 if (!buf) { 406 if (!buf) {
360 htmlf(cgit_error, "Error reading object"); 407 htmlf(cgit_error, "Error reading object");
361 return; 408 return;
362 } 409 }
363 410
364 buf[size] = '\0'; 411 buf[size] = '\0';
365 html("<h2>Object view</h2>"); 412 html("<h2>Object view</h2>");
366 htmlf("sha1=%s<br/>type=%s<br/>size=%i<br/>", hex, type, size); 413 htmlf("sha1=%s<br/>type=%s<br/>size=%i<br/>", hex, type, size);
367 html("<pre>"); 414 html("<pre>");
368 html_txt(buf); 415 html_txt(buf);
369 html("</pre>"); 416 html("</pre>");
370} 417}
371 418
372static void cgit_print_repo_page() 419static void cgit_print_repo_page()
373{ 420{
374 if (chdir(cgit_query_repo) || 421 if (chdir(fmt("%s/%s", cgit_root, cgit_query_repo)) ||
375 cgit_read_config(".git/info/cgit", cgit_repo_config_cb)) { 422 cgit_read_config("info/cgit", cgit_repo_config_cb)) {
376 char *title = fmt("%s - %s", cgit_root_title, "Bad request"); 423 char *title = fmt("%s - %s", cgit_root_title, "Bad request");
377 cgit_print_docstart(title); 424 cgit_print_docstart(title);
378 cgit_print_pageheader(title); 425 cgit_print_pageheader(title);
379 htmlf(cgit_lib_error, "Unable to scan repository", 426 htmlf(cgit_lib_error, "Unable to scan repository",
380 strerror(errno)); 427 strerror(errno));
381 cgit_print_docend(); 428 cgit_print_docend();
382 return; 429 return;
383 } 430 }
384 431 setenv("GIT_DIR", fmt("%s/%s", cgit_root, cgit_query_repo), 1);
385 char *title = fmt("%s - %s", cgit_repo_name, cgit_repo_desc); 432 char *title = fmt("%s - %s", cgit_repo_name, cgit_repo_desc);
386 cgit_print_docstart(title); 433 cgit_print_docstart(title);
387 cgit_print_pageheader(title); 434 cgit_print_pageheader(title);
388 if (!cgit_query_page) 435 if (!cgit_query_page)
389 cgit_print_repo_summary(); 436 cgit_print_repo_summary();
390 else if (!strcmp(cgit_query_page, "log")) { 437 else if (!strcmp(cgit_query_page, "log")) {
391 cgit_print_log(cgit_query_head, 0, 100); 438 cgit_print_log(cgit_query_head, 0, 100);
392 } else if (!strcmp(cgit_query_page, "view")) { 439 } else if (!strcmp(cgit_query_page, "view")) {
393 cgit_print_object(cgit_query_head); 440 cgit_print_object(cgit_query_sha1);
394 } 441 }
395 cgit_print_docend(); 442 cgit_print_docend();
396} 443}
397 444
398int main(int argc, const char **argv) 445static void cgit_fill_cache(struct cacheitem *item)
399{ 446{
400 if (cgit_read_config("/etc/cgitrc", cgit_global_config_cb)) 447 htmlfd = item->fd;
401 die("Error reading config: %d %s", errno, strerror(errno)); 448 item->st.st_mtime = time(NULL);
402
403 chdir(cgit_root);
404 cgit_parse_query(getenv("QUERY_STRING"), cgit_querystring_cb);
405 if (cgit_query_repo) 449 if (cgit_query_repo)
406 cgit_print_repo_page(); 450 cgit_print_repo_page();
407 else 451 else
408 cgit_print_repolist(); 452 cgit_print_repolist();
453}
454
455static void cgit_refresh_cache(struct cacheitem *item)
456{
457 top:
458 if (!cache_lookup(item)) {
459 if (cache_lock(item)) {
460 cgit_fill_cache(item);
461 cache_unlock(item);
462 } else {
463 sched_yield();
464 goto top;
465 }
466 } else if (cache_expired(item)) {
467 if (cache_lock(item)) {
468 cgit_fill_cache(item);
469 cache_unlock(item);
470 }
471 }
472}
473
474static void cgit_print_cache(struct cacheitem *item)
475{
476 static char buf[4096];
477 ssize_t i;
478
479 int fd = open(item->name, O_RDONLY);
480 if (fd<0)
481 die("Unable to open cached file %s", item->name);
482
483 while((i=read(fd, buf, sizeof(buf))) > 0)
484 write(STDOUT_FILENO, buf, i);
485
486 close(fd);
487}
488
489int main(int argc, const char **argv)
490{
491 cgit_read_config("/etc/cgitrc", cgit_global_config_cb);
492 cgit_querystring = xstrdup(getenv("QUERY_STRING"));
493 cgit_parse_query(cgit_querystring, cgit_querystring_cb);
494 cgit_refresh_cache(&cacheitem);
495 cgit_print_cache(&cacheitem);
409 return 0; 496 return 0;
410} 497}