226 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			226 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
#!/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              Save your changes to the environment
 | 
						|
	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 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
 | 
						|
	[ -x "$(which git 2>/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 &&
 | 
						|
		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" -a -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
 | 
						|
	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"
 | 
						|
	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" -a "$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" -o -d "$BASEDIR/files" ]; then
 | 
						|
		if ask_bool 1 "Do you want to start your configuration repository with the current configuration?"; then
 | 
						|
			[ -d "$BASEDIR/files" -a \! -L "$BASEDIR/files" ] && {
 | 
						|
				mkdir -p "$ENVDIR/files"
 | 
						|
				shopt -s dotglob
 | 
						|
				mv "$BASEDIR/files/"* "$ENVDIR/files/" 2>/dev/null
 | 
						|
				shopt -u dotglob
 | 
						|
				rmdir "$BASEDIR/files"
 | 
						|
			}
 | 
						|
			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
 |