about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--cache.c7
-rw-r--r--cgit.c2
-rw-r--r--cgit.css28
-rw-r--r--filter.c22
-rw-r--r--html.c2
-rw-r--r--robots.txt1
-rwxr-xr-xtests/t0105-commit.sh6
-rwxr-xr-xtests/t0106-diff.sh4
-rw-r--r--ui-blame.c4
-rw-r--r--ui-commit.c7
-rw-r--r--ui-diff.c30
-rw-r--r--ui-log.c4
-rw-r--r--ui-repolist.c4
-rw-r--r--ui-shared.c44
-rw-r--r--ui-snapshot.c3
-rw-r--r--ui-tag.c4
-rw-r--r--ui-tree.c40
17 files changed, 148 insertions, 64 deletions
diff --git a/cache.c b/cache.c index 55199e8..578b73b 100644 --- a/cache.c +++ b/cache.c
@@ -265,6 +265,13 @@ static int process_slot(struct cache_slot *slot)
265{ 265{
266 int err; 266 int err;
267 267
268 /*
269 * Make sure any buffered data is flushed before we redirect,
270 * do sendfile(2) or write(2)
271 */
272 if (fflush(stdout))
273 return errno;
274
268 err = open_slot(slot); 275 err = open_slot(slot);
269 if (!err && slot->match) { 276 if (!err && slot->match) {
270 if (is_expired(slot)) { 277 if (is_expired(slot)) {
diff --git a/cgit.c b/cgit.c index 08d81a1..40825cb 100644 --- a/cgit.c +++ b/cgit.c
@@ -674,7 +674,7 @@ static inline void authenticate_post(void)
674 len = MAX_AUTHENTICATION_POST_BYTES; 674 len = MAX_AUTHENTICATION_POST_BYTES;
675 if ((len = read(STDIN_FILENO, buffer, len)) < 0) 675 if ((len = read(STDIN_FILENO, buffer, len)) < 0)
676 die_errno("Could not read POST from stdin"); 676 die_errno("Could not read POST from stdin");
677 if (write(STDOUT_FILENO, buffer, len) < 0) 677 if (fwrite(buffer, 1, len, stdout) < len)
678 die_errno("Could not write POST to stdout"); 678 die_errno("Could not write POST to stdout");
679 cgit_close_filter(ctx.cfg.auth_filter); 679 cgit_close_filter(ctx.cfg.auth_filter);
680 exit(0); 680 exit(0);
diff --git a/cgit.css b/cgit.css index dfa144d..f3dbb7a 100644 --- a/cgit.css +++ b/cgit.css
@@ -75,7 +75,7 @@ div#cgit table.tabs td {
75} 75}
76 76
77div#cgit table.tabs td a { 77div#cgit table.tabs td a {
78 padding: 2px 0.75em; 78 padding: 2px 0.25em;
79 color: #777; 79 color: #777;
80 font-size: 110%; 80 font-size: 110%;
81} 81}
@@ -437,11 +437,6 @@ div#cgit div.commit-subject {
437 padding: 0em; 437 padding: 0em;
438} 438}
439 439
440div#cgit div.commit-msg {
441 white-space: pre;
442 font-family: monospace;
443}
444
445div#cgit div.notes-header { 440div#cgit div.notes-header {
446 font-weight: bold; 441 font-weight: bold;
447 padding-top: 1.5em; 442 padding-top: 1.5em;
@@ -538,26 +533,20 @@ div#cgit table.diff {
538 width: 100%; 533 width: 100%;
539} 534}
540 535
541div#cgit table.diff td { 536div#cgit table.diff td span.head {
542 font-family: monospace;
543 white-space: pre;
544}
545
546div#cgit table.diff td div.head {
547 font-weight: bold; 537 font-weight: bold;
548 margin-top: 1em;
549 color: black; 538 color: black;
550} 539}
551 540
552div#cgit table.diff td div.hunk { 541div#cgit table.diff td span.hunk {
553 color: #009; 542 color: #009;
554} 543}
555 544
556div#cgit table.diff td div.add { 545div#cgit table.diff td span.add {
557 color: green; 546 color: green;
558} 547}
559 548
560div#cgit table.diff td div.del { 549div#cgit table.diff td span.del {
561 color: red; 550 color: red;
562} 551}
563 552
@@ -581,7 +570,6 @@ div#cgit table.list td.reposection {
581 570
582div#cgit a.button { 571div#cgit a.button {
583 font-size: 80%; 572 font-size: 80%;
584 padding: 0em 0.5em;
585} 573}
586 574
587div#cgit a.primary { 575div#cgit a.primary {
@@ -671,7 +659,6 @@ div#cgit div.footer a:hover {
671 659
672div#cgit a.branch-deco { 660div#cgit a.branch-deco {
673 color: #000; 661 color: #000;
674 margin: 0px 0.5em;
675 padding: 0px 0.25em; 662 padding: 0px 0.25em;
676 background-color: #88ff88; 663 background-color: #88ff88;
677 border: solid 1px #007700; 664 border: solid 1px #007700;
@@ -679,7 +666,6 @@ div#cgit a.branch-deco {
679 666
680div#cgit a.tag-deco { 667div#cgit a.tag-deco {
681 color: #000; 668 color: #000;
682 margin: 0px 0.5em;
683 padding: 0px 0.25em; 669 padding: 0px 0.25em;
684 background-color: #ffff88; 670 background-color: #ffff88;
685 border: solid 1px #777700; 671 border: solid 1px #777700;
@@ -687,7 +673,6 @@ div#cgit a.tag-deco {
687 673
688div#cgit a.tag-annotated-deco { 674div#cgit a.tag-annotated-deco {
689 color: #000; 675 color: #000;
690 margin: 0px 0.5em;
691 padding: 0px 0.25em; 676 padding: 0px 0.25em;
692 background-color: #ffcc88; 677 background-color: #ffcc88;
693 border: solid 1px #777700; 678 border: solid 1px #777700;
@@ -695,7 +680,6 @@ div#cgit a.tag-annotated-deco {
695 680
696div#cgit a.remote-deco { 681div#cgit a.remote-deco {
697 color: #000; 682 color: #000;
698 margin: 0px 0.5em;
699 padding: 0px 0.25em; 683 padding: 0px 0.25em;
700 background-color: #ccccff; 684 background-color: #ccccff;
701 border: solid 1px #000077; 685 border: solid 1px #000077;
@@ -703,7 +687,6 @@ div#cgit a.remote-deco {
703 687
704div#cgit a.deco { 688div#cgit a.deco {
705 color: #000; 689 color: #000;
706 margin: 0px 0.5em;
707 padding: 0px 0.25em; 690 padding: 0px 0.25em;
708 background-color: #ff8888; 691 background-color: #ff8888;
709 border: solid 1px #770000; 692 border: solid 1px #770000;
@@ -714,7 +697,6 @@ div#cgit div.commit-subject a.tag-deco,
714div#cgit div.commit-subject a.tag-annotated-deco, 697div#cgit div.commit-subject a.tag-annotated-deco,
715div#cgit div.commit-subject a.remote-deco, 698div#cgit div.commit-subject a.remote-deco,
716div#cgit div.commit-subject a.deco { 699div#cgit div.commit-subject a.deco {
717 margin-left: 1em;
718 font-size: 75%; 700 font-size: 75%;
719} 701}
720 702
diff --git a/filter.c b/filter.c index 70f5b74..fba26aa 100644 --- a/filter.c +++ b/filter.c
@@ -48,6 +48,7 @@ static int open_exec_filter(struct cgit_filter *base, va_list ap)
48 for (i = 0; i < filter->base.argument_count; i++) 48 for (i = 0; i < filter->base.argument_count; i++)
49 filter->argv[i + 1] = va_arg(ap, char *); 49 filter->argv[i + 1] = va_arg(ap, char *);
50 50
51 chk_zero(fflush(stdout), "unable to flush STDOUT");
51 filter->old_stdout = chk_positive(dup(STDOUT_FILENO), 52 filter->old_stdout = chk_positive(dup(STDOUT_FILENO),
52 "Unable to duplicate STDOUT"); 53 "Unable to duplicate STDOUT");
53 chk_zero(pipe(pipe_fh), "Unable to create pipe to subprocess"); 54 chk_zero(pipe(pipe_fh), "Unable to create pipe to subprocess");
@@ -71,6 +72,7 @@ static int close_exec_filter(struct cgit_filter *base)
71 struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base; 72 struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base;
72 int i, exit_status = 0; 73 int i, exit_status = 0;
73 74
75 chk_zero(fflush(stdout), "unable to flush STDOUT");
74 chk_non_negative(dup2(filter->old_stdout, STDOUT_FILENO), 76 chk_non_negative(dup2(filter->old_stdout, STDOUT_FILENO),
75 "Unable to restore STDOUT"); 77 "Unable to restore STDOUT");
76 close(filter->old_stdout); 78 close(filter->old_stdout);
@@ -143,17 +145,32 @@ void cgit_init_filters(void)
143#endif 145#endif
144 146
145#ifndef NO_LUA 147#ifndef NO_LUA
146static ssize_t (*libc_write)(int fd, const void *buf, size_t count); 148static size_t (*libc_fwrite)(const void *buf, size_t size, size_t n, FILE *);
149static ssize_t (*libc_write)(int fd, const void *buf, size_t size);
147static ssize_t (*filter_write)(struct cgit_filter *base, const void *buf, size_t count) = NULL; 150static ssize_t (*filter_write)(struct cgit_filter *base, const void *buf, size_t count) = NULL;
148static struct cgit_filter *current_write_filter = NULL; 151static struct cgit_filter *current_write_filter = NULL;
149 152
150void cgit_init_filters(void) 153void cgit_init_filters(void)
151{ 154{
155 /*
156 * we need to wrap both functions since the Lua filter may
157 * have code which calls write(2) directly, bypassing fwrite(3)
158 */
159 libc_fwrite = dlsym(RTLD_NEXT, "fwrite");
160 if (!libc_fwrite)
161 die("Could not locate libc's write function");
152 libc_write = dlsym(RTLD_NEXT, "write"); 162 libc_write = dlsym(RTLD_NEXT, "write");
153 if (!libc_write) 163 if (!libc_write)
154 die("Could not locate libc's write function"); 164 die("Could not locate libc's write function");
155} 165}
156 166
167size_t fwrite(const void *buf, size_t size, size_t n, FILE *f)
168{
169 if (f != stdout || !filter_write)
170 return libc_fwrite(buf, size, n, f);
171 return filter_write(current_write_filter, buf, size * n);
172}
173
157ssize_t write(int fd, const void *buf, size_t count) 174ssize_t write(int fd, const void *buf, size_t count)
158{ 175{
159 if (fd != STDOUT_FILENO || !filter_write) 176 if (fd != STDOUT_FILENO || !filter_write)
@@ -305,6 +322,9 @@ static int open_lua_filter(struct cgit_filter *base, va_list ap)
305 struct lua_filter *filter = (struct lua_filter *)base; 322 struct lua_filter *filter = (struct lua_filter *)base;
306 int i; 323 int i;
307 324
325 if (fflush(stdout))
326 return 1;
327
308 if (init_lua_filter(filter)) 328 if (init_lua_filter(filter))
309 return 1; 329 return 1;
310 330
diff --git a/html.c b/html.c index 7f81965..cefcf5e 100644 --- a/html.c +++ b/html.c
@@ -80,7 +80,7 @@ char *fmtalloc(const char *format, ...)
80 80
81void html_raw(const char *data, size_t size) 81void html_raw(const char *data, size_t size)
82{ 82{
83 if (write(STDOUT_FILENO, data, size) != size) 83 if (fwrite(data, 1, size, stdout) != size)
84 die_errno("write error on html output"); 84 die_errno("write error on html output");
85} 85}
86 86
diff --git a/robots.txt b/robots.txt index 4ce948f..1b33266 100644 --- a/robots.txt +++ b/robots.txt
@@ -1,3 +1,4 @@
1User-agent: * 1User-agent: *
2Disallow: /*/snapshot/* 2Disallow: /*/snapshot/*
3Disallow: /*/blame/*
3Allow: / 4Allow: /
diff --git a/tests/t0105-commit.sh b/tests/t0105-commit.sh index 1a12ee3..cfed1e7 100755 --- a/tests/t0105-commit.sh +++ b/tests/t0105-commit.sh
@@ -11,7 +11,7 @@ test_expect_success 'find commit subject' '
11 grep "<div class=.commit-subject.>commit 5<" tmp 11 grep "<div class=.commit-subject.>commit 5<" tmp
12' 12'
13 13
14test_expect_success 'find commit msg' 'grep "<div class=.commit-msg.></div>" tmp' 14test_expect_success 'find commit msg' 'grep "<pre class=.commit-msg.></pre>" tmp'
15test_expect_success 'find diffstat' 'grep "<table summary=.diffstat. class=.diffstat.>" tmp' 15test_expect_success 'find diffstat' 'grep "<table summary=.diffstat. class=.diffstat.>" tmp'
16 16
17test_expect_success 'find diff summary' ' 17test_expect_success 'find diff summary' '
@@ -29,8 +29,8 @@ test_expect_success 'root commit contains diffstat' '
29' 29'
30 30
31test_expect_success 'root commit contains diff' ' 31test_expect_success 'root commit contains diff' '
32 grep ">diff --git a/file-1 b/file-1<" tmp && 32 grep ">diff --git a/file-1 b/file-1" tmp &&
33 grep "<div class=.add.>+1</div>" tmp 33 grep "<span class=.add.>+1</span>" tmp
34' 34'
35 35
36test_done 36test_done
diff --git a/tests/t0106-diff.sh b/tests/t0106-diff.sh index 82b645e..62a0a74 100755 --- a/tests/t0106-diff.sh +++ b/tests/t0106-diff.sh
@@ -9,11 +9,11 @@ test_expect_success 'find blob link' 'grep "<a href=./foo/tree/file-5?id=" tmp'
9test_expect_success 'find added file' 'grep "new file mode 100644" tmp' 9test_expect_success 'find added file' 'grep "new file mode 100644" tmp'
10 10
11test_expect_success 'find hunk header' ' 11test_expect_success 'find hunk header' '
12 grep "<div class=.hunk.>@@ -0,0 +1 @@</div>" tmp 12 grep "<span class=.hunk.>@@ -0,0 +1 @@</span>" tmp
13' 13'
14 14
15test_expect_success 'find added line' ' 15test_expect_success 'find added line' '
16 grep "<div class=.add.>+5</div>" tmp 16 grep "<span class=.add.>+5</span>" tmp
17' 17'
18 18
19test_done 19test_done
diff --git a/ui-blame.c b/ui-blame.c index 03136f7..4adec2b 100644 --- a/ui-blame.c +++ b/ui-blame.c
@@ -152,6 +152,10 @@ static void print_object(const struct object_id *oid, const char *path,
152 cgit_tree_link("tree", NULL, NULL, ctx.qry.head, rev, path); 152 cgit_tree_link("tree", NULL, NULL, ctx.qry.head, rev, path);
153 html(")\n"); 153 html(")\n");
154 154
155 if (buffer_is_binary(buf, size)) {
156 html("<div class='error'>blob is binary.</div>");
157 goto cleanup;
158 }
155 if (ctx.cfg.max_blob_size && size / 1024 > ctx.cfg.max_blob_size) { 159 if (ctx.cfg.max_blob_size && size / 1024 > ctx.cfg.max_blob_size) {
156 htmlf("<div class='error'>blob size (%ldKB)" 160 htmlf("<div class='error'>blob size (%ldKB)"
157 " exceeds display size limit (%dKB).</div>", 161 " exceeds display size limit (%dKB).</div>",
diff --git a/ui-commit.c b/ui-commit.c index 948118c..b49259e 100644 --- a/ui-commit.c +++ b/ui-commit.c
@@ -39,10 +39,11 @@ void cgit_print_commit(char *hex, const char *prefix)
39 } 39 }
40 info = cgit_parse_commit(commit); 40 info = cgit_parse_commit(commit);
41 41
42 format_display_notes(&oid, &notes, PAGE_ENCODING, 0); 42 format_display_notes(&oid, &notes, PAGE_ENCODING, 1);
43 43
44 load_ref_decorations(NULL, DECORATE_FULL_REFS); 44 load_ref_decorations(NULL, DECORATE_FULL_REFS);
45 45
46 ctx.page.title = fmtalloc("%s - %s", info->subject, ctx.page.title);
46 cgit_print_layout_start(); 47 cgit_print_layout_start();
47 cgit_print_diff_ctrls(); 48 cgit_print_diff_ctrls();
48 html("<table summary='commit info' class='commit-info'>\n"); 49 html("<table summary='commit info' class='commit-info'>\n");
@@ -120,11 +121,11 @@ void cgit_print_commit(char *hex, const char *prefix)
120 cgit_close_filter(ctx.repo->commit_filter); 121 cgit_close_filter(ctx.repo->commit_filter);
121 show_commit_decorations(commit); 122 show_commit_decorations(commit);
122 html("</div>"); 123 html("</div>");
123 html("<div class='commit-msg'>"); 124 html("<pre class='commit-msg'>");
124 cgit_open_filter(ctx.repo->commit_filter); 125 cgit_open_filter(ctx.repo->commit_filter);
125 html_txt(info->msg); 126 html_txt(info->msg);
126 cgit_close_filter(ctx.repo->commit_filter); 127 cgit_close_filter(ctx.repo->commit_filter);
127 html("</div>"); 128 html("</pre>");
128 if (notes.len != 0) { 129 if (notes.len != 0) {
129 html("<div class='notes-header'>Notes</div>"); 130 html("<div class='notes-header'>Notes</div>");
130 html("<div class='notes'>"); 131 html("<div class='notes'>");
diff --git a/ui-diff.c b/ui-diff.c index 5ed5990..2a64ae8 100644 --- a/ui-diff.c +++ b/ui-diff.c
@@ -231,11 +231,11 @@ static void print_line(char *line, int len)
231 else if (line[0] == '@') 231 else if (line[0] == '@')
232 class = "hunk"; 232 class = "hunk";
233 233
234 htmlf("<div class='%s'>", class); 234 htmlf("<span class='%s'>", class);
235 line[len-1] = '\0'; 235 line[len-1] = '\0';
236 html_txt(line); 236 html_txt(line);
237 html("</div>");
238 line[len-1] = c; 237 line[len-1] = c;
238 html("</span>\n");
239} 239}
240 240
241static void header(const struct object_id *oid1, char *path1, int mode1, 241static void header(const struct object_id *oid1, char *path1, int mode1,
@@ -245,22 +245,23 @@ static void header(const struct object_id *oid1, char *path1, int mode1,
245 int subproject; 245 int subproject;
246 246
247 subproject = (S_ISGITLINK(mode1) || S_ISGITLINK(mode2)); 247 subproject = (S_ISGITLINK(mode1) || S_ISGITLINK(mode2));
248 html("<div class='head'>"); 248 html("<span class='head'>");
249 html("diff --git a/"); 249 html("diff --git a/");
250 html_txt(path1); 250 html_txt(path1);
251 html(" b/"); 251 html(" b/");
252 html_txt(path2); 252 html_txt(path2);
253 html("\n");
253 254
254 if (mode1 == 0) 255 if (mode1 == 0)
255 htmlf("<br/>new file mode %.6o", mode2); 256 htmlf("new file mode %.6o\n", mode2);
256 257
257 if (mode2 == 0) 258 if (mode2 == 0)
258 htmlf("<br/>deleted file mode %.6o", mode1); 259 htmlf("deleted file mode %.6o\n", mode1);
259 260
260 if (!subproject) { 261 if (!subproject) {
261 abbrev1 = xstrdup(find_unique_abbrev(oid1, DEFAULT_ABBREV)); 262 abbrev1 = xstrdup(find_unique_abbrev(oid1, DEFAULT_ABBREV));
262 abbrev2 = xstrdup(find_unique_abbrev(oid2, DEFAULT_ABBREV)); 263 abbrev2 = xstrdup(find_unique_abbrev(oid2, DEFAULT_ABBREV));
263 htmlf("<br/>index %s..%s", abbrev1, abbrev2); 264 htmlf("index %s..%s", abbrev1, abbrev2);
264 free(abbrev1); 265 free(abbrev1);
265 free(abbrev2); 266 free(abbrev2);
266 if (mode1 != 0 && mode2 != 0) { 267 if (mode1 != 0 && mode2 != 0) {
@@ -268,28 +269,31 @@ static void header(const struct object_id *oid1, char *path1, int mode1,
268 if (mode2 != mode1) 269 if (mode2 != mode1)
269 htmlf("..%.6o", mode2); 270 htmlf("..%.6o", mode2);
270 } 271 }
272 html("\n");
271 if (is_null_oid(oid1)) { 273 if (is_null_oid(oid1)) {
272 path1 = "dev/null"; 274 path1 = "dev/null";
273 html("<br/>--- /"); 275 html("--- /");
274 } else 276 } else
275 html("<br/>--- a/"); 277 html("--- a/");
276 if (mode1 != 0) 278 if (mode1 != 0)
277 cgit_tree_link(path1, NULL, NULL, ctx.qry.head, 279 cgit_tree_link(path1, NULL, NULL, ctx.qry.head,
278 oid_to_hex(old_rev_oid), path1); 280 oid_to_hex(old_rev_oid), path1);
279 else 281 else
280 html_txt(path1); 282 html_txt(path1);
283 html("\n");
281 if (is_null_oid(oid2)) { 284 if (is_null_oid(oid2)) {
282 path2 = "dev/null"; 285 path2 = "dev/null";
283 html("<br/>+++ /"); 286 html("+++ /");
284 } else 287 } else
285 html("<br/>+++ b/"); 288 html("+++ b/");
286 if (mode2 != 0) 289 if (mode2 != 0)
287 cgit_tree_link(path2, NULL, NULL, ctx.qry.head, 290 cgit_tree_link(path2, NULL, NULL, ctx.qry.head,
288 oid_to_hex(new_rev_oid), path2); 291 oid_to_hex(new_rev_oid), path2);
289 else 292 else
290 html_txt(path2); 293 html_txt(path2);
294 html("\n");
291 } 295 }
292 html("</div>"); 296 html("</span>");
293} 297}
294 298
295static void filepair_cb(struct diff_filepair *pair) 299static void filepair_cb(struct diff_filepair *pair)
@@ -488,12 +492,12 @@ void cgit_print_diff(const char *new_rev, const char *old_rev,
488 html("<table summary='ssdiff' class='ssdiff'>"); 492 html("<table summary='ssdiff' class='ssdiff'>");
489 } else { 493 } else {
490 html("<table summary='diff' class='diff'>"); 494 html("<table summary='diff' class='diff'>");
491 html("<tr><td>"); 495 html("<tr><td><pre>");
492 } 496 }
493 cgit_diff_tree(old_rev_oid, new_rev_oid, filepair_cb, prefix, 497 cgit_diff_tree(old_rev_oid, new_rev_oid, filepair_cb, prefix,
494 ctx.qry.ignorews); 498 ctx.qry.ignorews);
495 if (!use_ssdiff) 499 if (!use_ssdiff)
496 html("</td></tr>"); 500 html("</pre></td></tr>");
497 html("</table>"); 501 html("</table>");
498 502
499 if (show_ctrls) 503 if (show_ctrls)
diff --git a/ui-log.c b/ui-log.c index 20774bf..b443ca7 100644 --- a/ui-log.c +++ b/ui-log.c
@@ -75,11 +75,13 @@ void show_commit_decorations(struct commit *commit)
75 * don't display anything. */ 75 * don't display anything. */
76 break; 76 break;
77 case DECORATION_REF_LOCAL: 77 case DECORATION_REF_LOCAL:
78 html(" ");
78 cgit_log_link(buf, NULL, "branch-deco", buf, NULL, 79 cgit_log_link(buf, NULL, "branch-deco", buf, NULL,
79 ctx.qry.vpath, 0, NULL, NULL, 80 ctx.qry.vpath, 0, NULL, NULL,
80 ctx.qry.showmsg, 0); 81 ctx.qry.showmsg, 0);
81 break; 82 break;
82 case DECORATION_REF_TAG: 83 case DECORATION_REF_TAG:
84 html(" ");
83 if (!read_ref(deco->name, &oid_tag) && !peel_iterated_oid(&oid_tag, &peeled)) 85 if (!read_ref(deco->name, &oid_tag) && !peel_iterated_oid(&oid_tag, &peeled))
84 is_annotated = !oideq(&oid_tag, &peeled); 86 is_annotated = !oideq(&oid_tag, &peeled);
85 cgit_tag_link(buf, NULL, is_annotated ? "tag-annotated-deco" : "tag-deco", buf); 87 cgit_tag_link(buf, NULL, is_annotated ? "tag-annotated-deco" : "tag-deco", buf);
@@ -87,12 +89,14 @@ void show_commit_decorations(struct commit *commit)
87 case DECORATION_REF_REMOTE: 89 case DECORATION_REF_REMOTE:
88 if (!ctx.repo->enable_remote_branches) 90 if (!ctx.repo->enable_remote_branches)
89 break; 91 break;
92 html(" ");
90 cgit_log_link(buf, NULL, "remote-deco", NULL, 93 cgit_log_link(buf, NULL, "remote-deco", NULL,
91 oid_to_hex(&commit->object.oid), 94 oid_to_hex(&commit->object.oid),
92 ctx.qry.vpath, 0, NULL, NULL, 95 ctx.qry.vpath, 0, NULL, NULL,
93 ctx.qry.showmsg, 0); 96 ctx.qry.showmsg, 0);
94 break; 97 break;
95 default: 98 default:
99 html(" ");
96 cgit_commit_link(buf, NULL, "deco", ctx.qry.head, 100 cgit_commit_link(buf, NULL, "deco", ctx.qry.head,
97 oid_to_hex(&commit->object.oid), 101 oid_to_hex(&commit->object.oid),
98 ctx.qry.vpath); 102 ctx.qry.vpath);
diff --git a/ui-repolist.c b/ui-repolist.c index 529a203..97b11c5 100644 --- a/ui-repolist.c +++ b/ui-repolist.c
@@ -321,7 +321,7 @@ void cgit_print_repolist(void)
321 } 321 }
322 htmlf("<tr><td class='%s'>", 322 htmlf("<tr><td class='%s'>",
323 !sorted && section ? "sublevel-repo" : "toplevel-repo"); 323 !sorted && section ? "sublevel-repo" : "toplevel-repo");
324 cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL); 324 cgit_summary_link(ctx.repo->name, NULL, NULL, NULL);
325 html("</td><td>"); 325 html("</td><td>");
326 repourl = cgit_repourl(ctx.repo->url); 326 repourl = cgit_repourl(ctx.repo->url);
327 html_link_open(repourl, NULL, NULL); 327 html_link_open(repourl, NULL, NULL);
@@ -353,8 +353,10 @@ void cgit_print_repolist(void)
353 if (ctx.cfg.enable_index_links) { 353 if (ctx.cfg.enable_index_links) {
354 html("<td>"); 354 html("<td>");
355 cgit_summary_link("summary", NULL, "button", NULL); 355 cgit_summary_link("summary", NULL, "button", NULL);
356 html(" ");
356 cgit_log_link("log", NULL, "button", NULL, NULL, NULL, 357 cgit_log_link("log", NULL, "button", NULL, NULL, NULL,
357 0, NULL, NULL, ctx.qry.showmsg, 0); 358 0, NULL, NULL, ctx.qry.showmsg, 0);
359 html(" ");
358 cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); 360 cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL);
359 html("</td>"); 361 html("</td>");
360 } 362 }
diff --git a/ui-shared.c b/ui-shared.c index acd8ab5..225a363 100644 --- a/ui-shared.c +++ b/ui-shared.c
@@ -894,6 +894,15 @@ void cgit_add_clone_urls(void (*fn)(const char *))
894 add_clone_urls(fn, ctx.cfg.clone_prefix, ctx.repo->url); 894 add_clone_urls(fn, ctx.cfg.clone_prefix, ctx.repo->url);
895} 895}
896 896
897static int print_this_commit_option(void)
898{
899 struct object_id oid;
900 if (!ctx.qry.head || get_oid(ctx.qry.head, &oid))
901 return 1;
902 html_option(oid_to_hex(&oid), "this commit", ctx.qry.head);
903 return 0;
904}
905
897static int print_branch_option(const char *refname, const struct object_id *oid, 906static int print_branch_option(const char *refname, const struct object_id *oid,
898 int flags, void *cb_data) 907 int flags, void *cb_data)
899{ 908{
@@ -995,15 +1004,18 @@ static void print_header(void)
995 if (ctx.repo) { 1004 if (ctx.repo) {
996 cgit_index_link("index", NULL, NULL, NULL, NULL, 0, 1); 1005 cgit_index_link("index", NULL, NULL, NULL, NULL, 0, 1);
997 html(" : "); 1006 html(" : ");
998 cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL); 1007 cgit_summary_link(ctx.repo->name, NULL, NULL, NULL);
999 if (ctx.env.authenticated) { 1008 if (ctx.env.authenticated) {
1000 html("</td><td class='form'>"); 1009 html("</td><td class='form'>");
1001 html("<form method='get'>\n"); 1010 html("<form method='get'>\n");
1002 cgit_add_hidden_formfields(0, 1, ctx.qry.page); 1011 cgit_add_hidden_formfields(0, 1, ctx.qry.page);
1003 html("<select name='h' onchange='this.form.submit();'>\n"); 1012 html("<select name='h' onchange='this.form.submit();'>\n");
1013 print_this_commit_option();
1014 html("<optgroup label='branches'>");
1004 for_each_branch_ref(print_branch_option, ctx.qry.head); 1015 for_each_branch_ref(print_branch_option, ctx.qry.head);
1005 if (ctx.repo->enable_remote_branches) 1016 if (ctx.repo->enable_remote_branches)
1006 for_each_remote_ref(print_branch_option, ctx.qry.head); 1017 for_each_remote_ref(print_branch_option, ctx.qry.head);
1018 html("</optgroup>");
1007 html("</select> "); 1019 html("</select> ");
1008 html("<input type='submit' value='switch'/>"); 1020 html("<input type='submit' value='switch'/>");
1009 html("</form>"); 1021 html("</form>");
@@ -1016,7 +1028,13 @@ static void print_header(void)
1016 if (ctx.repo) { 1028 if (ctx.repo) {
1017 html_txt(ctx.repo->desc); 1029 html_txt(ctx.repo->desc);
1018 html("</td><td class='sub right'>"); 1030 html("</td><td class='sub right'>");
1019 html_txt(ctx.repo->owner); 1031 if (ctx.repo->owner_filter) {
1032 cgit_open_filter(ctx.repo->owner_filter);
1033 html_txt(ctx.repo->owner);
1034 cgit_close_filter(ctx.repo->owner_filter);
1035 } else {
1036 html_txt(ctx.repo->owner);
1037 }
1020 } else { 1038 } else {
1021 if (ctx.cfg.root_desc) 1039 if (ctx.cfg.root_desc)
1022 html_txt(ctx.cfg.root_desc); 1040 html_txt(ctx.cfg.root_desc);
@@ -1032,32 +1050,41 @@ void cgit_print_pageheader(void)
1032 1050
1033 html("<table class='tabs'><tr><td>\n"); 1051 html("<table class='tabs'><tr><td>\n");
1034 if (ctx.env.authenticated && ctx.repo) { 1052 if (ctx.env.authenticated && ctx.repo) {
1035 if (ctx.repo->readme.nr) 1053 if (ctx.repo->readme.nr) {
1036 reporevlink("about", "about", NULL, 1054 reporevlink("about", "about", NULL,
1037 hc("about"), ctx.qry.head, NULL, 1055 hc("about"), ctx.qry.head, NULL,
1038 NULL); 1056 NULL);
1057 html(" ");
1058 }
1039 cgit_summary_link("summary", NULL, hc("summary"), 1059 cgit_summary_link("summary", NULL, hc("summary"),
1040 ctx.qry.head); 1060 ctx.qry.head);
1061 html(" ");
1041 cgit_refs_link("refs", NULL, hc("refs"), ctx.qry.head, 1062 cgit_refs_link("refs", NULL, hc("refs"), ctx.qry.head,
1042 ctx.qry.oid, NULL); 1063 ctx.qry.oid, NULL);
1064 html(" ");
1043 cgit_log_link("log", NULL, hc("log"), ctx.qry.head, 1065 cgit_log_link("log", NULL, hc("log"), ctx.qry.head,
1044 NULL, ctx.qry.vpath, 0, NULL, NULL, 1066 NULL, ctx.qry.vpath, 0, NULL, NULL,
1045 ctx.qry.showmsg, ctx.qry.follow); 1067 ctx.qry.showmsg, ctx.qry.follow);
1068 html(" ");
1046 if (ctx.qry.page && !strcmp(ctx.qry.page, "blame")) 1069 if (ctx.qry.page && !strcmp(ctx.qry.page, "blame"))
1047 cgit_blame_link("blame", NULL, hc("blame"), ctx.qry.head, 1070 cgit_blame_link("blame", NULL, hc("blame"), ctx.qry.head,
1048 ctx.qry.oid, ctx.qry.vpath); 1071 ctx.qry.oid, ctx.qry.vpath);
1049 else 1072 else
1050 cgit_tree_link("tree", NULL, hc("tree"), ctx.qry.head, 1073 cgit_tree_link("tree", NULL, hc("tree"), ctx.qry.head,
1051 ctx.qry.oid, ctx.qry.vpath); 1074 ctx.qry.oid, ctx.qry.vpath);
1075 html(" ");
1052 cgit_commit_link("commit", NULL, hc("commit"), 1076 cgit_commit_link("commit", NULL, hc("commit"),
1053 ctx.qry.head, ctx.qry.oid, ctx.qry.vpath); 1077 ctx.qry.head, ctx.qry.oid, ctx.qry.vpath);
1078 html(" ");
1054 cgit_diff_link("diff", NULL, hc("diff"), ctx.qry.head, 1079 cgit_diff_link("diff", NULL, hc("diff"), ctx.qry.head,
1055 ctx.qry.oid, ctx.qry.oid2, ctx.qry.vpath); 1080 ctx.qry.oid, ctx.qry.oid2, ctx.qry.vpath);
1056 if (ctx.repo->max_stats) 1081 if (ctx.repo->max_stats) {
1082 html(" ");
1057 cgit_stats_link("stats", NULL, hc("stats"), 1083 cgit_stats_link("stats", NULL, hc("stats"),
1058 ctx.qry.head, ctx.qry.vpath); 1084 ctx.qry.head, ctx.qry.vpath);
1085 }
1059 if (ctx.repo->homepage) { 1086 if (ctx.repo->homepage) {
1060 html("<a href='"); 1087 html(" <a href='");
1061 html_attr(ctx.repo->homepage); 1088 html_attr(ctx.repo->homepage);
1062 html("'>homepage</a>"); 1089 html("'>homepage</a>");
1063 } 1090 }
@@ -1201,9 +1228,12 @@ void cgit_set_title_from_path(const char *path)
1201 if (!path) 1228 if (!path)
1202 return; 1229 return;
1203 1230
1204 for (last_slash = path + strlen(path); (slash = memrchr(path, '/', last_slash - path)) != NULL; last_slash = slash) { 1231 last_slash = path + strlen(path);
1232 for (slash = last_slash; slash > path; --slash) {
1233 if (*slash != '/') continue;
1205 strbuf_add(&sb, slash + 1, last_slash - slash - 1); 1234 strbuf_add(&sb, slash + 1, last_slash - slash - 1);
1206 strbuf_addstr(&sb, " \xc2\xab "); 1235 strbuf_addstr(&sb, " \xc2\xab ");
1236 last_slash = slash;
1207 } 1237 }
1208 strbuf_add(&sb, path, last_slash - path); 1238 strbuf_add(&sb, path, last_slash - path);
1209 strbuf_addf(&sb, " - %s", ctx.page.title); 1239 strbuf_addf(&sb, " - %s", ctx.page.title);
diff --git a/ui-snapshot.c b/ui-snapshot.c index 18361a6..2801393 100644 --- a/ui-snapshot.c +++ b/ui-snapshot.c
@@ -37,6 +37,9 @@ static int write_archive_type(const char *format, const char *hex, const char *p
37 /* strvec guarantees a trailing NULL entry. */ 37 /* strvec guarantees a trailing NULL entry. */
38 memcpy(nargv, argv.v, sizeof(char *) * (argv.nr + 1)); 38 memcpy(nargv, argv.v, sizeof(char *) * (argv.nr + 1));
39 39
40 if (fflush(stdout))
41 return errno;
42
40 result = write_archive(argv.nr, nargv, NULL, the_repository, NULL, 0); 43 result = write_archive(argv.nr, nargv, NULL, the_repository, NULL, 0);
41 strvec_clear(&argv); 44 strvec_clear(&argv);
42 free(nargv); 45 free(nargv);
diff --git a/ui-tag.c b/ui-tag.c index 424bbcc..0595242 100644 --- a/ui-tag.c +++ b/ui-tag.c
@@ -25,9 +25,9 @@ static void print_tag_content(char *buf)
25 html_txt(buf); 25 html_txt(buf);
26 html("</div>"); 26 html("</div>");
27 if (p) { 27 if (p) {
28 html("<div class='commit-msg'>"); 28 html("<pre class='commit-msg'>");
29 html_txt(++p); 29 html_txt(++p);
30 html("</div>"); 30 html("</pre>");
31 } 31 }
32} 32}
33 33
diff --git a/ui-tree.c b/ui-tree.c index b61f6f5..21e0b88 100644 --- a/ui-tree.c +++ b/ui-tree.c
@@ -89,6 +89,7 @@ static void print_object(const struct object_id *oid, const char *path, const ch
89 enum object_type type; 89 enum object_type type;
90 char *buf; 90 char *buf;
91 unsigned long size; 91 unsigned long size;
92 int is_binary;
92 93
93 type = oid_object_info(the_repository, oid, &size); 94 type = oid_object_info(the_repository, oid, &size);
94 if (type == OBJ_BAD) { 95 if (type == OBJ_BAD) {
@@ -103,6 +104,7 @@ static void print_object(const struct object_id *oid, const char *path, const ch
103 "Error reading object %s", oid_to_hex(oid)); 104 "Error reading object %s", oid_to_hex(oid));
104 return; 105 return;
105 } 106 }
107 is_binary = buffer_is_binary(buf, size);
106 108
107 cgit_set_title_from_path(path); 109 cgit_set_title_from_path(path);
108 110
@@ -110,7 +112,7 @@ static void print_object(const struct object_id *oid, const char *path, const ch
110 htmlf("blob: %s (", oid_to_hex(oid)); 112 htmlf("blob: %s (", oid_to_hex(oid));
111 cgit_plain_link("plain", NULL, NULL, ctx.qry.head, 113 cgit_plain_link("plain", NULL, NULL, ctx.qry.head,
112 rev, path); 114 rev, path);
113 if (ctx.repo->enable_blame) { 115 if (ctx.repo->enable_blame && !is_binary) {
114 html(") ("); 116 html(") (");
115 cgit_blame_link("blame", NULL, NULL, ctx.qry.head, 117 cgit_blame_link("blame", NULL, NULL, ctx.qry.head,
116 rev, path); 118 rev, path);
@@ -123,7 +125,7 @@ static void print_object(const struct object_id *oid, const char *path, const ch
123 return; 125 return;
124 } 126 }
125 127
126 if (buffer_is_binary(buf, size)) 128 if (is_binary)
127 print_binary_buffer(buf, size); 129 print_binary_buffer(buf, size);
128 else 130 else
129 print_text_buffer(basename, buf, size); 131 print_text_buffer(basename, buf, size);
@@ -202,9 +204,11 @@ static int ls_item(const struct object_id *oid, struct strbuf *base,
202 struct walk_tree_context *walk_tree_ctx = cbdata; 204 struct walk_tree_context *walk_tree_ctx = cbdata;
203 char *name; 205 char *name;
204 struct strbuf fullpath = STRBUF_INIT; 206 struct strbuf fullpath = STRBUF_INIT;
207 struct strbuf linkpath = STRBUF_INIT;
205 struct strbuf class = STRBUF_INIT; 208 struct strbuf class = STRBUF_INIT;
206 enum object_type type; 209 enum object_type type;
207 unsigned long size = 0; 210 unsigned long size = 0;
211 char *buf;
208 212
209 name = xstrdup(pathname); 213 name = xstrdup(pathname);
210 strbuf_addf(&fullpath, "%s%s%s", ctx.qry.path ? ctx.qry.path : "", 214 strbuf_addf(&fullpath, "%s%s%s", ctx.qry.path ? ctx.qry.path : "",
@@ -216,8 +220,7 @@ static int ls_item(const struct object_id *oid, struct strbuf *base,
216 htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", 220 htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>",
217 name, 221 name,
218 oid_to_hex(oid)); 222 oid_to_hex(oid));
219 free(name); 223 goto cleanup;
220 return 0;
221 } 224 }
222 } 225 }
223 226
@@ -237,22 +240,45 @@ static int ls_item(const struct object_id *oid, struct strbuf *base,
237 cgit_tree_link(name, NULL, class.buf, ctx.qry.head, 240 cgit_tree_link(name, NULL, class.buf, ctx.qry.head,
238 walk_tree_ctx->curr_rev, fullpath.buf); 241 walk_tree_ctx->curr_rev, fullpath.buf);
239 } 242 }
243 if (S_ISLNK(mode)) {
244 html(" -> ");
245 buf = read_object_file(oid, &type, &size);
246 if (!buf) {
247 htmlf("Error reading object: %s", oid_to_hex(oid));
248 goto cleanup;
249 }
250 strbuf_addbuf(&linkpath, &fullpath);
251 strbuf_addf(&linkpath, "/../%s", buf);
252 strbuf_normalize_path(&linkpath);
253 cgit_tree_link(buf, NULL, class.buf, ctx.qry.head,
254 walk_tree_ctx->curr_rev, linkpath.buf);
255 free(buf);
256 strbuf_release(&linkpath);
257 }
240 htmlf("</td><td class='ls-size'>%li</td>", size); 258 htmlf("</td><td class='ls-size'>%li</td>", size);
241 259
242 html("<td>"); 260 html("<td>");
243 cgit_log_link("log", NULL, "button", ctx.qry.head, 261 cgit_log_link("log", NULL, "button", ctx.qry.head,
244 walk_tree_ctx->curr_rev, fullpath.buf, 0, NULL, NULL, 262 walk_tree_ctx->curr_rev, fullpath.buf, 0, NULL, NULL,
245 ctx.qry.showmsg, 0); 263 ctx.qry.showmsg, 0);
246 if (ctx.repo->max_stats) 264 if (ctx.repo->max_stats) {
265 html(" ");
247 cgit_stats_link("stats", NULL, "button", ctx.qry.head, 266 cgit_stats_link("stats", NULL, "button", ctx.qry.head,
248 fullpath.buf); 267 fullpath.buf);
249 if (!S_ISGITLINK(mode)) 268 }
269 if (!S_ISGITLINK(mode)) {
270 html(" ");
250 cgit_plain_link("plain", NULL, "button", ctx.qry.head, 271 cgit_plain_link("plain", NULL, "button", ctx.qry.head,
251 walk_tree_ctx->curr_rev, fullpath.buf); 272 walk_tree_ctx->curr_rev, fullpath.buf);
252 if (!S_ISDIR(mode) && ctx.repo->enable_blame) 273 }
274 if (!S_ISDIR(mode) && ctx.repo->enable_blame) {
275 html(" ");
253 cgit_blame_link("blame", NULL, "button", ctx.qry.head, 276 cgit_blame_link("blame", NULL, "button", ctx.qry.head,
254 walk_tree_ctx->curr_rev, fullpath.buf); 277 walk_tree_ctx->curr_rev, fullpath.buf);
278 }
255 html("</td></tr>\n"); 279 html("</td></tr>\n");
280
281cleanup:
256 free(name); 282 free(name);
257 strbuf_release(&fullpath); 283 strbuf_release(&fullpath);
258 strbuf_release(&class); 284 strbuf_release(&class);