Code Monkey home page Code Monkey logo

conf's Introduction

Adam Liter’s computer configuration

New machine setup

SSH

The first thing that must be done in order to set up a new machine is to configure SSH and create a key. This allows for cloning of the git repo that contains my configuration files, which is hosted on GitHub.

First, create the SSH directory:

mkdir -p ~/.ssh
chmod 700 ~/.ssh

Optionally, I can also set up an authorized_keys file, which is useful if the new machine is intended to be used as a server in any capacity.

touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Next, I need to actually create a new SSH key, which can be done with:

ssh-keygen -t rsa -b 4096 -C "COMMENT GOES HERE"

Then, I can set up a basic SSH configuration file to ensure that the key that I just generated is used when trying to connect to GitHub as well as my private git server, which contains some of the submodules in this repository. (Note that this basic SSH configuration file will be overwritten later in this new machine configuration process.)

This allows repositories to be cloned in either of the following manners:

  1. git clone ssh://github/adamliter/conf.git
  2. git clone github:adamliter/conf.git
cat > ~/.ssh/config <<EOF
Host github
  Hostname github.com
  IdentityFile ~/.ssh/id_rsa
  User git

Host git-adamliter
  Hostname git.adamliter.org
  IdentityFile ~/.ssh/id_rsa
  User git
EOF
chmod 600 ~/.ssh/config

Finally, the public key needs to be added to GitHub and to /home/git/.ssh/authorized_keys on the machine git.adamliter.org. (It will also eventually need to be added to GitLab and Bitbucket.)

Bootstrapping

To bootstrap the setup of a new machine, use the bootstrap.sh script, described below. It can be downloaded from GitHub with either curl or wget:

With curl:

curl -fsSL https://raw.githubusercontent.com/adamliter/conf/master/bootstrap.sh | bash -v

With wget:

wget -O- https://raw.githubusercontent.com/adamliter/conf/master/bootstrap.sh | bash -v

bootstrap.sh

This section defines a bootstrap script for installing Homebrew, Emacs, Doom Emacs, and a variety of other things.

That script is written to this repository when this file is tangled. The output of the tangling is not ignored by version control even though it is a derived file because tracking it allows a curl-able version of the file to exist on GitHub for bootstrapping the setup of a new machine.

The first thing the script does is set some flags for exiting and debugging:

# -*- coding: utf-8; mode: sh; -*-
# Exit when a command fails
set -o errexit
# Exit when a command in a series of pipes fails
set -o pipefail
# Exit when there is an undeclared variable
set -o nounset
# Trace what gets executed (for debugging)
#set -o xtrace

Let’s run the rest of the script from the home directory:

cd "${HOME}"

Next, let’s have the script detect the operating system, including whether it’s a Mac with an Intel chip or an Apple silicon chip.

if [[ $OSTYPE == darwin* ]]; then
    BASH_OS_TYPE='macOS'
elif [[ $OSTYPE == linux-gnu ]]; then
    BASH_OS_TYPE='Linux'
    echo "This bootstrapping script does not currently support Linux ..."
    exit 1
elif [[ '$OS' == Windows* ]]; then
    BASH_OS_TYPE='Windows'
    echo "This bootstrapping script does not currently support Windows ..."
    exit 1
else
    BASH_OS_TYPE='Unknown'
    echo "Unknown operating system ..."
    exit 1
fi

if [[ $BASH_OS_TYPE == 'macOS' ]]; then
    if [[ $(uname -m) == arm* ]]; then
        MAC_OS_TYPE='apple-silicon'
    elif [[ $(uname -m) == x86_64 ]]; then
        MAC_OS_TYPE='intel'
    else
        MAC_OS_TYPE='Unknown'
    fi
fi

Homebrew

Let’s install Homebrew as a package manager.

if [[ $BASH_OS_TYPE == macOS ]]; then
    if type brew >/dev/null 2>&1; then
        echo "Homebrew is already installed ..."
    else
        echo "Installing Homebrew ..."
        /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
        echo "Homebrew was successfully installed ..."
        if [[ $MAC_OS_TYPE == 'apple-silicon' ]]; then
            echo "Temporarily adding Homebrew to PATH for Apple Silicon Mac ..."
            eval $(/opt/homebrew/bin/brew shellenv)
        fi
        echo "Tapping ralwaycat/emacsport ..."
        brew tap railwaycat/emacsmacport
    fi
fi

${HOME}/conf

Next, the script clones the repository that contains my configuration files into ${HOME}/conf. If that directory already exists, the git clone command will fail, so I remove it first just to be cautious, but this should be unnecessary if this is a new machine.

If this is not a new machine, the command rm -rf "${HOME}/conf" will remove the file ~/.ssh/config, since that file is a symlink that points inside of the git repository. This will cause the bootstrap.sh script to fail since the submodules in the repository make use of the SSH hosts defined in the SSH config file. Thus, in order to ensure that this bootstrap.sh script can also be run on a machine that is already setup (to, for example, reset how everything is configured or apply new changes), we want to ensure that those SSH hosts still exist when this script tries to clone the repo and its submodules.

if [ -f "${HOME}/.ssh/config" ]; then
    cp -H "${HOME}/.ssh/config" "${HOME}/.ssh/config.temp"
    rm "${HOME}/.ssh/config"
    mv "${HOME}/.ssh/config.temp" "${HOME}/.ssh/config"
fi
if [ -d "${HOME}/conf" ]; then
    echo "~/conf already exists; backing it up to ~/conf.bkp ..."
    cp -r "${HOME}/conf" "${HOME}/conf.bkp"
fi
rm -rf "${HOME}/conf"
git clone github:adamliter/conf.git "${HOME}/conf"

