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>
Cette révision appartient à :
Parent
c0dfaf1c28
révision
cd4c77d989
35
cgit.c
35
cgit.c
@ -14,6 +14,8 @@
|
|||||||
#include "html.h"
|
#include "html.h"
|
||||||
#include "ui-shared.h"
|
#include "ui-shared.h"
|
||||||
#include "ui-stats.h"
|
#include "ui-stats.h"
|
||||||
|
#include "ui-blob.h"
|
||||||
|
#include "ui-summary.h"
|
||||||
#include "scan-tree.h"
|
#include "scan-tree.h"
|
||||||
|
|
||||||
const char *cgit_version = CGIT_VERSION;
|
const char *cgit_version = CGIT_VERSION;
|
||||||
@ -469,6 +471,38 @@ static char *guess_defbranch(void)
|
|||||||
return xstrdup(ref + 11);
|
return xstrdup(ref + 11);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void choose_readme(struct cgit_repo *repo)
|
||||||
|
{
|
||||||
|
char *entry, *filename, *ref;
|
||||||
|
|
||||||
|
/* If there's no space, we skip the possibly expensive
|
||||||
|
* selection process. */
|
||||||
|
if (!repo->readme || !strchr(repo->readme, ' '))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (entry = strtok(repo->readme, " "); entry; entry = strtok(NULL, " ")) {
|
||||||
|
cgit_parse_readme(entry, NULL, &filename, &ref, repo);
|
||||||
|
if (!(*filename)) {
|
||||||
|
free(filename);
|
||||||
|
free(ref);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*ref && cgit_ref_path_exists(filename, ref)) {
|
||||||
|
free(filename);
|
||||||
|
free(ref);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!access(filename, R_OK)) {
|
||||||
|
free(filename);
|
||||||
|
free(ref);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(filename);
|
||||||
|
free(ref);
|
||||||
|
}
|
||||||
|
repo->readme = entry;
|
||||||
|
}
|
||||||
|
|
||||||
static int prepare_repo_cmd(struct cgit_context *ctx)
|
static int prepare_repo_cmd(struct cgit_context *ctx)
|
||||||
{
|
{
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
@ -537,6 +571,7 @@ static int prepare_repo_cmd(struct cgit_context *ctx)
|
|||||||
}
|
}
|
||||||
sort_string_list(&ctx->repo->submodules);
|
sort_string_list(&ctx->repo->submodules);
|
||||||
cgit_prepare_repo_env(ctx->repo);
|
cgit_prepare_repo_env(ctx->repo);
|
||||||
|
choose_readme(ctx->repo);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
ui-blob.c
28
ui-blob.c
@ -13,7 +13,7 @@
|
|||||||
#include "ui-shared.h"
|
#include "ui-shared.h"
|
||||||
|
|
||||||
struct walk_tree_context {
|
struct walk_tree_context {
|
||||||
char *match_path;
|
const char *match_path;
|
||||||
unsigned char *matched_sha1;
|
unsigned char *matched_sha1;
|
||||||
int found_path;
|
int found_path;
|
||||||
};
|
};
|
||||||
@ -31,6 +31,32 @@ static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cgit_ref_path_exists(const char *path, const char *ref)
|
||||||
|
{
|
||||||
|
unsigned char sha1[20];
|
||||||
|
unsigned long size;
|
||||||
|
struct pathspec_item path_items = {
|
||||||
|
.match = path,
|
||||||
|
.len = strlen(path)
|
||||||
|
};
|
||||||
|
struct pathspec paths = {
|
||||||
|
.nr = 1,
|
||||||
|
.items = &path_items
|
||||||
|
};
|
||||||
|
struct walk_tree_context walk_tree_ctx = {
|
||||||
|
.match_path = path,
|
||||||
|
.matched_sha1 = sha1,
|
||||||
|
.found_path = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (get_sha1(ref, sha1))
|
||||||
|
return 0;
|
||||||
|
if (sha1_object_info(sha1, &size) != OBJ_COMMIT)
|
||||||
|
return 0;
|
||||||
|
read_tree_recursive(lookup_commit_reference(sha1)->tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx);
|
||||||
|
return walk_tree_ctx.found_path;
|
||||||
|
}
|
||||||
|
|
||||||
int cgit_print_file(char *path, const char *head)
|
int cgit_print_file(char *path, const char *head)
|
||||||
{
|
{
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef UI_BLOB_H
|
#ifndef UI_BLOB_H
|
||||||
#define UI_BLOB_H
|
#define UI_BLOB_H
|
||||||
|
|
||||||
|
extern int cgit_ref_path_exists(const char *path, const char *ref);
|
||||||
extern int cgit_print_file(char *path, const char *head);
|
extern int cgit_print_file(char *path, const char *head);
|
||||||
extern void cgit_print_blob(const char *hex, char *path, const char *head);
|
extern void cgit_print_blob(const char *hex, char *path, const char *head);
|
||||||
|
|
||||||
|
61
ui-summary.c
61
ui-summary.c
@ -95,70 +95,71 @@ void cgit_print_summary()
|
|||||||
html("</table>");
|
html("</table>");
|
||||||
}
|
}
|
||||||
|
|
||||||
void cgit_print_repo_readme(char *path)
|
/* The caller must free filename and ref after calling this. */
|
||||||
|
void cgit_parse_readme(const char *readme, const char *path, char **filename, char **ref, struct cgit_repo *repo)
|
||||||
{
|
{
|
||||||
char *slash, *tmp, *colon, *ref;
|
const char *slash, *colon;
|
||||||
int free_filename = 0;
|
|
||||||
|
|
||||||
if (!ctx.repo->readme || !(*ctx.repo->readme))
|
*filename = NULL;
|
||||||
|
*ref = NULL;
|
||||||
|
|
||||||
|
if (!readme || !(*readme))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ref = NULL;
|
|
||||||
|
|
||||||
/* Check if the readme is tracked in the git repo. */
|
/* Check if the readme is tracked in the git repo. */
|
||||||
colon = strchr(ctx.repo->readme, ':');
|
colon = strchr(readme, ':');
|
||||||
if (colon && strlen(colon) > 1) {
|
if (colon && strlen(colon) > 1) {
|
||||||
*colon = '\0';
|
|
||||||
/* If it starts with a colon, we want to use
|
/* If it starts with a colon, we want to use
|
||||||
* the default branch */
|
* the default branch */
|
||||||
if (colon == ctx.repo->readme && ctx.repo->defbranch)
|
if (colon == readme && repo->defbranch)
|
||||||
ref = ctx.repo->defbranch;
|
*ref = xstrdup(repo->defbranch);
|
||||||
else
|
else
|
||||||
ref = ctx.repo->readme;
|
*ref = xstrndup(readme, colon - readme);
|
||||||
ctx.repo->readme = colon + 1;
|
readme = colon + 1;
|
||||||
if (!(*ctx.repo->readme))
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepend repo path to relative readme path unless tracked. */
|
/* Prepend repo path to relative readme path unless tracked. */
|
||||||
if (!ref && *ctx.repo->readme != '/')
|
if (!(*ref) && *readme != '/')
|
||||||
ctx.repo->readme = fmtalloc("%s/%s", ctx.repo->path,
|
readme = fmtalloc("%s/%s", repo->path, readme);
|
||||||
ctx.repo->readme);
|
|
||||||
|
|
||||||
/* If a subpath is specified for the about page, make it relative
|
/* If a subpath is specified for the about page, make it relative
|
||||||
* to the directory containing the configured readme.
|
* to the directory containing the configured readme. */
|
||||||
*/
|
|
||||||
if (path) {
|
if (path) {
|
||||||
slash = strrchr(ctx.repo->readme, '/');
|
slash = strrchr(readme, '/');
|
||||||
if (!slash) {
|
if (!slash) {
|
||||||
if (!colon)
|
if (!colon)
|
||||||
return;
|
return;
|
||||||
slash = colon;
|
slash = colon;
|
||||||
}
|
}
|
||||||
free_filename = 1;
|
*filename = xmalloc(slash - readme + 1 + strlen(path) + 1);
|
||||||
tmp = xmalloc(slash - ctx.repo->readme + 1 + strlen(path) + 1);
|
strncpy(*filename, readme, slash - readme + 1);
|
||||||
strncpy(tmp, ctx.repo->readme, slash - ctx.repo->readme + 1);
|
strcpy(*filename + (slash - readme + 1), path);
|
||||||
strcpy(tmp + (slash - ctx.repo->readme + 1), path);
|
|
||||||
} else
|
} else
|
||||||
tmp = ctx.repo->readme;
|
*filename = xstrdup(readme);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cgit_print_repo_readme(char *path)
|
||||||
|
{
|
||||||
|
char *filename, *ref;
|
||||||
|
cgit_parse_readme(ctx.repo->readme, path, &filename, &ref, ctx.repo);
|
||||||
|
|
||||||
/* Print the calculated readme, either from the git repo or from the
|
/* Print the calculated readme, either from the git repo or from the
|
||||||
* filesystem, while applying the about-filter.
|
* filesystem, while applying the about-filter.
|
||||||
*/
|
*/
|
||||||
html("<div id='summary'>");
|
html("<div id='summary'>");
|
||||||
if (ctx.repo->about_filter) {
|
if (ctx.repo->about_filter) {
|
||||||
ctx.repo->about_filter->argv[1] = tmp;
|
ctx.repo->about_filter->argv[1] = filename;
|
||||||
cgit_open_filter(ctx.repo->about_filter);
|
cgit_open_filter(ctx.repo->about_filter);
|
||||||
}
|
}
|
||||||
if (ref)
|
if (ref)
|
||||||
cgit_print_file(tmp, ref);
|
cgit_print_file(filename, ref);
|
||||||
else
|
else
|
||||||
html_include(tmp);
|
html_include(filename);
|
||||||
if (ctx.repo->about_filter) {
|
if (ctx.repo->about_filter) {
|
||||||
cgit_close_filter(ctx.repo->about_filter);
|
cgit_close_filter(ctx.repo->about_filter);
|
||||||
ctx.repo->about_filter->argv[1] = NULL;
|
ctx.repo->about_filter->argv[1] = NULL;
|
||||||
}
|
}
|
||||||
html("</div>");
|
html("</div>");
|
||||||
if (free_filename)
|
free(filename);
|
||||||
free(tmp);
|
free(ref);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef UI_SUMMARY_H
|
#ifndef UI_SUMMARY_H
|
||||||
#define UI_SUMMARY_H
|
#define UI_SUMMARY_H
|
||||||
|
|
||||||
|
extern void cgit_parse_readme(const char *readme, const char *path, char **filename, char **ref, struct cgit_repo *repo);
|
||||||
extern void cgit_print_summary();
|
extern void cgit_print_summary();
|
||||||
extern void cgit_print_repo_readme(char *path);
|
extern void cgit_print_repo_readme(char *path);
|
||||||
|
|
||||||
|
Chargement…
Référencer dans un nouveau ticket
Block a user