From 7f299c3c7b99a903f18cf894ca81e0d5926df883 Mon Sep 17 00:00:00 2001 From: EuAndreh Date: Fri, 2 May 2025 08:14:19 -0300 Subject: mv src/gitstatic{,.in} --- src/gistatic | 1576 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/gistatic.in | 1576 ------------------------------------------------------- 2 files changed, 1576 insertions(+), 1576 deletions(-) create mode 100755 src/gistatic delete mode 100755 src/gistatic.in diff --git a/src/gistatic b/src/gistatic new file mode 100755 index 0000000..fec517a --- /dev/null +++ b/src/gistatic @@ -0,0 +1,1576 @@ +#!/bin/sh +# shellcheck disable=2034 disable=2059 +# FIXME: remove these ^^^ +set -eu + +MSG_USAGE_EN='Usage: + gistatic -i -o DIRECTORY REPOSITORY... + gistatic -o DIRECTORY -u CLONE_URL [-b MAIN_BRANCH] REPOSITORY + gistatic [-hV]' + +MSG_HELP_EN=' +Options: + -i build the index page of the repositories + -u CLONE_URL address to be shown alongside "git clone" + -o DIRECTORY output where to place the generated files + -b MAIN_BRANCH the default branch of the repository (default: main) + -h, --help show this help + -V, --version print the version information + +See "man gistatic" for more information.' + +MSG_MISSING_CLIARG_EN='Missing %s' +MSG_INCOMPATIBLE_OPTIONS_EN='Incompatible options: ' +MSG_MISSING_ARGS_EN='REPOSITORY' +MSG_LANGNAME_EN='en' +MSG_INDEX_DESCRIPTION_EN='Index of repositories' +MSG_DEFAULT_TITLE_EN='Repositories' +MSG_LOGO_ALT_INDEX_EN='Logo image of the repository list' +MSG_LOGO_ALT_REPOSITORY_EN='Logo image of the repository' +MSG_NAME_EN='Name' +MSG_DESCRIPTION_EN='Description' +MSG_LAST_COMMIT_EN='Last commit' +MSG_COMMIT_FEED_EN='commit feed' +MSG_TAGS_FEED_EN='tags feed' +MSG_NAV_FILES_EN='files' +MSG_NAV_LOG_EN='log' +MSG_NAV_REFS_EN='refs' +MSG_THEAD_BRANCH_EN='Branch' +MSG_THEAD_COMMITMSG_EN='Commit message' +MSG_THEAD_AUTHOR_EN='Author' +MSG_THEAD_DATE_EN='Date' +MSG_THEAD_TAG_EN='Tag' +MSG_TITLE_REFS_EN='refs' +MSG_GENERATING_LOG_EN='Generating %s...' + +# HTML escaped messages +MSG_ESCAPED_FOOTER_TEMPLATE_EN='Generated with gistatic.' + +set_lang() { + lang="$1" + eval " + MSG_USAGE=\$MSG_USAGE_$lang + MSG_HELP=\$MSG_HELP_$lang + MSG_MISSING_CLIARG=\$MSG_MISSING_CLIARG_$lang + MSG_INCOMPATIBLE_OPTIONS=\$MSG_INCOMPATIBLE_OPTIONS_$lang + MSG_MISSING_ARGS=\$MSG_MISSING_ARGS_$lang + MSG_LANGNAME=\$MSG_LANGNAME_$lang + MSG_INDEX_DESCRIPTION=\$MSG_INDEX_DESCRIPTION_$lang + MSG_DEFAULT_TITLE=\$MSG_DEFAULT_TITLE_$lang + MSG_LOGO_ALT_INDEX=\$MSG_LOGO_ALT_INDEX_$lang + MSG_LOGO_ALT_REPOSITORY=\$MSG_LOGO_ALT_REPOSITORY_$lang + MSG_NAME=\$MSG_NAME_$lang + MSG_DESCRIPTION=\$MSG_DESCRIPTION_$lang + MSG_LAST_COMMIT=\$MSG_LAST_COMMIT_$lang + MSG_COMMIT_FEED=\$MSG_COMMIT_FEED_$lang + MSG_TAGS_FEED=\$MSG_TAGS_FEED_$lang + MSG_NAV_FILES=\$MSG_NAV_FILES_$lang + MSG_NAV_LOG=\$MSG_NAV_LOG_$lang + MSG_NAV_REFS=\$MSG_NAV_REFS_$lang + MSG_THEAD_BRANCH=\$MSG_THEAD_BRANCH_$lang + MSG_THEAD_COMMITMSG=\$MSG_THEAD_COMMITMSG_$lang + MSG_THEAD_AUTHOR=\$MSG_THEAD_AUTHOR_$lang + MSG_THEAD_DATE=\$MSG_THEAD_DATE_$lang + MSG_THEAD_TAG=\$MSG_THEAD_TAG_$lang + MSG_TITLE_REFS=\$MSG_TITLE_REFS_$lang + MSG_GENERATING_LOG=\$MSG_GENERATING_LOG_$lang + + MSG_ESCAPED_FOOTER_TEMPLATE=\$MSG_ESCAPED_FOOTER_TEMPLATE_$lang +" +} + +get_lang() { + # LC_MESSAGES="ll_CC.CODESET@modifier" -> ll_CC, where quotes + # are optional + locale 2>/dev/null | + grep ^LC_MESSAGES | + cut -d. -f1 | + cut -d\" -f2 | + cut -d= -f2 +} + +case "$(get_lang)" in + *) + set_lang EN + ;; +esac + + +# +# Utilities +# + +tac() { + sed '1!G;h;$!d' +} + +escape() { + printf '%s' "$1" | + sed \ + -e 's|&|\&|g' \ + -e 's|<|\<|g' \ + -e 's|>|\>|g' \ + -e 's|"|\"|g' \ + -e "s|'|\'|g" +} + +realpath() { + mkdir -p "$1" + cd "$1" + pwd +} + + +# +# Documentation functions +# + +usage() { + printf '%s\n' "$MSG_USAGE" +} + +help() { + printf '%s\n' "$MSG_HELP" +} + +version() { + printf 'gistatic-0.1.0 1970-01-01\n' +} + + +# +# Template strings +# + +print_logo() { + cat <<-'EOF' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + EOF +} + +print_style() { + cat <<-'EOF' + :root { + --color: black; + --background-color: white; + --background-contrast-color: hsl(0, 0%, 98%); + --hover-color: hsl(0, 0%, 93%); + --nav-color: hsl(0, 0%, 87%); + --selected-color: hsl(0, 0%, 80%); + --diff-added-color: hsl(120, 100%, 23%); + --diff-removed-color: hsl(0, 100%, 47%); + } + + @media(prefers-color-scheme: dark) { + :root { + --color: white; + --background-color: black; + --background-contrast-color: hsl(0, 0%, 2%); + --hover-color: hsl(0, 0%, 7%); + --nav-color: hsl(0, 0%, 13%); + --selected-color: hsl(0, 0%, 20%); + } + + body { + color: var(--color); + background-color: var(--background-color); + } + + a { + color: hsl(211, 100%, 60%); + } + + a:visited { + color: hsl(242, 100%, 80%); + } + } + + body { + font-family: monospace; + max-width: 1100px; + margin: 0 auto 0 auto; + } + + .logo { + height: 6em; + width: 6em; + } + + .header-horizontal-grouping { + display: flex; + align-items: center; + margin-top: 1em; + margin-bottom: 1em; + } + + .header-description { + margin-left: 2em; + } + + nav { + margin-top: 2em; + } + + nav ul { + display: flex; + list-style-type: none; + margin-bottom: 0; + } + + nav li { + margin-left: 10px; + } + + nav a, nav a:visited { + padding: 2px 8px 0px 8px; + color: var(--color); + } + + .selected-nav-item { + background-color: var(--nav-color); + } + + hr { + margin-top: 0; + border: 0; + border-top: 3px solid var(--nav-color); + } + + table { + margin: 2em auto; + } + + th { + padding-bottom: 1em; + } + + tbody tr:hover { + background-color: var(--hover-color); + } + + td { + padding-left: 1em; + padding-right: 1em; + } + + + /* commit page */ + + .diff-added, .diff-removed { + text-decoration: none; + } + + .diff-added:target, .diff-removed:target { + background-color: var(--selected-color); + } + + .diff-added, .diff-added:visited { + color: var(--diff-added-color); + } + + .diff-removed, .diff-removed:visited { + color: var(--diff-removed-color); + } + + + /* log page */ + + .log-commit-box { + padding: 1em; + margin: 1em; + background-color: var(--background-contrast-color); + } + + .log-commit-tag { + padding: 2px; + border: 1px solid; + color: var(--color); + } + + .log-head-highlight { + background-color: #ff8888; /* FIXME: hsl + dark-mode */ + } + + .log-branch-highlight { + background-color: #88ff88; /* FIXME: hsl + dark-mode */ + } + + .log-tag-highlight { + background-color: #ffff88; /* FIXME: hsl + dark-mode */ + } + + .pre-wrapping { + overflow: auto; + margin: 1em; + } + + .log-notes { + /* FIXME: yellow box goes until the end of the screen */ + padding: 1em; + background-color: #ffd; /* FIXME: hsl + dark-mode */ + } + + .log-pagination { + text-align: center; + margin: 2em; + } + + + footer { + text-align: center; + } + EOF +} + +print_index_header() { + cat <<-EOF + + + + + + + + + $(escape "$TITLE") + + +
+
+ $(escape +

+ $(escape "$TITLE") +

+
+
+
+
+ + + + + + + + + +EOF +} + +print_index_row() { + repo="$(basename "$(realpath "${1%.git}")")" + description="$(cat "$1/description" 2>/dev/null ||:)" + last_commit_date="$(git -C "$1" log -1 --format=%cd --date='format:%Y-%m:%d %H:%M' 2>/dev/null ||:)" + cat <<-EOF + + + + + + EOF +} + +print_index_footer() { + cat <<-EOF + +
+ $(escape "$MSG_NAME") + + $(escape "$MSG_DESCRIPTION") + + $(escape "$MSG_LAST_COMMIT") +
+ + $(escape "$repo") + + + $(escape "$description") + + $(escape "$last_commit_date") +
+
+ + + + EOF +} + +index_write() { + { + print_index_header + for r in "$@"; do + print_index_row "$r" + done + print_index_footer + } > "$OUTDIR/index.html" + + print_logo > "$OUTDIR/logo.svg" + print_style > "$OUTDIR/style.css" +} + +genlog() { + if [ "$VERBOSE" = true ]; then + printf "$MSG_GENERATING_LOG\n" "$1" >&2 + fi +} + +parallel_n=0 +cached_run() { + TARGET_PATH="$1" + shift # drop $TARGET_PATH + shift # drop -- + + if [ -e "$OUTDIR/$TARGET_PATH" ]; then + return + fi + + if [ -e "$CACHE_DIR/$TARGET_PATH" ]; then + $CMD "$CACHE_DIR/$TARGET_PATH" "$OUTDIR/$TARGET_PATH" + else + { + genlog "$OUTDIR/$TARGET_PATH" + "$@" + $CMD "$CACHE_DIR/$TARGET_PATH" "$OUTDIR/$TARGET_PATH" + } & + parallel_n=$((parallel_n + 1)) + if [ "$parallel_n" = "$MAX_JOBS" ]; then + wait + parallel_n=0 + fi + fi +} + +# FIXME: get from config? +# exts() { } + +# FIXME: emit signatures code +TAB="$(printf '\t')" +repo_tarballs_write2() { + git branch --format '%(refname:lstrip=2)' | while read -r branch; do + cat <<-EOF + all: $OUTDIR/tarballs/$NAME-$branch.$EXT + + $OUTDIR/tarballs/$NAME-$branch.$EXT: $CACHE_DIR/tarballs/$NAME-$branch.$EXT + ${TAB}\$(LN) \$? \$@ + + $CACHE_DIR/tarballs/$NAME-$branch.$EXT: $CACHE_DIR/branch-revisions/$branch + ${TAB}git -C "$REPO" archive --prefix $NAME-$branch/ -o \$@ $branch + + $CACHE_DIR/branch-revisions/$branch: ALWAYS + ${TAB}@git -C "$REPO" rev-parse $branch | ifnew \$@ + + EOF + done + + git tag | while read -r tag; do + cat <<-EOF + all: $OUTDIR/tarballs/$NAME-$tag.$EXT + + $OUTDIR/tarballs/$NAME-$tag.$EXT: $CACHE_DIR/tarballs/$NAME-$tag.$EXT + ${TAB}\$(LN) \$? \$@ + + $CACHE_DIR/tarballs/$NAME-$tag.$EXT: + ${TAB}git -C "$REPO" archive --prefix $NAME-$tag/ -o \$@ $tag + + EOF + done +} + +repo_tarballs_write() { + repo="$1" + mkdir -p "$OUTDIR/tarballs" "$CACHE_DIR/tarballs" + local_parallel_n=0 + for branch in $(git branch --format '%(refname:lstrip=2)'); do + TARBALL_PATH="$OUTDIR/tarballs/$repo-$branch.tar.gz" + genlog "$TARBALL_PATH" + git archive --prefix "$repo-$branch/" "$branch" \ + -o "$TARBALL_PATH" & + local_parallel_n=$((local_parallel_n + 1)) + if [ "$local_parallel_n" = "$MAX_JOBS" ]; then + wait + local_parallel_n=0 + fi + done + wait + + for tag in $(git tag); do + TARBALL_PATH="tarballs/$repo-$tag.tar.gz" + cached_run "$TARBALL_PATH" -- \ + git archive --prefix "$repo-$tag/" "$tag" \ + -o "$CACHE_DIR/$TARBALL_PATH" + + SIGNATURE_PATH="tarballs/$repo-$tag.tar.gz.asc" + if git notes --ref=refs/notes/signatures/tar.gz show "$tag" \ + 1>/dev/null 2>&1; then + git notes --ref=refs/notes/signatures/tar.gz \ + show "$tag" > "$OUTDIR/$SIGNATURE_PATH" + fi + done + + wait +} + +print_repo_refs2() { + cat <<-EOF + all: $OUTDIR/refs.html + + $OUTDIR/refs.html: ALWAYS + ${TAB}$0 -x refs "$REPO" > \$@ + + EOF +} +exec_refs() { + repo_vars "$1" + cat <<-EOF + + + + + + + + + + + $(escape "$NAME") - $(escape "$MSG_TITLE_REFS") + + +
+
+ + + +
+

+ + $(escape "$NAME") + +

+

+ $(escape "$DESCRIPTION") +

+ + git clone $(escape "$CLONE_URL") + +
+
+ +
+
+
+ + + + + + + + + + + EOF + + for branch in $(git branch --format '%(refname:lstrip=2)'); do + sha="$(git rev-parse "$branch")" + cat < + + + + + +EOF + done + + cat < +
+ $(escape "$MSG_THEAD_BRANCH") + + $(escape "$MSG_THEAD_COMMITMSG") + + $(escape "$MSG_THEAD_AUTHOR") + + $(escape "$MSG_THEAD_DATE") +
+ + $(escape "$branch") + + + + $(escape "$(git log -1 --format=%s "$sha")") + + + $(escape "$(git log -1 --format=%an "$sha")") + + $(escape "$(git log -1 --format=%cd --date='format:%Y-%m:%d %H:%M' "$sha")") +
+EOF + PRINTED_TABLE_OPEN=false + + for tag in $(git tag | tac); do + if [ "$PRINTED_TABLE_OPEN" = false ]; then + PRINTED_TABLE_OPEN=true + cat < + + + + $(escape "$MSG_THEAD_TAG") + + + $(escape "$MSG_THEAD_AUTHOR") + + + $(escape "$MSG_THEAD_DATE") + + + + +EOF + fi + + if [ -e "$CACHE_DIR/tarballs/$repo-$tag.tar.gz.asc" ]; then + tarball_link="(tarball, + sig)" + else + tarball_link="(tarball)" + fi + + cat < + + + $(escape "$tag") + + $tarball_link + + + $(escape "$(git log -1 --format=%an "$tag")") + + + $(escape "$(git log -1 --format=%cd --date='format:%Y-%m:%d %H:%M' "$tag")") + + +EOF + done + + if [ "$PRINTED_TABLE_OPEN" = true ]; then + cat < + +EOF + fi + + cat < +
+
+

+ $MSG_ESCAPED_FOOTER_TEMPLATE +

+
+ + +EOF +} + +print_repo_refs() { + repo="$1" + description="$2" + cat < + + + + + + + + + + $(escape "$repo") - $(escape "$MSG_TITLE_REFS") + + +
+
+ + + +
+

+ + $(escape "$repo") + +

+

+ $(escape "$description") +

+ + git clone $(escape "$CLONE_URL") + +
+
+ +
+
+
+ + + + + + + + + + +EOF + + for branch in $(git branch --format '%(refname:lstrip=2)'); do + sha="$(git rev-parse "$branch")" + cat < + + + + + +EOF + done + + cat < +
+ $(escape "$MSG_THEAD_BRANCH") + + $(escape "$MSG_THEAD_COMMITMSG") + + $(escape "$MSG_THEAD_AUTHOR") + + $(escape "$MSG_THEAD_DATE") +
+ + $(escape "$branch") + + + + $(escape "$(git log -1 --format=%s "$sha")") + + + $(escape "$(git log -1 --format=%an "$sha")") + + $(escape "$(git log -1 --format=%cd --date='format:%Y-%m:%d %H:%M' "$sha")") +
+EOF + PRINTED_TABLE_OPEN=false + + for tag in $(git tag | tac); do + if [ "$PRINTED_TABLE_OPEN" = false ]; then + PRINTED_TABLE_OPEN=true + cat < + + + + $(escape "$MSG_THEAD_TAG") + + + $(escape "$MSG_THEAD_AUTHOR") + + + $(escape "$MSG_THEAD_DATE") + + + + +EOF + fi + + if [ -e "$CACHE_DIR/tarballs/$repo-$tag.tar.gz.asc" ]; then + tarball_link="(tarball, + sig)" + else + tarball_link="(tarball)" + fi + + cat < + + + $(escape "$tag") + + $tarball_link + + + $(escape "$(git log -1 --format=%an "$tag")") + + + $(escape "$(git log -1 --format=%cd --date='format:%Y-%m:%d %H:%M' "$tag")") + + +EOF + done + + if [ "$PRINTED_TABLE_OPEN" = true ]; then + cat < + +EOF + fi + + cat < +
+
+

+ $MSG_ESCAPED_FOOTER_TEMPLATE +

+
+ + +EOF +} + +print_formatted_diff() { + sha="$1" + previous_sha="$2" + printf '
'
+	# git show -p --stat "$sha"
+	escape "$(git show -p "$sha")" | awk \
+			-v SHA="$sha" -v PREVIOUS_SHA="$previous_sha" '
+		BEGIN {
+			diff_init = 0
+			diffl = 0
+		}
+
+		/^(diff|index) / {
+			diff_init = 1
+			print $0
+			next
+		}
+
+		diff_init == 1 && /^--- a\// {
+			fname = substr($0, 7)
+			printf "--- a/%s\n",
+				PREVIOUS_SHA, fname, fname
+			next
+		}
+
+		diff_init == 1 && /^\+\+\+ b\// {
+			fname = substr($0, 7)
+			printf "--- b/%s\n",
+				SHA, fname, fname
+			next
+		}
+
+		{ diff_init = 0 }
+
+		/^-/ {
+			diffl++
+			printf "%s\n",
+				diffl, diffl, $0
+			next
+		}
+
+		/^\+/ {
+			diffl++
+			printf "%s\n",
+			diffl, diffl, $0
+			next
+		}
+
+		{
+			print $0
+		}
+	'
+	printf '
\n' +} + +print_repo_commit_page() { + repo="$1" + description="$2" + sha="$3" + previous_sha="$(git rev-parse "$sha^" 2>/dev/null ||:)" + summary="$(git log -1 --format=%B "$sha")" + cat < + + + + + + + + + + $(escape "$repo")@$(escape "$sha") - $(escape "$summary") + + +
+
+ + + +
+

