diff --git a/.gitignore b/.gitignore index a7b33eade..be693d239 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ www/* www/assets/* !www/otp_register_template.html !www/reset_password.template.html + +# Runtime Environment +.venv diff --git a/autoexec.sh b/autoexec.sh new file mode 100644 index 000000000..7a67a4b4c --- /dev/null +++ b/autoexec.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash + +# Environment +ENIGMA_INSTALL_DIR=${ENIGMA_INSTALL_DIR:=$HOME/enigma-bbs} +AUTOEXEC_LOGFILE="$ENIGMA_INSTALL_DIR/logs/autoexec.log" +TIME_FORMAT=`date "+%Y-%m-%d %H:%M:%S"` + +# Mise en place +~/.local/bin/mise activate bash >> bash + +# Environment Versions +ENIGMA_NODE_VERSION=${ENIGMA_NODE_VERSION:=$(toml get --toml-path=$ENIGMA_INSTALL_DIR/mise.toml tools.node)} +ENIGMA_PYTHON_VERSION=${ENIGMA_PYTHON_VERSION:=$(toml get --toml-path=$ENIGMA_INSTALL_DIR/mise.toml tools.python)} + +# Validate Environment +DEPENDENCIES_VALIDATED=1 + +# Shared Functions +log() { + echo "${TIME_FORMAT} " "$*" >> $AUTOEXEC_LOGFILE +} + +# If this is a first run, the log path will not yet exist and must be created +if [ ! -d "$ENIGMA_INSTALL_DIR/logs" ] +then + mkdir -p $ENIGMA_INSTALL_DIR/logs +fi + +log "START:" +log "- PATH: $PATH" +log "- CURRENT DIR: ${PWD##}" + +if ! command -v "mise" 2>&1 >/dev/null +then + log "mise is not in your PATH, activating" + eval "$(~/.local/bin/mise activate bash)" +fi + +if ! command -v "node" 2>&1 >/dev/null +then + log "Node environment is not in your PATH" + log "ERROR END" + exit 1 +else + NODE_VERSION=$(node --version | tee /dev/null) + log "- NODE VERSION: $NODE_VERSION" + if [[ $NODE_VERSION != "v$ENIGMA_NODE_VERSION."* ]]; then + log "Node version found in your PATH is $NODE_VERSION, was expecting v$ENIGMA_NODE_VERSION.*; you may encounter compatibility issues" + DEPENDENCIES_VALIDATED=0 + fi +fi + +if ! command -v "python" 2>&1 >/dev/null +then + log "Python environment is not in your PATH" + log "ERROR END" + exit 1 +else + PYTHON_VERSION=$(python --version | tee /dev/null) + log "- PYTHON VERSION: $PYTHON_VERSION" + if [[ $PYTHON_VERSION != "Python $ENIGMA_PYTHON_VERSION"* ]]; then + log "Python version found in your PATH is $PYTHON_VERSION, was expecting Python $ENIGMA_PYTHON_VERSION.*; you may encounter compatibility issues" + DEPENDENCIES_VALIDATED=0 + fi +fi + +# Validate whether we are good to Start +if [ "$DEPENDENCIES_VALIDATED" == "0" ]; then + if [ -v ENIGMA_IGNORE_DEPENDENCIES ] && [ "${ENIGMA_IGNORE_DEPENDENCIES}" == "1" ]; then + log "ENIGMA_IGNORE_DEPENDENCIES=1 detected, starting up..." + else + log "NOTE: Please re-run with 'ENIGMA_IGNORE_DEPENDENCIES=1 /path/to/autoexec.sh' to force startup" + log "ERROR END" + exit 1 + fi +fi + +# Start BBS +log "Starting ENiGMA½" +~/enigma-bbs/main.js +result=$? + +# Determine whether a Startup Crash Occurred +# if [ $result -eq 0 ]; then +# # TODO: Notify via SMS / Email of Startup Failure +# fi + +log "ENiGMA½ exited with $result" +log "END" +exit $result diff --git a/misc/install.sh b/misc/install.sh index 1945e5bd7..a694cf661 100755 --- a/misc/install.sh +++ b/misc/install.sh @@ -1,16 +1,52 @@ #!/usr/bin/env bash { # this ensures the entire script is downloaded before execution - -ENIGMA_NODE_VERSION=${ENIGMA_NODE_VERSION:=18} ENIGMA_BRANCH=${ENIGMA_BRANCH:=master} ENIGMA_INSTALL_DIR=${ENIGMA_INSTALL_DIR:=$HOME/enigma-bbs} ENIGMA_SOURCE=${ENIGMA_SOURCE:=https://github.com/NuSkooler/enigma-bbs.git} TIME_FORMAT=`date "+%Y-%m-%d %H:%M:%S"` -WAIT_BEFORE_INSTALL=10 + +# ANSI Codes +RESET="\e[0m" +BOLD="\e[1m" +UNDERLINE="\e[4m" +INVERSE="\e7m" +FOREGROUND_BLACK="\e[30m" +FOREGROUND_RED="\e[31m" +FOREGROUND_GREEN="\e[32m" +FOREGROUND_YELLOW="\e[33m" +FOREGROUND_BLUE="\e[34m" +FOREGROUND_MAGENTA="\e[35m" +FOREGROUND_CYAN="\e[36m" +FOREGROUND_WHITE="\e[37m" +BACKGROUND_BLACK="\e[40m" +BACKGROUND_RED="\e[41m" +BACKGROUND_GREEN="\e[42m" +BACKGROUND_YELLOW="\e[43m" +BACKGROUND_BLUE="\e[44m" +BACKGROUND_MAGENTA="\e[45m" +BACKGROUND_CYAN="\e[46m" +BACKGROUND_WHITE="\e[47m" +FOREGROUND_STRONG_WHITE="\e[90m" +FOREGROUND_STRONG_RED="\e[91m" +FOREGROUND_STRONG_GREEN="\e[92m" +FOREGROUND_STRONG_YELLOW="\e[93m" +FOREGROUND_STRONG_BLUE="\e[94m" +FOREGROUND_STRONG_MAGENTA="\e[95m" +FOREGROUND_STRONG_CYAN="\e[96m" +FOREGROUND_STRONG_WHITE="\e[97m" +BACKGROUND_STRONG_BLACK="\e[100m" +BACKGROUND_STRONG_RED="\e[101m" +BACKGROUND_STRONG_GREEN="\e[102m" +BACKGROUND_STRONG_YELLOW="\e[103m" +BACKGROUND_STRONG_BLUE="\w[104m" +BACKGROUND_STRONG_MAGENTA="\e[105m" +BACKGROUND_STRONG_CYAN="\e[106m" +BACKGROUND_STRONG_WHITE="\e[107m" enigma_header() { clear + printf "$FOREGROUND_STRONG_WHITE" cat << EndOfMessage ______ _____________________ _____ ____________________ __________\\_ / @@ -22,27 +58,16 @@ _____________________ _____ ____________________ __________\\_ / <*> ENiGMA½ // https://github.com/NuSkooler/enigma-bbs <*> /__/ -Installing ENiGMA½: +ENiGMA½: Source : ${ENIGMA_SOURCE} (${ENIGMA_BRANCH} branch) Destination: ${ENIGMA_INSTALL_DIR} - Node.js : ${ENIGMA_NODE_VERSION}.x via NVM (If you have NVM it will be updated to the latest version) - ->> If this isn't what you were expecting, hit CTRL-C now! ->> Installation will continue in ${WAIT_BEFORE_INSTALL} seconds... EndOfMessage - - SECS=10 - while [ $SECS -gt 0 ]; do - echo -ne "${SECS}... " - sleep 1 - ((SECS --)) - done - echo "" + printf "$RESET" } fatal_error() { - printf "${TIME_FORMAT} \e[41mERROR:\033[0m %b\n" "$*" >&2; + log "${TIME_FORMAT} ERROR: %b\n $*" >&2; exit 1 } @@ -51,52 +76,68 @@ check_exists() { } enigma_install_needs_ex() { - echo -ne "Checking for '$1'..." + log "Checking for '$1'...${RESET}" if check_exists $1 ; then - echo " Found!" + log " Found!" else - echo "" fatal_error "ENiGMA½ requires '$1' but it was not found. Please install it and/or make sure it is in your path then restart the installer.\n\n$2" fi } -enigma_install_needs_python() { - echo -ne "Checking for a suitable Python installation..." - if check_exists "python" || check_exists "python7" || check_exists "python3" ; then - echo " Found!" +enigma_install_needs() { + enigma_install_needs_ex $1 "Examples:\n sudo apt install $1 # Debian/Ubuntu\n sudo yum install $1 # CentOS" +} + +enigma_has_mise() { + log "Checking for an installation of mise-en-place (https://mise.jdx.dev/)" + if check_exists "mise"; then + log "Found!" else - echo "" - fatal_error "ENiGMA½ requires Python for node-gyp to build binaries. Please see https://www.npmjs.com/package/node-gyp for details." + log "" + fatal_error "ENiGMA½ requires mise-enplace to install dependencies." fi } -enigma_install_needs() { - enigma_install_needs_ex $1 "Examples:\n sudo apt install $1 # Debian/Ubuntu\n sudo yum install $1 # CentOS" -} +log() { + local LOG_CONTENT=$1 + + local COLOUR="" + case $LOG_CONTENT in + "ERROR") + COLOUR="${FOREGROUND_STRONG_RED}" + ;; + *) + COLOUR="${FOREGROUND_GREEN}" + ;; + esac -log() { - printf "${TIME_FORMAT} %b\n" "$*"; + printf "${TIME_FORMAT} %b\n" "${COLOUR}${LOG_CONTENT}${RESET}"; } enigma_install_init() { enigma_install_needs git enigma_install_needs curl - enigma_install_needs_python enigma_install_needs_ex make "Examples:\n sudo apt install build-essential # Debian/Ubuntu\n sudo yum groupinstall 'Development Tools' # CentOS" enigma_install_needs make enigma_install_needs gcc } -install_nvm() { - log "Installing nvm" - curl -o- https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash +install_mise_en_place() { + curl https://mise.run | sh + + # ~/.local/bin/mise activate bash >> bash + eval "$(~/.local/bin/mise activate bash)" + + cd $ENIGMA_INSTALL_DIR + + mise install + + export PATH="$HOME/.local/share/mise/shims:$PATH" } -configure_nvm() { - log "Installing Node ${ENIGMA_NODE_VERSION} via nvm" - . ~/.nvm/nvm.sh - nvm install ${ENIGMA_NODE_VERSION} - nvm use ${ENIGMA_NODE_VERSION} +install_tools() { + # Used to read toml files from bash scripts + python -m pip install toml-cli } download_enigma_source() { @@ -104,7 +145,7 @@ download_enigma_source() { INSTALL_DIR=${ENIGMA_INSTALL_DIR} if [ -d "$INSTALL_DIR/.git" ]; then - log "ENiGMA½ is already installed in $INSTALL_DIR, trying to update using git" + log "ENiGMA½ is already installed in $INSTALL_DIR, trying to update using git..." command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" fetch 2> /dev/null || fatal_error "Failed to update ENiGMA½, run 'git fetch' in $INSTALL_DIR yourself." else @@ -126,19 +167,21 @@ is_arch_arm() { extra_npm_install_args() { if is_arch_arm ; then - echo "--build-from-source" + printf "--build-from-source" else - echo "" + printf "" fi } install_node_packages() { log "Installing required Node packages..." - log "Note that on some systems such as RPi, this can take a VERY long time. Be patient!" + printf "Note that on some systems such as RPi, this can take a VERY long time. Be patient!" cd ${ENIGMA_INSTALL_DIR} local EXTRA_NPM_ARGS=$(extra_npm_install_args) - git checkout ${ENIGMA_BRANCH} && npm install ${EXTRA_NPM_ARGS} + git checkout ${ENIGMA_BRANCH} + + npm install ${EXTRA_NPM_ARGS} if [ $? -eq 0 ]; then log "npm package installation complete" else @@ -147,21 +190,22 @@ install_node_packages() { } copy_template_files() { - if [[ ! -f "./gopher/gophermap" ]]; then - cp "./misc/gophermap" "./gopher/gophermap" + log "Copying Template Files to ${ENIGMA_INSTALL_DIR}/misc/gophermap" + if [[ ! -f "$ENIGMA_INSTALL_DIR/gopher/gophermap" ]]; then + cp "$ENIGMA_INSTALL_DIR/misc/gophermap" "$ENIGMA_INSTALL_DIR/gopher/gophermap" fi } enigma_footer() { log "ENiGMA½ installation complete!" - echo -e "\e[1;33m" + printf "${FOREGROUND_YELLOW}" cat << EndOfMessage ADDITIONAL ACTIONS ARE REQUIRED! -------------------------------- -1 - If you did not have Node.js and/or NVM installed previous to this please open a new shell/terminal now! - (!) Not doing so will prevent 'nvm' or 'node' commands from functioning! +1 - If you did not have Node.js and/or mise installed previous to this please open a new shell/terminal now! + (!) Not doing so will prevent 'nvm', 'node', or 'python' commands from functioning! 2 - If this is the first time you've installed ENiGMA½, you now need to generate a minimal configuration: @@ -185,17 +229,94 @@ ADDITIONAL ACTIONS ARE REQUIRED! See docs for more information including other useful binaries! +4 - Start ENiGMA½ BBS! + + ./autoexec.sh + +5 - Enable Automated Startup on Boot (optional) + + Create a file in /etc/systemd/system/bbs.service with the following contents: + [Unit] + Description=Enigma½ BBS + + [Install] + WantedBy=multi-user.target + + [Service] + ExecStart=/home//enigma-bbs/autoexec.sh + Type=simple + User= + Group= + WorkingDirectory=/home//enigma-bbs/ + Restart=on-failure + + Run 'sudo systemctl enable bbs.service' + EndOfMessage - echo -e "\e[39m" + printf "${RESET}" +} + +post_install() { + MISE_SHIM_PATH_COMMAND='export PATH="$HOME/.local/share/mise/shims:$PATH"' + if grep -Fxq "$MISE_SHIM_PATH_COMMAND" ~/.bashrc + then + log "Mise Shims found in your ~/.bashrc" + else + echo $MISE_SHIM_PATH_COMMAND >> ~/.bashrc + log "Installed Mise Shims into your ~/.bashrc" + fi +} + +install_dependencies() { + log "Installing Dependencies..." + + enigma_install_init + install_mise_en_place + install_tools + install_node_packages + post_install +} + +install_bbs() { + log "Installing ENiGMA½..." + + download_enigma_source + copy_template_files +} + +install_everything() { + log "Installing Everything..." + download_enigma_source + install_dependencies + copy_template_files +} + +menu() { + title="Installation Options" + prompt="Select>" + options=( + "Install Dependencies" + "Install ENiGMA½" + "Install Everything" + ) + + echo "$title" + PS3="$prompt " + select opt in "${options[@]}" "Quit"; do + case "$REPLY" in + 1) enigma_install_init; install_dependencies; break;; + 2) install_bbs; break;; + 3) enigma_install_init; install_everything; break;; + $((${#options[@]}+1))) printf "Goodbye!"; exit 0;; + *) printf "${FOREGROUND_STRONG_RED}Invalid option.${RESET}\n";continue;; + esac + done < /dev/tty + + unset PS3 } enigma_header -enigma_install_init -install_nvm -configure_nvm -download_enigma_source -install_node_packages -copy_template_files +menu enigma_footer } # this ensures the entire script is downloaded before execution diff --git a/mise.toml b/mise.toml index 6b1503af4..92efa94f5 100644 --- a/mise.toml +++ b/mise.toml @@ -1,6 +1,6 @@ [tools] -node = "18" -python = "3.10" +node = '18' +python = '3.10' [env] NODE_ENV = 'production'