After cloning, it updates all submodules. Submodules, as always, are a bit tricky. git submodule update --init --recursive will recursively initialize and update all submodules in the git repo. Moreover, with the --remote flag, any submodules that are specified to track a branch on the remote will be fast-forwarded to the most recent commit on that branch on the remote, regardless of the status of the submodule in the parent repo. Furthermore, since submodules are always checked out in a detached HEAD state, the script also checks out either the branch that the submodule is set up to track on the remote or the main branch for all submodules.

cd "${HOME}/conf"
git submodule update --init --remote --recursive

git submodule foreach --recursive \
  'git checkout \
  $(git config -f $toplevel/.gitmodules submodule.$name.branch || \
  echo main)'

cd "${HOME}"

XCode command line tools

if [[ $BASH_OS_TYPE == macOS ]]; then
    if xcode-select -p >/dev/null 2>&1; then
        echo "XCode command line tools are already installed ..."
    else
        echo "Installing XCode command line tools ..."
        xcode-select --install
    fi
fi

Emacs

if [[ $BASH_OS_TYPE == macOS ]]; then
    if ([[ $MAC_OS_TYPE == 'apple-silicon' ]] && [ -f /opt/homebrew/bin/emacs ]) \
        || ([[ $MAC_OS_TYPE == 'intel' ]] && [ -f /usr/local/bin/emacs ]); then
       echo "Emacs was already installed with Homebrew ..."
    else
        echo "Installing Emacs ..."
        brew install emacs-mac  --with-emacs-big-sur-icon --with-imagemagick \
            --with-natural-title-bar --with-native-compilation \
            --with-mac-metal --with-unlimited-select --with-tree-sitter
    fi
fi

Doom Emacs

First, let’s symlink .doom.d into place:

rm -rf "${HOME}/.doom.d"
ln -sn "${HOME}/conf/doom.d" "${HOME}/.doom.d"

Next, let’s install the dependencies for Doom Emacs:

if ~/.emacs.d/bin/doom >/dev/null 2>&1; then
    echo "Doom Emacs is arleady installed ..."
else
    echo "Installing dependencies for Doom Emacs ..."
    if [[ $BASH_OS_TYPE == macOS ]]; then
        brew install git ripgrep
    fi
    echo "Installing optional dependencies for Doom Emacs ..."
    if [[ $BASH_OS_TYPE == macOS ]]; then
        brew install coreutils fd
    fi
    echo "Cloning the doomemacs repository ..."
    git clone https://github.com/doomemacs/doomemacs ~/.emacs.d
    echo "Installing Doom Emacs ..."
    ~/.emacs.d/bin/doom install
fi

Tangle away

Next, the script evaluates all source code blocks in the file ${HOME}/conf/README.org where :eval yes as well as tangling the file in order to put all other configuration information in the proper locations.

