/* ui-summary.c: functions for generating repo summary page * * Copyright (C) 2006-2014 cgit Development Team * * Licensed under GNU General Public License v2 * (see COPYING for full license text) */ #include "cgit.h" #include "html.h" #include "ui-blob.h" #include "ui-log.h" #include "ui-plain.h" #include "ui-refs.h" #include "ui-shared.h" #include "ui-summary.h" static int urls; static void print_url(const char *url) { int columns = 3; if (ctx.repo->enable_log_filecount) columns++; if (ctx.repo->enable_log_linecount) columns++; if (urls++ == 0) { htmlf(" ", columns); htmlf("Clone\n", columns); } htmlf(""); html_txt(url); html("\n"); } void cgit_print_summary(void) { int columns = 3; if (ctx.repo->enable_log_filecount) columns++; if (ctx.repo->enable_log_linecount) columns++; cgit_print_layout_start(); html(""); cgit_print_branches(ctx.cfg.summary_branches); htmlf("", columns); cgit_print_tags(ctx.cfg.summary_tags); if (ctx.cfg.summary_log > 0) { htmlf("", columns); cgit_print_log(ctx.qry.head, 0, ctx.cfg.summary_log, NULL, NULL, NULL, 0, 0, 0); } urls = 0; cgit_add_clone_urls(print_url); html("
 
 
"); cgit_print_layout_end(); } /* The caller must free the return value. */ static char *append_readme_path(const char *filename, const char *ref, const char *path) { char *file, *base_dir, *full_path, *resolved_base = NULL, *resolved_full = NULL; /* If a subpath is specified for the about page, make it relative * to the directory containing the configured readme. */ file = xstrdup(filename); base_dir = dirname(file); if (!strcmp(base_dir, ".") || !strcmp(base_dir, "..")) { if (!ref) { free(file); return NULL; } full_path = xstrdup(path); } else full_path = fmtalloc("%s/%s", base_dir, path); if (!ref) { resolved_base = realpath(base_dir, NULL); resolved_full = realpath(full_path, NULL); if (!resolved_base || !resolved_full || !starts_with(resolved_full, resolved_base)) { free(full_path); full_path = NULL; } } free(file); free(resolved_base); free(resolved_full); return full_path; } struct get_readme_oid_ctx { struct object_id *oid; char **filename; const char *path; bool found; }; static int get_readme_oid_cb(const struct object_id *oid, struct strbuf *base, const char *pathname, unsigned mode, int stage, void *cbdata) { struct get_readme_oid_ctx *ctx = (struct get_readme_oid_ctx *)cbdata; // TODO: make readme.md configurable, ctx.readme (stringlist) const int readme_names_count = 2; const char **readme_names = (const char *[]){"readme.md", "readme"}; struct strbuf buffer = STRBUF_INIT; if (base->len > 0) strbuf_addbuf(&buffer, base); strbuf_addstr(&buffer, pathname); size_t path_len = (ctx->path == NULL) ? 0 : strlen(ctx->path); size_t cmp_count = (buffer.len > 0 && buffer.buf[buffer.len - 1] == '/') ? buffer.len - 1 : buffer.len; if (path_len < cmp_count) cmp_count = path_len; bool match_base = strncmp(buffer.buf, ctx->path, cmp_count) == 0; bool match_path = match_base && buffer.len == path_len; strbuf_release(&buffer); bool match_pathname = match_base && match_path && (oid_object_info(the_repository, oid, NULL) == OBJ_BLOB); // htmlf("[%s %s %s %b %b]", base->buf, pathname, ctx->path, match_base, match_path); for (int i = 0; i < readme_names_count; i++) { if (match_pathname || (match_base && strcasecmp(pathname, readme_names[i]) == 0)) { if (ctx->oid) *(ctx->oid) = *oid; if (ctx->filename) *(ctx->filename) = xstrdup(pathname); ctx->found = true; break; } } if (match_base && cmp_count > 0) return READ_TREE_RECURSIVE; else return 0; } bool get_readme_oid(struct tree *tree, struct pathspec *paths, struct object_id *oid, char **filename) { struct get_readme_oid_ctx gro_ctx = (struct get_readme_oid_ctx){ .oid = oid, .filename = filename, .path = (paths->nr == 1 ? paths->items[0].match : NULL), .found = false}; read_tree_recursive(the_repository, tree, "", 0, 0, paths, get_readme_oid_cb, &gro_ctx); return gro_ctx.found; } bool cgit_has_readme(void) { struct object_id oid; if (get_oid(ctx.qry.head, &oid)) { return false; } struct commit *commit = lookup_commit_reference(the_repository, &oid); struct object_id *commit_tree_oid = get_commit_tree_oid(commit); struct tree *tree = parse_tree_indirect(commit_tree_oid); struct pathspec paths = { .nr = 0, }; return get_readme_oid(tree, &paths, NULL, NULL); } void cgit_print_repo_readme_no_layout(struct tree *tree, struct pathspec *paths) { char *filename = NULL; struct object_id readme_oid; if (get_readme_oid(tree, paths, &readme_oid, &filename)) { html("
"); cgit_open_filter(ctx.repo->about_filter, filename); cgit_print_oid(&readme_oid); cgit_close_filter(ctx.repo->about_filter); html("
"); free(filename); } } void cgit_print_repo_readme(const char *path, struct object_id *oid) { struct commit *commit = lookup_commit_reference(the_repository, oid); struct object_id *commit_tree_oid = get_commit_tree_oid(commit); struct tree *tree = parse_tree_indirect(commit_tree_oid); struct pathspec_item path_items = {.match = path, .len = path ? strlen(path) : 0}; struct pathspec paths = {.nr = path ? 1 : 0, .items = &path_items}; cgit_print_layout_start(); cgit_print_repo_readme_no_layout(tree, &paths); } // void cgit_print_repo_readme_no_layout(const struct tree *tree, struct pathspec *paths) // { // if (ctx.repo->readme.nr) { // const char *filename = ctx.repo->readme.items[0].string; // // html("
"); // // cgit_open_filter(ctx.repo->about_filter, filename); // // char *ref = ctx.repo->readme.items[0].util; // cgit_print_file(filename, ref, 1); // // cgit_close_filter(ctx.repo->about_filter); // // html("
"); // } // }