forked from Telodendria/Telodendria
Jordan Bancino
e13442c122
tls_read() and tls_write() may return TLS_WANT_POLLIN or TLS_WANT_POLLOUT if data isn't ready to be read or written yet. We have to account for this by converting it to EAGAIN, which is how a typical read() or write() function should behave. Also installed a SIGPIPE handler; we do not want to be terminated by SIGPIPE, and it's safe to ignore this signal because it should be handled thoroughly in the code.
330 lines
9.1 KiB
Bash
330 lines
9.1 KiB
Bash
#!/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.3.0}"
|
|
: "${CVS_TAG:=Telodendria-$(echo $TELODENDRIA_VERSION | sed 's/\./_/g')}"
|
|
|
|
: "${DEFINES:=-D_DEFAULT_SOURCE -DTELODENDRIA_VERSION=\"${TELODENDRIA_VERSION}-$(uname)\"}"
|
|
|
|
: "${CC:=cc}"
|
|
: "${CFLAGS:=-Wall -Wextra -pedantic -ansi -O3 -pipe}"
|
|
: "${STATIC:=-static -Wl,-static}"
|
|
: "${LDFLAGS:=-lm -pthread -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections}"
|
|
: "${PROG:=telodendria}"
|
|
|
|
. "$(pwd)/tools/lib/common.sh"
|
|
|
|
if [ -n "$TLS_IMPL" ]; then
|
|
case "$TLS_IMPL" in
|
|
"TLS_LIBRESSL")
|
|
TLS_LIBS="-ltls -lcrypto -lssl"
|
|
;;
|
|
*)
|
|
echo "Unrecognized TLS implementation: ${TLS_IMPL}"
|
|
echo "Consult src/include/Tls.h for supported implementations."
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
DEFINES="${DEFINES} -DTLS_IMPL=${TLS_IMPL}"
|
|
LDFLAGS="${LDFLAGS} ${TLS_LIBS}"
|
|
fi
|
|
|
|
CFLAGS="${CFLAGS} ${DEFINES} ${INCLUDES}"
|
|
LDFLAGS="${LDFLAGS} ${STATIC}"
|
|
|
|
MAIN="Main"
|
|
|
|
if [ "$DEBUG" = "1" ]; then
|
|
CFLAGS="$CFLAGS -O0 -g"
|
|
LDFLAGS="-lm -pthread ${TLS_LIBS}"
|
|
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* | Haiku)
|
|
stat -c %Y "$1"
|
|
;;
|
|
*BSD | DragonFly | Minix)
|
|
stat -f %m "$1"
|
|
;;
|
|
*)
|
|
# Platform unknown, force rebuilding the whole
|
|
# project every time.
|
|
echo "0"
|
|
;;
|
|
esac
|
|
else
|
|
echo "0"
|
|
fi
|
|
}
|
|
|
|
# Substitute shell variables in a stream with their actual value
|
|
# in this shell.
|
|
setsubst() {
|
|
SED="/tmp/sed-$RANDOM.txt"
|
|
|
|
(
|
|
set | while IFS='=' read -r var val; do
|
|
val=$(echo "$val" | cut -d "'" -f 2- | rev | cut -d "'" -f 2- | rev)
|
|
echo "s|\\\${$var}|$val|g"
|
|
done
|
|
|
|
echo "s|\\\${[a-zA-Z_]*}||g"
|
|
echo "s|'''|'|g"
|
|
) >"$SED"
|
|
|
|
sed -f "$SED" $@
|
|
rm "$SED"
|
|
}
|
|
|
|
# Build the source code, and generate the 'build/telodendria'
|
|
# binary.
|
|
recipe_build() {
|
|
cd src
|
|
mkdir -p ../build
|
|
|
|
echo "CC = ${CC}"
|
|
echo "CFLAGS = ${CFLAGS}"
|
|
echo "LDFLAGS = ${LDFLAGS}"
|
|
echo
|
|
|
|
do_rebuild=0
|
|
objs=""
|
|
for src in $(find . -name '*.c' | cut -d '/' -f 2-); do
|
|
obj=$(echo "build/$src" | sed -e 's/\.c$/\.o/')
|
|
|
|
if [ $(basename "$obj" .o) != "$MAIN" ]; then
|
|
objs="$objs $obj"
|
|
fi
|
|
|
|
if [ $(mod_time "$src") -ge $(mod_time "../$obj") ]; then
|
|
echo "CC $(basename $obj)"
|
|
obj_dir=$(dirname "../$obj")
|
|
mkdir -p "$obj_dir"
|
|
if ! $CC $CFLAGS -Iinclude -c -o "../$obj" "$src"; then
|
|
exit 1
|
|
fi
|
|
do_rebuild=1
|
|
fi
|
|
done
|
|
|
|
cd ..
|
|
if [ $do_rebuild -eq 1 ] || [ ! -f "build/$PROG" ]; then
|
|
echo "LD $PROG"
|
|
$CC -o "build/$PROG" $objs ${LDFLAGS} "build/$MAIN.o"
|
|
fi
|
|
|
|
for src in $(find tools/src -name '*.c'); do
|
|
out=$(basename "$src" .c)
|
|
out="build/tools/$out"
|
|
|
|
if [ $(mod_time "$src") -ge $(mod_time "$out") ] || [ $do_rebuild -eq 1 ]; then
|
|
echo "CC $(basename $out)"
|
|
mkdir -p "$(dirname $out)"
|
|
if ! $CC $CFLAGS -Isrc/include -o "$out" $objs ${LDFLAGS} "$src"; then
|
|
exit 1
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
recipe_run() {
|
|
if [ -f "build/$PROG" ]; then
|
|
"build/$PROG" -f contrib/development.conf
|
|
|
|
dataDir=$(< contrib/development.conf json -s "dataDir->@decode")
|
|
if [ -f "$dataDir/Memory.txt" ]; then
|
|
echo "WARNING: Memory.txt exists in the data directory; this means"
|
|
echo "Telodendria is leaking memory. Please fix memory leaks."
|
|
fi
|
|
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 . -name '*.c' -or -name '*.h' | while IFS= read -r src; do
|
|
if [ -t 1 ]; then
|
|
printf "FMT %s%*c\r" $(basename "$src") "16" " "
|
|
fi
|
|
# 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
|
|
if [ -t 1 ]; then
|
|
printf "%*c\n" "50" " "
|
|
fi
|
|
}
|
|
|
|
# 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
|
|
|
|
# Set some variables that may be replaced in the files.
|
|
DATE=$(date)
|
|
USER_DOCS=$(man-table user)
|
|
DEV_DOCS=$(man-table dev)
|
|
|
|
cd site/
|
|
find . -type f | grep -v CVS | while IFS= read -r file; do
|
|
dest="$TELODENDRIA_PUB/$file"
|
|
dir=$(dirname "$dest")
|
|
|
|
echo "$dest"
|
|
|
|
mkdir -p "$dir"
|
|
setsubst "$file" >"$dest"
|
|
done
|
|
cd - >/dev/null
|
|
|
|
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 "$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
|
|
|
|
# Tag the release at this point in time.
|
|
cvs tag "$CVS_TAG"
|
|
|
|
mkdir -p "$TELODENDRIA_PUB/pub/v$TELODENDRIA_VERSION"
|
|
cd "$TELODENDRIA_PUB/pub/v$TELODENDRIA_VERSION"
|
|
|
|
# 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 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
|