emacs --batch \
  --eval="(progn
  (require 'org)
  (setq org-confirm-babel-evaluate nil)
  (find-file \"~/conf/README.org\")
  (org-babel-tangle)
  (org-babel-execute-buffer)
  (kill-buffer))"

Symlinks

Finally, the script sources a separate symlink.sh which symlinks most things into place (the exceptions are that bootstrap.sh does the symlinking for the submodules of this repository). The symlinking is separated out into its own script so that I can just run the symlink.sh script on a Linux machine where I don’t want to install anything, but I do want, for example, my Bash configuration set up in the same way that it is set up on my personal machine. The use case for this is on the Machine Learning Nodes.

. "${HOME}/conf/symlink.sh"

Command line utilities

This section of this org document both installs the relevant command line utility (if it is not already installed) and creates the appropriate configuration files for that utility, if necessary. Even though all of the configuration files are derived files, they are all kept under version control and symlinked into the appropriate locations. Doing so allows me to more readily notice any external programs or utilities that change my configuration files, as it will lead to a dirty working tree in git.

bash

Installation

The version of bash that ships on macOS is pretty outdated, so let’s install a more recent version via Homebrew. In order to use this newer version of bash as the login shell, it needs to be added to the file /etc/shells. Then, the shell can be changed to the new bash version for the current user. In order for this to take effect, I log back in.

if [[ $BASH_OS_TYPE == macOS ]]; then
    brew install bash
    if ([[ $MAC_OS_TYPE == 'apple-silicon' ]] && ! grep -q "/opt/homebrew/bin/bash" /etc/shells) \
        || ([[ $MAC_OS_TYPE == 'intel' ]] && ! grep -q "/usr/local/bin/bash" /etc/shells); then
        echo "Adding Homebrew's bash to possible login shells ..."
        if [[ $MAC_OS_TYPE == 'apple-silicon' ]]; then
            sudo bash -c "echo /opt/homebrew/bin/bash >> /etc/shells"
        fi
        if [[ $MAC_OS_TYPE == 'intel' ]]; then
            sudo bash -c "echo /usr/local/bin/bash >> /etc/shells"
        fi
    else
        echo "Homebrew's bash is already a possible login shell ..."
    fi
    if ([[ $MAC_OS_TYPE == 'apple-silicon' ]] && [ $SHELL == "/opt/homebrew/bin/bash" ]) \
        || ([[ $MAC_OS_TYPE == 'intel' ]] && [ $SHELL == "/usr/local/bin/bash" ]); then
        echo "Shell is already set to Homebrew's bash ..."
    else
        echo "Setting shell to Homebrew's bash ..."
        if [[ $MAC_OS_TYPE == 'apple-silicon' ]]; then
            chsh -s /opt/homebrew/bin/bash
        fi
        if [[ $MAC_OS_TYPE == 'intel' ]]; then
            chsh -s /usr/local/bin/bash
        fi
    fi
fi

Configuration

References:

~/.bash_profile

Login shells (e.g. a shell that you start from a non-graphical desktop environment, like when logging into a machine via SSH) read one of three files (assuming your shell is bash):

  1. ~/.bash_profile
  2. ~/.bash_login
  3. ~/.profile

Whichever file is found first is the one that gets read, and the shell stops looking for the others. Furthermore, login shells do not read ~/.bashrc, but the best practice is to have an interactive login shell read ~/.bashrc. Ensuring that this happens is done by adding the following to the ~/.bash_profile file:

# -*- mode: sh; fill-column: 72; coding: utf-8 -*-
if [ -f "${HOME}/.bashrc" ] && [[ $- == *i* ]]; then
    source "${HOME}/.bashrc"
fi

It’s worth noting that on macOS, unlike on Linux, all shells started from Terminal.app (or iTerm.app) in a graphical environment are started as login shells and thus read ~/.bash_profile (instead of ~/.bashrc, which is what is read when starting Terminal in a graphical desktop environment on Linux, since it is a non-login shell). Thus, if you want anything in your ~/.bashrc to be read when using macOS, you certainly need to make sure that ~/.bash_profile sources ~/.bashrc.

At any rate, this can now be symlinked into the appropriate location, after it is tangled:

ln -sf "${HOME}/conf/bash/bash_profile" "${HOME}/.bash_profile"

~/.bashrc

In the ~/.bashrc file, I want to ensure that the system-wide bashrc file is read, if it exists. On macOS, this usually exists as /etc/bashrc.

if [ -f /etc/bashrc ]; then
    source /etc/bashrc
fi

And, on Ubuntu, this usually exists as /etc/bash.bashrc.

if [ -f /etc/bash.bashrc ]; then
    source /etc/bash.bashrc
fi

While it is not considered best practice to source ~/.profile from inside of ~/.bashrc (in particular, see Gilles’s answer to Difference between .bashrc and .bash_profile), I’m going to go ahead and do this anyway because it makes life easier, and I have yet to encounter any problems because of it. The recommended best practice is to source ~/.basrhc and ~/.profile from ~/.bash_profile, in that order. However, for the reasons mentioned above when discussing macOS shells started in the graphical desktop environment, most shells started in a graphical desktop environment will only read ~/.bashrc because they are non-login shells. However, this means that environment variables that are set in ~/.profile will not be available in these shells. So I’ll flout the best practice for now, until I run into problems because of it.

if [ -f "${HOME}/.profile" ]; then
    source "${HOME}/.profile"
fi
Aliases

Sometimes you just need to shrug:

alias eh="echo ¯\\\_\(ツ\)_/¯ | pbcopy"
alias ehh="eh"

Some aliases for changing directories:

alias .1='cd ..'
alias ..='cd ..'
alias .2='cd ../..'
alias ....='cd ../..'
alias .3='cd ../../..'
alias .4='cd ../../../..'
alias .5='cd ../../../../..'

List all the things:

alias l='ls -aF'
alias ll='ls -alF'

# list only hidden directories and files
alias l.='ls -dF .*'
alias ll.'=ls -ldF .*'

To ensure the availability of 256 colors in tmux (see this answer to lose vim colorscheme in tmux mode).

alias tmux='tmux -2'

Some macOS-specific aliases:

if [[ $OSTYPE == darwin* ]]; then
    alias showFiles='defaults write com.apple.finder AppleShowAllFiles \
YES; killall Finder'
    alias hideFiles='defaults write com.apple.finder AppleShowAllFiles NO; \
killall Finder'
fi

An SSH alias for ssh-add:

alias sshid='ssh-add ~/.ssh/id_rsa'

Some aliases for pass:

alias ppass='PASSWORD_STORE_DIR=~/.password-store/personal/ pass'
alias pp='ppass'

# lingbib password store
alias lb-pass='PASSWORD_STORE_DIR=~/.password-store/shared-projects\
/lingbib/ pass'

# common logins
alias amazon='pp -c misc/amazon'
alias amex='pp -c finances/amex'
alias bb='pp -c misc/bitbucket'
alias chess='pp -c misc/chess'
alias dl='pp -c travel/delta'
alias fmail='pp -c email/fastmail/password'
alias kb='pp -c keybase/passphrase'
alias msufcu='pp -c finances/msufcu'

Some aliases for git and hub:

if type hub >/dev/null 2>&1; then
    alias git='hub'
fi
alias g='git status -sb'
alias gp='git pull'
alias gpr='git pull --rebase'
alias gpp='git pull --rebase && git push'
alias ga='git add'
alias gc='git commit'
alias gcn='git commit --no-edit'
alias gce='git commit -e'
alias gces='git commit -eS'
alias gca='git commit --amend'
alias gcah='git commit --amend -C HEAD'
alias gcv='git commit --no-verify'
alias gdv='git diff'
alias gdc='git diff --cached'
alias gl='git log --oneline --decorate --graph'
alias gla='git log --oneline --decorate --graph --all'
alias gt='git tag'
alias grc='git rebase --continue'
alias gsl='git stash list'
alias gss='git stash save'

And an alias for kubectl:

if command -v kubectl 1>/dev/null 2>&1; then
    alias k='kubectl'
fi
Auto completion

Auto completion for things installed with Homebrew:

if [ -d /usr/local/etc/bash_completion.d ]; then
    for f in /usr/local/etc/bash_completion.d/*; do
        . "${f}"
    done
fi
if [ -d /opt/homebrew/etc/bash_completion.d ]; then
    for f in /opt/homebrew/etc/bash_completion.d/*; do
        . "${f}"
    done
fi

Tab auto completion for pass:

if [ -f /usr/local/etc/bash_completion.d/pass ]; then
    source /usr/local/etc/bash_completion.d/pass
fi
# personal completion
_ppass(){
    PASSWORD_STORE_DIR=~/.password-store/personal/ _pass
}

complete -o filenames -o nospace -F _ppass ppass

_pp(){
    _ppass
}

complete -o filenames -o nospace -F _pp pp

# lingbib completion
_lb-pass(){
    PASSWORD_STORE_DIR=~/.password-store/shared-projects/lingbib/ _pass
}

complete -o filenames -o nospace -F _lb-pass lb-pass

Auto completion for kubectl and alias.

if command -v pyenv 1>/dev/null 2>&1; then
    # Only needed if autcompletion isn't already in Hombrew bash completion dir
    #source <(kubectl completion bash)
    complete -o default -F __start_kubectl k
fi
Prompt

First, let’s set up some more useful ways to refer to colors:

RED="\[\e[31m\]"
LIGHT_RED="\[\e[91m\]"
GREEN="\[\e[32m\]"
LIGHT_GREEN="\[\e[92m\]"
YELLOW="\[\e[33m\]"
LIGHT_YELLOW="\[\e[93m\]"
BLUE="\[\e[34m\]"
LIGHT_BLUE="\[\e[94m\]"
MAGENTA="\[\e[35m\]"
LIGHT_MAGENTA="\[\e[95m\]"
CYAN="\[\e[36m\]"
LIGHT_CYAN="\[\e[96m\]"
LIGHT_GREY="\[\e[37m\]"
LIGHT_GRAY="\[\e[37m\]"
WHITE="\[\e[97m\]"
COLOR_RESET="\[\e[0m\]"

Next, let’s define a separator to separate information in the prompt:

MY_PS1_SEP=" ${WHITE}${COLOR_RESET} "

Next, let’s write a function to determine if the current directory is a git repo:

function is_git_repository {
    git branch > /dev/null 2>&1
}

If it is, we’ll want to determine some information about it:

function set_git_branch {
    # Capture the output of the "git status" command.
    git_status="$(git status 2> /dev/null)"

    # Set color based on clean/staged/dirty
    clean_pattern="working (tree|directory) clean"
    if [[ ${git_status} =~ ${clean_pattern} ]]; then
        state="${LIGHT_GREEN}"
    elif [[ ${git_status} =~ "Changes to be committed" ]]; then
        state="${LIGHT_YELLOW}"
    else
        state="${RED}"
    fi

    # Set arrow icon based on status against remote.
    remote_pattern="(# )?Your branch is (ahead of|behind)"
    if [[ ${git_status} =~ ${remote_pattern} ]]; then
        if [[ ${BASH_REMATCH[2]} == "ahead of" ]]; then
            remote=""
        else
            remote=""
        fi
    else
        remote=""
    fi
    diverge_pattern="(# )?Your branch and (.*) have diverged"
    if [[ ${git_status} =~ ${diverge_pattern} ]]; then
        remote=""
    fi

    # Get the name of the branch.
    branch_pattern="^(# )?On branch ([^${IFS}]*)"
    detached_head_pattern="HEAD detached from"
    if [[ ${git_status} =~ ${branch_pattern} ]]; then
        branch=${BASH_REMATCH[2]}
    elif [[ ${git_status} =~ ${detached_head_pattern} ]]; then
        branch="HEAD"
    fi

    # Set the final branch string.
    BRANCH="${MY_PS1_SEP}${state}(${branch})${remote}${COLOR_RESET}"
}

Additionally, if this is also a Python virtual environment, we’ll want to add some information about that to the prompt:

function set_virtualenv () {
    if test -z "${VIRTUAL_ENV}" && test -z "${CONDA_DEFAULT_ENV}"; then
        MY_VENV=""
    else
        if test -z "${VIRTUAL_ENV}"; then
            MY_VENV="${LIGHT_GREY}[${CONDA_DEFAULT_ENV}]${COLOR_REST}\
${MY_PS1_SEP}"
        else
            MY_VENV="${LIGHT_GREY}[${VIRTUAL_ENV##*/}]${COLOR_RESET}\
