#!/bin/sh set -eu TYPES=' git fossil bitkeeper darcs mercurial cvs ' guess_type() { if [ -e "$1"/.git ] || { [ -n "${GIT_DIR:-}" ] && [ -n "$GIT_WORK_TREE" ]; }; then echo git elif [ -e "$1"/.hg ]; then echo mercurial elif [ -e "$1"/.bk ]; then echo bitkeeper elif [ -e "$1"/_darcs ]; then echo darcs elif [ -e "$1"/CVS/ ]; then echo cvs elif [ -e "$1"/.fslckout ]; then echo fossil else return 1 fi } git_fetch() { git fetch --all "$@" } fossil_fetch() { fossil pull "$@" } darcs_fetch() { darcs fetch "$@" } mercurial_fetch() { hg pull "$@" } cvs_fetch() { timeout 300 cvs update "$@" } git_status() { git status "$@" } fossil_status() { fossil status "$@" fossil extras "$@" } git_diff() { git diff "$@" } fossil_diff() { fossil diff --unified | diff-so-fancy | less -R } git_ps1() { BRANCH_NAME="$(git rev-parse --abbrev-ref HEAD)" OUT="$(git status --short --branch --porcelain)" BRANCH_LINE="$(printf '%s\n' "$OUT" | head -n 1)" DIFF_LINES="$(printf '%s\n' "$OUT" | tail -n +2)" IS_AHEAD=false IS_BEHIND=false if printf '%s\n' "$BRANCH_LINE" | grep -q 'ahead'; then IS_AHEAD=true fi if printf '%s\n' "$BRANCH_LINE" | grep -q 'behind'; then IS_BEHIND=true fi LINE='' if [ "$IS_AHEAD" = true ] && [ "$IS_BEHIND" = true ]; then LINE="^^^ $BRANCH_NAME vvv" elif [ "$IS_AHEAD" = true ]; then LINE="^ $BRANCH_NAME ^" elif [ "$IS_BEHIND" = true ]; then LINE="v $BRANCH_NAME v" else LINE="$BRANCH_NAME" fi HAS_DIFF=false HAS_UNTRACKED=false if printf '%s\n' "$DIFF_LINES" | grep -q '^[A|D|M|R| ][M|D| ]'; then HAS_DIFF=true fi if printf '%s\n' "$DIFF_LINES" | grep -Eq '^([?][?]| A)'; then HAS_UNTRACKED=true fi if [ "$HAS_DIFF" = true ]; then COLOR_FN=redb LINE="{$LINE}" elif [ "$IS_AHEAD" = true ] || [ "$IS_BEHIND" = true ]; then COLOR_FN=bluei LINE="[$LINE]" elif [ "$HAS_UNTRACKED" = true ]; then COLOR_FN=lightblue LINE="{$LINE}" else COLOR_FN=green LINE="($LINE)" fi color -c "$COLOR_FN" "$LINE" BRANCH_COUNT="$(git branch --list | wc -l)" if [ "$BRANCH_COUNT" -gt 1 ]; then color -c lightblue "<$BRANCH_COUNT>" fi STASH_COUNT="$(git stash list | wc -l)" if [ "$STASH_COUNT" != 0 ]; then color -c red "*$STASH_COUNT" fi color -c blacki " - git/$(git rev-parse HEAD)" } bitkeeper_ps1() { printf '' } cvs_ps1() { printf '' } fossil_ps1() { BRANCH_NAME="$(fossil branch current)" if [ -n "$(fossil extras)" ]; then HAS_UNTRACKED=1 fi BRANCH_MARKER="$BRANCH_NAME" if [ -n "${HAS_UNTRACKED:-}" ]; then COLOR_FN=lightblue LINE="($BRANCH_MARKER)" else COLOR_FN=green LINE="($BRANCH_MARKER)" fi color -c "$COLOR_FN" "$LINE" color -c blacki " - fossil/$(fossil info | awk '/^checkout:/ { print $2 }')" } mercurial_ps1() { BRANCH_NAME="$(hg branch)" } git_gc() { git remote prune origin "$@" git gc } git_ls() { git ls-files } fossil_ls() { fossil ls } git_clean() { git clean -nffdx } fossil_clean() { fossil clean -n -v -x --emptydirs } usage() { cat <<-'EOF' Usage: vcs [-C DIR] ACTION vcs [-C DIR] -t vcs -l vcs -h EOF } help() { cat <<-'EOF' Options: -C DIR change to DIR instead of PWD -l list the supported VCS types -t show the guesses VCS type -h, --help show this message ACTION the action to be performed on the repository: - fetch - ps1 - status - gc - ls Wrapper command for normalizing options of differenct version control software. Examples: Say the type of repo in "project/": $ vcs -C project/ -t Fetch updates for VCS in current directory: $ vcs fetch EOF } for flag in "$@"; do case "$flag" in (--) break ;; (--help) usage help exit ;; (*) ;; esac done while getopts 'C:lth' flag; do case "$flag" in C) cd "$OPTARG" ;; (l) # shellcheck disable=2086 echo $TYPES | tr ' ' '\n' exit ;; (t) guess_type "$PWD" || { printf 'Could not guess the type of the repository.\n' >&2 exit 2 } exit ;; (h) usage help exit ;; (*) usage >&2 exit 2 esac done shift $((OPTIND - 1)) ACTION="${1:-}" eval "$(assert-arg -- "$ACTION" 'ACTION')" shift if [ "${1:-}" = '--' ]; then shift fi TYPE="$(guess_type "$PWD")" if [ -z "$TYPE" ]; then printf 'Could not guess the type of the repository.\n' >&2 exit 2 fi CMD="$TYPE"_"$ACTION" if ! command -v "$CMD" >/dev/null; then printf 'Invalid ACTION: "%s".\n\n' "$ACTION" >&2 usage >&2 exit 2 fi "$CMD" "$@"