aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Jason A. Donenfeld <Jason@zx2c4.com>2013-05-25 23:32:37 (JST)
committerGravatar Jason A. Donenfeld <Jason@zx2c4.com>2013-05-26 03:33:28 (JST)
commitcd4c77d989983778432363061e99219f034c3717 (patch)
treea394b7960e7105c7dbcb130721298a49d49b8a75
parentc0dfaf1c281d0697ce43131343d7a9f170a61ff9 (diff)
downloadcgit-cd4c77d989983778432363061e99219f034c3717.zip
cgit-cd4c77d989983778432363061e99219f034c3717.tar.gz
readme: Accept multiple candidates and test them.
The readme variable may now contain multiple space deliminated entries, which per usual are either a filepath or a git ref filepath. If multiple are specified, cgit will now select the first one in the list that exists. This is to make it easier to specify multiple default readme types in the main cgitrc file and have them automatically get applied to each repo based on what exists. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--cgit.c35
-rw-r--r--ui-blob.c28
-rw-r--r--ui-blob.h1
-rw-r--r--ui-summary.c61
-rw-r--r--ui-summary.h1
5 files changed, 95 insertions, 31 deletions
diff --git a/cgit.c b/cgit.c
index 04682be..f738b83 100644
--- a/cgit.c
+++ b/cgit.c
@@ -14,6 +14,8 @@
14#include "html.h" 14#include "html.h"
15#include "ui-shared.h" 15#include "ui-shared.h"
16#include "ui-stats.h" 16#include "ui-stats.h"
17#include "ui-blob.h"
18#include "ui-summary.h"
17#include "scan-tree.h" 19#include "scan-tree.h"
18 20
19const char *cgit_version = CGIT_VERSION; 21const char *cgit_version = CGIT_VERSION;
@@ -469,6 +471,38 @@ static char *guess_defbranch(void)
469 return xstrdup(ref + 11); 471 return xstrdup(ref + 11);
470} 472}
471 473
474static void choose_readme(struct cgit_repo *repo)
475{
476 char *entry, *filename, *ref;
477
478 /* If there's no space, we skip the possibly expensive
479 * selection process. */
480 if (!repo->readme || !strchr(repo->readme, ' '))
481 return;
482
483 for (entry = strtok(repo->readme, " "); entry; entry = strtok(NULL, " ")) {
484 cgit_parse_readme(entry, NULL, &filename, &ref, repo);
485 if (!(*filename)) {
486 free(filename);
487 free(ref);
488 continue;
489 }
490 if (*ref && cgit_ref_path_exists(filename, ref)) {
491 free(filename);
492 free(ref);
493 break;
494 }
495 if (!access(filename, R_OK)) {
496 free(filename);
497 free(ref);
498 break;
499 }
500 free(filename);
501 free(ref);
502 }
503 repo->readme = entry;
504}
505
472static int prepare_repo_cmd(struct cgit_context *ctx) 506static int prepare_repo_cmd(struct cgit_context *ctx)
473{ 507{
474 unsigned char sha1[20]; 508 unsigned char sha1[20];
@@ -537,6 +571,7 @@ static int prepare_repo_cmd(struct cgit_context *ctx)
537 } 571 }
538 sort_string_list(&ctx->repo->submodules); 572 sort_string_list(&ctx->repo->submodules);
539 cgit_prepare_repo_env(ctx->repo); 573 cgit_prepare_repo_env(ctx->repo);
574 choose_readme(ctx->repo);
540 return 0; 575 return 0;
541} 576}
542 577
diff --git a/ui-blob.c b/ui-blob.c
index 8f6989f..b4be139 100644
--- a/ui-blob.c
+++ b/ui-blob.c
@@ -13,7 +13,7 @@
13#include "ui-shared.h" 13#include "ui-shared.h"
14 14
15struct walk_tree_context { 15struct walk_tree_context {
16 char *match_path; 16 const char *match_path;
17 unsigned char *matched_sha1; 17 unsigned char *matched_sha1;
18 int found_path; 18 int found_path;
19}; 19};
@@ -31,6 +31,32 @@ static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
31 return 0; 31 return 0;
32} 32}
33 33
34int cgit_ref_path_exists(const char *path, const char *ref)
35{
36 unsigned char sha1[20];
37 unsigned long size;
38 struct pathspec_item path_items = {
39 .match = path,
40 .len = strlen(path)
41 };
42 struct pathspec paths = {
43 .nr = 1,
44 .items = &path_items
45 };
46 struct walk_tree_context walk_tree_ctx = {
47 .match_path = path,
48 .matched_sha1 = sha1,
49 .found_path = 0
50 };
51
52 if (get_sha1(ref, sha1))
53 return 0;
54 if (sha1_object_info(sha1, &size) != OBJ_COMMIT)
55 return 0;
56 read_tree_recursive(lookup_commit_reference(sha1)->tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx);
57 return walk_tree_ctx.found_path;
58}
59
34int cgit_print_file(char *path, const char *head) 60int cgit_print_file(char *path, const char *head)
35{ 61{
36 unsigned char sha1[20]; 62 unsigned char sha1[20];
diff --git a/ui-blob.h b/ui-blob.h
index d7e7d45..ce3649f 100644
--- a/ui-blob.h
+++ b/ui-blob.h
@@ -1,6 +1,7 @@
1#ifndef UI_BLOB_H 1#ifndef UI_BLOB_H
2#define UI_BLOB_H 2#define UI_BLOB_H
3 3
4extern int cgit_ref_path_exists(const char *path, const char *ref);
4extern int cgit_print_file(char *path, const char *head); 5extern int cgit_print_file(char *path, const char *head);
5extern void cgit_print_blob(const char *hex, char *path, const char *head); 6extern void cgit_print_blob(const char *hex, char *path, const char *head);
6 7
diff --git a/ui-summary.c b/ui-summary.c
index ffad4f2..2f8a822 100644
--- a/ui-summary.c
+++ b/ui-summary.c
@@ -95,70 +95,71 @@ void cgit_print_summary()
95 html("</table>"); 95 html("</table>");
96} 96}
97 97
98void cgit_print_repo_readme(char *path) 98/* The caller must free filename and ref after calling this. */
99void cgit_parse_readme(const char *readme, const char *path, char **filename, char **ref, struct cgit_repo *repo)
99{ 100{
100 char *slash, *tmp, *colon, *ref; 101 const char *slash, *colon;
101 int free_filename = 0;
102 102
103 if (!ctx.repo->readme || !(*ctx.repo->readme)) 103 *filename = NULL;
104 return; 104 *ref = NULL;
105 105
106 ref = NULL; 106 if (!readme || !(*readme))
107 return;
107 108
108 /* Check if the readme is tracked in the git repo. */ 109 /* Check if the readme is tracked in the git repo. */
109 colon = strchr(ctx.repo->readme, ':'); 110 colon = strchr(readme, ':');
110 if (colon && strlen(colon) > 1) { 111 if (colon && strlen(colon) > 1) {
111 *colon = '\0';
112 /* If it starts with a colon, we want to use 112 /* If it starts with a colon, we want to use
113 * the default branch */ 113 * the default branch */
114 if (colon == ctx.repo->readme && ctx.repo->defbranch) 114 if (colon == readme && repo->defbranch)
115 ref = ctx.repo->defbranch; 115 *ref = xstrdup(repo->defbranch);
116 else 116 else
117 ref = ctx.repo->readme; 117 *ref = xstrndup(readme, colon - readme);
118 ctx.repo->readme = colon + 1; 118 readme = colon + 1;
119 if (!(*ctx.repo->readme))
120 return;
121 } 119 }
122 120
123 /* Prepend repo path to relative readme path unless tracked. */ 121 /* Prepend repo path to relative readme path unless tracked. */
124 if (!ref && *ctx.repo->readme != '/') 122 if (!(*ref) && *readme != '/')
125 ctx.repo->readme = fmtalloc("%s/%s", ctx.repo->path, 123 readme = fmtalloc("%s/%s", repo->path, readme);
126 ctx.repo->readme);
127 124
128 /* If a subpath is specified for the about page, make it relative 125 /* If a subpath is specified for the about page, make it relative
129 * to the directory containing the configured readme. 126 * to the directory containing the configured readme. */
130 */
131 if (path) { 127 if (path) {
132 slash = strrchr(ctx.repo->readme, '/'); 128 slash = strrchr(readme, '/');
133 if (!slash) { 129 if (!slash) {
134 if (!colon) 130 if (!colon)
135 return; 131 return;
136 slash = colon; 132 slash = colon;
137 } 133 }
138 free_filename = 1; 134 *filename = xmalloc(slash - readme + 1 + strlen(path) + 1);
139 tmp = xmalloc(slash - ctx.repo->readme + 1 + strlen(path) + 1); 135 strncpy(*filename, readme, slash - readme + 1);
140 strncpy(tmp, ctx.repo->readme, slash - ctx.repo->readme + 1); 136 strcpy(*filename + (slash - readme + 1), path);
141 strcpy(tmp + (slash - ctx.repo->readme + 1), path);
142 } else 137 } else
143 tmp = ctx.repo->readme; 138 *filename = xstrdup(readme);
139}
140
141void cgit_print_repo_readme(char *path)
142{
143 char *filename, *ref;
144 cgit_parse_readme(ctx.repo->readme, path, &filename, &ref, ctx.repo);
144 145
145 /* Print the calculated readme, either from the git repo or from the 146 /* Print the calculated readme, either from the git repo or from the
146 * filesystem, while applying the about-filter. 147 * filesystem, while applying the about-filter.
147 */ 148 */
148 html("<div id='summary'>"); 149 html("<div id='summary'>");
149 if (ctx.repo->about_filter) { 150 if (ctx.repo->about_filter) {
150 ctx.repo->about_filter->argv[1] = tmp; 151 ctx.repo->about_filter->argv[1] = filename;
151 cgit_open_filter(ctx.repo->about_filter); 152 cgit_open_filter(ctx.repo->about_filter);
152 } 153 }
153 if (ref) 154 if (ref)
154 cgit_print_file(tmp, ref); 155 cgit_print_file(filename, ref);
155 else 156 else
156 html_include(tmp); 157 html_include(filename);
157 if (ctx.repo->about_filter) { 158 if (ctx.repo->about_filter) {
158 cgit_close_filter(ctx.repo->about_filter); 159 cgit_close_filter(ctx.repo->about_filter);
159 ctx.repo->about_filter->argv[1] = NULL; 160 ctx.repo->about_filter->argv[1] = NULL;
160 } 161 }
161 html("</div>"); 162 html("</div>");
162 if (free_filename) 163 free(filename);
163 free(tmp); 164 free(ref);
164} 165}
diff --git a/ui-summary.h b/ui-summary.h
index c01f560..d6dc5ba 100644
--- a/ui-summary.h
+++ b/ui-summary.h
@@ -1,6 +1,7 @@
1#ifndef UI_SUMMARY_H 1#ifndef UI_SUMMARY_H
2#define UI_SUMMARY_H 2#define UI_SUMMARY_H
3 3
4extern void cgit_parse_readme(const char *readme, const char *path, char **filename, char **ref, struct cgit_repo *repo);
4extern void cgit_print_summary(); 5extern void cgit_print_summary();
5extern void cgit_print_repo_readme(char *path); 6extern void cgit_print_repo_readme(char *path);
6 7