${MY_PS1_SEP}"
        fi
    fi
}

We can also change the color of the prompt symbol, based on the exit code of the last command. Here’s a function to get and set that information:

function set_prompt_symbol () {
    if test $1 -eq 0 ; then
        PROMPT_SYMBOL="\$"
    else
        PROMPT_SYMBOL="${RED}\$${COLOR_RESET}"
    fi
}

I’d also like to shorten the path to the current working directory in the prompt if there isn’t enough room to display it in the shell. In order to do this, I need to first compute the prompt minus the working directory in order to determine the number of remaining columns that I have left to work with:

strip_color () {
    COLOR_REGEX='s/\\\[\\e\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]\\\]//g'
    if [[ $OSTYPE == darwin* ]]; then
        sed -Ee $COLOR_REGEX <<< """$1"""
    else
        sed -re $COLOR_REGEX <<< """$1"""
    fi
}

get_ps1_less_pwd () {
    PS1_LESS_PWD=$(printf "%s%s%s%s" \
                          "$(strip_color "${MY_VENV}")" \
                          "$(whoami)@$(hostname -s)" \
                          "$(strip_color "${MY_PS1_SEP}")" \
                          "$(strip_color "${BRANCH}")")
}

Now I can finally declare the function to actually compute and calculate the bash prompt:

