telodendria/tools/bin/td

265 lines
6.7 KiB
Text
Raw Normal View History

2022-07-23 00:19:12 +00:00
#!/usr/bin/env sh
2022-07-29 21:09:15 +00:00
#
# 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.
2022-07-23 17:44:55 +00:00
#
# 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.
#
2022-07-23 00:19:12 +00:00
2022-07-23 17:44:55 +00:00
: "${TELODENDRIA_VERSION:=0.0.0}"
: "${CVS_TAG:=Telodendria-$(echo $TELODENDRIA_VERSION | sed 's/\./_/g')}"
2022-07-23 00:19:12 +00:00
2022-08-12 23:32:06 +00:00
: "${DEFINES:=-D_POSIX_C_SOURCE=200809L -DTELODENDRIA_VERSION=\"$TELODENDRIA_VERSION\"}"
2022-07-23 17:44:55 +00:00
: "${INCLUDES:=-Isrc/include}"
: "${CC:=cc}"
2022-08-01 20:09:18 +00:00
: "${CFLAGS:=-Wall -Wextra -pedantic -ansi -std=c89 -O3 $DEFINES $INCLUDES}"
: "${LDFLAGS:=-pthread -static -flto -fdata-sections -ffunction-sections -s -Wl,-static -Wl,-gc-sections}"
2022-07-23 17:44:55 +00:00
: "${PROG:=telodendria}"
2022-08-01 20:09:18 +00:00
# If a .env file exists in the current directory, we load it.
# As Telodendria's build infrastructure relies heavily on
# environment variables, we allow users to specify their
# Telodendria-specific variables in a dedicated .env so they don't
# have to pollute their environment.
if [ -f "$(pwd)/.env" ]; then
. "$(pwd)/.env"
fi
2022-08-10 14:49:17 +00:00
if [ "$DEBUG" = "1" ]; then
CFLAGS="$CFLAGS -O0 -g"
LDFLAGS="$LDFLAGS -v"
2022-08-10 14:49:17 +00:00
PROG="$PROG-debug"
fi
2022-07-29 21:09:15 +00:00
# Check the modificiation time of a file. This is used to do
# incremental builds; we only want to rebuild files that have
# have changed.
2022-07-23 00:19:12 +00:00
mod_time() {
if [ -n "$1" ] && [ -f "$1" ]; then
case "$(uname)" in
Linux)
stat -c %Y "$1"
;;
*BSD)
stat -f %m "$1"
;;
*)
2022-07-29 21:09:15 +00:00
# Platform unknown, force rebuilding the whole
# project every time.
2022-07-23 00:19:12 +00:00
echo "0"
;;
esac
else
echo "0"
fi
}
2022-07-29 21:09:15 +00:00
# Build the source code, and generate the 'build/telodendria'
# binary.
recipe_build() {
mkdir -p build
2022-07-23 00:19:12 +00:00
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"
2022-07-23 00:19:12 +00:00
if [ $(mod_time "$src") -gt $(mod_time "$obj") ]; then
echo "CC $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 build/$PROG"
$CC $LDFLAGS -o "build/$PROG" $objs
else
echo "Up to date."
fi
}
2022-08-13 02:00:36 +00:00
recipe_run() {
if [ -f "build/$PROG" ]; then
"build/$PROG" -c contrib/development.conf
else
echo "build/$PROG does not exist; build it first."
fi
}
2022-07-29 21:09:15 +00:00
# Remove all build files, which can be regenerated by re-running the
# build recipe.
recipe_clean() {
rm -rv build
}
2022-07-29 21:09:15 +00:00
# Format the source code by updating the copyright headers and
# then running indent(1) on each source code file.
2022-07-25 19:18:25 +00:00
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 - src/header.txt |
patch "$src"
# Format the source code
if indent "$src"; then
rm $(basename "$src").BAK
fi
2022-07-25 19:18:25 +00:00
done
}
2022-07-29 21:09:15 +00:00
# Execute all the unit tests and report any failures.
recipe_test() {
2022-08-06 02:20:07 +00:00
passed=0
failed=0
mkdir -p "build/tests"
for testSrc in $(find tests -name 'Test*.c'); do
testBin=$(basename "$testSrc" .c)
testBin="build/tests/$testBin"
if ! $CC $CFLAGS -I src -o "$testBin" "$testSrc"; then
failed=$((failed + 1))
break;
fi
if ! "$testBin"; then
failed=$((failed + 1))
break;
fi
passed=$((passed + 1))
done
echo "Passed: $passed, failed: $failed"
echo "Total: $((passed + failed))"
}
2022-07-29 21:09:15 +00:00
# Deploy the Telodendria website by copying the required files to
# a web root defined by TELODENDRIA_PUB.
2022-07-23 17:44:55 +00:00
recipe_site() {
if [ -z "$TELODENDRIA_PUB" ]; then
echo "No public root directory specified."
echo "Set TELODENDRIA_PUB."
exit 1
fi
2022-07-23 21:29:54 +00:00
# In the future, this might do more.
cp -v site/* "$TELODENDRIA_PUB/"
2022-07-23 17:44:55 +00:00
}
2022-07-29 21:09:15 +00:00
# Generate a release tarball, checksum and sign it, and push it to
# the web root.
2022-07-23 17:44:55 +00:00
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"
2022-07-29 21:09:15 +00:00
# Generate release tarball
2022-07-23 17:44:55 +00:00
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"
2022-07-29 21:09:15 +00:00
# Checksum release tarball
2022-07-23 17:44:55 +00:00
sha256 "Telodendria-v$TELODENDRIA_VERSION.tar.gz" \
> "Telodendria-v$TELODENDRIA_VERSION.tar.gz.sha256"
2022-07-29 21:09:15 +00:00
# Sign 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
2022-07-23 17:44:55 +00:00
}
2022-07-29 21:09:15 +00:00
# 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.
2022-07-29 18:42:23 +00:00
recipe_patch() {
2022-07-29 21:09:15 +00:00
# If the user has not set their MXID, try to deduce one from
# their system.
2022-07-29 18:42:23 +00:00
if [ -z "$MXID" ]; then
MXID="@${USER}:$(hostname)"
fi
2022-07-29 21:09:15 +00:00
# If the user has not set their DISPLAY_NAME, try to deduce it
# from their system.
2022-07-29 18:42:23 +00:00
if [ -z "$DISPLAY_NAME" ]; then
DISPLAY_NAME=$(getent passwd "$USER" | cut -d ':' -f 5 | cut -d ',' -f 1)
fi
2022-07-29 21:09:15 +00:00
# If the user has not set their EDITOR, use a safe default.
# (vi should be available on any POSIX system)
2022-07-29 18:42:23 +00:00
if [ -z "$EDITOR" ]; then
EDITOR=vi
fi
2022-07-29 19:28:49 +00:00
NORMALIZED_MXID=$(echo "$MXID" | sed -e 's/@//g' -e 's/:/-/g')
PATCH_FILE="${NORMALIZED_MXID}_$(date +%s).patch"
2022-07-29 21:09:15 +00:00
# Generate the actual patch file
# Here we write some nice headers, and then do a cvs diff.
2022-07-29 18:42:23 +00:00
(
printf 'From: "%s" <%s>\n' "$DISPLAY_NAME" "$MXID"
echo "Date: $(date)"
2022-07-29 18:42:23 +00:00
echo "Subject: "
echo
2022-07-29 21:09:15 +00:00
cvs -q diff -uNp $PATCHSET | grep -v '^\? '
) > "$PATCH_FILE"
2022-07-29 18:42:23 +00:00
"$EDITOR" "$PATCH_FILE"
echo "$PATCH_FILE"
2022-07-29 18:42:23 +00:00
}
2022-07-29 21:09:15 +00:00
recipe_diff() {
2022-08-01 20:09:18 +00:00
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"
2022-07-29 21:09:15 +00:00
}
# Execute the user-specified recipes.
for recipe in $@; do
recipe_$recipe
2022-07-23 00:19:12 +00:00
done
2022-07-29 21:09:15 +00:00
# If no recipe was provided, run a build.
if [ -z "$1" ]; then
recipe_build
2022-07-23 00:19:12 +00:00
fi
2022-07-23 17:44:55 +00:00