#!/usr/bin/env zsh 'bootstrap'() { echo 'Bootstrapping your dotfiles...' >&2 mkdir -p $DOTFILES touch $DOTFILES/.stow if ! hash stow 2>/dev/null; then echo 'GNU Stow is not installed, fetching it...' >&2 clone-one stow || return $? STOW=$DOTFILES/stow/local/bin/stow fi clone dots git vim zsh || return $? link } 'clone'() { echo "Requested packages: $argv" >&2 for package in $argv; do clone-one $package || return $? done } 'clone-one'() { local url=$1 local package=${${url##*/}%.git} # Simple package names are fetched from my GitHub repos. [[ $url != */* ]] && url=$GITHUB_USER/dot-$package # user/repo packages are fetched from that user's repos. [[ $url != *:* ]] && url=https://github.com/$url if [[ -d $DOTFILES/$package ]]; then echo "Looks like you already have $package cloned." >&2 return 1 fi echo "Retrieving $package from $url now..." >&2 git clone $url $DOTFILES/$package } 'link'() { local -a packages packages=($argv) if (( $#packages == 0 )); then packages=( $DOTFILES/*(N:t) ) if (( $#packages == 0 )); then echo "No installed packages! Do you want to clone some first?" >&2 return 1 fi echo "Linking all packages ($packages) into $HOME now..." >&2 else echo "Linking $packages into $HOME now..." >&2 fi for nofold in $DOTFILES/${^packages}/.stow-no-folding(N); process-stow-no-folding $nofold $STOW -d $DOTFILES -t ~ $packages } 'process-stow-no-folding'() { zmodload zsh/mapfile for file in ${(f)mapfile[$1]}; do file=~/$file [[ -e $file ]] && continue mkdir -p ${file:h} touch $file done } 'fetch'() { local -a packages packages=($argv) (( $#packages == 0 )) && packages=( $DOTFILES/*(N:t) ) for p in $packages; do cd $DOTFILES/$p git fetch -p done } 'pull'() { local -a packages packages=($argv) (( $#packages == 0 )) && packages=( $DOTFILES/*(N:t) ) for p in $packages; do cd $DOTFILES/$p git pull done } 'status'() { local -a packages packages=($argv) (( $#packages == 0 )) && packages=( $DOTFILES/*(N:t) ) local length=${#${(O@)packages//?/X}[1]} git_status remote_status for p in $packages; do cd $DOTFILES/$p # Always show the repo's name at the beginning of the line. printf %${length}s' ' $p # Check if the package is actually a repo. It might not be if it's brand-new. git_status="$(git status --porcelain --ignore-submodules -unormal 2>/dev/null)" if (( $? != 0 )); then printf '%9s' '' # space across to the last column print -P %F{247}not a git repository%f continue fi # Indicate the working tree status. if [[ -z $git_status ]]; then print -Pn %F{green}clean%f' ' else print -Pn %F{red}unclean%f fi printf '%2s' '' # If the repository has an upstream remote configured, indicate the number # of commits out of sync we are from the remote. if git rev-parse --abbrev-ref @{u} &>/dev/null; then remote_status="$(git rev-list --left-right --count HEAD...@{u} 2>/dev/null)" remote_status=(${(ps:\t:)remote_status}) print -Pn %F{cyan} (( $remote_status[1] > 0 )) && print -n $remote_status[1]⇡ (( $remote_status[2] > 0 )) && print -n $remote_status[2]⇣ print -P %f else print -P %F{247}no remote%f fi done } : ${DOTFILES:=~/dotfiles} ${STOW:=stow} ${GITHUB_USER:=00dani} comm=$1 if (( $# == 0 )); then if [[ -d $DOTFILES ]]; then comm=status else comm=bootstrap fi fi case $comm in bootstrap) bootstrap ;; clone) clone ${argv[2,-1]} ;; fetch) fetch ${argv[2,-1]} ;; link) link ${argv[2,-1]} ;; pull) pull ${argv[2,-1]} ;; st|status) status ${argv[2,-1]} ;; esac