function set_bash_prompt () {
    # Set the PROMPT_SYMBOL variable. We do this first so we don't lose the
    # return value of the last command.
    set_prompt_symbol $?

    # Get virtualenv info
    set_virtualenv

    # Set the BRANCH variable.
    if is_git_repository ; then
        set_git_branch
    else
        BRANCH=''
    fi

    # get PS1_LESS_PWD to calculate length remaining
    get_ps1_less_pwd

    # get truncated PWD
    # loosely based on http://stackoverflow.com/a/26555347/2571049
    MY_PWD=$(pwd | awk -F/ -v "u=$PS1_LESS_PWD" -v "n=$(tput cols)" \
                       -v "h=^$HOME" \
                       '{sub(h,"~"); u=length(u); n=n-u-1; b=$1} \
                       length($0)<=n || NF==2 {print; next;} \
                       NF>2 {b=b"/.../"; e=$NF; n-=length(b $NF); \
                       for (i=NF-1; i>2 && n>length(e $i)+1; i--) e=$i"/"e;} {print b e;}')

    # Set the bash prompt variable.
    PS1="
${MY_VENV}\
${WHITE}\u${COLOR_RESET}\
${LIGHT_GREEN}@${COLOR_RESET}\
${LIGHT_MAGENTA}\h${COLOR_RESET}\
${MY_PS1_SEP}\
${LIGHT_CYAN}${MY_PWD}${COLOR_RESET}\
${BRANCH}
${PROMPT_SYMBOL} "
}

And, finally, we can actually call the function to set the prompt:

PROMPT_COMMAND=set_bash_prompt
Colors

See How can I configure Mac Terminal to have color ls output?

export CLICOLOR=1
export LSCOLORS=gxBxhxDxfxhxhxhxhxcxcx
Direnv
eval "$(direnv hook bash)"
Some Python stuff

Note that eval "$(pyenv virtualenv-init -)" needs to come after setting PROMPT_COMMAND in order to work correctly.

if command -v pyenv 1>/dev/null 2>&1; then
    eval "$(pyenv init -)"
fi

if command -v pyenv-virtualenv-init 1>/dev/null 2>&1; then
    eval "$(pyenv virtualenv-init -)"
fi

gpip2(){
    PIP_REQUIRE_VIRTUALENV="" pip2 "$@"
}

gpip3(){
    PIP_REQUIRE_VIRTUALENV="" pip3 "$@"
}

gpip(){
    PIP_REQUIRE_VIRTUALENV="" pip "$@"
}

Finally, ~/.bashrc can be symlinked into the appropriate location, after it is tangled:

ln -sf "${HOME}/conf/bash/bashrc" "${HOME}/.bashrc"
Some Ruby stuff
if command -v rbenv 1>/dev/null 2>&1; then
    eval "$(rbenv init -)"
fi
Symlinking into place

Finally, ~/.bashrc can be symlinked into the appropriate location, after it is tangled:

ln -sf "${HOME}/conf/bash/bashrc" "${HOME}/.bashrc"

~/.profile

~/.profile is where stuff that is not bash-specifc goes, such as environment variables.

# -*- mode: sh; fill-column: 72; coding: utf-8 -*-
if [[ $OSTYPE == darwin* ]] && [[ $(uname -m) == arm64 ]]; then
    eval $(/opt/homebrew/bin/brew shellenv)
fi
if [[ ":${PATH}:" != *":${HOME}/bin:"* ]] && [ -d "${HOME}/bin" ]; then
    export PATH="${HOME}/bin:${PATH}"
fi
if [[ ":${PATH}:" != *":${HOME}/.emacs.d/bin:"* ]] && [ -d "${HOME}/.emacs.d/bin" ]; then
    export PATH="${HOME}/.emacs.d/bin:${PATH}"
fi

# ----------------------------------------------------------------------
# EDITOR
# ----------------------------------------------------------------------
if [ -f "${HOME}/bin/ec" ]; then
    export EDITOR=ec
else
    if [ -f /usr/local/bin/emacs ]; then
        export EDITOR=/usr/local/bin/emacs
    elif [ -f /opt/homebrew/bin/emacs ]; then
         export EDITOR=/opt/homebrew/bin/emacs
    else
        export EDITOR=emacs
    fi
fi
export ALTERNATE_EDITOR=""

# ----------------------------------------------------------------------
# Node stuff
# ----------------------------------------------------------------------
if command -v npm 1>/dev/null 2>&1; then
    export NODE_PATH=$(npm root -g)
fi

# ----------------------------------------------------------------------
# Python stuff
# ----------------------------------------------------------------------
if [ -d "$HOME/.pyenv" ]; then
    export PYENV_ROOT="$HOME/.pyenv"
    export PATH="$PYENV_ROOT/bin:$PATH"
    if command -v pyenv 1>/dev/null 2>&1; then
        eval "$(pyenv init --path)"
        export PYENV_VIRTUALENV_VERBOSE_ACTIVATE=1
    fi
fi
export VIRTUAL_ENV_DISABLE_PROMPT=1

# ----------------------------------------------------------------------
# Rust stuff
# ----------------------------------------------------------------------
if [ -f "${HOME}/.cargo/env" ]; then
    source "${HOME}/.cargo/env"
fi

Finally, ~/.profile can be symlinked into the appropriate location, after it is tangled:

ln -sf "${HOME}/conf/bash/profile" "${HOME}/.profile"

cmake

CMake is needed in order to compile vterm for use inside Emacs.

Installation

brew install cmake

coreutils

Installation

coreutils is already installed in the bootstrapping process as an optional dependency for Doom Emacs.

direnv

Installation

brew install direnv

Configuration

dvc

Installation

brew install dvc

editorconfig

Installation

brew install editorconfig

fd

Installation

fd is already installed in the bootstrapping process as an optional dependency for Doom Emacs.

git

Installation

