#!/usr/bin/env bash # ============================================================================ # Gemeinsame Funktionen fuer make_installer_*.sh # ============================================================================ set -euo pipefail # Verzeichnisse SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SOURCE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" EXCLUDE_FILE="${SCRIPT_DIR}/exclude_patterns.txt" INSTALLER_DIR="${SCRIPT_DIR}/installer" BUILD_CONF="${SCRIPT_DIR}/build.conf" # --- build.conf laden --- load_build_conf() { # Defaults INCLUDE_AUDIO_ASSETS=true INCLUDE_MUSIC_ASSETS=false INCLUDE_MORPHER_ASSETS=true INCLUDE_WAKEWORD_MODELS=true INCLUDE_PIPER_MODELS=false INCLUDE_SYMSPELL=true INCLUDE_LLM_MODELS=false INCLUDE_PLUGIN_MODELS=false INCLUDE_TRAINER_SOURCE=true INCLUDE_TRAINING_DATA=false INCLUDE_DOCS=true INCLUDE_BASH_SCRIPTS=true if [[ -f "${BUILD_CONF}" ]]; then # Nur KEY=value Zeilen laden (keine Kommentare, keine leeren Zeilen) while IFS='=' read -r key value; do key=$(echo "${key}" | xargs) # Whitespace trimmen value=$(echo "${value}" | xargs) [[ -z "${key}" || "${key}" == \#* ]] && continue declare -g "${key}=${value}" done < "${BUILD_CONF}" echo " build.conf geladen" else echo " WARNUNG: ${BUILD_CONF} nicht gefunden — verwende Defaults" fi } # --- Dynamische Excludes aus build.conf generieren --- build_conf_excludes() { local mode="$1" local excludes="" # Assets if [[ "${INCLUDE_AUDIO_ASSETS}" != "true" ]]; then excludes+=" assets/default/audio" fi if [[ "${INCLUDE_MUSIC_ASSETS}" != "true" ]]; then excludes+=" assets/default/music" fi if [[ "${INCLUDE_MORPHER_ASSETS}" != "true" ]]; then excludes+=" assets/default/audio_morpher" fi # Modelle if [[ "${INCLUDE_WAKEWORD_MODELS}" != "true" ]]; then excludes+=" models/wakeword/*/*.onnx" fi if [[ "${INCLUDE_PIPER_MODELS}" != "true" ]]; then excludes+=" models/piper/*.onnx models/piper/.cache" fi if [[ "${INCLUDE_SYMSPELL}" != "true" ]]; then excludes+=" models/symspell" fi if [[ "${INCLUDE_LLM_MODELS}" != "true" ]]; then excludes+=" models/nlp/*.gguf" fi if [[ "${INCLUDE_PLUGIN_MODELS}" != "true" ]]; then excludes+=" plugins/*/models" fi # Trainer if [[ "${INCLUDE_TRAINER_SOURCE}" != "true" ]]; then excludes+=" trainer" fi if [[ "${INCLUDE_TRAINING_DATA}" != "true" ]]; then excludes+=" trainer/data/raw trainer/data/processed trainer/assets trainer/cache trainer/processed" fi # Sonstiges if [[ "${INCLUDE_DOCS}" != "true" ]]; then excludes+=" docs" fi if [[ "${INCLUDE_BASH_SCRIPTS}" != "true" ]]; then excludes+=" bash" fi echo "${excludes}" } # --- Version aus trixy_core/utils/version.py parsen --- parse_version() { local version_file="${SOURCE_DIR}/trixy_core/utils/version.py" if [[ ! -f "${version_file}" ]]; then echo "FEHLER: ${version_file} nicht gefunden" >&2 exit 1 fi local major minor revision major=$(grep -E '^MAJOR:\s*int\s*=' "${version_file}" | grep -oE '[0-9]+') minor=$(grep -E '^MINOR:\s*int\s*=' "${version_file}" | grep -oE '[0-9]+') revision=$(grep -E '^REVISION:\s*int\s*=' "${version_file}" | grep -oE '[0-9]+') echo "${major}.${minor}.${revision}" } # --- Release-Verzeichnis erstellen --- prepare_release_dir() { local version="$1" local mode="$2" local release_dir="${SCRIPT_DIR}/Release/${version}-${mode}" mkdir -p "${release_dir}" echo "${release_dir}" } # --- build.conf Einstellungen anzeigen --- print_build_conf() { local mode="$1" echo " Build-Konfiguration:" echo " Audio-Assets: ${INCLUDE_AUDIO_ASSETS}" echo " Musik-Assets: ${INCLUDE_MUSIC_ASSETS}" echo " Morpher-Assets: ${INCLUDE_MORPHER_ASSETS}" echo " Wakeword-Modelle: ${INCLUDE_WAKEWORD_MODELS}" echo " Piper-Modelle: ${INCLUDE_PIPER_MODELS}" echo " SymSpell: ${INCLUDE_SYMSPELL}" echo " LLM-Modelle: ${INCLUDE_LLM_MODELS}" echo " Plugin-Modelle: ${INCLUDE_PLUGIN_MODELS}" echo " Trainer-Source: ${INCLUDE_TRAINER_SOURCE}" echo " Trainings-Daten: ${INCLUDE_TRAINING_DATA}" echo " Dokumentation: ${INCLUDE_DOCS}" echo " Bash-Skripte: ${INCLUDE_BASH_SCRIPTS}" echo "" } # --- Source-tar erstellen --- create_source_tar() { local mode="$1" local version="$2" local release_dir="$3" local extra_excludes="$4" # Zusaetzliche Exclude-Patterns (Leerzeichen-getrennt) local tar_name="trixy-${mode}-${version}.tar.gz" local tar_path="${release_dir}/${tar_name}" echo " Erstelle ${tar_name}..." # Basis-Excludes aus exclude_patterns.txt local exclude_opts=() while IFS= read -r pattern; do [[ -z "${pattern}" || "${pattern}" == \#* ]] && continue exclude_opts+=("--exclude=${pattern}") done < "${EXCLUDE_FILE}" # build.conf-basierte Excludes local conf_excludes conf_excludes=$(build_conf_excludes "${mode}") for pattern in ${conf_excludes}; do exclude_opts+=("--exclude=${pattern}") done # Modus-spezifische Excludes for pattern in ${extra_excludes}; do exclude_opts+=("--exclude=${pattern}") done # tar in temporaere Datei schreiben, dann verschieben local tmp_tar tmp_tar="$(mktemp)" local prefix="trixy-${mode}-${version}" tar czf "${tmp_tar}" \ -C "${SOURCE_DIR}" \ "${exclude_opts[@]}" \ --exclude='make_installer/Release' \ --transform="s,^\\.,${prefix}," \ . mv "${tmp_tar}" "${tar_path}" echo " -> ${tar_name} ($(du -h "${tar_path}" | cut -f1))" } # --- Installer-tar erstellen --- create_installer_tar() { local mode="$1" local version="$2" local release_dir="$3" local tar_name="trixy-installer-${mode}-${version}.tar.gz" local tar_path="${release_dir}/${tar_name}" echo " Erstelle ${tar_name}..." tar czf "${tar_path}" \ -C "${INSTALLER_DIR}/.." \ --transform='s,^installer,trixy_installer,' \ --exclude='__pycache__' \ --exclude='*.pyc' \ installer/ echo " -> ${tar_name} ($(du -h "${tar_path}" | cut -f1))" } # --- install.sh generieren --- generate_install_sh() { local mode="$1" local version="$2" local release_dir="$3" local install_sh="${release_dir}/install-${mode}.sh" local source_tar="trixy-${mode}-${version}.tar.gz" local installer_tar="trixy-installer-${mode}-${version}.tar.gz" echo " Generiere install-${mode}.sh..." cat > "${install_sh}" << 'INSTALL_HEADER' #!/usr/bin/env bash # ============================================================================ # Trixy Installer — Bootstrap-Script # # Entpackt den Installer, erstellt ein temporaeres venv und startet die TUI. # ============================================================================ set -euo pipefail INSTALL_HEADER cat >> "${install_sh}" << INSTALL_VARS # --- Eingebettete Werte --- MODE="${mode}" VERSION="${version}" SOURCE_TAR="${source_tar}" INSTALLER_TAR="${installer_tar}" INSTALL_VARS cat >> "${install_sh}" << 'INSTALL_BODY' # --- Farben --- RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" TEMP_DIR="" cleanup() { if [[ -n "${TEMP_DIR}" && -d "${TEMP_DIR}" ]]; then echo -e "${YELLOW}Raeume auf...${NC}" rm -rf "${TEMP_DIR}" fi } trap cleanup EXIT echo "" echo -e "${GREEN}========================================" echo " Trixy Installer v${VERSION} [${MODE}]" echo -e "========================================${NC}" echo "" # 1. Pruefe ob tar-Dateien vorhanden if [[ ! -f "${SCRIPT_DIR}/${SOURCE_TAR}" ]]; then echo -e "${RED}FEHLER: ${SOURCE_TAR} nicht gefunden${NC}" exit 1 fi if [[ ! -f "${SCRIPT_DIR}/${INSTALLER_TAR}" ]]; then echo -e "${RED}FEHLER: ${INSTALLER_TAR} nicht gefunden${NC}" exit 1 fi # 2. Python >= 3.10 sicherstellen echo "Pruefe Python-Version..." PYTHON_BIN="" for py in python3.12 python3.11 python3.10 python3; do if command -v "${py}" >/dev/null 2>&1; then py_minor=$("${py}" -c "import sys; print(sys.version_info.minor)") if [[ "${py_minor}" -ge 10 ]]; then PYTHON_BIN="${py}" break fi fi done if [[ -z "${PYTHON_BIN}" ]]; then echo -e "${YELLOW}Python >= 3.10 nicht gefunden. Versuche Installation...${NC}" if command -v apt-get >/dev/null 2>&1; then sudo apt-get update -qq sudo apt-get install -y -qq python3 python3-venv python3-pip PYTHON_BIN="python3" else echo -e "${RED}FEHLER: Python >= 3.10 wird benoetigt${NC}" exit 1 fi fi echo " Verwende: ${PYTHON_BIN} ($(${PYTHON_BIN} --version 2>&1))" # 3. Installer-tar in temp-Verzeichnis entpacken TEMP_DIR="$(mktemp -d)" echo "Entpacke Installer nach ${TEMP_DIR}..." tar xzf "${SCRIPT_DIR}/${INSTALLER_TAR}" -C "${TEMP_DIR}" # 4. Installer-venv erstellen INST_VENV="${TEMP_DIR}/installer-venv" echo "Erstelle Installer-venv..." "${PYTHON_BIN}" -m venv "${INST_VENV}" "${INST_VENV}/bin/pip" install --upgrade pip -q 2>/dev/null "${INST_VENV}/bin/pip" install -r "${TEMP_DIR}/trixy_installer/requirements.txt" -q # 5. TUI starten echo "" echo -e "${GREEN}Starte Installer-TUI...${NC}" echo "" PYTHONPATH="${TEMP_DIR}" "${INST_VENV}/bin/python" -m trixy_installer \ --mode "${MODE}" \ --version "${VERSION}" \ --source-archive "${SCRIPT_DIR}/${SOURCE_TAR}" echo "" echo -e "${GREEN}Installer beendet.${NC}" INSTALL_BODY chmod +x "${install_sh}" echo " -> install-${mode}.sh generiert" } # --- Build zusammenfassen --- print_summary() { local mode="$1" local version="$2" local release_dir="$3" echo "" echo "========================================" echo " Build abgeschlossen: ${mode} v${version}" echo "========================================" echo "" echo " Release-Verzeichnis: ${release_dir}" echo "" ls -lh "${release_dir}/" echo "" echo " Deployment:" echo " 1. Release-Verzeichnis auf Zielgeraet kopieren" echo " 2. chmod +x install-${mode}.sh" echo " 3. ./install-${mode}.sh" echo "" }