-
Notifications
You must be signed in to change notification settings - Fork 0
/
fig_prompt
282 lines (259 loc) · 9.12 KB
/
fig_prompt
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#!/bin/zsh
# Common global variables that specify what to cache where.
FIG_CACHE_BASE_DIR=/tmp/fig-cache
FIG_STATE_INDICATOR_FILES=(".hg/blackbox.log" ".citc/manifest.rawproto")
FIG_STATUS_FILE="status.txt"
FIG_STATE_HASH_FILE="state.hash"
# Lines from .blackbox.log matching the following pattern will be ignored for
# hash computation and thus will prevent the status being updated. Add commands
# in here that do not change the Fig state.
BLACKBOX_IGNORE=">.*(xl|ll|figstatus|status|diff|root|exportedcl|preloading|debugfetchconfig)"
# Choose an md5 tool that's available.
if command -v md5sum >> /dev/null; then
MD5TOOL=md5sum
elif command -v md5 >> /dev/null; then
MD5TOOL=md5
else
MD5TOOL=cat
fi
# Returns the root directory of the current Fig client. Should only be called
# from within a Fig client.
function get_fig_client_root() {
local root_dir="${$(pwd -P)%/google3*}"
echo "$root_dir"
}
# Returns the name of the current Fig client. Should only be called from within
# a Fig client.
function get_fig_client_name() {
local root_dir="$( get_fig_client_root )"
local client_name="${root_dir##/*google/*/}"
echo "$client_name"
}
# Returns the directory where we cache the status for the current Fig client.
function get_fig_client_cache_dir() {
[ ! -d "$FIG_CACHE_BASE_DIR" ] && mkdir "$FIG_CACHE_BASE_DIR"
client_name=$( get_fig_client_name )
client_cache_dir="$FIG_CACHE_BASE_DIR/$client_name"
# Make sure the cache dir exists.
[ ! -d "$client_cache_dir" ] && mkdir "$client_cache_dir"
echo "$client_cache_dir"
}
# Returns the hash of the file state of the current Fig client.
function get_fig_client_state_hash() {
local state_hash=""
local -a state_files
for file in ${FIG_STATE_INDICATOR_FILES}; do
file="$( get_fig_client_root )/${file}"
if [ -f "$file" ]; then
if [[ "$file" =~ ".*blackbox.log" ]]; then
state_hash="${state_hash}\n$( egrep -a -v "${BLACKBOX_IGNORE}" "$file" \
| ${MD5TOOL} )"
else
state_hash="${state_hash}\n$( ${MD5TOOL} "$file" )"
fi
fi
done
echo "$state_hash"
}
# Returns 0 if the status cache for the current Fig client is outdated and
# needs to be updated and 1 otherwise. Should only be called from within a Fig
# client.
function should_update_fig_status_cache() {
local state_hash="$( get_fig_client_state_hash )"
local cached_state_hash="emptycache"
local cached_state_hash_file
cached_state_hash_file="$( get_fig_client_cache_dir )/$FIG_STATE_HASH_FILE"
if [ -f "$cached_state_hash_file" ]; then
cached_state_hash=$(<"$cached_state_hash_file")
fi
if [ "$cached_state_hash" != "$state_hash" ]; then
# Update cache since the state hash has changed.
return 0
fi
# Do not update cache.
return 1
}
# Updates the status cache for the current Fig client. Should only be called
# from within a Fig client.
function update_fig_status_cache() {
local status_file="$( get_fig_client_cache_dir )/$FIG_STATUS_FILE"
hg figstatus >! "$status_file"
local state_hash="$( get_fig_client_state_hash )"
local cached_state_hash_file
cached_state_hash_file="$( get_fig_client_cache_dir )/$FIG_STATE_HASH_FILE"
echo "$state_hash" >! "$cached_state_hash_file"
}
# Returns a multi-line output of the status of the current Fig client by either
# looking the status up in the cache file if the cache is current or loading it
# directly from Fig and updating the cache. Should only be called from within a
# Fig client.
function fig_status() {
if should_update_fig_status_cache; then
update_fig_status_cache
fi
local status_file="$( get_fig_client_cache_dir )/$FIG_STATUS_FILE"
cat "$status_file"
}
# Returns whether the current directory is (likely) a Fig-on-CITC client.
function is_fig_client() {
if [[ "$(pwd -P)" =~ /google/src/cloud/$USER/* ]] && \
[[ -d ${$(pwd -P)%%/google3*}/.hg ]]; then
return 0
fi
return 1
}
# Returns a pseudo-template string that can be used by get_fig_prompt to create
# a ZSH Fig prompt.
#
# The prompt returned by get_fig_prompt can be easily customized by overriding
# this function.
#
# Template Arguments:
# FIG_PROMPT_MODIFIED: Replaced with $modified
# FIG_PROMPT_ADDED: Replaced with $added
# FIG_PROMPT_DELETED: Replaced with $deleted
# FIG_PROMPT_UNKNOWN: Replaced with $unknown
# FIG_PROMPT_UNEXPORTED: Replaced with $unexported
# FIG_PROMPT_OBSOLETE: Replaced with $obsolete
# FIG_PROMPT_CL: Replaced with $cl
# FIG_PROMPT_DESCRIPTION: Replaced with $description
# FIG_PROMPT_CHANGENAME: Replaced with $changename
# FIG_PROMPT_HAS_SHELVE: Replaced with $has_shelve
# FIG_PROMPT_SHORT: Replaced with $short
function get_fig_prompt_template() {
echo -n '%b:%B%F{white}['
echo -n '%F{yellow}FIG_PROMPT_MODIFIED%F{green}FIG_PROMPT_ADDED'
echo -n '%F{red}FIG_PROMPT_DELETED%F{cyan}FIG_PROMPT_UNKNOWN'
echo -n '%F{magenta}FIG_PROMPT_HAS_SHELVE%F{white}FIG_PROMPT_CHANGENAME'
echo -n '%F{green}FIG_PROMPT_UNEXPORTED%F{red}FIG_PROMPT_OBSOLETE'
echo -n '%F{white}]%b'
}
# Returns a string that can be used in a ZSH prompt to display the status of
# the current Fig client.
function get_fig_prompt() {
if ! is_fig_client; then
return 0
fi
figstatus=("${(@f)$( fig_status )}")
modified=$figstatus[1]
added=$figstatus[2]
deleted=$figstatus[3]
unknown=$figstatus[4]
unexported=$figstatus[5]
obsolete=$figstatus[6]
# Turn the cl number into a hyperlink.
# This can be disabled by setting the environment variable
# "FIG_PROMPT_NO_HYPERLINKS=1"
#
# This works in most terminals. Complete list can be found
# here: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
# According to the above link, there is no way to reliably determine whether
# a terminal emulator supports hyperlinks. Use color support as a way to
# attempt to determine hyperlink support. If a terminal emulator supports
# > 8 colors, it likely supports hyperlinks.
COLORS=$(tput colors 2> /dev/null)
if [ $? != 0 ] || [ $COLORS -le 8 ] || [ "${FIG_PROMPT_NO_HYPERLINKS:-unset}" != "unset" ]; then
# Colors are not supported; although this does not mean that hyperlinks
# are not supported, we will disable by default.
cl=$figstatus[7]
else
# Colors are supported; enable hyperlinks
cl="\e]8;;http://cl/${figstatus[7]}\e\\\\${figstatus[7]}\e]8;;\e\\\\ "
fi
description=$figstatus[8]
branch=$figstatus[9]
if [ -z "$branch" ]; then
branch="$cl"
fi
changename=$figstatus[13]
if [ -z "$changename" ]; then
changename="$branch"
fi
has_shelve=""
# POSIX-compatible way to check whether shelved-directory is non-empty.
shelve_dir="$( get_fig_client_root )/.hg/shelved/"
if [ -d "$shelve_dir" ] && /bin/ls -1qA "$shelve_dir" | grep -q .; then
has_shelve="!"
fi
short=$figstatus[14]
local tpl="$(get_fig_prompt_template)"
tpl="${tpl//FIG_PROMPT_MODIFIED/$modified}"
tpl="${tpl//FIG_PROMPT_ADDED/$added}"
tpl="${tpl//FIG_PROMPT_DELETED/$deleted}"
tpl="${tpl//FIG_PROMPT_UNKNOWN/$unknown}"
tpl="${tpl//FIG_PROMPT_UNEXPORTED/$unexported}"
tpl="${tpl//FIG_PROMPT_OBSOLETE/$obsolete}"
tpl="${tpl//FIG_PROMPT_CL/$cl}"
tpl="${tpl//FIG_PROMPT_DESCRIPTION/$description}"
tpl="${tpl//FIG_PROMPT_CHANGENAME/$changename}"
tpl="${tpl//FIG_PROMPT_HAS_SHELVE/$has_shelve}"
tpl="${tpl//FIG_PROMPT_SHORT/$short}"
echo "$tpl"
}
typeset -Ag FIG_STATUS_INDICES
FIG_STATUS_INDICES[modified]=1
FIG_STATUS_INDICES[added]=2
FIG_STATUS_INDICES[deleted]=3
FIG_STATUS_INDICES[unknown]=4
FIG_STATUS_INDICES[unexported]=5
FIG_STATUS_INDICES[obsolete]=6
FIG_STATUS_INDICES[cl]=7
FIG_STATUS_INDICES[description]=8
FIG_STATUS_INDICES[branch]=9
FIG_STATUS_INDICES[changename]=13
# Returns the value of the specified property in the current Fig repository.
# While not as fast as get_fig_prompt, allows for personal configuration of the
# prompt string in a user's zshrc.
#
# TODO(cclausen): This would be far more convenient (and likely quicker) if we
# could pass around an associative array instead of reparsing the output for
# each property being used.
#
# Example usage:
# function my_hg_prompt {
# echo "$(fig_prop "modified") $(fig_prop "cl") $(fig_prop "description")"
# }
# PROMPT='%n@%m[$(my_hg_prompt)] %#'
#
# Prompt output:
# user@host[? 181818181 Excerpt from CL description] %
#
# Valid properties (from figstatus):
# modified
# added
# deleted
# unknown
# unexported
# obsolete
# cl
# description
# branch
function fig_prop() {
if ! is_fig_client; then
return 0
fi
figstatus=("${(@f)$( fig_status )}")
echo "${figstatus[$FIG_STATUS_INDICES[$1]]}"
}
# Collects the properties of the current Fig repository into the FIG_PROPS
# global associative array.
#
# Example usage:
# function my_hg_prompt {
# collect_fig_props
# echo "${FIG_PROPS["modified"]} ${FIG_PROPS["cl"]} ${FIG_PROPS["description"]}"
# }
# PROMPT='%n@%m[$(my_hg_prompt)] %#'
#
# See fig_prop for a list of valid properties
function collect_fig_props() {
if ! is_fig_client; then
return 0
fi
typeset -Ag FIG_PROPS
figstatus=("${(@f)$( fig_status )}")
# Map to global associative array FIG_PROPS
for index in "${(@k)FIG_STATUS_INDICES}" ; do
FIG_PROPS[${index}]="${figstatus[${FIG_STATUS_INDICES[${index}]}]}"
done
}