+ + $(escape "$repo") + +

+

+ $(escape "$description") +

+ + git clone $(escape "$CLONE_URL") + +
+
+ +
+
+
+$(print_formatted_diff "$sha" "$previous_sha") +
+
+
+

+ $MSG_ESCAPED_FOOTER_TEMPLATE +

+
+ + +EOF +} + +repo_commits_write() { + repo="$1" + description="$2" + mkdir -p "$OUTDIR/commit" "$CACHE_DIR/commit" + for branch in $(git branch --format '%(refname:lstrip=2)'); do + for commit in $(git rev-list "$branch"); do + COMMIT_PATH="commit/$commit.html" + + if [ -e "$OUTDIR/$COMMIT_PATH" ]; then + # Assume all previous history exists, too + break + fi + + cached_run "$COMMIT_PATH" -- \ + eval "print_repo_commit_page '$repo' '$description' '$commit' \ + > '$CACHE_DIR/$COMMIT_PATH'" + done + done + + wait +} + +NEWLINE="$(printf '\n')" +print_repo_log_page() { + repo="$1" + description="$2" + newer_page_name="$3" + older_page_name="$4" + shift + shift + shift + shift + + title='FIXME' + + if [ -z "$newer_page_name" ]; then + escaped_newer_page_link='' + else + escaped_newer_page_link=" newer FIXME i18n"' +' + fi + + if [ -z "$older_page_name" ]; then + escaped_older_page_link='' + else + escaped_older_page_link=" older FIXME i18n"' +' + fi + + if [ -n "$newer_page_name" ] || [ -n "$older_page_name" ]; then + escaped_pagination_open='
+' + escaped_pagination_close='
+' + else + escaped_pagination_open='' + escaped_pagination_close='' + fi + + if [ -n "$newer_page_name" ] && [ -n "$older_page_name" ]; then + escaped_pagination_separator=' | +' + else + escaped_pagination_separator='' + fi + + cat < + + + + + + + + + + $(escape "$repo") - $(escape "$title") + + +
+
+ + + +
+

+ + $(escape "$repo") + +

+

+ $(escape "$description") +

+ + git clone $(escape "$CLONE_URL") + +
+
+ +
+
+
+EOF + + for commit in "$@"; do + body_txt="$(git log -1 --format=%b "$commit")" + if [ "$body_txt" = "$NEWLINE" ]; then + body='' + else + body=" + +$body_txt" + fi + + notes_txt="$(git log -1 --format=%N "$commit")" + + if [ "$notes_txt" = "$NEWLINE" ]; then + escaped_notes='' + else + escaped_notes=" +
$(escape "$notes_txt")
" + fi + + # FIXME: show if commit is in branch, tag or HEAD + # HEAD + # main + # v0.2.1 + + cat < +

+ $(escape "$commit") + | + $(escape "$(git log -1 --format=%an "$commit")") +

+
$(escape "$(git log -1 --format=%s "$commit")")$(escape "$body")
$escaped_notes + +EOF + done + + cat < +
+
+

+ $MSG_ESCAPED_FOOTER_TEMPLATE +

+
+ + +EOF +} + +# FIXME: use log/main/1.html over diffs? +LOG_PAGE_MAX=50 +repo_log_write() { + repo="$1" + description="$2" + mkdir -p "$OUTDIR/log" "$CACHE_DIR/log" + for ref in $(git branch --format '%(refname:lstrip=2)') $(git tag); do + # FIXME: add bail out of loop when the first page already + # exists, so nothing after that needs to be ran + + mkdir -p "$CACHE_DIR/log_tmp/$ref" + PAGE_SIZE=0 + PAGE_INDEX=0 + for commit in $(git rev-list "$ref" | tac); do + if [ "$PAGE_SIZE" = 0 ]; then + FIRST="$commit" + fi + LAST="$commit" + PAGE_NAME="$FIRST..$LAST.html" + PAGE_SIZE=$((PAGE_SIZE + 1)) + + if [ "$PAGE_SIZE" != "$LOG_PAGE_MAX" ]; then + continue + fi + + echo "$PAGE_NAME" > "$CACHE_DIR/log_tmp/$ref/$PAGE_INDEX" + + PAGE_INDEX=$((PAGE_INDEX + 1)) + PAGE_SIZE=0 + done + if [ "$PAGE_SIZE" != 0 ]; then + echo "$PAGE_NAME" > "$CACHE_DIR/log_tmp/$ref/$PAGE_INDEX" + fi + + PAGE_COMMITS='' + PAGE_SIZE=0 + PAGE_INDEX=0 + for commit in $(git rev-list "$ref" | tac); do + PAGE_COMMITS="$commit $PAGE_COMMITS" + PAGE_SIZE=$((PAGE_SIZE + 1)) + + if [ "$PAGE_SIZE" != "$LOG_PAGE_MAX" ]; then + continue + fi + + # FIXME: 80 columns + NEWER_PAGE_NAME="$(cat "$CACHE_DIR/log_tmp/$ref/$((PAGE_INDEX + 1))" 2>/dev/null ||:)" + CURRT_PAGE_NAME="$(cat "$CACHE_DIR/log_tmp/$ref/$((PAGE_INDEX + 0))" 2>/dev/null ||:)" + OLDER_PAGE_NAME="$(cat "$CACHE_DIR/log_tmp/$ref/$((PAGE_INDEX - 1))" 2>/dev/null ||:)" + PAGE_PATH="log/$CURRT_PAGE_NAME" + + cached_run "$PAGE_PATH" -- eval "print_repo_log_page \ + '$repo' '$description' \ + '$NEWER_PAGE_NAME' '$OLDER_PAGE_NAME' \ + $PAGE_COMMITS \ + > '$CACHE_DIR/$PAGE_PATH'" + PAGE_COMMITS='' + PAGE_SIZE=0 + PAGE_INDEX=$((PAGE_INDEX + 1)) + done + if [ "$PAGE_SIZE" != 0 ]; then + # FIXME: 80 columns + NEWER_PAGE_NAME="$(cat "$CACHE_DIR/log_tmp/$ref/$((PAGE_INDEX + 1))" 2>/dev/null ||:)" + CURRT_PAGE_NAME="$(cat "$CACHE_DIR/log_tmp/$ref/$((PAGE_INDEX + 0))" 2>/dev/null ||:)" + OLDER_PAGE_NAME="$(cat "$CACHE_DIR/log_tmp/$ref/$((PAGE_INDEX - 1))" 2>/dev/null ||:)" + PAGE_PATH="log/$CURRT_PAGE_NAME" + + cached_run "$PAGE_PATH" -- eval "print_repo_log_page \ + '$repo' '$description' \ + '$NEWER_PAGE_NAME' '$OLDER_PAGE_NAME' \ + $PAGE_COMMITS \ + > '$CACHE_DIR/$PAGE_PATH'" + fi + ln -fs "$CURRT_PAGE_NAME" "$OUTDIR/log/$ref.html" + done + rm -rf "$CACHE_DIR/log_tmp" + + wait +} + +print_repo_index_page() { + repo="$1" + description="$2" + + cat < + + + + + + + + + + $(escape "$repo") - FIXME + + +
+
+ + + +
+

