[PATCH] Add a license tab
Cameron Katri
me at cameronkatri.com
Tue Jun 15 15:57:24 UTC 2021
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: <readme>.
+repo.license::
+ A path (relative to <repo.path>) 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: <license>.
+
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 at 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("<a href='");
html_attr(ctx.repo->homepage);
diff --git a/ui-summary.c b/ui-summary.c
index 947812a..dc4d0a6 100644
--- a/ui-summary.c
+++ b/ui-summary.c
@@ -66,11 +66,11 @@ void cgit_print_summary(void)
}
/* The caller must free the return value. */
-static char* append_readme_path(const char *filename, const char *ref, const char *path)
+static char* append_file_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. */
+ * to the directory containing the configured file. */
file = xstrdup(filename);
base_dir = dirname(file);
@@ -98,8 +98,7 @@ static char* append_readme_path(const char *filename, const char *ref, const cha
return full_path;
}
-
-void cgit_print_repo_readme(const char *path)
+void cgit_print_repo_info_file(struct string_list file, const char *path)
{
char *filename, *ref, *mimetype;
int free_filename = 0;
@@ -115,20 +114,20 @@ void cgit_print_repo_readme(const char *path)
free(mimetype);
cgit_print_layout_start();
- if (ctx.repo->readme.nr == 0)
+ if (file.nr == 0)
goto done;
- filename = ctx.repo->readme.items[0].string;
- ref = ctx.repo->readme.items[0].util;
+ filename = file.items[0].string;
+ ref = file.items[0].util;
if (path) {
free_filename = 1;
- filename = append_readme_path(filename, ref, path);
+ filename = append_file_path(filename, ref, path);
if (!filename)
goto done;
}
- /* Print the calculated readme, either from the git repo or from the
+ /* Print the calculated file, either from the git repo or from the
* filesystem, while applying the about-filter.
*/
html("<div id='summary'>");
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 <string-list.h>
+
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
More information about the CGit
mailing list