#!/bin/echo "This file is sourced, not run" # This file contains generic functions, presumably reusable in other contexts. # Create a blank directory at first argument, deleting existing contents if any proc blank_tempdir { # sanity test: never rm -rf something we don't own. test -z $1 && dienow touch -c $1 || dienow # Delete old directory, create new one. test -z $NO_CLEANUP && rm -rf $1 mkdir -p $1 || dienow } # output the sha1sum of a file proc sha1file { sha1sum /dev/null @Argv | tail -n +2 | awk '{print $1}' } # dienow() is an exit function that works properly even from a subshell. # (actually_dienow is run in the parent shell via signal handler.) proc actually_dienow { echo -e "\n\e[31mExiting due to errors ($ARCH_NAME $STAGE_NAME $PACKAGE)\e[0m" > !2 exit 1 } trap actually_dienow SIGUSR1 setglobal TOPSHELL = $Pid proc dienow { kill -USR1 $TOPSHELL exit 1 } # Turn a bunch of output lines into a much quieter series of periods, # roughly one per screenfull proc dotprogress { setglobal x = '0' while read i { setglobal x = $shExpr('$x + ') if [[ "$x" -eq 25 ]] { setglobal x = '0' echo -n . } } echo } # Announce an action to the world proc announce { # Write a line to the log file with easily greppable header echo "=== $1 ($ARCH_NAME $STAGE_NAME)" # Set the title bar of the current xterm test -z $NO_TITLE_BAR && echo -en "\033]2;$ARCH_NAME $STAGE_NAME $1\007" } # Filter out unnecessary noise, keeping just lines starting with "===" proc maybe_quiet { test -z $FORK && cat || grep "^===" } # Run a command background if FORK is set, in foreground otherwise proc maybe_fork { test -z $BUILD_VERBOSE || echo "$ifsjoin(Argv)" if test -z $FORK { eval "$ifsjoin(Argv)" } else { eval "$ifsjoin(Argv)" & } } # Kill a process and all its decendants proc killtree { var KIDS = ''"" while [ $# -ne 0 ] { set KIDS = ""$KIDS $[pgrep -P$1]"" shift } set KIDS = $[echo -n $KIDS] if test ! -z $KIDS { # Depth first kill avoids reparent_to_init hiding stuff. killtree $KIDS kill $KIDS !2 >/dev/null } } # Search a colon-separated path for files matching a pattern. # Arguments are 1) path to search, 2) pattern, 3) command to run on each file. # During command, $DIR/$FILE points to file found. proc path_search { # For each each $PATH element, loop through each file in that directory, # and create a symlink to the wrapper with that name. In the case of # duplicates, keep the first one. echo $1 | sed 's/:/\n/g' | while read DIR { find "$DIR/" -maxdepth 1 -mindepth 1 -name $2 | sed 's@.*/@@' | \ while read FILE { eval $3 # Output is verbose. Pipe it to dotprogress. echo $FILE } } } # Abort if we haven't got a prerequisite in the $PATH proc check_prerequisite { if test -z $[which $1] { test -z $FAIL_QUIET && echo No $1 in '$PATH'. > !2 dienow } } # Search through all the files under a directory and collapse together # identical files into hardlinks proc collapse_hardlinks { setglobal SHA1LIST = ''"" find $1 -type f | while read FILE { echo $FILE setglobal SHA1 = $[sha1file $FILE] setglobal MATCH = $[echo $SHA1LIST | grep "^$SHA1] if test -z $MATCH { # Yes, the quote spanning two lines here is intentional setglobal SHA1LIST = ""$SHA1LIST $SHA1 $FILE"" } else { setglobal FILE2 = $[echo $MATCH | sed 's/[^ ]* //] cmp -s $FILE $FILE2 || continue ln -f $FILE $FILE2 || dienow } } } # Check if $1 is in the comma separated list $2 proc is_in_list { test $2 == all || test ! -z $[echo ,"$2", | grep ,"$1",] }