#!/usr/bin/env bash
# This script sets up a development environment for a Linux-based system.
# It installs and configures various tools, packages, and configurations
# necessary for a comfortable and efficient development experience.
#
# Currently only supported on ubuntu and ubuntu derivitives, built for 22.04
# Written by: https://github.com/linkinlog
# Exit if anything fails (has an exit code of 1)
set -e
# Set arguments
readonly HOSTNAME="$1"
readonly GIT_EMAIL="$2"
readonly GIT_USER="$3"
readonly GH_PERSONAL_TOKEN="$4"
readonly HOMEDIR="$HOME"
## Tools
readonly TOOLS=("ssh" "gh" "git" "xclip" "docker" "ripgrep" "tmux" "zsh" "brave-browser" "i3")
readonly DEPS=("ninja-build" "gettext" "libtool-bin" "cmake" "g++" "pkg-config" "unzip" "curl" "python3" "python3-pip" "bsdutils" "cmake" "dpkg-dev" "fakeroot" "gcc" "g++" "libegl1-mesa-dev" "libssl-dev" "libfontconfig1-dev" "libwayland-dev" "libx11-xcb-dev" "libxcb-ewmh-dev" "libxcb-icccm4-dev" "libxcb-image0-dev" "libxcb-keysyms1-dev" "libxcb-randr0-dev" "libxcb-render0-dev" "libxcb-xkb-dev" "libxkbcommon-dev" "libxkbcommon-x11-dev" "libxcb-util0-dev" "lsb-release" "python3" "xdg-utils" "xorg-dev" "luarocks" "ruby" "ruby-dev" "php" "php-zip" "unzip" "openjdk-11-jdk" "julia" "powershell" "wget" "apt-transport-https" "software-properties-common")
# Ensure all dependencies are here after installation
check_dependencies() {
printf "\r\e[K\e[34m🛠️ Checking dependencies...\e[0m"
if ! git --version >/dev/null 2>&1; then
printf "\r\e[K\e[31m❌ Git is not installed. Please install Git and try again. Exiting... \e[0m"
exit 1
fi
if ! curl --version >/dev/null 2>&1; then
printf "\r\e[K\e[31m❌ Curl is not installed. Please install Curl and try again. Exiting... \e[0m"
exit 1
fi
if ! wget --version >/dev/null 2>&1; then
printf "\r\e[K\e[31m❌ Wget is not installed. Please install Wget and try again. Exiting... \e[0m"
exit 1
fi
if ! unzip -v >/dev/null 2>&1; then
printf "\r\e[K\e[31m❌ Unzip is not installed. Please install Unzip and try again. Exiting... \e[0m"
exit 1
fi
if ! dpkg -s build-essential >/dev/null 2>&1; then
printf "\r\e[K\e[31m❌ Build-essential is not installed. Please install Build-essential and try again. Exiting... \e[0m"
exit 1
fi
printf "\r\e[K\e[32m✅ All dependencies set. Continuing...\e[0m"
}
# Refresh sudo auth so we can ask for password less
refresh_sudo() {
printf "\r\e[K\e[34m🛠️ Refreshing sudo authentication... \e[0m"
sudo -v
}
# Installs whatever package list is passed in
# @param Array package_list
install_packages() {
local package_manager opts
local update_cmd="update"
local install_cmd="install"
local package_list=("$@")
printf "\r\e[K\e[34m🛠️ Determining package manager... \e[0m"
if command -v apt-get >/dev/null 2>&1; then
package_manager="apt-get"
opts=(-y -qq)
update_cmd="upgrade"
sudo "$package_manager" update "${opts[@]}"
elif command -v dnf >/dev/null 2>&1; then
package_manager="dnf"
opts=(-y -q)
update_cmd="upgrade"
elif command -v pacman >/dev/null 2>&1; then
package_manager="pacman"
opts=(--noconfirm --quiet)
update_cmd="-Syu"
install_cmd="-S"
elif command -v zypper >/dev/null 2>&1; then
package_manager="zypper"
opts=(--non-interactive --quiet)
else
printf "\r\e[K\e[31m❌ No supported package manager found. Exiting... \e[0m"
exit 1
fi
printf "\r\e[K\e[34m🛠️ Using %s as package manager and updating...\e[0m" "$package_manager"
sudo "$package_manager" "${opts[@]}" "$update_cmd"
sudo "$package_manager" "${opts[@]}" "$install_cmd" "${package_list[@]}"
printf "\r\e[K\e[32m✅ All packages installed. Continuing...\e[0m"
}
add_ms_repo() {
local deb_output=packages-microsoft-prod.deb
local microsoft_deb
if [ -e "$deb_output" ]; then
printf "\r\e[K\e[32m✅ Microsoft deb found. Continuing...\e[0m"
return 0
fi
microsoft_deb=https://packages.microsoft.com/config/ubuntu/"$(lsb_release -rs)"/packages-microsoft-prod.deb
if output=$(sudo wget -q -O "$deb_output" "$microsoft_deb" 2>&1); then
printf "\r\e[K\e[32m✅ Installing powershell dependency. Continuing...\e[0m"
sudo dpkg -i packages-microsoft-prod.deb
else
printf "\r\e[K\e[31m❌ Error occurred: %s Exiting... \e[0m" "$output"
exit 1
fi
printf "\r\e[K\e[32m✅ Powershell all set to be installed. Continuing...\e[0m"
}
## Setting up brave gpg key
add_brave_repo() {
printf "\r\e[K\e[34m🛠️ Adding Brave GPG key if needed...\e[0m"
local gpg_output=/usr/share/keyrings/brave-browser-archive-keyring.gpg
if [ -e "$gpg_output" ]; then
printf "\r\e[K\e[32m✅ Brave gpg keyring found. Continuing...\e[0m"
return 0
fi
local brave_gpg=https://brave-browser-apt-release.s3.brave.com/brave-browser-archive-keyring.gpg
if output=$(sudo wget -O "$gpg_output" "$brave_gpg" 2>&1); then
echo "deb [signed-by=/usr/share/keyrings/brave-browser-archive-keyring.gpg] https://brave-browser-apt-release.s3.brave.com/ stable main" | sudo bash -c 'cat > /etc/apt/sources.list.d/brave-browser-release.list'
else
printf "\r\e[K\e[31m❌ Error occurred: %s Exiting... \e[0m" "$output"
exit 1
fi
printf "\r\e[K\e[32m✅ Brave all set to be installed. Continuing...\e[0m"
}
# Use Rustup to install Rust stable
install_rust() {
# Allows a user to set the profile/toolchain they want
local profile="${RUST_PROFILE:-minimal}"
local toolchain="${RUST_TOOLCHAIN:-stable}"
if ! command -v rustc >/dev/null 2>&1; then
printf "\r\e[K\e[34m🛠️ Installing Rust stable with Rustup...\e[0m"
curl https://sh.rustup.rs -sSf | sh -s -- --profile "$profile" --default-toolchain "$toolchain" -y >/dev/null
printf "\r\e[K\e[32m✅ Rust stable installed. Continuing...\e[0m"
fi
rustup default "$toolchain" >/dev/null 2>&1
rustup update >/dev/null 2>&1
printf "\r\e[K\e[32m✅ Rust stable updated. Continuing...\e[0m"
}
# Installing various cargo tools
# for now just tree-sitter.
install_rust_tools() {
printf "\r\e[K\e[34m🛠️ Installing tree-sitter-cli with Cargo...\e[0m"
# Add Rust to PATH (taken from .cargo/env)
export PATH="$HOMEDIR/.cargo/bin:$PATH"
if ! command -v cargo >/dev/null 2>&1; then
printf "\r\e[K\e[31m❌ Cargo not found. Exiting... \e[0m"
exit 1
fi
if ! command -v tree-sitter >/dev/null 2>&1; then
cargo install tree-sitter-cli >/dev/null
fi
printf "\r\e[K\e[32m✅ Tree-sitter-cli installed. Continuing...\e[0m"
}
# Installing our terminal emulator, wezterm
install_wezterm() {
local wezterm_version
local release
wezterm_version=$(curl -s "https://api.github.com/repos/wez/wezterm/releases/latest" | grep -Po '"tag_name": "\K[^"]*')
release=$(lsb_release -rs)
if command -v wezterm >/dev/null 2>&1; then
installed_version=$(wezterm -V | awk '{print $2}')
if [ "$installed_version" = "$wezterm_version" ]; then
printf "\r\e[K\e[32m✅ Wezterm is installed and up to date. Continuing...\e[0m"
return 0
fi
fi
printf "\r\e[K\e[34m🛠️ Installing WezTerm version %s...\e[0m" "$wezterm_version"
if output=$(curl -LO "https://github.com/wez/wezterm/releases/download/${wezterm_version}/wezterm-${wezterm_version}.Ubuntu${release}.deb" 2>&1); then
sudo apt-get install -yq "./wezterm-${wezterm_version}.Ubuntu${release}.deb" >/dev/null
else
printf "\r\e[K\e[31m❌ Error occured: %s Exiting... \e[0m" "$output"
fi
printf "\r\e[K\e[32m✅ Wezterm installed. Continuing...\e[0m"
}
# Installing Go from source and deleting old copies
install_go() {
local arch="linux-amd64"
local go_version
local go_install_path
go_version=$(curl -sSL "https://golang.org/VERSION?m=text")
go_install_path="$HOME/${go_version}.${arch}.tar.gz"
if command -v go >/dev/null 2>&1 && [[ "$(go version | awk '{print $3}')" == "$go_version" ]]; then
printf "\r\e[K\e[32m✅ Go version %s is already installed. Continuing... \e[0m" "$go_version"
return 0
fi
if output=$(sudo wget -O "$go_install_path" "https://go.dev/dl/${go_version}.${arch}.tar.gz" 2>&1); then
printf "\r\e[K\e[34m🛠️ Installing Go version %s to %s... \e[0m" "$go_version" "$go_install_path"
sudo rm -rf /usr/local/go &&
sudo tar -C /usr/local -xzf "${go_version}.${arch}.tar.gz" >/dev/null
else
printf "\r\e[K\e[31m❌ Error occurred: %s. Exiting... \e[0m" "$output"
exit 1
fi
printf "\r\e[K\e[32m✅ Go installed. Continuing...\e[0m"
}
# Install all recommended Go tools
install_go_tools() {
printf "\r\e[K\e[34m🛠️ Installing/updating Go tools...\e[0m"
if command -v go >/dev/null 2>&1; then
local go_tools=(
"github.com/ChimeraCoder/gojson/gojson@latest"
"github.com/abenz1267/gomvp@latest"
"github.com/alvaroloes/enumer@latest"
"github.com/cweill/gotests/gotests@latest"
"github.com/davidrjenni/reftools/cmd/fillstruct@latest"
"github.com/fatih/errwrap@latest"
"github.com/fatih/gomodifytags@latest"
"github.com/go-delve/delve/cmd/dlv@latest"
"github.com/godoctor/godoctor@latest"
"github.com/golang/mock/mockgen@latest"
"github.com/golangci/golangci-lint/cmd/golangci-lint@latest"
"github.com/jimmyfrasche/closed/cmds/fillswitch@latest"
"github.com/josharian/impl@latest"
"github.com/koron/iferr@latest"
"github.com/kyoh86/richgo@latest"
"github.com/ofabry/go-callvis@latest"
"github.com/onsi/ginkgo/ginkgo@latest"
"github.com/rogpeppe/godef@latest"
"github.com/searKing/golang/tools/go-enum@latest"
"github.com/segmentio/golines@latest"
"github.com/tmc/json-to-struct@latest"
"github.com/uber/go-torch@latest"
"golang.org/x/tools/cmd/callgraph@latest"
"golang.org/x/tools/cmd/goimports@latest"
"golang.org/x/tools/cmd/gorename@latest"
"golang.org/x/tools/cmd/guru@latest"
"golang.org/x/vuln/cmd/govulncheck@latest"
"gotest.tools/gotestsum@latest"
"mvdan.cc/gofumpt@latest"
)
for tool in "${go_tools[@]}"; do
exec_name=$(basename "${tool%@*}")
if ! type "$exec_name" >/dev/null 2>&1; then
printf "\r\e[K\e[34m🛠️ Installing/updating %s...\n\e[0m" "${tool%@*}"
GO111MODULE=on sudo go install "$tool" >/dev/null
fi
done
fi
printf "\r\e[K\e[32m✅ Go tools installed/updated. Continuing...\e[0m"
}
# We use packer for plugin management in Neovim, so install that.
# We use TPM for plugin management in Tmux, so install that.
install_terminal_tools() {
local packer_repo="https://github.com/wbthomason/packer.nvim"
local packer_dir="$HOMEDIR/.local/share/nvim/site/pack/packer/start/packer.neovim"
local tpm_repo="https://github.com/tmux-plugins/tpm"
local tpm_dir="$HOMEDIR/.tmux/plugins/tpm"
printf "\r\e[K\e[34m🛠️ Installing TPM and Packer...\e[0m"
if [ -d "$packer_dir" ]; then
git -C "$packer_dir" pull -q >/dev/null
else
git clone -q --depth 1 "$packer_repo" "$packer_dir" >/dev/null
fi
if [ -d "$tpm_dir" ]; then
git -C "$tpm_dir" pull -q >/dev/null
else
git clone -q "$tpm_repo" "$tpm_dir" >/dev/null
fi
printf "\r\e[K\e[32m✅ Packer and TPM should be installed! \e[33mBe sure to run +I to install TPM plugins.\e[32m Continuing...\e[0m"
}
# Lazygit makes working with Git in the CLI much nicer, so install it.
install_lazygit() {
local lazygit_version
lazygit_version=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | grep -Po '"tag_name": "v\K[^"]*')
if command -v lazygit >/dev/null 2>&1 && [[ "$lazygit_version" == "$(lazygit -v | grep -oP '(?<=, )version=\K[^,]*')" ]]; then
printf "\r\e[K\e[32m✅ Lazygit version %s is already installed. Continuing... \e[0m" "$lazygit_version"
return 0
fi
printf "\r\e[K\e[34m🛠️ Installing lazygit...\e[0m"
if output=$(curl -Lo lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/latest/download/lazygit_${lazygit_version}_Linux_x86_64.tar.gz" 2>&1); then
tar xf lazygit.tar.gz lazygit
sudo install lazygit /usr/local/bin
printf "\r\e[K\e[32m✅ Installed Lazygit. Continuing...\e[0m"
else
printf "\r\e[K\e[31m❌ Failed cURL'ing lazygit. Exiting... \e[0m"
return 1
fi
}
# Lazydocker makes working with Docker in the CLI much nicer, so install it.
install_lazydocker() {
if command -v lazydocker >/dev/null 2>&1; then
printf "\r\e[K\e[32m✅ Lazydocker already installed. Continuing...\e[0m"
return 0
fi
printf "\r\e[K\e[34m🛠️ Installing Lazydocker...\e[0m"
if output=$(curl https://raw.githubusercontent.com/jesseduffield/lazydocker/master/scripts/install_update_linux.sh | bash 2>&1); then
printf "\r\e[K\e[32m✅ Installed Lazydocker. Continuing... \e[0m"
else
printf "\r\e[K\e[32m✅ Error: Failed to install Lazydocker. Continuing... \e[0m"
fi
printf "\r\e[K\e[32m✅ Installed Lazydocker. Continuing...\e[0m"
}
# I cant write code without vim, apologies
install_neovim() {
local neovim_repo="https://github.com/neovim/neovim"
local neovim_dir="$HOMEDIR/neovim-build"
if command -v nvim >/dev/null 2>&1; then
installed_version=$(nvim --version | head -n 1 | grep -oP 'NVIM v\K[\d.]+')
latest_version=$(curl -s https://api.github.com/repos/neovim/neovim/releases/tags/nightly | grep -oP 'NVIM v\K[\d.]+')
if [ "$installed_version" = "$latest_version" ]; then
printf "\r\e[K\e[32m✅ Neovim is already up-to-date. Continuing...\e[0m"
return 0
fi
fi
printf "\r\e[K\e[34m🛠️ Installing Neovim...\e[0m"
if [ -d "$neovim_dir" ]; then
printf "\r\e[K\e[34m🛠️ Neovim build directory found, updating...\e[0m"
git -C "$neovim_dir" pull -q >/dev/null
rm -rf "$neovim_dir/build" >/dev/null
else
printf "\r\e[K\e[34m🛠️ Neovim build not directory found, cloning...\e[0m"
git clone -q --depth 1 "$neovim_repo" "$neovim_dir" >/dev/null
fi
printf "\r\e[K\e[34m🛠️ Making Neovim...\e[0m"
cd "$neovim_dir" && make CMAKE_BUILD_TYPE=RelWithDebInfo >/dev/null
printf "\r\e[K\e[34m🛠️ Installing Neovim...\e[0m"
sudo make install >/dev/null || {
printf "\r\e[K\e[31m❌ Error: failed installing Neovim. Exiting... \e[0m"
return 1
}
nvim -c 'TSUpdate' -c 'qa' >/dev/null
printf "\r\e[K\e[32m✅ Installed Neovim %s. Continuing...\e[0m" "$(nvim --version | head -n 1 | awk '{print $2}')"
}
# Tools provided by pip/npm
install_neovim_tools() {
if pip3 list 2>/dev/null | grep -q neovim; then
printf "\r\e[K\e[32m✅ Neovim is installed with pip3. Continuing...\e[0m"
else
pip3 install neovim >/dev/null
fi
if pip3 list 2>/dev/null | grep -q autopep8; then
printf "\r\e[K\e[32m✅ Autopep8 is installed with pip3. Continuing... \e[0m"
else
pip3 install autopep8 >/dev/null
fi
if npm list -g --depth=0 2>/dev/null | grep -q remark; then
printf "\r\e[K\e[32m✅ Remark is installed globally with npm. Continuing...\e[0m"
else
sudo npm install -g remark >/dev/null
fi
if npm list -g --depth=0 2>/dev/null | grep -q neovim; then
printf "\r\e[K\e[32m✅ Neovim is installed globally with npm. Continuing...\e[0m"
else
sudo npm install -g neovim >/dev/null
fi
if gem list -i neovim >/dev/null 2>&1; then
printf "\r\e[K\e[32m✅ Neovim is installed with gem. Continuing...\e[0m"
else
sudo gem install neovim >/dev/null
fi
}
# Change the hostname to whatever was set
set_hostname() {
if [ "$HOSTNAME" == "" ]; then
printf "\r\e[K\e[34m🛠️ Skipping hostname config...\e[0m"
return 0
fi
sudo su -c "echo '$HOSTNAME' > /etc/hostname"
export HOST=$HOSTNAME
printf "\r\e[K\e[32m✅ Hostname set to %s. Continuing...\e[0m" "$HOSTNAME"
}
# Configure local git
config_git() {
if [ "$GIT_EMAIL" == "" ] || [ "$GIT_USER" == "" ]; then
printf "\r\e[K\e[34m🛠️ Skipping git config...\e[0m"
return 0
fi
git config --global user.email "$GIT_EMAIL"
git config --global user.name "$GIT_USER"
printf "\r\e[K\e[32m✅ Git configured to use %s as email and %s as user. Continuing...\e[0m" "$GIT_EMAIL" "$GIT_USER"
}
# Use systemd to start and enable ssh so we can connect
start_enable_ssh() {
# Check if the service is enabled
printf "\r\e[K\e[34m🛠️ Starting and enabling SSH...\e[0m"
if ! systemctl is-enabled ssh >/dev/null 2>&1; then
sudo systemctl enable ssh >/dev/null 2>&1
fi
# Check if the service is started (active)
if ! systemctl is-active ssh >/dev/null 2>&1; then
sudo systemctl start ssh >/dev/null 2>&1
fi
printf "\r\e[K\e[32m✅ SSH started and enabled. Continuing...\e[0m"
}
install_composer() {
if ! command -v composer >/dev/null 2>&1; then
curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer
fi
}
# Take the personal token that was made, auth with it, and add the ssh key
# Necessary since we use git submodules with SSH
setup_github() {
if [ "$GH_PERSONAL_TOKEN" == "" ]; then
printf "\r\e[K\e[34m🛠️ Skipping GH auth...\e[0m"
return 0
fi
printf "\r\e[K\e[34m🛠️ Setting up GitHub...\e[0m"
if ! gh auth status >/dev/null 2>&1; then
printf "\r\e[K\e[34m🛠️ Adding Token %s... \e[0m" "$GH_PERSONAL_TOKEN"
gh auth login --with-token <<<"$GH_PERSONAL_TOKEN"
fi
if [ ! -f "$HOME/.ssh/github" ]; then
# Make new ssh key for gh
printf "\r\e[K\e[34m🛠️ Creating ssh key for GitHub for %s...\e[0m" "$HOST"
ssh-keygen -f ~/.ssh/github -N ""
printf "\r\e[K\e[34m🛠️ Adding ssh key to github... \e[0m"
gh ssh-key add "$HOMEDIR/.ssh/github.pub" --title "$HOST"
fi
printf "\r\e[K\e[32m✅ GitHub setup finished. Continuing...\e[0m"
}
# Heres the meat and potatoes, our bare repo will be unpacked
setup_git_repo() {
printf "\r\e[K\e[34m🛠️ Setting up Git repo... \e[0m"
local dotfiles_repo="https://github.com/linkinlog/.dotfiles"
local dotfiles_dir="$HOMEDIR/.dotfiles.git"
local config_cmd="git --git-dir=$dotfiles_dir --work-tree=$HOMEDIR"
if [ ! -d "$dotfiles_dir" ]; then
git clone --bare "$dotfiles_repo" >/dev/null
eval "$config_cmd" checkout >/dev/null
fi
eval "$config_cmd" fetch -q origin development >/dev/null
eval "$config_cmd" merge -q development >/dev/null
eval "$config_cmd" config --local status.showUntrackedFiles no
printf "\r\e[K\e[34m🛠️ Setting up bare repo's submodules... \e[0m"
GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=no' eval "$config_cmd" submodule update --init --remote >/dev/null
printf "\r\e[K\e[34m🛠️ Installing our neovim plugins... \e[0m"
nvim --headless -c 'autocmd User PackerComplete quitall' -c 'PackerSync'
printf "\r\e[K\e[32m✅ Dotfiles repo setup finished. Continuing...\e[0m"
}
# Mainly just for the theme, hoping to phase out at some point
setup_ohmyzsh() {
printf "\r\e[K\e[34m🛠️ Setting up OhMyZsh... \e[0m"
if [ ! -d "$HOMEDIR/.oh-my-zsh" ]; then
export RUNZSH=no
export KEEP_ZSHRC=yes
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" \
"" --unattended || {
printf "\r\e[K\e[31m❌ Error: could not install OhMyZsh. Exiting... \e[0m"
exit 1
}
sudo chsh -s "$(which zsh)" -u "$(whoami)"
else
git -C "$HOMEDIR/.oh-my-zsh" pull -q >/dev/null
fi
local zsh_syntax_highlighting_path="${ZSH_CUSTOM:-$HOMEDIR/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting"
if [ -d "$zsh_syntax_highlighting_path" ]; then
git -C "$zsh_syntax_highlighting_path" pull -q >/dev/null
else
git clone -q https://github.com/zsh-users/zsh-syntax-highlighting.git "$zsh_syntax_highlighting_path" || {
printf "\r\e[K\e[31m❌ Error: could not clone zsh-syntax-highlighting Exiting... \e[0m"
exit 1
} >/dev/null
fi
local zsh_autosuggestions_path="${ZSH_CUSTOM:-$HOMEDIR/.oh-my-zsh/custom}/plugins/zsh-autosuggestions"
if [ -d "$zsh_autosuggestions_path" ]; then
git -C "$zsh_autosuggestions_path" pull -q >/dev/null
else
git clone -q https://github.com/zsh-users/zsh-autosuggestions "$zsh_autosuggestions_path" || {
printf "\r\e[K\e[31m❌ Error: could not clone zsh-autosuggestions Exiting... \e[0m"
exit 1
} >/dev/null
fi
printf "\r\e[K\e[32m✅ OhMyZsh, zsh-syntax-highlighting, and zsh-autosuggestions installed. Continuing...\e[0m"
}
# Group the dependency commands together
install_dependencies() {
add_brave_repo
add_ms_repo
install_packages "${DEPS[@]}" "${TOOLS[@]}"
check_dependencies
}
# Group the env setup commands together
configure_environment() {
set_hostname
config_git
start_enable_ssh
refresh_sudo
(install_go)
(install_go_tools)
(install_composer)
(install_lazydocker)
(install_lazygit)
refresh_sudo
(install_neovim)
(install_neovim_tools)
(install_rust)
refresh_sudo
(install_rust_tools)
(install_terminal_tools)
(setup_github)
(setup_git_repo)
refresh_sudo
(install_wezterm)
(setup_ohmyzsh)
}
# Run it all and only care about STDERR
main() {
cd "$HOME"
install_dependencies
configure_environment
printf "\r\e[K\e[32m✅ Should be all set, good luck!!\n\e[0m"
}
main "$@"