Root/scripts/schhist2web

Source at commit a3aac7e80bd612bace666e90cdd697e14d471897 created 9 years 5 months ago.
By Werner Almesberger, Reorganized cache and output directory structure. Some code cleanup.
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/$commit/html"
86    echo "<A href=\"$commit/html/$file.html\"><IMG src=\"$commit/thumb/$file.png\"></A>"
87    cat <<EOF >"$dir/$commit/html/$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/$file.pdf"><IMG src="../diff/$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,thumb,html,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/$n/ps\" \"$cache/$n/ppm0\" \"$cache/$n/ppm1\" \
214      \"$cache/$n/ppm2\" \"$tmp\"" 0
215    if [ ! -d "$cache/$n/ppm2" ]; then
216    rm -rf "$cache/$n/"{ps,ppm0,ppm1,ppm2}
217    mkdir -p "$cache/$n/"{ps,ppm0,ppm1,ppm2}
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/$n/ps/`basename "$m"`"
228        normalizeschps "$m" "$ps" || exit
229
230        # Unadorned pixmap, for comparison
231        ppm="$cache/$n/ppm0/`basename "$m" .ps`.ppm"
232        schps2ppm -n "$ps" "$ppm" || exit
233
234        # Pixmap with thin lines, for the detail views
235        ppm="$cache/$n/ppm1/`basename "$m" .ps`.ppm"
236        normalizeschps -w 120 "$m" | schps2ppm - "$ppm" || exit
237
238        # Pixmap with thick lines, for the thumbnails
239        ppm="$cache/$n/ppm2/`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/$n/ppm0/"*; do
245    [ "$m" = "$cache/$n/ppm0/*" ] && break
246    if [ ! -z "$head" ]; then
247        prev="$cache/$head/ppm0/${m##*/}"
248        if [ -r "$prev" ] && cmp -s "$prev" "$m"; then
249        for d in ppm0 ppm1 ppm2; do
250            symlink "../../$head/$d/${m##*/}" "$cache/$n/$d/${m##*/}"
251        done
252        m_ps=${m%.ppm}.ps
253        symlink "../../$head/$d/${m_ps##*/}" "$cache/$n/$d/${m_ps##*/}"
254        fi
255    fi
256    touch "$out/names/`basename \"$m\" .ppm`"
257    done
258    trap 0
259    head=$n
260done
261
262if [ -z "$head" ]; then
263    echo "no usable head found" 2>&1
264    exit 1
265fi
266
267
268# --- Title of the Web page and table header ----------------------------------
269
270
271index="$out/index.html"
272all=
273{
274    cat <<EOF
275<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
276<HTML>
277EOF
278    if [ ! -z "$SCHHIST_TITLE" ]; then
279    echo "<TITLE>$SCHHIST_TITLE</TITLE>"
280    fi
281    echo "<BODY>"
282    if [ ! -z "$SCHHIST_TITLE" ]; then
283    echo "<H1>"
284    [ -z "$SCHHIST_HOME_URL" ] || echo "<A href=\"$SCHHIST_HOME_URL\">"
285    echo "$SCHHIST_TITLE"
286    [ -z "$SCHHIST_HOME_URL" ] || echo "</A>"
287    echo "</H1>"
288    fi
289    cat <<EOF
290<TABLE bgcolor="$BG_COLOR" callpadding=1>
291<TR bgcolor="$FNAME_COLOR">
292EOF
293    while read m; do
294    ps="$cache/$head/ps/$m.ps"
295    if [ -r "$ps" ]; then
296        #
297        # Note: we read from variable ps_$head but we write to constant
298        # pdf_head. We can't use pdf_$head here, because that may just be a
299        # commit with a change and we thus generate a delta PDF below.
300        #
301        mkdir -p "$out/pdf_head"
302        schps2pdf -o "$out/pdf_head/$m.pdf" "$ps" || exit
303        all="$all \"$ps\""
304        echo "<TD><A href=\"pdf_head/$m.pdf\"><B>$m</B></A>"
305    else
306        echo "<TD><B>$m</B>"
307    fi
308    done < <(ls -1 "$out/names")
309    proj=`basename "$sch" .sch`
310    eval schps2pdf -t \""$proj-"\" -o \""$out/pdf_$proj.pdf"\" $all
311    echo "<TD><A href=\"pdf_$proj.pdf\">All sheets</A>"
312} >"$index"
313
314
315# --- Diff all the revisions, newest to oldest --------------------------------
316
317
318next="$head"
319for n in `cd "$dir" && git rev-list $first..HEAD~1` $first; do
320    [ -d "$cache/$n/ppm0" ] || continue
321    empty=true
322    s="<TR>"
323    mkdir -p "$out/$next/"{diff,thumb,html,pdf}
324    while read m; do
325    a0="$cache/$n/ppm0/$m.ppm"
326    a1="$cache/$n/ppm1/$m.ppm"
327    a2="$cache/$n/ppm2/$m.ppm"
328    aps="$cache/$n/ps/$m.ps"
329
330    b0="$cache/$next/ppm0/$m.ppm"
331    b1="$cache/$next/ppm1/$m.ppm"
332    b2="$cache/$next/ppm2/$m.ppm"
333    bps="$cache/$next/ps/$m.ps"
334
335    diff="$out/$next/diff/$m.png"
336    thumb="$out/$next/thumb/$m.png"
337    pdf="$out/$next/pdf/$m.pdf"
338
339    if [ -f "$a0" -a -f "$b0" ]; then
340        s="$s<TD align=\"center\" valign=\"middle\">"
341        if ! pngdiff cat "$diff" "$a1" "$b1" "$a0" "$b0"; then
342        s="$s<IMG src=\"unchanged.png\""
343        continue
344        fi
345        pngdiff shrink "$thumb" -f $THUMB_OPTS "$a2" "$b2" "$a0" "$b0" ||
346          exit
347        schps2pdf -T BEFORE -T AFTER -o "$pdf" "$aps" "$bps" || exit
348    elif [ -f "$a0" ]; then
349        s="$s<TD>"
350        pngdiff cat "$diff" -f -c 1,0,0 "$a1" "$a1" || exit
351        pngdiff shrink "$thumb" -f $THUMB_OPTS -c 1,0,0 "$a2" "$a2" ||
352          exit
353        schps2pdf -T DELETED -o "$pdf" "$aps" || exit
354    elif [ -f "$b0" ]; then
355        s="$s<TD>"
356        pngdiff cat "$diff" -f -c 0,1,0 "$b1" "$b1" || exit
357        pngdiff shrink "$thumb" -f $THUMB_OPTS -c 0,1,0 "$b2" "$b2" ||
358          exit
359        schps2pdf -T NEW -o "$pdf" "$bps" || exit
360    else
361        s="$s<TD>"
362        continue
363    fi
364    echo "$s"
365    s=
366        wrapped_png "$out" "$next" "$m"
367    empty=false
368    done < <(ls -1 "$out/names")
369    if ! $empty; then
370     echo "$s<TD valign=\"middle\">"
371    commit_entry "$dir" $next
372    fi
373    next=$n
374done >>"$index"
375
376
377# --- Add creation entries for all files in the first commit ------------------
378
379
380if [ -d "$cache/$next/ppm0" ]; then # could this ever be false ?
381    empty=true
382    echo "<TR>"
383    mkdir -p "$out/$next/"{diff,thumb,html,pdf}
384    while read m; do
385    p1="$cache/$next/ppm1/$m.ppm"
386    p2="$cache/$next/ppm2/$m.ppm"
387    ps="$cache/$next/ps/$m.ps"
388    diff="$out/$next/diff/$m.png"
389    thumb="$out/$next/thumb/$m.png"
390    pdf="$out/$next/pdf/$m.pdf"
391
392    echo "<TD>"
393    [ -f "$p1" ] || continue
394    pngdiff cat "$diff" -f -c 0,1,0 "$p1" "$p1" || exit
395    pngdiff shrink "$thumb" -f $THUMB_OPTS -c 0,1,0 "$p2" "$p2" ||
396      exit
397    schps2pdf -T NEW -o "$pdf" "$ps" || exit
398    wrapped_png "$out" "$next" "$m"
399    empty=false
400    done < <(ls -1 "$out/names")
401    if ! $empty; then
402     echo "<TD valign=\"middle\">"
403    commit_entry "$dir" $next
404    fi
405fi >>"$index"
406
407
408# --- Finish ------------------------------------------------------------------
409
410
411cat <<EOF >>"$index"
412</TABLE>
413<HR>
414`date -u '+%F %X'` UTC
415</BODY>
416</HTML>
417EOF
418

Archive Download this file



interactive