diagnostics.zsh 9.9 KB

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