Classic Shell Scripting - Arnold Robbins [109]
We need a few variables, most initially empty, to collect command-line settings:
ALLTARGETS= Programs or make targets to build
altlogdir= Alternative location for log files
altsrcdirs= Alternative location for source files
ALTUSERHOSTS= File with list of additional hosts
CHECKTARGETS=check Make target name to run package test suite
CONFIGUREDIR=. Subdirectory with configure script
CONFIGUREFLAGS= Special flags for configure program
LOGDIR= Local directory to hold log files
userhosts= Additional build hosts named on command line
We also need to refer a few times to the directory where build-all's initialization files are found, so we give it a name:
BUILDHOME=$HOME/.build
Two scripts, executed on the remote host in the context of the login shell at the beginning and end of the build, provide for further customization and log-file reports. They overcome a secure-shell (ssh) problem with login shells of ksh or sh: those shells do not read $HOME/.profile unless they are started as login shells, and the secure shell doesn't arrange for that to happen if it is invoked with command arguments, as build-all does:
BUILDBEGIN=./.build/begin
BUILDEND=./.build/end
As in pathfind in Example 8-1, warnings contribute to a final exit code:
EXITCODE=0
There are no default extra environment variables:
EXTRAENVIRONMENT= Any extra environment variables to pass in
The program name is needed later, so we save its value and its version number:
PROGRAM=`basename $0` Remember program name
VERSION=1.0 Record program version number
We include timestamps in the build-log filenames, using the odometer style requested by the date format in DATEFLAGS to obtain filenames that sort in time order. Apart from punctuation, this is the format recommended in ISO 8601:2000.[2] We invoke date the same way later on the remote hosts, so we want the complex date format to be defined in just one place:
DATEFLAGS="+%Y.%m.%d.%H.%M.%S"
At our sites, we communicate with remote hosts using the secure shell, and we need both scp and ssh. Sites that still use the old insecure remote shell could change them to rcp and rsh. During development, we set these variables to "echo scp" and "echo ssh" so that the logs record what would have been done, without actually doing it:
SCP=scp
SSH=ssh
Depending on user and system configuration file settings, ssh may create a separate encrypted channel for X Window System traffic. We almost never require that feature in software builds, so we reduce startup overhead by turning it off with the -x option, unless a setting of the SSHFLAGS environment variable supplies a different set of options:
SSHFLAGS=${SSHFLAGS--x}
It proves useful to permit shell-style comments in initialization files. STRIPCOMMENTS provides a simple way to remove them, assuming that the comment character does not otherwise appear in the files:
STRIPCOMMENTS='sed -e s/#.*$//'
We also need a filter to indent a data stream (for better-looking output), and another to replace newlines by spaces:
INDENT="awk '{ print \"\t\t\t\" \$0 }'"
JOINLINES="tr '\n' '\040'"
Definitions of the two optional initialization files come next:
defaultdirectories=$BUILDHOME/directories
defaultuserhosts=$BUILDHOME/userhosts
The final initialization sets the list of source directories:
SRCDIRS="`$STRIPCOMMENTS $defaultdirectories 2> /dev/null`"
Since command substitution replaces newlines by spaces and collapses runs of whitespace, directories in the initialization file can be written one or more per line.
If the user customization file does not exist, STRIPCOMMENTS produces an empty string in SRCDIRS, so we test for that condition and reset SRCDIRS to a reasonable default list honed by years of experience:
test -z "$SRCDIRS" && \
SRCDIRS="
.
/usr/local/src
/usr/local/gnu/src
$HOME/src
$HOME/gnu/src
/tmp
/usr/tmp
/var/tmp
"
A backslash following the || and && operators at end-of-line is required for the C-shell family, and is harmless for the Bourne-shell family. The current directory (.) is a member