As a developer, it’s important to have a reliable and efficient development environment in order to streamline your workflow and increase productivity. However, setting up a new Mac can be time-consuming and tedious, especially if you have a long list of tools and applications that you need to install and configure.

To help streamline the process, I have created a macOS setup script written in bash that automates the installation and configuration of all the tools and applications that I use in my development workflow. This script takes care of everything from installing the latest version of Xcode to configuring your terminal with your preferred color scheme and plugins.

So if you’re a developer looking to streamline your MacOS setup process, or if you’re just interested in learning more about the tools and applications that I use in my development workflow, stay tuned for more posts.

#!/bin/bash
# MacOS Developer Build Script
#
# README FIRST
# 
# 1. Download to downloads/document folder, doesn't matter. Name it macos_build.sh
# 2. Open Terminal, cd to the directory you downloaded it to
# 3. Run chmod 777 macos_build.sh
# 4. Install xcode, xcode-select --install
# 5. Wait for install to complete of xcode
# 6. Run, ./macos_build.sh
# 7. Download PostgreSQL.app from https://github.com/PostgresApp/PostgresApp/releases/download/v2.5/Postgres-2.5-9.6-10-11-12-13-14.dmg
# 8. Download Redis.app from https://jpadilla.github.io/redisapp/
#



# helpers
function echo_ok { echo -e '\033[1;32m'"$1"'\033[0m'; }
function echo_warn { echo -e '\033[1;33m'"$1"'\033[0m'; }
function echo_error  { echo -e '\033[1;31mERROR: '"$1"'\033[0m'; }

echo_ok "Install starting. You may be asked for your password (for sudo)."

# requires xcode and tools!
xcode-select -p || exit "XCode must be installed! (use the app store)"

# requirements
# cd ~
# mkdir -p tmp
# echo_warn "setting permissions..."
# for dir in "/usr/local/bin /usr/local/include /usr/local/lib /usr/local/share"; do
#     sudo chgrp admin $dir
#     sudo chmod g+w $dir
# done

# homebrew
export HOMEBREW_CASK_OPTS="--appdir=/Applications"
if hash brew &> /dev/null; then
    echo_ok "Homebrew already installed"
else
    echo_warn "Installing homebrew..."
    ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
fi

# moar homebrew...
brew update && brew cleanup

# brew taps
brew tap homebrew/cask-versions


function install_homebrew_core_packages() {
    local packages=(
        bash
        bash-completion
        openssl
	coreutils
        ctags
        fd
        fzf
        git
        graphviz
        htop
        httpie
        hub
        hugo
        imagemagick
        jq
        pgbadger
	libpq
        pv
        rename
        ripgrep
        terminal-notifier
        the_silver_searcher
	libxmlsec1
        geoipupdate
        yarn
        npm
        azure-cli
        pango
        libffi
        autoconf
        automake
        cowsay
        cmatrix
        figlet
        gettext
        go
        freetype
        htop-osx
        jq
        libxml2
        node
        qt 
        readline
        sqlite
        v8
        wget
        pipx
        pyenv
        pyenv-virtualenvwrapper
        shellcheck
        svn
	libmagic
        archey
        dockutil
    )
    brew install ${packages[@]} || continue
}

install_homebrew_core_packages

function install_homebrew_cask_packages() {
    local casks=(
    	google-chrome
    	firefox
        appcleaner
    	chrome-devtools
    	sublime-text
    	pycharm
    	Datagrip
    	github
    	iterm2
    	postman
    	mongodb-compass
    	zoom
    	termius
    	clickup
    	another-redis-desktop-manager
    	microsoft-word	
    	microsoft-excel
    	microsoft-powerpoint
    	microsoft-outlook
    	setapp
        pgadmin4
        ngrok
        bettertouchtool
        day-o
        karabiner-elements
        the-unarchiver
        flux
        skitch
        devutils
        virtualbox
        coteditor
        yippy
	rectangle
    )
    brew install --cask ${casks[@]} || continue
}

echo_warn "Installing applications..."
install_homebrew_cask_packages

sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

# Install Docker, which requires virtualbox
brew install docker

# Install developer friendly quick look plugins; see https://github.com/sindresorhus/quick-look-plugins
brew install --cask qlcolorcode qlstephen qlmarkdown quicklook-json qlprettypatch quicklook-csv betterzip qlimagesize webpquicklook suspicious-package quicklookase qlvideo


