DEV Community

abbazs
abbazs

Posted on • Edited on

A setup script to install developer applications like docker, vscode, git, etc in debian based linux.

Here is a bash script that I've been working to install some of the applications that I install after setting up a new system:

Save the contents to a file named setup.sh anywhere, change the file permission and execute it.

#!/bin/bash

VPNROOT="/usr/local/vpnclient"
VPNCLIENT="$VPNROOT/vpnclient"

# Function to handle errors
handle_error() {
    # Print error message in red color and bold font
    local line_number=$1
    local error_message=$2
    echo -e "\033[1;31mError at line $line_number: $error_message\033[0m"
    exit 1
}

# Enable error handling
set -e

# Trap errors and call the handle_error function
trap 'handle_error ${LINENO} "Script execution failed"' ERR

# Function to print colored text
print_color() {
    local color=$1
    shift
    local text=$@
    echo -e "\033[${color}m${text}\033[0m"
}

# Function to check if a package is already installed
package_installed() {
    command -v "$1" &>/dev/null
}

# Function to check if the SoftEtherVPN Client is installed
softether_vpnclient_installed() {
    # Check if the file exists and if the command can be executed successfully
    if [ -f $VPNCLIENT ]; then
        return 0
    else
        return 1
    fi
}

add_microsoft_gpg() {
    if [ ! -f /etc/apt/trusted.gpg.d/microsoft.gpg ]; then
        # Check if the URL is reachable
        if ! curl --silent --head --fail https://packages.microsoft.com/keys/microsoft.asc >/dev/null; then
            handle_error ${LINENO} "[${apps[$app]}] Failed to install $app. Unable to reach the URL: https://packages.microsoft.com/keys/microsoft.asc"
        fi
        curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor >microsoft.gpg
        sudo install -o root -g root -m 644 microsoft.gpg /etc/apt/trusted.gpg.d/
        sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/edge stable main" > /etc/apt/sources.list.d/microsoft-edge-dev.list'
        sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list'
        sudo rm microsoft.gpg
        sudo aptitude update || handle_error ${LINENO} "Failed to update aptitude"
    fi
}

# Dictionary to store application names and their installation status
declare -A apps=(
    ["nvm"]="NVM"
    ["code"]="Visual Studio Code"
    ["microsoft-edge-stable"]="Microsoft Edge"
    ["google-chrome-stable"]="Google Chrome"
    ["docker"]="Docker"
    ["pyenv"]="Pyenv"
    ["poetry"]="Poetry"
    ["softether-vpnclient"]="SoftEtherVPN Client"
)

# Dictionary to store installed applications
installed_apps=()

# Dictionary to store not installed applications
not_installed_apps=()

# Iterate over the dictionary and check installation status
for app in "${!apps[@]}"; do
    echo "Checking $app"
    if package_installed "$app"; then
        installed_apps+=("$app")
    elif [ "$app" == "softether-vpnclient" ] && softether_vpnclient_installed; then
        installed_apps+=("$app")
    else
        not_installed_apps+=("$app")
    fi
done

# Display installation summary
print_color 41 "---------------------"
print_color 45 "Installation Summary:"
print_color 41 "---------------------"
if [ "${#installed_apps[@]}" -gt 0 ]; then
    print_color 45 "Installed applications:"
    print_color 41 "-----------------------"
    for app in "${installed_apps[@]}"; do
        echo -e "\e[1;32m[${apps[$app]}] $app\e[0m"
    done
    print_color 41 "-----------------------"
fi
if [ "${#not_installed_apps[@]}" -gt 0 ]; then
    print_color 45 "Not installed applications:"
    print_color 41 "---------------------------"
    for app in "${not_installed_apps[@]}"; do
        echo -e "\e[1;33m[${apps[$app]}] $app\e[0m"
    done
    print_color 41 "---------------------------"
fi

# Prompt user for installation
read -p "Do you want to install any missing applications? (y/n): " choice

