diff options
Diffstat (limited to 'third_party/cgit')
44 files changed, 300 insertions, 1690 deletions
diff --git a/third_party/cgit/AUTHORS b/third_party/cgit/AUTHORS index 031de338f9..256ea6b3bc 100644 --- a/third_party/cgit/AUTHORS +++ b/third_party/cgit/AUTHORS @@ -1,5 +1,5 @@ Maintainer: - Jason A. Donenfeld <Jason@zx2c4.com> + June McEnroe <june@causal.agency> Contributors: Jason A. Donenfeld <Jason@zx2c4.com> diff --git a/third_party/cgit/Makefile b/third_party/cgit/Makefile index 9153a393f7..1a7f1f6381 100644 --- a/third_party/cgit/Makefile +++ b/third_party/cgit/Makefile @@ -1,6 +1,6 @@ all:: -CGIT_VERSION = v1.2.3 +CGIT_VERSION = 1.4.1 CGIT_SCRIPT_NAME = cgit.cgi CGIT_SCRIPT_PATH = /var/www/htdocs/cgit CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH) @@ -14,7 +14,7 @@ htmldir = $(docdir) pdfdir = $(docdir) mandir = $(prefix)/share/man SHA1_HEADER = <openssl/sha.h> -GIT_VER = 2.34.0 +GIT_VER = 2.41.0 GIT_URL = https://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.xz INSTALL = install COPYTREE = cp -r @@ -88,7 +88,6 @@ install: all $(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_DATA_PATH) $(INSTALL) -m 0644 cgit.css $(DESTDIR)$(CGIT_DATA_PATH)/cgit.css $(INSTALL) -m 0644 cgit.png $(DESTDIR)$(CGIT_DATA_PATH)/cgit.png - $(INSTALL) -m 0644 favicon.ico $(DESTDIR)$(CGIT_DATA_PATH)/favicon.ico $(INSTALL) -m 0644 robots.txt $(DESTDIR)$(CGIT_DATA_PATH)/robots.txt $(INSTALL) -m 0755 -d $(DESTDIR)$(filterdir) $(COPYTREE) filters/* $(DESTDIR)$(filterdir) @@ -111,7 +110,6 @@ uninstall: rm -f $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) rm -f $(DESTDIR)$(CGIT_DATA_PATH)/cgit.css rm -f $(DESTDIR)$(CGIT_DATA_PATH)/cgit.png - rm -f $(DESTDIR)$(CGIT_DATA_PATH)/favicon.ico uninstall-doc: uninstall-man uninstall-html uninstall-pdf diff --git a/third_party/cgit/README b/third_party/cgit/README index 7a6b4a40ca..2094b87df0 100644 --- a/third_party/cgit/README +++ b/third_party/cgit/README @@ -1,8 +1,9 @@ -cgit - CGI for Git -================== +cgit-pink - CGI for Git +======================= -This is an attempt to create a fast web interface for the Git SCM, using a -built-in cache to decrease server I/O pressure. +This is a fork of cgit, an attempt to create a fast web interface +for the Git SCM, using a built-in cache to decrease server I/O +pressure. Installation ------------ @@ -32,18 +33,6 @@ This will install `cgit.cgi` and `cgit.css` into `/var/www/htdocs/cgit`. You can configure this location (and a few other things) by providing a `cgit.conf` file (see the Makefile for details). -If you'd like to compile without Lua support, you may use: - - $ make NO_LUA=1 - -And if you'd like to specify a Lua implementation, you may use: - - $ make LUA_PKGCONFIG=lua5.1 - -If this is not specified, the Lua implementation will be auto-detected, -preferring LuaJIT if many are present. Acceptable values are generally "lua", -"luajit", "lua5.1", and "lua5.2". - Dependencies ------------ @@ -51,7 +40,6 @@ Dependencies * libzip * libcrypto (OpenSSL) * libssl (OpenSSL) -* optional: luajit or lua, most reliably used when pkg-config is available Apache configuration -------------------- @@ -92,8 +80,9 @@ the HTTP headers `Modified` and `Expires`. Online presence --------------- -* The cgit homepage is hosted by cgit at <https://git.zx2c4.com/cgit/about/> +* The cgit-pink homepage is hosted by cgit at + <https://git.causal.agency/cgit-pink/about> -* Patches, bug reports, discussions and support should go to the cgit - mailing list: <cgit@lists.zx2c4.com>. To sign up, visit - <https://lists.zx2c4.com/mailman/listinfo/cgit> +* Patches, bug reports, discussions and support should go to the cgit-pink + mailing list: <list+cgit@causal.agency>. Archives are available at: + <https://causal.agency/list/cgit.html> diff --git a/third_party/cgit/cache.c b/third_party/cgit/cache.c index 55199e8fe5..59372541cb 100644 --- a/third_party/cgit/cache.c +++ b/third_party/cgit/cache.c @@ -85,40 +85,45 @@ static int close_slot(struct cache_slot *slot) /* Print the content of the active cache slot (but skip the key). */ static int print_slot(struct cache_slot *slot) { + off_t off; #ifdef HAVE_LINUX_SENDFILE - off_t start_off; - int ret; + off_t size; +#endif + + off = slot->keylen + 1; - start_off = slot->keylen + 1; +#ifdef HAVE_LINUX_SENDFILE + size = slot->cache_st.st_size; do { - ret = sendfile(STDOUT_FILENO, slot->cache_fd, &start_off, - slot->cache_st.st_size - start_off); + ssize_t ret; + ret = sendfile(STDOUT_FILENO, slot->cache_fd, &off, size - off); if (ret < 0) { if (errno == EAGAIN || errno == EINTR) continue; + /* Fall back to read/write on EINVAL or ENOSYS */ + if (errno == EINVAL || errno == ENOSYS) + break; return errno; } - return 0; + if (off == size) + return 0; } while (1); -#else - ssize_t i, j; +#endif - i = lseek(slot->cache_fd, slot->keylen + 1, SEEK_SET); - if (i != slot->keylen + 1) + if (lseek(slot->cache_fd, off, SEEK_SET) != off) return errno; do { - i = j = xread(slot->cache_fd, slot->buf, sizeof(slot->buf)); - if (i > 0) - j = xwrite(STDOUT_FILENO, slot->buf, i); - } while (i > 0 && j == i); - - if (i < 0 || j != i) - return errno; - else - return 0; -#endif + ssize_t ret; + ret = xread(slot->cache_fd, slot->buf, sizeof(slot->buf)); + if (ret < 0) + return errno; + if (ret == 0) + return 0; + if (write_in_full(STDOUT_FILENO, slot->buf, ret) < 0) + return errno; + } while (1); } /* Check if the slot has expired */ @@ -265,6 +270,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/third_party/cgit/cgit.c b/third_party/cgit/cgit.c index 4b2d86c881..40202ead67 100644 --- a/third_party/cgit/cgit.c +++ b/third_party/cgit/cgit.c @@ -378,7 +378,7 @@ static void prepare_context(void) ctx.cfg.commit_sort = 0; ctx.cfg.css = "/cgit.css"; ctx.cfg.logo = "/cgit.png"; - ctx.cfg.favicon = "/favicon.ico"; + ctx.cfg.favicon = NULL; ctx.cfg.local_time = 0; ctx.cfg.enable_http_clone = 1; ctx.cfg.enable_index_owner = 1; @@ -507,9 +507,11 @@ static inline void parse_readme(const char *readme, char **filename, char **ref, /* Check if the readme is tracked in the git repo. */ colon = strchr(readme, ':'); if (colon && strlen(colon) > 1) { - /* If it starts with a colon, we want to use - * the default branch */ - if (colon == readme && repo->defbranch) + /* If it starts with a colon, we want to use head given + * from query or the default branch */ + if (colon == readme && ctx.qry.head) + *ref = xstrdup(ctx.qry.head); + else if (colon == readme && repo->defbranch) *ref = xstrdup(repo->defbranch); else *ref = xstrndup(readme, colon - readme); @@ -626,7 +628,7 @@ static int prepare_repo_cmd(int nongit) return 1; } - if (get_oid(ctx.qry.head, &oid)) { + if (repo_get_oid(the_repository, ctx.qry.head, &oid)) { char *old_head = ctx.qry.head; ctx.qry.head = xstrdup(ctx.repo->defbranch); cgit_print_error_page(404, "Not found", @@ -674,7 +676,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); @@ -963,13 +965,7 @@ static void cgit_parse_args(int argc, const char **argv) for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--version")) { - printf("CGit %s | https://git.zx2c4.com/cgit/\n\nCompiled in features:\n", CGIT_VERSION); -#ifdef NO_LUA - printf("[-] "); -#else - printf("[+] "); -#endif - printf("Lua scripting\n"); + printf("CGit-pink %s | https://git.causal.agency/cgit-pink/\n\nCompiled in features:\n", CGIT_VERSION); #ifndef HAVE_LINUX_SENDFILE printf("[-] "); #else @@ -1051,7 +1047,6 @@ int cmd_main(int argc, const char **argv) const char *path; int err, ttl; - cgit_init_filters(); atexit(cgit_cleanup_filters); prepare_context(); diff --git a/third_party/cgit/cgit.css b/third_party/cgit/cgit.css index dfa144d05d..7133a7ba37 100644 --- a/third_party/cgit/cgit.css +++ b/third_party/cgit/cgit.css @@ -75,7 +75,7 @@ div#cgit table.tabs td { } div#cgit table.tabs td a { - padding: 2px 0.75em; + padding: 2px 0.25em; color: #777; font-size: 110%; } @@ -363,6 +363,10 @@ div#cgit table.blame td.lines > div > pre { top: 0; } +div#cgit table.blame .oid { + font-size: 100%; +} + div#cgit table.bin-blob { margin-top: 0.5em; border: solid 1px black; @@ -437,11 +441,6 @@ div#cgit div.commit-subject { padding: 0em; } -div#cgit div.commit-msg { - white-space: pre; - font-family: monospace; -} - div#cgit div.notes-header { font-weight: bold; padding-top: 1.5em; @@ -538,26 +537,20 @@ div#cgit table.diff { width: 100%; } -div#cgit table.diff td { - font-family: monospace; - white-space: pre; -} - -div#cgit table.diff td div.head { +div#cgit table.diff td span.head { font-weight: bold; - margin-top: 1em; color: black; } -div#cgit table.diff td div.hunk { +div#cgit table.diff td span.hunk { color: #009; } -div#cgit table.diff td div.add { +div#cgit table.diff td span.add { color: green; } -div#cgit table.diff td div.del { +div#cgit table.diff td span.del { color: red; } @@ -581,7 +574,6 @@ div#cgit table.list td.reposection { div#cgit a.button { font-size: 80%; - padding: 0em 0.5em; } div#cgit a.primary { @@ -671,15 +663,20 @@ div#cgit div.footer a:hover { div#cgit a.branch-deco { color: #000; - margin: 0px 0.5em; padding: 0px 0.25em; background-color: #88ff88; border: solid 1px #007700; } +div#cgit a.rev-deco { + color: #000; + padding: 0px 0.25em; + background-color: #eee; + border: solid 1px #aaa; +} + div#cgit a.tag-deco { color: #000; - margin: 0px 0.5em; padding: 0px 0.25em; background-color: #ffff88; border: solid 1px #777700; @@ -687,7 +684,6 @@ div#cgit a.tag-deco { div#cgit a.tag-annotated-deco { color: #000; - margin: 0px 0.5em; padding: 0px 0.25em; background-color: #ffcc88; border: solid 1px #777700; @@ -695,7 +691,6 @@ div#cgit a.tag-annotated-deco { div#cgit a.remote-deco { color: #000; - margin: 0px 0.5em; padding: 0px 0.25em; background-color: #ccccff; border: solid 1px #000077; @@ -703,7 +698,6 @@ div#cgit a.remote-deco { div#cgit a.deco { color: #000; - margin: 0px 0.5em; padding: 0px 0.25em; background-color: #ff8888; border: solid 1px #770000; @@ -713,8 +707,8 @@ div#cgit div.commit-subject a.branch-deco, 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.rev-deco, div#cgit div.commit-subject a.deco { - margin-left: 1em; font-size: 75%; } diff --git a/third_party/cgit/cgit.h b/third_party/cgit/cgit.h index 69b5c13232..f201f82b85 100644 --- a/third_party/cgit/cgit.h +++ b/third_party/cgit/cgit.h @@ -1,25 +1,33 @@ #ifndef CGIT_H #define CGIT_H +#include <stdbool.h> #include <git-compat-util.h> -#include <stdbool.h> -#include <cache.h> +#include <archive.h> +#include <commit.h> +#include <diffcore.h> +#include <diff.h> +#include <environment.h> +#include <graph.h> #include <grep.h> +#include <hex.h> +#include <log-tree.h> +#include <notes.h> #include <object.h> +#include <object-name.h> #include <object-store.h> -#include <tree.h> -#include <commit.h> -#include <tag.h> -#include <diff.h> -#include <diffcore.h> -#include <strvec.h> +#include <path.h> #include <refs.h> #include <revision.h> -#include <log-tree.h> -#include <archive.h> +#include <setup.h> #include <string-list.h> +#include <strvec.h> +#include <tag.h> +#include <tree.h> +#include <utf8.h> +#include <wrapper.h> #include <xdiff-interface.h> #include <xdiff/xdiff.h> #include <utf8.h> @@ -385,7 +393,6 @@ extern void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char extern void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv); extern struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype); extern void cgit_cleanup_filters(void); -extern void cgit_init_filters(void); extern void cgit_prepare_repo_env(struct cgit_repo * repo); diff --git a/third_party/cgit/cgit.mk b/third_party/cgit/cgit.mk index 3fcc1ca314..5b9ed5be8e 100644 --- a/third_party/cgit/cgit.mk +++ b/third_party/cgit/cgit.mk @@ -27,32 +27,6 @@ ifdef NO_C99_FORMAT CFLAGS += -DNO_C99_FORMAT endif -ifdef NO_LUA - LUA_MESSAGE := linking without specified Lua support - CGIT_CFLAGS += -DNO_LUA -else -ifeq ($(LUA_PKGCONFIG),) - LUA_PKGCONFIG := $(shell for pc in luajit lua lua5.2 lua5.1; do \ - $(PKG_CONFIG) --exists $$pc 2>/dev/null && echo $$pc && break; \ - done) - LUA_MODE := autodetected -else - LUA_MODE := specified -endif -ifneq ($(LUA_PKGCONFIG),) - LUA_MESSAGE := linking with $(LUA_MODE) $(LUA_PKGCONFIG) - LUA_LIBS := $(shell $(PKG_CONFIG) --libs $(LUA_PKGCONFIG) 2>/dev/null) - LUA_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(LUA_PKGCONFIG) 2>/dev/null) - CGIT_LIBS += $(LUA_LIBS) - CGIT_CFLAGS += $(LUA_CFLAGS) -else - LUA_MESSAGE := linking without autodetected Lua support - NO_LUA := YesPlease - CGIT_CFLAGS += -DNO_LUA -endif - -endif - # Add -ldl to linker flags on systems that commonly use GNU libc. ifneq (,$(filter $(uname_S),Linux GNU GNU/kFreeBSD)) CGIT_LIBS += -ldl @@ -130,7 +104,6 @@ $(CGIT_OBJS): %.o: %.c GIT-CFLAGS $(CGIT_PREFIX)CGIT-CFLAGS $(missing_dep_dirs) $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $(CGIT_CFLAGS) $< $(CGIT_PREFIX)cgit: $(CGIT_OBJS) GIT-LDFLAGS $(GITLIBS) - @echo 1>&1 " * $(LUA_MESSAGE)" $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) $(CGIT_LIBS) CGIT_SP_OBJS := $(patsubst %.o,%.sp,$(CGIT_OBJS)) diff --git a/third_party/cgit/cgitrc.5.txt b/third_party/cgit/cgitrc.5.txt index 33a6a8c0c7..cafb5355ea 100644 --- a/third_party/cgit/cgitrc.5.txt +++ b/third_party/cgit/cgitrc.5.txt @@ -219,7 +219,7 @@ enable-tree-linenumbers:: favicon:: Url used as link to a shortcut icon for cgit. It is suggested to use the value "/favicon.ico" since certain browsers will ignore other - values. Default value: "/favicon.ico". + values. Default value: none. footer:: The content of the file specified with this option will be included @@ -579,11 +579,11 @@ repo.readme:: verbatim as the "About" 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:docs/readme.mkd". If the value begins - with a colon, i.e. ":docs/readme.rst", the default branch of the - repository will be used. Sharing any file will expose that entire - directory tree to the "/about/PATH" endpoints, so be sure that there - are no non-public files located in the same directory as the readme - file. Default value: <readme>. + with a colon, i.e. ":docs/readme.rst", the head giving in query or + the default branch of the repository will be used. Sharing any file + will expose that entire directory tree to the "/about/PATH" endpoints, + so be sure that there are no non-public files located in the same + directory as the readme file. Default value: <readme>. repo.section:: Override the current section name for this repository. Default value: @@ -632,37 +632,6 @@ specification with the relevant string; available values are: 'exec:':: The default "one process per filter" mode. -'lua:':: - Executes the script using a built-in Lua interpreter. The script is - loaded once per execution of cgit, and may be called multiple times - during cgit's lifetime, making it a good choice for repeated filters - such as the 'email filter'. It responds to three functions: - - 'filter_open(argument1, argument2, argument3, ...)':: - This is called upon activation of the filter for a particular - set of data. - 'filter_write(buffer)':: - This is called whenever cgit writes data to the webpage. - 'filter_close()':: - This is called when the current filtering operation is - completed. It must return an integer value. Usually 0 - indicates success. - - Additionally, cgit exposes to the Lua the following built-in functions: - - 'html(str)':: - Writes 'str' to the webpage. - 'html_txt(str)':: - HTML escapes and writes 'str' to the webpage. - 'html_attr(str)':: - HTML escapes for an attribute and writes "str' to the webpage. - 'html_url_path(str)':: - URL escapes for a path and writes 'str' to the webpage. - 'html_url_arg(str)':: - URL escapes for an argument and writes 'str' to the webpage. - 'html_include(file)':: - Includes 'file' in webpage. - Parameters are provided to filters as follows. @@ -696,9 +665,6 @@ auth filter:: with a 302 redirect, and write to output one or more "Set-Cookie" HTTP headers, each followed by a newline. - Please see `filters/simple-authentication.lua` for a clear example - script that may be modified. - commit filter:: This filter is given no arguments. The commit message text that is to be filtered is available on standard input and the filtered text is diff --git a/third_party/cgit/default.nix b/third_party/cgit/default.nix index 025877ee4b..c783bda16e 100644 --- a/third_party/cgit/default.nix +++ b/third_party/cgit/default.nix @@ -1,21 +1,23 @@ { depot, lib, pkgs, ... }: let - inherit (pkgs) stdenv gzip bzip2 xz luajit zlib autoconf openssl pkgconfig; -in stdenv.mkDerivation rec { - pname = "cgit"; + inherit (pkgs) stdenv gzip bzip2 xz lzip zstd zlib openssl; +in +stdenv.mkDerivation rec { + pname = "cgit-pink"; version = "master"; src = ./.; - nativeBuildInputs = [ autoconf pkgconfig ]; - buildInputs = [ openssl zlib luajit ]; + buildInputs = [ openssl zlib ]; enableParallelBuilding = true; postPatch = '' sed -e 's|"gzip"|"${gzip}/bin/gzip"|' \ -e 's|"bzip2"|"${bzip2.bin}/bin/bzip2"|' \ + -e 's|"lzip"|"${lzip}/bin/lzip"|' \ -e 's|"xz"|"${xz.bin}/bin/xz"|' \ + -e 's|"zstd"|"${zstd}/bin/zstd"|' \ -i ui-snapshot.c ''; @@ -32,12 +34,18 @@ in stdenv.mkDerivation rec { cat tvl-extra.css >> cgit.css ''; + stripDebugList = [ "cgit" ]; + + # We don't use the filters and they require wrapping to find their deps + postInstall = '' + rm -rf "$out/lib/cgit/filters" + find "$out" -type d -empty -delete + ''; + meta = { - homepage = https://git.zx2c4.com/cgit/about/; - repositories.git = git://git.zx2c4.com/cgit; - description = "Web frontend for git repositories"; + hompepage = "https://git.causal.agency/cgit-pink/"; + description = "cgit fork aiming for better maintenance"; license = lib.licenses.gpl2; platforms = lib.platforms.linux; - maintainers = with lib.maintainers; [ bjornfor ]; }; } diff --git a/third_party/cgit/favicon.ico b/third_party/cgit/favicon.ico deleted file mode 100644 index 56ff59384f..0000000000 --- a/third_party/cgit/favicon.ico +++ /dev/null Binary files differdiff --git a/third_party/cgit/filter.c b/third_party/cgit/filter.c index 181d9a892f..190fb5501b 100644 --- a/third_party/cgit/filter.c +++ b/third_party/cgit/filter.c @@ -8,12 +8,6 @@ #include "cgit.h" #include "html.h" -#ifndef NO_LUA -#include <dlfcn.h> -#include <lua.h> -#include <lualib.h> -#include <lauxlib.h> -#endif static inline void reap_filter(struct cgit_filter *filter) { @@ -48,6 +42,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 +66,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); @@ -136,234 +132,6 @@ void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **ar filter->base.argument_count = 0; } -#ifdef NO_LUA -void cgit_init_filters(void) -{ -} -#endif - -#ifndef NO_LUA -static ssize_t (*libc_write)(int fd, const void *buf, size_t count); -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) -{ - libc_write = dlsym(RTLD_NEXT, "write"); - if (!libc_write) - die("Could not locate libc's write function"); -} - -ssize_t write(int fd, const void *buf, size_t count) -{ - if (fd != STDOUT_FILENO || !filter_write) - return libc_write(fd, buf, count); - return filter_write(current_write_filter, buf, count); -} - -static inline void hook_write(struct cgit_filter *filter, ssize_t (*new_write)(struct cgit_filter *base, const void *buf, size_t count)) -{ - /* We want to avoid buggy nested patterns. */ - assert(filter_write == NULL); - assert(current_write_filter == NULL); - current_write_filter = filter; - filter_write = new_write; -} - -static inline void unhook_write(void) -{ - assert(filter_write != NULL); - assert(current_write_filter != NULL); - filter_write = NULL; - current_write_filter = NULL; -} - -struct lua_filter { - struct cgit_filter base; - char *script_file; - lua_State *lua_state; -}; - -static void error_lua_filter(struct lua_filter *filter) -{ - die("Lua error in %s: %s", filter->script_file, lua_tostring(filter->lua_state, -1)); - lua_pop(filter->lua_state, 1); -} - -static ssize_t write_lua_filter(struct cgit_filter *base, const void *buf, size_t count) -{ - struct lua_filter *filter = (struct lua_filter *)base; - - lua_getglobal(filter->lua_state, "filter_write"); - lua_pushlstring(filter->lua_state, buf, count); - if (lua_pcall(filter->lua_state, 1, 0, 0)) { - error_lua_filter(filter); - errno = EIO; - return -1; - } - return count; -} - -static inline int hook_lua_filter(lua_State *lua_state, void (*fn)(const char *txt)) -{ - const char *str; - ssize_t (*save_filter_write)(struct cgit_filter *base, const void *buf, size_t count); - struct cgit_filter *save_filter; - - str = lua_tostring(lua_state, 1); - if (!str) - return 0; - - save_filter_write = filter_write; - save_filter = current_write_filter; - unhook_write(); - fn(str); - hook_write(save_filter, save_filter_write); - - return 0; -} - -static int html_lua_filter(lua_State *lua_state) -{ - return hook_lua_filter(lua_state, html); -} - -static int html_txt_lua_filter(lua_State *lua_state) -{ - return hook_lua_filter(lua_state, html_txt); -} - -static int html_attr_lua_filter(lua_State *lua_state) -{ - return hook_lua_filter(lua_state, html_attr); -} - -static int html_url_path_lua_filter(lua_State *lua_state) -{ - return hook_lua_filter(lua_state, html_url_path); -} - -static int html_url_arg_lua_filter(lua_State *lua_state) -{ - return hook_lua_filter(lua_state, html_url_arg); -} - -static int html_include_lua_filter(lua_State *lua_state) -{ - return hook_lua_filter(lua_state, (void (*)(const char *))html_include); -} - -static void cleanup_lua_filter(struct cgit_filter *base) -{ - struct lua_filter *filter = (struct lua_filter *)base; - - if (!filter->lua_state) - return; - - lua_close(filter->lua_state); - filter->lua_state = NULL; - if (filter->script_file) { - free(filter->script_file); - filter->script_file = NULL; - } -} - -static int init_lua_filter(struct lua_filter *filter) -{ - if (filter->lua_state) - return 0; - - if (!(filter->lua_state = luaL_newstate())) - return 1; - - luaL_openlibs(filter->lua_state); - - lua_pushcfunction(filter->lua_state, html_lua_filter); - lua_setglobal(filter->lua_state, "html"); - lua_pushcfunction(filter->lua_state, html_txt_lua_filter); - lua_setglobal(filter->lua_state, "html_txt"); - lua_pushcfunction(filter->lua_state, html_attr_lua_filter); - lua_setglobal(filter->lua_state, "html_attr"); - lua_pushcfunction(filter->lua_state, html_url_path_lua_filter); - lua_setglobal(filter->lua_state, "html_url_path"); - lua_pushcfunction(filter->lua_state, html_url_arg_lua_filter); - lua_setglobal(filter->lua_state, "html_url_arg"); - lua_pushcfunction(filter->lua_state, html_include_lua_filter); - lua_setglobal(filter->lua_state, "html_include"); - - if (luaL_dofile(filter->lua_state, filter->script_file)) { - error_lua_filter(filter); - lua_close(filter->lua_state); - filter->lua_state = NULL; - return 1; - } - return 0; -} - -static int open_lua_filter(struct cgit_filter *base, va_list ap) -{ - struct lua_filter *filter = (struct lua_filter *)base; - int i; - - if (init_lua_filter(filter)) - return 1; - - hook_write(base, write_lua_filter); - - lua_getglobal(filter->lua_state, "filter_open"); - for (i = 0; i < filter->base.argument_count; ++i) - lua_pushstring(filter->lua_state, va_arg(ap, char *)); - if (lua_pcall(filter->lua_state, filter->base.argument_count, 0, 0)) { - error_lua_filter(filter); - return 1; - } - return 0; -} - -static int close_lua_filter(struct cgit_filter *base) -{ - struct lua_filter *filter = (struct lua_filter *)base; - int ret = 0; - - lua_getglobal(filter->lua_state, "filter_close"); - if (lua_pcall(filter->lua_state, 0, 1, 0)) { - error_lua_filter(filter); - ret = -1; - } else { - ret = lua_tonumber(filter->lua_state, -1); - lua_pop(filter->lua_state, 1); - } - - unhook_write(); - return ret; -} - -static void fprintf_lua_filter(struct cgit_filter *base, FILE *f, const char *prefix) -{ - struct lua_filter *filter = (struct lua_filter *)base; - fprintf(f, "%slua:%s\n", prefix, filter->script_file); -} - - -static struct cgit_filter *new_lua_filter(const char *cmd, int argument_count) -{ - struct lua_filter *filter; - - filter = xmalloc(sizeof(*filter)); - memset(filter, 0, sizeof(*filter)); - filter->base.open = open_lua_filter; - filter->base.close = close_lua_filter; - filter->base.fprintf = fprintf_lua_filter; - filter->base.cleanup = cleanup_lua_filter; - filter->base.argument_count = argument_count; - filter->script_file = xstrdup(cmd); - - return &filter->base; -} - -#endif - - int cgit_open_filter(struct cgit_filter *filter, ...) { int result; @@ -395,9 +163,6 @@ static const struct { struct cgit_filter *(*ctor)(const char *cmd, int argument_count); } filter_specs[] = { { "exec", new_exec_filter }, -#ifndef NO_LUA - { "lua", new_lua_filter }, -#endif }; struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype) diff --git a/third_party/cgit/filters/email-gravatar.lua b/third_party/cgit/filters/email-gravatar.lua deleted file mode 100644 index c39b490d6b..0000000000 --- a/third_party/cgit/filters/email-gravatar.lua +++ /dev/null @@ -1,35 +0,0 @@ --- This script may be used with the email-filter or repo.email-filter settings in cgitrc. --- It adds gravatar icons to author names. It is designed to be used with the lua: --- prefix in filters. It is much faster than the corresponding python script. --- --- Requirements: --- luaossl --- <http://25thandclement.com/~william/projects/luaossl.html> --- - -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 = "" - md5 = md5_hex(email:sub(2, -2):lower()) -end - -function filter_close() - html("<img src='//www.gravatar.com/avatar/" .. md5 .. "?s=13&d=retro' width='13' height='13' alt='Gravatar' /> " .. buffer) - return 0 -end - -function filter_write(str) - buffer = buffer .. str -end - - diff --git a/third_party/cgit/filters/email-gravatar.py b/third_party/cgit/filters/email-gravatar.py index d70440ea54..012113c591 100755 --- a/third_party/cgit/filters/email-gravatar.py +++ b/third_party/cgit/filters/email-gravatar.py @@ -1,8 +1,5 @@ #!/usr/bin/env python3 -# Please prefer the email-gravatar.lua using lua: as a prefix over this script. This -# script is very slow, in comparison. -# # This script may be used with the email-filter or repo.email-filter settings in cgitrc. # # The following environment variables can be used to retrieve the configuration diff --git a/third_party/cgit/filters/email-libravatar.lua b/third_party/cgit/filters/email-libravatar.lua deleted file mode 100644 index 7336baf830..0000000000 --- a/third_party/cgit/filters/email-libravatar.lua +++ /dev/null @@ -1,36 +0,0 @@ --- This script may be used with the email-filter or repo.email-filter settings in cgitrc. --- It adds libravatar icons to author names. It is designed to be used with the lua: --- prefix in filters. --- --- Requirements: --- luaossl --- <http://25thandclement.com/~william/projects/luaossl.html> --- - -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 = "" - md5 = 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("<img src='" .. baseurl .. "avatar/" .. md5 .. "?s=13&d=retro' width='13' height='13' alt='Libravatar' /> " .. buffer) - return 0 -end - -function filter_write(str) - buffer = buffer .. str -end - - diff --git a/third_party/cgit/filters/file-authentication.lua b/third_party/cgit/filters/file-authentication.lua deleted file mode 100644 index 024880463c..0000000000 --- a/third_party/cgit/filters/file-authentication.lua +++ /dev/null @@ -1,359 +0,0 @@ --- This script may be used with the auth-filter. --- --- Requirements: --- luaossl --- <http://25thandclement.com/~william/projects/luaossl.html> --- luaposix --- <https://github.com/luaposix/luaposix> --- -local sysstat = require("posix.sys.stat") -local unistd = require("posix.unistd") -local rand = require("openssl.rand") -local hmac = require("openssl.hmac") - --- This file should contain a series of lines in the form of: --- username1:hash1 --- username2:hash2 --- username3:hash3 --- ... --- Hashes can be generated using something like `mkpasswd -m sha-512 -R 300000`. --- This file should not be world-readable. -local users_filename = "/etc/cgit-auth/users" - --- This file should contain a series of lines in the form of: --- groupname1:username1,username2,username3,... --- ... -local groups_filename = "/etc/cgit-auth/groups" - --- This file should contain a series of lines in the form of: --- reponame1:groupname1,groupname2,groupname3,... --- ... -local repos_filename = "/etc/cgit-auth/repos" - --- Set this to a path this script can write to for storing a persistent --- cookie secret, which should not be world-readable. -local secret_filename = "/var/cache/cgit/auth-secret" - --- --- --- Authentication functions follow below. Swap these out if you want different authentication semantics. --- --- - --- Looks up a hash for a given user. -function lookup_hash(user) - local line - for line in io.lines(users_filename) do - local u, h = string.match(line, "(.-):(.+)") - if u:lower() == user:lower() then - return h - end - end - return nil -end - --- Looks up users for a given repo. -function lookup_users(repo) - local users = nil - local groups = nil - local line, group, user - for line in io.lines(repos_filename) do - local r, g = string.match(line, "(.-):(.+)") - if r == repo then - groups = { } - for group in string.gmatch(g, "([^,]+)") do - groups[group:lower()] = true - end - break - end - end - if groups == nil then - return nil - end - for line in io.lines(groups_filename) do - local g, u = string.match(line, "(.-):(.+)") - if groups[g:lower()] then - if users == nil then - users = { } - end - for user in string.gmatch(u, "([^,]+)") do - users[user:lower()] = true - end - end - end - return users -end - - --- Sets HTTP cookie headers based on post and sets up redirection. -function authenticate_post() - local hash = lookup_hash(post["username"]) - local redirect = validate_value("redirect", post["redirect"]) - - if redirect == nil then - not_found() - return 0 - end - - redirect_to(redirect) - - if hash == nil or hash ~= unistd.crypt(post["password"], hash) then - set_cookie("cgitauth", "") - else - -- One week expiration time - local username = secure_value("username", post["username"], os.time() + 604800) - set_cookie("cgitauth", username) - end - - html("\n") - return 0 -end - - --- Returns 1 if the cookie is valid and 0 if it is not. -function authenticate_cookie() - accepted_users = lookup_users(cgit["repo"]) - if accepted_users == nil then - -- We return as valid if the repo is not protected. - return 1 - end - - local username = validate_value("username", get_cookie(http["cookie"], "cgitauth")) - if username == nil or not accepted_users[username:lower()] then - return 0 - else - return 1 - end -end - --- Prints the html for the login form. -function body() - html("<h2>Authentication Required</h2>") - html("<form method='post' action='") - html_attr(cgit["login"]) - html("'>") - html("<input type='hidden' name='redirect' value='") - html_attr(secure_value("redirect", cgit["url"], 0)) - html("' />") - html("<table>") - html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autofocus /></td></tr>") - html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' /></td></tr>") - html("<tr><td colspan='2'><input value='Login' type='submit' /></td></tr>") - html("</table></form>") - - return 0 -end - - - --- --- --- Wrapper around filter API, exposing the http table, the cgit table, and the post table to the above functions. --- --- - -local actions = {} -actions["authenticate-post"] = authenticate_post -actions["authenticate-cookie"] = authenticate_cookie -actions["body"] = body - -function filter_open(...) - action = actions[select(1, ...)] - - http = {} - http["cookie"] = select(2, ...) - http["method"] = select(3, ...) - http["query"] = select(4, ...) - http["referer"] = select(5, ...) - http["path"] = select(6, ...) - http["host"] = select(7, ...) - http["https"] = select(8, ...) - - cgit = {} - cgit["repo"] = select(9, ...) - cgit["page"] = select(10, ...) - cgit["url"] = select(11, ...) - cgit["login"] = select(12, ...) - -end - -function filter_close() - return action() -end - -function filter_write(str) - post = parse_qs(str) -end - - --- --- --- Utility functions based on keplerproject/wsapi. --- --- - -function url_decode(str) - if not str then - return "" - end - str = string.gsub(str, "+", " ") - str = string.gsub(str, "%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end) - str = string.gsub(str, "\r\n", "\n") - return str -end - -function url_encode(str) - if not str then - return "" - end - str = string.gsub(str, "\n", "\r\n") - str = string.gsub(str, "([^%w ])", function(c) return string.format("%%%02X", string.byte(c)) end) - str = string.gsub(str, " ", "+") - return str -end - -function parse_qs(qs) - local tab = {} - for key, val in string.gmatch(qs, "([^&=]+)=([^&=]*)&?") do - tab[url_decode(key)] = url_decode(val) - end - return tab -end - -function get_cookie(cookies, name) - cookies = string.gsub(";" .. cookies .. ";", "%s*;%s*", ";") - return url_decode(string.match(cookies, ";" .. name .. "=(.-);")) -end - -function tohex(b) - local x = "" - for i = 1, #b do - x = x .. string.format("%.2x", string.byte(b, i)) - end - return x -end - --- --- --- Cookie construction and validation helpers. --- --- - -local secret = nil - --- Loads a secret from a file, creates a secret, or returns one from memory. -function get_secret() - if secret ~= nil then - return secret - end - local secret_file = io.open(secret_filename, "r") - if secret_file == nil then - local old_umask = sysstat.umask(63) - local temporary_filename = secret_filename .. ".tmp." .. tohex(rand.bytes(16)) - local temporary_file = io.open(temporary_filename, "w") - if temporary_file == nil then - os.exit(177) - end - temporary_file:write(tohex(rand.bytes(32))) - temporary_file:close() - unistd.link(temporary_filename, secret_filename) -- Intentionally fails in the case that another process is doing the same. - unistd.unlink(temporary_filename) - sysstat.umask(old_umask) - secret_file = io.open(secret_filename, "r") - end - if secret_file == nil then - os.exit(177) - end - secret = secret_file:read() - secret_file:close() - if secret:len() ~= 64 then - os.exit(177) - end - return secret -end - --- Returns value of cookie if cookie is valid. Otherwise returns nil. -function validate_value(expected_field, cookie) - local i = 0 - local value = "" - local field = "" - local expiration = 0 - local salt = "" - local chmac = "" - - if cookie == nil or cookie:len() < 3 or cookie:sub(1, 1) == "|" then - return nil - end - - for component in string.gmatch(cookie, "[^|]+") do - if i == 0 then - field = component - elseif i == 1 then - value = component - elseif i == 2 then - expiration = tonumber(component) - if expiration == nil then - expiration = -1 - end - elseif i == 3 then - salt = component - elseif i == 4 then - chmac = component - else - break - end - i = i + 1 - end - - if chmac == nil or chmac:len() == 0 then - return nil - end - - -- Lua hashes strings, so these comparisons are time invariant. - if chmac ~= tohex(hmac.new(get_secret(), "sha256"):final(field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt)) then - return nil - end - - if expiration == -1 or (expiration ~= 0 and expiration <= os.time()) then - return nil - end - - if url_decode(field) ~= expected_field then - return nil - end - - return url_decode(value) -end - -function secure_value(field, value, expiration) - if value == nil or value:len() <= 0 then - return "" - end - - local authstr = "" - local salt = tohex(rand.bytes(16)) - value = url_encode(value) - field = url_encode(field) - authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt - authstr = authstr .. "|" .. tohex(hmac.new(get_secret(), "sha256"):final(authstr)) - return authstr -end - -function set_cookie(cookie, value) - html("Set-Cookie: " .. cookie .. "=" .. value .. "; HttpOnly") - if http["https"] == "yes" or http["https"] == "on" or http["https"] == "1" then - html("; secure") - end - html("\n") -end - -function redirect_to(url) - html("Status: 302 Redirect\n") - html("Cache-Control: no-cache, no-store\n") - html("Location: " .. url .. "\n") -end - -function not_found() - html("Status: 404 Not Found\n") - html("Cache-Control: no-cache, no-store\n\n") -end diff --git a/third_party/cgit/filters/gentoo-ldap-authentication.lua b/third_party/cgit/filters/gentoo-ldap-authentication.lua deleted file mode 100644 index 673c88d102..0000000000 --- a/third_party/cgit/filters/gentoo-ldap-authentication.lua +++ /dev/null @@ -1,360 +0,0 @@ --- This script may be used with the auth-filter. Be sure to configure it as you wish. --- --- Requirements: --- luaossl --- <http://25thandclement.com/~william/projects/luaossl.html> --- lualdap >= 1.2 --- <https://git.zx2c4.com/lualdap/about/> --- luaposix --- <https://github.com/luaposix/luaposix> --- -local sysstat = require("posix.sys.stat") -local unistd = require("posix.unistd") -local lualdap = require("lualdap") -local rand = require("openssl.rand") -local hmac = require("openssl.hmac") - --- --- --- Configure these variables for your settings. --- --- - --- A list of password protected repositories, with which gentooAccess --- group is allowed to access each one. -local protected_repos = { - glouglou = "infra", - portage = "dev" -} - --- Set this to a path this script can write to for storing a persistent --- cookie secret, which should be guarded. -local secret_filename = "/var/cache/cgit/auth-secret" - - --- --- --- Authentication functions follow below. Swap these out if you want different authentication semantics. --- --- - --- Sets HTTP cookie headers based on post and sets up redirection. -function authenticate_post() - local redirect = validate_value("redirect", post["redirect"]) - - if redirect == nil then - not_found() - return 0 - end - - redirect_to(redirect) - - local groups = gentoo_ldap_user_groups(post["username"], post["password"]) - if groups == nil then - set_cookie("cgitauth", "") - else - -- One week expiration time - set_cookie("cgitauth", secure_value("gentoogroups", table.concat(groups, ","), os.time() + 604800)) - end - - html("\n") - return 0 -end - - --- Returns 1 if the cookie is valid and 0 if it is not. -function authenticate_cookie() - local required_group = protected_repos[cgit["repo"]] - if required_group == nil then - -- We return as valid if the repo is not protected. - return 1 - end - - local user_groups = validate_value("gentoogroups", get_cookie(http["cookie"], "cgitauth")) - if user_groups == nil or user_groups == "" then - return 0 - end - for group in string.gmatch(user_groups, "[^,]+") do - if group == required_group then - return 1 - end - end - return 0 -end - --- Prints the html for the login form. -function body() - html("<h2>Gentoo LDAP Authentication Required</h2>") - html("<form method='post' action='") - html_attr(cgit["login"]) - html("'>") - html("<input type='hidden' name='redirect' value='") - html_attr(secure_value("redirect", cgit["url"], 0)) - html("' />") - html("<table>") - html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autofocus /></td></tr>") - html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' /></td></tr>") - html("<tr><td colspan='2'><input value='Login' type='submit' /></td></tr>") - html("</table></form>") - - return 0 -end - --- --- --- Gentoo LDAP support. --- --- - -function gentoo_ldap_user_groups(username, password) - -- Ensure the user is alphanumeric - if username == nil or username:match("%W") then - return nil - end - - local who = "uid=" .. username .. ",ou=devs,dc=gentoo,dc=org" - - local ldap, err = lualdap.open_simple { - uri = "ldap://ldap1.gentoo.org", - who = who, - password = password, - starttls = true, - certfile = "/var/www/uwsgi/cgit/gentoo-ldap/star.gentoo.org.crt", - keyfile = "/var/www/uwsgi/cgit/gentoo-ldap/star.gentoo.org.key", - cacertfile = "/var/www/uwsgi/cgit/gentoo-ldap/ca.pem" - } - if ldap == nil then - return nil - end - - local group_suffix = ".group" - local group_suffix_len = group_suffix:len() - local groups = {} - for dn, attribs in ldap:search { base = who, scope = "subtree" } do - local access = attribs["gentooAccess"] - if dn == who and access ~= nil then - for i, v in ipairs(access) do - local vlen = v:len() - if vlen > group_suffix_len and v:sub(-group_suffix_len) == group_suffix then - table.insert(groups, v:sub(1, vlen - group_suffix_len)) - end - end - end - end - - ldap:close() - - return groups -end - --- --- --- Wrapper around filter API, exposing the http table, the cgit table, and the post table to the above functions. --- --- - -local actions = {} -actions["authenticate-post"] = authenticate_post -actions["authenticate-cookie"] = authenticate_cookie -actions["body"] = body - -function filter_open(...) - action = actions[select(1, ...)] - - http = {} - http["cookie"] = select(2, ...) - http["method"] = select(3, ...) - http["query"] = select(4, ...) - http["referer"] = select(5, ...) - http["path"] = select(6, ...) - http["host"] = select(7, ...) - http["https"] = select(8, ...) - - cgit = {} - cgit["repo"] = select(9, ...) - cgit["page"] = select(10, ...) - cgit["url"] = select(11, ...) - cgit["login"] = select(12, ...) - -end - -function filter_close() - return action() -end - -function filter_write(str) - post = parse_qs(str) -end - - --- --- --- Utility functions based on keplerproject/wsapi. --- --- - -function url_decode(str) - if not str then - return "" - end - str = string.gsub(str, "+", " ") - str = string.gsub(str, "%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end) - str = string.gsub(str, "\r\n", "\n") - return str -end - -function url_encode(str) - if not str then - return "" - end - str = string.gsub(str, "\n", "\r\n") - str = string.gsub(str, "([^%w ])", function(c) return string.format("%%%02X", string.byte(c)) end) - str = string.gsub(str, " ", "+") - return str -end - -function parse_qs(qs) - local tab = {} - for key, val in string.gmatch(qs, "([^&=]+)=([^&=]*)&?") do - tab[url_decode(key)] = url_decode(val) - end - return tab -end - -function get_cookie(cookies, name) - cookies = string.gsub(";" .. cookies .. ";", "%s*;%s*", ";") - return string.match(cookies, ";" .. name .. "=(.-);") -end - -function tohex(b) - local x = "" - for i = 1, #b do - x = x .. string.format("%.2x", string.byte(b, i)) - end - return x -end - --- --- --- Cookie construction and validation helpers. --- --- - -local secret = nil - --- Loads a secret from a file, creates a secret, or returns one from memory. -function get_secret() - if secret ~= nil then - return secret - end - local secret_file = io.open(secret_filename, "r") - if secret_file == nil then - local old_umask = sysstat.umask(63) - local temporary_filename = secret_filename .. ".tmp." .. tohex(rand.bytes(16)) - local temporary_file = io.open(temporary_filename, "w") - if temporary_file == nil then - os.exit(177) - end - temporary_file:write(tohex(rand.bytes(32))) - temporary_file:close() - unistd.link(temporary_filename, secret_filename) -- Intentionally fails in the case that another process is doing the same. - unistd.unlink(temporary_filename) - sysstat.umask(old_umask) - secret_file = io.open(secret_filename, "r") - end - if secret_file == nil then - os.exit(177) - end - secret = secret_file:read() - secret_file:close() - if secret:len() ~= 64 then - os.exit(177) - end - return secret -end - --- Returns value of cookie if cookie is valid. Otherwise returns nil. -function validate_value(expected_field, cookie) - local i = 0 - local value = "" - local field = "" - local expiration = 0 - local salt = "" - local chmac = "" - - if cookie == nil or cookie:len() < 3 or cookie:sub(1, 1) == "|" then - return nil - end - - for component in string.gmatch(cookie, "[^|]+") do - if i == 0 then - field = component - elseif i == 1 then - value = component - elseif i == 2 then - expiration = tonumber(component) - if expiration == nil then - expiration = -1 - end - elseif i == 3 then - salt = component - elseif i == 4 then - chmac = component - else - break - end - i = i + 1 - end - - if chmac == nil or chmac:len() == 0 then - return nil - end - - -- Lua hashes strings, so these comparisons are time invariant. - if chmac ~= tohex(hmac.new(get_secret(), "sha256"):final(field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt)) then - return nil - end - - if expiration == -1 or (expiration ~= 0 and expiration <= os.time()) then - return nil - end - - if url_decode(field) ~= expected_field then - return nil - end - - return url_decode(value) -end - -function secure_value(field, value, expiration) - if value == nil or value:len() <= 0 then - return "" - end - - local authstr = "" - local salt = tohex(rand.bytes(16)) - value = url_encode(value) - field = url_encode(field) - authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt - authstr = authstr .. "|" .. tohex(hmac.new(get_secret(), "sha256"):final(authstr)) - return authstr -end - -function set_cookie(cookie, value) - html("Set-Cookie: " .. cookie .. "=" .. value .. "; HttpOnly") - if http["https"] == "yes" or http["https"] == "on" or http["https"] == "1" then - html("; secure") - end - html("\n") -end - -function redirect_to(url) - html("Status: 302 Redirect\n") - html("Cache-Control: no-cache, no-store\n") - html("Location: " .. url .. "\n") -end - -function not_found() - html("Status: 404 Not Found\n") - html("Cache-Control: no-cache, no-store\n\n") -end diff --git a/third_party/cgit/filters/owner-example.lua b/third_party/cgit/filters/owner-example.lua deleted file mode 100644 index 50fc25a8e5..0000000000 --- a/third_party/cgit/filters/owner-example.lua +++ /dev/null @@ -1,17 +0,0 @@ --- This script is an example of an owner-filter. It replaces the --- usual query link with one to a fictional homepage. This script may --- be used with the owner-filter or repo.owner-filter settings in --- cgitrc with the `lua:` prefix. - -function filter_open() - buffer = "" -end - -function filter_close() - html(string.format("<a href=\"%s\">%s</a>", "http://wiki.example.com/about/" .. buffer, buffer)) - return 0 -end - -function filter_write(str) - buffer = buffer .. str -end diff --git a/third_party/cgit/filters/simple-authentication.lua b/third_party/cgit/filters/simple-authentication.lua deleted file mode 100644 index 23d345763b..0000000000 --- a/third_party/cgit/filters/simple-authentication.lua +++ /dev/null @@ -1,314 +0,0 @@ --- This script may be used with the auth-filter. Be sure to configure it as you wish. --- --- Requirements: --- luaossl --- <http://25thandclement.com/~william/projects/luaossl.html> --- luaposix --- <https://github.com/luaposix/luaposix> --- -local sysstat = require("posix.sys.stat") -local unistd = require("posix.unistd") -local rand = require("openssl.rand") -local hmac = require("openssl.hmac") - --- --- --- Configure these variables for your settings. --- --- - --- A list of password protected repositories along with the users who can access them. -local protected_repos = { - glouglou = { laurent = true, jason = true }, - qt = { jason = true, bob = true } -} - --- A list of users and hashes, generated with `mkpasswd -m sha-512 -R 300000`. -local users = { - jason = "$6$rounds=300000$YYJct3n/o.ruYK$HhpSeuCuW1fJkpvMZOZzVizeLsBKcGA/aF2UPuV5v60JyH2MVSG6P511UMTj2F3H75.IT2HIlnvXzNb60FcZH1", - laurent = "$6$rounds=300000$dP0KNHwYb3JKigT$pN/LG7rWxQ4HniFtx5wKyJXBJUKP7R01zTNZ0qSK/aivw8ywGAOdfYiIQFqFhZFtVGvr11/7an.nesvm8iJUi.", - bob = "$6$rounds=300000$jCLCCt6LUpTz$PI1vvd1yaVYcCzqH8QAJFcJ60b6W/6sjcOsU7mAkNo7IE8FRGW1vkjF8I/T5jt/auv5ODLb1L4S2s.CAyZyUC" -} - --- Set this to a path this script can write to for storing a persistent --- cookie secret, which should be guarded. -local secret_filename = "/var/cache/cgit/auth-secret" - --- --- --- Authentication functions follow below. Swap these out if you want different authentication semantics. --- --- - --- Sets HTTP cookie headers based on post and sets up redirection. -function authenticate_post() - local hash = users[post["username"]] - local redirect = validate_value("redirect", post["redirect"]) - - if redirect == nil then - not_found() - return 0 - end - - redirect_to(redirect) - - if hash == nil or hash ~= unistd.crypt(post["password"], hash) then - set_cookie("cgitauth", "") - else - -- One week expiration time - local username = secure_value("username", post["username"], os.time() + 604800) - set_cookie("cgitauth", username) - end - - html("\n") - return 0 -end - - --- Returns 1 if the cookie is valid and 0 if it is not. -function authenticate_cookie() - accepted_users = protected_repos[cgit["repo"]] - if accepted_users == nil then - -- We return as valid if the repo is not protected. - return 1 - end - - local username = validate_value("username", get_cookie(http["cookie"], "cgitauth")) - if username == nil or not accepted_users[username:lower()] then - return 0 - else - return 1 - end -end - --- Prints the html for the login form. -function body() - html("<h2>Authentication Required</h2>") - html("<form method='post' action='") - html_attr(cgit["login"]) - html("'>") - html("<input type='hidden' name='redirect' value='") - html_attr(secure_value("redirect", cgit["url"], 0)) - html("' />") - html("<table>") - html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autofocus /></td></tr>") - html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' /></td></tr>") - html("<tr><td colspan='2'><input value='Login' type='submit' /></td></tr>") - html("</table></form>") - - return 0 -end - - - --- --- --- Wrapper around filter API, exposing the http table, the cgit table, and the post table to the above functions. --- --- - -local actions = {} -actions["authenticate-post"] = authenticate_post -actions["authenticate-cookie"] = authenticate_cookie -actions["body"] = body - -function filter_open(...) - action = actions[select(1, ...)] - - http = {} - http["cookie"] = select(2, ...) - http["method"] = select(3, ...) - http["query"] = select(4, ...) - http["referer"] = select(5, ...) - http["path"] = select(6, ...) - http["host"] = select(7, ...) - http["https"] = select(8, ...) - - cgit = {} - cgit["repo"] = select(9, ...) - cgit["page"] = select(10, ...) - cgit["url"] = select(11, ...) - cgit["login"] = select(12, ...) - -end - -function filter_close() - return action() -end - -function filter_write(str) - post = parse_qs(str) -end - - --- --- --- Utility functions based on keplerproject/wsapi. --- --- - -function url_decode(str) - if not str then - return "" - end - str = string.gsub(str, "+", " ") - str = string.gsub(str, "%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end) - str = string.gsub(str, "\r\n", "\n") - return str -end - -function url_encode(str) - if not str then - return "" - end - str = string.gsub(str, "\n", "\r\n") - str = string.gsub(str, "([^%w ])", function(c) return string.format("%%%02X", string.byte(c)) end) - str = string.gsub(str, " ", "+") - return str -end - -function parse_qs(qs) - local tab = {} - for key, val in string.gmatch(qs, "([^&=]+)=([^&=]*)&?") do - tab[url_decode(key)] = url_decode(val) - end - return tab -end - -function get_cookie(cookies, name) - cookies = string.gsub(";" .. cookies .. ";", "%s*;%s*", ";") - return url_decode(string.match(cookies, ";" .. name .. "=(.-);")) -end - -function tohex(b) - local x = "" - for i = 1, #b do - x = x .. string.format("%.2x", string.byte(b, i)) - end - return x -end - --- --- --- Cookie construction and validation helpers. --- --- - -local secret = nil - --- Loads a secret from a file, creates a secret, or returns one from memory. -function get_secret() - if secret ~= nil then - return secret - end - local secret_file = io.open(secret_filename, "r") - if secret_file == nil then - local old_umask = sysstat.umask(63) - local temporary_filename = secret_filename .. ".tmp." .. tohex(rand.bytes(16)) - local temporary_file = io.open(temporary_filename, "w") - if temporary_file == nil then - os.exit(177) - end - temporary_file:write(tohex(rand.bytes(32))) - temporary_file:close() - unistd.link(temporary_filename, secret_filename) -- Intentionally fails in the case that another process is doing the same. - unistd.unlink(temporary_filename) - sysstat.umask(old_umask) - secret_file = io.open(secret_filename, "r") - end - if secret_file == nil then - os.exit(177) - end - secret = secret_file:read() - secret_file:close() - if secret:len() ~= 64 then - os.exit(177) - end - return secret -end - --- Returns value of cookie if cookie is valid. Otherwise returns nil. -function validate_value(expected_field, cookie) - local i = 0 - local value = "" - local field = "" - local expiration = 0 - local salt = "" - local chmac = "" - - if cookie == nil or cookie:len() < 3 or cookie:sub(1, 1) == "|" then - return nil - end - - for component in string.gmatch(cookie, "[^|]+") do - if i == 0 then - field = component - elseif i == 1 then - value = component - elseif i == 2 then - expiration = tonumber(component) - if expiration == nil then - expiration = -1 - end - elseif i == 3 then - salt = component - elseif i == 4 then - chmac = component - else - break - end - i = i + 1 - end - - if chmac == nil or chmac:len() == 0 then - return nil - end - - -- Lua hashes strings, so these comparisons are time invariant. - if chmac ~= tohex(hmac.new(get_secret(), "sha256"):final(field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt)) then - return nil - end - - if expiration == -1 or (expiration ~= 0 and expiration <= os.time()) then - return nil - end - - if url_decode(field) ~= expected_field then - return nil - end - - return url_decode(value) -end - -function secure_value(field, value, expiration) - if value == nil or value:len() <= 0 then - return "" - end - - local authstr = "" - local salt = tohex(rand.bytes(16)) - value = url_encode(value) - field = url_encode(field) - authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt - authstr = authstr .. "|" .. tohex(hmac.new(get_secret(), "sha256"):final(authstr)) - return authstr -end - -function set_cookie(cookie, value) - html("Set-Cookie: " .. cookie .. "=" .. value .. "; HttpOnly") - if http["https"] == "yes" or http["https"] == "on" or http["https"] == "1" then - html("; secure") - end - html("\n") -end - -function redirect_to(url) - html("Status: 302 Redirect\n") - html("Cache-Control: no-cache, no-store\n") - html("Location: " .. url .. "\n") -end - -function not_found() - html("Status: 404 Not Found\n") - html("Cache-Control: no-cache, no-store\n\n") -end diff --git a/third_party/cgit/html.c b/third_party/cgit/html.c index 7f81965fdd..ced781adc6 100644 --- a/third_party/cgit/html.c +++ b/third_party/cgit/html.c @@ -59,7 +59,7 @@ char *fmt(const char *format, ...) va_start(args, format); len = vsnprintf(buf[bufidx], sizeof(buf[bufidx]), format, args); va_end(args); - if (len > sizeof(buf[bufidx])) { + if (len >= sizeof(buf[bufidx])) { fprintf(stderr, "[html.c] string truncated: %s\n", format); exit(1); } @@ -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/third_party/cgit/parsing.c b/third_party/cgit/parsing.c index e093aaf701..83d3521e89 100644 --- a/third_party/cgit/parsing.c +++ b/third_party/cgit/parsing.c @@ -198,7 +198,7 @@ struct taginfo *cgit_parse_tag(struct tag *tag) const char *p; struct taginfo *ret = NULL; - data = read_object_file(&tag->object.oid, &type, &size); + data = repo_read_object_file(the_repository, &tag->object.oid, &type, &size); if (!data || type != OBJ_TAG) goto cleanup; diff --git a/third_party/cgit/robots.txt b/third_party/cgit/robots.txt index 4ce948fec2..1b33266d53 100644 --- a/third_party/cgit/robots.txt +++ b/third_party/cgit/robots.txt @@ -1,3 +1,4 @@ User-agent: * Disallow: /*/snapshot/* +Disallow: /*/blame/* Allow: / diff --git a/third_party/cgit/scan-tree.c b/third_party/cgit/scan-tree.c index 6a2f65a86b..aa93665426 100644 --- a/third_party/cgit/scan-tree.c +++ b/third_party/cgit/scan-tree.c @@ -54,7 +54,7 @@ static void scan_tree_repo_config(const char *name, const char *value) config_fn(repo, name, value); } -static int gitconfig_config(const char *key, const char *value, void *cb) +static int gitconfig_config(const char *key, const char *value, const struct config_context *, void *cb) { const char *name; @@ -137,8 +137,6 @@ static void add_repo(const char *base, struct strbuf *path, repo_config_fn fn) repo->path = xstrdup(path->buf); while (!repo->owner) { if ((pwd = getpwuid(st.st_uid)) == NULL) { - fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n", - path->buf, strerror(errno), errno); break; } if (pwd->pw_gecos) diff --git a/third_party/cgit/shared.c b/third_party/cgit/shared.c index 8115469a7c..26b6ddb329 100644 --- a/third_party/cgit/shared.c +++ b/third_party/cgit/shared.c @@ -241,7 +241,7 @@ static int load_mmfile(mmfile_t *file, const struct object_id *oid) file->ptr = (char *)""; file->size = 0; } else { - file->ptr = read_object_file(oid, &type, + file->ptr = repo_read_object_file(the_repository, oid, &type, (unsigned long *)&file->size); } return 1; @@ -341,10 +341,9 @@ void cgit_diff_tree(const struct object_id *old_oid, filepair_fn fn, const char *prefix, int ignorews) { struct diff_options opt; - struct pathspec_item item; + struct pathspec_item *item; - memset(&item, 0, sizeof(item)); - diff_setup(&opt); + repo_diff_setup(the_repository, &opt); opt.output_format = DIFF_FORMAT_CALLBACK; opt.detect_rename = 1; opt.rename_limit = ctx.cfg.renamelimit; @@ -354,10 +353,11 @@ void cgit_diff_tree(const struct object_id *old_oid, opt.format_callback = cgit_diff_tree_cb; opt.format_callback_data = fn; if (prefix) { - item.match = xstrdup(prefix); - item.len = strlen(prefix); + item = xcalloc(1, sizeof(*item)); + item->match = xstrdup(prefix); + item->len = strlen(prefix); opt.pathspec.nr = 1; - opt.pathspec.items = &item; + opt.pathspec.items = item; } diff_setup_done(&opt); @@ -367,8 +367,6 @@ void cgit_diff_tree(const struct object_id *old_oid, diff_root_tree_oid(new_oid, "", &opt); diffcore_std(&opt); diff_flush(&opt); - - free(item.match); } void cgit_diff_commit(struct commit *commit, filepair_fn fn, const char *prefix) @@ -541,7 +539,9 @@ char *expand_macros(const char *txt) char *get_mimetype_for_filename(const char *filename) { - char *ext, *mimetype, *token, line[1024], *saveptr; + char *ext, *mimetype, line[1024]; + struct string_list list = STRING_LIST_INIT_NODUP; + int i; FILE *file; struct string_list_item *mime; @@ -566,13 +566,16 @@ char *get_mimetype_for_filename(const char *filename) while (fgets(line, sizeof(line), file)) { if (!line[0] || line[0] == '#') continue; - mimetype = strtok_r(line, " \t\r\n", &saveptr); - while ((token = strtok_r(NULL, " \t\r\n", &saveptr))) { - if (!strcasecmp(ext, token)) { + string_list_split_in_place(&list, line, " \t\r\n", -1); + string_list_remove_empty_items(&list, 0); + mimetype = list.items[0].string; + for (i = 1; i < list.nr; i++) { + if (!strcasecmp(ext, list.items[i].string)) { fclose(file); return xstrdup(mimetype); } } + string_list_clear(&list, 0); } fclose(file); return NULL; diff --git a/third_party/cgit/tests/filters/dump.lua b/third_party/cgit/tests/filters/dump.lua deleted file mode 100644 index 1f15c93105..0000000000 --- a/third_party/cgit/tests/filters/dump.lua +++ /dev/null @@ -1,17 +0,0 @@ -function filter_open(...) - buffer = "" - for i = 1, select("#", ...) do - buffer = buffer .. select(i, ...) .. " " - end -end - -function filter_close() - html(buffer) - return 0 -end - -function filter_write(str) - buffer = buffer .. string.upper(str) -end - - diff --git a/third_party/cgit/tests/setup.sh b/third_party/cgit/tests/setup.sh index 8db810ff11..31e7d5bb27 100755 --- a/third_party/cgit/tests/setup.sh +++ b/third_party/cgit/tests/setup.sh @@ -60,12 +60,6 @@ fi FILTER_DIRECTORY=$(cd ../filters && pwd) -if cgit --version | grep -F -q "[+] Lua scripting"; then - export CGIT_HAS_LUA=1 -else - export CGIT_HAS_LUA=0 -fi - mkrepo() { name=$1 count=$2 @@ -144,19 +138,6 @@ repo.email-filter=exec:$FILTER_DIRECTORY/dump.sh repo.source-filter=exec:$FILTER_DIRECTORY/dump.sh repo.readme=master:a+b EOF - - if [ $CGIT_HAS_LUA -eq 1 ]; then - cat >>cgitrc <<EOF -repo.url=filter-lua -repo.path=$PWD/repos/filter/.git -repo.desc=filtered repo -repo.about-filter=lua:$FILTER_DIRECTORY/dump.lua -repo.commit-filter=lua:$FILTER_DIRECTORY/dump.lua -repo.email-filter=lua:$FILTER_DIRECTORY/dump.lua -repo.source-filter=lua:$FILTER_DIRECTORY/dump.lua -repo.readme=master:a+b -EOF - fi } cgit_query() diff --git a/third_party/cgit/tests/t0105-commit.sh b/third_party/cgit/tests/t0105-commit.sh index 1a12ee39a9..cfed1e7d69 100755 --- a/third_party/cgit/tests/t0105-commit.sh +++ b/third_party/cgit/tests/t0105-commit.sh @@ -11,7 +11,7 @@ test_expect_success 'find commit subject' ' grep "<div class=.commit-subject.>commit 5<" tmp ' -test_expect_success 'find commit msg' 'grep "<div class=.commit-msg.></div>" tmp' +test_expect_success 'find commit msg' 'grep "<pre class=.commit-msg.></pre>" tmp' test_expect_success 'find diffstat' 'grep "<table summary=.diffstat. class=.diffstat.>" tmp' test_expect_success 'find diff summary' ' @@ -29,8 +29,8 @@ test_expect_success 'root commit contains diffstat' ' ' test_expect_success 'root commit contains diff' ' - grep ">diff --git a/file-1 b/file-1<" tmp && - grep "<div class=.add.>+1</div>" tmp + grep ">diff --git a/file-1 b/file-1" tmp && + grep "<span class=.add.>+1</span>" tmp ' test_done diff --git a/third_party/cgit/tests/t0106-diff.sh b/third_party/cgit/tests/t0106-diff.sh index 82b645ec72..62a0a74a64 100755 --- a/third_party/cgit/tests/t0106-diff.sh +++ b/third_party/cgit/tests/t0106-diff.sh @@ -9,11 +9,11 @@ test_expect_success 'find blob link' 'grep "<a href=./foo/tree/file-5?id=" tmp' test_expect_success 'find added file' 'grep "new file mode 100644" tmp' test_expect_success 'find hunk header' ' - grep "<div class=.hunk.>@@ -0,0 +1 @@</div>" tmp + grep "<span class=.hunk.>@@ -0,0 +1 @@</span>" tmp ' test_expect_success 'find added line' ' - grep "<div class=.add.>+5</div>" tmp + grep "<span class=.add.>+5</span>" tmp ' test_done diff --git a/third_party/cgit/tests/t0111-filter.sh b/third_party/cgit/tests/t0111-filter.sh index 2fdc3669f4..e5d357507c 100755 --- a/third_party/cgit/tests/t0111-filter.sh +++ b/third_party/cgit/tests/t0111-filter.sh @@ -4,9 +4,6 @@ test_description='Check filtered content' . ./setup.sh prefixes="exec" -if [ $CGIT_HAS_LUA -eq 1 ]; then - prefixes="$prefixes lua" -fi for prefix in $prefixes do diff --git a/third_party/cgit/ui-atom.c b/third_party/cgit/ui-atom.c index 1056f36397..fefbc79809 100644 --- a/third_party/cgit/ui-atom.c +++ b/third_party/cgit/ui-atom.c @@ -67,17 +67,12 @@ static void add_entry(struct commit *commit, const char *host) html("'/>\n"); free(pageurl); } - htmlf("<id>%s</id>\n", hex); + html("<id>"); + html_txtf("urn:%s:%s", the_hash_algo->name, hex); + html("</id>\n"); html("<content type='text'>\n"); html_txt(info->msg); html("</content>\n"); - html("<content type='xhtml'>\n"); - html("<div xmlns='http://www.w3.org/1999/xhtml'>\n"); - html("<pre>\n"); - html_txt(info->msg); - html("</pre>\n"); - html("</div>\n"); - html("</content>\n"); html("</entry>\n"); cgit_free_commitinfo(info); } @@ -90,6 +85,7 @@ void cgit_print_atom(char *tip, const char *path, int max_count) struct commit *commit; struct rev_info rev; int argc = 2; + int first = 1; if (ctx.qry.show_all) argv[1] = "--all"; @@ -101,7 +97,7 @@ void cgit_print_atom(char *tip, const char *path, int max_count) argv[argc++] = path; } - init_revisions(&rev, NULL); + repo_init_revisions(the_repository, &rev, NULL); rev.abbrev = DEFAULT_ABBREV; rev.commit_format = CMIT_FMT_DEFAULT; rev.verbose_header = 1; @@ -130,18 +126,30 @@ void cgit_print_atom(char *tip, const char *path, int max_count) html_txt(ctx.repo->desc); html("</subtitle>\n"); if (host) { + char *fullurl = cgit_currentfullurl(); char *repourl = cgit_repourl(ctx.repo->url); + html("<id>"); + html_txtf("%s%s%s", cgit_httpscheme(), host, fullurl); + html("</id>\n"); + html("<link rel='self' href='"); + html_attrf("%s%s%s", cgit_httpscheme(), host, fullurl); + html("'/>\n"); html("<link rel='alternate' type='text/html' href='"); - html(cgit_httpscheme()); - html_attr(host); - html_attr(repourl); + html_attrf("%s%s%s", cgit_httpscheme(), host, repourl); html("'/>\n"); + free(fullurl); free(repourl); } while ((commit = get_revision(&rev)) != NULL) { + if (first) { + html("<updated>"); + html_txt(show_date(commit->date, 0, + date_mode_from_type(DATE_ISO8601_STRICT))); + html("</updated>\n"); + first = 0; + } add_entry(commit, host); - free_commit_buffer(the_repository->parsed_objects, commit); - free_commit_list(commit->parents); + release_commit_memory(the_repository->parsed_objects, commit); commit->parents = NULL; } html("</feed>\n"); diff --git a/third_party/cgit/ui-blame.c b/third_party/cgit/ui-blame.c index 786a7105d5..6418b24221 100644 --- a/third_party/cgit/ui-blame.c +++ b/third_party/cgit/ui-blame.c @@ -49,11 +49,20 @@ static void emit_blame_entry_hash(struct blame_entry *ent) char *detail = emit_suspect_detail(suspect); html("<span class='oid'>"); - cgit_commit_link(find_unique_abbrev(oid, DEFAULT_ABBREV), detail, + cgit_commit_link(repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV), detail, NULL, ctx.qry.head, oid_to_hex(oid), suspect->path); html("</span>"); free(detail); + if (!repo_parse_commit(the_repository, suspect->commit) && suspect->commit->parents) { + struct commit *parent = suspect->commit->parents->item; + + html(" "); + cgit_blame_link("^", "Blame the previous revision", NULL, + ctx.qry.head, oid_to_hex(&parent->object.oid), + suspect->path); + } + while (line++ < ent->num_lines) html("\n"); } @@ -117,7 +126,7 @@ static void print_object(const struct object_id *oid, const char *path, return; } - buf = read_object_file(oid, &type, &size); + buf = repo_read_object_file(the_repository, oid, &type, &size); if (!buf) { cgit_print_error_page(500, "Internal server error", "Error reading object %s", oid_to_hex(oid)); @@ -126,7 +135,7 @@ static void print_object(const struct object_id *oid, const char *path, strvec_push(&rev_argv, "blame"); strvec_push(&rev_argv, rev); - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); revs.diffopt.flags.allow_textconv = 1; setup_revisions(rev_argv.nr, rev_argv.v, &revs, NULL); init_scoreboard(&sb); @@ -278,13 +287,13 @@ void cgit_print_blame(void) if (!rev) rev = ctx.qry.head; - if (get_oid(rev, &oid)) { + if (repo_get_oid(the_repository, rev, &oid)) { cgit_print_error_page(404, "Not found", "Invalid revision name: %s", rev); return; } commit = lookup_commit_reference(the_repository, &oid); - if (!commit || parse_commit(commit)) { + if (!commit || repo_parse_commit(the_repository, commit)) { cgit_print_error_page(404, "Not found", "Invalid commit reference: %s", rev); return; diff --git a/third_party/cgit/ui-blob.c b/third_party/cgit/ui-blob.c index c10ae42ebd..08f94ee97e 100644 --- a/third_party/cgit/ui-blob.c +++ b/third_party/cgit/ui-blob.c @@ -52,7 +52,7 @@ int cgit_ref_path_exists(const char *path, const char *ref, int file_only) .file_only = file_only }; - if (get_oid(ref, &oid)) + if (repo_get_oid(the_repository, ref, &oid)) goto done; if (oid_object_info(the_repository, &oid, &size) != OBJ_COMMIT) goto done; @@ -87,7 +87,7 @@ int cgit_print_file(char *path, const char *head, int file_only) .file_only = file_only }; - if (get_oid(head, &oid)) + if (repo_get_oid(the_repository, head, &oid)) return -1; type = oid_object_info(the_repository, &oid, &size); if (type == OBJ_COMMIT) { @@ -100,7 +100,7 @@ int cgit_print_file(char *path, const char *head, int file_only) } if (type == OBJ_BAD) return -1; - buf = read_object_file(&oid, &type, &size); + buf = repo_read_object_file(the_repository, &oid, &type, &size); if (!buf) return -1; buf[size] = '\0'; @@ -138,7 +138,7 @@ void cgit_print_blob(const char *hex, char *path, const char *head, int file_onl return; } } else { - if (get_oid(head, &oid)) { + if (repo_get_oid(the_repository, head, &oid)) { cgit_print_error_page(404, "Not found", "Bad ref: %s", head); return; @@ -160,7 +160,7 @@ void cgit_print_blob(const char *hex, char *path, const char *head, int file_onl return; } - buf = read_object_file(&oid, &type, &size); + buf = repo_read_object_file(the_repository, &oid, &type, &size); if (!buf) { cgit_print_error_page(500, "Internal server error", "Error reading object %s", hex); diff --git a/third_party/cgit/ui-commit.c b/third_party/cgit/ui-commit.c index 96eecebe19..6517e50cc6 100644 --- a/third_party/cgit/ui-commit.c +++ b/third_party/cgit/ui-commit.c @@ -26,7 +26,7 @@ void cgit_print_commit(char *hex, const char *prefix) if (!hex) hex = ctx.qry.head; - if (get_oid(hex, &oid)) { + if (repo_get_oid(the_repository, hex, &oid)) { cgit_print_error_page(400, "Bad request", "Bad object id: %s", hex); return; @@ -39,7 +39,7 @@ void cgit_print_commit(char *hex, const char *prefix) } info = cgit_parse_commit(commit); - format_display_notes(&oid, ¬es, PAGE_ENCODING, 0); + format_display_notes(&oid, ¬es, PAGE_ENCODING, 1); load_ref_decorations(NULL, DECORATE_FULL_REFS); @@ -121,11 +121,11 @@ void cgit_print_commit(char *hex, const char *prefix) cgit_close_filter(ctx.repo->commit_filter); show_commit_decorations(commit); html("</div>"); - html("<div class='commit-msg'>"); + html("<pre class='commit-msg'>"); cgit_open_filter(ctx.repo->commit_filter); html_txt(info->msg); cgit_close_filter(ctx.repo->commit_filter); - html("</div>"); + html("</pre>"); if (notes.len != 0) { html("<div class='notes-header'>Notes</div>"); html("<div class='notes'>"); diff --git a/third_party/cgit/ui-diff.c b/third_party/cgit/ui-diff.c index 5ed5990c29..a82313fc64 100644 --- a/third_party/cgit/ui-diff.c +++ b/third_party/cgit/ui-diff.c @@ -231,11 +231,11 @@ static void print_line(char *line, int len) else if (line[0] == '@') class = "hunk"; - htmlf("<div class='%s'>", class); + htmlf("<span class='%s'>", class); line[len-1] = '\0'; html_txt(line); - html("</div>"); line[len-1] = c; + html("</span>\n"); } static void header(const struct object_id *oid1, char *path1, int mode1, @@ -245,22 +245,23 @@ static void header(const struct object_id *oid1, char *path1, int mode1, int subproject; subproject = (S_ISGITLINK(mode1) || S_ISGITLINK(mode2)); - html("<div class='head'>"); + html("<span class='head'>"); html("diff --git a/"); html_txt(path1); html(" b/"); html_txt(path2); + html("\n"); if (mode1 == 0) - htmlf("<br/>new file mode %.6o", mode2); + htmlf("new file mode %.6o\n", mode2); if (mode2 == 0) - htmlf("<br/>deleted file mode %.6o", mode1); + htmlf("deleted file mode %.6o\n", mode1); if (!subproject) { - abbrev1 = xstrdup(find_unique_abbrev(oid1, DEFAULT_ABBREV)); - abbrev2 = xstrdup(find_unique_abbrev(oid2, DEFAULT_ABBREV)); - htmlf("<br/>index %s..%s", abbrev1, abbrev2); + abbrev1 = xstrdup(repo_find_unique_abbrev(the_repository, oid1, DEFAULT_ABBREV)); + abbrev2 = xstrdup(repo_find_unique_abbrev(the_repository, oid2, DEFAULT_ABBREV)); + htmlf("index %s..%s", abbrev1, abbrev2); free(abbrev1); free(abbrev2); if (mode1 != 0 && mode2 != 0) { @@ -268,28 +269,31 @@ static void header(const struct object_id *oid1, char *path1, int mode1, if (mode2 != mode1) htmlf("..%.6o", mode2); } + html("\n"); if (is_null_oid(oid1)) { path1 = "dev/null"; - html("<br/>--- /"); + html("--- /"); } else - html("<br/>--- a/"); + html("--- a/"); if (mode1 != 0) cgit_tree_link(path1, NULL, NULL, ctx.qry.head, oid_to_hex(old_rev_oid), path1); else html_txt(path1); + html("\n"); if (is_null_oid(oid2)) { path2 = "dev/null"; - html("<br/>+++ /"); + html("+++ /"); } else - html("<br/>+++ b/"); + html("+++ b/"); if (mode2 != 0) cgit_tree_link(path2, NULL, NULL, ctx.qry.head, oid_to_hex(new_rev_oid), path2); else html_txt(path2); + html("\n"); } - html("</div>"); + html("</span>"); } static void filepair_cb(struct diff_filepair *pair) @@ -402,13 +406,13 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, if (!new_rev) new_rev = ctx.qry.head; - if (get_oid(new_rev, new_rev_oid)) { + if (repo_get_oid(the_repository, new_rev, new_rev_oid)) { cgit_print_error_page(404, "Not found", "Bad object name: %s", new_rev); return; } commit = lookup_commit_reference(the_repository, new_rev_oid); - if (!commit || parse_commit(commit)) { + if (!commit || repo_parse_commit(the_repository, commit)) { cgit_print_error_page(404, "Not found", "Bad commit: %s", oid_to_hex(new_rev_oid)); return; @@ -416,7 +420,7 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, new_tree_oid = get_commit_tree_oid(commit); if (old_rev) { - if (get_oid(old_rev, old_rev_oid)) { + if (repo_get_oid(the_repository, old_rev, old_rev_oid)) { cgit_print_error_page(404, "Not found", "Bad object name: %s", old_rev); return; @@ -429,7 +433,7 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, if (!is_null_oid(old_rev_oid)) { commit2 = lookup_commit_reference(the_repository, old_rev_oid); - if (!commit2 || parse_commit(commit2)) { + if (!commit2 || repo_parse_commit(the_repository, commit2)) { cgit_print_error_page(404, "Not found", "Bad commit: %s", oid_to_hex(old_rev_oid)); return; @@ -442,7 +446,7 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, if (raw) { struct diff_options diffopt; - diff_setup(&diffopt); + repo_diff_setup(the_repository, &diffopt); diffopt.output_format = DIFF_FORMAT_PATCH; diffopt.flags.recursive = 1; diff_setup_done(&diffopt); @@ -488,12 +492,12 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, html("<table summary='ssdiff' class='ssdiff'>"); } else { html("<table summary='diff' class='diff'>"); - html("<tr><td>"); + html("<tr><td><pre>"); } cgit_diff_tree(old_rev_oid, new_rev_oid, filepair_cb, prefix, ctx.qry.ignorews); if (!use_ssdiff) - html("</td></tr>"); + html("</pre></td></tr>"); html("</table>"); if (show_ctrls) diff --git a/third_party/cgit/ui-log.c b/third_party/cgit/ui-log.c index 20774bf82f..358cdec4e7 100644 --- a/third_party/cgit/ui-log.c +++ b/third_party/cgit/ui-log.c @@ -71,15 +71,27 @@ void show_commit_decorations(struct commit *commit) strlcpy(buf, prettify_refname(deco->name), sizeof(buf)); switch(deco->type) { case DECORATION_NONE: + /* If it is a depot revision, display it, otherwise + * ... */ + if (strncmp("refs/r/", buf, 7) == 0) { + html(" "); + cgit_log_link(/* trim 'refs/' */ buf + 5, + NULL, "rev-deco", buf, NULL, + ctx.qry.vpath, 0, NULL, NULL, + ctx.qry.showmsg, 0); + } + /* If the git-core doesn't recognize it, * 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 (!read_ref(deco->name, &oid_tag) && !peel_iterated_oid(&oid_tag, &peeled)) is_annotated = !oideq(&oid_tag, &peeled); cgit_tag_link(buf, NULL, is_annotated ? "tag-annotated-deco" : "tag-deco", buf); @@ -87,12 +99,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); @@ -146,7 +160,7 @@ static int show_commit(struct commit *commit, struct rev_info *revs) /* When we get here we have precisely one parent. */ parent = parents->item; /* If we can't parse the commit, let print_commit() report an error. */ - if (parse_commit(parent)) + if (repo_parse_commit(the_repository, parent)) return 1; files = 0; @@ -159,7 +173,7 @@ static int show_commit(struct commit *commit, struct rev_info *revs) "", &revs->diffopt); diffcore_std(&revs->diffopt); - found = !diff_queue_is_empty(); + found = !diff_queue_is_empty(&revs->diffopt); saved_fmt = revs->diffopt.output_format; revs->diffopt.output_format = DIFF_FORMAT_CALLBACK; revs->diffopt.format_callback = cgit_diff_tree_cb; @@ -238,9 +252,10 @@ static void print_commit(struct commit *commit, struct rev_info *revs) strlcpy(info->subject + i, wrap_symbol, subject_len - i + 1); } } + show_commit_decorations(commit); + html(" "); cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, oid_to_hex(&commit->object.oid), ctx.qry.vpath); - show_commit_decorations(commit); html("</td><td>"); cgit_open_filter(ctx.repo->email_filter, info->author_email, "log"); html_txt(info->author); @@ -330,7 +345,7 @@ static const char *disambiguate_ref(const char *ref, int *must_free_result) struct strbuf longref = STRBUF_INIT; strbuf_addf(&longref, "refs/heads/%s", ref); - if (get_oid(longref.buf, &oid) == 0) { + if (repo_get_oid(the_repository, longref.buf, &oid) == 0) { *must_free_result = 1; return strbuf_detach(&longref, NULL); } @@ -430,7 +445,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern if (path) strvec_push(&rev_argv, path); - init_revisions(&rev, NULL); + repo_init_revisions(the_repository, &rev, NULL); rev.abbrev = DEFAULT_ABBREV; rev.commit_format = CMIT_FMT_DEFAULT; rev.verbose_header = 1; @@ -489,8 +504,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; /* nop */) { if (show_commit(commit, &rev)) i++; - free_commit_buffer(the_repository->parsed_objects, commit); - free_commit_list(commit->parents); + release_commit_memory(the_repository->parsed_objects, commit); commit->parents = NULL; } @@ -511,8 +525,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern i++; print_commit(commit, &rev); } - free_commit_buffer(the_repository->parsed_objects, commit); - free_commit_list(commit->parents); + release_commit_memory(the_repository->parsed_objects, commit); commit->parents = NULL; } if (pager) { diff --git a/third_party/cgit/ui-patch.c b/third_party/cgit/ui-patch.c index 4ac03cbef1..3819a8152a 100644 --- a/third_party/cgit/ui-patch.c +++ b/third_party/cgit/ui-patch.c @@ -31,7 +31,7 @@ void cgit_print_patch(const char *new_rev, const char *old_rev, if (!new_rev) new_rev = ctx.qry.head; - if (get_oid(new_rev, &new_rev_oid)) { + if (repo_get_oid(the_repository, new_rev, &new_rev_oid)) { cgit_print_error_page(404, "Not found", "Bad object id: %s", new_rev); return; @@ -44,7 +44,7 @@ void cgit_print_patch(const char *new_rev, const char *old_rev, } if (old_rev) { - if (get_oid(old_rev, &old_rev_oid)) { + if (repo_get_oid(the_repository, old_rev, &old_rev_oid)) { cgit_print_error_page(404, "Not found", "Bad object id: %s", old_rev); return; @@ -78,7 +78,7 @@ void cgit_print_patch(const char *new_rev, const char *old_rev, "%s%n%n%w(0)%b"; } - init_revisions(&rev, NULL); + repo_init_revisions(the_repository, &rev, NULL); rev.abbrev = DEFAULT_ABBREV; rev.verbose_header = 1; rev.diff = 1; diff --git a/third_party/cgit/ui-plain.c b/third_party/cgit/ui-plain.c index 65a205fad7..a66c5a1de0 100644 --- a/third_party/cgit/ui-plain.c +++ b/third_party/cgit/ui-plain.c @@ -28,7 +28,7 @@ static int print_object(const struct object_id *oid, const char *path) return 0; } - buf = read_object_file(oid, &type, &size); + buf = repo_read_object_file(the_repository, oid, &type, &size); if (!buf) { cgit_print_error_page(404, "Not found", "Not found"); return 0; @@ -181,12 +181,12 @@ void cgit_print_plain(void) if (!rev) rev = ctx.qry.head; - if (get_oid(rev, &oid)) { + if (repo_get_oid(the_repository, rev, &oid)) { cgit_print_error_page(404, "Not found", "Not found"); return; } commit = lookup_commit_reference(the_repository, &oid); - if (!commit || parse_commit(commit)) { + if (!commit || repo_parse_commit(the_repository, commit)) { cgit_print_error_page(404, "Not found", "Not found"); return; } diff --git a/third_party/cgit/ui-repolist.c b/third_party/cgit/ui-repolist.c index 529a2038ba..97b11c5f16 100644 --- a/third_party/cgit/ui-repolist.c +++ b/third_party/cgit/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, ctx.repo->name, NULL, NULL); + cgit_summary_link(ctx.repo->name, NULL, NULL, NULL); html("</td><td>"); repourl = cgit_repourl(ctx.repo->url); html_link_open(repourl, NULL, NULL); @@ -353,8 +353,10 @@ void cgit_print_repolist(void) if (ctx.cfg.enable_index_links) { html("<td>"); cgit_summary_link("summary", NULL, "button", NULL); + html(" "); cgit_log_link("log", NULL, "button", NULL, NULL, NULL, 0, NULL, NULL, ctx.qry.showmsg, 0); + html(" "); cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); html("</td>"); } diff --git a/third_party/cgit/ui-shared.c b/third_party/cgit/ui-shared.c index cf7907ffe3..d047f9a131 100644 --- a/third_party/cgit/ui-shared.c +++ b/third_party/cgit/ui-shared.c @@ -836,7 +836,7 @@ void cgit_print_docend(void) if (ctx.cfg.footer) html_include(ctx.cfg.footer); else { - htmlf("<div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit %s</a> " + htmlf("<div class='footer'>generated by <a href='https://git.causal.agency/cgit-pink/about/'>cgit-pink %s</a> " "(<a href='https://git-scm.com/'>git %s</a>) at ", cgit_version, git_version_string); html_txt(show_date(time(NULL), 0, cgit_date_mode(DATE_DOTTIME))); html("</div>\n"); @@ -898,7 +898,7 @@ void cgit_add_clone_urls(void (*fn)(const char *)) static int print_this_commit_option(void) { struct object_id oid; - if (get_oid(ctx.qry.head, &oid)) + if (!ctx.qry.head || repo_get_oid(the_repository, ctx.qry.head, &oid)) return 1; html_option(oid_to_hex(&oid), "this commit", ctx.qry.head); return 0; @@ -1003,7 +1003,7 @@ static void print_header(void) html("<td class='main'>"); if (ctx.repo) { - cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL); + cgit_summary_link(ctx.repo->name, NULL, NULL, NULL); if (ctx.env.authenticated) { html("</td><td class='form'>"); html("<form method='get'>\n"); @@ -1027,7 +1027,13 @@ static void print_header(void) if (ctx.repo) { html_txt(ctx.repo->desc); html("</td><td class='sub right'>"); - html_txt(ctx.repo->owner); + if (ctx.repo->owner_filter) { + cgit_open_filter(ctx.repo->owner_filter); + html_txt(ctx.repo->owner); + cgit_close_filter(ctx.repo->owner_filter); + } else { + html_txt(ctx.repo->owner); + } } else { if (ctx.cfg.root_desc) html_txt(ctx.cfg.root_desc); @@ -1046,29 +1052,37 @@ void cgit_print_pageheader(void) if (ctx.repo->readme.nr) { cgit_about_link("about", NULL, hc("about"), ctx.qry.head, ctx.qry.oid, ctx.qry.vpath); + html(" "); } cgit_summary_link("summary", NULL, hc("summary"), ctx.qry.head); + html(" "); cgit_refs_link("refs", NULL, hc("refs"), ctx.qry.head, ctx.qry.oid, NULL); + html(" "); cgit_log_link("log", NULL, hc("log"), ctx.qry.head, NULL, ctx.qry.vpath, 0, NULL, NULL, ctx.qry.showmsg, ctx.qry.follow); + html(" "); if (ctx.qry.page && !strcmp(ctx.qry.page, "blame")) cgit_blame_link("blame", NULL, hc("blame"), ctx.qry.head, ctx.qry.oid, ctx.qry.vpath); else cgit_tree_link("tree", NULL, hc("tree"), ctx.qry.head, - ctx.qry.oid, ctx.qry.vpath); + ctx.qry.oid, ctx.qry.vpath); + html(" "); cgit_commit_link("commit", NULL, hc("commit"), ctx.qry.head, ctx.qry.oid, ctx.qry.vpath); + html(" "); cgit_diff_link("diff", NULL, hc("diff"), ctx.qry.head, ctx.qry.oid, ctx.qry.oid2, ctx.qry.vpath); - if (ctx.repo->max_stats) + if (ctx.repo->max_stats) { + html(" "); cgit_stats_link("stats", NULL, hc("stats"), ctx.qry.head, ctx.qry.vpath); + } if (ctx.repo->homepage) { - html("<a href='"); + html(" <a href='"); html_attr(ctx.repo->homepage); html("'>homepage</a>"); } @@ -1153,11 +1167,11 @@ void cgit_compose_snapshot_prefix(struct strbuf *filename, const char *base, * name starts with {v,V}[0-9] and the prettify mapping is injective, * i.e. each stripped tag can be inverted without ambiguities. */ - if (get_oid(fmt("refs/tags/%s", ref), &oid) == 0 && + if (repo_get_oid(the_repository, fmt("refs/tags/%s", ref), &oid) == 0 && (ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1]) && - ((get_oid(fmt("refs/tags/%s", ref + 1), &oid) == 0) + - (get_oid(fmt("refs/tags/v%s", ref + 1), &oid) == 0) + - (get_oid(fmt("refs/tags/V%s", ref + 1), &oid) == 0) == 1)) + ((repo_get_oid(the_repository, fmt("refs/tags/%s", ref + 1), &oid) == 0) + + (repo_get_oid(the_repository, fmt("refs/tags/v%s", ref + 1), &oid) == 0) + + (repo_get_oid(the_repository, fmt("refs/tags/V%s", ref + 1), &oid) == 0) == 1)) ref++; strbuf_addf(filename, "%s-%s", base, ref); @@ -1212,9 +1226,12 @@ void cgit_set_title_from_path(const char *path) if (!path) return; - for (last_slash = path + strlen(path); (slash = memrchr(path, '/', last_slash - path)) != NULL; last_slash = slash) { + last_slash = path + strlen(path); + for (slash = last_slash; slash > path; --slash) { + if (*slash != '/') continue; strbuf_add(&sb, slash + 1, last_slash - slash - 1); strbuf_addstr(&sb, " \xc2\xab "); + last_slash = slash; } strbuf_add(&sb, path, last_slash - path); strbuf_addf(&sb, " - %s", ctx.page.title); diff --git a/third_party/cgit/ui-snapshot.c b/third_party/cgit/ui-snapshot.c index 18361a6553..992853bcd7 100644 --- a/third_party/cgit/ui-snapshot.c +++ b/third_party/cgit/ui-snapshot.c @@ -37,6 +37,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); @@ -117,7 +120,7 @@ const struct object_id *cgit_snapshot_get_sig(const char *ref, struct notes_tree *tree; struct object_id oid; - if (get_oid(ref, &oid)) + if (repo_get_oid(the_repository, ref, &oid)) return NULL; tree = &snapshot_sig_notes[f - &cgit_snapshot_formats[0]]; @@ -156,7 +159,7 @@ static int make_snapshot(const struct cgit_snapshot_format *format, { struct object_id oid; - if (get_oid(hex, &oid)) { + if (repo_get_oid(the_repository, hex, &oid)) { cgit_print_error_page(404, "Not found", "Bad object id: %s", hex); return 1; @@ -190,7 +193,7 @@ static int write_sig(const struct cgit_snapshot_format *format, return 0; } - buf = read_object_file(note, &type, &size); + buf = repo_read_object_file(the_repository, note, &type, &size); if (!buf) { cgit_print_error_page(404, "Not found", "Not found"); return 0; @@ -230,7 +233,7 @@ static const char *get_ref_from_filename(const struct cgit_repo *repo, strbuf_addstr(&snapshot, filename); strbuf_setlen(&snapshot, snapshot.len - strlen(format->suffix)); - if (get_oid(snapshot.buf, &oid) == 0) + if (repo_get_oid(the_repository, snapshot.buf, &oid) == 0) goto out; reponame = cgit_snapshot_prefix(repo); @@ -242,15 +245,15 @@ static const char *get_ref_from_filename(const struct cgit_repo *repo, strbuf_splice(&snapshot, 0, new_start - snapshot.buf, "", 0); } - if (get_oid(snapshot.buf, &oid) == 0) + if (repo_get_oid(the_repository, snapshot.buf, &oid) == 0) goto out; strbuf_insert(&snapshot, 0, "v", 1); - if (get_oid(snapshot.buf, &oid) == 0) + if (repo_get_oid(the_repository, snapshot.buf, &oid) == 0) goto out; strbuf_splice(&snapshot, 0, 1, "V", 1); - if (get_oid(snapshot.buf, &oid) == 0) + if (repo_get_oid(the_repository, snapshot.buf, &oid) == 0) goto out; result = 0; diff --git a/third_party/cgit/ui-stats.c b/third_party/cgit/ui-stats.c index 09b3625e7e..9aed4ac3bf 100644 --- a/third_party/cgit/ui-stats.c +++ b/third_party/cgit/ui-stats.c @@ -230,7 +230,7 @@ static struct string_list collect_stats(const struct cgit_period *period) argv[4] = ctx.qry.path; argc += 2; } - init_revisions(&rev, NULL); + repo_init_revisions(the_repository, &rev, NULL); rev.abbrev = DEFAULT_ABBREV; rev.commit_format = CMIT_FMT_DEFAULT; rev.max_parents = 1; @@ -241,8 +241,7 @@ static struct string_list collect_stats(const struct cgit_period *period) memset(&authors, 0, sizeof(authors)); while ((commit = get_revision(&rev)) != NULL) { add_commit(&authors, commit, period); - free_commit_buffer(the_repository->parsed_objects, commit); - free_commit_list(commit->parents); + release_commit_memory(the_repository->parsed_objects, commit); commit->parents = NULL; } return authors; diff --git a/third_party/cgit/ui-summary.c b/third_party/cgit/ui-summary.c index d1bb6a59fa..ec7b76fabf 100644 --- a/third_party/cgit/ui-summary.c +++ b/third_party/cgit/ui-summary.c @@ -114,6 +114,9 @@ void cgit_print_repo_readme(const char *path) } free(mimetype); + if (path) + ctx.page.title = fmtalloc("%s - %s", path, ctx.page.title); + cgit_print_layout_start(); if (ctx.repo->readme.nr == 0) goto done; diff --git a/third_party/cgit/ui-tag.c b/third_party/cgit/ui-tag.c index 08789102f6..be1122b905 100644 --- a/third_party/cgit/ui-tag.c +++ b/third_party/cgit/ui-tag.c @@ -25,9 +25,9 @@ static void print_tag_content(char *buf) html_txt(buf); html("</div>"); if (p) { - html("<div class='commit-msg'>"); + html("<pre class='commit-msg'>"); html_txt(++p); - html("</div>"); + html("</pre>"); } } @@ -48,7 +48,7 @@ void cgit_print_tag(char *revname) revname = ctx.qry.head; strbuf_addf(&fullref, "refs/tags/%s", revname); - if (get_oid(fullref.buf, &oid)) { + if (repo_get_oid(the_repository, fullref.buf, &oid)) { cgit_print_error_page(404, "Not found", "Bad tag reference: %s", revname); goto cleanup; diff --git a/third_party/cgit/ui-tree.c b/third_party/cgit/ui-tree.c index 1907450763..436b333809 100644 --- a/third_party/cgit/ui-tree.c +++ b/third_party/cgit/ui-tree.c @@ -98,7 +98,7 @@ static void print_object(const struct object_id *oid, const char *path, const ch return; } - buf = read_object_file(oid, &type, &size); + buf = repo_read_object_file(the_repository, oid, &type, &size); if (!buf) { cgit_print_error_page(500, "Internal server error", "Error reading object %s", oid_to_hex(oid)); @@ -242,7 +242,7 @@ static int ls_item(const struct object_id *oid, struct strbuf *base, } if (S_ISLNK(mode)) { html(" -> "); - buf = read_object_file(oid, &type, &size); + buf = repo_read_object_file(the_repository, oid, &type, &size); if (!buf) { htmlf("Error reading object: %s", oid_to_hex(oid)); goto cleanup; @@ -261,15 +261,21 @@ static int ls_item(const struct object_id *oid, struct strbuf *base, cgit_log_link("log", NULL, "button", ctx.qry.head, walk_tree_ctx->curr_rev, fullpath.buf, 0, NULL, NULL, ctx.qry.showmsg, 0); - if (ctx.repo->max_stats) + if (ctx.repo->max_stats) { + html(" "); cgit_stats_link("stats", NULL, "button", ctx.qry.head, fullpath.buf); - if (!S_ISGITLINK(mode)) + } + if (!S_ISGITLINK(mode)) { + html(" "); cgit_plain_link("plain", NULL, "button", ctx.qry.head, walk_tree_ctx->curr_rev, fullpath.buf); - if (!S_ISDIR(mode) && ctx.repo->enable_blame) + } + if (!S_ISDIR(mode) && ctx.repo->enable_blame) { + html(" "); cgit_blame_link("blame", NULL, "button", ctx.qry.head, walk_tree_ctx->curr_rev, fullpath.buf); + } html("</td></tr>\n"); cleanup: @@ -372,13 +378,13 @@ void cgit_print_tree(const char *rev, char *path) if (!rev) rev = ctx.qry.head; - if (get_oid(rev, &oid)) { + if (repo_get_oid(the_repository, rev, &oid)) { cgit_print_error_page(404, "Not found", "Invalid revision name: %s", rev); return; } commit = lookup_commit_reference(the_repository, &oid); - if (!commit || parse_commit(commit)) { + if (!commit || repo_parse_commit(the_repository, commit)) { cgit_print_error_page(404, "Not found", "Invalid commit reference: %s", rev); return; |