telodendria/tools/bin/td
Jordan Bancino 8d75d8a023 Add simple HTTP CLI tool that uses the HttpClient API.
You might be asking why I would just write a simple curl replacement
when curl does the job just fine. Well, the most immediate reason is
to test the HttpClient API, but since Telodendria's goal is to not
be dependent on any third-party code if at all possible, it makes
sense to have a simple HTTP client to use not only for testing
Telodendria, but also for configuring it. When we move the
configuration to the database, we'll ship a script that uses this
tool to allow admins to easily submit API requests.

Do not be concerned that HttpClient does not support TLS yet. TLS
support is necessary for federation to work, so it is coming
eventually.
2023-03-08 03:30:36 +00:00

309 lines
8.4 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.2.1}"
: "${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"
CFLAGS="${CFLAGS} ${DEFINES} ${INCLUDES}"
LDFLAGS="${LDFLAGS} ${STATIC}"
MAIN="Telodendria"
if [ "$DEBUG" = "1" ]; then
CFLAGS="$CFLAGS -O0 -g -pg"
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*|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 $LDFLAGS -o "build/$PROG" $objs "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") ]; then
echo "CC $(basename $out)"
mkdir -p "$(dirname $out)"
if ! $CC $CFLAGS $LDFLAGS -Isrc/include -o "$out" $objs "$src"; then
exit 1
fi
fi
done
}
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 . -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