253 lines
7.3 KiB
Bash
Executable File
253 lines
7.3 KiB
Bash
Executable File
#! /bin/bash
|
|
|
|
# Catch signals so we don't leave zombie tasks behind if we Ctrl^C
|
|
# No idea why but it seems to prevent the script from working? Disable!
|
|
#trap "exit" INT TERM ERR
|
|
#trap "kill 0" EXIT
|
|
|
|
# Default logging levels (error is always enabled)
|
|
INFO=1
|
|
DEBUG=0
|
|
|
|
# TODO: Remove this quickhack which prevents from using real value in tasks
|
|
# (but enables unit testing of host-based config)
|
|
if [ ! -z $HOST ]; then
|
|
HOSTNAME="$HOST"
|
|
fi
|
|
|
|
# Extract two letters from $LANG
|
|
locale="${LANG:0:2}"
|
|
|
|
# Ensure translations have been setup
|
|
if [ -d /usr/share/forgebuild/i18n ]; then
|
|
I18N_DIR=/usr/share/forgebuild/i18n
|
|
elif [ -d $HOME/.local/share/forgebuild/i18n ]; then
|
|
I18N_DIR=$HOME/.local/share/forgebuild/i18n
|
|
else
|
|
echo "ERROR: could not find translations. Maybe you need to run the setup.sh script?"
|
|
exit 1
|
|
fi
|
|
|
|
# Initialize translations
|
|
[ -f $I18N_DIR/$locale.json ] && locale_strings="$(cat $I18N_DIR/$locale.json)" || locale_strings="$(cat $I18N_DIR/en.json)"
|
|
|
|
# Takes one argument, looks up translation
|
|
trans() {
|
|
res="$(echo "$locale_strings" | jq ".$1")"
|
|
if [[ "$res" = "" ]]; then
|
|
echo "ERROR: Failed to translate $1"
|
|
exit 1
|
|
fi
|
|
res=${res#"\""}
|
|
res=${res%"\""}
|
|
echo -n "$res"
|
|
}
|
|
|
|
# We set custom logging functions so that later we can decorate stuff
|
|
warn() {
|
|
[[ $INFO = 1 ]] && echo -e "\e[33m$(trans warning)\e[0m$(trans $1)" | envsubst > /dev/stderr
|
|
}
|
|
|
|
info() {
|
|
[[ $INFO = 1 ]] && echo "[git-build] $(trans $1)" | envsubst
|
|
}
|
|
|
|
error () {
|
|
echo -e "\e[31m$(trans error)\e[0m$(trans $1)" | envsubst > /dev/stderr
|
|
}
|
|
|
|
debug () {
|
|
[[ $DEBUG = 1 ]] && echo -e "\e[36m$(trans debug)\e[0m$(trans $1)" | envsubst
|
|
}
|
|
|
|
help () {
|
|
echo "forgebuild [tasks]"
|
|
echo " Trigger updates on `tasks` (all tasks by default)"
|
|
echo "ARGS:"
|
|
echo " -f: force run of tasks regardless of updates on the repository"
|
|
echo " -b BASEDIR: consider tasks from BASEDIR, not ~/.forgebuild"
|
|
}
|
|
|
|
# Logging is done with the LOG="debug|info|error" environment variable
|
|
if [ ! -z $LOG ] && [ "$LOG" != "" ]; then
|
|
case $LOG in
|
|
"debug"|"DEBUG")
|
|
DEBUG=1
|
|
;;
|
|
"error"|"ERROR")
|
|
INFO=0
|
|
;;
|
|
"info"|"INFO")
|
|
# Default settings
|
|
;;
|
|
*)
|
|
warn loglevel_bad
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
run() {
|
|
p_name="$1"
|
|
i18n_task="$p_name" info run
|
|
# Run in background and redirect output to $p_name.log
|
|
#(GITBUILDCONF="$CONFDIR" GITBUILDDIR="$BASEDIR" nohup $BASEDIR/$p_name $p_name > $BASEDIR/$p_name.log 2>&1) &
|
|
GITBUILDCONF="$CONFDIR" GITBUILDDIR="$BASEDIR" $BASEDIR/$p_name $p_name > $BASEDIR/$p_name.log 2>&1
|
|
}
|
|
|
|
# Overriden by -f/--force to force rebuild when no update is available
|
|
FORCE=0
|
|
|
|
# Find targeted projects from args and extra arguments
|
|
PROJECTS=()
|
|
BASEDIR="$HOME/.forgebuild"
|
|
FOUND_BASEDIR=0
|
|
for arg in "$@"; do
|
|
if [ $FOUND_BASEDIR -eq 1 ]; then
|
|
BASEDIR="$(readlink -m $arg)"
|
|
if [ ! -d $BASEDIR ]; then
|
|
echo "ERROR: Could not find task directory: $BASEDIR"
|
|
exit 1
|
|
fi
|
|
FOUND_BASEDIR=0
|
|
elif [[ "$arg" = "-f" ]] || [[ "$arg" = "--force" ]]; then
|
|
info force_flag
|
|
FORCE=1
|
|
elif [[ "$arg" = "-b" ]] || [[ "$arg" = "--basedir" ]]; then
|
|
FOUND_BASEDIR=1
|
|
# Maybe it's a task name and we find a corresponding source?
|
|
# TODO: Support source-less tasks https://tildegit.org/southerntofu/git-build.sh/issues/8
|
|
elif [ -f $BASEDIR/$arg.source ]; then
|
|
export i18n_task="$arg"
|
|
debug found_task
|
|
PROJECTS+=("$arg")
|
|
# Maybe it's a repo URL and we find a corresponding task?
|
|
elif matches="$(grep --files-with-matches --word-regexp "$arg" $BASEDIR/*.source)"; then
|
|
# Iterate over the files found to extract the task name
|
|
IFS= echo "$matches" | while read -r file; do
|
|
task_name="$(basename "$file" .source)"
|
|
# Make sure we don't have a .source file without name lying around, just in case
|
|
if [[ "$task_name" != "" ]]; then
|
|
export i18n_task="$task_name" i18n_source="$arg"
|
|
debug found_url
|
|
PROJECT+=("$task_name")
|
|
fi
|
|
done
|
|
else
|
|
export i18n_arg="$arg"
|
|
error unknown_arg
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
# Still the default BASEDIR, if it doesn't exist we create it as a convenience
|
|
if [ ! -d $BASEDIR ]; then
|
|
echo "ERROR: No such basedir: $BASEDIR. Creating it and aborting"
|
|
exit 1
|
|
fi
|
|
|
|
# So scripts can know we're still running (for autoupdater)
|
|
echo "$BASHPID" > $BASEDIR/.LOCK
|
|
|
|
# If no project argument passed, default to all projects
|
|
if [[ ${#PROJECTS[*]} = 0 ]]; then
|
|
info no_task
|
|
# TODO: sourceless tasks
|
|
for file in $BASEDIR/*.source; do
|
|
# Extract the project name from path
|
|
task="$(basename $file .source)"
|
|
export i18n_task="$task"
|
|
debug found_task
|
|
PROJECTS+=("$task")
|
|
done
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Check if we have host-specific config or default to the config/ folder
|
|
[ -d $BASEDIR/$HOSTNAME ] && CONFDIR="$BASEDIR/$HOSTNAME" || CONFDIR=$BASEDIR/config
|
|
export i18n_config="$CONFDIR"
|
|
info config
|
|
|
|
# TODO: sourceless tasks
|
|
for p_name in ${PROJECTS[*]}; do
|
|
# For translations
|
|
export i18n_task="$p_name"
|
|
debug start_proc
|
|
# Check if task should run on host
|
|
if [ -f $BASEDIR/$p_name.hosts ]; then
|
|
if ! grep "^\s*$HOSTNAME\s*$" $BASEDIR/$p_name.hosts > /dev/null; then
|
|
# The task is specifically configured for different hosts, ignore
|
|
export i18n_host="$for_host"
|
|
debug skipped
|
|
continue
|
|
fi
|
|
fi
|
|
# The task has a PROJECT.ignore file in host config, ignore
|
|
if [ -f $BASEDIR/$HOSTNAME/$p_name.ignore ]; then
|
|
info host_ignored
|
|
continue
|
|
fi
|
|
info process
|
|
# checkout a specific branch/commit
|
|
if [ -f $BASEDIR/$p_name.checkout ]; then
|
|
p_branch="$(cat $BASEDIR/$p_name.checkout)"
|
|
export i18n_branch="$p_branch"
|
|
info to_branch
|
|
else
|
|
# TODO: support non-master primary branch
|
|
p_branch="master"
|
|
export i18n_branch="$p_branch"
|
|
debug default_branch
|
|
fi
|
|
p_dir="$BASEDIR/.$p_name"
|
|
if [ ! -d $p_dir ]; then
|
|
source="$(cat $BASEDIR/$p_name.source)"
|
|
export i18n_source="$source"
|
|
info clone
|
|
# Don't forget the git submodules!
|
|
if ! git clone --recursive "$source" "$p_dir"; then
|
|
error clone_failed
|
|
exit 1
|
|
fi
|
|
cd $p_dir
|
|
if [[ "$p_branch" != "master" ]]; then
|
|
debug checkout
|
|
if ! git checkout "$p_branch"; then
|
|
error checkout_failed
|
|
exit 1
|
|
fi
|
|
fi
|
|
run $p_name
|
|
# Skip to the next task!
|
|
continue
|
|
fi
|
|
debug already_cloned
|
|
cd "$p_dir"
|
|
# Refresh remote before comparing with local
|
|
git fetch --quiet origin
|
|
git diff --quiet remotes/origin/$p_branch
|
|
if [[ $? != 0 ]]; then
|
|
info pull
|
|
# Update all submodules, for now only when the main repo changed (TODO)
|
|
if ! git pull --quiet --recurse-submodules; then
|
|
error pull_failed
|
|
exit 1
|
|
fi
|
|
run $p_name
|
|
# If no update was found, we can still force rebuild with -f/--force
|
|
elif [[ $FORCE = 1 ]]; then
|
|
debug forcing
|
|
run $p_name
|
|
else
|
|
debug no_update
|
|
fi
|
|
done
|
|
|
|
# Check the PID in lockfile is still ours, we don't want
|
|
# to remove the lockfile if another git-build "owns" it
|
|
if [[ "$(cat $BASEDIR/.LOCK)" = "$BASHPID" ]]; then
|
|
rm $BASEDIR/.LOCK
|
|
fi
|