Root/scripts/schhist2web

Source at commit 6260614015a181b643670109d65b6e921a90e1e8 created 9 years 5 months ago.
By Werner Almesberger, Reduce the number of I/O redirections.
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
81wrapped_png()
82{
83    local dir=$1 commit=$2 file=$3
84
85    mkdir -p "$dir/html_$commit"
86    echo "<A href=\"html_$commit/$file.html\"><IMG src=\"thumb_$commit/$file.png\"></A>"
87    cat <<EOF >"$dir/html_$commit/$file.html"
88<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
89<HTML>
90<TITLE>$file</TITLE>
91<BODY>
92<A href="../pdf_$commit/$file.pdf"><IMG src="../diff_$commit/$file.png"></A>
93</BODY>
94EOF
95}
96
97
98usage()
99{
100    cat <<EOF 2>&1
101usage: $0 [-c cache-dir] [-n] [-S] [top-dir] [top-schem] [out-dir]
102
103  top-dir top-level directory of the git archive (default: locate it)
104  top-schem root sheet of the schematics (default: locate it in top-dir)
105  out-dir output directory (default: $OUTDIR)
106  -c cache-dir cache directory (default: same as out-dir)
107  -n don't use previous cache content (rebuild the cache)
108  -S sanitize KiCad profile
109EOF
110    exit 1
111}
112
113
114# --- Parse command-line options ----------------------------------------------
115
116
117no_cache=false
118sanitize=
119
120while true; do
121    case "$1" in
122    -n) no_cache=true
123    shift;;
124    -c) [ -z "$1" ] && usage
125    cache="$1"
126    shift 2;;
127    -S) sanitize=-S
128    shift;;
129    -*) usage;;
130    *) break;;
131    esac
132done
133
134
135# --- Interpret the command-line arguments ------------------------------------
136
137
138if [ ! -z "$1" -a -d "$1/.git" ]; then
139    dir="$1"
140    shift
141else
142    dir=.
143    while [ ! -d $dir/.git ]; do
144    if [ $dir -ef $dir/.. ]; then
145        echo "no .git/ directory found in hierarchy" 1>&2
146        exit 1
147    fi
148    dir=$dir/..
149    done
150    echo "found top-dir: $dir" 1>&2
151fi
152
153if [ ! -z "$1" -a -f "$dir/$1" -a \
154  -f "$dir/${1%.sch}.pro" ]; then
155    sch="$1"
156    shift
157else
158    for n in "$dir"/*.sch; do
159    [ -f "${n%.sch}.pro" ] || continue
160    if [ ! -z "$sch" ]; then
161        echo "multiple choices for top-level .sch file" 1>&2
162        exit 1
163    fi
164    sch="$n"
165    done
166    if [ -z "$sch" -o "$sch" = "$dir/*.sch" ]; then
167    echo "no candidate for top-level .sch file found" 1>&2
168    exit 1
169    fi
170    echo "found root sheet: $sch" 1>&2
171fi
172
173if [ ! -z "$1" ] && [ ! -e "$1" ] || [ -d "$1" -a ! -d "$1"/.git ]; then
174    out="$1"
175    shift
176else
177    out=$OUTDIR
178fi
179[ -z "$cache" ] && cache="$out"
180
181[ -z "$1" ] || usage
182
183
184# --- Set up some variables and the directories for cache and output ----------
185
186
187PATH=`dirname "$0"`:"$PATH"
188first=`gitenealogy "$dir" "$sch" | sed '$s/ .*//p;d'`
189schname=`gitenealogy "$dir" "$sch" | sed '$s/^.* //p;d'`
190
191rm -rf "$out/diff_*" "$out/thumb_*" "$out/html_*" "$out/pdf_*" "$out/names"
192$no_cache && rm -rf "$cache"
193mkdir -p "$out/names"
194mkdir -p "$cache"
195
196ppmmake '#e0e0e0' 5 30 | pnmtopng >"$out"/unchanged.png
197
198
199# --- Generate/update the cache -----------------------------------------------
200
201
202head=
203for n in $first `cd "$dir" && git rev-list --reverse $first..HEAD`; do
204    ( cd "$dir" && git show --pretty=format:'' --name-only $n; ) |
205      egrep -q '\.sch$|\.pro$|\.lib$' || continue
206    echo Processing $n
207    new=`gitenealogy "$dir" "$sch" | sed "/^$n /s///p;d"`
208    if [ ! -z "$new" ]; then
209    echo Name change $schname to $new 1>&2
210    schname="$new"
211    fi
212    tmp=`pwd`/_schhist2web
213    trap "rm -rf \"$cache/ppm_$n\" \"$cache/fat_$n\" \"$cache/ps_$n\" \
214      \"$cache/hard_$n\" \"$tmp\"" 0
215    if [ ! -d "$cache/ppm_$n" ]; then
216    rm -rf "$cache/ppm_$n" "$cache/fat_$n" "$cache/ps_$n" "$cache/hard_$n"
217    mkdir "$cache/ppm_$n" "$cache/fat_$n" "$cache/ps_$n" "$cache/hard_$n"
218    #
219    # potential optimization here: remember Postscript files from previous
220    # run (or their md5sum) and check if they have changed. If not, skip
221    # the ghostscript run and just put a symlink, replacing the less
222    # efficient optimization below.
223    #
224    gitsch2ps $sanitize "$dir" "$schname" $n "$tmp" || exit
225    for m in "$tmp"/*.ps; do
226        # Postscript, for making PDFs later
227        ps="$cache/ps_$n/`basename "$m"`"
228        normalizeschps "$m" "$ps" || exit
229
230        # Unadorned pixmap, for comparison
231        ppm="$cache/hard_$n/`basename "$m" .ps`.ppm"
232        schps2ppm -n "$ps" "$ppm" || exit
233
234        # Pixmap with thin lines, for the detail views
235        ppm="$cache/ppm_$n/`basename "$m" .ps`.ppm"
236        normalizeschps -w 120 "$m" | schps2ppm - "$ppm" || exit
237
238        # Pixmap with thick lines, for the thumbnails
239        ppm="$cache/fat_$n/`basename "$m" .ps`.ppm"
240        normalizeschps -w 500 "$m" | schps2ppm - "$ppm" || exit
241    done
242    rm -rf "$tmp"
243    fi
244    for m in "$cache/ppm_$n/"*; do
245    [ "$m" = "$cache/ppm_$n/*" ] && break
246    if [ ! -z "$head" ]; then
247        prev="$cache/ppm_$head"/`basename "$m"`
248        if [ -r "$prev" ] && cmp -s "$prev" "$m"; then
249        symlink "../ppm_$head/`basename \"$m\"`" "$m"
250        symlink "../fat_$head/`basename \"$m\"`" \
251          "$cache/fat_$n/`basename \"$m\"`"
252        fi
253    fi
254    touch "$out/names/`basename \"$m\" .ppm`"
255    done
256    trap 0
257    head=$n
258done
259
260if [ -z "$head" ]; then
261    echo "no usable head found" 2>&1
262    exit 1
263fi
264
265
266# --- Title of the Web page and table header ----------------------------------
267
268
269index="$out/index.html"
270all=
271{
272    cat <<EOF
273<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
274<HTML>
275EOF
276    if [ ! -z "$SCHHIST_TITLE" ]; then
277    echo "<TITLE>$SCHHIST_TITLE</TITLE>"
278    fi
279    echo "<BODY>"
280    if [ ! -z "$SCHHIST_TITLE" ]; then
281    echo "<H1>"
282    [ -z "$SCHHIST_HOME_URL" ] || echo "<A href=\"$SCHHIST_HOME_URL\">"
283    echo "$SCHHIST_TITLE"
284    [ -z "$SCHHIST_HOME_URL" ] || echo "</A>"
285    echo "</H1>"
286    fi
287    cat <<EOF
288<TABLE bgcolor="$BG_COLOR" callpadding=1>
289<TR bgcolor="$FNAME_COLOR">
290EOF
291    while read m; do
292    ps="$cache/ps_$head/$m.ps"
293    if [ -r "$ps" ]; then
294        #
295        # Note: we read from variable ps_$head but we write to constant
296        # pdf_head. We can't use pdf_$head here, because that may just be a
297        # commit with a change and we thus generate a delta PDF below.
298        #
299        mkdir -p "$out/pdf_head"
300        schps2pdf -o "$out/pdf_head/$m.pdf" "$ps" || exit
301        all="$all \"$ps\""
302        echo "<TD><A href=\"pdf_head/$m.pdf\"><B>$m</B></A>"
303    else
304        echo "<TD><B>$m</B>"
305    fi
306    done < <(ls -1 "$out/names")
307    proj=`basename "$sch" .sch`
308    eval schps2pdf -t \""$proj-"\" -o \""$out/pdf_$proj.pdf"\" $all
309    echo "<TD><A href=\"pdf_$proj.pdf\">All sheets</A>"
310} >"$index"
311
312
313# --- Diff all the revisions, newest to oldest --------------------------------
314
315
316next="$head"
317for n in `cd "$dir" && git rev-list $first..HEAD~1` $first; do
318    [ -d "$cache/ppm_$n" ] || continue
319    empty=true
320    s="<TR>"
321    mkdir -p "$out/diff_$next" "$out/thumb_$next"
322    while read m; do
323    a="$cache/ppm_$n/$m.ppm"
324    fat_a="$cache/fat_$n/$m.ppm"
325    hard_a="$cache/hard_$n/$m.ppm"
326    b="$cache/ppm_$next/$m.ppm"
327    fat_b="$cache/fat_$next/$m.ppm"
328    hard_b="$cache/hard_$next/$m.ppm"
329    diff="$out/diff_$next/$m.png"
330    thumb="$out/thumb_$next/$m.png"
331
332    if [ -f "$a" -a -f "$b" ]; then
333        s="$s<TD align=\"center\" valign=\"middle\">"
334        if ! pngdiff cat "$diff" "$a" "$b" "$hard_a" "$hard_b"; then
335        s="$s<IMG src=\"unchanged.png\""
336        continue
337        fi
338        pngdiff shrink "$thumb" -f $THUMB_OPTS "$fat_a" "$fat_b" \
339          "$hard_a" "$hard_b" || exit
340        mkdir -p "$out/pdf_$next"
341        schps2pdf -T BEFORE -T AFTER -o "$out/pdf_$next/$m.pdf" \
342          "$cache/ps_$n/$m.ps" "$cache/ps_$next/$m.ps" || exit
343    elif [ -f "$a" ]; then
344        s="$s<TD>"
345        pngdiff cat "$diff" -f -c 1,0,0 "$a" "$a" || exit
346        pngdiff shrink "$thumb" -f $THUMB_OPTS -c 1,0,0 "$fat_a" "$fat_a" \
347          || exit
348        mkdir -p "$out/pdf_$next"
349        schps2pdf -T DELETED -o "$out/pdf_$next/$m.pdf" \
350          "$cache/ps_$n/$m.ps" || exit
351    elif [ -f "$b" ]; then
352        s="$s<TD>"
353        pngdiff cat "$diff" -f -c 0,1,0 "$b" "$b" || exit
354        pngdiff shrink "$thumb" -f $THUMB_OPTS -c 0,1,0 "$fat_b" "$fat_b" \
355          || exit
356        mkdir -p "$out/pdf_$next"
357        schps2pdf -T NEW -o "$out/pdf_$next/$m.pdf" \
358          "$cache/ps_$next/$m.ps" || exit
359    else
360        s="$s<TD>"
361        continue
362    fi
363    echo "$s"
364    s=
365    empty=false
366        wrapped_png "$out" "$next" "$m"
367    done < <(ls -1 "$out/names")
368    if ! $empty; then
369     echo "$s<TD valign=\"middle\">"
370    commit_entry "$dir" $next
371    fi
372    next=$n
373done >>"$index"
374
375
376# --- Add creation entries for all files in the first commit ------------------
377
378
379if [ -d "$cache/ppm_$next" ]; then # could this ever be false ?
380    empty=true
381    echo "<TR>"
382    mkdir -p "$out/diff_$next" "$out/thumb_$next"
383    while read m; do
384    ppm="$cache/ppm_$next/$m.ppm"
385    fat="$cache/fat_$next/$m.ppm"
386    diff="$out/diff_$next/$m.png"
387    thumb="$out/thumb_$next/$m.png"
388
389    echo "<TD>"
390    [ -f "$ppm" ] || continue
391    pngdiff cat "$diff" -f -c 0,1,0 "$ppm" "$ppm" || exit
392    pngdiff shrink "$thumb" -f $THUMB_OPTS -c 0,1,0 "$fat" "$fat" \
393          || exit
394    empty=false
395    mkdir -p "$out/pdf_$next"
396    schps2pdf -T NEW -o "$out/pdf_$next/$m.pdf" \
397      "$cache/ps_$next/$m.ps" || exit
398    wrapped_png "$out" "$next" "$m"
399    done < <(ls -1 "$out/names")
400    if ! $empty; then
401     echo "<TD valign=\"middle\">"
402    commit_entry "$dir" $next
403    fi
404fi >>"$index"
405
406
407# --- Finish ------------------------------------------------------------------
408
409
410cat <<EOF >>"$index"
411</TABLE>
412<HR>
413`date -u '+%F %X'` UTC
414</BODY>
415</HTML>
416EOF
417

Archive Download this file



interactive