@@ -22,6 +22,61 @@ MINISIGN_PUBKEY="${HAPPIER_MINISIGN_PUBKEY:-${DEFAULT_MINISIGN_PUBKEY}}"
2222MINISIGN_PUBKEY_URL=" ${HAPPIER_MINISIGN_PUBKEY_URL:- https:// happier.dev/ happier-release.pub} "
2323MINISIGN_BIN=" minisign"
2424
25+ INSTALLER_COLOR_MODE=" ${HAPPIER_INSTALLER_COLOR:- auto} " # auto|always|never
26+
27+ supports_color () {
28+ if [[ " ${INSTALLER_COLOR_MODE} " == " never" ]]; then
29+ return 1
30+ fi
31+ if [[ -n " ${NO_COLOR:- } " ]]; then
32+ return 1
33+ fi
34+ if [[ " ${INSTALLER_COLOR_MODE} " == " always" ]]; then
35+ return 0
36+ fi
37+ [[ -t 1 ]] && [[ " ${TERM:- } " != " dumb" ]]
38+ }
39+
40+ if supports_color; then
41+ COLOR_RESET=$' \033 [0m'
42+ COLOR_BOLD=$' \033 [1m'
43+ COLOR_GREEN=$' \033 [32m'
44+ COLOR_YELLOW=$' \033 [33m'
45+ COLOR_CYAN=$' \033 [36m'
46+ else
47+ COLOR_RESET=" "
48+ COLOR_BOLD=" "
49+ COLOR_GREEN=" "
50+ COLOR_YELLOW=" "
51+ COLOR_CYAN=" "
52+ fi
53+
54+ say () {
55+ printf ' %s\n' " $* "
56+ }
57+
58+ info () {
59+ say " ${COLOR_CYAN} $* ${COLOR_RESET} "
60+ }
61+
62+ success () {
63+ say " ${COLOR_GREEN} $* ${COLOR_RESET} "
64+ }
65+
66+ warn () {
67+ say " ${COLOR_YELLOW} $* ${COLOR_RESET} "
68+ }
69+
70+ tar_extract_gz () {
71+ local archive_path=" $1 "
72+ local dest_dir=" $2 "
73+ mkdir -p " ${dest_dir} "
74+ # GNU tar on Linux emits noisy, non-actionable warnings when extracting archives created by bsdtar/libarchive:
75+ # "Ignoring unknown extended header keyword 'LIBARCHIVE.xattr...'"
76+ # Filter those while preserving real errors.
77+ tar -xzf " ${archive_path} " -C " ${dest_dir} " 2> >( grep -v -E " ^tar: Ignoring unknown extended header keyword" >&2 || true)
78+ }
79+
2580usage () {
2681 cat << 'EOF '
2782Usage:
@@ -296,7 +351,7 @@ ensure_minisign() {
296351 local extract_dir=" ${TMP_DIR} /minisign-extract"
297352 mkdir -p " ${extract_dir} "
298353 if [[ " ${asset} " == * .tar.gz ]]; then
299- tar -xzf " ${archive_path} " -C " ${extract_dir} "
354+ tar_extract_gz " ${archive_path} " " ${extract_dir} "
300355 else
301356 if command -v unzip > /dev/null 2>&1 ; then
302357 unzip -q " ${archive_path} " -d " ${extract_dir} "
@@ -345,7 +400,7 @@ write_minisign_public_key() {
345400}
346401
347402API_URL=" https://api.github.com/repos/${GITHUB_REPO} /releases/tags/${TAG} "
348- echo " Fetching ${TAG} release metadata..."
403+ info " Fetching ${TAG} release metadata..."
349404if ! RELEASE_JSON=" $( curl -fsSL " ${API_URL} " ) " ; then
350405 if [[ " ${CHANNEL} " == " stable" ]]; then
351406 echo " No stable releases found for Happier Stack." >&2
@@ -393,7 +448,7 @@ CHECKSUMS_PATH="${TMP_DIR}/checksums.txt"
393448curl -fsSL " ${ASSET_URL} " -o " ${ARCHIVE_PATH} "
394449curl -fsSL " ${CHECKSUMS_URL} " -o " ${CHECKSUMS_PATH} "
395450
396- EXPECTED_SHA=" $( grep -E " $( basename " ${ASSET_URL} " ) $" " ${CHECKSUMS_PATH} " | awk ' {print $1}' | head -n 1) "
451+ EXPECTED_SHA=" $( grep -E " $( basename " ${ASSET_URL} " ) $" " ${CHECKSUMS_PATH} " | awk ' {print $1}' | head -n 1 || true ) "
397452if [[ -z " ${EXPECTED_SHA} " ]]; then
398453 echo " Failed to resolve checksum for $( basename " ${ASSET_URL} " ) " >&2
399454 exit 1
@@ -403,7 +458,7 @@ if [[ "${EXPECTED_SHA}" != "${ACTUAL_SHA}" ]]; then
403458 echo " Checksum verification failed." >&2
404459 exit 1
405460fi
406- echo " Checksum verified."
461+ success " Checksum verified."
407462
408463if ! ensure_minisign; then
409464 echo " minisign is required for installer signature verification." >&2
@@ -416,11 +471,11 @@ SIG_PATH="${TMP_DIR}/checksums.txt.minisig"
416471write_minisign_public_key " ${PUBKEY_PATH} "
417472curl -fsSL " ${SIG_URL} " -o " ${SIG_PATH} "
418473" ${MINISIGN_BIN} " -Vm " ${CHECKSUMS_PATH} " -x " ${SIG_PATH} " -p " ${PUBKEY_PATH} " > /dev/null
419- echo " Signature verified."
474+ success " Signature verified."
420475
421476EXTRACT_DIR=" ${TMP_DIR} /extract"
422477mkdir -p " ${EXTRACT_DIR} "
423- tar -xzf " ${ARCHIVE_PATH} " -C " ${EXTRACT_DIR} "
478+ tar_extract_gz " ${ARCHIVE_PATH} " " ${EXTRACT_DIR} "
424479BINARY_PATH=" $( find " ${EXTRACT_DIR} " -type f -name hstack -perm -u+x | head -n 1 || true) "
425480if [[ -z " ${BINARY_PATH} " ]]; then
426481 echo " Failed to locate extracted hstack binary." >&2
@@ -432,7 +487,7 @@ cp "${BINARY_PATH}" "${STACK_INSTALL_DIR}/bin/hstack"
432487chmod +x " ${STACK_INSTALL_DIR} /bin/hstack"
433488ln -sf " ${STACK_INSTALL_DIR} /bin/hstack" " ${STACK_BIN_DIR} /hstack"
434489
435- echo " Installed hstack to ${STACK_INSTALL_DIR} /bin/hstack"
490+ success " Installed hstack to ${STACK_INSTALL_DIR} /bin/hstack"
436491
437492SELF_HOST_ARGS=(self-host install --non-interactive --channel=" ${CHANNEL} " --mode=" ${MODE} " )
438493if [[ " ${WITH_CLI} " != " 1" ]]; then
442497export HAPPIER_NONINTERACTIVE=" ${NONINTERACTIVE} "
443498
444499if [[ " ${NONINTERACTIVE} " != " 1" ]]; then
445- echo " Starting Happier Self-Host guided installation..."
500+ info " Starting Happier Self-Host guided installation..."
501+ say
502+ info " This can take a few minutes. If it looks stuck, check logs:"
503+ if [[ " ${MODE} " == " system" ]]; then
504+ SELF_HOST_LOG_DIR=" ${HAPPIER_SELF_HOST_LOG_DIR:-/ var/ log/ happier} "
505+ SELF_HOST_SERVICE_NAME=" ${HAPPIER_SELF_HOST_SERVICE_NAME:- happier-server} "
506+ else
507+ SELF_HOST_LOG_DIR=" ${HAPPIER_SELF_HOST_LOG_DIR:- ${HAPPIER_HOME} / self-host/ logs} "
508+ SELF_HOST_SERVICE_NAME=" ${HAPPIER_SELF_HOST_SERVICE_NAME:- happier-server} "
509+ fi
510+ say " - ${SELF_HOST_LOG_DIR} /server.err.log"
511+ say " - ${SELF_HOST_LOG_DIR} /server.out.log"
512+ if [[ " ${OS} " == " linux" ]]; then
513+ if [[ " ${MODE} " == " system" ]]; then
514+ say " - sudo journalctl -u ${SELF_HOST_SERVICE_NAME} -e --no-pager"
515+ else
516+ say " - journalctl --user -u ${SELF_HOST_SERVICE_NAME} -e --no-pager"
517+ fi
518+ fi
519+ say
520+ fi
521+ if ! " ${STACK_INSTALL_DIR} /bin/hstack" " ${SELF_HOST_ARGS[@]} " ; then
522+ warn
523+ warn " [self-host] install failed"
524+ say
525+ info " Troubleshooting:"
526+ say " ${STACK_BIN_DIR} /hstack self-host status --mode=${MODE} --channel=${CHANNEL} "
527+ say " ${STACK_BIN_DIR} /hstack self-host doctor --mode=${MODE} --channel=${CHANNEL} "
528+ say " ${STACK_BIN_DIR} /hstack self-host config view --mode=${MODE} --channel=${CHANNEL} --json"
529+ say
530+ info " Logs:"
531+ if [[ " ${MODE} " == " system" ]]; then
532+ SELF_HOST_LOG_DIR=" ${HAPPIER_SELF_HOST_LOG_DIR:-/ var/ log/ happier} "
533+ SELF_HOST_SERVICE_NAME=" ${HAPPIER_SELF_HOST_SERVICE_NAME:- happier-server} "
534+ else
535+ SELF_HOST_LOG_DIR=" ${HAPPIER_SELF_HOST_LOG_DIR:- ${HAPPIER_HOME} / self-host/ logs} "
536+ SELF_HOST_SERVICE_NAME=" ${HAPPIER_SELF_HOST_SERVICE_NAME:- happier-server} "
537+ fi
538+ say " tail -n 200 ${SELF_HOST_LOG_DIR} /server.err.log"
539+ say " tail -n 200 ${SELF_HOST_LOG_DIR} /server.out.log"
540+ if [[ " ${OS} " == " linux" ]]; then
541+ if [[ " ${MODE} " == " system" ]]; then
542+ say " sudo journalctl -u ${SELF_HOST_SERVICE_NAME} -e --no-pager"
543+ else
544+ say " journalctl --user -u ${SELF_HOST_SERVICE_NAME} -e --no-pager"
545+ fi
546+ fi
547+ exit 1
446548fi
447- " ${STACK_INSTALL_DIR} /bin/hstack" " ${SELF_HOST_ARGS[@]} "
448549
449550echo
450- echo " Happier Self-Host installation completed."
451- echo " Run: ${STACK_BIN_DIR} /hstack self-host status"
551+ success " Happier Self-Host installation completed."
552+ info " Run: ${STACK_BIN_DIR} /hstack self-host status"
0 commit comments