#!/bin/bash
########################################################################
# simh-update - Attempt to automatically merge in the latest upstream
# SIMH 4 changes from the GitHub repository.
#
# Copyright © 2017-2018 Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above
# shall not be used in advertising or otherwise to promote the sale,
# use or other dealings in this Software without prior written
# authorization from those authors.
########################################################################
SRCDIR="@srcdir@"
SRCSUBDIR="$SRCDIR/src/SIMH"
PRGNAME="$(basename "$0")"
WORKDIR="@builddir@/$PRGNAME-temp"
OUR_SIMH_DIR="$WORKDIR/simh/ours"
CURR_SIMH_DIR="$WORKDIR/simh/curr"
LOGFILE="$WORKDIR/output.log"
PATCHFILE="$WORKDIR/pidp8i.patch"
OLD_SGCID=$(grep ^SGCID "@srcdir@"/Makefile.in | cut -f2 -d=)
SOFFICE=/Applications/LibreOffice.app/Contents/MacOS/soffice
# If LibreOffice isn't here, we can't convert DOC to PDF below.
if [ ! -x "$SOFFICE" ]
then
cat <<USAGE
Sorry, this must be run on a system where LibreOffice is installed
as $SOFFICE.
TODO: Find this same program in other places.
USAGE
exit 1
fi
# If we don't have the Git worktree sub-command, we're probably running
# this on Jessie, which ships Git 2.1.4.
if ! git help worktree &> /dev/null
then
cat <<ERROR
Sorry, this must be run on a system with the "git worktree" feature,
which first shipped in Git 2.5.
ERROR
exit 1
fi
# Set up working directory
rm -rf "$WORKDIR"
mkdir -p "$WORKDIR"
# From here on, send all output to the log file.
# Code based on http://stackoverflow.com/a/20564208/142454
exec 1<&-
exec 2<&-
exec 1<>"$LOGFILE"
exec 2>&1
function say() {
echo "$@" >> /dev/tty
}
# Bail on errors so we don't have to test everything. Ideally, nothing
# from here on will fail. If it does, the log file will explain it.
# Code based on http://stackoverflow.com/a/185900/142454
function error() {
lineno="$1"
message="$2"
code="${3:-1}"
if [ -n "$message" ] ; then message=": $message" ; fi
read -r -d '%' errmsg <<ERROR
Error on or near line $lineno, code ${code}$message! (See log file for
more info: $LOGFILE)
%
ERROR
say
say "$errmsg"
say
exit $code
}
trap 'error ${LINENO}' ERR
# Deal with uncommitted changes in $SRCSUBDIR
cd "$SRCSUBDIR/.." # we need the SIMH/ prefix to do this test properly!
if [ $(fossil status | grep '^EDITED.*SIMH/' | wc -l) -gt 0 ]
then
if [ "$1" = "-f" ]
then
say "Tossing uncommitted changes in $SRCSUBDIR..."
fossil revert $(fossil status | grep '^EDITED.*SIMH/' | cut -f 2- -d' ')
shift
else
read -r -d '%' errmsg <<ERROR
Cowardly refusing to update SIMH to the current upstream version while
there are uncommitted changes in $SRCSUBDIR. Say
make simh-update-f
or pass -f to force those changes to be tossed.
%
ERROR
say
say "$errmsg"
say
exit 3
fi
fi
cd "@builddir@"
# Retreive the tip-of-master and $OLD_SGCID versions of SIMH
say Retreiving upstream SIMH versions...
mkdir -p "$OUR_SIMH_DIR"
mkdir -p "$CURR_SIMH_DIR"
git clone https://github.com/open-simh/simh.git "$CURR_SIMH_DIR"
pushd "$CURR_SIMH_DIR"
NEW_SGCID=$(git log -1 --pretty='%H')
NEW_SGCTM=$(git log -1 --pretty='%aI')
say "Pulled ${NEW_SGCID:0:8} as curr, authored ${NEW_SGCTM}; prev is ${OLD_SGCID:0:8}."
git worktree add "$OUR_SIMH_DIR" $OLD_SGCID
popd
# Copy over updated versions of the docs and replace them in the Fossil
# unversioned area. We simplify the upstream naming scheme in the
# transfer, dropping unnecessary prefixes and suffixes.
pushd "$SRCDIR"
pdfdir=doc/simh
mkdir -p $pdfdir
for fs in pdp8_doc simh_faq simh_doc
do
ft=$(echo $fs | sed -e 's/simh_//' -e 's/_doc//')
test "$ft" = "doc" && ft=main
pdfout=$pdfdir/$ft.pdf
pdftmp="$fs.pdf"
say -n "Converting upstream $fs.doc to $pdfout..."
if [ ! -e "$pdfout" ]
then
# Pull a copy out of the unversioned store
fossil uv export $pdfout $pdfout
fi
if "$SOFFICE" --convert-to pdf "$CURR_SIMH_DIR/doc/$fs.doc"
then
szo=$(stat -f %z $pdfout)
szt=$(stat -f %z $pdftmp)
if [ -n "$szo" ] && [ -n "$szt" ] && [ "$szo" != "$szt" ]
then
# The upstream doc has apparently changed, since the PDF output
# file is a different size. Replace our public version.
#
# We can't use cmp or similar here because a bunch of metadata
# change each time we re-render the PDF, even if the source doc
# is unchanged. There are proper PDF comparison tools, but none
# preinstalled everywhere, and we don't want to make one of
# those tools a dependency of this script. Size comparison
# suffices for our purposes, since most any substantial text
# change will change the output file size.
say "changes detected."
mv "$pdftmp" "$pdfout"
fossil uv add "$pdfout"
else
say "unchanged."
fi
else
say "generation failed!"
exit 1
fi
done
say "Syncing new PDFs..."
fossil uv sync
popd
# Rename upstream Git paths to match our *.in files so that our produced
# patches are made against those higher-level versions. If we didn't do
# this, we'd have to manually resubstitute variables for absolute paths.
#
# Filter out Makefile.in because we don't want to try and patch the
# upstream plain Makefile to work with autosetup. It complicates the
# resulting patch file to no purpose.
say Renaming upstream files to match our \*.in variants...
find "$SRCSUBDIR" -name \*.in -print | grep -v Makefile.in | while read f
do
inf="${f#$SRCSUBDIR/}" # make path fully relative
genf="${inf%.in}" # remove .in from the end
if [ -f "$OUR_SIMH_DIR/$genf" ]
then
mv "$OUR_SIMH_DIR/$genf" "$OUR_SIMH_DIR/$inf"
mv "$CURR_SIMH_DIR/$genf" "$CURR_SIMH_DIR/$inf"
fi
# else, it's a *.in file specific to our code base, not a
# parameterized version of an upstream file
done
# Remove untracked files: we don't want them appearing in the diff.
fossil extra | grep src/SIMH | while read doomed
do
rm -f "$doomed"
done
# Produce a patch file for modifying the upstream $OLD_SGCID version to
# merge in our local changes.
#
# For some reason, diff(1) returns an error when we do this, at least on
# OS X. Perhaps it is not happy about the fact that the file set in
# each tree is different? Regardless of reason, we must check for a
# non-empty patch file to determine whether an actual error occurred.
say Producing clean patch file from upstream ${OLD_SGCID:0:8} version
say to our local PiDP-8/I version...
if ! diff -ru "$OUR_SIMH_DIR" "$SRCSUBDIR" | grep -v '^Only in' > "$PATCHFILE" &&
[ ! -s "$PATCHFILE" ]
then
error $LINENO "patch generation failed" 2
fi
# For each file in src/SIMH that is also present in the current upstream
# version of SIMH, overwrite our version.
find "$SRCSUBDIR" -type f -print | while read f
do
base="${f#$SRCSUBDIR}"
upstream="$CURR_SIMH_DIR/$base"
test -e "$upstream" && cp "$upstream" "$f"
done
# Now try to apply the patch we made above to the upstream files.
patch -p0 < "$PATCHFILE"
# No error, so save the new tip-of-master Git commit ID and rebuild.
# Force at least SCP to rebuild, else new values won't be added.
#
# The reconfig step is sidesteps a dependency bug in the current
# Makefile.in which allows make(1) to rebuild scp.o before the automatic
# reconfig occurs, so the old timestamp gets baked into the simulator.
# It'd be better to fix the bug, but I failed to diagnose it.
say "Patch appears to have applied cleanly. Attempting a rebuild..."
sed -e "s/^SGCID=.*/SGCID=$NEW_SGCID/" \
-e "s/^SGCTM=.*/SGCTM=$NEW_SGCTM/" \
-i tmp @srcdir@/Makefile.in
touch src/SIMH/scp.c
make reconfig
tools/mmake
# Restore stdout and let the human test it
say "Build completed without error. Running default bootscript to test it..."
say
say "(Nuke $WORKDIR when finished.)"
say
exec 1<&-
exec 1<>/dev/tty
exec make run