if [[ $choice =~ ^[Yy]$ ]]; then
    # Check if aptitude is installed
    if ! package_installed aptitude; then
        echo "aptitude package manager not found. Installing aptitude..."
        sudo apt-get update || handle_error ${LINENO} "Failed to update packages"
        sudo apt-get install -y aptitude || handle_error ${LINENO} "Failed to install aptitude"
        sudo aptitude update || handle_error ${LINENO} "Failed to update aptitude"
        sudo aptitude install -y apt-transport-https \
            ca-certificates \
            curl \
            software-properties-common \
            gnupg \
            git \
            build-essential \
            libbz2-dev \
            libffi-dev \
            liblzma-dev \
            libncursesw5-dev \
            libreadline-dev \
            libsqlite3-dev \
            libssl-dev \
            libxml2-dev \
            libxmlsec1-dev \
            llvm \
            tk-dev \
            xz-utils \
            zlib1g-dev \
            jq \
            meld || handle_error ${LINENO} "Failed to install required packages"
    fi

    # Install microsoft gpg certificates
    add_microsoft_gpg
    # Install missing applications
    for app in "${not_installed_apps[@]}"; do
        echo "Installing ${apps[$app]}..."

        # Add installation steps for each application here

        # Example: Install NVM
        if [ "$app" == "nvm" ]; then
            # Add NVM installation steps here
            if ! curl --silent --head --fail https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh >/dev/null; then
                handle_error ${LINENO} "[${apps[$app]}] Failed to install $app. Unable to reach the URL: https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh"
            fi
            curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
            echo -e "\e[1;32m[${apps[$app]}] $app has been installed.\e[0m"
        fi

        # Example: Install Visual Studio Code
        if [ "$app" == "code" ]; then
            sudo aptitude install -y code
            echo -e "\e[1;32m[${apps[$app]}] $app has been installed.\e[0m"
        fi

        # Check if the app is "microsoft-edge-stable"
        if [ "$app" == "microsoft-edge-stable" ]; then
            # Add Microsoft Edge installation steps here
            sudo aptitude install -y $app || handle_error "[${apps[$app]}] Failed to install $app."
            echo -e "\e[1;32m[${apps[$app]}] $app has been installed.\e[0m"
        fi

        # Check if the app is "google-chrome-stable"
        if [ "$app" == "google-chrome-stable" ]; then
            # Add Google Chrome installation steps here

            # Check if the URL is reachable
            if ! curl --silent --head --fail https://dl.google.com/linux/linux_signing_key.pub >/dev/null; then
                handle_error ${LINENO} "[${apps[$app]}] Failed to install $app. Unable to reach the URL: https://dl.google.com/linux/linux_signing_key.pub"
            fi

            curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/google.gpg >/dev/null
            sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list'
            sudo aptitude update || handle_error "Failed to update aptitude"
            sudo aptitude install -y google-chrome-stable || handle_error "[${apps[$app]}] Failed to install $app."
            echo -e "\e[1;32m[${apps[$app]}] $app has been installed.\e[0m"
        fi

        # Check if the app is "docker"
        if [ "$app" == "docker" ]; then
            # Add Docker installation steps here

            # Check if the URL is reachable
            if ! curl --silent --head --fail https://download.docker.com/linux/ubuntu/gpg >/dev/null; then
                handle_error ${LINENO} "[${apps[$app]}] Failed to install $app. Unable to reach the URL: https://download.docker.com/linux/ubuntu/gpg"
            fi

            curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor >docker.gpg
            sudo install -o root -g root -m 644 docker.gpg /etc/apt/trusted.gpg.d/
            echo \
                "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/docker.gpg] https://download.docker.com/linux/ubuntu \
                $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" |
                sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
            sudo rm docker.gpg

            if ! curl --silent --head --fail https://download.docker.com/linux/ubuntu >/dev/null; then
                handle_error ${LINENO} "[${apps[$app]}] Failed to install $app. Unable to reach the URL: https://download.docker.com/linux/ubuntu"
            fi

            sudo aptitude update || handle_error${LINENO} "Failed to update aptitude"
            sudo aptitude install -y docker-ce docker-ce-cli containerd.io || handle_error ${LINENO} "[${apps[$app]}] Failed to install $app."

            # Add the current user to the docker group
            if ! grep -q "^docker:" /etc/group; then
                sudo groupadd docker
                sudo usermod -aG docker $USER
            fi

            # Check if the URL is reachable
            if ! curl --silent --head --fail "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" >/dev/null; then
                handle_error ${LINENO} "[${apps[$app]}] Failed to install Docker Compose. Unable to reach the URL: https://github.com/docker/compose/releases/latest"
            fi

            # Install Docker Compose
            sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" \
                -o /usr/local/bin/docker-compose
            sudo chmod +x /usr/local/bin/docker-compose

            echo -e "\e[1;32m[${apps[$app]}] $app has been installed.\e[0m"
        fi
        # Check if the app is "pyenv"
        if [ "$app" == "pyenv" ]; then
            # Add Pyenv installation steps here
            # Check if the URL is reachable
            if ! curl --silent --head --fail https://pyenv.run >/dev/null; then
                handle_error ${LINENO} "[${apps[$app]}] Failed to install $app. Unable to reach the URL: https://pyenv.run"
            else
                if ! curl https://pyenv.run | bash >/dev/null 2>&1; then
                    handle_error ${LINENO} "[${apps[$app]}] Failed to install $app."
                else
                    echo "" >>~/.bashrc
                    echo "# Add pyenv to path" >>~/.bashrc
                    echo 'export PYENV_ROOT="$HOME/.pyenv"' >>~/.bashrc
                    echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >>~/.bashrc
                    echo 'eval "$(pyenv init -)"' >>~/.bashrc
                    export PATH="$HOME/.pyenv/bin:$PATH"
                    eval "$(pyenv init --path)"
                    echo -e "\e[1;32m[${apps[$app]}] $app has been installed.\e[0m"
                fi
            fi
        fi
        # Example: Install Poetry
        if [ "$app" == "poetry" ]; then
            # Add Poetry installation steps here
            if ! curl --silent --head --fail https://install.python-poetry.org >/dev/null; then
                handle_error ${LINENO} "[${apps[$app]}] Failed to install $app. Unable to reach the URL: https://install.python-poetry.org"
            else
                if ! command -v python >/dev/null 2>&1; then
                    PYTHON_EXECUTABLE="python3"
                else
                    PYTHON_EXECUTABLE="python"
                fi

                if ! curl -sSL https://install.python-poetry.org | "$PYTHON_EXECUTABLE" - >/dev/null 2>&1; then
                    handle_error ${LINENO} "[${apps[$app]}] Failed to install $app."
                else
                    export PATH="$HOME/.local/bin:$PATH"
                    echo -e "\e[1;32m[${apps[$app]}] $app has been installed.\e[0m"
                fi
            fi
        fi

        # Example: Install SoftEtherVPN Client
        if [ "$app" == "softether-vpnclient" ]; then
            # Add SoftEtherVPN Client installation steps here
            api_url="https://api.github.com/repos/SoftEtherVPN/SoftEtherVPN_Stable/releases/latest"
            # Check if the URL is reachable
            if ! curl --silent --head --fail "$api_url" >/dev/null; then
                handle_error ${LINENO} "Failed to install $app. Unable to reach the URL: $api_url"
            fi

            response=$(curl -s "$api_url")
            build_tag=$(echo "$response" | jq -r '.tag_name')
            published_date=$(echo "$response" | jq -r '.published_at')
            published_date=$(date -u -d "$published_date" +%Y.%m.%d)
            arc=$(uname -m | rev | cut -c 1-2 | rev)
            url="https://github.com/SoftEtherVPN/SoftEtherVPN_Stable/releases/download/${build_tag}/softether-vpnclient-${build_tag}-${published_date}-linux-x64-64bit.tar.gz"
            # Check if the URL is reachable
            if ! curl --silent --head --fail "$url" >/dev/null; then
                handle_error ${LINENO} "Failed to install $app. Unable to reach the URL: $url"
            fi
            #
            curl -O -L $url
            # Extract SoftEtherVPN Client and handle errors
            if ! tar xzvf "softether-vpnclient-${build_tag}-${published_date}-linux-x64-64bit.tar.gz"; then
                handle_error ${LINENO} "Failed to extract $app."
            fi

            cd vpnclient
            # Compile SoftEtherVPN Client
            if ! make; then
                cd ..
                handle_error ${LINENO} "Failed to compile $app."
            fi
            cd ..
            sudo mv vpnclient /usr/local || handle_error ${LINENO} "Unable to move vpnclient to /usr/local"
            # Start SoftEtherVPN Client and handle errors
            if ! sudo $VPNCLIENT start; then
                handle_error ${LINENO} "Failed to start vpnclient"
            fi
            echo -e "\e[1;32m$app has been installed.\e[0m"
        fi
    done

    echo "Installation complete."
else
    echo "No applications will be installed."
fi
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
nricks profile image
nricks • Edited

I think they repackaged compose into an actual docker plugin installable from the repo that you run as "docker compose up" instead of the way you're doing it, there is actually some since QoL stuff in it even in the naming conventions alone.