git is already installed in the bootstrapping process as a dependency for Doom Emacs.

Configuration

~/.gitconfig

[init]
# -*- mode: gitconfig; coding: utf-8 -*-
[init]
    defaultBranch = main
[user]

git needs to know who I am.

[user]
    name = Adam Liter
    email = [email protected]
    signkey = 0x98723A2089026CD6
[core]

Set up my editor for git and a global ignore file.

[core]
    editor = "emacsclient -t -a=''"
    excludesfile = ~/.gitignore_global
    attributesfile = ~/.gitattributes_global
    pager = delta
[interactive]
[interactive]
    diffFilter = delta --color-only
[delta]
[delta]
    navigate = true
    light = true
    features = line-numbers
    side-by-side = false
[delta "magit-delta"]
    line-numbers = false
[merge]
[merge]
    conflictstyle = diff3
[color]

This sets up some defaults for displaying color with git.

[color]
    diff = auto
    status = auto
    branch = auto
    interactive = auto
    ui = true
    pager = true
[alias]

This sets up an alias for automatically pushing submodules.

[alias]
    pushall = push --recurse-submodule=on-demand
[diff]

The following sets up a diff driver called pandoc for diffing Word documents that git is tracking. For reference, see e.g., Using Microsoft Word with git.

[diff]
    colorMoved = default
[diff "pandoc"]
    textconv=pandoc --to=markdown
    prompt = false
[filter]

The following sets up a filter driver called lfs for using Git LFS.

[filter "lfs"]
    clean = git-lfs clean -- %f
    smudge = git-lfs smudge -- %f
    process = git-lfs filter-process
    required = true
[push]

The following sets the default behavior of git push such that it only pushes the current branch to the remote repo. For further discussion, see either of the following questions on Stack Overflow:

[push]
    default = simple
[pull]

git pull should rebase by default. In versions of git older than 1.8.5, this can be achieved by setting the configuration option pull.rebase to true. In git 1.8.5 and more recent versions, it became possible to set the configuration option pull.rebase to preserve (see here). This is better because it runs git pull --preserve-merges instead of git pull --rebase. The use case for this is that if you are working locally and do a non-fast-forward merge of your feature branch into the master branch but then need to pull in changes from the upstream master branch before being able to push, the git pull --rebase would flatten the non-fast-forward merge that you just did, whereas git pull --preserve-merges will preserve that merge commit.

However, in git 2.22.0, the option of setting =pull.rebase= to preserve was deprecated in favor of setting pull.rebase to merges in order to preserve merge commits. This runs git rebase --rebase-merges behind the scenes.

[pull]
    rebase = merges
[gpg]

For gpg stuff with git, we want to use gpg2, which is now just gpg, at least if installed with Homebrew.

[gpg]
    program = gpg
Configuration for =forge=

This sets up my user names on the git forges, GitHub and GitLab, for use with =forge=.

[gitlab]
    user = adamliter
[github]
    user = adamliter
Symlink into place

Finally, the gitconfig file needs to be symlinked into the proper location.

ln -sf "${HOME}/conf/git/gitconfig" "${HOME}/.gitconfig"

~/.gitignore_global

A good reference for all sorts of patterns that git ought to ignore is =github/gitingore=.

The following things are things that I have git ignore by default globally.

macOS

Some stuff to ignore on macOS, taken from =github/gitignore=. However, I haven’t added the Icon ignore pattern because it needs to end with a carriage return, and I have Emacs set up to trim trailing white space. I’d rather not disable that for this document just to be able to add this ignore pattern, since it is a pretty uncommon pattern and largely only occurs in the top-level directories of the folders associated with services like Dropbox or Google Drive (I don’t generally change/set a directory’s icon).

# -*- mode: gitignore; coding: utf-8 -*-
*.DS_Store
.AppleDouble
.LSOverride

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
Linux

The following is stuff to ignore on Linux, taken from =github/gitignore=.

# temporary files which can be created if a
# process still has a handle open of a deleted file
.fuse_hidden*

# KDE directory preferences
.directory

# Linux trash folder which might appear on any partition or disk
.Trash-*

# .nfs files are created when an open file
# is removed but is still being accessed
.nfs*
Windows

The following is stuff to ignore in Windows, taken from =github/gitingore=.

# Windows image file caches
Thumbs.db
ehthumbs.db

# Dump file
*.stackdump

# Folder config file
Desktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msm
*.msp

# Windows shortcuts
*.lnk
Emacs

The following is Emacs stuff to ignore, taken from =github/gitignore=.

*~
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
*.elc
auto-save-list
tramp
.\#*

# Org-mode
.org-id-locations
*_archive

# flymake-mode
*_flymake.*

# eshell files
**/eshell/history
**/eshell/lastdir

# elpa packages
/elpa/

# reftex files
*.rel

# AUCTeX auto folder
**/auto/

# cask packages
.cask/
dist/

# Flycheck
flycheck_*.el

# server auth directory
/server/

# projectiles files
.projectile

# directory configuration
.dir-locals.el
TeX

The following is stuff to ignore for (La)TeX, taken from =github/gitignore=.

## Core latex/pdflatex auxiliary files:
*.aux
*.lof
*.log
*.lot
*.fls
*.out
*.toc
*.fmt
*.fot
*.cb
*.cb2

## Intermediate documents:
*.dvi
*-converted-to.*
# these rules might exclude image files for figures etc.
# *.ps
# *.eps
# *.pdf

## Generated if empty string is given at "Please type another file name for output:"
.pdf

## Bibliography auxiliary files (bibtex/biblatex/biber):
*.bbl
*.bcf
*.blg
*-blx.aux
*-blx.bib
*.brf
*.run.xml

