Building Apps and Getting Notified
8 minute readUse what we've learned to build for F-Droid and get a Telegram message when it's done.
If you’ve followed along with all of the articles in this series you’ll now have:
- A complete F-Droid build environment set up in a container
- A Telegram bot raring to go
Now we’ll put it all together, add some bash scripts to make everything easy to work with, and see how to get notified in Telegram when the local F-Droid build process has finished.
We use a couple of shell scripts to facilitate this, they’re available here in my Codeberg repo.
I’ll refer to the Alpine container as the host as all of these instructions are based on that environment, and from that context the F-Droid docker container will be the guest.
Alpine container directory structure
So far in our Alpine container we should have a couple of directories which are our local clones of the F-Droid repos fdroiddata
and fdroidserver
.
We also need to add a directory where we’ll store our shell scripts:
mkdir shell-scripts
So now we should have the following structure (I named my Alpine container fdroid
):
fdroid:~$ ls -1
fdroiddata
fdroidserver
shell-scripts
The scripts
In ~/shell-scripts
we’ll have two scripts. Don’t forget to make sure they’re executable with chmod +x
.
docker-run-fdroidserver.sh
Run this on the Alpine host to start the container.
This is really just a docker run
command, based on the example given in the F-Droid docs, then heavily commented for people like me who aren’t experts in docker and need to be reminded of the basics.
Here is the script:
#!/bin/sh
# Based on F-Droid's guide at https://f-droid.org/en/docs/Submitting_to_F-Droid_Quick_Start_Guide/
# The only amendment to this script from the above URL are:
# - Mount an additional volume, the `shell-scripts` directory (parent directory of this script and `fdroid-prepare-env.sh`)
# - Change the entry point to `fdroid-prepare-env.sh`
# - Pass a couple of environment variables, IDs to be used to interact with Telegram so we can get a message pushed when a process finishes
# Explanation of command:
# `run` creates a container from the image (image is given as final argument to the command)
# --rm when the container is exited, automatically remove it (the container, not the image)
# -i `--interactive`, meaning you will be put into a `/bin/bash` (from the later command) session in the container
# -t `--tty` container output gets sent to a virtual tty, meaning it will be formatted nicely and behave in specific expected ways
# -u `--user` so in this case we are running as user 'vagrant'
# --entrypoint overrides the default ENTRYPOINT of the image
# -v mount a volume, the arg:arg format mounts a local (1st arg) volume inside the container at (2nd arg)
# :z at the end means Docker labels the content with a shared content label. Shared volume labels allow all containers to read/write content
# :Z at the end means Docker to label the content with a private unshared label. Only the current container can use a private volume
# -e environment variable to be passed
# [final arg] the image from which the container will be created
# Notes on setting up credentials for Telegram bot
# Based on tips from https://www.techrepublic.com/article/how-to-safely-store-passwords-linux-server/
# sudo apk add pass gnupg gnupg2 pinentry-tty
# gpg2 --full-generate-key
# pass init m@mm-dev.rocks
# pass insert telegrambot/botid
# pass insert telegrambot/chatid
# gpg-connect-agent reloadagent /bye
sudo docker run --rm -itu vagrant --entrypoint /home/vagrant/shell-scripts/fdroid-prepare-env.sh \
-v ~/fdroiddata:/build:z \
-v ~/fdroidserver:/home/vagrant/fdroidserver:Z \
-v ~/shell-scripts:/home/vagrant/shell-scripts:Z \
-e TELEGRAM_BOTID="$(pass telegrambot/botid)" \
-e TELEGRAM_CHATID="$(pass telegrambot/chatid)" \
registry.gitlab.com/fdroid/fdroidserver:buildserver
In addition to the F-Droid original functionality, this version does a few other important things:
- Pass in, as environment variables, some credentials which are required to access a Telegram bot via the Telegram API
- API token for the bot
- An ID for the chat channel that the message will be delivered to
- Mount our
~/shell-scripts
directory in the container so that thefdroid-prepare-env.sh
script is available to it - Set the
fdroid-prepare-env.sh
script as the entry point for the container so that it automatically runs
As explained earlier in this series of articles, the Telegram credentials are stored on the host via GPG passwords and passed to the container as environment variables.
This means the credentials will be accessible in the clear to the container user so if this isn’t secure enough for your needs you should use another method.
fdroid-prepare-env.sh
This script is run inside the container to finish setting it up.
fdroid-prepare-env.sh
is stored on the Alpine host in the~/shell-scripts
directory- But that
~/shell-scripts
directory is mounted as a volume inside the container as/home/vagrant/shell-scripts
vagrant
is the name of the user inside the container - So the script is accessible from inside the container
As it is passed (by the docker-run-fdroidserver.sh
script) to the docker run
command as the entry point, it gets run automatically when the container starts.
The full script is below:
#!/bin/bash
# #################################
#
# F-Droid build tools helper script
#
# #################################
#
# Docker image housekeeping, stuff to be done whenever the F-Droid container is creaated.
# Based on F-Droid's guide at https://f-droid.org/en/docs/Submitting_to_F-Droid_Quick_Start_Guide/
#
# - Several commands need to be run inside the container every time it starts, meaning constandly having to refer to the above URL
# - Instead, now this script is passed as the entry point to `docker run`
# - Alongside the F-Droid recommendations, export a function `send_tg_alert`, which allows a Telegram message to be sent when a command has completed execution
# Bring in system-wide settings and add some environment variables
# #################################
. /etc/profile
export PATH="$fdroidserver:$PATH" PYTHONPATH="$fdroidserver"
export JAVA_HOME=$(java -XshowSettings:properties -version 2>&1 > /dev/null | grep 'java.home' | awk -F'=' '{print $2}' | tr -d ' ')
# Create the message text to be sent to Telegram
# #################################
#
# - The message contains the shell command (from history) last entered (ie the command that was run and we are informing the recipient about)
# - Use MarkdownV2 syntax, see notes at https://core.telegram.org/bots/api#markdownv2-style
# - Use heredoc style to create the message and allow sending of newlines to survive the following pipeline:
# bash | curl (GET, urlencode) | Telegram API
function get_msg_text {
# Enable history, as it's not usually available from within bash scripts
set -o history
cat <<EOF
\`\`\`
# F\\-Droid command finished at:
# $(date)
# Command as entered:
\$ $(history | cut -c 8-)
\`\`\`
EOF
}
# Send a Telegram message via a bot
# #################################
function send_tg_alert {
# Use heredoc style to create $MSG_TXT and allow sending of newlines to survive:
# bash | curl (GET, urlencode) | Telegram API
MSG_TXT=$(get_msg_text)
echo "$MSG_TXT"
# $TELEGRAM_CHATID and $TELEGRAM_BOTID should already exist in this container as environment variables,
# having been passed in via the `docker run` command
curl \
--get \
--data-urlencode "chat_id=${TELEGRAM_CHATID}" \
--data-urlencode "parse_mode=MarkdownV2" \
--data-urlencode "text=${MSG_TXT}" \
https://api.telegram.org/bot${TELEGRAM_BOTID}/sendMessage
}
# Make functions available to the container and shell
# #################################
#
# If functions calls other functions, all functions in the chain need to be exported
export -f send_tg_alert
export -f get_msg_text
# Finish up...
# #################################
#
# Show some helpful reminders
cat << EOF
Example commands:
fdroid readmeta
fdroid rewritemeta com.example
fdroid checkupdates --allow-dirty com.example
fdroid lint com.example
fdroid build com.example
To send a Telegram message after the command has completed, append '; send_tg_alert', eg:
fdroid build com.example ; send_tg_alert
EOF
# Enter the directory which is most likely to be useful when the F-Droid commands are run
cd /build
# By default, the container would exit at the end of this ENTRYPOINT script --- start a shell instead.
/bin/bash "$@"
The effects of running the script in the container are:
- Sets up some environment variables as per F-Droid’s instructions
- Creates and exports our
send_tg_alert
function which can be called to send a message to a Telegram bot when a shell command has finished - The notification message sent by the function will include the command which was run/finished
The Telegram messaging is useful because the F-Droid build command can take a long time to complete. The function is just appended as an extra command eg:
# Build the 'com.example.appname'
# then send a Telegram message
fdroid build com.example.appname ; send_tg_alert
The F-Droid command will run, and when it ends a Telegram message will be sent to the specified channel, saying something like:
# F-Droid command finished at:
# Mon Jul 29 17:34:42 UTC 2024# Command as entered:
$ fdroid build com.example.appname ; send_tg_alert
The F-Droid build commands
Now from inside the docker container (the entry point script should have put us inside the /build
directory already) we can run the fdroid commands.
You can run fdroid --help
to get a list of subcommands such as:
# Build a package from source
fdroid build
# Read all the metadata files and exit
fdroid readmeta
# Rewrite all the metadata files
fdroid rewritemeta
# Warn about possible errors in the metadata
fdroid lint
For each command you can append --help
for more details, eg fdroid build --help
, but check the official documentation for full details.