+ + $(escape "$repo") + +

+

+ $(escape "$description") +

+ + git clone $(escape "$CLONE_URL") + +
+
+ +
+
+
+
+ Os arquivos vão aqui. +
+
+ O README vai aqui. +
+
+
+
+

+ $MSG_ESCAPED_FOOTER_TEMPLATE +

+
+ + +EOF +} + +repo_trees_write() { + echo +} + +preamble() { + cat <<-EOF + .POSIX: + + LN = $CMD + + default: all + + ALWAYS: + + + EOF +} + +repo_vars() { + EXT=tar.xz + REPO_DIR="${1%/}" + REPO="${1%/}" # FIXME: shesc + NAME="$(basename "$REPO" .git)" + CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/gistatic/$NAME" + GIT_DIR="$REPO/$(git -C "$REPO" rev-parse --git-dir)" + export GIT_DIR + DESCRIPTION="$(cat "$GIT_DIR"/description 2>/dev/null ||:)" +} + +repo_write2() { + repo_vars "$1" + mkdir -p \ + "$OUTDIR"/tarballs \ + "$CACHE_DIR"/tarballs \ + "$CACHE_DIR"/branch-revisions + { + preamble + repo_tarballs_write2 + print_repo_refs2 + } | tee f | make -f- +} + +repo_write() { + cd "$1" + # FIXME: use $REPO and $DESCRIPTION + repo="$(basename "$(realpath "${1%.git}")")" + description="$(cat "$1/description" 2>/dev/null ||:)" + CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/gistatic/$repo" + + repo_tarballs_write "$repo" + print_repo_refs "$repo" "$description" > "$OUTDIR/refs.html" + repo_commits_write "$repo" "$description" + repo_log_write "$repo" "$description" + print_repo_index_page "$repo" "$description" > "$OUTDIR/index.html" + repo_trees_write "$repo" "$description" + + cd - > /dev/null +} + + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + --version) + version + exit + ;; + *) + ;; + esac +done + +VERBOSE=true +INDEX=false +TITLE="$MSG_DEFAULT_TITLE" +OUTDIR= +CLONE_URL= +CACHE_DIR= +MAX_JOBS=1 +MAIN_BRANCH='main' +MAIN_BRANCH_SET=false +REPO= +DESCRIPTION= +CMD='ln' +EXEC= +while getopts 'b:o:t:u:j:isqx:hV' flag; do + case "$flag" in + b) + MAIN_BRANCH="$OPTARG" + MAIN_BRANCH_SET=true + ;; + o) + OUTDIR="$(realpath "$OPTARG")" + ;; + t) + TITLE="$OPTARG" + ;; + u) + CLONE_URL="$OPTARG" + ;; + j) + MAX_JOBS="$OPTARG" + ;; + i) + INDEX=true + ;; + q) + VERBOSE=false + ;; + s) + CMD='ln -s' + ;; + x) + EXEC="$OPTARG" + ;; + h) + usage + help + exit + ;; + V) + version + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +assert_arg() { + if [ -z "$1" ]; then + printf "$MSG_MISSING_CLIARG\n\n" "$2" >&2 + usage >&2 + exit 2 + fi +} + +if [ -n "$EXEC" ]; then + "exec_$EXEC" "$@" + exit +fi +assert_arg "$OUTDIR" '-o DIRECTORY' + +if [ "$INDEX" = false ]; then + assert_arg "$CLONE_URL" '-u CLONE_URL' +elif [ -n "$CLONE_URL" ] || [ "$MAIN_BRANCH_SET" = true ]; then + { + printf '%s' "$MSG_INCOMPATIBLE_OPTIONS" + printf -- '-i' + if [ -n "$CLONE_URL" ]; then + printf -- ' -u' + fi + if [ "$MAIN_BRANCH_SET" = true ]; then + printf -- ' -b' + fi + printf '\n\n' + + usage + } >&2 + exit 2 +fi + +assert_arg "${1:-}" "$MSG_MISSING_ARGS" + +mkdir -p "$OUTDIR" + +if [ "$INDEX" = true ]; then + index_write "$@" +else + # repo_write "$1" + repo_write2 "$1" +fi diff --git a/src/gistatic.in b/src/gistatic.in deleted file mode 100755 index fec517a..0000000 --- a/src/gistatic.in +++ /dev/null @@ -1,1576 +0,0 @@ -#!/bin/sh -# shellcheck disable=2034 disable=2059 -# FIXME: remove these ^^^ -set -eu - -MSG_USAGE_EN='Usage: - gistatic -i -o DIRECTORY REPOSITORY... - gistatic -o DIRECTORY -u CLONE_URL [-b MAIN_BRANCH] REPOSITORY - gistatic [-hV]' - -MSG_HELP_EN=' -Options: - -i build the index page of the repositories - -u CLONE_URL address to be shown alongside "git clone" - -o DIRECTORY output where to place the generated files - -b MAIN_BRANCH the default branch of the repository (default: main) - -h, --help show this help - -V, --version print the version information - -See "man gistatic" for more information.' - -MSG_MISSING_CLIARG_EN='Missing %s' -MSG_INCOMPATIBLE_OPTIONS_EN='Incompatible options: ' -MSG_MISSING_ARGS_EN='REPOSITORY' -MSG_LANGNAME_EN='en' -MSG_INDEX_DESCRIPTION_EN='Index of repositories' -MSG_DEFAULT_TITLE_EN='Repositories' -MSG_LOGO_ALT_INDEX_EN='Logo image of the repository list' -MSG_LOGO_ALT_REPOSITORY_EN='Logo image of the repository' -MSG_NAME_EN='Name' -MSG_DESCRIPTION_EN='Description' -MSG_LAST_COMMIT_EN='Last commit' -MSG_COMMIT_FEED_EN='commit feed' -MSG_TAGS_FEED_EN='tags feed' -MSG_NAV_FILES_EN='files' -MSG_NAV_LOG_EN='log' -MSG_NAV_REFS_EN='refs' -MSG_THEAD_BRANCH_EN='Branch' -MSG_THEAD_COMMITMSG_EN='Commit message' -MSG_THEAD_AUTHOR_EN='Author' -MSG_THEAD_DATE_EN='Date' -MSG_THEAD_TAG_EN='Tag' -MSG_TITLE_REFS_EN='refs' -MSG_GENERATING_LOG_EN='Generating %s...' - -# HTML escaped messages -MSG_ESCAPED_FOOTER_TEMPLATE_EN='Generated with gistatic.' - -set_lang() { - lang="$1" - eval " - MSG_USAGE=\$MSG_USAGE_$lang - MSG_HELP=\$MSG_HELP_$lang - MSG_MISSING_CLIARG=\$MSG_MISSING_CLIARG_$lang - MSG_INCOMPATIBLE_OPTIONS=\$MSG_INCOMPATIBLE_OPTIONS_$lang - MSG_MISSING_ARGS=\$MSG_MISSING_ARGS_$lang - MSG_LANGNAME=\$MSG_LANGNAME_$lang - MSG_INDEX_DESCRIPTION=\$MSG_INDEX_DESCRIPTION_$lang - MSG_DEFAULT_TITLE=\$MSG_DEFAULT_TITLE_$lang - MSG_LOGO_ALT_INDEX=\$MSG_LOGO_ALT_INDEX_$lang - MSG_LOGO_ALT_REPOSITORY=\$MSG_LOGO_ALT_REPOSITORY_$lang - MSG_NAME=\$MSG_NAME_$lang - MSG_DESCRIPTION=\$MSG_DESCRIPTION_$lang - MSG_LAST_COMMIT=\$MSG_LAST_COMMIT_$lang - MSG_COMMIT_FEED=\$MSG_COMMIT_FEED_$lang - MSG_TAGS_FEED=\$MSG_TAGS_FEED_$lang - MSG_NAV_FILES=\$MSG_NAV_FILES_$lang - MSG_NAV_LOG=\$MSG_NAV_LOG_$lang - MSG_NAV_REFS=\$MSG_NAV_REFS_$lang - MSG_THEAD_BRANCH=\$MSG_THEAD_BRANCH_$lang - MSG_THEAD_COMMITMSG=\$MSG_THEAD_COMMITMSG_$lang - MSG_THEAD_AUTHOR=\$MSG_THEAD_AUTHOR_$lang - MSG_THEAD_DATE=\$MSG_THEAD_DATE_$lang - MSG_THEAD_TAG=\$MSG_THEAD_TAG_$lang - MSG_TITLE_REFS=\$MSG_TITLE_REFS_$lang - MSG_GENERATING_LOG=\$MSG_GENERATING_LOG_$lang - - MSG_ESCAPED_FOOTER_TEMPLATE=\$MSG_ESCAPED_FOOTER_TEMPLATE_$lang -" -} - -get_lang() { - # LC_MESSAGES="ll_CC.CODESET@modifier" -> ll_CC, where quotes - # are optional - locale 2>/dev/null | - grep ^LC_MESSAGES | - cut -d. -f1 | - cut -d\" -f2 | - cut -d= -f2 -} - -case "$(get_lang)" in - *) - set_lang EN - ;; -esac - - -# -# Utilities -# - -tac() { - sed '1!G;h;$!d' -} - -escape() { - printf '%s' "$1" | - sed \ - -e 's|&|\&|g' \ - -e 's|<|\<|g' \ - -e 's|>|\>|g' \ - -e 's|"|\"|g' \ - -e "s|'|\'|g" -} - -realpath() { - mkdir -p "$1" - cd "$1" - pwd -} - - -# -# Documentation functions -# - -usage() { - printf '%s\n' "$MSG_USAGE" -} - -help() { - printf '%s\n' "$MSG_HELP" -} - -version() { - printf 'gistatic-0.1.0 1970-01-01\n' -} - - -# -# Template strings -# - -print_logo() { - cat <<-'EOF' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EOF -} - -print_style() { - cat <<-'EOF' - :root { - --color: black; - --background-color: white; - --background-contrast-color: hsl(0, 0%, 98%); - --hover-color: hsl(0, 0%, 93%); - --nav-color: hsl(0, 0%, 87%); - --selected-color: hsl(0, 0%, 80%); - --diff-added-color: hsl(120, 100%, 23%); - --diff-removed-color: hsl(0, 100%, 47%); - } - - @media(prefers-color-scheme: dark) { - :root { - --color: white; - --background-color: black; - --background-contrast-color: hsl(0, 0%, 2%); - --hover-color: hsl(0, 0%, 7%); - --nav-color: hsl(0, 0%, 13%); - --selected-color: hsl(0, 0%, 20%); - } - - body { - color: var(--color); - background-color: var(--background-color); - } - - a { - color: hsl(211, 100%, 60%); - } - - a:visited { - color: hsl(242, 100%, 80%); - } - } - - body { - font-family: monospace; - max-width: 1100px; - margin: 0 auto 0 auto; - } - - .logo { - height: 6em; - width: 6em; - } - - .header-horizontal-grouping { - display: flex; - align-items: center; - margin-top: 1em; - margin-bottom: 1em; - } - - .header-description { - margin-left: 2em; - } - - nav { - margin-top: 2em; - } - - nav ul { - display: flex; - list-style-type: none; - margin-bottom: 0; - } - - nav li { - margin-left: 10px; - } - - nav a, nav a:visited { - padding: 2px 8px 0px 8px; - color: var(--color); - } - - .selected-nav-item { - background-color: var(--nav-color); - } - - hr { - margin-top: 0; - border: 0; - border-top: 3px solid var(--nav-color); - } - - table { - margin: 2em auto; - } - - th { - padding-bottom: 1em; - } - - tbody tr:hover { - background-color: var(--hover-color); - } - - td { - padding-left: 1em; - padding-right: 1em; - } - - - /* commit page */ - - .diff-added, .diff-removed { - text-decoration: none; - } - - .diff-added:target, .diff-removed:target { - background-color: var(--selected-color); - } - - .diff-added, .diff-added:visited { - color: var(--diff-added-color); - } - - .diff-removed, .diff-removed:visited { - color: var(--diff-removed-color); - } - - - /* log page */ - - .log-commit-box { - padding: 1em; - margin: 1em; - background-color: var(--background-contrast-color); - } - - .log-commit-tag { - padding: 2px; - border: 1px solid; - color: var(--color); - } - - .log-head-highlight { - background-color: #ff8888; /* FIXME: hsl + dark-mode */ - } - - .log-branch-highlight { - background-color: #88ff88; /* FIXME: hsl + dark-mode */ - } - - .log-tag-highlight { - background-color: #ffff88; /* FIXME: hsl + dark-mode */ - } - - .pre-wrapping { - overflow: auto; - margin: 1em; - } - - .log-notes { - /* FIXME: yellow box goes until the end of the screen */ - padding: 1em; - background-color: #ffd; /* FIXME: hsl + dark-mode */ - } - - .log-pagination { - text-align: center; - margin: 2em; - } - - - footer { - text-align: center; - } - EOF -} - -print_index_header() { - cat <<-EOF - - - - - - - - - $(escape "$TITLE") - - -
-
- $(escape -

- $(escape "$TITLE") -

-
-
-
-
- - - - - - - - - -EOF -} - -print_index_row() { - repo="$(basename "$(realpath "${1%.git}")")" - description="$(cat "$1/description" 2>/dev/null ||:)" - last_commit_date="$(git -C "$1" log -1 --format=%cd --date='format:%Y-%m:%d %H:%M' 2>/dev/null ||:)" - cat <<-EOF - - - - - - EOF -} - -print_index_footer() { - cat <<-EOF - -
- $(escape "$MSG_NAME") - - $(escape "$MSG_DESCRIPTION") - - $(escape "$MSG_LAST_COMMIT") -
- - $(escape "$repo") - - - $(escape "$description") - - $(escape "$last_commit_date") -
-
-
-
-

- $MSG_ESCAPED_FOOTER_TEMPLATE -

-
- - - EOF -} - -index_write() { - { - print_index_header - for r in "$@"; do - print_index_row "$r" - done - print_index_footer - } > "$OUTDIR/index.html" - - print_logo > "$OUTDIR/logo.svg" - print_style > "$OUTDIR/style.css" -} - -genlog() { - if [ "$VERBOSE" = true ]; then - printf "$MSG_GENERATING_LOG\n" "$1" >&2 - fi -} - -parallel_n=0 -cached_run() { - TARGET_PATH="$1" - shift # drop $TARGET_PATH - shift # drop -- - - if [ -e "$OUTDIR/$TARGET_PATH" ]; then - return - fi - - if [ -e "$CACHE_DIR/$TARGET_PATH" ]; then - $CMD "$CACHE_DIR/$TARGET_PATH" "$OUTDIR/$TARGET_PATH" - else - { - genlog "$OUTDIR/$TARGET_PATH" - "$@" - $CMD "$CACHE_DIR/$TARGET_PATH" "$OUTDIR/$TARGET_PATH" - } & - parallel_n=$((parallel_n + 1)) - if [ "$parallel_n" = "$MAX_JOBS" ]; then - wait - parallel_n=0 - fi - fi -} - -# FIXME: get from config? -# exts() { } - -# FIXME: emit signatures code -TAB="$(printf '\t')" -repo_tarballs_write2() { - git branch --format '%(refname:lstrip=2)' | while read -r branch; do - cat <<-EOF - all: $OUTDIR/tarballs/$NAME-$branch.$EXT - - $OUTDIR/tarballs/$NAME-$branch.$EXT: $CACHE_DIR/tarballs/$NAME-$branch.$EXT - ${TAB}\$(LN) \$? \$@ - - $CACHE_DIR/tarballs/$NAME-$branch.$EXT: $CACHE_DIR/branch-revisions/$branch - ${TAB}git -C "$REPO" archive --prefix $NAME-$branch/ -o \$@ $branch - - $CACHE_DIR/branch-revisions/$branch: ALWAYS - ${TAB}@git -C "$REPO" rev-parse $branch | ifnew \$@ - - EOF - done - - git tag | while read -r tag; do - cat <<-EOF - all: $OUTDIR/tarballs/$NAME-$tag.$EXT - - $OUTDIR/tarballs/$NAME-$tag.$EXT: $CACHE_DIR/tarballs/$NAME-$tag.$EXT - ${TAB}\$(LN) \$? \$@ - - $CACHE_DIR/tarballs/$NAME-$tag.$EXT: - ${TAB}git -C "$REPO" archive --prefix $NAME-$tag/ -o \$@ $tag - - EOF - done -} - -repo_tarballs_write() { - repo="$1" - mkdir -p "$OUTDIR/tarballs" "$CACHE_DIR/tarballs" - local_parallel_n=0 - for branch in $(git branch --format '%(refname:lstrip=2)'); do - TARBALL_PATH="$OUTDIR/tarballs/$repo-$branch.tar.gz" - genlog "$TARBALL_PATH" - git archive --prefix "$repo-$branch/" "$branch" \ - -o "$TARBALL_PATH" & - local_parallel_n=$((local_parallel_n + 1)) - if [ "$local_parallel_n" = "$MAX_JOBS" ]; then - wait - local_parallel_n=0 - fi - done - wait - - for tag in $(git tag); do - TARBALL_PATH="tarballs/$repo-$tag.tar.gz" - cached_run "$TARBALL_PATH" -- \ - git archive --prefix "$repo-$tag/" "$tag" \ - -o "$CACHE_DIR/$TARBALL_PATH" - - SIGNATURE_PATH="tarballs/$repo-$tag.tar.gz.asc" - if git notes --ref=refs/notes/signatures/tar.gz show "$tag" \ - 1>/dev/null 2>&1; then - git notes --ref=refs/notes/signatures/tar.gz \ - show "$tag" > "$OUTDIR/$SIGNATURE_PATH" - fi - done - - wait -} - -print_repo_refs2() { - cat <<-EOF - all: $OUTDIR/refs.html - - $OUTDIR/refs.html: ALWAYS - ${TAB}$0 -x refs "$REPO" > \$@ - - EOF -} -exec_refs() { - repo_vars "$1" - cat <<-EOF - - - - - - - - - - - $(escape "$NAME") - $(escape "$MSG_TITLE_REFS") - - -
-
- - - -
-

- - $(escape "$NAME") - -

-

- $(escape "$DESCRIPTION") -

- - git clone $(escape "$CLONE_URL") - -
-
- -
-
-
- - - - - - - - - - - EOF - - for branch in $(git branch --format '%(refname:lstrip=2)'); do - sha="$(git rev-parse "$branch")" - cat < - - - - - -EOF - done - - cat < -
- $(escape "$MSG_THEAD_BRANCH") - - $(escape "$MSG_THEAD_COMMITMSG") - - $(escape "$MSG_THEAD_AUTHOR") - - $(escape "$MSG_THEAD_DATE") -
- - $(escape "$branch") - - - - $(escape "$(git log -1 --format=%s "$sha")") - - - $(escape "$(git log -1 --format=%an "$sha")") - - $(escape "$(git log -1 --format=%cd --date='format:%Y-%m:%d %H:%M' "$sha")") -
-EOF - PRINTED_TABLE_OPEN=false - - for tag in $(git tag | tac); do - if [ "$PRINTED_TABLE_OPEN" = false ]; then - PRINTED_TABLE_OPEN=true - cat < - - - - $(escape "$MSG_THEAD_TAG") - - - $(escape "$MSG_THEAD_AUTHOR") - - - $(escape "$MSG_THEAD_DATE") - - - - -EOF - fi - - if [ -e "$CACHE_DIR/tarballs/$repo-$tag.tar.gz.asc" ]; then - tarball_link="(tarball, - sig)" - else - tarball_link="(tarball)" - fi - - cat < - - - $(escape "$tag") - - $tarball_link - - - $(escape "$(git log -1 --format=%an "$tag")") - - - $(escape "$(git log -1 --format=%cd --date='format:%Y-%m:%d %H:%M' "$tag")") - - -EOF - done - - if [ "$PRINTED_TABLE_OPEN" = true ]; then - cat < - -EOF - fi - - cat < -
-
-

- $MSG_ESCAPED_FOOTER_TEMPLATE -

-
- - -EOF -} - -print_repo_refs() { - repo="$1" - description="$2" - cat < - - - - - - - - - - $(escape "$repo") - $(escape "$MSG_TITLE_REFS") - - -
-
- - - -
-

- - $(escape "$repo") - -

-

- $(escape "$description") -

- - git clone $(escape "$CLONE_URL") - -
-
- -
-
-
- - - - - - - - - - -EOF - - for branch in $(git branch --format '%(refname:lstrip=2)'); do - sha="$(git rev-parse "$branch")" - cat < - - - - - -EOF - done - - cat < -
- $(escape "$MSG_THEAD_BRANCH") - - $(escape "$MSG_THEAD_COMMITMSG") - - $(escape "$MSG_THEAD_AUTHOR") - - $(escape "$MSG_THEAD_DATE") -
- - $(escape "$branch") - - - - $(escape "$(git log -1 --format=%s "$sha")") - - - $(escape "$(git log -1 --format=%an "$sha")") - - $(escape "$(git log -1 --format=%cd --date='format:%Y-%m:%d %H:%M' "$sha")") -
-EOF - PRINTED_TABLE_OPEN=false - - for tag in $(git tag | tac); do - if [ "$PRINTED_TABLE_OPEN" = false ]; then - PRINTED_TABLE_OPEN=true - cat < - - - - $(escape "$MSG_THEAD_TAG") - - - $(escape "$MSG_THEAD_AUTHOR") - - - $(escape "$MSG_THEAD_DATE") - - - - -EOF - fi - - if [ -e "$CACHE_DIR/tarballs/$repo-$tag.tar.gz.asc" ]; then - tarball_link="(tarball, - sig)" - else - tarball_link="(tarball)" - fi - - cat < - - - $(escape "$tag") - - $tarball_link - - - $(escape "$(git log -1 --format=%an "$tag")") - - - $(escape "$(git log -1 --format=%cd --date='format:%Y-%m:%d %H:%M' "$tag")") - - -EOF - done - - if [ "$PRINTED_TABLE_OPEN" = true ]; then - cat < - -EOF - fi - - cat < -
-
-

- $MSG_ESCAPED_FOOTER_TEMPLATE -

-
- - -EOF -} - -print_formatted_diff() { - sha="$1" - previous_sha="$2" - printf '
'
-	# git show -p --stat "$sha"
-	escape "$(git show -p "$sha")" | awk \
-			-v SHA="$sha" -v PREVIOUS_SHA="$previous_sha" '
-		BEGIN {
-			diff_init = 0
-			diffl = 0
-		}
-
-		/^(diff|index) / {
-			diff_init = 1
-			print $0
-			next
-		}
-
-		diff_init == 1 && /^--- a\// {
-			fname = substr($0, 7)
-			printf "--- a/%s\n",
-				PREVIOUS_SHA, fname, fname
-			next
-		}
-
-		diff_init == 1 && /^\+\+\+ b\// {
-			fname = substr($0, 7)
-			printf "--- b/%s\n",
-				SHA, fname, fname
-			next
-		}
-
-		{ diff_init = 0 }
-
-		/^-/ {
-			diffl++
-			printf "%s\n",
-				diffl, diffl, $0
-			next
-		}
-
-		/^\+/ {
-			diffl++
-			printf "%s\n",
-			diffl, diffl, $0
-			next
-		}
-
-		{
-			print $0
-		}
-	'
-	printf '
\n' -} - -print_repo_commit_page() { - repo="$1" - description="$2" - sha="$3" - previous_sha="$(git rev-parse "$sha^" 2>/dev/null ||:)" - summary="$(git log -1 --format=%B "$sha")" - cat < - - - - - - - - - - $(escape "$repo")@$(escape "$sha") - $(escape "$summary") - - -
-
- - - -
-

