]> src.twobees.de Git - dotfiles.git/blob - stow/oh-my-zsh/.oh-my-zsh/lib/diagnostics.zsh
eaeba7d2313be12f843ee0ab0249a4c23076207d
[dotfiles.git] / stow / oh-my-zsh / .oh-my-zsh / lib / diagnostics.zsh
1 # diagnostics.zsh
2 #
3 # Diagnostic and debugging support for oh-my-zsh
4
5 # omz_diagnostic_dump()
6 #
7 # Author: Andrew Janke <andrew@apjanke.net>
8 #
9 # Usage:
10 #
11 # omz_diagnostic_dump [-v] [-V] [file]
12 #
13 # NOTE: This is a work in progress. Its interface and behavior are going to change,
14 # and probably in non-back-compatible ways.
15 #
16 # Outputs a bunch of information about the state and configuration of
17 # oh-my-zsh, zsh, and the user's system. This is intended to provide a
18 # bunch of context for diagnosing your own or a third party's problems, and to
19 # be suitable for posting to public bug reports.
20 #
21 # The output is human-readable and its format may change over time. It is not
22 # suitable for parsing. All the output is in one single file so it can be posted
23 # as a gist or bug comment on GitHub. GitHub doesn't support attaching tarballs
24 # or other files to bugs; otherwise, this would probably have an option to produce
25 # tarballs that contain copies of the config and customization files instead of
26 # catting them all in to one file.
27 #
28 # This is intended to be widely portable, and run anywhere that oh-my-zsh does.
29 # Feel free to report any portability issues as bugs.
30 #
31 # This is written in a defensive style so it still works (and can detect) cases when
32 # basic functionality like echo and which have been redefined. In particular, almost
33 # everything is invoked with "builtin" or "command", to work in the face of user 
34 # redefinitions.
35 #
36 # OPTIONS
37 #
38 # [file]   Specifies the output file. If not given, a file in the current directory
39 #        is selected automatically.
40 #
41 # -v    Increase the verbosity of the dump output. May be specified multiple times.
42 #       Verbosity levels:
43 #        0 - Basic info, shell state, omz configuration, git state
44 #        1 - (default) Adds key binding info and configuration file contents
45 #        2 - Adds zcompdump file contents
46 #
47 # -V    Reduce the verbosity of the dump output. May be specified multiple times.
48 #
49 # TODO:
50 # * Multi-file capture
51 # * Add automatic gist uploading
52 # * Consider whether to move default output file location to TMPDIR. More robust
53 #     but less user friendly.
54 #
55
56 autoload -Uz is-at-least
57
58 function omz_diagnostic_dump() {
59   emulate -L zsh
60
61   builtin echo "Generating diagnostic dump; please be patient..."
62   
63   local thisfcn=omz_diagnostic_dump
64   local -A opts
65   local opt_verbose opt_noverbose opt_outfile
66   local timestamp=$(date +%Y%m%d-%H%M%S)
67   local outfile=omz_diagdump_$timestamp.txt
68   builtin zparseopts -A opts -D -- "v+=opt_verbose" "V+=opt_noverbose"
69   local verbose n_verbose=${#opt_verbose} n_noverbose=${#opt_noverbose}
70   (( verbose = 1 + n_verbose - n_noverbose ))
71
72   if [[ ${#*} > 0 ]]; then
73     opt_outfile=$1
74   fi
75   if [[ ${#*} > 1 ]]; then
76     builtin echo "$thisfcn: error: too many arguments" >&2
77     return 1
78   fi
79   if [[ -n "$opt_outfile" ]]; then
80     outfile="$opt_outfile"
81   fi
82
83   # Always write directly to a file so terminal escape sequences are
84   # captured cleanly
85   _omz_diag_dump_one_big_text &> "$outfile"
86   if [[ $? != 0 ]]; then
87     builtin echo "$thisfcn: error while creating diagnostic dump; see $outfile for details"
88   fi
89
90   builtin echo
91   builtin echo Diagnostic dump file created at: "$outfile"
92   builtin echo
93   builtin echo To share this with OMZ developers, post it as a gist on GitHub 
94   builtin echo at "https://gist.github.com" and share the link to the gist.
95   builtin echo
96   builtin echo "WARNING: This dump file contains all your zsh and omz configuration files,"
97   builtin echo "so don't share it publicly if there's sensitive information in them."
98   builtin echo
99
100 }
101
102 function _omz_diag_dump_one_big_text() {
103   local program programs progfile md5
104
105   builtin echo oh-my-zsh diagnostic dump
106   builtin echo
107   builtin echo $outfile
108   builtin echo 
109   
110   # Basic system and zsh information
111   command date
112   command uname -a
113   builtin echo OSTYPE=$OSTYPE
114   builtin echo ZSH_VERSION=$ZSH_VERSION
115   builtin echo User: $USERNAME
116   builtin echo umask: $(umask)
117   builtin echo
118   _omz_diag_dump_os_specific_version
119   builtin echo
120
121   # Installed programs
122   programs=(sh zsh ksh bash sed cat grep ls find git posh)
123   local progfile="" extra_str="" sha_str=""
124   for program in $programs; do
125     extra_str="" sha_str=""
126     progfile=$(builtin which $program)
127     if [[ $? == 0 ]]; then
128       if [[ -e $progfile ]]; then
129         if builtin whence shasum &>/dev/null; then
130           sha_str=($(command shasum $progfile))
131           sha_str=$sha_str[1]
132           extra_str+=" SHA $sha_str"
133         fi
134         if [[ -h "$progfile" ]]; then
135           extra_str+=" ( -> ${progfile:A} )"
136         fi
137       fi
138       builtin printf '%-9s %-20s %s\n' "$program is" "$progfile" "$extra_str"
139     else
140       builtin echo "$program: not found"
141     fi
142   done
143   builtin echo
144   builtin echo Command Versions:
145   builtin echo "zsh: $(zsh --version)"
146   builtin echo "this zsh session: $ZSH_VERSION"
147   builtin echo "bash: $(bash --version | command grep bash)"
148   builtin echo "git: $(git --version)"
149   builtin echo "grep: $(grep --version)"
150   builtin echo
151
152   # Core command definitions
153   _omz_diag_dump_check_core_commands || return 1
154   builtin echo  
155
156   # ZSH Process state
157   builtin echo Process state:
158   builtin echo pwd: $PWD
159   if builtin whence pstree &>/dev/null; then
160     builtin echo Process tree for this shell:
161     pstree -p $$
162   else
163     ps -fT
164   fi
165   builtin set | command grep -a '^\(ZSH\|plugins\|TERM\|LC_\|LANG\|precmd\|chpwd\|preexec\|FPATH\|TTY\|DISPLAY\|PATH\)\|OMZ'
166   builtin echo
167   #TODO: Should this include `env` instead of or in addition to `export`?
168   builtin echo Exported:
169   builtin echo $(builtin export | command sed 's/=.*//')
170   builtin echo 
171   builtin echo Locale:
172   command locale
173   builtin echo
174
175   # Zsh installation and configuration
176   builtin echo Zsh configuration:
177   builtin echo setopt: $(builtin setopt)
178   builtin echo
179   builtin echo zstyle:
180   builtin zstyle
181   builtin echo
182   builtin echo 'compaudit output:'
183   compaudit
184   builtin echo 
185   builtin echo '$fpath directories:'
186   command ls -lad $fpath
187   builtin echo
188
189   # Oh-my-zsh installation
190   builtin echo oh-my-zsh installation:
191   command ls -ld ~/.z*
192   command ls -ld ~/.oh*
193   builtin echo
194   builtin echo oh-my-zsh git state:
195   (builtin cd $ZSH && builtin echo "HEAD: $(git rev-parse HEAD)" && git remote -v && git status | command grep "[^[:space:]]")
196   if [[ $verbose -ge 1 ]]; then
197     (builtin cd $ZSH && git reflog --date=default | command grep pull)
198   fi
199   builtin echo
200   if [[ -e $ZSH_CUSTOM ]]; then
201     local custom_dir=$ZSH_CUSTOM
202     if [[ -h $custom_dir ]]; then
203       custom_dir=$(builtin cd $custom_dir && pwd -P)
204     fi
205     builtin echo "oh-my-zsh custom dir:"
206     builtin echo "   $ZSH_CUSTOM ($custom_dir)"
207     (builtin cd ${custom_dir:h} && command find ${custom_dir:t} -name .git -prune -o -print)
208     builtin echo
209   fi
210
211   # Key binding and terminal info
212   if [[ $verbose -ge 1 ]]; then
213     builtin echo "bindkey:"
214     builtin bindkey
215     builtin echo
216     builtin echo "infocmp:"
217     command infocmp -L
218     builtin echo
219   fi
220
221   # Configuration file info
222   local zdotdir=${ZDOTDIR:-$HOME}
223   builtin echo "Zsh configuration files:"
224   local cfgfile cfgfiles
225   # Some files for bash that zsh does not use are intentionally included
226   # to help with diagnosing behavior differences between bash and zsh
227   cfgfiles=( /etc/zshenv /etc/zprofile /etc/zshrc /etc/zlogin /etc/zlogout 
228     $zdotdir/.zshenv $zdotdir/.zprofile $zdotdir/.zshrc $zdotdir/.zlogin $zdotdir/.zlogout
229     ~/.zsh.pre-oh-my-zsh
230     /etc/bashrc /etc/profile ~/.bashrc ~/.profile ~/.bash_profile ~/.bash_logout )
231   command ls -lad $cfgfiles 2>&1
232   builtin echo
233   if [[ $verbose -ge 1 ]]; then
234     for cfgfile in $cfgfiles; do
235       _omz_diag_dump_echo_file_w_header $cfgfile
236     done
237   fi
238   builtin echo
239   builtin echo "Zsh compdump files:"
240   local dumpfile dumpfiles
241   command ls -lad $zdotdir/.zcompdump*
242   dumpfiles=( $zdotdir/.zcompdump*(N) )
243   if [[ $verbose -ge 2 ]]; then
244     for dumpfile in $dumpfiles; do
245       _omz_diag_dump_echo_file_w_header $dumpfile
246     done
247   fi
248
249 }
250
251 function _omz_diag_dump_check_core_commands() {
252   builtin echo "Core command check:"
253   local redefined name builtins externals reserved_words
254   redefined=()
255   # All the zsh non-module builtin commands
256   # These are taken from the zsh reference manual for 5.0.2
257   # Commands from modules should not be included.
258   # (For back-compatibility, if any of these are newish, they should be removed,
259   # or at least made conditional on the version of the current running zsh.)
260   # "history" is also excluded because OMZ is known to redefine that
261   reserved_words=( do done esac then elif else fi for case if while function 
262     repeat time until select coproc nocorrect foreach end '!' '[[' '{' '}' 
263     )
264   builtins=( alias autoload bg bindkey break builtin bye cd chdir command
265     comparguments compcall compctl compdescribe compfiles compgroups compquote comptags
266     comptry compvalues continue dirs disable disown echo echotc echoti emulate
267     enable eval exec exit false fc fg functions getln getopts hash
268     jobs kill let limit log logout noglob popd print printf
269     pushd pushln pwd r read rehash return sched set setopt shift
270     source suspend test times trap true ttyctl type ulimit umask unalias
271     unfunction unhash unlimit unset unsetopt vared wait whence where which zcompile
272     zle zmodload zparseopts zregexparse zstyle )
273   if is-at-least 5.1; then
274     reserved_word+=( declare export integer float local readonly typeset )
275   else
276     builtins+=( declare export integer float local readonly typeset )
277   fi
278   builtins_fatal=( builtin command local )
279   externals=( zsh )
280   for name in $reserved_words; do
281     if [[ $(builtin whence -w $name) != "$name: reserved" ]]; then
282       builtin echo "reserved word '$name' has been redefined"
283       builtin which $name
284       redefined+=$name
285     fi
286   done
287   for name in $builtins; do
288     if [[ $(builtin whence -w $name) != "$name: builtin" ]]; then
289       builtin echo "builtin '$name' has been redefined"
290       builtin which $name
291       redefined+=$name
292     fi
293   done
294   for name in $externals; do
295     if [[ $(builtin whence -w $name) != "$name: command" ]]; then
296       builtin echo "command '$name' has been redefined"
297       builtin which $name
298       redefined+=$name
299     fi
300   done
301
302   if [[ -n "$redefined" ]]; then
303     builtin echo "SOME CORE COMMANDS HAVE BEEN REDEFINED: $redefined"
304   else
305     builtin echo "All core commands are defined normally"
306   fi
307
308 }
309
310 function _omz_diag_dump_echo_file_w_header() {
311   local file=$1
312   if [[ ( -f $file || -h $file ) ]]; then
313     builtin echo "========== $file =========="
314     if [[ -h $file ]]; then
315       builtin echo "==========    ( => ${file:A} )   =========="
316     fi
317     command cat $file
318     builtin echo "========== end $file =========="
319     builtin echo
320   elif [[ -d $file ]]; then
321     builtin echo "File '$file' is a directory"
322   elif [[ ! -e $file ]]; then
323     builtin echo "File '$file' does not exist"
324   else
325     command ls -lad "$file"
326   fi
327 }
328
329 function _omz_diag_dump_os_specific_version() {
330   local osname osver version_file version_files
331   case "$OSTYPE" in
332     darwin*)
333       osname=$(command sw_vers -productName)
334       osver=$(command sw_vers -productVersion)      
335       builtin echo "OS Version: $osname $osver build $(sw_vers -buildVersion)"
336       ;;
337     cygwin)
338       command systeminfo | command head -n 4 | command tail -n 2
339       ;;
340   esac
341
342   if builtin which lsb_release >/dev/null; then
343     builtin echo "OS Release: $(command lsb_release -s -d)"
344   fi
345
346   version_files=( /etc/*-release(N) /etc/*-version(N) /etc/*_version(N) )
347   for version_file in $version_files; do
348     builtin echo "$version_file:"
349     command cat "$version_file"
350     builtin echo
351   done
352 }
353