function configure_all() {
    configure_keyboard
    configure_screensaver
    configure_screencapture
    configure_touchpad

    # Reveal IP address, hostname, OS version, etc. when clicking the clock
    # in the login window
    sudo defaults write /Library/Preferences/com.apple.loginwindow AdminHostInfo HostName

    # Show icons for hard drives, servers, and removable media on the desktop
    defaults write com.apple.finder ShowExternalHardDrivesOnDesktop -bool true
    defaults write com.apple.finder ShowHardDrivesOnDesktop -bool true
    defaults write com.apple.finder ShowMountedServersOnDesktop -bool true
    defaults write com.apple.finder ShowRemovableMediaOnDesktop -bool true

    # Finder: show hidden files by default
    defaults write com.apple.finder AppleShowAllFiles -bool true

    # Finder: show all filename extensions
    defaults write NSGlobalDomain AppleShowAllExtensions -bool true

    # Finder: show status bar
    defaults write com.apple.finder ShowStatusBar -bool true

    # Finder: show path bar
    defaults write com.apple.finder ShowPathbar -bool true

    # Finder: allow text selection in Quick Look
    defaults write com.apple.finder QLEnableTextSelection -bool true

    # Display full POSIX path as Finder window title
    defaults write com.apple.finder _FXShowPosixPathInTitle -bool true

    # When performing a search, search the current folder by default
    defaults write com.apple.finder FXDefaultSearchScope -string "SCcf"

    # Disable the warning when changing a file extension
    defaults write com.apple.finder FXEnableExtensionChangeWarning -bool false

    # Enable spring loading for directories
    defaults write NSGlobalDomain com.apple.springing.enabled -bool true

    # Tweak the spring loading delay for directories
    defaults write NSGlobalDomain com.apple.springing.delay -float .5

    # Avoid creating .DS_Store files on network volumes
    defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true

    # Use list view in all Finder windows by default
    # Four-letter codes for the other view modes: `icnv`, `clmv`, `Flwv`
    defaults write com.apple.finder FXPreferredViewStyle -string "Nlsv"

    # Show the ~/Library folder
    chflags nohidden ~/Library

    # Show the main window when launching Activity Monitor
    defaults write com.apple.ActivityMonitor OpenMainWindow -bool true

    # Visualize CPU usage in the Activity Monitor Dock icon
    defaults write com.apple.ActivityMonitor IconType -int 5

    # Show all processes in Activity Monitor
    defaults write com.apple.ActivityMonitor ShowCategory -int 0

    # Sort Activity Monitor results by CPU usage
    defaults write com.apple.ActivityMonitor SortColumn -string "CPUUsage"
    defaults write com.apple.ActivityMonitor SortDirection -int 0

}

function configure_keyboard() {
    # Set fast key repeat rate.
    defaults write NSGlobalDomain KeyRepeat -int 2
    defaults write NSGlobalDomain InitialKeyRepeat -int 15
}

function configure_screensaver() {
    # Require password as soon as screen-saver or sleep mode starts.
    defaults write com.apple.screensaver askForPassword -int 1
    defaults write com.apple.screensaver askForPasswordDelay -int 0
}

function configure_screencapture() {
    # Disable shadow effect in screen capture.
    defaults write com.apple.screencapture disable-shadow -bool true
}

function configure_touchpad() {
    defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true
    defaults -currentHost write NSGlobalDomain com.apple.mouse.tapBehavior -int 1
}

configure_all

echo 'export PATH="/usr/local/opt/libpq/bin:$PATH"' >> ~/.zshrc

#cat >> ~/.bashrc << EOT
#if which pyenv > /dev/null 2>&1
#then
#    # Pyenv (will add shims to front of $PATH)
#    eval "$(pyenv init -)"
#
#    # Ensure commands from virtualenvwrapper are available, no matter which
#    # Python version is active. This is equiv to sourcing virtualenvwrapper.sh
#    pyenv virtualenvwrapper
#fi
#
#PIP_REQUIRE_VIRTUALENV=false pip list
#
#EOT

pyenv install 3.8.12
pyenv global 3.8.12
export PIP_REQUIRE_VIRTUALENV=true


# brew cask fonts
echo_warn "Installing fonts..."

function install_fonts() {
    brew tap homebrew/cask-fonts
    local fonts=(
        font-anonymous-pro
        font-inconsolata 
        font-inconsolata-for-powerline
        font-nixie-one
        font-office-code-pro
        font-roboto
        font-lato
        font-source-code-pro
        font-source-code-pro-for-powerline
        font-source-sans-pro
    )
    brew install ${fonts[@]} || continue
}

install_fonts