#!/usr/bin/env bash ## CONSTANTS REPO_BRANCH=main YAMAL_DIR=/home/yamal YAMAL_CONFIG=$YAMAL_DIR/config RAILS_BASE_PORT=900 FORCE=false DEBUG='' PACMAN_CMD='pacman' SESSION_RESTART=false OS_RELEASE=/etc/os-release DISTRO=$(test -f "$OS_RELEASE" && (grep -s ^ID "$OS_RELEASE" | cut -d= -f2) || echo unknown_distro) # TODO: project introspection... declare -A DISTRO_PACKAGES DISTRO_PACKAGES[_]="postgresql shfmt" DISTRO_PACKAGES[debian]="build-essential libssl-dev libyaml-dev zlib1g-dev libgmp-dev libpq-dev libvips42 poppler-utils redis-server" DISTRO_PACKAGES[arch]="base-devel openssl libyaml zlib gmp libvips poppler valkey" ## FUNCTIONS function usage { echo "$(dirname $0)/$(basename $0) --repo-url|-r [--repo-name|-n ] [--project|-p ] [--branch|-b ] [--force|-f] [--debug|-d]" } function assert_requirements { [[ ! $SHELL =~ /bash$ ]] && (echo 'bash is mandatory!' && exit 1) command -v curl >/dev/null || (echo 'curl is mandatory!' && exit 2) true } function parse_options { while [[ $# -gt 0 ]]; do case "$1" in --repo-url | -r) shift 1 [[ -z ${1:-} || $1 =~ ^- ]] && usage && exit 1 REPO_URL=$1 ;; --repo-name | -n) shift 1 [[ -z ${1:-} || $1 =~ ^- ]] && usage && exit 1 REPO_NAME=$1 ;; --project | -p) shift 1 [[ -z ${1:-} || $1 =~ ^- ]] && usage && exit 1 PROJECT_NAME=$1 ;; --branch | -b) shift 1 [[ -z ${1:-} || $1 =~ ^- ]] && usage && exit 1 REPO_BRANCH=$1 ;; --origin | -o) shift 1 [[ -z ${1:-} || $1 =~ ^- ]] && usage && exit 1 ORIGIN=$1 ;; --force | -f) FORCE=true ;; --debug | -d) DEBUG='bash -xl' ;; --help | -h) usage exit 0 ;; *) echo "Unknown option: $1" usage exit 2 ;; esac shift 1 # Move to the next argument done } function assert_repo_url { if [[ -z ${REPO_URL:-} ]]; then >&2 echo -e "ERROR3: REPO_URL undefined!\n\tplease either use --repo-url or -r\n" usage exit 3 fi } function create_user { if ! id -u $PROJECT_NAME >/dev/null 2>&1; then [[ -d /opt/$PROJECT_NAME ]] && echo -e "ERROR\n special opt folder not empty: /opt/$PROJECT_NAME\nplease specify unique project name with argument --project|-p" && exit 20 sudo -u yamal -- mkdir -p $YAMAL_DIR/projects useradd -G ssh,yamal -rm --home-dir $YAMAL_DIR/projects/$PROJECT_NAME --shell /bin/bash $PROJECT_NAME echo "user $PROJECT_NAME successfully created!" fi if [[ ! -d /opt/$PROJECT_NAME ]]; then mkdir -p /opt/$PROJECT_NAME chown $PROJECT_NAME:$PROJECT_NAME /opt/$PROJECT_NAME fi if [[ ! -d /etc/$PROJECT_NAME ]]; then mkdir -p /etc/$PROJECT_NAME echo "special folder: /etc/$PROJECT_NAME successfully created!" fi chown -R $PROJECT_NAME:$PROJECT_NAME /etc/$PROJECT_NAME } function set_project_name { [[ -z ${REPO_NAME:-} ]] && REPO_NAME=$(echo $REPO_URL | rev | cut -d/ -f1 | rev |cut -d. -f1) # get last url part minus '.git' DB_USER=$REPO_NAME [[ -z ${PROJECT_NAME:-} ]] && PROJECT_NAME=$REPO_NAME true } function define_rails_app { if [[ -f $YAMAL_CONFIG ]]; then local index=$(grep "^rails_app_.*=$PROJECT_NAME\$" $YAMAL_CONFIG | cut -d '=' -f1 | cut -d '_' -f3) [[ -z $index ]] && index=$(grep "rails_app_count=" $YAMAL_CONFIG | cut -d '=' -f2) fi RAILS_APP=${index:-0} } function inc_rails_app_count { if [[ -f $YAMAL_CONFIG ]]; then if ! grep -q "^rails_app_.*=$PROJECT_NAME\$" $YAMAL_CONFIG; then echo "rails_app_$RAILS_APP=$PROJECT_NAME" >>$YAMAL_CONFIG RAILS_APP=$(($RAILS_APP + 1)) sed -i "s/^rails_app_count.*/rails_app_count=$RAILS_APP/" $YAMAL_CONFIG echo "new rails app succesfully registered!" fi else mkdir -p $(dirname $YAMAL_CONFIG) echo "rails_app_count=1" >$YAMAL_CONFIG echo "rails_app_$RAILS_APP=$PROJECT_NAME" >>$YAMAL_CONFIG fi } function install_systemd_service { local service="/etc/systemd/system/$PROJECT_NAME.service" local rails_port=$(($RAILS_BASE_PORT + $RAILS_APP)) if [[ ! -f $service ]]; then cat <$service [Unit] Description=$PROJECT_NAME After=network.target [Service] Type=simple User=$PROJECT_NAME SyslogIdentifier=$PROJECT_NAME AmbientCapabilities=CAP_NET_BIND_SERVICE PermissionsStartOnly=true WorkingDirectory=/opt/$PROJECT_NAME ExecStart=$YAMAL_DIR/projects/$PROJECT_NAME/.local/bin/mise exec -- rails server --port $rails_port [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable $PROJECT_NAME fi systemctl restart $PROJECT_NAME systemctl is-active $PROJECT_NAME >/dev/null && echo "service $PROJECT_NAME running on port: $rails_port" } function launch_normal_user_setup { # clean temporary files in case mise install ruby fails! rm /tmp/mise-ruby-build -rf echo "launch setup as normal user: $PROJECT_NAME" local cmd="${DEBUG:-bash -l} -- $(realpath $(dirname "$0"))/lib/setup-prod-normal-user.bash $REPO_URL $REPO_BRANCH $FORCE" if sudo -iu $PROJECT_NAME $cmd; then : #ok else local exit_code=$? [[ $exit_code == 100 ]] && echo 'up-to-date: no change!' && exit 0 echo "an error $exit_code has occured during 'setup-prod-normal-user'" && exit $exit_code fi } function enhance_mise_user_from_origin { [[ -z ${ORIGIN:-} ]] && return if [[ -d $ORIGIN/.local/share/mise/installs/ruby ]] && [[ ! -f /home/$PROJECT_NAME/.local/bin/mise ]]; then echo -n "copy mise ruby from origin=$ORIGIN..." mkdir -p /home/$PROJECT_NAME/.local/share/mise/installs/ruby cp -r $ORIGIN/.local/share/mise/installs/ruby /home/$PROJECT_NAME/.local/share/mise/installs/ chown -R $PROJECT_NAME:$PROJECT_NAME /home/$PROJECT_NAME/.local echo OK fi } function install_pacapt { if [[ ! -f $HOME/.local/bin/pacman ]]; then mkdir -p $HOME/.local/bin curl -sLo $HOME/.local/bin/pacman https://github.com/icy/pacapt/raw/ng/pacapt chmod 755 $HOME/.local/bin/pacman else if [[ $DISTRO == 'arch' ]]; then echo 'pacman natively detected!' else PACMAN_CMD="$HOME/.local/bin/pacman" # echo "pacapt/pacman ($PACMAN_CMD) already installed!" fi fi } function install_idem_packages { if ! pacman -Qi $1 &>/dev/null; then sudo $HOME/.local/bin/pacman -S --noconfirm $1 >/dev/null echo "$2 installed successfully" else echo "$2 already installed!" fi } function install_packages { install_idem_packages "${DISTRO_PACKAGES[_]}" "generic packages" [ -v "DISTRO_PACKAGES[${DISTRO}]" ] && install_idem_packages "${DISTRO_PACKAGES[${DISTRO}]}" "distro specific packages: [$DISTRO]" true } function assert_etc_config_for_user { local config_dir="/etc/$PROJECT_NAME" if [[ -d $config_dir ]]; then chown $PROJECT_NAME $config_dir chmod -R 750 $config_dir else echo -e "-----\nERROR\n-----\nplease provide configuration file from location:\n $config_dir" false fi } function postgres_newdb { if ! (sudo -u postgres -- psql --csv -tc "SELECT 1 as found FROM pg_roles WHERE rolname = '$DB_USER'" | grep -q ^1$); then echo "creating postgresql user: $DB_USER" sudo -iu postgres psql -c "CREATE USER $DB_USER WITH PASSWORD '$DB_USER'" sudo -iu postgres psql -c "ALTER USER $DB_USER WITH SUPERUSER" fi } function postgres_global_encoding_utf8 { if ! sudo -iu postgres -- psql -c '\l template1' | grep -q UTF8; then echo 'defining postgresql template1 with default UTF8 encoding' sudo -iu postgres -- psql <