ui-repolist: Allow sections to be collapsible

The index page can be difficult to navigate for really large git
servers. This change allows a configuration like:

 section-collapse=people
 section-collapse=tests

And an index page would only display the "people" and "tests" section
headers entries (not their repos) with a hyperlink that can be used to
drill down into each section.

Additionally the boolean logic around displaying sections in
ui-repolist.c was simplified to eliminate an impossible condition.

Signed-off-by: Andy Doan <andy.doan@linaro.org>
Reviewed-by: John Keeping <john@keeping.me.uk>
Signed-off-by: John Keeping <john@keeping.me.uk>
This commit is contained in:
Andy Doan 2016-09-12 22:54:08 -05:00 committed by John Keeping
parent 84b158abe0
commit 1a66e7f3c1
6 changed files with 63 additions and 24 deletions

27
cgit.c
View File

@ -77,7 +77,7 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va
item = string_list_append(&repo->submodules, xstrdup(name + 12));
item->util = xstrdup(value);
} else if (!strcmp(name, "section"))
repo->section = xstrdup(value);
repo->section = get_or_create_section(value);
else if (!strcmp(name, "readme") && value != NULL) {
if (repo->readme.items == ctx.cfg.readme.items)
memset(&repo->readme, 0, sizeof(repo->readme));
@ -107,7 +107,7 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va
static void config_cb(const char *name, const char *value)
{
if (!strcmp(name, "section") || !strcmp(name, "repo.group"))
ctx.cfg.section = xstrdup(value);
ctx.cfg.section = get_or_create_section(value);
else if (!strcmp(name, "repo.url"))
ctx.repo = cgit_add_repo(value);
else if (ctx.repo && !strcmp(name, "repo.path"))
@ -242,6 +242,8 @@ static void config_cb(const char *name, const char *value)
ctx.cfg.section_from_path = atoi(value);
else if (!strcmp(name, "repository-sort"))
ctx.cfg.repository_sort = xstrdup(value);
else if (!strcmp(name, "section-collapse"))
get_or_create_section(value)->collapse = 1;
else if (!strcmp(name, "section-sort"))
ctx.cfg.section_sort = atoi(value);
else if (!strcmp(name, "source-filter"))
@ -385,7 +387,7 @@ static void prepare_context(void)
ctx.cfg.root_desc = "a fast webinterface for the git dscm";
ctx.cfg.scan_hidden_path = 0;
ctx.cfg.script_name = CGIT_SCRIPT_NAME;
ctx.cfg.section = "";
ctx.cfg.section = NULL;
ctx.cfg.repository_sort = "name";
ctx.cfg.section_sort = 1;
ctx.cfg.summary_branches = 10;
@ -794,7 +796,7 @@ static void print_repo(FILE *f, struct cgit_repo *repo)
if (repo->module_link)
fprintf(f, "repo.module-link=%s\n", repo->module_link);
if (repo->section)
fprintf(f, "repo.section=%s\n", repo->section);
fprintf(f, "repo.section=%s\n", repo->section->name);
if (repo->homepage)
fprintf(f, "repo.homepage=%s\n", repo->homepage);
if (repo->clone_url)
@ -1026,6 +1028,23 @@ static int calc_ttl(void)
return ctx.cfg.cache_repo_ttl;
}
struct cgit_section* get_or_create_section(const char *section)
{
struct cgit_section *ptr = ctx.sections;
while(ptr) {
if (!strcmp(section, ptr->name))
return ptr;
ptr = ptr->next;
}
/* Not found insert into head of list */
ptr = xmalloc(sizeof(*ptr));
ptr->name = xstrdup(section);
ptr->collapse = 0;
ptr->next = ctx.sections;
ctx.sections = ptr;
return ptr;
}
int cmd_main(int argc, const char **argv)
{
const char *path;

13
cgit.h
View File

@ -75,6 +75,12 @@ struct cgit_exec_filter {
int pid;
};
struct cgit_section {
unsigned int collapse : 1;
char *name;
struct cgit_section *next;
};
struct cgit_repo {
char *url;
char *name;
@ -85,7 +91,7 @@ struct cgit_repo {
char *defbranch;
char *module_link;
struct string_list readme;
char *section;
struct cgit_section *section;
char *clone_url;
char *logo;
char *logo_link;
@ -208,7 +214,7 @@ struct cgit_config {
char *root_desc;
char *root_readme;
char *script_name;
char *section;
struct cgit_section *section;
char *repository_sort;
char *virtual_root; /* Always ends with '/'. */
char *strict_export;
@ -305,6 +311,7 @@ struct cgit_context {
struct cgit_config cfg;
struct cgit_repo *repo;
struct cgit_page page;
struct cgit_section *sections;
};
typedef int (*write_archive_fn_t)(const char *, const char *);
@ -322,6 +329,8 @@ extern struct cgit_repolist cgit_repolist;
extern struct cgit_context ctx;
extern const struct cgit_snapshot_format cgit_snapshot_formats[];
extern struct cgit_section* get_or_create_section(const char *section);
extern char *cgit_default_repo_desc;
extern struct cgit_repo *cgit_add_repo(const char *url);
extern struct cgit_repo *cgit_get_repoinfo(const char *url);

View File

@ -404,6 +404,11 @@ section::
after this option will inherit the current section name. Default value:
none.
section-collapse::
Name of a section to "collapse" and not display on the index page.
Multiple config entries can be specified and each one will be
collapsed.
section-sort::
Flag which, when set to "1", will sort the sections on the repository
listing by name. Set this flag to "0" if the order in the cgitrc file should

View File

@ -164,10 +164,10 @@ static void add_repo(const char *base, struct strbuf *path, repo_config_fn fn)
}
if (slash && !n) {
*slash = '\0';
repo->section = xstrdup(rel.buf);
repo->section = get_or_create_section(rel.buf);
*slash = '/';
if (starts_with(repo->name, repo->section)) {
repo->name += strlen(repo->section);
if (starts_with(repo->name, repo->section->name)) {
repo->name += strlen(repo->section->name);
if (*repo->name == '/')
repo->name++;
}

View File

@ -443,13 +443,16 @@ typedef struct {
void cgit_prepare_repo_env(struct cgit_repo * repo)
{
char *section = NULL;
if (repo->section)
section = repo->section->name;
cgit_env_var env_vars[] = {
{ .name = "CGIT_REPO_URL", .value = repo->url },
{ .name = "CGIT_REPO_NAME", .value = repo->name },
{ .name = "CGIT_REPO_PATH", .value = repo->path },
{ .name = "CGIT_REPO_OWNER", .value = repo->owner },
{ .name = "CGIT_REPO_DEFBRANCH", .value = repo->defbranch },
{ .name = "CGIT_REPO_SECTION", .value = repo->section },
{ .name = "CGIT_REPO_SECTION", .value = section },
{ .name = "CGIT_REPO_CLONE_URL", .value = repo->clone_url }
};
int env_var_count = ARRAY_SIZE(env_vars);

View File

@ -188,10 +188,16 @@ static int sort_section(const void *a, const void *b)
{
const struct cgit_repo *r1 = a;
const struct cgit_repo *r2 = b;
const char *s1 = "";
const char *s2 = "";
int result;
time_t t;
result = cmp(r1->section, r2->section);
if (r1->section)
s1 = r1->section->name;
if (r2->section)
s2 = r2->section->name;
result = cmp(s1, s2);
if (!result) {
if (!strcmp(ctx.cfg.repository_sort, "age")) {
// get_repo_modtime caches the value in r->mtime, so we don't
@ -273,8 +279,8 @@ static int sort_repolist(char *field)
void cgit_print_repolist(void)
{
int i, columns = 3, hits = 0, header = 0;
char *last_section = NULL;
char *section;
struct cgit_section *last_section = NULL;
struct cgit_section *section;
int sorted = 0;
if (!any_repos_visible()) {
@ -294,12 +300,10 @@ void cgit_print_repolist(void)
if (ctx.cfg.index_header)
html_include(ctx.cfg.index_header);
if (ctx.qry.sort)
sorted = sort_repolist(ctx.qry.sort);
else if (ctx.cfg.section_sort)
sort_repolist("section");
html("<table summary='repository list' class='list nowrap'>");
for (i = 0; i < cgit_repolist.count; i++) {
ctx.repo = &cgit_repolist.repos[i];
@ -313,23 +317,22 @@ void cgit_print_repolist(void)
if (!header++)
print_header();
section = ctx.repo->section;
if (section && !strcmp(section, ""))
if (section && !strcmp(section->name, ""))
section = NULL;
if (!sorted &&
((last_section == NULL && section != NULL) ||
(last_section != NULL && section == NULL) ||
(last_section != NULL && section != NULL &&
strcmp(section, last_section)))) {
if (!sorted && section && last_section != section ) {
htmlf("<tr class='nohover'><td colspan='%d' class='reposection'>",
columns);
html("<a href='");
html_attr(section);
html_attr(section->name);
html("'>");
html_txt(section);
html_txt(section->name);
html("</a>");
html("</td></tr>");
last_section = section;
}
last_section = section;
if (section && section->collapse && !strstr(ctx.qry.url, section->name))
continue;
htmlf("<tr><td class='%s'>",
!sorted && section ? "sublevel-repo" : "toplevel-repo");
cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL);