1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
#!/usr/bin/env bash
#
# Summary: Display help for a command
#
# Usage: pyenv help [--usage] COMMAND
#
# Parses and displays help contents from a command's source file.
#
# A command is considered documented if it starts with a comment block
# that has a `Summary:' or `Usage:' section. Usage instructions can
# span multiple lines as long as subsequent lines are indented.
# The remainder of the comment block is displayed as extended
# documentation.
set -e
[ -n "$PYENV_DEBUG" ] && set -x
# Provide pyenv completions
if [ "$1" = "--complete" ]; then
echo --usage
exec pyenv-commands
fi
command_path() {
local command="$1"
command -v pyenv-"$command" || command -v pyenv-sh-"$command" || true
}
extract_initial_comment_block() {
LC_ALL= \
LC_CTYPE=C \
sed -ne "
/^#/ !{
q
}
s/^#$/# /
/^# / {
s/^# //
p
}
"
}
collect_documentation() {
# `tail` prevents "broken pipe" errors due to `head` closing the pipe without reading everything
# https://superuser.com/questions/554855/how-can-i-fix-a-broken-pipe-error/642932#642932
$(type -P gawk awk | tail -n +1 | head -n1) '
/^Summary:/ {
summary = substr($0, 10)
next
}
/^Usage:/ {
reading_usage = 1
usage = usage "\n" $0
next
}
/^( *$| )/ && reading_usage {
usage = usage "\n" $0
next
}
{
reading_usage = 0
help = help "\n" $0
}
function escape(str) {
gsub(/[`\\$"]/, "\\\\&", str)
return str
}
function trim(str) {
sub(/^\n*/, "", str)
sub(/\n*$/, "", str)
return str
}
END {
if (usage || summary) {
print "summary=\"" escape(summary) "\""
print "usage=\"" escape(trim(usage)) "\""
print "help=\"" escape(trim(help)) "\""
}
}
'
}
documentation_for() {
local filename
filename="$(command_path "$1")"
if [ -n "$filename" ]; then
extract_initial_comment_block < "$filename" | collect_documentation
fi
}
print_summary() {
local command="$1"
local summary usage help
eval "$(documentation_for "$command")"
if [ -n "$summary" ]; then
printf " %-9s %s\n" "$command" "$summary"
fi
}
print_summaries() {
for command; do
print_summary "$command"
done
}
print_help() {
local command="$1"
local summary usage help
eval "$(documentation_for "$command")"
[ -n "$help" ] || help="$summary"
if [ -n "$usage" ] || [ -n "$summary" ]; then
if [ -n "$usage" ]; then
echo "$usage"
else
echo "Usage: pyenv ${command}"
fi
if [ -n "$help" ]; then
echo
echo "$help"
echo
fi
else
echo "Sorry, this command isn't documented yet." >&2
return 1
fi
}
print_usage() {
local command="$1"
local summary usage help
eval "$(documentation_for "$command")"
[ -z "$usage" ] || echo "$usage"
}
unset usage
if [ "$1" = "--usage" ]; then
usage="1"
shift
fi
if [ -z "$1" ] || [ "$1" == "pyenv" ]; then
echo "Usage: pyenv <command> [<args>]"
[ -z "$usage" ] || exit
echo
echo "Some useful pyenv commands are:"
print_summaries $(exec pyenv-commands | sort -u)
echo
echo "See \`pyenv help <command>' for information on a specific command."
echo "For full documentation, see: https://github.com/pyenv/pyenv#readme"
else
command="$1"
if [ -n "$(command_path "$command")" ]; then
if [ -n "$usage" ]; then
print_usage "$command"
else
print_help "$command"
fi
else
echo "pyenv: no such command \`$command'" >&2
exit 1
fi
fi
|