summaryrefslogblamecommitdiffstats
path: root/.bin/oak
blob: 4ea560ef8b99ec94b3f7ff83021584430318d777 (plain) (tree)



















































































































































































                                                                                       
#!/bin/sh
#             _
#            | |
#  __   __,  | |
# /  \_/  |  |/_)
# \__/ \_/|_/| \_/
#
# ~/.bin/oak
#
# manage multiple dotfiles repo in same work tree
#
# Example:
#  dotfiles.d/
#  |_ config
#  |_ secret
#
# ~ rgoncalves.se

usage() {
	cat <<- EOF
	USAGE ${0} : git_dirname git_action [arguments...]
	    -b: enable bootstraping for absent repository
	    -d: oak directory to work on
	        works in batch mode if no directory is provided
	    -f: force all operations
	        use with caution
	    -m: commit message when using -s option
	        commits_msg_have_to_be_written_like_this
	    -r: git remote with full path to parent directory
	    -h: show usage of ${0}
	EOF
}

log() {
	echo "[OAK  ] ${@}"
}

git_chroot() {
	log ">> ${1}"
	git --git-dir="${OAK_ROOT}/${1}" --work-tree="${HOME}" ${2}
}

git_bootstrap() {
	# directory url remote
	git_chroot "${1}" "clone --bare git@${2}/${1} ${OAK_ROOT}/${1}"
	[ "${?}" -ne 0 ] && log "Failed to bootstrap ${1}" && exit 1
	git_chroot "${1}" "checkout trunk" >/dev/null 2>&1
	git_chroot "${1}" "branch --set-upstream-to trunk origin/trunk" >/dev/null 2>&1
	git_chroot "${1}" "push -u origin trunk" >/dev/null 2>&1
}

git_sync() {
	# actions
	git_sane_all
	pull_out=$(git_chroot "${1}" "pull")
	if [ "${?}" -ne 0 ]; then
		log "error while doing git pull"
		exit 1
	fi
	echo "${pull_out}" 2>&1 | grep " ."
	git_chroot "${1}" "add -u" >/dev/null
	git_chroot "${1}" "commit -m ${OAK_MSG}"
	git_chroot "${1}" "push --set-upstream origin trunk"
	# cleanup
	unset pull_out push_out
}

git_list() {
	log "Available repositories : "
	for dir in ${OAK_DIRS}; do
		log " - ${dir}"
	done
}

git_sane() {
	if [ "${1}" = "${2}" ]; then
		return 1
	fi
	git_chroot "${1}" "ls-files" > ~/.cache/oak_a
	git_chroot "${2}" "ls-files" > ~/.cache/oak_b
	out=$(grep -F -x -f ~/.cache/oak_a ~/.cache/oak_b)
	if [ -n "${out}" ]; then
		log "detected similar files for directories: ${repo_a}, ${repo_b}"
		echo "${out}"
		return 1
	fi
	return 0
}

git_sane_all() {
	for repo_a in ${DOT_DIRS}; do
		for repo_b in ${DOT_DIRS}; do
			if [ "${repo_a}" = "${repo_b}" ]; then
				continue
			fi
			git_sane "${DOT_ROOT}/${repo_a}" "${DOT_ROOT}/${repo_b}"
			if [ "${?}" -ne 0 ]; then
				log "aborting"
				exit 1
			fi
		done
	done
}

main() {

	OAK_ROOT="${HOME}/.dotfiles.d"
	OAK_DIRS=$(ls "${OAK_ROOT}")
	OAK_DIR=""
	OAK_REMOTE=""
	OAK_CMD=""
	OAK_MSG=""

	# Retrieve oak params
	while getopts "bd:hlm:r:s" arg; do
		case "${arg}" in
			b)
				OAK_BOOTSTRAP=1
				;;
			d)
				OAK_DIR="${OPTARG}"
				;;
			f)
				OAK_FORCE=1
				;;
			h)
				usage && exit 0
				;;
			m)
				OAK_MSG="$(echo ${OPTARG} | tr -s '_' ' ')"
				;;
			l)
				git_list
				exit 0
				;;
			r)
				OAK_REMOTE="${OPTARG}"
				;;
			s)
				OAK_SYNC=1
				;;
		esac
	done

	[ -z "${OAK_MSG}" ] && OAK_MSG=$(date +%j_%H_%M_%S)

	# Bootstrap non-present repositories
	if [ -n "${OAK_DIR}" ] && [ ! -d "${OAK_ROOT}/${OAK_DIR}" ]; then
		git_bootstrap "${OAK_DIR}" "${OAK_REMOTE}"
		if [ "${?}" -ne 0 ]; then
			log "Git repository does not exist. Error"
			exit 1
		fi
		log "Successfully bootstraped git repository"
	fi

	# Retrieve oak command for git
	shift $(expr "${OPTIND}" - 1)
	for cmd in "${@}"; do
		OAK_CMD="${OAK_CMD}${cmd} "
	done

	# Git synchronization in each repository
	if [ -n "${OAK_SYNC}" ]; then
		for dir in ${OAK_DIR:-$OAK_DIRS}; do
			log "synchronize ${dir}"
			git_sync "${dir}"
		done
	fi

	# Raw command in each git repository
	if [ -n "${OAK_CMD}" ]; then
		for dir in ${OAK_DIR:-$OAK_DIRS}; do
			git_chroot "${dir}" "${OAK_CMD}"
		done
	fi

}

main $@
remember that computers suck.