## Build tool auxiliary files:
*.fdb_latexmk
*.synctex
*.synctex(busy)
*.synctex.gz
*.synctex.gz(busy)
*.pdfsync

## Auxiliary and intermediate files from other packages:
# algorithms
*.alg
*.loa

# achemso
acs-*.bib

# amsthm
*.thm

# beamer
*.nav
*.snm
*.vrb

# changes
*.soc

# cprotect
*.cpt

# elsarticle
*.spl

# endnotes
*.ent

# fixme
*.lox

# feynmf/feynmp
*.mf
*.mp
*.t[1-9]
*.t[1-9][0-9]
*.tfm

#(r)(e)ledmac/(r)(e)ledpar
*.end
*.?end
*.[1-9]
*.[1-9][0-9]
*.[1-9][0-9][0-9]
*.[1-9]R
*.[1-9][0-9]R
*.[1-9][0-9][0-9]R
*.eledsec[1-9]
*.eledsec[1-9]R
*.eledsec[1-9][0-9]
*.eledsec[1-9][0-9]R
*.eledsec[1-9][0-9][0-9]
*.eledsec[1-9][0-9][0-9]R

# glossaries
*.acn
*.acr
*.glg
*.glo
*.gls
*.glsdefs

# gnuplottex
*-gnuplottex-*

# gregoriotex
*.gaux
*.gtex

# hyperref
*.brf

# knitr
*-concordance.tex
# TODO Comment the next line if you want to keep your tikz graphics files
*.tikz
*-tikzDictionary

# listings
*.lol

# makeidx
*.idx
*.ilg
*.ind
*.ist

# minitoc
*.maf
*.mlf
*.mlt
*.mtc[0-9]*
*.slf[0-9]*
*.slt[0-9]*
*.stc[0-9]*

# minted
_minted*
*.pyg

# morewrites
*.mw

# nomencl
*.nlo

# pax
*.pax

# pdfpcnotes
*.pdfpc

# sagetex
*.sagetex.sage
*.sagetex.py
*.sagetex.scmd

# scrwfile
*.wrt

# sympy
*.sout
*.sympy
sympy-plots-for-*.tex/

# pdfcomment
*.upa
*.upb

# pythontex
*.pytxcode
pythontex-files-*/

# thmtools
*.loe

# TikZ & PGF
*.dpth
*.md5
*.auxlock

# todonotes
*.tdo

# easy-todo
*.lod

# xindy
*.xdy

# xypic precompiled matrices
*.xyc

# endfloat
*.ttt
*.fff

# Latexian
TSWLatexianTemp*

## Editors:
# WinEdt
*.bak
*.sav

# Texpad
.texpadtmp

# Kile
*.backup

# KBibTeX
*~[0-9]*

