Created
September 25, 2023 11:40
-
-
Save ikskuh/9f8be7322d1bd05a6c7e3d41caf3ae3d to your computer and use it in GitHub Desktop.
basic dotfile manager
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -euo pipefail | |
which git sed cut 1>/dev/null | |
timestamp="$(date +'%Y-%m-%d %H:%M')" | |
c_base=$'\033[0m' | |
c_red=$'\033[00;31m' | |
c_green=$'\033[00;32m' | |
c_yellow=$'\033[00;33m' | |
c_blue=$'\033[00;34m' | |
c_purple=$'\033[00;35m' | |
c_cyan=$'\033[00;36m' | |
c_lightgray=$'\033[00;37m' | |
c_lred=$'\033[01;31m' | |
c_lgreen=$'\033[01;32m' | |
c_lyellow=$'\033[01;33m' | |
c_lblue=$'\033[01;34m' | |
c_lpurple=$'\033[01;35m' | |
c_lcyan=$'\033[01;36m' | |
c_white=$'\033[01;37m' | |
function dotgit() | |
{ | |
git -c core.excludesFile=$HOME/.shared-config/.gitignore --git-dir=$HOME/.shared-config/.git --work-tree=$HOME "$@" | |
} | |
function errlog() | |
{ | |
echo "$@" >&2 | |
} | |
function panic() | |
{ | |
errlog "$@" | |
exit 255 | |
} | |
function dotfiles-status() | |
{ | |
dotgit status "$@" --porcelain --null | ( | |
while IFS= read -r -d $'\0' line; do | |
if [[ "$line" = \?\?* ]]; then | |
continue | |
fi | |
status="$(echo $(echo "$line" | cut -b 1-3))" | |
file="$(echo "$line" | cut -b 4-)" | |
if [ "$status" != "??" ]; then | |
case "$status" in | |
M) # modified | |
echo " ${c_lgreen}~/${file}${c_base}" | |
;; | |
D) # deleted | |
echo " ${c_red}~/${file}${c_base} (deleted)" | |
;; | |
A) # added | |
;& | |
AM) # added+modified | |
;& | |
*) | |
echo " ${c_lpurple}~/${file}${c_base} (unknown status: '${status}')" | |
;; | |
esac | |
fi | |
done | |
) | |
} | |
function dotfiles-diff() | |
{ | |
dotgit diff HEAD "$@" | |
} | |
function dotfiles-sync() | |
{ | |
dotgit status "$@" --porcelain --null | { | |
declare -a files=() | |
fault=0 | |
while IFS= read -r -d $'\0' line; do | |
if [[ "$line" = \?\?* ]]; then | |
continue | |
fi | |
status="$(echo $(echo "$line" | cut -b 1-3))" | |
file="$(echo "$line" | cut -b 4-)" | |
if [ "$status" != "??" ]; then | |
case "$status" in | |
M) # modified | |
files+=("$HOME/${file}") | |
;; | |
D) # deleted | |
echo " ${c_red}~/${file}${c_base} (deleted)" | |
fault=1 | |
;; | |
*) | |
echo " ${c_lpurple}~/${file}${c_base} (unknown status: '${status}')" | |
fault=1 | |
;; | |
esac | |
fi | |
done | |
if [ $fault -ne 0 ]; then | |
errlog "Repository unclean, please fix state first before syncing!" | |
return 1 | |
fi | |
dotgit add -f "${files[@]}" | |
dotgit commit -m "[${timestamp}] Synchronizes ${files[@]}" || { | |
dotgit reset "${files[@]}" | |
errlog "failed create commit!" | |
return 1 | |
} | |
dotgit push | |
dotgit pull --rebase=false | |
} | |
} | |
function dotfiles-add() | |
{ | |
if [ "$#" -lt 1 ]; then | |
panic "add requires files to be added!" | |
fi | |
declare -a list=() | |
for file in "$@"; do | |
rfile="$(realpath "${file}")" | |
dotgit add -f "${rfile}" | |
list+=("$(echo "${rfile}" | sed 's|^'"$HOME"'|~|')") | |
unset rfile | |
done | |
msg="[${timestamp}] Adds/updates ${list[@]}" | |
dotgit commit -m "msg" | |
dotgit push | |
} | |
function dotfiles-remove() | |
{ | |
if [ "$#" -lt 1 ]; then | |
panic "remove requires files to be added!" | |
fi | |
declare -a list=() | |
fault=0 | |
for file in "$@"; do | |
rfile="$(realpath "${file}")" | |
if dotgit rm -rf "${rfile}"; then | |
list+=("$(echo "${rfile}" | sed 's|^'"$HOME"'|~|')") | |
else | |
errlog "failed to remove ${file}" | |
fault=1 | |
fi | |
done | |
if [ $fault -eq 0 ]; then | |
dotgit commit -m "[${timestamp}] Deletes ${list[@]}" | |
dotgit push | |
else | |
errlog "won't delete files with failures!" | |
fi | |
} | |
if [ "$#" -lt 1 ]; then | |
errlog "usage: dotfiles <command>" | |
errlog "" | |
errlog " commands:" | |
errlog " status - prints which local files have changes." | |
errlog " diff - lists all active changes." | |
errlog " sync - commits changes and pulls changes from the remote." | |
errlog " add <files…> - adds the given files and pushes them to the remote." | |
errlog " remove <files>… - removes the given files and drops them from the remote." | |
errlog " git <…> - direct access to git." | |
errlog "" | |
exit 1 | |
fi | |
command="$1" | |
shift | |
case "${command}" in | |
status) | |
dotfiles-status "$@" | |
;; | |
sync) | |
dotfiles-sync "$@" | |
;; | |
add) | |
dotfiles-add "$@" | |
;; | |
remove) | |
dotfiles-remove "$@" | |
;; | |
diff) | |
dotfiles-diff "$@" | |
;; | |
git) | |
dotgit "$@" | |
;; | |
*) | |
panic "invalid command ${command}" | |
;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment