first commit

This commit is contained in:
Noah Swerhun 2021-04-16 17:37:08 -05:00
commit 6fe2126d61
18 changed files with 3792 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*.o
stagit
stagit-index

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT/X Consortium License
(c) 2015-2021 Hiltjo Posthuma <hiltjo@codemadness.org>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

109
Makefile Normal file
View file

@ -0,0 +1,109 @@
.POSIX:
NAME = stagit
VERSION = 0.9.5
# paths
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/man
DOCPREFIX = ${PREFIX}/share/doc/${NAME}
LIBGIT_INC = -I/usr/local/include
LIBGIT_LIB = -L/usr/local/lib -lgit2
# use system flags.
STAGIT_CFLAGS = ${LIBGIT_INC} ${CFLAGS}
STAGIT_LDFLAGS = ${LIBGIT_LIB} ${LDFLAGS}
STAGIT_CPPFLAGS = -D_XOPEN_SOURCE=700 -D_DEFAULT_SOURCE -D_BSD_SOURCE
SRC = \
stagit.c\
stagit-index.c
COMPATSRC = \
reallocarray.c\
strlcat.c\
strlcpy.c
BIN = \
stagit\
stagit-index
MAN1 = \
stagit.1\
stagit-index.1
DOC = \
LICENSE\
README
HDR = compat.h
COMPATOBJ = \
reallocarray.o\
strlcat.o\
strlcpy.o
OBJ = ${SRC:.c=.o} ${COMPATOBJ}
all: ${BIN}
.o:
${CC} -o $@ ${LDFLAGS}
.c.o:
${CC} -o $@ -c $< ${STAGIT_CFLAGS} ${STAGIT_CPPFLAGS}
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} | \
gzip -c > ${NAME}-${VERSION}.tar.gz
rm -rf ${NAME}-${VERSION}
${OBJ}: ${HDR}
stagit: stagit.o ${COMPATOBJ}
${CC} -o $@ stagit.o ${COMPATOBJ} ${STAGIT_LDFLAGS}
stagit-index: stagit-index.o ${COMPATOBJ}
${CC} -o $@ stagit-index.o ${COMPATOBJ} ${STAGIT_LDFLAGS}
clean:
rm -f ${BIN} ${OBJ} ${NAME}-${VERSION}.tar.gz
install: all
# installing executable files.
mkdir -p ${DESTDIR}${PREFIX}/bin
cp -f ${BIN} ${DESTDIR}${PREFIX}/bin
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\
${DESTDIR}${DOCPREFIX}
# installing manual pages.
mkdir -p ${DESTDIR}${MANPREFIX}/man1
cp -f ${MAN1} ${DESTDIR}${MANPREFIX}/man1
for m in ${MAN1}; do chmod 644 ${DESTDIR}${MANPREFIX}/man1/$$m; done
uninstall:
# removing executable files.
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
-rmdir ${DESTDIR}${DOCPREFIX}
# removing manual pages.
for m in ${MAN1}; do rm -f ${DESTDIR}${MANPREFIX}/man1/$$m; done
.PHONY: all clean dist install uninstall

181
README Normal file
View file

@ -0,0 +1,181 @@
stagit
------
static git page generator.
It generates static HTML pages for a git repository.
Usage
-----
Make files per repository:
$ mkdir -p htmldir && cd htmldir
$ stagit path-to-repo
Make index file for repositories:
$ stagit-index repodir1 repodir2 repodir3 > 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.

6
compat.h Normal file
View file

@ -0,0 +1,6 @@
#undef strlcat
size_t strlcat(char *, const char *, size_t);
#undef strlcpy
size_t strlcpy(char *, const char *, size_t);
#undef reallocarray
void *reallocarray(void *, size_t, size_t);

43
example_create.sh Executable file
View file

@ -0,0 +1,43 @@
#!/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

73
example_post-receive.sh Executable file
View file

@ -0,0 +1,73 @@
#!/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"

