diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2013-05-26 22:20:02 (JST) |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2013-05-26 23:30:03 (JST) |
commit | dcbc0438b2543a733858d62170f3110a89edbed6 (patch) | |
tree | bdacfe4546c88bf6b03860ea69a0cad885fa6af4 | |
parent | fe36f84d843cd755c6dab629a0758264de5bcc00 (diff) | |
download | cgit-dcbc0438b2543a733858d62170f3110a89edbed6.zip cgit-dcbc0438b2543a733858d62170f3110a89edbed6.tar.gz |
readme: use string_list instead of space deliminations
Now this is possible in cgitrc -
readme=:README.md
readme=:readme.md
readme=:README.mkd
readme=:readme.mkd
readme=:README.rst
readme=:readme.rst
readme=:README.html
readme=:readme.html
readme=:README.htm
readme=:readme.htm
readme=:README.txt
readme=:readme.txt
readme=:README
readme=:readme
readme=:INSTALL.txt
readme=:install.txt
readme=:INSTALL
readme=:install
Suggested-by: John Keeping <john@keeping.me.uk>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r-- | cgit.c | 92 | ||||
-rw-r--r-- | cgit.h | 4 | ||||
-rw-r--r-- | cgitrc.5.txt | 5 | ||||
-rw-r--r-- | cmd.c | 3 | ||||
-rw-r--r-- | scan-tree.c | 8 | ||||
-rw-r--r-- | ui-blob.c | 61 | ||||
-rw-r--r-- | ui-blob.h | 6 | ||||
-rw-r--r-- | ui-shared.c | 2 | ||||
-rw-r--r-- | ui-summary.c | 100 | ||||
-rw-r--r-- | ui-summary.h | 1 |
10 files changed, 160 insertions, 122 deletions
@@ -1,7 +1,7 @@ | |||
1 | /* cgit.c: cgi for the git scm | 1 | /* cgit.c: cgi for the git scm |
2 | * | 2 | * |
3 | * Copyright (C) 2006 Lars Hjemli | 3 | * Copyright (C) 2006 Lars Hjemli |
4 | * Copyright (C) 2010, 2012 Jason A. Donenfeld <Jason@zx2c4.com> | 4 | * Copyright (C) 2010-2013 Jason A. Donenfeld <Jason@zx2c4.com> |
5 | * | 5 | * |
6 | * Licensed under GNU General Public License v2 | 6 | * Licensed under GNU General Public License v2 |
7 | * (see COPYING for full license text) | 7 | * (see COPYING for full license text) |
@@ -101,13 +101,15 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va | |||
101 | else if (!strcmp(name, "module-link")) | 101 | else if (!strcmp(name, "module-link")) |
102 | repo->module_link= xstrdup(value); | 102 | repo->module_link= xstrdup(value); |
103 | else if (!prefixcmp(name, "module-link.")) { | 103 | else if (!prefixcmp(name, "module-link.")) { |
104 | item = string_list_append(&repo->submodules, name + 12); | 104 | item = string_list_append(&repo->submodules, xstrdup(name + 12)); |
105 | item->util = xstrdup(value); | 105 | item->util = xstrdup(value); |
106 | } else if (!strcmp(name, "section")) | 106 | } else if (!strcmp(name, "section")) |
107 | repo->section = xstrdup(value); | 107 | repo->section = xstrdup(value); |
108 | else if (!strcmp(name, "readme") && value != NULL) | 108 | else if (!strcmp(name, "readme") && value != NULL) { |
109 | repo->readme = xstrdup(value); | 109 | if (repo->readme.items == ctx.cfg.readme.items) |
110 | else if (!strcmp(name, "logo") && value != NULL) | 110 | memset(&repo->readme, 0, sizeof(repo->readme)); |
111 | string_list_append(&repo->readme, xstrdup(value)); | ||
112 | } else if (!strcmp(name, "logo") && value != NULL) | ||
111 | repo->logo = xstrdup(value); | 113 | repo->logo = xstrdup(value); |
112 | else if (!strcmp(name, "logo-link") && value != NULL) | 114 | else if (!strcmp(name, "logo-link") && value != NULL) |
113 | repo->logo_link = xstrdup(value); | 115 | repo->logo_link = xstrdup(value); |
@@ -131,8 +133,8 @@ static void config_cb(const char *name, const char *value) | |||
131 | ctx.repo->path = trim_end(value, '/'); | 133 | ctx.repo->path = trim_end(value, '/'); |
132 | else if (ctx.repo && !prefixcmp(name, "repo.")) | 134 | else if (ctx.repo && !prefixcmp(name, "repo.")) |
133 | repo_config(ctx.repo, name + 5, value); | 135 | repo_config(ctx.repo, name + 5, value); |
134 | else if (!strcmp(name, "readme")) | 136 | else if (!strcmp(name, "readme") && value != NULL) |
135 | ctx.cfg.readme = xstrdup(value); | 137 | string_list_append(&ctx.cfg.readme, xstrdup(value)); |
136 | else if (!strcmp(name, "root-title")) | 138 | else if (!strcmp(name, "root-title")) |
137 | ctx.cfg.root_title = xstrdup(value); | 139 | ctx.cfg.root_title = xstrdup(value); |
138 | else if (!strcmp(name, "root-desc")) | 140 | else if (!strcmp(name, "root-desc")) |
@@ -470,37 +472,76 @@ static char *guess_defbranch(void) | |||
470 | return "master"; | 472 | return "master"; |
471 | return xstrdup(ref + 11); | 473 | return xstrdup(ref + 11); |
472 | } | 474 | } |
475 | /* The caller must free filename and ref after calling this. */ | ||
476 | static inline void parse_readme(const char *readme, char **filename, char **ref, struct cgit_repo *repo) | ||
477 | { | ||
478 | const char *colon; | ||
479 | |||
480 | *filename = NULL; | ||
481 | *ref = NULL; | ||
482 | |||
483 | if (!readme || !readme[0]) | ||
484 | return; | ||
473 | 485 | ||
486 | /* Check if the readme is tracked in the git repo. */ | ||
487 | colon = strchr(readme, ':'); | ||
488 | if (colon && strlen(colon) > 1) { | ||
489 | /* If it starts with a colon, we want to use | ||
490 | * the default branch */ | ||
491 | if (colon == readme && repo->defbranch) | ||
492 | *ref = xstrdup(repo->defbranch); | ||
493 | else | ||
494 | *ref = xstrndup(readme, colon - readme); | ||
495 | readme = colon + 1; | ||
496 | } | ||
497 | |||
498 | /* Prepend repo path to relative readme path unless tracked. */ | ||
499 | if (!(*ref) && readme[0] != '/') | ||
500 | *filename = fmtalloc("%s/%s", repo->path, readme); | ||
501 | else | ||
502 | *filename = xstrdup(readme); | ||
503 | } | ||
474 | static void choose_readme(struct cgit_repo *repo) | 504 | static void choose_readme(struct cgit_repo *repo) |
475 | { | 505 | { |
476 | char *entry, *filename, *ref; | 506 | int found; |
507 | char *filename, *ref; | ||
508 | struct string_list_item *entry; | ||
477 | 509 | ||
478 | /* If there's no space, we skip the possibly expensive | 510 | if (!repo->readme.nr) |
479 | * selection process. */ | ||
480 | if (!repo->readme || !strchr(repo->readme, ' ')) | ||
481 | return; | 511 | return; |
482 | 512 | ||
483 | for (entry = strtok(repo->readme, " "); entry; entry = strtok(NULL, " ")) { | 513 | found = 0; |
484 | cgit_parse_readme(entry, NULL, &filename, &ref, repo); | 514 | for_each_string_list_item(entry, &repo->readme) { |
485 | if (!(*filename)) { | 515 | parse_readme(entry->string, &filename, &ref, repo); |
516 | if (!filename) { | ||
486 | free(filename); | 517 | free(filename); |
487 | free(ref); | 518 | free(ref); |
488 | continue; | 519 | continue; |
489 | } | 520 | } |
490 | if (*ref && cgit_ref_path_exists(filename, ref)) { | 521 | /* If there's only one item, we skip the possibly expensive |
491 | free(filename); | 522 | * selection process. */ |
492 | free(ref); | 523 | if (repo->readme.nr == 1) { |
524 | found = 1; | ||
493 | break; | 525 | break; |
494 | } | 526 | } |
495 | if (!access(filename, R_OK)) { | 527 | if (ref) { |
496 | free(filename); | 528 | if (cgit_ref_path_exists(filename, ref, 1)) { |
497 | free(ref); | 529 | found = 1; |
530 | break; | ||
531 | } | ||
532 | } | ||
533 | else if (!access(filename, R_OK)) { | ||
534 | found = 1; | ||
498 | break; | 535 | break; |
499 | } | 536 | } |
500 | free(filename); | 537 | free(filename); |
501 | free(ref); | 538 | free(ref); |
502 | } | 539 | } |
503 | repo->readme = entry; | 540 | repo->readme.strdup_strings = 1; |
541 | string_list_clear(&repo->readme, 0); | ||
542 | repo->readme.strdup_strings = 0; | ||
543 | if (found) | ||
544 | string_list_append(&repo->readme, filename)->util = ref; | ||
504 | } | 545 | } |
505 | 546 | ||
506 | static int prepare_repo_cmd(struct cgit_context *ctx) | 547 | static int prepare_repo_cmd(struct cgit_context *ctx) |
@@ -660,6 +701,7 @@ static char *get_first_line(char *txt) | |||
660 | 701 | ||
661 | static void print_repo(FILE *f, struct cgit_repo *repo) | 702 | static void print_repo(FILE *f, struct cgit_repo *repo) |
662 | { | 703 | { |
704 | struct string_list_item *item; | ||
663 | fprintf(f, "repo.url=%s\n", repo->url); | 705 | fprintf(f, "repo.url=%s\n", repo->url); |
664 | fprintf(f, "repo.name=%s\n", repo->name); | 706 | fprintf(f, "repo.name=%s\n", repo->name); |
665 | fprintf(f, "repo.path=%s\n", repo->path); | 707 | fprintf(f, "repo.path=%s\n", repo->path); |
@@ -670,8 +712,12 @@ static void print_repo(FILE *f, struct cgit_repo *repo) | |||
670 | fprintf(f, "repo.desc=%s\n", tmp); | 712 | fprintf(f, "repo.desc=%s\n", tmp); |
671 | free(tmp); | 713 | free(tmp); |
672 | } | 714 | } |
673 | if (repo->readme) | 715 | for_each_string_list_item(item, &repo->readme) { |
674 | fprintf(f, "repo.readme=%s\n", repo->readme); | 716 | if (item->util) |
717 | fprintf(f, "repo.readme=%s:%s\n", (char *)item->util, item->string); | ||
718 | else | ||
719 | fprintf(f, "repo.readme=%s\n", item->string); | ||
720 | } | ||
675 | if (repo->defbranch) | 721 | if (repo->defbranch) |
676 | fprintf(f, "repo.defbranch=%s\n", repo->defbranch); | 722 | fprintf(f, "repo.defbranch=%s\n", repo->defbranch); |
677 | if (repo->module_link) | 723 | if (repo->module_link) |
@@ -73,7 +73,7 @@ struct cgit_repo { | |||
73 | char *owner; | 73 | char *owner; |
74 | char *defbranch; | 74 | char *defbranch; |
75 | char *module_link; | 75 | char *module_link; |
76 | char *readme; | 76 | struct string_list readme; |
77 | char *section; | 77 | char *section; |
78 | char *clone_url; | 78 | char *clone_url; |
79 | char *logo; | 79 | char *logo; |
@@ -183,7 +183,7 @@ struct cgit_config { | |||
183 | char *mimetype_file; | 183 | char *mimetype_file; |
184 | char *module_link; | 184 | char *module_link; |
185 | char *project_list; | 185 | char *project_list; |
186 | char *readme; | 186 | struct string_list readme; |
187 | char *robots; | 187 | char *robots; |
188 | char *root_title; | 188 | char *root_title; |
189 | char *root_desc; | 189 | char *root_desc; |
diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 12a843b..6437ef4 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt | |||
@@ -290,8 +290,9 @@ project-list:: | |||
290 | 290 | ||
291 | readme:: | 291 | readme:: |
292 | Text which will be used as default value for "repo.readme". Multiple | 292 | Text which will be used as default value for "repo.readme". Multiple |
293 | files may be specified, separated by a space, and cgit will use the | 293 | config keys may be specified, and cgit will use the first found file |
294 | first found file in this list. Default value: none. | 294 | in this list. This is useful in conjunction with scan-path. Default |
295 | value: none. See also: scan-path, repo.readme. | ||
295 | 296 | ||
296 | remove-suffix:: | 297 | remove-suffix:: |
297 | If set to "1" and scan-path is enabled, if any repositories are found | 298 | If set to "1" and scan-path is enabled, if any repositories are found |
@@ -1,6 +1,7 @@ | |||
1 | /* cmd.c: the cgit command dispatcher | 1 | /* cmd.c: the cgit command dispatcher |
2 | * | 2 | * |
3 | * Copyright (C) 2008 Lars Hjemli | 3 | * Copyright (C) 2008 Lars Hjemli |
4 | * Copyright (C) 2013 Jason A. Donenfeld <Jason@zx2c4.com>. | ||
4 | * | 5 | * |
5 | * Licensed under GNU General Public License v2 | 6 | * Licensed under GNU General Public License v2 |
6 | * (see COPYING for full license text) | 7 | * (see COPYING for full license text) |
@@ -46,7 +47,7 @@ static void about_fn(struct cgit_context *ctx) | |||
46 | 47 | ||
47 | static void blob_fn(struct cgit_context *ctx) | 48 | static void blob_fn(struct cgit_context *ctx) |
48 | { | 49 | { |
49 | cgit_print_blob(ctx->qry.sha1, ctx->qry.path, ctx->qry.head); | 50 | cgit_print_blob(ctx->qry.sha1, ctx->qry.path, ctx->qry.head, 0); |
50 | } | 51 | } |
51 | 52 | ||
52 | static void commit_fn(struct cgit_context *ctx) | 53 | static void commit_fn(struct cgit_context *ctx) |
diff --git a/scan-tree.c b/scan-tree.c index a1ec8fb..2684b44 100644 --- a/scan-tree.c +++ b/scan-tree.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* scan-tree.c | 1 | /* scan-tree.c |
2 | * | 2 | * |
3 | * Copyright (C) 2008-2009 Lars Hjemli | 3 | * Copyright (C) 2008-2009 Lars Hjemli |
4 | * Copyright (C) 2010, 2012 Jason A. Donenfeld <Jason@zx2c4.com> | 4 | * Copyright (C) 2010-2013 Jason A. Donenfeld <Jason@zx2c4.com> |
5 | * | 5 | * |
6 | * Licensed under GNU General Public License v2 | 6 | * Licensed under GNU General Public License v2 |
7 | * (see COPYING for full license text) | 7 | * (see COPYING for full license text) |
@@ -147,12 +147,6 @@ static void add_repo(const char *base, struct strbuf *path, repo_config_fn fn) | |||
147 | strbuf_setlen(path, pathlen); | 147 | strbuf_setlen(path, pathlen); |
148 | } | 148 | } |
149 | 149 | ||
150 | if (!repo->readme) { | ||
151 | strbuf_addstr(path, "README.html"); | ||
152 | if (!stat(path->buf, &st)) | ||
153 | repo->readme = "README.html"; | ||
154 | strbuf_setlen(path, pathlen); | ||
155 | } | ||
156 | if (ctx.cfg.section_from_path) { | 150 | if (ctx.cfg.section_from_path) { |
157 | n = ctx.cfg.section_from_path; | 151 | n = ctx.cfg.section_from_path; |
158 | if (n > 0) { | 152 | if (n > 0) { |
@@ -1,7 +1,7 @@ | |||
1 | /* ui-blob.c: show blob content | 1 | /* ui-blob.c: show blob content |
2 | * | 2 | * |
3 | * Copyright (C) 2008 Lars Hjemli | 3 | * Copyright (C) 2008 Lars Hjemli |
4 | * Copyright (C) 2010 Jason A. Donenfeld <Jason@zx2c4.com> | 4 | * Copyright (C) 2010-2013 Jason A. Donenfeld <Jason@zx2c4.com> |
5 | * | 5 | * |
6 | * Licensed under GNU General Public License v2 | 6 | * Licensed under GNU General Public License v2 |
7 | * (see COPYING for full license text) | 7 | * (see COPYING for full license text) |
@@ -15,7 +15,8 @@ | |||
15 | struct walk_tree_context { | 15 | struct walk_tree_context { |
16 | const 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:1; |
19 | int file_only:1; | ||
19 | }; | 20 | }; |
20 | 21 | ||
21 | static int walk_tree(const unsigned char *sha1, const char *base, int baselen, | 22 | static int walk_tree(const unsigned char *sha1, const char *base, int baselen, |
@@ -23,6 +24,8 @@ static int walk_tree(const unsigned char *sha1, const char *base, int baselen, | |||
23 | { | 24 | { |
24 | struct walk_tree_context *walk_tree_ctx = cbdata; | 25 | struct walk_tree_context *walk_tree_ctx = cbdata; |
25 | 26 | ||
27 | if (walk_tree_ctx->file_only && !S_ISREG(mode)) | ||
28 | return READ_TREE_RECURSIVE; | ||
26 | if (strncmp(base, walk_tree_ctx->match_path, baselen) | 29 | if (strncmp(base, walk_tree_ctx->match_path, baselen) |
27 | || strcmp(walk_tree_ctx->match_path + baselen, pathname)) | 30 | || strcmp(walk_tree_ctx->match_path + baselen, pathname)) |
28 | return READ_TREE_RECURSIVE; | 31 | return READ_TREE_RECURSIVE; |
@@ -31,33 +34,34 @@ static int walk_tree(const unsigned char *sha1, const char *base, int baselen, | |||
31 | return 0; | 34 | return 0; |
32 | } | 35 | } |
33 | 36 | ||
34 | int cgit_ref_path_exists(const char *path, const char *ref) | 37 | int cgit_ref_path_exists(const char *path, const char *ref, int file_only) |
35 | { | 38 | { |
36 | unsigned char sha1[20]; | 39 | unsigned char sha1[20]; |
37 | unsigned long size; | 40 | unsigned long size; |
38 | struct pathspec_item path_items = { | 41 | struct pathspec_item path_items = { |
39 | .match = path, | 42 | .match = path, |
40 | .len = strlen(path) | 43 | .len = strlen(path) |
41 | }; | 44 | }; |
42 | struct pathspec paths = { | 45 | struct pathspec paths = { |
43 | .nr = 1, | 46 | .nr = 1, |
44 | .items = &path_items | 47 | .items = &path_items |
45 | }; | 48 | }; |
46 | struct walk_tree_context walk_tree_ctx = { | 49 | struct walk_tree_context walk_tree_ctx = { |
47 | .match_path = path, | 50 | .match_path = path, |
48 | .matched_sha1 = sha1, | 51 | .matched_sha1 = sha1, |
49 | .found_path = 0 | 52 | .found_path = 0, |
50 | }; | 53 | .file_only = file_only |
54 | }; | ||
51 | 55 | ||
52 | if (get_sha1(ref, sha1)) | 56 | if (get_sha1(ref, sha1)) |
53 | return 0; | 57 | return 0; |
54 | if (sha1_object_info(sha1, &size) != OBJ_COMMIT) | 58 | if (sha1_object_info(sha1, &size) != OBJ_COMMIT) |
55 | return 0; | 59 | return 0; |
56 | read_tree_recursive(lookup_commit_reference(sha1)->tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx); | 60 | read_tree_recursive(lookup_commit_reference(sha1)->tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx); |
57 | return walk_tree_ctx.found_path; | 61 | return walk_tree_ctx.found_path; |
58 | } | 62 | } |
59 | 63 | ||
60 | int cgit_print_file(char *path, const char *head) | 64 | int cgit_print_file(char *path, const char *head, int file_only) |
61 | { | 65 | { |
62 | unsigned char sha1[20]; | 66 | unsigned char sha1[20]; |
63 | enum object_type type; | 67 | enum object_type type; |
@@ -75,7 +79,8 @@ int cgit_print_file(char *path, const char *head) | |||
75 | struct walk_tree_context walk_tree_ctx = { | 79 | struct walk_tree_context walk_tree_ctx = { |
76 | .match_path = path, | 80 | .match_path = path, |
77 | .matched_sha1 = sha1, | 81 | .matched_sha1 = sha1, |
78 | .found_path = 0 | 82 | .found_path = 0, |
83 | .file_only = file_only | ||
79 | }; | 84 | }; |
80 | 85 | ||
81 | if (get_sha1(head, sha1)) | 86 | if (get_sha1(head, sha1)) |
@@ -98,7 +103,7 @@ int cgit_print_file(char *path, const char *head) | |||
98 | return 0; | 103 | return 0; |
99 | } | 104 | } |
100 | 105 | ||
101 | void cgit_print_blob(const char *hex, char *path, const char *head) | 106 | void cgit_print_blob(const char *hex, char *path, const char *head, int file_only) |
102 | { | 107 | { |
103 | unsigned char sha1[20]; | 108 | unsigned char sha1[20]; |
104 | enum object_type type; | 109 | enum object_type type; |
@@ -116,6 +121,8 @@ void cgit_print_blob(const char *hex, char *path, const char *head) | |||
116 | struct walk_tree_context walk_tree_ctx = { | 121 | struct walk_tree_context walk_tree_ctx = { |
117 | .match_path = path, | 122 | .match_path = path, |
118 | .matched_sha1 = sha1, | 123 | .matched_sha1 = sha1, |
124 | .found_path = 0, | ||
125 | .file_only = file_only | ||
119 | }; | 126 | }; |
120 | 127 | ||
121 | if (hex) { | 128 | if (hex) { |
@@ -1,8 +1,8 @@ | |||
1 | #ifndef UI_BLOB_H | 1 | #ifndef UI_BLOB_H |
2 | #define UI_BLOB_H | 2 | #define UI_BLOB_H |
3 | 3 | ||
4 | extern int cgit_ref_path_exists(const char *path, const char *ref); | 4 | extern int cgit_ref_path_exists(const char *path, const char *ref, int file_only); |
5 | extern int cgit_print_file(char *path, const char *head); | 5 | extern int cgit_print_file(char *path, const char *head, int file_only); |
6 | extern void cgit_print_blob(const char *hex, char *path, const char *head); | 6 | extern void cgit_print_blob(const char *hex, char *path, const char *head, int file_only); |
7 | 7 | ||
8 | #endif /* UI_BLOB_H */ | 8 | #endif /* UI_BLOB_H */ |
diff --git a/ui-shared.c b/ui-shared.c index 519eef7..7ab2ab1 100644 --- a/ui-shared.c +++ b/ui-shared.c | |||
@@ -864,7 +864,7 @@ void cgit_print_pageheader(struct cgit_context *ctx) | |||
864 | if (ctx->repo->max_stats) | 864 | if (ctx->repo->max_stats) |
865 | cgit_stats_link("stats", NULL, hc(ctx, "stats"), | 865 | cgit_stats_link("stats", NULL, hc(ctx, "stats"), |
866 | ctx->qry.head, ctx->qry.vpath); | 866 | ctx->qry.head, ctx->qry.vpath); |
867 | if (ctx->repo->readme) | 867 | if (ctx->repo->readme.nr) |
868 | reporevlink("about", "about", NULL, | 868 | reporevlink("about", "about", NULL, |
869 | hc(ctx, "about"), ctx->qry.head, NULL, | 869 | hc(ctx, "about"), ctx->qry.head, NULL, |
870 | NULL); | 870 | NULL); |
diff --git a/ui-summary.c b/ui-summary.c index 57206dd..d8500d6 100644 --- a/ui-summary.c +++ b/ui-summary.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* ui-summary.c: functions for generating repo summary page | 1 | /* ui-summary.c: functions for generating repo summary page |
2 | * | 2 | * |
3 | * Copyright (C) 2006 Lars Hjemli | 3 | * Copyright (C) 2006 Lars Hjemli |
4 | * Copyright (C) 2010 Jason A. Donenfeld <Jason@zx2c4.com> | 4 | * Copyright (C) 2010-2013 Jason A. Donenfeld <Jason@zx2c4.com> |
5 | * | 5 | * |
6 | * Licensed under GNU General Public License v2 | 6 | * Licensed under GNU General Public License v2 |
7 | * (see COPYING for full license text) | 7 | * (see COPYING for full license text) |
@@ -13,6 +13,7 @@ | |||
13 | #include "ui-log.h" | 13 | #include "ui-log.h" |
14 | #include "ui-refs.h" | 14 | #include "ui-refs.h" |
15 | #include "ui-blob.h" | 15 | #include "ui-blob.h" |
16 | #include <libgen.h> | ||
16 | 17 | ||
17 | static void print_url(char *base, char *suffix) | 18 | static void print_url(char *base, char *suffix) |
18 | { | 19 | { |
@@ -95,69 +96,57 @@ void cgit_print_summary() | |||
95 | html("</table>"); | 96 | html("</table>"); |
96 | } | 97 | } |
97 | 98 | ||
98 | /* The caller must free filename and ref after calling this. */ | 99 | /* The caller must free the return value. */ |
99 | void cgit_parse_readme(const char *readme, const char *path, char **filename, char **ref, struct cgit_repo *repo) | 100 | static char* append_readme_path(const char *filename, const char *ref, const char *path) |
100 | { | 101 | { |
101 | const char *slash, *colon; | 102 | char *file, *base_dir, *full_path, *resolved_base = NULL, *resolved_full = NULL; |
102 | char *resolved_base, *resolved_full; | ||
103 | |||
104 | *filename = NULL; | ||
105 | *ref = NULL; | ||
106 | |||
107 | if (!readme || !(*readme)) | ||
108 | return; | ||
109 | |||
110 | /* Check if the readme is tracked in the git repo. */ | ||
111 | colon = strchr(readme, ':'); | ||
112 | if (colon && strlen(colon) > 1) { | ||
113 | /* If it starts with a colon, we want to use | ||
114 | * the default branch */ | ||
115 | if (colon == readme && repo->defbranch) | ||
116 | *ref = xstrdup(repo->defbranch); | ||
117 | else | ||
118 | *ref = xstrndup(readme, colon - readme); | ||
119 | readme = colon + 1; | ||
120 | } | ||
121 | |||
122 | /* Prepend repo path to relative readme path unless tracked. */ | ||
123 | if (!(*ref) && *readme != '/') | ||
124 | readme = fmtalloc("%s/%s", repo->path, readme); | ||
125 | |||
126 | /* If a subpath is specified for the about page, make it relative | 103 | /* If a subpath is specified for the about page, make it relative |
127 | * to the directory containing the configured readme. */ | 104 | * to the directory containing the configured readme. */ |
128 | if (path) { | 105 | |
129 | slash = strrchr(readme, '/'); | 106 | file = xstrdup(filename); |
130 | if (!slash) { | 107 | base_dir = dirname(file); |
131 | if (!colon) | 108 | if (!strcmp(base_dir, ".") || !strcmp(base_dir, "..")) { |
132 | return; | 109 | if (!ref) { |
133 | slash = colon; | 110 | free(file); |
134 | } | 111 | return NULL; |
135 | *filename = xmalloc(slash - readme + 1 + strlen(path) + 1); | ||
136 | strncpy(*filename, readme, slash - readme + 1); | ||
137 | if (!(*ref)) | ||
138 | resolved_base = realpath(*filename, NULL); | ||
139 | strcpy(*filename + (slash - readme + 1), path); | ||
140 | if (!(*ref)) | ||
141 | resolved_full = realpath(*filename, NULL); | ||
142 | if (!(*ref) && (!resolved_base || !resolved_full || strstr(resolved_full, resolved_base) != resolved_full)) { | ||
143 | free(*filename); | ||
144 | *filename = NULL; | ||
145 | } | ||
146 | if (!(*ref)) { | ||
147 | free(resolved_base); | ||
148 | free(resolved_full); | ||
149 | } | 112 | } |
113 | full_path = xstrdup(path); | ||
150 | } else | 114 | } else |
151 | *filename = xstrdup(readme); | 115 | full_path = fmtalloc("%s/%s", base_dir, path); |
116 | |||
117 | if (!ref) { | ||
118 | resolved_base = realpath(base_dir, NULL); | ||
119 | resolved_full = realpath(full_path, NULL); | ||
120 | if (!resolved_base || !resolved_full || strncmp(resolved_base, resolved_full, strlen(resolved_base))) { | ||
121 | free(full_path); | ||
122 | full_path = NULL; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | free(file); | ||
127 | free(resolved_base); | ||
128 | free(resolved_full); | ||
129 | |||
130 | return full_path; | ||
152 | } | 131 | } |
153 | 132 | ||
154 | void cgit_print_repo_readme(char *path) | 133 | void cgit_print_repo_readme(char *path) |
155 | { | 134 | { |
156 | char *filename, *ref; | 135 | char *filename, *ref; |
157 | cgit_parse_readme(ctx.repo->readme, path, &filename, &ref, ctx.repo); | 136 | int free_filename = 0; |
158 | 137 | ||
159 | if (!filename) | 138 | if (ctx.repo->readme.nr == 0) |
160 | return; | 139 | return; |
140 | |||
141 | filename = ctx.repo->readme.items[0].string; | ||
142 | ref = ctx.repo->readme.items[0].util; | ||
143 | |||
144 | if (path) { | ||
145 | free_filename = 1; | ||
146 | filename = append_readme_path(filename, ref, path); | ||
147 | if (!filename) | ||
148 | return; | ||
149 | } | ||
161 | 150 | ||
162 | /* Print the calculated readme, either from the git repo or from the | 151 | /* Print the calculated readme, either from the git repo or from the |
163 | * filesystem, while applying the about-filter. | 152 | * filesystem, while applying the about-filter. |
@@ -168,14 +157,15 @@ void cgit_print_repo_readme(char *path) | |||
168 | cgit_open_filter(ctx.repo->about_filter); | 157 | cgit_open_filter(ctx.repo->about_filter); |
169 | } | 158 | } |
170 | if (ref) | 159 | if (ref) |
171 | cgit_print_file(filename, ref); | 160 | cgit_print_file(filename, ref, 1); |
172 | else | 161 | else |
173 | html_include(filename); | 162 | html_include(filename); |
174 | if (ctx.repo->about_filter) { | 163 | if (ctx.repo->about_filter) { |
175 | cgit_close_filter(ctx.repo->about_filter); | 164 | cgit_close_filter(ctx.repo->about_filter); |
176 | ctx.repo->about_filter->argv[1] = NULL; | 165 | ctx.repo->about_filter->argv[1] = NULL; |
166 | free(ref); | ||
177 | } | 167 | } |
178 | html("</div>"); | 168 | html("</div>"); |
179 | free(filename); | 169 | if (free_filename) |
180 | free(ref); | 170 | free(filename); |
181 | } | 171 | } |
diff --git a/ui-summary.h b/ui-summary.h index d6dc5ba..c01f560 100644 --- a/ui-summary.h +++ b/ui-summary.h | |||
@@ -1,7 +1,6 @@ | |||
1 | #ifndef UI_SUMMARY_H | 1 | #ifndef UI_SUMMARY_H |
2 | #define UI_SUMMARY_H | 2 | #define UI_SUMMARY_H |
3 | 3 | ||
4 | extern void cgit_parse_readme(const char *readme, const char *path, char **filename, char **ref, struct cgit_repo *repo); | ||
5 | extern void cgit_print_summary(); | 4 | extern void cgit_print_summary(); |
6 | extern void cgit_print_repo_readme(char *path); | 5 | extern void cgit_print_repo_readme(char *path); |
7 | 6 | ||