stagit
Fork of stagit for GNUfault.org
Log | Files | Refs | README | LICENSE
commit 87dbcb84cc44b5f34cf1d423bd8282650c541f83
parent 519cae2fcab6f2427dc8f2805d6a5d1eee4bdb05
Author: Connor Thomson <connor@gnufault.org>
Date:   Wed, 11 Nov 2026 17:09:07 -0800

Add GNUfault.org specifc stuff

Diffstat:
MMakefile | 16++--------------
MREADME | 187+------------------------------------------------------------------------------
Dexample_create.sh | 43-------------------------------------------
Dexample_post-receive.sh | 73-------------------------------------------------------------------------
Dfavicon.png | 0
Dlogo.png | 0
Mstagit-index.c | 17++++++-----------
Mstagit.c | 32+++++++++-----------------------
Dstyle.css | 154-------------------------------------------------------------------------------
9 files changed, 18 insertions(+), 504 deletions(-)

diff --git a/Makefile b/Makefile @@ -57,8 +57,6 @@ dist: rm -rf ${NAME}-${VERSION} mkdir -p ${NAME}-${VERSION} cp -f ${MAN1} ${HDR} ${SRC} ${COMPATSRC} ${DOC} \ - Makefile favicon.png logo.png style.css \ - example_create.sh example_post-receive.sh \ ${NAME}-${VERSION} # make tarball tar -cf - ${NAME}-${VERSION} | \ @@ -83,12 +81,7 @@ install: all for f in ${BIN}; do chmod 755 ${DESTDIR}${PREFIX}/bin/$$f; done # installing example files. mkdir -p ${DESTDIR}${DOCPREFIX} - cp -f style.css\ - favicon.png\ - logo.png\ - example_create.sh\ - example_post-receive.sh\ - README\ + cp -f README.md\ ${DESTDIR}${DOCPREFIX} # installing manual pages. mkdir -p ${DESTDIR}${MANPREFIX}/man1 @@ -100,12 +93,7 @@ uninstall: for f in ${BIN}; do rm -f ${DESTDIR}${PREFIX}/bin/$$f; done # removing example files. rm -f \ - ${DESTDIR}${DOCPREFIX}/style.css\ - ${DESTDIR}${DOCPREFIX}/favicon.png\ - ${DESTDIR}${DOCPREFIX}/logo.png\ - ${DESTDIR}${DOCPREFIX}/example_create.sh\ - ${DESTDIR}${DOCPREFIX}/example_post-receive.sh\ - ${DESTDIR}${DOCPREFIX}/README + ${DESTDIR}${DOCPREFIX}/README.md -rmdir ${DESTDIR}${DOCPREFIX} # removing manual pages. for m in ${MAN1}; do rm -f ${DESTDIR}${MANPREFIX}/man1/$$m; done diff --git a/README b/README @@ -1,186 +1 @@ -stagit ------- - -static git page generator. - -It generates static HTML pages for a git repository. - - -Usage ------ - -Make files per repository: - - $ mkdir -p htmlroot/htmlrepo1 && cd htmlroot/htmlrepo1 - $ stagit path/to/gitrepo1 - repeat for other repositories - $ ... - -Make index file for repositories: - - $ cd htmlroot - $ stagit-index path/to/gitrepo1 \ - path/to/gitrepo2 \ - path/to/gitrepo3 > index.html - - -Build and install ------------------ - -$ make -# make install - - -Dependencies ------------- - -- C compiler (C99). -- libc (tested with OpenBSD, FreeBSD, NetBSD, Linux: glibc and musl). -- libgit2 (v0.22+). -- POSIX make (optional). - - -Documentation -------------- - -See man pages: stagit(1) and stagit-index(1). - - -Building a static binary ------------------------- - -It may be useful to build static binaries, for example to run in a chroot. - -It can be done like this at the time of writing (v0.24): - -cd libgit2-src - -# change the options in the CMake file: CMakeLists.txt -BUILD_SHARED_LIBS to OFF (static) -CURL to OFF (not needed) -USE_SSH OFF (not needed) -THREADSAFE OFF (not needed) -USE_OPENSSL OFF (not needed, use builtin) - -mkdir -p build && cd build -cmake ../ -make -make install - - -Extract owner field from git config ------------------------------------ - -A way to extract the gitweb owner for example in the format: - - [gitweb] - owner = Name here - -Script: - - #!/bin/sh - awk '/^[ ]*owner[ ]=/ { - sub(/^[^=]*=[ ]*/, ""); - print $0; - }' - - -Set clone URL for a directory of repos --------------------------------------- - #!/bin/sh - cd "$dir" - for i in *; do - test -d "$i" && echo "git://git.codemadness.org/$i" > "$i/url" - done - - -Update files on git push ------------------------- - -Using a post-receive hook the static files can be automatically updated. -Keep in mind git push -f can change the history and the commits may need -to be recreated. This is because stagit checks if a commit file already -exists. It also has a cache (-c) option which can conflict with the new -history. See stagit(1). - -git post-receive hook (repo/.git/hooks/post-receive): - - #!/bin/sh - # detect git push -f - force=0 - while read -r old new ref; do - hasrevs=$(git rev-list "$old" "^$new" | sed 1q) - if test -n "$hasrevs"; then - force=1 - break - fi - done - - # remove commits and .cache on git push -f - #if test "$force" = "1"; then - # ... - #fi - - # see example_create.sh for normal creation of the files. - - -Create .tar.gz archives by tag ------------------------------- - #!/bin/sh - name="stagit" - mkdir -p archives - git tag -l | while read -r t; do - f="archives/${name}-$(echo "${t}" | tr '/' '_').tar.gz" - test -f "${f}" && continue - git archive \ - --format tar.gz \ - --prefix "${t}/" \ - -o "${f}" \ - -- \ - "${t}" - done - - -Features --------- - -- Log of all commits from HEAD. -- Log and diffstat per commit. -- Show file tree with linkable line numbers. -- Show references: local branches and tags. -- Detect README and LICENSE file from HEAD and link it as a webpage. -- Detect submodules (.gitmodules file) from HEAD and link it as a webpage. -- Atom feed of the commit log (atom.xml). -- Atom feed of the tags/refs (tags.xml). -- Make index page for multiple repositories with stagit-index. -- After generating the pages (relatively slow) serving the files is very fast, - simple and requires little resources (because the content is static), only - a HTTP file server is required. -- Usable with text-browsers such as dillo, links, lynx and w3m. - - -Cons ----- - -- Not suitable for large repositories (2000+ commits), because diffstats are - an expensive operation, the cache (-c flag) is a workaround for this in - some cases. -- Not suitable for large repositories with many files, because all files are - written for each execution of stagit. This is because stagit shows the lines - of textfiles and there is no "cache" for file metadata (this would add more - complexity to the code). -- Not suitable for repositories with many branches, a quite linear history is - assumed (from HEAD). - - In these cases it is better to just use cgit or possibly change stagit to - run as a CGI program. - -- Relatively slow to run the first time (about 3 seconds for sbase, - 1500+ commits), incremental updates are faster. -- Does not support some of the dynamic features cgit has, like: - - Snapshot tarballs per commit. - - File tree per commit. - - History log of branches diverged from HEAD. - - Stats (git shortlog -s). - - This is by design, just use git locally. +This is a fork of stagit v1.3 for GNUfault.org diff --git a/example_create.sh b/example_create.sh @@ -1,43 +0,0 @@ -#!/bin/sh -# - Makes index for repositories in a single directory. -# - Makes static pages for each repository directory. -# -# NOTE, things to do manually (once) before running this script: -# - copy style.css, logo.png and favicon.png manually, a style.css example -# is included. -# -# - write clone URL, for example "git://git.codemadness.org/dir" to the "url" -# file for each repo. -# - write owner of repo to the "owner" file. -# - write description in "description" file. -# -# Usage: -# - mkdir -p htmldir && cd htmldir -# - sh example_create.sh - -# path must be absolute. -reposdir="/var/www/domains/git.codemadness.nl/home/src" -curdir="$(pwd)" - -# make index. -stagit-index "${reposdir}/"*/ > "${curdir}/index.html" - -# make files per repo. -for dir in "${reposdir}/"*/; do - # strip .git suffix. - r=$(basename "${dir}") - d=$(basename "${dir}" ".git") - printf "%s... " "${d}" - - mkdir -p "${curdir}/${d}" - cd "${curdir}/${d}" || continue - stagit -c ".cache" -u "https://git.codemadness.nl/$d/" "${reposdir}/${r}" - - # symlinks - ln -sf log.html index.html - ln -sf ../style.css style.css - ln -sf ../logo.png logo.png - ln -sf ../favicon.png favicon.png - - echo "done" -done diff --git a/example_post-receive.sh b/example_post-receive.sh @@ -1,73 +0,0 @@ -#!/bin/sh -# generic git post-receive hook. -# change the config options below and call this script in your post-receive -# hook or symlink it. -# -# usage: $0 [name] -# -# if name is not set the basename of the current directory is used, -# this is the directory of the repo when called from the post-receive script. - -# NOTE: needs to be set for correct locale (expects UTF-8) otherwise the -# default is LC_CTYPE="POSIX". -export LC_CTYPE="en_US.UTF-8" - -name="$1" -if test "${name}" = ""; then - name=$(basename "$(pwd)") -fi - -# config -# paths must be absolute. -reposdir="/home/src/src" -dir="${reposdir}/${name}" -htmldir="/home/www/domains/git.codemadness.org/htdocs" -stagitdir="/" -destdir="${htmldir}${stagitdir}" -cachefile=".htmlcache" -# /config - -if ! test -d "${dir}"; then - echo "${dir} does not exist" >&2 - exit 1 -fi -cd "${dir}" || exit 1 - -# detect git push -f -force=0 -while read -r old new ref; do - test "${old}" = "0000000000000000000000000000000000000000" && continue - test "${new}" = "0000000000000000000000000000000000000000" && continue - - hasrevs=$(git rev-list "${old}" "^${new}" | sed 1q) - if test -n "${hasrevs}"; then - force=1 - break - fi -done - -# strip .git suffix. -r=$(basename "${name}") -d=$(basename "${name}" ".git") -printf "[%s] stagit HTML pages... " "${d}" - -mkdir -p "${destdir}/${d}" -cd "${destdir}/${d}" || exit 1 - -# remove commits and ${cachefile} on git push -f, this recreated later on. -if test "${force}" = "1"; then - rm -f "${cachefile}" - rm -rf "commit" -fi - -# make index. -stagit-index "${reposdir}/"*/ > "${destdir}/index.html" - -# make pages. -stagit -c "${cachefile}" -u "https://git.codemadness.nl/$d/" "${reposdir}/${r}" - -ln -sf log.html index.html -ln -sf ../style.css style.css -ln -sf ../logo.png logo.png - -echo "done" diff --git a/favicon.png b/favicon.png Binary files differ. diff --git a/logo.png b/logo.png Binary files differ. diff --git a/stagit-index.c b/stagit-index.c @@ -95,30 +95,25 @@ printtimeshort(FILE *fp, const git_time *intime) void writeheader(FILE *fp) { - fputs("<!DOCTYPE html>\n" + fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n" "<html>\n<head>\n" - "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" - "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n" "<title>", fp); xmlencode(fp, description, strlen(description)); - fprintf(fp, "</title>\n<link rel=\"icon\" type=\"image/png\" href=\"%sfavicon.png\" />\n", relpath); - fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"%sstyle.css\" />\n", relpath); fputs("</head>\n<body>\n", fp); - fprintf(fp, "<table>\n<tr><td><img src=\"%slogo.png\" alt=\"\" width=\"32\" height=\"32\" /></td>\n" + fprintf(fp, "<table>\n<tr><td></td>\n" "<td><span class=\"desc\">", relpath); xmlencode(fp, description, strlen(description)); fputs("</span></td></tr><tr><td></td><td>\n" - "</td></tr>\n</table>\n<hr/>\n<div id=\"content\">\n" - "<table id=\"index\"><thead>\n" + "</td></tr>\n</table>\n<hr/>\n" + "<table id=\"index\">\n" "<tr><td><b>Name</b></td><td><b>Description</b></td><td><b>Owner</b></td>" - "<td><b>Last commit</b></td></tr>" - "</thead><tbody>\n", fp); + "<td><b>Last commit</b></td></tr>", fp); } void writefooter(FILE *fp) { - fputs("</tbody>\n</table>\n</div>\n</body>\n</html>\n", fp); + fputs("</table>\n</body>\n</html>\n", fp); } int diff --git a/stagit.c b/stagit.c @@ -499,10 +499,8 @@ printtimeshort(FILE *fp, const git_time *intime) void writeheader(FILE *fp, const char *title) { - fputs("<!DOCTYPE html>\n" + fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n" "<html>\n<head>\n" - "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" - "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n" "<title>", fp); xmlencode(fp, title, strlen(title)); if (title[0] && strippedname[0]) @@ -511,30 +509,18 @@ writeheader(FILE *fp, const char *title) if (description[0]) fputs(" - ", fp); xmlencode(fp, description, strlen(description)); - fprintf(fp, "</title>\n<link rel=\"icon\" type=\"image/png\" href=\"%sfavicon.png\" />\n", relpath); - fputs("<link rel=\"alternate\" type=\"application/atom+xml\" title=\"", fp); - xmlencode(fp, name, strlen(name)); - fprintf(fp, " Atom Feed\" href=\"%satom.xml\" />\n", relpath); - fputs("<link rel=\"alternate\" type=\"application/atom+xml\" title=\"", fp); - xmlencode(fp, name, strlen(name)); - fprintf(fp, " Atom Feed (tags)\" href=\"%stags.xml\" />\n", relpath); - fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"%sstyle.css\" />\n", relpath); - fputs("</head>\n<body>\n<table><tr><td>", fp); - fprintf(fp, "<a href=\"../%s\"><img src=\"%slogo.png\" alt=\"\" width=\"32\" height=\"32\" /></a>", - relpath, relpath); - fputs("</td><td><h1>", fp); - xmlencode(fp, strippedname, strlen(strippedname)); - fputs("</h1><span class=\"desc\">", fp); + fputs("</title>\n</head>\n<body>\n", fp); + fprintf(fp, "<b>%s</b><br/>\n", strippedname); xmlencode(fp, description, strlen(description)); - fputs("</span></td></tr>", fp); + fputs("<br/>\n", fp); + if (cloneurl[0]) { - fputs("<tr class=\"url\"><td></td><td>git clone <a href=\"", fp); - xmlencode(fp, cloneurl, strlen(cloneurl)); /* not percent-encoded */ + fputs("git clone <a href=\"", fp); + xmlencode(fp, cloneurl, strlen(cloneurl)); fputs("\">", fp); xmlencode(fp, cloneurl, strlen(cloneurl)); - fputs("</a></td></tr>", fp); + fputs("</a><br/>\n", fp); } - fputs("<tr><td></td><td>\n", fp); fprintf(fp, "<a href=\"%slog.html\">Log</a> | ", relpath); fprintf(fp, "<a href=\"%sfiles.html\">Files</a> | ", relpath); fprintf(fp, "<a href=\"%srefs.html\">Refs</a>", relpath); @@ -547,7 +533,7 @@ writeheader(FILE *fp, const char *title) if (license) fprintf(fp, " | <a href=\"%sfile/%s.html\">LICENSE</a>", relpath, license); - fputs("</td></tr></table>\n<hr/>\n<div id=\"content\">\n", fp); + fputs("<hr/>\n", fp); } void diff --git a/style.css b/style.css @@ -1,154 +0,0 @@ -body { - color: #000; - background-color: #fff; - font-family: monospace; -} - -h1, h2, h3, h4, h5, h6 { - font-size: 1em; - margin: 0; -} - -img, h1, h2 { - vertical-align: middle; -} - -img { - border: 0; -} - -a:target { - background-color: #ccc; -} - -a.d, -a.h, -a.i, -a.line { - text-decoration: none; -} - -#blob a { - color: #555; -} - -#blob a:hover { - color: blue; - text-decoration: none; -} - -table thead td { - font-weight: bold; -} - -table td { - padding: 0 0.4em; -} - -#content table td { - vertical-align: top; - white-space: nowrap; -} - -#branches tr:hover td, -#tags tr:hover td, -#index tr:hover td, -#log tr:hover td, -#files tr:hover td { - background-color: #eee; -} - -#index tr td:nth-child(2), -#tags tr td:nth-child(3), -#branches tr td:nth-child(3), -#log tr td:nth-child(2) { - white-space: normal; -} - -td.num { - text-align: right; -} - -.desc { - color: #555; -} - -hr { - border: 0; - border-top: 1px solid #555; - height: 1px; -} - -pre { - font-family: monospace; -} - -pre a.h { - color: #00a; -} - -.A, -span.i, -pre a.i { - color: #070; -} - -.D, -span.d, -pre a.d { - color: #e00; -} - -pre a.h:hover, -pre a.i:hover, -pre a.d:hover { - text-decoration: none; -} - -@media (prefers-color-scheme: dark) { - body { - background-color: #000; - color: #bdbdbd; - } - hr { - border-color: #222; - } - a { - color: #56c8ff; - } - a:target { - background-color: #222; - } - .desc { - color: #aaa; - } - #blob a { - color: #555; - } - #blob a:target { - color: #eee; - } - #blob a:hover { - color: #56c8ff; - } - pre a.h { - color: #00cdcd; - } - .A, - span.i, - pre a.i { - color: #00cd00; - } - .D, - span.d, - pre a.d { - color: #cd0000; - } - #branches tr:hover td, - #tags tr:hover td, - #index tr:hover td, - #log tr:hover td, - #files tr:hover td { - background-color: #111; - } -}