commit 38efdca5e160c227e670152298c44e2a0dff4ad8
parent 270090df88dbda257d7636a791b308a1a31b5079
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri, 1 Feb 2019 12:11:18 +0100
add tool to quickly test wiki patches and generate a status overview
Diffstat:
A | testpatches.sh | | | 329 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 329 insertions(+), 0 deletions(-)
diff --git a/testpatches.sh b/testpatches.sh
@@ -0,0 +1,329 @@
+#!/bin/sh
+# TODO:
+# ? git clone --bare for project repos.
+# ? build:
+# - set flags per project? (per version too?).
+# - add build status (OK, FAIL, unknown), must be secure though.
+
+projects() {
+cat <<!__EOF__
+dmenu tools.suckless.org/dmenu/patches
+dwm dwm.suckless.org/patches
+ii tools.suckless.org/ii/patches
+sent tools.suckless.org/sent/patches
+sic tools.suckless.org/sic/patches
+slock tools.suckless.org/slock/patches
+st st.suckless.org/patches
+surf surf.suckless.org/patches
+tabbed tools.suckless.org/tabbed/patches
+!__EOF__
+}
+
+wikidir="$HOME/tmp/sites"
+repodir="$(pwd)/repos"
+revdir="$(pwd)/rev"
+resultsdir="$(pwd)/results"
+builddir="$(pwd)/build"
+
+# dryrun patch command (OpenBSD).
+# must be unified diff (-u, so no ed script), -t and -C are dryrun (non-POSIX).
+dryrun="patch -u -p1 -t -C"
+
+# getdateutc()
+getdateutc() {
+ # date as UTC+0 time.
+ TZ="UTC+0" date
+}
+
+# log(s)
+log() {
+ s="[$(date)] $1"
+ echo "$s" >&2
+}
+
+# getprojects()
+getprojects() {
+ # allow commenting to disable.
+ projects | grep -v '^#'
+}
+
+# clone()
+clone() {
+ getprojects | while read -r -- project dir; do
+ test -d "$repodir/$project" && continue
+
+ git clone "git://git.suckless.org/$project" "$repodir/$project"
+ done
+}
+
+# pull()
+pull() {
+ getprojects | while read -r -- project dir; do
+ test -d "$repodir/$project" || continue
+
+ GIT_DIR="$repodir/$project/.git" git pull "git://git.suckless.org/$project"
+ done
+}
+
+# listpatches()
+listpatches() {
+ getprojects | while read -r -- project dir; do
+ find "$wikidir/$dir" -iname "*.diff" | while read -r p; do
+ test -f "$p" || continue
+
+ b=$(basename "$p")
+ bb="${b%.diff}"
+ bb="${bb#${project}-}"
+
+ # NOTE: historical patches like "r1506" (mercurial) are ignored.
+ v=$(echo "$bb" | sed -En 's@^([0-9a-f\.]+)-.*$@\1@p')
+ if test -z "$v"; then
+ v=$(echo "$bb" | sed -En 's@^.*-([0-9a-f\.]+)$@\1@p')
+ fi
+
+ # version not found, skip.
+ if test -z "$v"; then
+ continue
+ fi
+
+ name="${p%.diff}"
+ name="${name##*/patches/}"
+ name="${name%%/*}"
+
+ printf '%s\t%s\t%s\t%s\t%s\n' "$project" "$v" "$dir" "$name" "$p"
+ done
+ done
+}
+
+# checkoutrev(project, version)
+checkoutrev() {
+ project="$1"
+ v="$2"
+
+ test -f "$revdir/$project/$v/fail" && return 1
+ test -d "$revdir/$project/$v" && return 0
+
+ cur=$(pwd)
+ mkdir -p "$revdir/$project/$v"
+ cd "$revdir/$project/$v" || return 1
+
+ GIT_DIR="$repodir/$project/.git" git checkout -f "$v" -- . 2> "$revdir/$project/$v/fail"
+ status=$?
+ if test x"$status" != x"0"; then
+ status=1
+ else
+ rm -f "$revdir/$project/$v/fail"
+ fi
+ cd "$cur"
+
+ return $status
+}
+
+# preparebuilds()
+preparebuilds() {
+ listpatches | while read -r -- project v dir name p; do
+ test -f "$p" || continue
+
+ # version quirks (wrong tagging).
+ if test x"$project" = x"sent"; then
+ if test x"$v" = x"1.0"; then
+ v="1"
+ test -e "$revdir/$project/1.0" || \
+ ln -sf "$v" "$revdir/$project/1.0"
+ fi
+ fi
+ if test x"$project" = x"ii"; then
+ if test x"$v" = x"1.7"; then
+ v="v1.7"
+ test -e "$revdir/$project/1.7" || \
+ ln -sf "$v" "$revdir/$project/1.7"
+ fi
+ fi
+
+ # prepare clean build directory for patch.
+ b=$(basename "$p")
+ b="${b%.diff}"
+
+ # cannot prepare revision for build: skip.
+ if ! checkoutrev "$project" "$v"; then
+ log "CANNOT CHECKOUT REVISION: $project v=$v, name=$name, patch=$b, error=$(cat "$revdir/$project/$v/fail")"
+ continue
+ fi
+
+ # already has clean builddir.
+ test -d "$builddir/$project/$b" && continue
+ cleanbuild "$project" "$v" "$b"
+ done
+}
+
+# cleanbuild(project, version, build)
+cleanbuild() {
+ if test -d "$builddir/$project/$b"; then
+ rm -rf "$builddir/$project/$b"
+ fi
+
+ mkdir -p "$builddir/$project"
+ cp -r "$revdir/$project/$v" "$builddir/$project/$b"
+}
+
+# testpatches()
+testpatches() {
+ # sort by project, name, version
+ listpatches | sort -k1,1 -k4,4 -k2,2 | \
+ while read -r -- project v dir name p; do
+ test -f "$p" || continue
+
+ # cannot prepare revision for build: skip.
+ checkoutrev "$project" "$v" || continue
+
+ b=$(basename "$p")
+ b="${b%.diff}"
+
+ test -d "$builddir/$project/$b" || continue
+ cd "$builddir/$project/$b" || continue
+
+ # copy patch file for convenience / debugging.
+ cp "$p" "$builddir/$project/$b/p.diff"
+
+ # lenient: copy config.def.h to config.h if config.h doesn't exist.
+ #rm -f "$builddir/$project/$b/config.h" # DEBUG
+ #if test -f "$builddir/$project/$b/config.def.h"; then
+ # if ! test -f "$builddir/$project/$b/config.h"; then
+ # cp "$builddir/$project/$b/config.def.h" "$builddir/$project/$b/config.h"
+ # fi
+ #fi
+
+ # patch (dryrun).
+ $dryrun < "$p" 2> "$builddir/$project/$b/patch.2.log" >"$builddir/$project/$b/patch.1.log"
+ applystatus=$?
+
+ # write results to metadata file (for creating views).
+ printf "%s\t%s\t%s\t%s\t%s\t%s\n" \
+ "$project" "$v" "$dir" "$name" "$applystatus" "$b" > "$builddir/$project/$b/metadata"
+
+ log "$p $applystatus"
+ done
+}
+
+# outputhtml()
+outputhtml() {
+ index="$resultsdir/index.html"
+ title="Last updated on $(getdateutc)"
+
+cat > "$index" <<!__EOF__
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>$title - Patch applystatus</title>
+<style type="text/css">
+table { border-collapse: collapse; }
+td { padding: 2px; }
+thead td { background-color: #eee; }
+.s-0 td { background-color: #ccffcc; }
+.s-1 td { background-color: #ffcccc; }
+.s-2 td { background-color: #ff0000; color: #fff; }
+</style>
+</head>
+<body>
+<h1>$title</h1>
+<table>
+<thead>
+<tr>
+ <td><b>Project</b></td>
+ <td><b>Version/revision</b></td>
+ <td><b>Patch</b></td>
+ <td><b>Patch</b></td>
+ <td><b>Patch file</b></td>
+ <td><b>Patch stdout</b></td>
+ <td><b>Patch stderr</b></td>
+ <td><b>Exitcode</b></td>
+ <td><b>Status</b></td>
+</tr>
+</thead>
+<tbody>
+!__EOF__
+
+ # sort by project, name, version
+ find "$builddir" -name "metadata" -type f -exec cat {} \; | \
+ sort -k1,1 -k4,4 -k2,2 | \
+ while read -r -- project v dir name applystatus b; do
+ test -d "$builddir/$project/$b" || continue
+
+ # HTML output test
+ mkdir -p "$resultsdir/$b/"
+ cp \
+ "$builddir/$project/$b/p.diff"\
+ "$builddir/$project/$b/patch.2.log"\
+ "$builddir/$project/$b/patch.1.log"\
+ "$resultsdir/$b/"
+
+ statustext="OK"
+ pageurl="https://$dir/$name/"
+
+ case "$applystatus" in
+ 0) statustext="OK";;
+ 1) statustext="FAIL";;
+ 2) statustext="CORRUPT";;
+ *) statustext="UNKNOWN";;
+ esac
+
+ cat >> "$index" <<!__EOF__
+<tr class="s-$applystatus">
+ <td><a href="https://git.suckless.org/$project/">$project</a></td>
+ <td>$v</td>
+ <td><a href="$pageurl">$name</a></td>
+ <td><a href="$pageurl">$b</a></td>
+ <td><a href="$b/p.diff">[patch]</a></td>
+ <td><a href="$b/patch.1.log">[stdout]</a></td>
+ <td><a href="$b/patch.2.log">[stderr]</a></td>
+ <td>$applystatus</td>
+ <td>$statustext</td>
+</tr>
+!__EOF__
+ done
+
+ echo "</tbody></table></body></html>" >> "$index"
+}
+
+# outputcsv()
+outputcsv() {
+ index="$resultsdir/index.csv"
+
+ # sort by project, name, version
+ find "$builddir" -name "metadata" -type f -exec cat {} \; | \
+ sort -k1,1 -k4,4 -k2,2 | \
+ while read -r -- project v dir name applystatus b; do
+ test -d "$builddir/$project/$b" || continue
+
+ printf '%s\n' "$project $v $name $b $applystatus" >> "$index"
+ done
+}
+
+case "$1" in
+clone|pull)
+ mkdir -p "$repodir"
+ $1
+ ;;
+clean)
+ rm -rf "$revdir" "$builddir"
+ ;;
+prepare)
+ mkdir -p "$builddir" "$revdir"
+ preparebuilds
+ ;;
+test)
+ testpatches
+ ;;
+results)
+ # output results
+ rm -rf "$resultsdir"
+ mkdir -p "$resultsdir"
+ outputhtml
+ outputcsv
+ ;;
+*)
+ echo "usage: $0 <clone | pull | clean | prepare | test | results>" >&2
+ exit 1
+ ;;
+esac