From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, MAILING_LIST_MULTI autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 15147 invoked from network); 15 Jun 2021 16:07:23 -0000 Received: from lists.zx2c4.com (165.227.139.114) by inbox.vuxu.org with ESMTPUTF8; 15 Jun 2021 16:07:23 -0000 Received: by lists.zx2c4.com (ZX2C4 Mail Server) with ESMTP id 834734ff; Tue, 15 Jun 2021 16:07:11 +0000 (UTC) Return-Path: Received: from cameronkatri.com (cameronkatri.com [206.189.178.249]) by lists.zx2c4.com (ZX2C4 Mail Server) with ESMTPS id f449c1da (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO) for ; Tue, 15 Jun 2021 16:07:09 +0000 (UTC) Received: from FreeBSDY540.hsd1.fl.comcast.net (c-73-84-80-103.hsd1.fl.comcast.net [73.84.80.103]) by cameronkatri.com (Postfix) with ESMTPSA id 0A93D40EF6; Tue, 15 Jun 2021 11:57:26 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cameronkatri.com; s=20201109; t=1623772647; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:references; bh=UxrvM7TzCB+gQ6TRpLzIKBml56jZCLABzaL4F/oxVv8=; b=n3wvlch8hGnArFMeBQ4koF1Deob4MFY/+JE15XhYfIkLMSXGxD+mFD/ElVtOOwzGO57BhK n+MU54GNXET9EVlZ4qK4X3h4cN+uAW+x38mKiJ5PV6CjnCHOewcMn+f6AfblLuJ9XzOkDV vw6dzkneZvX/cAzJK1syEJvP/zK/Cq4= From: Cameron Katri To: cgit@lists.zx2c4.com Cc: Cameron Katri Subject: [PATCH] Add a license tab Date: Tue, 15 Jun 2021 11:57:24 -0400 Message-Id: <20210615155724.97097-1-me@cameronkatri.com> X-Mailer: git-send-email 2.31.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: cgit@lists.zx2c4.com X-Mailman-Version: 2.1.30rc1 Precedence: list List-Id: List for cgit developers and users List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: cgit-bounces@lists.zx2c4.com Sender: "CGit" This tab is nearly identical to the about tab, use the license field in cgitrc to set a list of files to check for or use repo.license or cgit.license as a git-config key. --- This is useful in large repos where you gotta scroll and scroll to find the license text, you can just click the license tab and get it right there. cgit.c | 59 ++++++++++++++++++++++++++++++++++------------------ cgit.h | 3 +++ cgitrc.5.txt | 24 ++++++++++++++++++++- cmd.c | 27 +++++++++++++++++++++++- shared.c | 1 + ui-shared.c | 4 ++++ ui-summary.c | 17 +++++++-------- ui-summary.h | 4 +++- 8 files changed, 107 insertions(+), 32 deletions(-) diff --git a/cgit.c b/cgit.c index 08d81a1..c88dd5b 100644 --- a/cgit.c +++ b/cgit.c @@ -99,6 +99,10 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va if (repo->readme.items == ctx.cfg.readme.items) memset(&repo->readme, 0, sizeof(repo->readme)); string_list_append(&repo->readme, xstrdup(value)); + } else if (!strcmp(name, "license") && value != NULL) { + if (repo->license.items == ctx.cfg.license.items) + memset(&repo->license, 0, sizeof(repo->license)); + string_list_append(&repo->license, xstrdup(value)); } else if (!strcmp(name, "logo") && value != NULL) repo->logo = xstrdup(value); else if (!strcmp(name, "logo-link") && value != NULL) @@ -135,6 +139,8 @@ static void config_cb(const char *name, const char *value) repo_config(ctx.repo, arg, value); else if (!strcmp(name, "readme")) string_list_append(&ctx.cfg.readme, xstrdup(value)); + else if (!strcmp(name, "license")) + string_list_append(&ctx.cfg.license, xstrdup(value)); else if (!strcmp(name, "root-title")) ctx.cfg.root_title = xstrdup(value); else if (!strcmp(name, "root-desc")) @@ -213,6 +219,8 @@ static void config_cb(const char *name, const char *value) ctx.cfg.cache_dynamic_ttl = atoi(value); else if (!strcmp(name, "cache-about-ttl")) ctx.cfg.cache_about_ttl = atoi(value); + else if (!strcmp(name, "cache-license-ttl")) + ctx.cfg.cache_license_ttl = atoi(value); else if (!strcmp(name, "cache-snapshot-ttl")) ctx.cfg.cache_snapshot_ttl = atoi(value); else if (!strcmp(name, "case-sensitive-sort")) @@ -367,6 +375,7 @@ static void prepare_context(void) ctx.cfg.cache_max_create_time = 5; ctx.cfg.cache_root = CGIT_CACHE_ROOT; ctx.cfg.cache_about_ttl = 15; + ctx.cfg.cache_license_ttl = 15; ctx.cfg.cache_snapshot_ttl = 5; ctx.cfg.cache_repo_ttl = 5; ctx.cfg.cache_root_ttl = 5; @@ -494,46 +503,46 @@ static char *guess_defbranch(void) } /* The caller must free filename and ref after calling this. */ -static inline void parse_readme(const char *readme, char **filename, char **ref, struct cgit_repo *repo) +static inline void parse_info_file(const char *file, char **filename, char **ref, struct cgit_repo *repo) { const char *colon; *filename = NULL; *ref = NULL; - if (!readme || !readme[0]) + if (!file || !file[0]) return; - /* Check if the readme is tracked in the git repo. */ - colon = strchr(readme, ':'); + /* Check if the file is tracked in the git repo. */ + colon = strchr(file, ':'); if (colon && strlen(colon) > 1) { /* If it starts with a colon, we want to use * the default branch */ - if (colon == readme && repo->defbranch) + if (colon == file && repo->defbranch) *ref = xstrdup(repo->defbranch); else - *ref = xstrndup(readme, colon - readme); - readme = colon + 1; + *ref = xstrndup(file, colon - file); + file = colon + 1; } - /* Prepend repo path to relative readme path unless tracked. */ - if (!(*ref) && readme[0] != '/') - *filename = fmtalloc("%s/%s", repo->path, readme); + /* Prepend repo path to relative file path unless tracked. */ + if (!(*ref) && file[0] != '/') + *filename = fmtalloc("%s/%s", repo->path, file); else - *filename = xstrdup(readme); + *filename = xstrdup(file); } -static void choose_readme(struct cgit_repo *repo) +static void choose_string_list_item(struct cgit_repo *repo, struct string_list *file) { int found; char *filename, *ref; struct string_list_item *entry; - if (!repo->readme.nr) + if (!file->nr) return; found = 0; - for_each_string_list_item(entry, &repo->readme) { - parse_readme(entry->string, &filename, &ref, repo); + for_each_string_list_item(entry, file) { + parse_info_file(entry->string, &filename, &ref, repo); if (!filename) { free(filename); free(ref); @@ -552,11 +561,11 @@ static void choose_readme(struct cgit_repo *repo) free(filename); free(ref); } - repo->readme.strdup_strings = 1; - string_list_clear(&repo->readme, 0); - repo->readme.strdup_strings = 0; + file->strdup_strings = 1; + string_list_clear(file, 0); + file->strdup_strings = 0; if (found) - string_list_append(&repo->readme, filename)->util = ref; + string_list_append(file, filename)->util = ref; } static void print_no_repo_clone_urls(const char *url) @@ -636,7 +645,8 @@ static int prepare_repo_cmd(int nongit) } string_list_sort(&ctx.repo->submodules); cgit_prepare_repo_env(ctx.repo); - choose_readme(ctx.repo); + choose_string_list_item(ctx.repo, &ctx.repo->readme); + choose_string_list_item(ctx.repo, &ctx.repo->license); return 0; } @@ -804,6 +814,12 @@ static void print_repo(FILE *f, struct cgit_repo *repo) else fprintf(f, "repo.readme=%s\n", item->string); } + for_each_string_list_item(item, &repo->license) { + if (item->util) + fprintf(f, "repo.license=%s:%s\n", (char *)item->util, item->string); + else + fprintf(f, "repo.license=%s\n", item->string); + } if (repo->defbranch) fprintf(f, "repo.defbranch=%s\n", repo->defbranch); if (repo->extra_head_content) @@ -1034,6 +1050,9 @@ static int calc_ttl(void) if (!strcmp(ctx.qry.page, "about")) return ctx.cfg.cache_about_ttl; + if (!strcmp(ctx.qry.page, "license")) + return ctx.cfg.cache_license_ttl; + if (!strcmp(ctx.qry.page, "snapshot")) return ctx.cfg.cache_snapshot_ttl; diff --git a/cgit.h b/cgit.h index 69b5c13..f0ad595 100644 --- a/cgit.h +++ b/cgit.h @@ -88,6 +88,7 @@ struct cgit_repo { char *defbranch; char *module_link; struct string_list readme; + struct string_list license; char *section; char *clone_url; char *logo; @@ -206,6 +207,7 @@ struct cgit_config { char *module_link; char *project_list; struct string_list readme; + struct string_list license; char *robots; char *root_title; char *root_desc; @@ -223,6 +225,7 @@ struct cgit_config { int cache_scanrc_ttl; int cache_static_ttl; int cache_about_ttl; + int cache_license_ttl; int cache_snapshot_ttl; int case_sensitive_sort; int embedded; diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 33a6a8c..5a0e422 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -331,6 +331,12 @@ readme:: in this list. This is useful in conjunction with scan-path. Default value: none. See also: scan-path, repo.readme. +license:: + Text which will be used as default value for "repo.license". Multiple + config keys may be specified, and cgit will use the first found file + in this list. This is useful in conjunction with scan-path. Default + value: none. See also: scan-path, repo.license. + remove-suffix:: If set to "1" and scan-path is enabled, if any repositories are found with a suffix of ".git", this suffix will be removed for the url and @@ -585,6 +591,17 @@ repo.readme:: are no non-public files located in the same directory as the readme file. Default value: . +repo.license:: + A path (relative to ) which specifies a file to include + verbatim as the "license" page for this repo. You may also specify a + git refspec by head or by hash by prepending the refspec followed by + a colon. For example, "master:LICENSE". If the value begins + with a colon, i.e. ":COPYING", the default branch of the + repository will be used. Sharing any file will expose that entire + directory tree to the "/license/PATH" endpoints, so be sure that there + are no non-public files located in the same directory as the license + file. Default value: . + repo.section:: Override the current section name for this repository. Default value: none. @@ -669,7 +686,7 @@ Parameters are provided to filters as follows. about filter:: This filter is given a single parameter: the filename of the source file to filter. The filter can use the filename to determine (for - example) the type of syntax to follow when formatting the readme file. + example) the type of syntax to follow when formatting the readme/license file. The about text that is to be filtered is available on standard input and the filtered text is expected on standard output. @@ -930,6 +947,10 @@ readme=:install.txt readme=:INSTALL readme=:install +license=:LICENSE.md +license=:LICENSE +license=:COPYING.md +license=:COPYING ## ## List of repositories. @@ -946,6 +967,7 @@ repo.path=/pub/git/foo.git repo.desc=the master foo repository repo.owner=fooman@example.com repo.readme=info/web/about.html +repo.license=GPLv3.html repo.url=bar diff --git a/cmd.c b/cmd.c index 0eb75b1..fb1ccc0 100644 --- a/cmd.c +++ b/cmd.c @@ -50,7 +50,7 @@ static void about_fn(void) free(currenturl); free(redirect); } else if (ctx.repo->readme.nr) - cgit_print_repo_readme(ctx.qry.path); + cgit_print_repo_info_file(ctx.repo->readme, ctx.qry.path); else if (ctx.repo->homepage) cgit_redirect(ctx.repo->homepage, false); else { @@ -97,6 +97,30 @@ static void info_fn(void) cgit_clone_info(); } +static void license_fn(void) +{ + if (ctx.repo) { + size_t path_info_len = ctx.env.path_info ? strlen(ctx.env.path_info) : 0; + if (!ctx.qry.path && + ctx.qry.url[strlen(ctx.qry.url) - 1] != '/' && + (!path_info_len || ctx.env.path_info[path_info_len - 1] != '/')) { + char *currenturl = cgit_currenturl(); + char *redirect = fmtalloc("%s/", currenturl); + cgit_redirect(redirect, true); + free(currenturl); + free(redirect); + } else if (ctx.repo->license.nr) + cgit_print_repo_info_file(ctx.repo->license, ctx.qry.path); + else { + char *currenturl = cgit_currenturl(); + char *redirect = fmtalloc("%s../", currenturl); + cgit_redirect(redirect, false); + free(currenturl); + free(redirect); + } + } +} + static void log_fn(void) { cgit_print_log(ctx.qry.oid, ctx.qry.ofs, ctx.cfg.max_commit_count, @@ -178,6 +202,7 @@ struct cgit_cmd *cgit_get_cmd(void) def_cmd(commit, 1, 1, 0), def_cmd(diff, 1, 1, 0), def_cmd(info, 1, 0, 1), + def_cmd(license, 1, 1, 0), def_cmd(log, 1, 1, 0), def_cmd(ls_cache, 0, 0, 0), def_cmd(objects, 1, 0, 1), diff --git a/shared.c b/shared.c index 8115469..c7b98cc 100644 --- a/shared.c +++ b/shared.c @@ -70,6 +70,7 @@ struct cgit_repo *cgit_add_repo(const char *url) ret->commit_sort = ctx.cfg.commit_sort; ret->module_link = ctx.cfg.module_link; ret->readme = ctx.cfg.readme; + ret->license = ctx.cfg.license; ret->mtime = -1; ret->about_filter = ctx.cfg.about_filter; ret->commit_filter = ctx.cfg.commit_filter; diff --git a/ui-shared.c b/ui-shared.c index acd8ab5..207bf69 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -1056,6 +1056,10 @@ void cgit_print_pageheader(void) if (ctx.repo->max_stats) cgit_stats_link("stats", NULL, hc("stats"), ctx.qry.head, ctx.qry.vpath); + if (ctx.repo->license.nr) + reporevlink("license", "license", NULL, + hc("license"), ctx.qry.head, NULL, + NULL); if (ctx.repo->homepage) { html(""); diff --git a/ui-summary.h b/ui-summary.h index cba696a..9592802 100644 --- a/ui-summary.h +++ b/ui-summary.h @@ -1,7 +1,9 @@ #ifndef UI_SUMMARY_H #define UI_SUMMARY_H +#include + extern void cgit_print_summary(void); -extern void cgit_print_repo_readme(const char *path); +extern void cgit_print_repo_info_file(struct string_list file, const char *path); #endif /* UI_SUMMARY_H */ -- 2.31.1