dots/local/bin/dots

165 lines
4 KiB
Bash
Executable file

#!/usr/bin/env zsh
# <a href="https://dots.00dani.me/README">WHAT IS THIS</a>
{ # Wrap the entire program in a braced block so it won't run at all if you do curl | zsh and the connection drops.
global_ignore=(
'\.git.*'
'README\.md'
'\.stow-no-folding'
'\.stow-rename'
'\.mypy_cache'
'\..*\.swp'
)
bootstrap() {
echo 'Bootstrapping your dotfiles...' >&2
mkdir -p $DOTFILES
touch $DOTFILES/.stow
if (( ! $+commands[stow] )); 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 the configured source prefix.
[[ $url != */* ]] && url=$DOTS_SOURCE_PREFIX/$package
# user/repo packages are fetched from that user's GitHub 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 ~ --ignore=${^global_ignore} $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 || return $?
done
}
pull() {
local -a packages
packages=($argv)
(( $#packages == 0 )) && packages=( $DOTFILES/*(N:t) )
for p in $packages; do
cd $DOTFILES/$p
git pull || return $?
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
}
main() {
: ${DOTFILES:=~/dotfiles} ${STOW:=stow} ${DOTS_SOURCE_PREFIX:=https://git.00dani.me/dot}
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]} ;;
*) echo "Unknown subcommand $comm" >&2; return 2 ;;
esac
}
main "$@"
}