Changes
6 changed files (+196/-970)
-
Unnamed-Server/default-pages.patch (deleted)
-
@@ -1,246 +0,0 @@From d9f3d6fb1817fd22512ac62e8d7c36c67dc5584a Mon Sep 17 00:00:00 2001 From: Naïm Favier <fnaim42@gmail.com> Date: Mon, 9 Dec 2019 19:38:14 +0100 Subject: Make default pages configurable Signed-off-by: Christian Hesse <mail@eworm.de> --- cgit.c | 10 ++++++++++ cgit.h | 3 +++ cgitrc.5.txt | 14 ++++++++++++++ cmd.c | 18 +++++++++--------- ui-repolist.c | 2 +- ui-shared.c | 12 +++++++++--- ui-shared.h | 2 ++ 7 files changed, 48 insertions(+), 13 deletions(-) diff --git a/cgit.c b/cgit.c index 57d7097..e7c0172 100644 --- a/cgit.c +++ b/cgit.c @@ -56,6 +56,8 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va repo->homepage = strdup_first_line(value); else if (!strcmp(name, "defbranch")) repo->defbranch = strdup_first_line(value); + else if (!strcmp(name, "default-page")) + repo->default_page = strdup_first_line(value); else if (!strcmp(name, "extra-head-content")) repo->extra_head_content = strdup_first_line(value); else if (!strcmp(name, "snapshots")) @@ -141,6 +143,8 @@ static void config_cb(const char *name, const char *value) ctx.cfg.root_desc = strdup_first_line(value); else if (!strcmp(name, "root-readme")) ctx.cfg.root_readme = strdup_first_line(value); + else if (!strcmp(name, "root-default-page")) + ctx.cfg.root_default_page = strdup_first_line(value); else if (!strcmp(name, "css")) string_list_append(&ctx.cfg.css, strdup_first_line(value)); else if (!strcmp(name, "js")) @@ -157,6 +161,8 @@ static void config_cb(const char *name, const char *value) ctx.cfg.logo = strdup_first_line(value); else if (!strcmp(name, "logo-link")) ctx.cfg.logo_link = strdup_first_line(value); + else if (!strcmp(name, "default-page")) + ctx.cfg.default_page = strdup_first_line(value); else if (!strcmp(name, "module-link")) ctx.cfg.module_link = strdup_first_line(value); else if (!strcmp(name, "strict-export")) @@ -380,6 +386,7 @@ static void prepare_context(void) ctx.cfg.case_sensitive_sort = 1; ctx.cfg.branch_sort = 0; ctx.cfg.commit_sort = 0; + ctx.cfg.default_page= "summary"; ctx.cfg.logo = "/cgit.png"; ctx.cfg.favicon = "/favicon.ico"; ctx.cfg.local_time = 0; @@ -400,6 +407,7 @@ static void prepare_context(void) ctx.cfg.robots = "index, nofollow"; ctx.cfg.root_title = "Git repository browser"; ctx.cfg.root_desc = "a fast webinterface for the git dscm"; + ctx.cfg.root_default_page = "repolist"; ctx.cfg.scan_hidden_path = 0; ctx.cfg.script_name = CGIT_SCRIPT_NAME; ctx.cfg.section = ""; @@ -811,6 +819,8 @@ static void print_repo(FILE *f, struct cgit_repo *repo) } if (repo->defbranch) fprintf(f, "repo.defbranch=%s\n", repo->defbranch); + if (repo->default_page) + fprintf(f, "repo.default-page=%s\n", repo->default_page); if (repo->extra_head_content) fprintf(f, "repo.extra-head-content=%s\n", repo->extra_head_content); if (repo->module_link) diff --git a/cgit.h b/cgit.h index ddd2ccb..9f9daac 100644 --- a/cgit.h +++ b/cgit.h @@ -87,6 +87,7 @@ struct cgit_repo { char *owner; char *homepage; char *defbranch; + char *default_page; char *module_link; struct string_list readme; char *section; @@ -196,6 +197,7 @@ struct cgit_config { char *cache_root; char *clone_prefix; char *clone_url; + char *default_page; char *favicon; char *footer; char *head_include; @@ -211,6 +213,7 @@ struct cgit_config { char *root_title; char *root_desc; char *root_readme; + char *root_default_page; char *script_name; char *section; char *repository_sort; diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 6f3e952..ac86864 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -129,6 +129,12 @@ css:: Default value: "/cgit.css". May be given multiple times, each css URL path is added in the head section of the document in turn. +default-page:: + Specifies the default page for repositories. This setting is only used + if `repo.default-page` is unspecified. Possible values: "about", + "summary", "refs", "log", "tree", "commit", "diff", "stats". Default + value: "summary". + email-filter:: Specifies a command which will be invoked to format names and email address of committers, authors, and taggers, as represented in various @@ -359,6 +365,10 @@ robots:: Text used as content for the "robots" meta-tag. Default value: "index, nofollow". +root-default-page:: + Specifies the default root page. Possible values are "repolist" and + "about". Default value: "repolist". + root-desc:: Text printed below the heading on the repository index page. Default value: "a fast webinterface for the git dscm". @@ -482,6 +492,10 @@ repo.commit-sort:: ordering. If unset, the default ordering of "git log" is used. Default value: unset. +repo.default-page:: + Specifies the default page for the repository. Default value: global + default-page. + repo.defbranch:: The name of the default branch for this repository. If no such branch exists in the repository, the first branch name (when sorted) is used diff --git a/cmd.c b/cmd.c index 0eb75b1..669c345 100644 --- a/cmd.c +++ b/cmd.c @@ -51,13 +51,10 @@ static void about_fn(void) free(redirect); } else if (ctx.repo->readme.nr) cgit_print_repo_readme(ctx.qry.path); - else if (ctx.repo->homepage) - cgit_redirect(ctx.repo->homepage, false); else { - char *currenturl = cgit_currenturl(); - char *redirect = fmtalloc("%s../", currenturl); + char *redirect = fmtalloc("%s%s/summary/", + ctx.cfg.virtual_root, ctx.repo->url); cgit_redirect(redirect, false); - free(currenturl); free(redirect); } } else @@ -195,10 +192,13 @@ struct cgit_cmd *cgit_get_cmd(void) int i; if (ctx.qry.page == NULL) { - if (ctx.repo) - ctx.qry.page = "summary"; - else - ctx.qry.page = "repolist"; + if (ctx.repo) { + if (ctx.repo->default_page && *ctx.repo->default_page) + ctx.qry.page = ctx.repo->default_page; + else + ctx.qry.page = ctx.cfg.default_page; + } else + ctx.qry.page = ctx.cfg.root_default_page; } for (i = 0; i < sizeof(cmds)/sizeof(*cmds); i++) diff --git a/ui-repolist.c b/ui-repolist.c index d12e3dd..2390eae 100644 --- a/ui-repolist.c +++ b/ui-repolist.c @@ -321,7 +321,7 @@ void cgit_print_repolist(void) } htmlf("<tr><td class='%s'>", !sorted && section ? "sublevel-repo" : "toplevel-repo"); - cgit_summary_link(ctx.repo->name, NULL, NULL, NULL); + cgit_repo_link(ctx.repo->name, NULL, NULL, NULL); html("</td><td>"); repourl = cgit_repourl(ctx.repo->url); html_link_open(repourl, NULL, NULL); diff --git a/ui-shared.c b/ui-shared.c index baea6f2..81e1f46 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -328,10 +328,16 @@ static void reporevlink(const char *page, const char *name, const char *title, html("</a>"); } +void cgit_repo_link(const char *name, const char *title, const char *class, + const char *head) +{ + reporevlink(NULL, name, title, class, head, NULL, NULL); +} + void cgit_summary_link(const char *name, const char *title, const char *class, const char *head) { - reporevlink(NULL, name, title, class, head, NULL, NULL); + reporevlink("summary", name, title, class, head, NULL, NULL); } void cgit_tag_link(const char *name, const char *title, const char *class, @@ -1035,7 +1041,7 @@ static void print_header(void) if (ctx.repo) { cgit_index_link("index", NULL, NULL, NULL, NULL, 0, 1); html(" : "); - cgit_summary_link(ctx.repo->name, NULL, NULL, NULL); + cgit_repo_link(ctx.repo->name, NULL, NULL, NULL); if (ctx.env.authenticated) { html("</td><td class='form'>"); html("<form method='get'>\n"); @@ -1130,7 +1136,7 @@ void cgit_print_pageheader(void) html("</form>\n"); } else if (ctx.env.authenticated) { char *currenturl = cgit_currenturl(); - site_link(NULL, "index", NULL, hc("repolist"), NULL, NULL, 0, 1); + site_link("repolist", "index", NULL, hc("repolist"), NULL, NULL, 0, 1); if (ctx.cfg.root_readme) site_link("about", "about", NULL, hc("about"), NULL, NULL, 0, 1); diff --git a/ui-shared.h b/ui-shared.h index 6964873..4d14858 100644 --- a/ui-shared.h +++ b/ui-shared.h @@ -17,6 +17,8 @@ extern void cgit_add_clone_urls(void (*fn)(const char *)); extern void cgit_index_link(const char *name, const char *title, const char *class, const char *pattern, const char *sort, int ofs, int always_root); +extern void cgit_repo_link(const char *name, const char *title, + const char *class, const char *head); extern void cgit_summary_link(const char *name, const char *title, const char *class, const char *head); extern void cgit_tag_link(const char *name, const char *title, -- cgit v1.3-14-g43fede
-
-
-
@@ -133,11 +133,7 @@root * ${pkgs.cgit}/cgit file_server } reverse_proxy unix//run/fcgiwrap-caddy.sock { transport fastcgi { env SCRIPT_FILENAME ${pkgs.cgit}/cgit/cgit.cgi } } reverse_proxy localhost:5555 ''; "*.unnamed.website".extraConfig = '' tls {
-
@@ -147,13 +143,6 @@} } root * /srv/http/{labels.2} handle /cgi-bin/* { reverse_proxy unix//run/fcgiwrap-caddy.sock { transport fastcgi { env SCRIPT_FILENAME {http.vars.root}{path} } } } file_server ''; "{$SECRET_DOMAIN}".extraConfig = ''
-
@@ -165,51 +154,26 @@''; }; }; # services.cgit configures cgit and fcgiwrap for nginx so it's just more straightforward to do it manually services.fcgiwrap.instances.caddy.socket = { user = "caddy"; group = "caddy"; }; environment.etc.cgitrc.text = (lib.generators.toINIWithGlobalSection { } { globalSection = { root-title = "DO NOT L∃∀N"; root-desc = "Department of Provably Bad Code"; clone-prefix = "https://git.unnamed.website"; default-page = "about"; # The owner column is just me repeated so don't show it enable-index-owner = 0; # Idle column uses master branch # https://lists.zx2c4.com/pipermail/cgit/2020-August/004514.html # Can manually set the time using # touch -m --date=@$(git log -1 --format=%ct) $(git show-ref | awk '{print $2}') # https://ch1p.io/cgit-idle-time/ repository-sort = "age"; # The cache reduces load and most importantly, prevents cgit from scanning the repos on disk every time # To clear cache, restart fcgiwrap-caddy.service cache-size = 64; # No spam plz noplainemail = 1; # The default md2html filter uses the super slow python-markdown, so instead use MD4C about-filter = pkgs.writeShellScript "md2html" '' ${pkgs.md4c}/bin/md2html --github | sed 's/<a href="\([^/]*\)">/<a href="tree\/\1">/g' ''; # Syntax highlighting source-filter = "${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py"; readme = ":README.md"; # To make repo unlisted, add hide=1 to its cgitrc section-from-path = 1; # Git server services.legit = { enable = true; settings = { meta = { title = "Typeclass instance problem is stuck"; description = "It is often due to incompetence"; }; repo = { readme = [ "README.md" ]; scanPath = "/srv/git"; }; }) # scan-path MUST be last! # toINIWithGlobalSection sorts the options so we have to manually concatenate scan-path # https://wiki.archlinux.org/title/Cgit#readme_files_are_not_found,_about_tab_not_shown + "scan-path=/srv/git"; server.name = "git.unnamed.website"; }; }; systemd = { # The cgit cache dir must be writable by dynamic user running cgit # Easy solution is to use /var/tmp as the cache dir # I couldn't figure out how to set cache-root for cgit, so instead symlink it tmpfiles.rules = [ "L /var/cache/cgit - - - - /var/tmp" ]; # Fix error when git cloning services.legit.path = [ pkgs.git ]; # Update Git mirrors services.update-mirrors = { wantedBy = [ "multi-user.target" ];
-
-
Unnamed-Server/for-jason.patch (deleted)
-
@@ -1,657 +0,0 @@From a42071e287f3fbf24c1010170f1aaff4781567b6 Mon Sep 17 00:00:00 2001 From: Christian Hesse <mail@eworm.de> Date: Fri, 16 Dec 2022 18:37:10 +0100 Subject: [PATCH 01/10] ui-log: show ellipsis if detailed commit message is available The existence of a detailed commit message may be of interst even if only the subject is shown by default. Signed-off-by: Christian Hesse <mail@eworm.de> --- cgit.css | 9 +++++++++ ui-log.c | 2 ++ 2 files changed, 11 insertions(+) diff --git a/cgit.css b/cgit.css index d10a24d..1d4634c 100644 --- a/cgit.css +++ b/cgit.css @@ -678,6 +678,15 @@ div#cgit div.footer a:hover { text-decoration: underline; } +div#cgit span.msg-avail { + color: #000; + margin: 0px 0.5em; + padding: 0px 0.25em; + background-color: #f0f0f0; + border: solid 1px #777777; + border-radius: 5px; +} + div#cgit a.branch-deco { color: #000; margin: 0px 0.5em; diff --git a/ui-log.c b/ui-log.c index 9906bbc..ee51bde 100644 --- a/ui-log.c +++ b/ui-log.c @@ -244,6 +244,8 @@ static void print_commit(struct commit *commit, struct rev_info *revs) } cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, oid_to_hex(&commit->object.oid), ctx.qry.vpath); + if (!ctx.qry.showmsg && info->msg && *(info->msg)) + html("<span class='msg-avail'>...</span>"); show_commit_decorations(commit); html("</td><td>"); cgit_open_filter(ctx.repo->email_filter, info->author_email, "log"); -- 2.54.0 From c829e631ded662d70fc843b8b83eb7b5d9872cd3 Mon Sep 17 00:00:00 2001 From: Christian Hesse <mail@eworm.de> Date: Mon, 5 Aug 2024 00:25:49 +0200 Subject: [PATCH 02/10] ui-log: show commit message in tooltip ... now that we have the ellipsis to indicate it is available. Signed-off-by: Christian Hesse <mail@eworm.de> --- cgit.css | 18 ++++++++++++++++++ ui-log.c | 7 +++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/cgit.css b/cgit.css index 1d4634c..092883f 100644 --- a/cgit.css +++ b/cgit.css @@ -687,6 +687,24 @@ div#cgit span.msg-avail { border-radius: 5px; } +div#cgit span.msg-avail span.msg-tooltip { + color: #000; + margin: 0px 0.5em; + padding: 0px 0.25em; + background-color: #f0f0f0; + border: solid 1px #777777; + border-radius: 5px; + box-shadow: 2px 2px 7px rgba(100,100,100,0.75); + visibility: hidden; + position: absolute; + white-space: pre; + z-index: 1; +} + +div#cgit span.msg-avail:hover span.msg-tooltip { + visibility: visible; +} + div#cgit a.branch-deco { color: #000; margin: 0px 0.5em; diff --git a/ui-log.c b/ui-log.c index ee51bde..4ec5817 100644 --- a/ui-log.c +++ b/ui-log.c @@ -244,8 +244,11 @@ static void print_commit(struct commit *commit, struct rev_info *revs) } cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, oid_to_hex(&commit->object.oid), ctx.qry.vpath); - if (!ctx.qry.showmsg && info->msg && *(info->msg)) - html("<span class='msg-avail'>...</span>"); + if (!ctx.qry.showmsg && info->msg && *(info->msg)) { + html("<span class='msg-avail'>...<span class='msg-tooltip'>"); + html_txt(info->msg); + html("</span></span>"); + } show_commit_decorations(commit); html("</td><td>"); cgit_open_filter(ctx.repo->email_filter, info->author_email, "log"); -- 2.54.0 From 8c1d1cd5dee361084e28e7561e903eb5fbf5a544 Mon Sep 17 00:00:00 2001 From: Christian Hesse <mail@eworm.de> Date: Wed, 16 Oct 2024 11:59:42 +0200 Subject: [PATCH 03/10] ui-log: build ellipsis from bullets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These look cleaner... IMHO. 😜 Signed-off-by: Christian Hesse <mail@eworm.de> --- ui-log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-log.c b/ui-log.c index 4ec5817..434ff8d 100644 --- a/ui-log.c +++ b/ui-log.c @@ -245,7 +245,7 @@ static void print_commit(struct commit *commit, struct rev_info *revs) cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, oid_to_hex(&commit->object.oid), ctx.qry.vpath); if (!ctx.qry.showmsg && info->msg && *(info->msg)) { - html("<span class='msg-avail'>...<span class='msg-tooltip'>"); + html("<span class='msg-avail'>•••<span class='msg-tooltip'>"); html_txt(info->msg); html("</span></span>"); } -- 2.54.0 From f1861553f3bfd48f4fc1559b23a5cc1b0cc7bda2 Mon Sep 17 00:00:00 2001 From: Christian Hesse <mail@eworm.de> Date: Sat, 29 Dec 2018 00:13:54 +0100 Subject: [PATCH 04/10] ui-tree: provide link to about page for pretty formatting We have an ongoing discussion about display filters and pretty formatting in tree view. How about providing a link to about page for pretty formatting? Signed-off-by: Christian Hesse <mail@eworm.de> --- ui-shared.c | 6 ++++++ ui-shared.h | 3 +++ ui-tree.c | 3 +++ 3 files changed, 12 insertions(+) diff --git a/ui-shared.c b/ui-shared.c index df52a9b..0734711 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -348,6 +348,12 @@ void cgit_tree_link(const char *name, const char *title, const char *class, reporevlink("tree", name, title, class, head, rev, path); } +void cgit_about_link(const char *name, const char *title, const char *class, + const char *head, const char *rev, const char *path) +{ + reporevlink("about", name, title, class, head, rev, path); +} + void cgit_plain_link(const char *name, const char *title, const char *class, const char *head, const char *rev, const char *path) { diff --git a/ui-shared.h b/ui-shared.h index 2a3a7f5..6a2c6e2 100644 --- a/ui-shared.h +++ b/ui-shared.h @@ -24,6 +24,9 @@ extern void cgit_tag_link(const char *name, const char *title, extern void cgit_tree_link(const char *name, const char *title, const char *class, const char *head, const char *rev, const char *path); +extern void cgit_about_link(const char *name, const char *title, + const char *class, const char *head, + const char *rev, const char *path); extern void cgit_plain_link(const char *name, const char *title, const char *class, const char *head, const char *rev, const char *path); diff --git a/ui-tree.c b/ui-tree.c index 5ac8c9a..851074e 100644 --- a/ui-tree.c +++ b/ui-tree.c @@ -112,6 +112,9 @@ static void print_object(const struct object_id *oid, const char *path, const ch cgit_print_layout_start(); htmlf("blob: %s (", oid_to_hex(oid)); + cgit_about_link("about", NULL, NULL, ctx.qry.head, + rev, path); + html(") ("); cgit_plain_link("plain", NULL, NULL, ctx.qry.head, rev, path); if (ctx.repo->enable_blame && !is_binary) { -- 2.54.0 From 4c037918a2aab30e47cacfe1b296a7927137ace4 Mon Sep 17 00:00:00 2001 From: Christian Hesse <mail@eworm.de> Date: Wed, 2 Jan 2019 09:20:40 +0100 Subject: [PATCH 05/10] ui-tree: add about link in tree view list Signed-off-by: Christian Hesse <mail@eworm.de> --- ui-tree.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui-tree.c b/ui-tree.c index 851074e..542c523 100644 --- a/ui-tree.c +++ b/ui-tree.c @@ -272,6 +272,9 @@ static int ls_item(const struct object_id *oid, struct strbuf *base, if (!S_ISGITLINK(mode)) cgit_plain_link("plain", NULL, "button", ctx.qry.head, walk_tree_ctx->curr_rev, fullpath.buf); + if (!S_ISDIR(mode)) + cgit_about_link("about", NULL, "button", ctx.qry.head, + walk_tree_ctx->curr_rev, fullpath.buf); if (!S_ISDIR(mode) && ctx.repo->enable_blame) cgit_blame_link("blame", NULL, "button", ctx.qry.head, walk_tree_ctx->curr_rev, fullpath.buf); -- 2.54.0 From 1854c18658707741c5bf0b5eaca554e083a3729b Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" <Jason@zx2c4.com> Date: Wed, 19 Mar 2014 02:58:41 -0600 Subject: [PATCH 06/10] steal kernel.org's libravatar lua Signed-off-by: Christian Hesse <mail@eworm.de> --- cgit.css | 28 ++++++++++++++++++++++++++++ filters/email-libravatar-hover.lua | 25 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 filters/email-libravatar-hover.lua diff --git a/cgit.css b/cgit.css index 092883f..dab5977 100644 --- a/cgit.css +++ b/cgit.css @@ -934,3 +934,31 @@ div#cgit table.ssdiff td.space { div#cgit table.ssdiff td.space div { min-height: 3em; } +div#cgit span.libravatar img.onhover { + display: none; + border: 1px solid gray; + padding: 0px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + width: 128px; + height: 128px; +} + +div#cgit span.libravatar img.inline { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + width: 13px; + height: 13px; + margin-right: 0.2em; + opacity: 0.6; +} + +div#cgit span.libravatar:hover > img.onhover { + display: block; + position: absolute; + margin-left: 1.5em; + background-color: #eeeeee; + box-shadow: 2px 2px 7px rgba(100,100,100,0.75); +} diff --git a/filters/email-libravatar-hover.lua b/filters/email-libravatar-hover.lua new file mode 100644 index 0000000..c14b618 --- /dev/null +++ b/filters/email-libravatar-hover.lua @@ -0,0 +1,25 @@ +local digest = require("openssl.digest") + +function md5_hex(input) + local b = digest.new("md5"):final(input) + local x = "" + for i = 1, #b do + x = x .. string.format("%.2x", string.byte(b, i)) + end + return x +end + +function filter_open(email, page) + buffer = "" + hexdigest = md5_hex(email:sub(2, -2):lower()) +end + +function filter_close() + baseurl = os.getenv("HTTPS") and "https://seccdn.libravatar.org/" or "http://cdn.libravatar.org/" + html("<span class='libravatar'><img class='inline' src='" .. baseurl .. "avatar/" .. hexdigest .. "?s=13&d=retro' /><img class='onhover' src='" .. baseurl .. "avatar/" .. hexdigest .. "?s=128&d=retro' /></span>" .. buffer) + return 0 +end + +function filter_write(str) + buffer = buffer .. str +end -- 2.54.0 From 0f782947ed10ba7341d95fcf3de5095c3dc2ef8c Mon Sep 17 00:00:00 2001 From: Eric Wong <e@80x24.org> Date: Thu, 21 May 2026 15:04:30 +0200 Subject: [PATCH 07/10] ui-log: improve decoration display for browsers without CSS Text-based browsers without CSS support show all the decorations bunched together without spacing. Rely on a whitespace instead of CSS support. --- cgit.css | 1 - ui-log.c | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cgit.css b/cgit.css index dab5977..d669e47 100644 --- a/cgit.css +++ b/cgit.css @@ -755,7 +755,6 @@ div#cgit div.commit-subject a.tag-deco, div#cgit div.commit-subject a.tag-annotated-deco, div#cgit div.commit-subject a.remote-deco, div#cgit div.commit-subject a.deco { - margin-left: 1em; font-size: 75%; } diff --git a/ui-log.c b/ui-log.c index 434ff8d..b4c895c 100644 --- a/ui-log.c +++ b/ui-log.c @@ -77,11 +77,13 @@ void show_commit_decorations(struct commit *commit) * don't display anything. */ break; case DECORATION_REF_LOCAL: + html(" "); cgit_log_link(buf, NULL, "branch-deco", buf, NULL, ctx.qry.vpath, 0, NULL, NULL, ctx.qry.showmsg, 0); break; case DECORATION_REF_TAG: + html(" "); if (!refs_read_ref(get_main_ref_store(the_repository), deco->name, &oid_tag) && !peel_object(the_repository, &oid_tag, &peeled, PEEL_OBJECT_VERIFY_TAGGED_OBJECT_TYPE)) is_annotated = !oideq(&oid_tag, &peeled); @@ -90,12 +92,14 @@ void show_commit_decorations(struct commit *commit) case DECORATION_REF_REMOTE: if (!ctx.repo->enable_remote_branches) break; + html(" "); cgit_log_link(buf, NULL, "remote-deco", NULL, oid_to_hex(&commit->object.oid), ctx.qry.vpath, 0, NULL, NULL, ctx.qry.showmsg, 0); break; default: + html(" "); cgit_commit_link(buf, NULL, "deco", ctx.qry.head, oid_to_hex(&commit->object.oid), ctx.qry.vpath); -- 2.54.0 From 1cd637cd1f637aa8aa1c2d416ae01ee31b3a691c Mon Sep 17 00:00:00 2001 From: Eric Wong <e@80x24.org> Date: Thu, 21 May 2026 15:11:10 +0200 Subject: [PATCH 08/10] use buffered stdio Our generation of HTML triggers many small write(2) syscalls which is inefficient. Time output on a horrible query against my git.git mirror shows significant performance improvement: QUERY_STRING='id=2b93bfac0f5bcabbf60f174f4e7bfa9e318e64d5&id2=d6da71a9d16b8cf27f9d8f90692d3625c849cbc8' PATH_INFO=/mirrors/git.git/diff export QUERY_STRING PATH_INFO time ./cgit >/dev/null Before: real 0m1.585s user 0m0.904s sys 0m0.658s After: real 0m0.750s user 0m0.666s sys 0m0.076s Signed-off-by: Eric Wong <e@80x24.org> Signed-off-by: Alyssa Ross <hi@alyssa.is> --- cache.c | 7 +++++++ cgit.c | 2 +- filter.c | 22 +++++++++++++++++++++- html.c | 2 +- ui-snapshot.c | 3 +++ 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/cache.c b/cache.c index e70af13..13cceac 100644 --- a/cache.c +++ b/cache.c @@ -272,6 +272,13 @@ static int process_slot(struct cache_slot *slot) { int err; + /* + * Make sure any buffered data is flushed before we redirect, + * do sendfile(2) or write(2) + */ + if (fflush(stdout)) + return errno; + err = open_slot(slot); if (!err && slot->match) { if (is_expired(slot)) { diff --git a/cgit.c b/cgit.c index ca318e8..3dc55c3 100644 --- a/cgit.c +++ b/cgit.c @@ -684,7 +684,7 @@ static inline void authenticate_post(void) len = MAX_AUTHENTICATION_POST_BYTES; if ((len = read(STDIN_FILENO, buffer, len)) < 0) die_errno("Could not read POST from stdin"); - if (write(STDOUT_FILENO, buffer, len) < 0) + if (fwrite(buffer, 1, len, stdout) < len) die_errno("Could not write POST to stdout"); cgit_close_filter(ctx.cfg.auth_filter); exit(0); diff --git a/filter.c b/filter.c index c778d05..781f8e3 100644 --- a/filter.c +++ b/filter.c @@ -48,6 +48,7 @@ static int open_exec_filter(struct cgit_filter *base, va_list ap) for (i = 0; i < filter->base.argument_count; i++) filter->argv[i + 1] = va_arg(ap, char *); + chk_zero(fflush(stdout), "unable to flush STDOUT"); filter->old_stdout = chk_positive(dup(STDOUT_FILENO), "Unable to duplicate STDOUT"); chk_zero(pipe(pipe_fh), "Unable to create pipe to subprocess"); @@ -71,6 +72,7 @@ static int close_exec_filter(struct cgit_filter *base) struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base; int i, exit_status = 0; + chk_zero(fflush(stdout), "unable to flush STDOUT"); chk_non_negative(dup2(filter->old_stdout, STDOUT_FILENO), "Unable to restore STDOUT"); close(filter->old_stdout); @@ -143,17 +145,32 @@ void cgit_init_filters(void) #endif #ifndef NO_LUA -static ssize_t (*libc_write)(int fd, const void *buf, size_t count); +static size_t (*libc_fwrite)(const void *buf, size_t size, size_t n, FILE *); +static ssize_t (*libc_write)(int fd, const void *buf, size_t size); static ssize_t (*filter_write)(struct cgit_filter *base, const void *buf, size_t count) = NULL; static struct cgit_filter *current_write_filter = NULL; void cgit_init_filters(void) { + /* + * we need to wrap both functions since the Lua filter may + * have code which calls write(2) directly, bypassing fwrite(3) + */ + libc_fwrite = dlsym(RTLD_NEXT, "fwrite"); + if (!libc_fwrite) + die("Could not locate libc's write function"); libc_write = dlsym(RTLD_NEXT, "write"); if (!libc_write) die("Could not locate libc's write function"); } +size_t fwrite(const void *buf, size_t size, size_t n, FILE *f) +{ + if (f != stdout || !filter_write) + return libc_fwrite(buf, size, n, f); + return filter_write(current_write_filter, buf, size * n); +} + ssize_t write(int fd, const void *buf, size_t count) { if (fd != STDOUT_FILENO || !filter_write) @@ -305,6 +322,9 @@ static int open_lua_filter(struct cgit_filter *base, va_list ap) struct lua_filter *filter = (struct lua_filter *)base; int i; + if (fflush(stdout)) + return 1; + if (init_lua_filter(filter)) return 1; diff --git a/html.c b/html.c index 0bac34b..ced781a 100644 --- a/html.c +++ b/html.c @@ -80,7 +80,7 @@ char *fmtalloc(const char *format, ...) void html_raw(const char *data, size_t size) { - if (write(STDOUT_FILENO, data, size) != size) + if (fwrite(data, 1, size, stdout) != size) die_errno("write error on html output"); } diff --git a/ui-snapshot.c b/ui-snapshot.c index d157222..b3039d9 100644 --- a/ui-snapshot.c +++ b/ui-snapshot.c @@ -39,6 +39,9 @@ static int write_archive_type(const char *format, const char *hex, const char *p /* strvec guarantees a trailing NULL entry. */ memcpy(nargv, argv.v, sizeof(char *) * (argv.nr + 1)); + if (fflush(stdout)) + return errno; + result = write_archive(argv.nr, nargv, NULL, the_repository, NULL, 0); strvec_clear(&argv); free(nargv); -- 2.54.0 From 55f8359c0b18e6f2c182fd14132d1d58fb39b6d1 Mon Sep 17 00:00:00 2001 From: Alyssa Ross <hi@alyssa.is> Date: Thu, 21 May 2026 14:17:50 +0200 Subject: [PATCH 09/10] ui-shared: add "this commit" option to switch form Branches are grouped into their own section to make the "this commit" option visually distinct. Adding this option will result in two options being marked as selected if a branch has the same name as a commit oid. But that would cause all sorts of other problems anyway (attempting to switch to the branch would actually give you the commit, etc.), so let's not worry about that. A "permalink" link on the blob view next to the "plain" link would probably be more discoverable, but that would only work for the blob view. The switch UI is visible everywhere. Signed-off-by: Alyssa Ross <hi@alyssa.is> --- ui-shared.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ui-shared.c b/ui-shared.c index 0734711..9b602cc 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -947,6 +947,15 @@ void cgit_add_clone_urls(void (*fn)(const char *)) add_clone_urls(fn, ctx.cfg.clone_prefix, ctx.repo->url); } +static int print_this_commit_option(void) +{ + struct object_id oid; + if (repo_get_oid(the_repository, ctx.qry.head, &oid)) + return 1; + html_option(oid_to_hex(&oid), "this commit", ctx.qry.head); + return 0; +} + static int print_branch_option(const struct reference *ref, void *cb_data) { char *name = (char *)ref->name; @@ -1053,11 +1062,14 @@ static void print_header(void) html("<form method='get'>\n"); cgit_add_hidden_formfields(0, 1, ctx.qry.page); html("<select name='h' onchange='this.form.submit();'>\n"); + print_this_commit_option(); + html("<optgroup label='branches'>"); refs_for_each_branch_ref(get_main_ref_store(the_repository), print_branch_option, ctx.qry.head); if (ctx.repo->enable_remote_branches) refs_for_each_remote_ref(get_main_ref_store(the_repository), print_branch_option, ctx.qry.head); + html("</optgroup>"); html("</select> "); html("<input type='submit' value='switch'/>"); html("</form>"); -- 2.54.0 From c9f91124f9462d8eeb0a9d2ddeff586807413fc0 Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez <git@bitsofnetworks.org> Date: Fri, 27 Feb 2026 16:51:11 +0100 Subject: [PATCH 10/10] cgit: Fix guessing default branch Even when HEAD is set to "main" in a repository, cgit still uses the "master" branch to detect the age of the last commit. Example: $ cat repositories/openwrt/openwrt.git/HEAD ref: refs/heads/main $ stat repositories/openwrt/openwrt.git/refs/heads/master Modify: 2024-02-22 23:00:01.285731731 +0000 $ stat repositories/openwrt/openwrt.git/refs/heads/main Modify: 2026-02-27 15:33:49.506017172 +0000 In this situation, cgit displays "25 months" for this repository on the index page. I guess the internal format for HEAD has changed at some point, so it needs to be taken into account when parsing it in cgit. Signed-off-by: Baptiste Jonglez <git@bitsofnetworks.org> --- cgit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgit.c b/cgit.c index 3dc55c3..2efbb2c 100644 --- a/cgit.c +++ b/cgit.c @@ -496,7 +496,7 @@ static char *guess_defbranch(void) ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", 0, &oid, NULL); - if (!ref || !skip_prefix(ref, "refs/heads/", &refname)) + if (!ref || !skip_prefix(ref, "ref: refs/heads/", &refname)) return "master"; return xstrdup(refname); } -- 2.54.0
-
-
-
@@ -0,0 +1,156 @@diff --git a/git/git.go b/git/git.go index d55460f..768966a 100644 --- a/git/git.go +++ b/git/git.go @@ -143,13 +143,7 @@ func (g *GitRepo) FileContent(path string) (string, error) { return "", err } - isbin, _ := file.IsBinary() - - if !isbin { - return file.Contents() - } else { - return "Not displaying binary file", nil - } + return file.Contents() } func (g *GitRepo) Tags() ([]*TagReference, error) { diff --git a/go.mod b/go.mod index 9491e43..bc6a398 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,9 @@ module github.com/pocka/legit -go 1.22.0 +go 1.25 require ( - github.com/alecthomas/chroma/v2 v2.14.0 + github.com/alecthomas/chroma/v2 v2.27.0 github.com/bluekeyes/go-gitdiff v0.8.0 github.com/cyphar/filepath-securejoin v0.4.1 github.com/dustin/go-humanize v1.0.1 @@ -20,7 +20,7 @@ require ( github.com/acomagu/bufpipe v1.0.4 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/cloudflare/circl v1.6.0 // indirect - github.com/dlclark/regexp2 v1.11.4 // indirect + github.com/dlclark/regexp2/v2 v2.2.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.6.2 // indirect diff --git a/go.sum b/go.sum index f8ba6ba..6a89c93 100644 --- a/go.sum +++ b/go.sum @@ -6,12 +6,12 @@ github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= -github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= -github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= -github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= -github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= -github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= +github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/alecthomas/chroma/v2 v2.27.0 h1:FodwmyOBgJULFYmDqibcp9pvfDLWdtPRh9v/r5BXYZs= +github.com/alecthomas/chroma/v2 v2.27.0/go.mod h1:NjJ3ciIgrqBNeIkWZ4e46nseoLDslxU1LmfCoL+wcY8= +github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= +github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -30,8 +30,8 @@ github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGL github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= -github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2/v2 v2.2.1 h1:mf4KkFUj0gJuarK8P+LgiS+Lit7m9N1yAwEfPbee7R0= +github.com/dlclark/regexp2/v2 v2.2.1/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= diff --git a/routes/routes.go b/routes/routes.go index 71a0d67..4767e48 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -138,7 +138,7 @@ func (d *deps) RepoIndex(w http.ResponseWriter, r *http.Request) { return blackfriday.GoToNext } - if node.Type == blackfriday.Link { + if node.Type == blackfriday.Link || node.Type == blackfriday.Image { href := string(node.LinkData.Destination) parsedURL, err := url.Parse(href) if err == nil && parsedURL.Host != "" { @@ -151,7 +151,9 @@ func (d *deps) RepoIndex(w http.ResponseWriter, r *http.Request) { href = "." + href } - if strings.LastIndexByte(href, '/') == len(href)-1 { + if node.Type == blackfriday.Image { + node.LinkData.Destination = fmt.Appendf([]byte{}, "/%s/blob/%s/%s?raw=true", name, mainBranch, href) + } else if strings.LastIndexByte(href, '/') == len(href)-1 { node.LinkData.Destination = fmt.Appendf([]byte{}, "/%s/tree/%s/%s", name, mainBranch, href) node.LinkData.Destination = node.LinkData.Destination[:len(node.LinkData.Destination)-1] } else { @@ -188,6 +190,7 @@ func (d *deps) RepoIndex(w http.ResponseWriter, r *http.Request) { } if readmeContent == "" { + readmeContent = template.HTML(fmt.Sprintf("no readme found for %s", name)) log.Printf("no readme found for %s", name) } @@ -404,13 +407,11 @@ func (d *deps) FileContent(w http.ResponseWriter, r *http.Request) { PreviewTypes: previewTypes, } - if d.c.Meta.SyntaxHighlight { - highlighted, err := highlightCode(treePath, contents) - if err != nil { - log.Println(err) - } else { - data.SyntaxHighlightedContent = highlighted - } + highlighted, err := highlightCode(treePath, contents) + if err != nil { + log.Println(err) + } else { + data.SyntaxHighlightedContent = highlighted } if err := t.ExecuteTemplate(w, "repo-blob-ref", data); err != nil { diff --git a/templates/repo-blob-ref.html.tmpl b/templates/repo-blob-ref.html.tmpl index a0876df..7518c2f 100644 --- a/templates/repo-blob-ref.html.tmpl +++ b/templates/repo-blob-ref.html.tmpl @@ -73,6 +73,10 @@ SPDX-License-Identifier: MIT <aside class="aside"> <dl class="metadata"> {{- template "tab-selector" -}} + <dt class="metadata--key">Raw</dt> + <dd class="metadata--value"> + <a href="?raw=true">View raw</a> + </dd> {{- range .PreviewTypes -}} <dt class="metadata--key">Preview (<span class="preview-type">{{ . }}</span>)</dt> <dd class="metadata--value"> diff --git a/templates/repo-list.html.tmpl b/templates/repo-list.html.tmpl index efb2c37..9f78372 100644 --- a/templates/repo-list.html.tmpl +++ b/templates/repo-list.html.tmpl @@ -18,6 +18,7 @@ SPDX-License-Identifier: MIT <div class="header-title"> <h1 class="header-title--name">{{ .Config.Meta.Title }}</h1> <p class="header-title--description">{{ .Config.Meta.Description }}</p> + <p class="header-title--description">Powered by <a href="https://git.pocka.jp/legit.git">pocka/legit</a></p> </div> </header> <main class="main">
-
-
-
@@ -1,12 +1,21 @@final: prev: { cgit = prev.cgit.overrideAttrs (old: { patches = [ # Make default pages configurable # Vendor the patch here since the original no longer applies cleanly ./default-pages.patch # This has some performance improvements and doesn't assume the default branch is master # Actually that default branch bug might not be fixed but whatever ./for-jason.patch ]; legit-web = prev.legit-web.overrideAttrs (old: { src = prev.fetchFromGitHub { owner = "pocka"; repo = "legit"; rev = "master"; hash = "sha256-Z7pDdIvJXfSCGFxhOxSL1dBVjgHnC5P6Wa7AsQ9t6CY="; }; vendorHash = "sha256-GR+ddG6058s9NDGwbk2z86vcOIa11DUQqP6tS0ruUdo="; # Use a patch instead of a repo hosted on this server to avoid a circular dependency patches = (old.patches or [ ]) ++ [ ./legit.patch ]; # The package in nixpkgs is a huge mess and has tons of mistakes postInstall = '' mkdir -p $out/lib/legit/templates mkdir -p $out/lib/legit/static cp -r templates/* $out/lib/legit/templates cp -r static/* $out/lib/legit/static ''; }); }
-
-
-
@@ -43,11 +43,11 @@}, "nixpkgs": { "locked": { "lastModified": 1782723713, "narHash": "sha256-oPXCU/SSUokcGaJREHibG1CBX3+s/W7orDWQOZDsEeQ=", "lastModified": 1783224372, "narHash": "sha256-8i/87eeoqiGE4yOTjwSA3Eh/ziJRQEmd/unYU+K27sk=", "owner": "NixOS", "repo": "nixpkgs", "rev": "b5aa0fbd538984f6e3d201be0005b4463d8b09f8", "rev": "d407951447dcd00442e97087bf374aad70c04cea", "type": "github" }, "original": {
-