BIN
favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 B

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 B

39
reallocarray.c Normal file
View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include "compat.h"
/*
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
*/
#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
void *
reallocarray(void *optr, size_t nmemb, size_t size)
{
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size) {
errno = ENOMEM;
return NULL;
}
return realloc(optr, size * nmemb);
}

42
stagit-index.1 Normal file
View file

@ -0,0 +1,42 @@
.Dd December 26, 2015
.Dt STAGIT-INDEX 1
.Os
.Sh NAME
.Nm stagit-index
.Nd static git index page generator
.Sh SYNOPSIS
.Nm
.Op Ar repodir...
.Sh DESCRIPTION
.Nm
will create an index HTML page for the repositories specified and writes
the HTML data to stdout.
The repos in the index are in the same order as the arguments
.Ar repodir
specified.
.Pp
The basename of the directory is used as the repository name.
The suffix ".git" is removed from the basename, this suffix is commonly used
for "bare" repos.
.Pp
The content of the follow files specifies the meta data for each repository:
.Bl -tag -width Ds
.It .git/description or description (bare repos).
description
.It .git/owner or owner (bare repo).
owner of repository
.El
.Pp
For changing the style of the page you can use the following files:
.Bl -tag -width Ds
.It favicon.png
favicon image.
.It logo.png
32x32 logo.
.It style.css
CSS stylesheet.
.El
.Sh SEE ALSO
.Xr stagit 1
.Sh AUTHORS
.An Hiltjo Posthuma Aq Mt hiltjo@codemadness.org

216
stagit-index.c Normal file
View file

