mirror of
https://github.com/facebook/sapling.git
synced 2024-10-12 01:39:21 +03:00
bbd4b91102
Summary: In the future the changelog would need to access 'remotenames' to figure out public heads. Move the state file to svfs so it can be read by the changelog object, which only has access to svfs. Reviewed By: sfilipco Differential Revision: D17199834 fbshipit-source-id: 9000e0d8e8bb8d398d6c77b5b395da904fef6418
250 lines
7.8 KiB
Bash
250 lines
7.8 KiB
Bash
# Copyright (C) 2015 Facebook, Inc
|
|
# Maintained by Ryan McElroy <rm@fb.com>
|
|
#
|
|
# Inspiration and derivation from git-completion.bash by Shawn O. Pearce.
|
|
#
|
|
# Distributed under the GNU General Public License, version 2.0.
|
|
#
|
|
# ========================================================================
|
|
#
|
|
# Quickly determines the and emits some useful information about the state
|
|
# of your current mercurial or git repository. Useful for PS1 prompts.
|
|
#
|
|
# Design goals:
|
|
# * Useful for both git and mercurial
|
|
# * Portable to both zsh and bash
|
|
# * Portable to both Mac (BSD-based utils) and Linux (GNU-based utils)
|
|
# * As fast as possible given the above constraints (few command invocations)
|
|
# * Avoids invoking git or mercurial, which may be slow on large repositories
|
|
#
|
|
# To use from zsh:
|
|
#
|
|
# NOTE! the single quotes are important; if you use double quotes
|
|
# then the prompt won't change when you chdir or checkout different
|
|
# branches!
|
|
#
|
|
# setopt PROMPT_SUBST
|
|
# source /path/to/scm-prompt
|
|
# export PS1='$(_scm_prompt)$USER@%m:%~%% '
|
|
#
|
|
# To use from bash:
|
|
#
|
|
# source /path/to/scm-prompt
|
|
# export PS1="\$(_scm_prompt)\u@\h:\W\$ "
|
|
#
|
|
# NOTE! You *EITHER* need to single-quote the whole thing *OR* back-slash
|
|
# the $(...) (as above), but not both. Which one you use depends on if
|
|
# you need the rest of your PS1 to interpolate variables.
|
|
#
|
|
# You may additionally pass a format-string to the scm_info command. This
|
|
# allows you to control the format of the prompt string without interfering
|
|
# with the prompt outside of a mercurial or git repository. For example:
|
|
#
|
|
# $(_scm_prompt "%s")
|
|
#
|
|
# The default format string is " (%s)" (note the space)
|
|
#
|
|
# Options: you may want to set these environment variables
|
|
# * HOME_IS_NOT_A_REPO : Stop walking up the filesystem looking for a git or
|
|
# hg repo at (but not including) /home instead of /. This helps when /home
|
|
# is a remote or autofs mount point.
|
|
# * WANT_OLD_SCM_PROMPT : Use '%s' as the formatting for the prompt instead
|
|
# of ' (%s)'
|
|
#
|
|
# Notes to developers:
|
|
#
|
|
# * Aliases can screw up the default commands. To prevent this issue, use
|
|
# the 'builtin' prefix for built-in shell commands (eg, 'cd' and 'echo')
|
|
# and use the 'command' prefix for external commands that you do not want
|
|
# to invoke aliases for (eg, 'grep', 'cut').
|
|
#
|
|
# =========================================================================
|
|
#
|
|
|
|
_find_most_relevant() {
|
|
# We don't want to output all remote bookmarks because there can be many
|
|
# of them. This function finds the most relevant remote bookmark using this
|
|
# algorithm:
|
|
# 1. If 'master' or '@' bookmark is available then output it
|
|
# 2. Sort remote bookmarks and output the first in reverse sorted order (
|
|
# it's a heuristic that tries to find the newest bookmark. It will work well
|
|
# with bookmarks like 'release20160926' and 'release20161010').
|
|
relevantbook="$(command grep -m1 -E -o "^[^/]+/(master|@)$" <<< "$1")"
|
|
if [[ -n $relevantbook ]]; then
|
|
builtin echo $relevantbook
|
|
return 0
|
|
fi
|
|
|
|
builtin echo "$(command sort -r <<< "$1" | command head -n 1)"
|
|
}
|
|
|
|
_hg_prompt() {
|
|
local hg br extra
|
|
hg="$1"
|
|
|
|
if [[ -f "$hg/bisect.state" ]]; then
|
|
extra="|BISECT"
|
|
elif [[ -f "$hg/histedit-state" ]]; then
|
|
extra="|HISTEDIT"
|
|
elif [[ -f "$hg/graftstate" ]]; then
|
|
extra="|GRAFT"
|
|
elif [[ -f "$hg/unshelverebasestate" ]]; then
|
|
extra="|UNSHELVE"
|
|
elif [[ -f "$hg/rebasestate" ]]; then
|
|
extra="|REBASE"
|
|
elif [[ -d "$hg/merge" ]]; then
|
|
extra="|MERGE"
|
|
elif [[ -L "$hg/store/lock" ]]; then
|
|
extra="|STORE-LOCKED"
|
|
elif [[ -L "$hg/wlock" ]]; then
|
|
extra="|WDIR-LOCKED"
|
|
fi
|
|
local dirstate="$( \
|
|
( [[ -f "$hg/dirstate" ]] && \
|
|
command hexdump -vn 20 -e '1/1 "%02x"' "$hg/dirstate") || \
|
|
builtin echo "empty")"
|
|
|
|
local remote="$hg/store/remotenames"
|
|
local shared_hg="$hg"
|
|
if [[ -f "$hg/sharedpath" ]]; then
|
|
shared_hg="$(command cat $hg/sharedpath)"
|
|
remote="$shared_hg/store/remotenames"
|
|
fi
|
|
|
|
local active="$hg/bookmarks.current"
|
|
if [[ -f "$active" ]]; then
|
|
br="$(command cat "$active")"
|
|
# check to see if active bookmark needs update (eg, moved after pull)
|
|
local marks="$hg/bookmarks"
|
|
if [[ -f "$hg/sharedpath" && -f "$hg/shared" ]] &&
|
|
command grep -q '^bookmarks$' "$hg/shared"; then
|
|
marks="$shared_hg/bookmarks"
|
|
fi
|
|
if [[ -z "$extra" ]] && [[ -f "$marks" ]]; then
|
|
local markstate="$(command grep " $br$" "$marks" | \
|
|
command cut -f 1 -d ' ')"
|
|
if [[ $markstate != "$dirstate" ]]; then
|
|
extra="|UPDATE_NEEDED"
|
|
fi
|
|
fi
|
|
else
|
|
br="$(builtin echo "$dirstate" | command cut -c 1-8)"
|
|
fi
|
|
if [[ -f "$remote" ]]; then
|
|
local allremotemarks="$(command grep "^$dirstate bookmarks" "$remote" | \
|
|
command cut -f 3 -d ' ')"
|
|
|
|
if [[ -n "$allremotemarks" ]]; then
|
|
local remotemark="$(_find_most_relevant "$allremotemarks")"
|
|
if [[ -n "$remotemark" ]]; then
|
|
br="$br|$remotemark"
|
|
if [[ "$remotemark" != "$allremotemarks" ]]; then
|
|
# if there is more than one, let the user know with an elipsis
|
|
br="${br}..."
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
local branch
|
|
if [[ -f "$hg/branch" ]]; then
|
|
branch="$(command cat "$hg/branch")"
|
|
if [[ "$branch" != "default" ]]; then
|
|
br="$br|$branch"
|
|
fi
|
|
fi
|
|
br="$br$extra"
|
|
builtin printf "%s" "$br"
|
|
}
|
|
|
|
_git_prompt() {
|
|
local git br
|
|
git="$1"
|
|
if [[ -f "$git/HEAD" ]]; then
|
|
read br < "$git/HEAD"
|
|
case $br in
|
|
ref:\ refs/heads/*) br=${br#ref: refs/heads/} ;;
|
|
*) br="$(builtin echo "$br" | command cut -c 1-8)" ;;
|
|
esac
|
|
if [[ -f "$git/rebase-merge/interactive" ]]; then
|
|
b="$(command cat "$git/rebase-merge/head-name")"
|
|
b="${b#refs/heads/}"
|
|
br="$br|REBASE-i|$b"
|
|
elif [[ -d "$git/rebase-merge" ]]; then
|
|
b="$(command cat "$git/rebase-merge/head-name")"
|
|
b="${b#refs/heads/}"
|
|
br="$br|REBASE-m|$b"
|
|
else
|
|
if [[ -d "$git/rebase-apply" ]]; then
|
|
if [[ -f "$git/rebase-apply/rebasing" ]]; then
|
|
b="$(command cat "$git/rebase-apply/head-name")"
|
|
b="${b#refs/heads/}"
|
|
br="$br|REBASE|$b"
|
|
elif [[ -f "$git/rebase-apply/applying" ]]; then
|
|
br="$br|AM"
|
|
else
|
|
br="$br|AM/REBASE"
|
|
fi
|
|
elif [[ -f "$git/CHERRY_PICK_HEAD" ]]; then
|
|
br="$br|CHERRY-PICKING"
|
|
elif [[ -f "$git/REVERT_HEAD" ]]; then
|
|
br="$br|REVERTING"
|
|
elif [[ -f "$git/MERGE_HEAD" ]]; then
|
|
br="$br|MERGE"
|
|
elif [[ -f "$git/BISECT_LOG" ]]; then
|
|
br="$br|BISECT"
|
|
fi
|
|
fi
|
|
fi
|
|
builtin printf "%s" "$br"
|
|
}
|
|
|
|
_scm_prompt() {
|
|
local dir fmt br
|
|
# Default to be compatable with __git_ps1. In particular:
|
|
# - provide a space for the user so that they don't have to have
|
|
# random extra spaces in their prompt when not in a repo
|
|
# - provide parens so it's differentiated from other crap in their prompt
|
|
fmt="${1:- (%s)}"
|
|
|
|
# find out if we're in a git or hg repo by looking for the control dir
|
|
dir="$PWD"
|
|
while : ; do
|
|
[[ -n "$HOME_IS_NOT_A_REPO" ]] && [[ "$dir" = "/home" ]] && break
|
|
if [[ -d "$dir/.git" ]]; then
|
|
br="$(_git_prompt "$dir/.git")"
|
|
break
|
|
elif [[ -d "$dir/.hg" ]]; then
|
|
br="$(_hg_prompt "$dir/.hg")"
|
|
break
|
|
fi
|
|
[[ "$dir" = "/" ]] && break
|
|
# portable "realpath" equivalent
|
|
dir="$(builtin cd -P "$dir/.." && builtin echo "$PWD")"
|
|
done
|
|
|
|
if [[ -n "$br" ]]; then
|
|
builtin printf "$fmt" "$br"
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Backwards-compatibility layer for odl scm-prompt script
|
|
#
|
|
# Older versions of this file at Facebook used a longer function name.
|
|
# These versions also included support for an environmental directive
|
|
# called $WANT_OLD_SCM_PROMPT. Support this to remain compatible.
|
|
#
|
|
|
|
_dotfiles_scm_info() {
|
|
local fmt
|
|
fmt=$1
|
|
if [[ -z "$fmt" ]]; then
|
|
if [[ -n "$WANT_OLD_SCM_PROMPT" ]]; then
|
|
fmt="%s"
|
|
else
|
|
fmt=' (%s)'
|
|
fi
|
|
fi
|
|
_scm_prompt "$fmt"
|
|
}
|