dot file automation

Sharpen and clean your tools to make them last longer. Hone your tools to make them more precise. The tools of a SRE start with the terminal. The terminal is honed sharp with dotfiles.

Live your life long enough in a terminal and tweaks and customizations happen. Live longer and when those tweaks are lost from a catastrophe or when you switch machines, you will be hamstrung and saddened going back to nothing.

Phase 1: maintain my dot files for tmux, bash, git and vim in a GitHub repo, and then manually symlink from the repo to my home directory.

Phase 2: automate all of the configuration setup process and the supporting software.

Complexity 1: half a dozen machines.

Complexity 2: the machines were split between Mac and linux.

Complexity 3: a couple of the linux VMs, want to be run as root. -Rage note about root- These are kali and security distributions that are not meant to be long lived, but I will be on the long enough to want a toolset.

The dot files are arranged in a shell script that will be run and then the proper bash git tmux and vim files are symlinked and used based on the os and the user that I am running as.

If there is anything that I’ve done horribly wrong with these I would really like to hear about it, these are the dot files that I have dragged around and revised for the past 5 years now or so, and we all know that looking t anything that was written even 6 months ago, we can think of way better ways of doing things.

Let’s dive right in.

#!/bin/bash
#..setup.sh .  double dots because gist, gets auto sorted (ugh)
# Hi im a penguin
if [ "Linux" = "$(uname -a | awk '{printf $1}')" ] 

then
	# this is handled is submodoules
	#git clone https://github.com/magicmonty/bash-git-prompt.git ~/.bash-git-prompt --depth=1

	#create symlinks
	#root because kali
    if [ "root" = "$(whoami)" ] 
    then
	    ln -s "$(pwd)"/.tmux.conf /"$(whoami)"/.tmux.conf 
	    ln -s "$(pwd)"/.vimrc /"$(whoami)"/.vimrc 
	    ln -s "$(pwd)"/.bashrc /"$(whoami)"/.bashrc 
	    ln -s "$(pwd)"/.gitconfig /"$(whoami)"/.gitconfig 

	    #not root like a sane person
	    else
	    ln -s "$(pwd)"/.tmux.conf /home/"$(whoami)"/.tmux.conf 
	    ln -s "$(pwd)"/.vimrc /home/"$(whoami)"/.vimrc 
	    ln -s "$(pwd)"/.bashrc /home/"$(whoami)"/.bashrc 
	    ln -s "$(pwd)"/.gitconfig /home/"$(whoami)"/.gitconfig 
    fi

	#install latest ripgrep
	rg_tag=$(curl --silent "https://api.github.com/repos/BurntSushi/ripgrep/releases/latest" |grep '"tag_name":'  | sed -E 's/.*"([^"]+)".*/\1/' )
	curl -LO https://github.com/BurntSushi/ripgrep/releases/download/"$rg_tag"/ripgrep_"$rg_tag"_amd64.deb
	sudo dpkg -i ripgrep_"$rg_tag"_amd64.deb
	rm ripgrep_"$rg_tag"_amd64.deb

fi

# hi I'm a mac
if [ "Mac" = "$(sw_vers|grep ProductName |awk '{printf $2}')" ]
then
    ln -s "$(pwd)"/.tmux.conf /Users/"$(whoami)"/.tmux.conf 
    ln -s "$(pwd)"/.vimrc /Users/"$(whoami)"/.vimrc 
    ln -s "$(pwd)"/.bash_profile /Users/"$(whoami)"/.bash_profile
    ln -s "$(pwd)"/.gitconfig /Users/"$(whoami)"/.gitconfig 

    brew install ripgrep
    brew install ranger

fi

mkdir -p ~/.vim/autoload ~/.vim/bundle && \
    curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
#bash_profile
GIT_PROMPT_ONLY_IN_REPO=1
  source ~/.bash-git-prompt/gitprompt.sh

export PATH=/usr/local/sbin:/usr/local/bin:$PATH
export PATH="/Users/$(whoami)/platform-tools/:/usr/local/opt/python/libexec/bin:$PATH"
export PATH=~/.local/bin:$PATH

alias gpox='git push origin `git rev-parse --abbrev-ref HEAD`'
alias weather="curl wttr.in/<your city>"
alias docker_logs_latest="docker logs -f "$(docker ps -l -q)" "

## a quick way to get out of current directory ##
alias ..='cd ..'
alias ...='cd ../../../'
alias ....='cd ../../../../'
alias .....='cd ../../../../'
alias .4='cd ../../../../'
alias .5='cd ../../../../..'

alias vi=vim
alias ping='ping -c 5'
#.bashrc
# things for git
GIT_PROMPT_ONLY_IN_REPO=1
source ~/.bash-git-prompt/gitprompt.sh

alias gpox='git push origin `git rev-parse --abbrev-ref HEAD`'

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth

# append to the history file, don't overwrite it
shopt -s histappend

# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000

# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize

# If set, the pattern "**" used in a pathname expansion context will
# match all files and zero or more directories and subdirectories.
#shopt -s globstar

# make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"

# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
    debian_chroot=$(cat /etc/debian_chroot)