@ -0,0 +1,216 @@
#include <err.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <git2.h>
static git_repository *repo;
static const char *relpath = "";
static char description[255] = "Repositories";
static char *name = "";
static char owner[255];
void
joinpath(char *buf, size_t bufsiz, const char *path, const char *path2)
{
int r;
r = snprintf(buf, bufsiz, "%s%s%s",
path, path[0] && path[strlen(path) - 1] != '/' ? "/" : "", path2);
if (r < 0 || (size_t)r >= bufsiz)
errx(1, "path truncated: '%s%s%s'",
path, path[0] && path[strlen(path) - 1] != '/' ? "/" : "", path2);
}
/* Escape characters below as HTML 2.0 / XML 1.0. */
void
xmlencode(FILE *fp, const char *s, size_t len)
{
size_t i;
for (i = 0; *s && i < len; s++, i++) {
switch(*s) {
case '<': fputs("&lt;", fp); break;
case '>': fputs("&gt;", fp); break;
case '\'': fputs("&#39;" , fp); break;
case '&': fputs("&amp;", fp); break;
case '"': fputs("&quot;", fp); break;
default: putc(*s, fp);
}
}
}
void
printtimeshort(FILE *fp, const git_time *intime)
{
struct tm *intm;
time_t t;
char out[32];
t = (time_t)intime->time;
if (!(intm = gmtime(&t)))
return;
strftime(out, sizeof(out), "%Y-%m-%d %H:%M", intm);
fputs(out, fp);
}
void
writeheader(FILE *fp)
{
fputs("<!DOCTYPE html>\n"
"<html>\n<head>\n"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\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"
"<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"
"<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);
}
void
writefooter(FILE *fp)
{
fputs("</tbody>\n</table>\n</div>\n</body>\n</html>\n", fp);
}
int
writelog(FILE *fp)
{
git_commit *commit = NULL;
const git_signature *author;
git_revwalk *w = NULL;
git_oid id;
char *stripped_name = NULL, *p;
int ret = 0;
git_revwalk_new(&w, repo);
git_revwalk_push_head(w);
git_revwalk_simplify_first_parent(w);
if (git_revwalk_next(&id, w) ||
git_commit_lookup(&commit, repo, &id)) {
ret = -1;
goto err;
}
author = git_commit_author(commit);
/* strip .git suffix */
if (!(stripped_name = strdup(name)))
err(1, "strdup");
if ((p = strrchr(stripped_name, '.')))
if (!strcmp(p, ".git"))
*p = '\0';
fputs("<tr><td><a href=\"", fp);
xmlencode(fp, stripped_name, strlen(stripped_name));
fputs("/log.html\">", fp);
xmlencode(fp, stripped_name, strlen(stripped_name));
fputs("</a></td><td>", fp);
xmlencode(fp, description, strlen(description));
fputs("</td><td>", fp);
xmlencode(fp, owner, strlen(owner));
fputs("</td><td>", fp);
if (author)
printtimeshort(fp, &(author->when));
fputs("</td></tr>", fp);
git_commit_free(commit);
err:
git_revwalk_free(w);
free(stripped_name);
return ret;
}
int
main(int argc, char *argv[])
{
FILE *fp;
char path[PATH_MAX], repodirabs[PATH_MAX + 1];
const char *repodir;
int i, ret = 0;
if (argc < 2) {
fprintf(stderr, "%s [repodir...]\n", argv[0]);
return 1;
}
git_libgit2_init();
#ifdef __OpenBSD__
if (pledge("stdio rpath", NULL) == -1)
err(1, "pledge");
#endif
writeheader(stdout);
for (i = 1; i < argc; i++) {
repodir = argv[i];
if (!realpath(repodir, repodirabs))
err(1, "realpath");
if (git_repository_open_ext(&repo, repodir,
GIT_REPOSITORY_OPEN_NO_SEARCH, NULL)) {
fprintf(stderr, "%s: cannot open repository\n", argv[0]);
ret = 1;
continue;
}
/* use directory name as name */
if ((name = strrchr(repodirabs, '/')))
name++;
else
name = "";
/* read description or .git/description */
joinpath(path, sizeof(path), repodir, "description");
if (!(fp = fopen(path, "r"))) {
joinpath(path, sizeof(path), repodir, ".git/description");
fp = fopen(path, "r");
}
description[0] = '\0';
if (fp) {
if (!fgets(description, sizeof(description), fp))
description[0] = '\0';
fclose(fp);
}
/* read owner or .git/owner */
joinpath(path, sizeof(path), repodir, "owner");
if (!(fp = fopen(path, "r"))) {
joinpath(path, sizeof(path), repodir, ".git/owner");
fp = fopen(path, "r");
}
owner[0] = '\0';
if (fp) {
if (!fgets(owner, sizeof(owner), fp))
owner[0] = '\0';
owner[strcspn(owner, "\n")] = '\0';
fclose(fp);
}
writelog(stdout);
}
writefooter(stdout);
/* cleanup */
git_repository_free(repo);
git_libgit2_shutdown();
return ret;
}

115
stagit.1 Normal file
View file

@ -0,0 +1,115 @@
.Dd March 5, 2021
.Dt STAGIT 1
.Os
.Sh NAME
.Nm stagit
.Nd static git page generator
.Sh SYNOPSIS
.Nm
.Op Fl c Ar cachefile
.Op Fl l Ar commits
.Op Fl u Ar baseurl
.Ar repodir
.Sh DESCRIPTION
.Nm
writes HTML pages for the repository
.Ar repodir
to the current directory.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl c Ar cachefile
Cache the entries of the log page up to the point of
the last commit.
The
.Ar cachefile
will store the last commit id and the entries in the HTML table.
It is up to the user to make sure the state of the
.Ar cachefile
is in sync with the history of the repository.
.It Fl l Ar commits
Write a maximum number of
.Ar commits
to the log.html file only.
However the commit files are written as usual.
.It Fl u Ar baseurl
Base URL to make links in the Atom feeds absolute.
For example: "https://git.codemadness.org/stagit/".
.El
.Pp
The options
.Fl c
and
.Fl l
cannot be used at the same time.
.Pp
The following files will be written:
.Bl -tag -width Ds
.It atom.xml
Atom XML feed of the last 100 commits.
.It tags.xml
Atom XML feed of the tags.
.It files.html
List of files in the latest tree, linking to the file.
.It log.html
List of commits in reverse chronological applied commit order, each commit
links to a page with a diffstat and diff of the commit.
.It refs.html
Lists references of the repository such as branches and tags.
.El
.Pp
For each entry in HEAD a file will be written in the format:
file/filepath.html.
This file will contain the textual data of the file prefixed by line numbers.
The file will have the string "Binary file" if the data is considered to be
non-textual.
.Pp
For each commit a file will be written in the format:
commit/commitid.html.
This file will contain the diffstat and diff of the commit.
It will write the string "Binary files differ" if the data is considered to
be non-textual.
Too large diffs will be suppressed and a string
"Diff is too large, output suppressed" will be written.
.Pp
When a commit HTML file exists it won't be overwritten again, note that if
you've changed
.Nm
or changed one of the metadata files of the repository it is recommended to
recreate all the output files because it will contain old data.
To do this remove the output directory and
.Ar cachefile ,
then recreate the files.
.Pp
The basename of the directory is used as the repository name.
The suffix ".git" is removed from the basename, this suffix is commonly used
for "bare" repos.
.Pp
The content of the follow files specifies the metadata for each repository:
.Bl -tag -width Ds
.It .git/description or description (bare repo).
description
.It .git/owner or owner (bare repo).
owner of repository
.It .git/url or url (bare repo).
primary clone url of the repository, for example: git://git.2f30.org/stagit
.El
.Pp
When a README or LICENSE file exists in HEAD or a .gitmodules submodules file
exists in HEAD a direct link in the menu is made.
.Pp
For changing the style of the page you can use the following files:
.Bl -tag -width Ds
.It favicon.png
favicon image.
.It logo.png
32x32 logo.
.It style.css
CSS stylesheet.
.El
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr stagit-index 1
.Sh AUTHORS
.An Hiltjo Posthuma Aq Mt hiltjo@codemadness.org

1369
stagit.c Normal file

File diff suppressed because it is too large Load diff

1360
stagit.c.bak Normal file

File diff suppressed because it is too large Load diff

57
strlcat.c Normal file
View file

@ -0,0 +1,57 @@
/* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */
/*
* Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
#include "compat.h"
/*
* Appends src to string dst of size dsize (unlike strncat, dsize is the
* full size of dst, not space left). At most dsize-1 characters
* will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
* Returns strlen(src) + MIN(dsize, strlen(initial dst)).
* If retval >= dsize, truncation occurred.
*/
size_t
strlcat(char *dst, const char *src, size_t dsize)
{
const char *odst = dst;
const char *osrc = src;
size_t n = dsize;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end. */
while (n-- != 0 && *dst != '\0')
dst++;
dlen = dst - odst;
n = dsize - dlen;
if (n-- == 0)
return(dlen + strlen(src));
while (*src != '\0') {
if (n != 0) {
*dst++ = *src;
n--;
}
src++;
}
*dst = '\0';
return(dlen + (src - osrc)); /* count does not include NUL */
}

52
strlcpy.c Normal file
View file

@ -0,0 +1,52 @@
/* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */
/*
* Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
#include "compat.h"
/*
* Copy string src to buffer dst of size dsize. At most dsize-1
* chars will be copied. Always NUL terminates (unless dsize == 0).
* Returns strlen(src); if retval >= dsize, truncation occurred.
*/
size_t
strlcpy(char *dst, const char *src, size_t dsize)
{
const char *osrc = src;
size_t nleft = dsize;
/* Copy as many bytes as will fit. */
if (nleft != 0) {
while (--nleft != 0) {
if ((*dst++ = *src++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src. */
if (nleft == 0) {
if (dsize != 0)
*dst = '\0'; /* NUL-terminate dst */
while (*src++)
;
}
return(src - osrc - 1); /* count does not include NUL */
}

106
style.css Normal file
View file

@ -0,0 +1,106 @@
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;
}