- - $(escape "$repo") - -

-

- $(escape "$description") -

- - git clone $(escape "$CLONE_URL") - -
-
- -
-
-
-$(print_formatted_diff "$sha" "$previous_sha") -
-
-
-

- $MSG_ESCAPED_FOOTER_TEMPLATE -

-
- - -EOF -} - -repo_commits_write() { - repo="$1" - description="$2" - mkdir -p "$OUTDIR/commit" "$CACHE_DIR/commit" - for branch in $(git branch --format '%(refname:lstrip=2)'); do - for commit in $(git rev-list "$branch"); do - COMMIT_PATH="commit/$commit.html" - - if [ -e "$OUTDIR/$COMMIT_PATH" ]; then - # Assume all previous history exists, too - break - fi - - cached_run "$COMMIT_PATH" -- \ - eval "print_repo_commit_page '$repo' '$description' '$commit' \ - > '$CACHE_DIR/$COMMIT_PATH'" - done - done - - wait -} - -NEWLINE="$(printf '\n')" -print_repo_log_page() { - repo="$1" - description="$2" - newer_page_name="$3" - older_page_name="$4" - shift - shift - shift - shift - - title='FIXME' - - if [ -z "$newer_page_name" ]; then - escaped_newer_page_link='' - else - escaped_newer_page_link=" newer FIXME i18n"' -' - fi - - if [ -z "$older_page_name" ]; then - escaped_older_page_link='' - else - escaped_older_page_link=" older FIXME i18n"' -' - fi - - if [ -n "$newer_page_name" ] || [ -n "$older_page_name" ]; then - escaped_pagination_open='
-' - escaped_pagination_close='
-' - else - escaped_pagination_open='' - escaped_pagination_close='' - fi - - if [ -n "$newer_page_name" ] && [ -n "$older_page_name" ]; then - escaped_pagination_separator=' | -' - else - escaped_pagination_separator='' - fi - - cat < - - - - - - - - - - $(escape "$repo") - $(escape "$title") - - -
-
- - - -
-

- - $(escape "$repo") - -

-

- $(escape "$description") -

- - git clone $(escape "$CLONE_URL") - -
-
- -
-
-
-EOF - - for commit in "$@"; do - body_txt="$(git log -1 --format=%b "$commit")" - if [ "$body_txt" = "$NEWLINE" ]; then - body='' - else - body=" - -$body_txt" - fi - - notes_txt="$(git log -1 --format=%N "$commit")" - - if [ "$notes_txt" = "$NEWLINE" ]; then - escaped_notes='' - else - escaped_notes=" -
$(escape "$notes_txt")
" - fi - - # FIXME: show if commit is in branch, tag or HEAD - # HEAD - # main - # v0.2.1 - - cat < -

- $(escape "$commit") - | - $(escape "$(git log -1 --format=%an "$commit")") -

-
$(escape "$(git log -1 --format=%s "$commit")")$(escape "$body")
$escaped_notes - -EOF - done - - cat < -
-
-

- $MSG_ESCAPED_FOOTER_TEMPLATE -

-
- - -EOF -} - -# FIXME: use log/main/1.html over diffs? -LOG_PAGE_MAX=50 -repo_log_write() { - repo="$1" - description="$2" - mkdir -p "$OUTDIR/log" "$CACHE_DIR/log" - for ref in $(git branch --format '%(refname:lstrip=2)') $(git tag); do - # FIXME: add bail out of loop when the first page already - # exists, so nothing after that needs to be ran - - mkdir -p "$CACHE_DIR/log_tmp/$ref" - PAGE_SIZE=0 - PAGE_INDEX=0 - for commit in $(git rev-list "$ref" | tac); do - if [ "$PAGE_SIZE" = 0 ]; then - FIRST="$commit" - fi - LAST="$commit" - PAGE_NAME="$FIRST..$LAST.html" - PAGE_SIZE=$((PAGE_SIZE + 1)) - - if [ "$PAGE_SIZE" != "$LOG_PAGE_MAX" ]; then - continue - fi - - echo "$PAGE_NAME" > "$CACHE_DIR/log_tmp/$ref/$PAGE_INDEX" - - PAGE_INDEX=$((PAGE_INDEX + 1)) - PAGE_SIZE=0 - done - if [ "$PAGE_SIZE" != 0 ]; then - echo "$PAGE_NAME" > "$CACHE_DIR/log_tmp/$ref/$PAGE_INDEX" - fi - - PAGE_COMMITS='' - PAGE_SIZE=0 - PAGE_INDEX=0 - for commit in $(git rev-list "$ref" | tac); do - PAGE_COMMITS="$commit $PAGE_COMMITS" - PAGE_SIZE=$((PAGE_SIZE + 1)) - - if [ "$PAGE_SIZE" != "$LOG_PAGE_MAX" ]; then - continue - fi - - # FIXME: 80 columns - NEWER_PAGE_NAME="$(cat "$CACHE_DIR/log_tmp/$ref/$((PAGE_INDEX + 1))" 2>/dev/null ||:)" - CURRT_PAGE_NAME="$(cat "$CACHE_DIR/log_tmp/$ref/$((PAGE_INDEX + 0))" 2>/dev/null ||:)" - OLDER_PAGE_NAME="$(cat "$CACHE_DIR/log_tmp/$ref/$((PAGE_INDEX - 1))" 2>/dev/null ||:)" - PAGE_PATH="log/$CURRT_PAGE_NAME" - - cached_run "$PAGE_PATH" -- eval "print_repo_log_page \ - '$repo' '$description' \ - '$NEWER_PAGE_NAME' '$OLDER_PAGE_NAME' \ - $PAGE_COMMITS \ - > '$CACHE_DIR/$PAGE_PATH'" - PAGE_COMMITS='' - PAGE_SIZE=0 - PAGE_INDEX=$((PAGE_INDEX + 1)) - done - if [ "$PAGE_SIZE" != 0 ]; then - # FIXME: 80 columns - NEWER_PAGE_NAME="$(cat "$CACHE_DIR/log_tmp/$ref/$((PAGE_INDEX + 1))" 2>/dev/null ||:)" - CURRT_PAGE_NAME="$(cat "$CACHE_DIR/log_tmp/$ref/$((PAGE_INDEX + 0))" 2>/dev/null ||:)" - OLDER_PAGE_NAME="$(cat "$CACHE_DIR/log_tmp/$ref/$((PAGE_INDEX - 1))" 2>/dev/null ||:)" - PAGE_PATH="log/$CURRT_PAGE_NAME" - - cached_run "$PAGE_PATH" -- eval "print_repo_log_page \ - '$repo' '$description' \ - '$NEWER_PAGE_NAME' '$OLDER_PAGE_NAME' \ - $PAGE_COMMITS \ - > '$CACHE_DIR/$PAGE_PATH'" - fi - ln -fs "$CURRT_PAGE_NAME" "$OUTDIR/log/$ref.html" - done - rm -rf "$CACHE_DIR/log_tmp" - - wait -} - -print_repo_index_page() { - repo="$1" - description="$2" - - cat < - - - - - - - - - - $(escape "$repo") - FIXME - - -
-
- - - -
-

