diff --git a/jeannie b/jeannie index 76abcc8..0333709 100755 --- a/jeannie +++ b/jeannie @@ -2,6 +2,10 @@ set -euo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${REPO_ROOT}/lib/jeannie/core.sh" +source "${REPO_ROOT}/lib/jeannie/env.sh" +source "${REPO_ROOT}/lib/jeannie/toolchain.sh" +source "${REPO_ROOT}/lib/jeannie/pimox.sh" BUILDX_CONFIG="/tmp/buildx-config.toml" HOMELAB_STATE_DIR="${HOMELAB_STATE_DIR:-${XDG_DATA_HOME:-${HOME}/.local/share}/homelab}" COSIGN_KEY_PREFIX="${COSIGN_KEY_PREFIX:-${HOMELAB_STATE_DIR}/cosign/cosign}" @@ -785,209 +789,16 @@ doctor_versions() { exit "$?" } -truthy() { - local value - value="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')" - case "${value}" in - 1 | true | yes | on) - return 0 - ;; - *) - return 1 - ;; - esac -} -disabled_value() { - local value - value="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')" - case "${value}" in - 0 | false | no | off | disabled) - return 0 - ;; - *) - return 1 - ;; - esac -} -jeannie_log_start() { - local command_name="$1" - local timestamp - if [[ -n "${JEANNIE_LOG_FILE}" ]]; then - return 0 - fi - timestamp="$(date +%Y%m%d-%H%M%S)" - mkdir -p "${JEANNIE_LOG_DIR}" - JEANNIE_LOG_FILE="${JEANNIE_LOG_DIR}/jeannie-${command_name}-${timestamp}.log" - JEANNIE_ERROR_LOG_FILE="${JEANNIE_LOG_DIR}/jeannie-${command_name}-${timestamp}.error.log" - : >"${JEANNIE_LOG_FILE}" - : >"${JEANNIE_ERROR_LOG_FILE}" - printf 'Log: %s\n' "${JEANNIE_LOG_FILE}" - printf 'Error log: %s\n' "${JEANNIE_ERROR_LOG_FILE}" -} -jeannie_step_plan() { - JEANNIE_STEP_INDEX=0 - JEANNIE_STEP_TOTAL="$1" -} -jeannie_verbose_enabled() { - truthy "${JEANNIE_VERBOSE:-false}" -} -jeannie_step_prefix() { - local description="$1" - if ((JEANNIE_STEP_TOTAL > 0)); then - printf '[%d/%d] %-42s ' "${JEANNIE_STEP_INDEX}" "${JEANNIE_STEP_TOTAL}" "${description}" - else - printf '[%d] %-46s ' "${JEANNIE_STEP_INDEX}" "${description}" - fi -} - -jeannie_compact_text() { - local text="$1" - local max_length="${2:-96}" - - text="${text//$'\r'/ }" - text="${text//$'\n'/ }" - text="$(printf '%s' "${text}" | sed -E 's/[[:space:]]+/ /g; s/^ //; s/ $//')" - if ((${#text} > max_length)); then - text="${text:0:max_length - 3}..." - fi - printf '%s' "${text}" -} - -jeannie_step_progress() { - local description="$1" - local step_log="$2" - local started_at="$3" - local last_line="${4:-}" - local elapsed=$((SECONDS - started_at)) - - printf '\r' - jeannie_step_prefix "${description}" - if [[ -n "${last_line}" ]]; then - printf 'running %ss | %s' "${elapsed}" "${last_line}" - else - printf 'running %ss' "${elapsed}" - fi - printf '\033[K' -} - -jeannie_step_latest_progress_line() { - local step_log="$1" - local last_line="" - - if [[ -s "${step_log}" ]]; then - last_line="$(tail -n 1 "${step_log}" 2>/dev/null || true)" - last_line="$(jeannie_compact_text "${last_line}" 88)" - fi - printf '%s' "${last_line}" -} - -redact_sensitive_output() { - sed -E \ - -e 's/(GITEA_BOOTSTRAP_PASSWORD=)["'\'']?[^"'\''[:space:]]+["'\'']?/\1[REDACTED]/g' \ - -e 's/(PIHOLE_WEBPASSWORD=)["'\'']?[^"'\''[:space:]]+["'\'']?/\1[REDACTED]/g' \ - -e 's/(COSIGN_PASSWORD=)["'\'']?[^"'\''[:space:]]+["'\'']?/\1[REDACTED]/g' \ - -e 's/(GITEA_RUNNER_REGISTRATION_TOKEN=)["'\'']?[^"'\''[:space:]]+["'\'']?/\1[REDACTED]/g' \ - -e 's/(--password[=[:space:]]+)["'\'']?[^"'\''[:space:]]+["'\'']?/\1[REDACTED]/g' \ - -e 's/(--token[=[:space:]]+)["'\'']?[^"'\''[:space:]]+["'\'']?/\1[REDACTED]/g' \ - -e 's/(password[=:][[:space:]]*)[^[:space:]]+/\1[REDACTED]/Ig' \ - -e 's/(token[=:][[:space:]]*)[^[:space:]]+/\1[REDACTED]/Ig' \ - -e 's#(https?://[^:/[:space:]]+):[^@/[:space:]]+@#\1:[REDACTED]@#g' -} - -run_step() { - local description="$1" - local step_log - local status_file - local status - local progress_pid - local progress_interval="${JEANNIE_PROGRESS_INTERVAL_SECONDS:-10}" - local started_at - local current_progress_line="" - local last_progress_line="" - local last_progress_rendered_at=0 - shift - - JEANNIE_STEP_INDEX=$((JEANNIE_STEP_INDEX + 1)) - jeannie_step_prefix "${description}" - - step_log="$(mktemp)" - status_file="$(mktemp)" - { - printf '\n== [%d/%d] %s ==\n' "${JEANNIE_STEP_INDEX}" "${JEANNIE_STEP_TOTAL}" "${description}" - printf 'Started: %s\n' "$(date -Is)" - } >>"${JEANNIE_LOG_FILE}" - - if jeannie_verbose_enabled; then - set +e - "$@" 2>&1 | redact_sensitive_output | tee "${step_log}" | tee -a "${JEANNIE_LOG_FILE}" - status=${PIPESTATUS[0]} - set -e - else - set +e - ( - set +e - "$@" 2>&1 | redact_sensitive_output | tee "${step_log}" >>"${JEANNIE_LOG_FILE}" - printf '%s\n' "${PIPESTATUS[0]}" >"${status_file}" - ) & - progress_pid=$! - if ! [[ "${progress_interval}" =~ ^[0-9]+$ ]] || ((progress_interval < 1)); then - progress_interval=10 - fi - started_at="${SECONDS}" - while kill -0 "${progress_pid}" >/dev/null 2>&1; do - sleep "${progress_interval}" - if kill -0 "${progress_pid}" >/dev/null 2>&1; then - current_progress_line="$(jeannie_step_latest_progress_line "${step_log}")" - if [[ "${current_progress_line}" != "${last_progress_line}" ]] || - ((SECONDS - last_progress_rendered_at >= 60)); then - jeannie_step_progress "${description}" "${step_log}" "${started_at}" "${current_progress_line}" - last_progress_line="${current_progress_line}" - last_progress_rendered_at="${SECONDS}" - fi - fi - done - wait "${progress_pid}" || true - status="$(cat "${status_file}" 2>/dev/null || printf '1')" - set -e - fi - - printf 'Finished: %s\n' "$(date -Is)" >>"${JEANNIE_LOG_FILE}" - - if ((status == 0)); then - printf '\r' - jeannie_step_prefix "${description}" - printf 'ok\033[K\n' - rm -f "${step_log}" "${status_file}" - return 0 - fi - - printf '\r' - jeannie_step_prefix "${description}" - printf 'failed\033[K\n\n' - { - printf '\n== FAILED [%d/%d] %s ==\n' "${JEANNIE_STEP_INDEX}" "${JEANNIE_STEP_TOTAL}" "${description}" - printf 'Finished: %s\n' "$(date -Is)" - sed 's/^/ /' "${step_log}" - } >>"${JEANNIE_ERROR_LOG_FILE}" - printf 'Step failed: %s\n' "${description}" >&2 - printf 'Exit status: %s\n' "${status}" >&2 - printf 'Full step output:\n' >&2 - sed 's/^/ /' "${step_log}" >&2 - printf '\nFull log: %s\n' "${JEANNIE_LOG_FILE}" >&2 - printf 'Error log: %s\n' "${JEANNIE_ERROR_LOG_FILE}" >&2 - rm -f "${step_log}" "${status_file}" - return "${status}" -} worker_index_is_skipped() { local index="$1"