123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- #!/usr/bin/env bash
- BASEDIR="$PWD"
- ENVDIR="$PWD/env"
- export GREP_OPTIONS=
- usage() {
- cat <<EOF
- Usage: $0 [options] <command> [arguments]
- Commands:
- help This help text
- list List environments
- clear Delete all environment and revert to flat config/files
- new <name> Create a new environment
- switch <name> Switch to a different environment
- delete <name> Delete an environment
- rename <newname> Rename the current environment
- diff Show differences between current state and environment
- save [message] Save your changes to the environment, optionally using
- the given commit message
- revert Revert your changes since last save
- Options:
- EOF
- exit "${1:-1}"
- }
- error() {
- echo "$0: $*"
- exit 1
- }
- ask_bool() {
- local DEFAULT="$1"; shift
- local def defstr val
- case "$DEFAULT" in
- 1) def=0; defstr="Y/n";;
- 0) def=1; defstr="y/N";;
- *) def=; defstr="y/n";;
- esac
- while [ -z "$val" ]; do
- local VAL
- echo -n "$* ($defstr): "
- read -r VAL
- case "$VAL" in
- y*|Y*) val=0;;
- n*|N*) val=1;;
- *) val="$def";;
- esac
- done
- return "$val"
- }
- env_init() {
- local CREATE="$1"
- if [ -z "$CREATE" ]; then
- [ -d "$ENVDIR" ] || exit 0
- fi
- command -v git >/dev/null || error "Git is not installed"
- mkdir -p "$ENVDIR" || error "Failed to create the environment directory"
- cd "$ENVDIR" || error "Failed to switch to the environment directory"
- [ -d .git ] || {
- git init -b master &&
- touch .config &&
- mkdir files &&
- git add . &&
- git commit -q -m "Initial import"
- } || {
- rm -rf .git
- error "Failed to initialize the environment directory"
- }
- }
- env_sync_data() {
- [ ! -L "$BASEDIR/.config" ] && [ -f "$BASEDIR/.config" ] && mv "$BASEDIR/.config" "$ENVDIR"
- git add .
- git add -u
- }
- env_sync() {
- local STR="$1"
- env_sync_data
- git commit -m "${STR:-Update} at $(date)"
- }
- env_link_config() {
- rm -f "$BASEDIR/.config"
- ln -s env/.config "$BASEDIR/.config"
- mkdir -p "$ENVDIR/files"
- [ -L "$BASEDIR/files" ] || ln -s env/files "$BASEDIR/files"
- }
- env_do_reset() {
- git reset --hard HEAD
- git clean -d -f
- }
- env_list() {
- env_init
- git branch --color | grep -vE '^. master$'
- }
- env_diff() {
- env_init
- env_sync_data
- git diff --cached --color=auto
- env_link_config
- }
- env_save() {
- env_init
- env_sync "$@"
- env_link_config
- }
- env_revert() {
- env_init
- env_do_reset
- env_link_config
- }
- env_ask_sync() {
- env_sync_data
- LINES="$(env_diff | wc -l)" # implies env_init
- [ "$LINES" -gt 0 ] && {
- if ask_bool 1 "Do you want to save your changes"; then
- env_sync
- else
- env_do_reset
- fi
- }
- }
- env_clear() {
- env_init
- [ -L "$BASEDIR/.config" ] && rm -f "$BASEDIR/.config"
- [ -L "$BASEDIR/files" ] && rm -f "$BASEDIR/files"
- [ -f "$ENVDIR/.config" ] || ( cd "$ENVDIR/files" && find . | grep -vE '^\.$' > /dev/null )
- env_sync_data
- if ask_bool 1 "Do you want to keep your current config and files"; then
- mkdir -p "$BASEDIR/files"
- shopt -s dotglob
- cp -a "$ENVDIR/files/"* "$BASEDIR/files" 2>/dev/null >/dev/null
- shopt -u dotglob
- cp "$ENVDIR/.config" "$BASEDIR/"
- else
- rm -rf "$BASEDIR/files" "$BASEDIR/.config"
- fi
- cd "$BASEDIR" || exit 1
- rm -rf "$ENVDIR"
- }
- env_delete() {
- local name="${1##*/}"
- env_init
- [ -z "$name" ] && usage
- branch="$(git branch | grep '^\* ' | awk '{print $2}')"
- [ "$name" = "$branch" ] && error "cannot delete the currently selected environment"
- git branch -D "$name"
- }
- env_switch() {
- local name="${1##*/}"
- [ -z "$name" ] && usage
- env_init
- env_ask_sync
- git checkout "$name" || error "environment '$name' not found"
- env_link_config
- }
- env_rename() {
- local NAME="${1##*/}"
- env_init
- git branch -m "$NAME"
- }
- env_new() {
- local NAME="$1"
- local branch
- local from="master"
- [ -z "$NAME" ] && usage
- env_init 1
-
- branch="$(git branch | grep '^\* ' | awk '{print $2}')"
- if [ -n "$branch" ] && [ "$branch" != "master" ]; then
- env_ask_sync
- if ask_bool 0 "Do you want to clone the current environment?"; then
- from="$branch"
- fi
- rm -f "$BASEDIR/.config" "$BASEDIR/files"
- fi
- git checkout -b "$1" "$from"
- if [ -f "$BASEDIR/.config" ] || [ -d "$BASEDIR/files" ]; then
- if ask_bool 1 "Do you want to start your configuration repository with the current configuration?"; then
- if [ -d "$BASEDIR/files" ] && [ ! -L "$BASEDIR/files" ]; then
- mkdir -p "$ENVDIR/files"
- shopt -s dotglob
- mv "$BASEDIR/files/"* "$ENVDIR/files/" 2>/dev/null
- shopt -u dotglob
- rmdir "$BASEDIR/files"
- fi
- env_sync
- else
- rm -rf "$BASEDIR/.config" "$BASEDIR/files"
- fi
- fi
- env_link_config
- }
- COMMAND="$1"; shift
- case "$COMMAND" in
- help) usage 0;;
- new) env_new "$@";;
- list) env_list "$@";;
- clear) env_clear "$@";;
- switch) env_switch "$@";;
- delete) env_delete "$@";;
- rename) env_rename "$@";;
- diff) env_diff "$@";;
- save) env_save "$@";;
- revert) env_revert "$@";;
- *) usage;;
- esac
|