- - $(escape "$repo") - -

-

- $(escape "$description") -

- - git clone $(escape "$CLONE_URL") - -
-
- -
-
-
-
- Os arquivos vão aqui. -
-
- O README vai aqui. -
-
- - - -EOF -} - -repo_trees_write() { - echo -} - -preamble() { - cat <<-EOF - .POSIX: - - LN = $CMD - - default: all - - ALWAYS: - - - EOF -} - -repo_vars() { - EXT=tar.xz - REPO_DIR="${1%/}" - REPO="${1%/}" # FIXME: shesc - NAME="$(basename "$REPO" .git)" - CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/gistatic/$NAME" - GIT_DIR="$REPO/$(git -C "$REPO" rev-parse --git-dir)" - export GIT_DIR - DESCRIPTION="$(cat "$GIT_DIR"/description 2>/dev/null ||:)" -} - -repo_write2() { - repo_vars "$1" - mkdir -p \ - "$OUTDIR"/tarballs \ - "$CACHE_DIR"/tarballs \ - "$CACHE_DIR"/branch-revisions - { - preamble - repo_tarballs_write2 - print_repo_refs2 - } | tee f | make -f- -} - -repo_write() { - cd "$1" - # FIXME: use $REPO and $DESCRIPTION - repo="$(basename "$(realpath "${1%.git}")")" - description="$(cat "$1/description" 2>/dev/null ||:)" - CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/gistatic/$repo" - - repo_tarballs_write "$repo" - print_repo_refs "$repo" "$description" > "$OUTDIR/refs.html" - repo_commits_write "$repo" "$description" - repo_log_write "$repo" "$description" - print_repo_index_page "$repo" "$description" > "$OUTDIR/index.html" - repo_trees_write "$repo" "$description" - - cd - > /dev/null -} - - -for flag in "$@"; do - case "$flag" in - --) - break - ;; - --help) - usage - help - exit - ;; - --version) - version - exit - ;; - *) - ;; - esac -done - -VERBOSE=true -INDEX=false -TITLE="$MSG_DEFAULT_TITLE" -OUTDIR= -CLONE_URL= -CACHE_DIR= -MAX_JOBS=1 -MAIN_BRANCH='main' -MAIN_BRANCH_SET=false -REPO= -DESCRIPTION= -CMD='ln' -EXEC= -while getopts 'b:o:t:u:j:isqx:hV' flag; do - case "$flag" in - b) - MAIN_BRANCH="$OPTARG" - MAIN_BRANCH_SET=true - ;; - o) - OUTDIR="$(realpath "$OPTARG")" - ;; - t) - TITLE="$OPTARG" - ;; - u) - CLONE_URL="$OPTARG" - ;; - j) - MAX_JOBS="$OPTARG" - ;; - i) - INDEX=true - ;; - q) - VERBOSE=false - ;; - s) - CMD='ln -s' - ;; - x) - EXEC="$OPTARG" - ;; - h) - usage - help - exit - ;; - V) - version - exit - ;; - *) - usage >&2 - exit 2 - ;; - esac -done -shift $((OPTIND - 1)) - -assert_arg() { - if [ -z "$1" ]; then - printf "$MSG_MISSING_CLIARG\n\n" "$2" >&2 - usage >&2 - exit 2 - fi -} - -if [ -n "$EXEC" ]; then - "exec_$EXEC" "$@" - exit -fi -assert_arg "$OUTDIR" '-o DIRECTORY' - -if [ "$INDEX" = false ]; then - assert_arg "$CLONE_URL" '-u CLONE_URL' -elif [ -n "$CLONE_URL" ] || [ "$MAIN_BRANCH_SET" = true ]; then - { - printf '%s' "$MSG_INCOMPATIBLE_OPTIONS" - printf -- '-i' - if [ -n "$CLONE_URL" ]; then - printf -- ' -u' - fi - if [ "$MAIN_BRANCH_SET" = true ]; then - printf -- ' -b' - fi - printf '\n\n' - - usage - } >&2 - exit 2 -fi - -assert_arg "${1:-}" "$MSG_MISSING_ARGS" - -mkdir -p "$OUTDIR" - -if [ "$INDEX" = true ]; then - index_write "$@" -else - # repo_write "$1" - repo_write2 "$1" -fi -- cgit v1.2.3