Root/scripts/schhist2web

Source at commit 66cf6a296ec30f5bbda7ebe1eb59c2041c656a87 created 10 years 24 days ago.
By Werner Almesberger, We now generate and link delta PDFs with the state(s) of the sheet.
1#!/bin/bash
2#
3# schhist2web - Web-browseable graphical revision history of schematics
4#
5# Written 2010 by Werner Almesberger
6# Copyright 2010 Werner Almesberger
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13
14
15OUTDIR=_out
16THUMB_OPTS="-w 3 -d 60 -c 0.5,0.5,0.5 -n 1,1,0"
17BG_COLOR="f0f0ff"
18FNAME_COLOR="#b0f0ff"
19SEP_COLOR="#000000"
20
21
22shrink()
23{
24    pnmscale -width 120 "$@" || exit
25}
26
27
28pngdiff()
29{
30    # pngdiff preproc outfile arg ...
31    pp="$1"
32    of="$2"
33    shift 2
34    if ! PATH=$PATH:`dirname $0`/ppmdiff ppmdiff "$@" "$out/_tmp"; then
35    rm -f "$out/_tmp"
36    return 1
37    fi
38    $pp "$out/_tmp" | pnmtopng >"$of"
39    rm "$out/_tmp"
40}
41
42
43symlink()
44{
45    local old=$1 new=$2
46    local src=`dirname "$new"`/$old
47
48    if [ -L "$src" ]; then
49    ln -sf "`readlink \"$src\"`" "$new"
50    else
51    ln -sf "$old" "$new"
52    fi
53}
54
55
56commit_entry()
57{
58    # usage: commit_entry <base-dir> <commit>
59    # note: the repository's base in $dir must be provided by the caller
60
61    local dir=$1 next=$2
62
63    cat <<EOF
64<TABLE bgcolor="$SEP_COLOR" cellspacing=0 width="100%"><TR><TD></TABLE>
65EOF
66    echo "<PRE>"
67    ( cd "$dir" && git show \
68        --pretty=format:"%aN <%aE>%n%ad, %ar%n%n %s" \
69    --quiet $next; ) |
70      sed 's/&/&amp;/g;s/</\&lt;/g;s/>/\&gt;/g' |
71      if [ -z "$SCHHIST_COMMIT_TEMPLATE" ]; then
72    cat
73      else
74    url=`echo "$SCHHIST_COMMIT_TEMPLATE" | sed "s/{}/$next/g"`
75    sed "1s|^|<A href=\"$url\"><B>\&gt;\&gt;\&gt;</B></a> |"
76      fi
77    echo "</PRE>"
78}
79
80
81usage()
82{
83    cat <<EOF 2>&1
84usage: $0 [-c cache-dir] [-n] [-S] [top-dir] [top-schem] [out-dir]
85
86  top-dir top-level directory of the git archive (default: locate it)
87  top-schem root sheet of the schematics (default: locate it in top-dir)
88  out-dir output directory (default: $OUTDIR)
89  -c cache-dir cache directory (default: same as out-dir)
90  -n don't use previous cache content (rebuild the cache)
91  -S sanitize KiCad profile
92EOF
93    exit 1
94}
95
96
97# --- Parse command-line options ----------------------------------------------
98
99
100no_cache=false
101sanitize=
102
103while true; do
104    case "$1" in
105    -n) no_cache=true
106    shift;;
107    -c) [ -z "$1" ] && usage
108    cache="$1"
109    shift 2;;
110    -S) sanitize=-S
111    shift;;
112    -*) usage;;
113    *) break;;
114    esac
115done
116
117
118# --- Interpret the command-line arguments ------------------------------------
119
120
121if [ ! -z "$1" -a -d "$1/.git" ]; then
122    dir="$1"
123    shift
124else
125    dir=.
126    while [ ! -d $dir/.git ]; do
127    if [ $dir -ef $dir/.. ]; then
128        echo "no .git/ directory found in hierarchy" 1>&2
129        exit 1
130    fi
131    dir=$dir/..
132    done
133    echo "found top-dir: $dir" 1>&2
134fi
135
136if [ ! -z "$1" -a -f "$dir/$1" -a \
137  -f "$dir/${1%.sch}.pro" ]; then
138    sch="$1"
139    shift
140else
141    for n in "$dir"/*.sch; do
142    [ -f "${n%.sch}.pro" ] || continue
143    if [ ! -z "$sch" ]; then
144        echo "multiple choices for top-level .sch file" 1>&2
145        exit 1
146    fi
147    sch="$n"
148    done
149    if [ -z "$sch" -o "$sch" = "$dir/*.sch" ]; then
150    echo "no candidate for top-level .sch file found" 1>&2
151    exit 1
152    fi
153    echo "found root sheet: $sch" 1>&2
154fi
155
156if [ ! -z "$1" ] && [ ! -e "$1" ] || [ -d "$1" -a ! -d "$1"/.git ]; then
157    out="$1"
158    shift
159else
160    out=$OUTDIR
161fi
162[ -z "$cache" ] && cache="$out"
163
164[ -z "$1" ] || usage
165
166
167# --- Set up some variables and the directories for cache and output ----------
168
169
170PATH=`dirname "$0"`:"$PATH"
171first=`gitenealogy "$dir" "$sch" | sed '$s/ .*//p;d'`
172schname=`gitenealogy "$dir" "$sch" | sed '$s/^.* //p;d'`
173
174rm -rf "$out/diff_*" "$out/thumb_*" "$out/names"
175$no_cache && rm -rf "$cache"
176mkdir -p "$out/names"
177mkdir -p "$cache"
178
179ppmmake '#e0e0e0' 5 30 | pnmtopng >"$out"/unchanged.png
180
181
182# --- Generate/update the cache -----------------------------------------------
183
184
185head=
186for n in $first `cd "$dir" && git rev-list --reverse $first..HEAD`; do
187    ( cd "$dir" && git show --pretty=format:'' --name-only $n; ) |
188      egrep -q '\.sch$|\.pro$|\.lib$' || continue
189    echo Processing $n
190    new=`gitenealogy "$dir" "$sch" | sed "/^$n /s///p;d"`
191    if [ ! -z "$new" ]; then
192    echo Name change $schname to $new 1>&2
193    schname="$new"
194    fi
195    tmp=`pwd`/_schhist2web
196    trap "rm -rf \"$cache/ppm_$n\" \"$cache/fat_$n\" \"$tmp\"" 0
197    if [ ! -d "$cache/ppm_$n" ]; then
198    rm -rf "$cache/ppm_$n" "$cache/fat_$n" "$cache/ps_$n"
199    mkdir "$cache/ppm_$n" "$cache/fat_$n" "$cache/ps_$n"
200    #
201    # potential optimization here: remember Postscript files from previous
202    # run (or their md5sum) and check if they have changed. If not, skip
203    # the ghostscript run and just put a symlink, replacing the less
204    # efficient optimization below.
205    #
206    gitsch2ps $sanitize "$dir" "$schname" $n "$tmp" || exit
207    for m in "$tmp"/*.ps; do
208        ppm="$cache/ppm_$n/`basename "$m" .ps`.ppm"
209        normalizeschps -w 120 "$m" | schps2ppm - "$ppm" || exit
210        ppm="$cache/fat_$n/`basename "$m" .ps`.ppm"
211        normalizeschps -w 500 "$m" | schps2ppm - "$ppm" || exit
212        ps="$cache/ps_$n/`basename "$m"`"
213        normalizeschps "$m" "$ps" || exit
214    done
215    rm -rf "$tmp"
216    fi
217    for m in "$cache/ppm_$n/"*; do
218    [ "$m" = "$cache/ppm_$n/*" ] && break
219    if [ ! -z "$head" ]; then
220        prev="$cache/ppm_$head"/`basename "$m"`
221        if [ -r "$prev" ] && cmp -s "$prev" "$m"; then
222        symlink "../ppm_$head/`basename \"$m\"`" "$m"
223        symlink "../fat_$head/`basename \"$m\"`" \
224          "$cache/fat_$n/`basename \"$m\"`"
225        fi
226    fi
227    touch "$out/names/`basename \"$m\" .ppm`"
228    done
229    trap 0
230    head=$n
231done
232
233if [ -z "$head" ]; then
234    echo "no usable head found" 2>&1
235    exit 1
236fi
237
238
239# --- Title of the Web page and table header ----------------------------------
240
241
242index="$out/index.html"
243all=
244{
245    cat <<EOF
246<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
247<HTML>
248EOF
249    if [ ! -z "$SCHHIST_TITLE" ]; then
250    echo "<TITLE>$SCHHIST_TITLE</TITLE>"
251    fi
252    echo "<BODY>"
253    if [ ! -z "$SCHHIST_TITLE" ]; then
254    echo "<H1>"
255    [ -z "$SCHHIST_HOME_URL" ] || echo "<A href=\"$SCHHIST_HOME_URL\">"
256    echo "$SCHHIST_TITLE"
257    [ -z "$SCHHIST_HOME_URL" ] || echo "</A>"
258    echo "</H1>"
259    fi
260    cat <<EOF
261<TABLE bgcolor="$BG_COLOR" callpadding=1>
262<TR bgcolor="$FNAME_COLOR">
263EOF
264    while read m; do
265    ps="$cache/ps_$head/$m.ps"
266    if [ -r "$ps" ]; then
267        #
268        # Note: we read from variable ps_$head but we write to constant
269        # pdf_head. We can't use pdf_$head here, because that may just be a
270        # commit with a change and we thus generate a delta PDF below.
271        #
272        mkdir -p "$out/pdf_head"
273        schps2pdf -o "$out/pdf_head/$m.pdf" "$ps" || exit
274        all="$all \"$ps\""
275        echo "<TD><A href=\"pdf_head/$m.pdf\"><B>$m</B></A>"
276    else
277        echo "<TD><B>$m</B>"
278    fi
279    done < <(ls -1 "$out/names")
280    proj=`basename "$sch" .sch`
281    eval schps2pdf -t \""$proj-"\" -o \""$out/pdf_$proj.pdf"\" $all
282    echo "<TD><A href=\"pdf_$proj.pdf\">All sheets</A>"
283} >"$index"
284
285
286# --- Diff all the revisions, newest to oldest --------------------------------
287
288
289next="$head"
290for n in `cd "$dir" && git rev-list $first..HEAD~1` $first; do
291    [ -d "$cache/ppm_$n" ] || continue
292    empty=true
293    s="<TR>"
294    mkdir -p "$out/diff_$next" "$out/thumb_$next"
295    while read m; do
296    a="$cache/ppm_$n/$m.ppm"
297    fat_a="$cache/fat_$n/$m.ppm"
298    b="$cache/ppm_$next/$m.ppm"
299    fat_b="$cache/fat_$next/$m.ppm"
300    diff="$out/diff_$next/$m.png"
301    thumb="$out/thumb_$next/$m.png"
302
303    if [ -f "$a" -a -f "$b" ]; then
304        s="$s<TD align=\"center\" valign=\"middle\">"
305        if ! pngdiff cat "$diff" "$a" "$b"; then
306        s="$s<IMG src=\"unchanged.png\""
307        continue
308        fi
309        pngdiff shrink "$thumb" -f $THUMB_OPTS "$fat_a" "$fat_b" \
310          "$a" "$b" || exit
311        mkdir -p "$out/pdf_$next"
312        schps2pdf -T BEFORE -T AFTER -o "$out/pdf_$next/$m.pdf" \
313          "$cache/ps_$n/$m.ps" "$cache/ps_$next/$m.ps" || exit
314    elif [ -f "$a" ]; then
315        s="$s<TD>"
316        pngdiff cat "$diff" -f -c 1,0,0 "$a" "$a" || exit
317        pngdiff shrink "$thumb" -f $THUMB_OPTS -c 1,0,0 "$fat_a" "$fat_a" \
318          || exit
319        mkdir -p "$out/pdf_$next"
320        schps2pdf -T DELETED -o "$out/pdf_$next/$m.pdf" \
321          "$cache/ps_$n/$m.ps" || exit
322    elif [ -f "$b" ]; then
323        s="$s<TD>"
324        pngdiff cat "$diff" -f -c 0,1,0 "$b" "$b" || exit
325        pngdiff shrink "$thumb" -f $THUMB_OPTS -c 0,1,0 "$fat_b" "$fat_b" \
326          || exit
327        mkdir -p "$out/pdf_$next"
328        schps2pdf -T NEW -o "$out/pdf_$next/$m.pdf" \
329          "$cache/ps_$next/$m.ps" || exit
330    else
331        s="$s<TD>"
332        continue
333    fi
334    echo "$s" >>"$index"
335    s=
336    empty=false
337    mkdir -p "$out/html_$next"
338    echo "<A href=\"html_$next/$m.html\"><IMG src=\"thumb_$next/$m.png\"></A>" >>"$index"
339    cat <<EOF >"$out/html_$next/$m.html"
340<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
341<HTML>
342<TITLE>$m</TITLE>
343<BODY>
344<A href="../pdf_$next/$m.pdf"><IMG src="../diff_$next/$m.png"></A>
345</BODY>
346EOF
347    done < <(ls -1 "$out/names")
348    if ! $empty; then
349     echo "$s<TD valign=\"middle\">" >>"$index"
350    commit_entry "$dir" $next >>"$index"
351    fi
352    next=$n
353done
354
355
356# --- Add creation entries for all files in the first commit ------------------
357
358
359if [ -d "$cache/ppm_$next" ]; then # could this ever be false ?
360    empty=true
361    echo "<TR>" >>"$index"
362    mkdir -p "$out/diff_$next" "$out/thumb_$next"
363    while read m; do
364    ppm="$cache/ppm_$next/$m.ppm"
365    fat="$cache/fat_$next/$m.ppm"
366    diff="$out/diff_$next/$m.png"
367    thumb="$out/thumb_$next/$m.png"
368
369    echo "<TD>" >>"$index"
370    [ -f "$ppm" ] || continue
371    pngdiff cat "$diff" -f -c 0,1,0 "$ppm" "$ppm" || exit
372    pngdiff shrink "$thumb" -f $THUMB_OPTS -c 0,1,0 "$fat" "$fat" \
373          || exit
374    empty=false
375    echo "<A href=\"diff_$next/$m.png\"><IMG src=\"thumb_$next/$m.png\"></A>" >>"$index"
376    done < <(ls -1 "$out/names")
377    if ! $empty; then
378     echo "<TD valign=\"middle\">" >>"$index"
379    commit_entry "$dir" $next >>"$index"
380    fi
381fi
382
383
384# --- Finish ------------------------------------------------------------------
385
386
387cat <<EOF >>"$index"
388</TABLE>
389<HR>
390`date -u '+%F %X'` UTC
391</BODY>
392</HTML>
393EOF
394

Archive Download this file



interactive