Files
beets-setup/setup.sh

188 lines
4.9 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
PROJECT_DIR="${PROJECT_DIR:-$SCRIPT_DIR}"
VENV_DIR="${VENV_DIR:-$PROJECT_DIR/venv}"
REQ_IN="${REQ_IN:-$PROJECT_DIR/requirements.in}"
REQ_TXT="${REQ_TXT:-$PROJECT_DIR/requirements.txt}"
PYTHON_BIN="${PYTHON_BIN:-python3}"
BEETS_CONFIG="${BEETS_CONFIG:-$PROJECT_DIR/config/config.yaml}"
LASTGENRE_WHITELIST="${LASTGENRE_WHITELIST:-$PROJECT_DIR/config/lastgenre-whitelist.txt}"
CHECK_AUDIO_DECODE="${CHECK_AUDIO_DECODE:-$PROJECT_DIR/scripts/audit/check-audio-decode}"
GAPLESS_CONVERT="${GAPLESS_CONVERT:-$PROJECT_DIR/scripts/convert/gapless-convert}"
die() {
echo "error: $*" >&2
exit 1
}
warn() {
echo "warning: $*" >&2
}
have_cmd() {
command -v "$1" >/dev/null 2>&1
}
need_file() {
[[ -f "$1" ]] || die "missing required file: $1"
}
need_executable_file() {
[[ -x "$1" ]] || die "missing required executable: $1"
}
find_system_pip_compile() {
local path_entry candidate
local -a path_parts
IFS=':' read -ra path_parts <<< "$PATH"
for path_entry in "${path_parts[@]}"; do
[[ -z "$path_entry" ]] && continue
candidate="$path_entry/pip-compile"
[[ -x "$candidate" ]] || continue
# Do not use pip-compile from this project's venv.
if [[ "$candidate" == "$VENV_DIR/bin/pip-compile" ]]; then
continue
fi
# Do not use pip-compile from the currently active venv either.
if [[ -n "${VIRTUAL_ENV:-}" && "$candidate" == "$VIRTUAL_ENV/bin/pip-compile" ]]; then
continue
fi
printf '%s\n' "$candidate"
return 0
done
return 1
}
check_system_dependencies() {
local missing=0
local cmd
for cmd in python3 ffmpeg ffprobe fpcalc flac mp3val; do
if ! have_cmd "$cmd"; then
echo "missing command: $cmd" >&2
missing=1
fi
done
# ImageMagick:
#
# Modern ImageMagick usually exposes "magick".
# Beets documentation historically says it looks for "convert".
# Accept either, but make the exact situation visible.
if have_cmd magick; then
:
elif have_cmd convert; then
:
else
echo "missing command: magick or convert from ImageMagick" >&2
missing=1
fi
if have_cmd magick && ! have_cmd convert; then
warn "found 'magick' but not 'convert'; if beets cannot use ImageMagick, install/enable the ImageMagick 'convert' compatibility command or rely on Pillow where possible"
fi
if (( missing != 0 )); then
die "missing required system dependencies"
fi
}
check_ffmpeg_capabilities() {
if ! ffmpeg -hide_banner -encoders 2>/dev/null \
| awk '$2 == "libopus" { found = 1 } END { exit found ? 0 : 1 }'
then
die "ffmpeg is installed, but it does not appear to have the libopus encoder required by your convert.opus command"
fi
}
check_project_files() {
need_file "$REQ_IN"
# These are referenced directly by your beets config.
need_executable_file "$CHECK_AUDIO_DECODE"
need_executable_file "$GAPLESS_CONVERT"
need_file "$LASTGENRE_WHITELIST"
if [[ ! -f "$BEETS_CONFIG" ]]; then
warn "beets config not found at $BEETS_CONFIG; skipping beets config validation"
fi
}
create_venv_if_missing() {
if [[ ! -d "$VENV_DIR" ]]; then
echo "Creating virtualenv: $VENV_DIR"
"$PYTHON_BIN" -m venv "$VENV_DIR"
fi
if [[ ! -x "$VENV_DIR/bin/python" ]]; then
die "venv exists but does not contain executable Python: $VENV_DIR/bin/python"
fi
}
compile_requirements() {
local pip_compile_bin
pip_compile_bin="${PIP_COMPILE_BIN:-}"
if [[ -z "$pip_compile_bin" ]]; then
pip_compile_bin="$(find_system_pip_compile || true)"
fi
if [[ -z "$pip_compile_bin" ]]; then
die "could not find system-wide pip-compile; install pip-tools outside this project venv"
fi
if [[ ! -x "$pip_compile_bin" ]]; then
die "configured PIP_COMPILE_BIN is not executable: $pip_compile_bin"
fi
echo "Using pip-compile: $pip_compile_bin"
"$pip_compile_bin" --upgrade "$REQ_IN" -o "$REQ_TXT"
}
install_requirements() {
echo "Installing requirements into: $VENV_DIR"
"$VENV_DIR/bin/python" -m pip install --upgrade pip setuptools wheel
"$VENV_DIR/bin/python" -m pip install -r "$REQ_TXT"
"$VENV_DIR/bin/python" -m pip check
}
validate_beets() {
if [[ ! -f "$BEETS_CONFIG" ]]; then
return 0
fi
if [[ ! -x "$VENV_DIR/bin/beet" ]]; then
die "beet was not installed into the venv: $VENV_DIR/bin/beet"
fi
echo "Validating beets config: $BEETS_CONFIG"
"$VENV_DIR/bin/beet" -c "$BEETS_CONFIG" config >/dev/null
}
main() {
check_system_dependencies
check_ffmpeg_capabilities
check_project_files
create_venv_if_missing
compile_requirements
install_requirements
validate_beets
echo "Done."
}
main "$@"