#!/usr/bin/env sh # # td: "Telodendria Developer" # # A helper script that operates sort of like Make, except it is # a lot easier to read and write than a Makefile, and it works on # any POSIX system. # # I chose to use a custom build script instead of using Make because # it is much more portable and flexible. This script doesn't only # handle building the code, it also handles formatting it, as well # as generating patch files. # # Set variables # # This syntax may look odd, but as far as I can tell, it is POSIX, # and it allows the values to be overridden by the environment, # such that these serve more as sane defaults than hard requirements. # : "${TELODENDRIA_VERSION:=0.1.0}" : "${CVS_TAG:=Telodendria-$(echo $TELODENDRIA_VERSION | sed 's/\./_/g')}" : "${DEFINES:=-D_DEFAULT_SOURCE -DTELODENDRIA_VERSION=\"$TELODENDRIA_VERSION\"}" : "${INCLUDES:=-Isrc/include}" : "${CC:=cc}" : "${CFLAGS:=-Wall -Wextra -pedantic -std=c89 -O3}" : "${LDFLAGS:=-lm -pthread -static -flto -fdata-sections -ffunction-sections -s -Wl,-static -Wl,-gc-sections}" : "${PROG:=telodendria}" . "$(pwd)/tools/lib/common.sh" CFLAGS="${CFLAGS} ${DEFINES} ${INCLUDES}" if [ "$DEBUG" = "1" ]; then CFLAGS="$CFLAGS -O0 -g" LDFLAGS="-lm -pthread -v" PROG="$PROG-debug" fi # Check the modificiation time of a file. This is used to do # incremental builds; we only want to rebuild files that have # have changed. mod_time() { if [ -n "$1" ] && [ -f "$1" ]; then case "$(uname)" in Linux|CYGWIN_NT*) stat -c %Y "$1" ;; *BSD|DragonFly) stat -f %m "$1" ;; *) # Platform unknown, force rebuilding the whole # project every time. echo "0" ;; esac else echo "0" fi } # Build the source code, and generate the 'build/telodendria' # binary. recipe_build() { mkdir -p build do_rebuild=0 objs="" for src in $(find src -name '*.c'); do obj=$(echo "$src" | sed -e 's/^src/build/' -e 's/\.c$/\.o/') objs="$objs $obj" if [ $(mod_time "$src") -ge $(mod_time "$obj") ]; then echo "CC $(basename $obj)" obj_dir=$(dirname "$obj") mkdir -p "$obj_dir" if ! $CC $CFLAGS -c -o "$obj" "$src"; then exit 1 fi do_rebuild=1 fi done if [ $do_rebuild -eq 1 ] || [ ! -f "build/$PROG" ]; then echo "LD $PROG" $CC $LDFLAGS -o "build/$PROG" $objs else echo "Up to date." fi } recipe_run() { if [ -f "build/$PROG" ]; then "build/$PROG" -f contrib/development.conf else echo "build/$PROG does not exist; build it first." fi } # Remove all build files, which can be regenerated by re-running the # build recipe. recipe_clean() { rm -r build } # Format the source code by updating the copyright headers and # then running indent(1) on each source code file. recipe_format() { find src -name '*.c' -or -name '*.h' | while IFS= read -r src; do # Update the headers srcHeader=$(grep -n -m 1 '^ \*/' "$src" | cut -d ':' -f 1) head "-n$srcHeader" "$src" | diff -u -p - LICENSE.txt | patch "$src" | grep -v "^Hmm" # Format the source code if indent "$src"; then rm $(basename "$src").BAK fi done } # Deploy the Telodendria website by copying the required files to # a web root defined by TELODENDRIA_PUB. recipe_site() { if [ -z "$TELODENDRIA_PUB" ]; then echo "No public root directory specified." echo "Set TELODENDRIA_PUB." exit 1 fi cp -v site/* "$TELODENDRIA_PUB/" find man/ -name '*.[1-9]' | while IFS= read -r man; do dir=$(dirname "$man") html=$(basename "$man") mkdir -p "$TELODENDRIA_PUB/$dir/" mandoc -Thtml -O style=/style.css,man=/man/man%S/%N.%S.html "$man" > "$TELODENDRIA_PUB/$dir/$html.html" echo "$man -> $TELODENDRIA_PUB/$dir/$html.html" done } # Generate a release tarball, checksum and sign it, and push it to # the web root. recipe_release() { if [ -z "$TELODENDRIA_PUB" ]; then echo "No public root directory specified." echo "Set TELODENDRIA_PUB." exit 1 fi mkdir -p "$TELODENDRIA_PUB/pub/v$TELODENDRIA_VERSION" cd "$TELODENDRIA_PUB/pub/v$TELODENDRIA_VERSION" # Tag the release at this point in time. cvs tag "$CVS_TAG" # Generate the release tarball. cvs export "-r$CVS_TAG" "Telodendria" mv "Telodendria" "Telodendria-v$TELODENDRIA_VERSION" tar -czf "Telodendria-v$TELODENDRIA_VERSION.tar.gz" \ "Telodendria-v$TELODENDRIA_VERSION" rm -r "Telodendria-v$TELODENDRIA_VERSION" # Checksum the release tarball. sha256 "Telodendria-v$TELODENDRIA_VERSION.tar.gz" \ > "Telodendria-v$TELODENDRIA_VERSION.tar.gz.sha256" # Sign the release tarball. if [ ! -z "$TELODENDRIA_SIGNIFY_SECRET" ]; then signify -S -s "$TELODENDRIA_SIGNIFY_SECRET" \ -m "Telodendria-v$TELODENDRIA_VERSION.tar.gz" \ -x "Telodendria-v$TELODENDRIA_VERSION.tar.gz.sig" else echo "Warning: TELODENDRIA_SIGNIFY_SECRET not net." echo "The built tarball will not be signed." fi } # Generate a formatted patch file. The Telodendria project isn't # really picky about how patches look, but this is how we like them # best. Makes them easy to read. recipe_patch() { # If the user has not set their MXID, try to deduce one from # their system. if [ -z "$MXID" ]; then MXID="@${USER}:$(hostname)" fi # If the user has not set their DISPLAY_NAME, try to deduce it # from their system. if [ -z "$DISPLAY_NAME" ]; then DISPLAY_NAME=$(getent passwd "$USER" | cut -d ':' -f 5 | cut -d ',' -f 1) fi # If the user has not set their EDITOR, use a safe default. # (vi should be available on any POSIX system) if [ -z "$EDITOR" ]; then EDITOR=vi fi NORMALIZED_MXID=$(echo "$MXID" | sed -e 's/@//g' -e 's/:/-/g') PATCH_FILE="${NORMALIZED_MXID}_$(date +%s).patch" # Generate the actual patch file # Here we write some nice headers, and then do a cvs diff. ( printf 'From: "%s" <%s>\n' "$DISPLAY_NAME" "$MXID" echo "Date: $(date)" echo "Subject: " echo echo "[ ] I have read the Telodendria Project developer certificate" echo " of origin, and certify that I have permission to submit" echo " this patch under the conditions specified in it." echo cvs -q diff -uNp $PATCHSET | grep -v '^\? ' ) > "$PATCH_FILE" "$EDITOR" "$PATCH_FILE" echo "$PATCH_FILE" } recipe_diff() { tmp_patch="/tmp/telodendria-$(date +%s).patch" cvs -q diff -uNp $PATCHSET > "$tmp_patch" if [ -z "$PAGER" ]; then PAGER="less -F" fi $PAGER "$tmp_patch" rm "$tmp_patch" } # Execute the user-specified recipes. for recipe in $@; do recipe_$recipe done # If no recipe was provided, run a build. if [ -z "$1" ]; then recipe_build fi