233 lines
5.7 KiB
Bash
Executable file
233 lines
5.7 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'
|
|
'\.editorconfig'
|
|
'\.stow-no-folding'
|
|
'\.mypy_cache'
|
|
'\..*\.swp'
|
|
)
|
|
|
|
supported_stow_versions=(
|
|
2.3.2-fixbug56727
|
|
)
|
|
|
|
call-git() {
|
|
git $argv ${VERBOSE:+-v}
|
|
}
|
|
|
|
call-gnu-stow() {
|
|
$STOW --dotfiles -d $DOTFILES -t ~ --ignore=${^global_ignore} ${VERBOSE:+-vvv} $argv
|
|
}
|
|
|
|
do-bootstrap() {
|
|
echo 'Bootstrapping your dotfiles...' >&2
|
|
mkdir -p $DOTFILES
|
|
touch $DOTFILES/.stow
|
|
if (( $+commands[stow] )); then
|
|
local stow_version=${"$(stow -V)"#stow*version }
|
|
if (( 0 == $supported_stow_versions[(Ie)$stow_version] )); then
|
|
echo "GNU Stow is installed, but version $stow_version is bugged." >&2
|
|
echo 'See https://github.com/aspiers/stow/issues/33 for info.' >&2
|
|
echo 'Will fetch patched version of Stow...' >&2
|
|
install-custom-gnu-stow || return $?
|
|
else
|
|
echo "GNU Stow version $stow_version is installed and is compatible with dots." >&2
|
|
fi
|
|
else
|
|
echo 'GNU Stow is not installed, fetching it...' >&2
|
|
install-custom-gnu-stow || return $?
|
|
fi
|
|
|
|
do-clone dots git vim zsh || return $?
|
|
do-stow
|
|
}
|
|
|
|
install-custom-gnu-stow() {
|
|
clone-one stow || return $?
|
|
STOW=$DOTFILES/stow/dot-local/bin/stow
|
|
}
|
|
|
|
do-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
|
|
call-git clone $url $DOTFILES/$package
|
|
}
|
|
|
|
do-stow() {
|
|
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 "Stowing all packages ($packages) into $HOME now..." >&2
|
|
else
|
|
echo "Stowing $packages into $HOME now..." >&2
|
|
fi
|
|
|
|
for nofold in $DOTFILES/${^packages}/.stow-no-folding(N); process-stow-no-folding $nofold
|
|
call-gnu-stow -S $packages
|
|
}
|
|
|
|
do-unstow() {
|
|
local -a packages
|
|
packages=($argv)
|
|
if (( $#packages == 0 )); then
|
|
packages=( $DOTFILES/*(N:t) )
|
|
if (( $#packages == 0 )); then
|
|
echo "No installed packages! There's nothing to unstow!" >&2
|
|
return 1
|
|
fi
|
|
echo "Unstowing all packages ($packages) from $HOME now..." >&2
|
|
else
|
|
echo "Unstowing $packages from $HOME now..." >&2
|
|
fi
|
|
|
|
call-gnu-stow -D $packages
|
|
}
|
|
|
|
do-restow() {
|
|
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 "Restowing all packages ($packages) into $HOME now..." >&2
|
|
else
|
|
echo "Restowing $packages into $HOME now..." >&2
|
|
fi
|
|
|
|
for nofold in $DOTFILES/${^packages}/.stow-no-folding(N); process-stow-no-folding $nofold
|
|
call-gnu-stow -R $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
|
|
}
|
|
|
|
do-fetch() {
|
|
local -a packages
|
|
packages=($argv)
|
|
(( $#packages == 0 )) && packages=( $DOTFILES/*(N:t) )
|
|
for p in $packages; do
|
|
cd $DOTFILES/$p
|
|
call-git fetch -p || return $?
|
|
done
|
|
}
|
|
|
|
do-pull() {
|
|
local -a packages
|
|
packages=($argv)
|
|
(( $#packages == 0 )) && packages=( $DOTFILES/*(N:t) )
|
|
for p in $packages; do
|
|
cd $DOTFILES/$p
|
|
call-git pull || return $?
|
|
done
|
|
}
|
|
|
|
|
|
do-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="$(call-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}
|
|
|
|
local opt_index=$argv[(I)(-v|--verbose)]
|
|
if (( opt_index != 0 )); then
|
|
VERBOSE=yes
|
|
argv[opt_index]=()
|
|
fi
|
|
|
|
comm=$1
|
|
if (( $# == 0 )); then
|
|
if [[ -d $DOTFILES ]]; then
|
|
comm=status
|
|
else
|
|
comm=bootstrap
|
|
fi
|
|
fi
|
|
|
|
case $comm in
|
|
bootstrap) do-bootstrap ;;
|
|
clone) do-clone ${argv[2,-1]} ;;
|
|
fetch) do-fetch ${argv[2,-1]} ;;
|
|
stow) do-stow ${argv[2,-1]} ;;
|
|
unstow) do-unstow ${argv[2,-1]} ;;
|
|
restow) do-restow ${argv[2,-1]} ;;
|
|
pull) do-pull ${argv[2,-1]} ;;
|
|
st|status) do-status ${argv[2,-1]} ;;
|
|
*) echo "Unknown subcommand $comm" >&2; return 2 ;;
|
|
esac
|
|
}
|
|
|
|
main "$@"
|
|
}
|