fi

# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
    xterm-color|*-256color) color_prompt=yes;;
esac

# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes

if [ -n "$force_color_prompt" ]; then
    if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
	# We have color support; assume it's compliant with Ecma-48
	# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
	# a case would tend to support setf rather than setaf.)
	color_prompt=yes
    else
	color_prompt=
    fi
fi

if [ "$color_prompt" = yes ]; then
    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
unset color_prompt force_color_prompt

# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
    PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
    ;;
*)
    ;;
esac

# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
    test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
    alias ls='ls --color=auto'
    #alias dir='dir --color=auto'
    #alias vdir='vdir --color=auto'

    alias grep='grep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias egrep='egrep --color=auto'
fi

# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'

# Add an "alert" alias for long running commands.  Use like so:
#   sleep 10; alert
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'

# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
  if [ -f /usr/share/bash-completion/bash_completion ]; then
    . /usr/share/bash-completion/bash_completion
  elif [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
  fi
fi
#.gitconfig
[alias]
    # abbreviations
    st = status -s
    ch = checkout
    co = commit
    br = branch
    # watch log
    watch = "!f() { while [ 1 ]; do clear; git log --all --oneline --decorate --graph; sleep 3; done; }; f"
    # pretty log with graph output
    lg = log --graph --pretty=format:'%C(yellow)%h%Cred -%C(auto)%d%Creset %s %Cgreen(%cr) %C(cyan)<%an>%Creset' --decorate --abbrev-commit --date=relative
    # pretty log file details
    ll = log --pretty=format:'%C(yellow)%h%Cred%d %Creset%s%Cblue [%cn]' --decorate --numstat
    # pretty log with dates
    ld = log --pretty=format:'%C(yellow)%h %Cred%ad %Cblue%an%Cgreen%d %Creset%s' --date=local
    # pretty log with dates, first parent only
    lf = log --pretty=format:'%C(yellow)%h %Cred%ad %Cblue%an%Cgreen%d %Creset%s' --date=local
    # prettier blame
    who = blame -c --show-stats --date=relative
    # prettier and concise whatchanged
    what = whatchanged --pretty=format:'%C(yellow)%h %Cred%ad %Cblue%an%Cgreen%d %Creset%s' --date=local --stat
    # prettier whatchanged with full diffs
    whatwhat = whatchanged --pretty=format:'%C(yellow)%h %Cred%ad %Cblue%an%Cgreen%d %Creset%s' --date=local -p
    # prettier whatchanged with full diffs based on text search
    whatwhen = whatchanged --pretty=format:'%C(yellow)%h %Cred%ad %Cblue%an%Cgreen%d %Creset%s' --date=local -p -S
    # search the log for when given text was introduced
    when = log -S
    # list of files that have changed (with status)
    changes = diff --name-status
    # list of files that have changed
    changed = diff --name-status
    # diff - ignore whitespace
    wdiff = diff -w
    # smart diff shows the changes that matter on a very granular level
    smartdiff = diff -w -b --patience
    # list of changes since current branch diverge from master branch
    mdiff = "!f() { git fetch; git diff origin/master...HEAD; }; f"
    # list of changes since current branch diverge from master branch - ignore whitespace
    mwdiff = "!f() { git fetch; git diff -w origin/master...HEAD; }; f"
    # list of files that have changed (with status) since current branch diverge from master branch
    mchanges = "!f() { git fetch; git diff --name-status origin/master...HEAD; }; f"
    # list of files that have changed since current branch diverge from master branch
    mchanged = "!f() { git fetch; git diff --name-only origin/master...HEAD; }; f"
    # diff between two branchs
    bdiff = "!f() { git diff $1...HEAD; }; f"
    # list of files that have changed (with status) between two branches
    bchanges = "!f() { git diff --name-status $1...HEAD; }; f"
    # list of files that have changed between two branches
    bchanged = "!f() { git diff --name-only $1...HEAD; }; f"
    # get diff between HEAD and origin/HEAD
    odiff = diff HEAD...origin/HEAD
    # get diff between HEAD and origin/HEAD
    ochanges = diff --name-status HEAD...origin/HEAD
    # find files
    f = "!git ls-files | grep -i"
    # find files containing text
    g = grep -Ii
    # find out which branch contains a change
    contains = branch --contains
    # pretty print all commits which were introduced by a given merge. NOTE: requires merge commit as an argument!
    introduced = "!f() { git log $(git merge-base --octopus $(git show $1 --format='%P'))..$(git show $1 --format='%H') --boundary --graph --pretty=oneline --abbrev-commit; }; f"
    # used after a revert to show commands you'll need to run in order to reintroduce commits previously introduced by a given merge commit. NOTE: requires merge commit as an argument!
    reintroduce = "!f() { git log $(git merge-base --octopus $(git show $1 --format='%P'))..$(git show $1 --format='%H') --format='git cherry-pick %H' --no-merges --reverse; }; f"
    # list branchs that exist on local only
    localonly = "!f() { LOCALS=$(git branch --list --no-color | cut -c 3-);REMOTES=$(git branch --all --no-color | grep 'remotes/origin' | grep -v HEAD | awk -F'/' '{print $3}');for R in $REMOTES; do LOCALS=$(echo \"$LOCALS\" | grep -v $R); done; echo \"$LOCALS\"; }; f"
    # leaderboard
    leaderboard = shortlog -s -n
    # hard reset
    hard = reset --hard
    # hard reset to HEAD
    hardhead = reset --hard HEAD
    # hard reset to first parent
    undo = reset --hard @^
    # head commit
    head = rev-parse HEAD
    # head commit
    shorthead = rev-parse --short HEAD
    # cherry pick
    pick = cherry-pick -x
    # stash
    save = stash -u
    # stash pop
    pop = stash pop
    # copy given commit hash
    copy = "!f() { REF=${1:-HEAD}; git rev-parse --short $REF | tr -d '\n' | pbcopy; }; f"
    # fixup commit
    fixup = !sh -c 'git commit -m \"fixup! $(git log -1 --format='\\''%s'\\'' $@)\"' -
    # squash commit
    squash = !sh -c 'git commit -m \"squash! $(git log -1 --format='\\''%s'\\'' $@)\"' -
    # interactive rebase
    ri = rebase --interactive --autosquash
    # svn update commit
    svnupdate = "!f() { svn update; git add -A; git commit -m 'svn update'; }; f"
    # unapply stash
    stash-unapply = !git stash show -p --no-color | git apply -R
    # reset to guarenteed state
    goto = "!f() { git fetch; git reset --hard $1; git clean -d -f; }; f"
    # pull rebase
    pullr = pull --rebase
    # freebase
    freebase = "!f() { git fetch; git rebase `git remote show | head -1`/$1; }; f"
    # freeset
    freeset = "!f() { git fetch; git reset --hard `git remote show | head -1`/$1; }; f"
#.gitmodules
[submodule ".bash-git-prompt"]
	path = .bash-git-prompt
	url = git@github.com:magicmonty/bash-git-prompt.git
[submodule ".vim/bundle/nerdtree"]
	path = .vim/bundle/nerdtree
	url = git@github.com:scrooloose/nerdtree.git
[submodule ".vim/bundle/syntastic"]
	path = .vim/bundle/syntastic
	url = https://github.com/scrooloose/syntastic.git
#.tmux.conf
# color
set -g default-terminal "xterm-256color"
set -g status-fg white
set -g status-bg black
setw -g window-status-fg cyan
setw -g window-status-bg default
setw -g window-status-attr dim
setw -g window-status-current-fg white
setw -g window-status-current-bg red
setw -g window-status-current-attr bright
set -g pane-border-fg green
set -g pane-border-bg black
set -g pane-active-border-fg white
set -g pane-active-border-bg yellow
set -g message-fg white
set -g message-bg black
set -g message-attr bright
set-option -g history-limit 100000
#vim stuff
setw -g mode-keys vi
bind -Tcopy-mode-vi 'y' send -X copy-selection-and-cancel
bind -Tcopy-mode-vi 'y' send -X copy-pipe-and-cancel "reattach-to-user-namespace pbcopy"

set-option -g mouse on

# syncing sessions
bind s setw synchronize-panes 

# window & pane control
bind | split-window -h
bind - split-window -v
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
bind -r C-h select-window -t :-
bind -r C-l select-window -t :+
bind K swap-pane -t 1
bind J swap-pane -t 2
bind L swap-pane -t 2
bind H swap-pane -t 1
bind b previous-window

#home and end keys
bind -n End send-key C-e
bind -n Home send-key C-a

set -g mode-keys vi

# easily reload conf
bind r source-file ~/.tmux.conf \; display "Reloaded!"

set-option -g default-command "/bin/bash -c 'which reattach-to-user-namespace >/dev/null && exec reattach-to-user-namespace $SHELL -l || exec $SHELL -l'"
.vimrc
syntax on
filetype plugin indent on
set nocompatible
execute pathogen#infect()
set statusline+=%#warningmsg#
set statusline+=%*
set laststatus=2

" [buffer number] followed by filename:
 set statusline+=[%n]\ %F
" for Syntastic messages:
set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*
" show line#:column# on the right hand side
set statusline+=%=%l:%c

set number

" no swap files
set noswapfile
" don't write to a backup file then delete the original and then rename the
" backup to the name of the original file... it's annoying
set nowritebackup

" persistent undo
set undofile 
set undodir=~/.vim/undodir


" easier switch to split
nmap <C-h> <C-w>h
nmap <C-l> <C-w>l
nmap <C-k> <C-w>k
nmap <C-j> <C-w>j

" changing tabs to spaces
set expandtab ts=4 sts=4 sw=4

"setting autoindent
set ai

" Ignore case when searching
set ignorecase

" copy paste from system clipboard
set clipboard=unnamed
vmap ç "*y
vmap ≈ "*d
nmap √ :set paste<CR>"*p:set nopaste<CR>
imap √ <ESC>√

" toggle paste mode with <F1> ... this way you can leave autocommenting on
" most of the time a quickly disable it for pasting in code
set pastetoggle=<F1>
set showmode