# auto folder when using emacs and auctex
/auto/*
Python

The following is stuff to ignore for Python, taken from =github/gitignore=.

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# virtualenv
.env
.venv/
venv/
ENV/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
R

The following is stuff to ignore for R, taken from =github/gitignore=.

# History files
.Rhistory
.Rapp.history

# Session Data files
.RData

# Example code in package build process
*-Ex.R

# Output files from R CMD build
/*.tar.gz

# Output files from R CMD check
/*.Rcheck/

# RStudio files
.Rproj.user/

# produced vignettes
vignettes/*.html
vignettes/*.pdf

# OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3
.httr-oauth

# knitr and R markdown default cache directories
/*_cache/
/cache/

# Temporary files created by R markdown
*.utf8.md
*.knit.md
Symlink into place

Finally, the gitignore_global file needs to be symlinked into the proper location.

ln -sf "${HOME}/conf/git/gitignore_global" "${HOME}/.gitignore_global"

~/.gitattributes_global

This sets attribtues globally for Word documents so that I can diff Word documents using the pandoc driver. See the =diff= section above.

# -*- mode: gitattributes; coding: utf-8 -*-
*.docx diff=pandoc
*.doc  diff=pandoc

Finally, the gitattributes_global file needs to be symlinked into the proper location.

ln -sf "${HOME}/conf/git/gitattributes_global" "${HOME}/.gitattributes_global"

git-delta

Installation

brew install git-delta

Configuration

The main behavior is configured in ~/.gitconfig above. See the manual for configuration options and information.

git-lfs

Installation

brew install git-lfs

glow

Installation

brew install glow

gpg

Installation

brew install gnupg

Configuration

Some useful resources:

helm

Installation

brew install helm

htop

Installation

brew install htop

Configuration

Nothing for now.

# -*- mode: conf-unix; coding: utf-8; -*-

Symlink it into place:

mkdir -p ~/.config/htop
ln -sf "${HOME}/conf/htop/htoprc" "${HOME}/.config/htop/htoprc"

hub

Installation

brew install hub

Configuration

jq

Installation

brew install jq

kubernetes-cli

Installation

brew install kubernetes-cli

lab

Installation

brew install lab

Configuration

# -*- mode: conf-toml; coding: utf-8; -*-
[core]
  host = "https://gitlab.com"
  load_token = # TODO: set up load_token with pass
  user = "adam.liter"

Symlink it into place:

mkdir -p ~/.config/lab
ln -sf "${HOME}/conf/lab/lab.toml" "${HOME}/.config/lab/lab.toml"

minikube

Installation

brew install minikube

pandoc

Installation

brew install pandoc

Configuration

There is no configuration setup for pandoc.

pass

Installation

brew install pass

Config

No current configuration for pass.

pinentry-mac

Installation

brew install pinentry-mac

Let’s set it up so that the password is not saved in the macOS Keychain (and so that this option isn’t even displayed).

defaults write org.gpgtools.common UseKeychain NO
defaults write org.gpgtools.common DisableKeychain -bool yes

Configuration

To use pinentry-mac, the following line needs to be set in the file ~/.gnupg/gpg-agent.conf:

pinentry-program $HOMEBREW_PREFIX/bin/pinentry-mac

This is done above in the section for configuring gpg.

pre-commit

Installation

brew install pre-commit

reattach-to-user-namespace

This allows for accessing the clipboard from inside of tmux sessions on macOS. See the GitHub repository for more info.

Installation

brew install reattach-to-user-namespace

ripgrep

Installation

ripgrep is installed in the bootstrapping process as a dependency for Doom Emacs.

ruff

Installation

brew install ruff

ssh

Installation

ssh is already installed on both macOS and Linux, by default.

Configuration

My SSH configuration is kept in a submodule hosted by my private git server so as to keep the details of my SSH configuration private. The following code, which is executed when this file is tangled, will create my SSH config and then symlink it into the appropriate location.

(org-babel-tangle-file "~/conf/ssh/README.org")
ln -sf "${HOME}/conf/ssh/config" "${HOME}/.ssh/config"

tmux

Installation

Install tmux:

brew install tmux

Configuration

To ensure that colors work properly, I’ve followed the suggestion in this answer on Stack Overflow.

# -*- coding: utf-8; mode: conf-unix; fill-column: 72 -*-
set-option -g default-terminal "xterm-256color"

The following ensures that the macOS pasteboard is available in tmux sessions. See the Github repository for more information.

set-option -g default-command "reattach-to-user-namespace -l $SHELL"

The following allows the tmux configuration file to be reloaded.

bind-key r source-file ~/.tmux.conf

The following are some key bindings for opening new SSH sessions in either a new windows, a vertically split window, or a horizontally split window.

bind-key S   command-prompt -p "host" "new-window -n %1 'ssh %1'"
bind-key C-S command-prompt -p "host" "split-window -v 'ssh %1'"
bind-key M-S command-prompt -p "host" "split-window -h 'ssh %1'"

The following are some key bindings for opening Emacs in either a new window, a vertically split window, or a horizontally split window.

bind-key y   new-window -n "emacs"  "emacsclient -nw"
bind-key C-y split-window -v "emacsclient -nw"
bind-key M-y split-window -h "emacsclient -nw"

The following defines some more intuitive key bindings for splitting a window and undefines the default key bindings for this.

bind-key | split-window -h
bind-key - split-window -v
unbind '"'
unbind %

The following allows for switching between tmux panes using just M-<arrow>, without the tmux prefix key.

bind-key -n M-Left select-pane -L
bind-key -n M-Right select-pane -R
bind-key -n M-Up select-pane -U
bind-key -n M-Down select-pane -D

And, finally, the following symlinks the configuration file into the appropriate location.

ln -sf "${HOME}/conf/tmux/tmux.conf" "${HOME}/.tmux.conf"

trivy

Installation

brew install trivy

wget

Installation

wget is not installed by default on macOS:

brew install wget

yq

Installation

brew install yq

Programming languages

NodeJS

node

Installation

brew install node

Configuration

Nothing for now.

# -*- mode: conf-unix; coding: utf-8; -*-

Symlink it into place:

ln -sf "${HOME}/conf/npm/npmrc" "${HOME}/.npmrc"

nodenv

Installation

brew install nodenv

node packages

I use pyright as an LSP server for Python development in Emacs.

echo "Installing node package pyright globally ..."
npm install -g pyright

I also use @commitlint/cli and @commitlint/config-conventional for commit linting across a variety of projects.

echo "Installing @commitlint/{cli,config-conventional} globally ..."
npm install -g @commitlint/{cli,config-conventional}

org

My default directory for org files is a submodule of this repository and thus needs to be symlinked into the location of org-directory, whose value I’ve set to ~/org in .doom.d/config.el.

rm -rf "${HOME}/org"
ln -sn "${HOME}/conf/org" "${HOME}/org"

Python

conda

Installation

Configuration

This answer to Installing anaconda with pyenv, unable to configure virtual environment is helpful for installing conda alongside pyenv.

# -*- mode: yaml; coding: utf-8; -*-
auto_activate_base: false
channels:
  - defaults

Symlink the configuration file into the appropriate location:

ln -sf "${HOME}/conf/conda/condarc" "${HOME}/.condarc"

pdm

Installation

brew install pdm

pyenv

Installation

brew install pyenv pyenv-virtualenv
pyenv install 3:latest

Configuration

Nothing at the moment.

Rust

Installation

brew install rustup
# Make sure rust-analyzer is installed for LSP
rustup component add rust-analyzer

Configuration

Nothing at the moment.

R

Ruby

TeX

${HOME}/bin

if [ -d "${HOME}/bin" ]; then
    echo "~/bin already exists; backing it up to ~/bin.bkp ..."
    cp -r "${HOME}/bin" "${HOME}/bin.bkp"
fi
rm -rf ${HOME}/bin
ln -sn "${HOME}/conf/bin" "${HOME}/bin"

ec

emacsclient -t -a="" "$@"

Applications and GUIs

Alfred

Amphetamine

Bartender

Cardhop

Contexts

Discord

Dropbox

Fantastical

Final Cut Pro

Firefox

Flux

Google Chrome

Google Drive

Handbrake

Inkscape

iTerm2

LibreOffice

Maestral

Magnet

MailMate

MakeMKV

ownCloud

Peek

Plex

Praat

PsychoPy

RStudio

Signal

Skim

Slack

Spotify

Sublime Text

Tor

Transmission

UnicodeChecker

VLC

Xcode

Zoom

Fonts

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.