From ea6adc5a0a3332e541a812a2da0e94c73e2102da Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Fri, 29 May 2015 22:59:07 -0400 Subject: [PATCH 1/8] Add omz_diagnostic_dump() to help with bug reports. --- lib/diagnostics.zsh | 280 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 lib/diagnostics.zsh diff --git a/lib/diagnostics.zsh b/lib/diagnostics.zsh new file mode 100644 index 000000000..cca13f4e4 --- /dev/null +++ b/lib/diagnostics.zsh @@ -0,0 +1,280 @@ +# diagnostics.zsh +# +# Diagnostic and debugging support for oh-my-zsh + +# omz_diagnostic_dump() +# +# Author: Andrew Janke +# +# Usage: +# +# omz_diagnostic_dump [-v] [-V] [file] +# +# NOTE: This is a work in progress. Its interface and behavior are going to change, +# and probably in non-back-compatible ways. +# +# Outputs a bunch of information about the state and configuration of +# oh-my-zsh, zsh, and the user's system. This is intended to provide a +# bunch of context for diagnosing your own or a third party's problems, and to +# be suitable for posting to public bug reports. +# +# The output is human-readable and its format may change over time. It is not +# suitable for parsing. All the output is in one single file so it can be posted +# as a gist or bug comment on GitHub. GitHub doesn't support attaching tarballs +# or other files to bugs; otherwise, this would probably have an option to produce +# tarballs that contain copies of the config and customization files instead of +# catting them all in to one file. +# +# This is intended to be widely portable, and run anywhere that oh-my-zsh does. +# Feel free to report any portability issues as bugs. +# +# This is written in a defensive style so it still works (and can detect) cases when +# basic functionality like echo and which have been redefined. In particular, almost +# everything is invoked with "builtin" or "command", to work in the face of user +# redefinitions. +# +# OPTIONS +# +# [file] Specifies the output file. If not given, a file in the current directory +# is selected automatically. +# +# -v Increase the verbosity of the dump output. May be specified multiple times. +# Verbosity levels: +# 0 - Basic info, shell state, omz configuration, git state +# 1 - (default) Adds key binding info and configuration file contents +# 2 - Adds zcompdump file contents +# +# -V Reduce the verbosity of the dump output. May be specified multiple times. +# +# TODO: +# * Multi-file capture +# * Add automatic gist uploading +# * Consider whether to move default output file location to TMPDIR. More robust +# but less user friendly. +# +function omz_diagnostic_dump() { + emulate -L zsh + + local thisfcn=omz_diagnostic_dump + local -A opts + local opt_verbose opt_noverbose opt_outfile + local timestamp=$(date +%Y%m%d-%H%M%S) + local outfile=omz_diagdump_$timestamp.txt + builtin zparseopts -A opts -D -- "v+=opt_verbose" "V+=opt_noverbose" + local verbose n_verbose=${#opt_verbose} n_noverbose=${#opt_noverbose} + (( verbose = 1 + n_verbose - n_noverbose )) + + if [[ ${#*} > 0 ]]; then + opt_outfile=$1 + fi + if [[ ${#*} > 1 ]]; then + builtin echo "$thisfcn: error: too many arguments" >&2 + return 1 + fi + if [[ -n "$opt_outfile" ]]; then + outfile="$opt_outfile" + fi + + # Always write directly to a file so terminal escape sequences are + # captured cleanly + _omz_diag_dump_one_big_text &> "$outfile" + if [[ $? != 0 ]]; then + builtin echo "$thisfcn: error while creating diagnostic dump; see $outfile for details" + fi + + builtin echo + builtin echo Diagnostic dump file created at: "$outfile" + builtin echo + builtin echo To share this with OMZ developers, post it as a gist on GitHub + builtin echo at "https://gist.github.com" and share the link to the gist. + builtin echo + builtin echo "WARNING: This dump file contains all your zsh and omz configuration files," + builtin echo "so don't share it publicly if there's sensitive information in them." + builtin echo + +} + +function _omz_diag_dump_one_big_text() { + local program programs progfile md5 + + builtin echo oh-my-zsh diagnostic dump + builtin echo + + # Basic system and zsh information + command date + command uname -a + builtin echo OSTYPE=$OSTYPE + command zsh --version + builtin echo User: $USER + builtin echo + + # Installed programs + programs=(sh zsh ksh bash sed cat grep find git posh) + for program in $programs; do + local md5_str="" md5="" link_str="" extra_str="" + progfile=$(builtin which $program) + if [[ $? == 0 ]]; then + if [[ -e $progfile ]]; then + if builtin whence md5 &>/dev/null; then + extra_str+=" $(md5 -q $progfile)" + fi + if [[ -h "$progfile" ]]; then + extra_str+=" ( -> ${file:A} )" + fi + fi + builtin printf '%-9s %-20s %s\n' "$program is" "$progfile" "$extra_str" + else + builtin echo "$program: not found" + fi + done + builtin echo + builtin echo Versions: + builtin echo "zsh: $(zsh --version)" + builtin echo "bash: $(bash --version | command grep bash)" + builtin echo "git: $(git --version)" + builtin echo "grep: $(grep --version)" + builtin echo + + # Core command definitions + _omz_diag_dump_check_core_commands || return 1 + builtin echo + + # ZSH Process state + builtin echo Process state: + builtin echo pwd: $PWD + if builtin whence pstree &>/dev/null; then + builtin echo Process tree for this shell: + pstree -p $$ + else + ps -fT + fi + builtin set | command grep -a '^\(ZSH\|plugins\|TERM\|LC_\|LANG\|precmd\|chpwd\|preexec\|FPATH\|TTY\|DISPLAY\|PATH\)\|OMZ' + builtin echo + #TODO: Should this include `env` instead of or in addition to `export`? + builtin echo Exported: + builtin echo $(builtin export | command sed 's/=.*//') + builtin echo + builtin echo Locale: + command locale + builtin echo + + # Zsh configuration + builtin echo Zsh configuration: + builtin echo setopt: $(builtin setopt) + builtin echo + + # Oh-my-zsh installation + builtin echo oh-my-zsh installation: + command ls -ld ~/.z* + command ls -ld ~/.oh* + builtin echo + builtin echo oh-my-zsh git state: + (cd $ZSH && builtin echo "HEAD: $(git rev-parse HEAD)" && git remote -v && git status | command grep "[^[:space:]]") + if [[ $verbose -ge 1 ]]; then + (cd $ZSH && git reflog --date=default | command grep pull) + fi + builtin echo + if [[ -e $ZSH_CUSTOM ]]; then + local custom_dir=$ZSH_CUSTOM + if [[ -h $custom_dir ]]; then + custom_dir=$(cd $custom_dir && pwd -P) + fi + builtin echo "oh-my-zsh custom dir:" + builtin echo " $ZSH_CUSTOM ($custom_dir)" + (cd ${custom_dir:h} && command find ${custom_dir:t} -name .git -prune -o -print) + builtin echo + fi + + # Key binding and terminal info + if [[ $verbose -ge 1 ]]; then + builtin echo "bindkey:" + builtin bindkey + builtin echo + builtin echo "infocmp:" + command infocmp + builtin echo + fi + + # Configuration file info + local zdotdir=${ZDOTDIR:-$HOME} + builtin echo "Zsh configuration files:" + local cfgfile cfgfiles + cfgfiles=( /etc/zshenv /etc/zprofile /etc/zshrc /etc/zlogin /etc/zlogout + $zdotdir/.zshenv $zdotdir/.zprofile $zdotdir/.zshrc $zdotdir/.zlogin $zdotdir/.zlogout ) + command ls -lad $cfgfiles 2>&1 + builtin echo + if [[ $verbose -ge 1 ]]; then + for cfgfile in $cfgfiles; do + _omz_diag_dump_echo_file_w_header $cfgfile + done + fi + builtin echo "Zsh compdump files:" + local dumpfile dumpfiles + command ls -lad $zdotdir/.zcompdump* + dumpfiles=( $zdotdir/.zcompdump*(N) ) + if [[ $verbose -ge 2 ]]; then + for dumpfile in $dumpfiles; do + _omz_diag_dump_echo_file_w_header $dumpfile + done + fi + +} + +function _omz_diag_dump_check_core_commands() { + builtin echo "Core command check:" + local redefined name builtins externals + redefined=() + # All the zsh non-module builtin commands + # These are taken from the zsh reference manual for 5.0.2 + # Commands from modules should not be included. + # (For back-compatibility, if any of these are newish, they should be removed, + # or at least made conditional on the version of the current running zsh.) + # "history" is also excluded because OMZ is known to redefine that + builtins=( alias autoload bg bindkey break builtin bye cd chdir command + comparguments compcall compctl compdescribe compfiles compgroups compquote comptags + comptry compvalues continue declare dirs disable disown echo echotc echoti emulate + enable eval exec exit export false fc fg float functions getln getopts hash + integer jobs kill let limit local log logout noglob popd print printf + pushd pushln pwd r read readonly rehash return sched set setopt shift + source suspend test times trap true ttyctl type typeset ulimit umask unalias + unfunction unhash unlimit unset unsetopt vared wait whence where which zcompile + zle zmodload zparseopts zregexparse zstyle ) + builtins_fatal=( builtin command local ) + externals=( zsh ) + for name in $builtins; do + if [[ $(builtin whence -w $name) != "$name: builtin" ]]; then + builtin echo "builtin '$name' has been redefined" + builtin which $name + redefined+=$name + fi + done + for name in $externals; do + if [[ $(builtin whence -w $name) != "$name: command" ]]; then + builtin echo "command '$name' has been redefined" + builtin which $name + redefined+=$name + fi + done + + if [[ -n "$redefined" ]]; then + builtin echo "SOME CORE COMMANDS HAVE BEEN REDEFINED: $redefined" + else + builtin echo "All core commands are defined normally" + fi + +} + +function _omz_diag_dump_echo_file_w_header() { + local file=$1 + if [[ ( -f $file || -h $file ) ]]; then + builtin echo "========== $file ==========" + if [[ -h $file ]]; then + builtin echo "========== ( => ${file:A} ) ==========" + fi + command cat $file + builtin echo "========== end $file ==========" + builtin echo + fi +} + + From 82c1288cb25b1567b4d17f33a75192de1b9f4634 Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Sat, 6 Jun 2015 01:19:29 -0400 Subject: [PATCH 2/8] Include some bash rc files; improve formatting; more version info --- lib/diagnostics.zsh | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/diagnostics.zsh b/lib/diagnostics.zsh index cca13f4e4..7991b64c8 100644 --- a/lib/diagnostics.zsh +++ b/lib/diagnostics.zsh @@ -104,12 +104,12 @@ function _omz_diag_dump_one_big_text() { command date command uname -a builtin echo OSTYPE=$OSTYPE - command zsh --version + builtin echo ZSH_VERSION=$ZSH_VERSION builtin echo User: $USER builtin echo # Installed programs - programs=(sh zsh ksh bash sed cat grep find git posh) + programs=(sh zsh ksh bash sed cat grep ls find git posh) for program in $programs; do local md5_str="" md5="" link_str="" extra_str="" progfile=$(builtin which $program) @@ -119,7 +119,7 @@ function _omz_diag_dump_one_big_text() { extra_str+=" $(md5 -q $progfile)" fi if [[ -h "$progfile" ]]; then - extra_str+=" ( -> ${file:A} )" + extra_str+=" ( -> ${progfile:A} )" fi fi builtin printf '%-9s %-20s %s\n' "$program is" "$progfile" "$extra_str" @@ -128,8 +128,9 @@ function _omz_diag_dump_one_big_text() { fi done builtin echo - builtin echo Versions: + builtin echo Command Versions: builtin echo "zsh: $(zsh --version)" + builtin echo "this zsh session: $ZSH_VERSION" builtin echo "bash: $(bash --version | command grep bash)" builtin echo "git: $(git --version)" builtin echo "grep: $(grep --version)" @@ -199,8 +200,12 @@ function _omz_diag_dump_one_big_text() { local zdotdir=${ZDOTDIR:-$HOME} builtin echo "Zsh configuration files:" local cfgfile cfgfiles + # Some files for bash that zsh does not use are intentionally included + # to help with diagnosing behavior differences between bash and zsh cfgfiles=( /etc/zshenv /etc/zprofile /etc/zshrc /etc/zlogin /etc/zlogout - $zdotdir/.zshenv $zdotdir/.zprofile $zdotdir/.zshrc $zdotdir/.zlogin $zdotdir/.zlogout ) + $zdotdir/.zshenv $zdotdir/.zprofile $zdotdir/.zshrc $zdotdir/.zlogin $zdotdir/.zlogout + ~/.zsh-pre-oh-my-zsh + /etc/bashrc /etc/profile ~/.bashrc ~/.profile ~/.bash_profile ~/.bash_logout ) command ls -lad $cfgfiles 2>&1 builtin echo if [[ $verbose -ge 1 ]]; then @@ -208,6 +213,7 @@ function _omz_diag_dump_one_big_text() { _omz_diag_dump_echo_file_w_header $cfgfile done fi + builtin echo builtin echo "Zsh compdump files:" local dumpfile dumpfiles command ls -lad $zdotdir/.zcompdump* @@ -274,6 +280,12 @@ function _omz_diag_dump_echo_file_w_header() { command cat $file builtin echo "========== end $file ==========" builtin echo + elif [[ -d $file ]]; then + builtin echo "File '$file' is a directory" + elif [[ ! -e $file ]]; then + builtin echo "File '$file' does not exist" + else + command ls -lad "$file" fi } From afadb5a7fba061bc1b6da1df3b00e20ede4a5cba Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Sat, 6 Jun 2015 11:04:14 -0400 Subject: [PATCH 3/8] diagnostics: add zstyle state to output --- lib/diagnostics.zsh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/diagnostics.zsh b/lib/diagnostics.zsh index 7991b64c8..6dede0664 100644 --- a/lib/diagnostics.zsh +++ b/lib/diagnostics.zsh @@ -163,6 +163,9 @@ function _omz_diag_dump_one_big_text() { builtin echo Zsh configuration: builtin echo setopt: $(builtin setopt) builtin echo + builtin echo zstyle: + builtin zstyle + builtin echo # Oh-my-zsh installation builtin echo oh-my-zsh installation: From af68165207ea757e303fdbab365ac9e3f11c8530 Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Sat, 6 Jun 2015 11:50:05 -0400 Subject: [PATCH 4/8] Fix name of backed-up zshrc --- lib/diagnostics.zsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/diagnostics.zsh b/lib/diagnostics.zsh index 6dede0664..023ba42b9 100644 --- a/lib/diagnostics.zsh +++ b/lib/diagnostics.zsh @@ -207,7 +207,7 @@ function _omz_diag_dump_one_big_text() { # to help with diagnosing behavior differences between bash and zsh cfgfiles=( /etc/zshenv /etc/zprofile /etc/zshrc /etc/zlogin /etc/zlogout $zdotdir/.zshenv $zdotdir/.zprofile $zdotdir/.zshrc $zdotdir/.zlogin $zdotdir/.zlogout - ~/.zsh-pre-oh-my-zsh + ~/.zsh.pre-oh-my-zsh /etc/bashrc /etc/profile ~/.bashrc ~/.profile ~/.bash_profile ~/.bash_logout ) command ls -lad $cfgfiles 2>&1 builtin echo From 9813ff5f24c6ce8409490d7ef8b8c4458f2a6a66 Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Sun, 28 Jun 2015 16:54:04 -0400 Subject: [PATCH 5/8] omz_diagnostic_dump: Add umask and $fpath listing. This helps catch issues with compinit and insecure directories. --- lib/diagnostics.zsh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/diagnostics.zsh b/lib/diagnostics.zsh index 023ba42b9..f5f15deaa 100644 --- a/lib/diagnostics.zsh +++ b/lib/diagnostics.zsh @@ -106,6 +106,7 @@ function _omz_diag_dump_one_big_text() { builtin echo OSTYPE=$OSTYPE builtin echo ZSH_VERSION=$ZSH_VERSION builtin echo User: $USER + builtin echo umask: $(umask) builtin echo # Installed programs @@ -159,13 +160,19 @@ function _omz_diag_dump_one_big_text() { command locale builtin echo - # Zsh configuration + # Zsh installation and configuration builtin echo Zsh configuration: builtin echo setopt: $(builtin setopt) builtin echo builtin echo zstyle: builtin zstyle builtin echo + builtin echo 'compaudit output:' + compaudit + builtin echo + builtin echo '$fpath directories:' + command ls -lad $fpath + builtin echo # Oh-my-zsh installation builtin echo oh-my-zsh installation: @@ -195,7 +202,7 @@ function _omz_diag_dump_one_big_text() { builtin bindkey builtin echo builtin echo "infocmp:" - command infocmp + command infocmp -L builtin echo fi From bca720fa9549f7fe4687acd1aaf91720428657e9 Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Thu, 9 Jul 2015 20:50:57 -0400 Subject: [PATCH 6/8] diagnostics: include detailed OS version info if possible --- lib/diagnostics.zsh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/diagnostics.zsh b/lib/diagnostics.zsh index f5f15deaa..53c6548de 100644 --- a/lib/diagnostics.zsh +++ b/lib/diagnostics.zsh @@ -55,6 +55,8 @@ function omz_diagnostic_dump() { emulate -L zsh + builtin echo "Generating diagnostic dump; please be patient..." + local thisfcn=omz_diagnostic_dump local -A opts local opt_verbose opt_noverbose opt_outfile @@ -108,6 +110,8 @@ function _omz_diag_dump_one_big_text() { builtin echo User: $USER builtin echo umask: $(umask) builtin echo + _omz_diag_dump_os_specific_version + builtin echo # Installed programs programs=(sh zsh ksh bash sed cat grep ls find git posh) @@ -299,4 +303,28 @@ function _omz_diag_dump_echo_file_w_header() { fi } +function _omz_diag_dump_os_specific_version() { + local osname osver version_file version_files + case "$OSTYPE" in + darwin*) + osname=$(command sw_vers -productName) + osver=$(command sw_vers -productVersion) + builtin echo "OS Version: $osname $osver build $(sw_vers -buildVersion)" + ;; + cygwin) + command systeminfo | command grep "^OS Name\|^OS Version" + ;; + esac + + if builtin which lsb_release >/dev/null; then + builtin echo "OS Release: $(command lsb_release -s -d)" + fi + + version_files=( /etc/*-release(N) /etc/*-version(N) /etc/*_version(N) ) + for version_file in $version_files; do + builtin echo "$version_file:" + command cat "$version_file" + builtin echo + done +} From fa254458688acf0bede8567b2bb5793a9ed944d6 Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Wed, 22 Jul 2015 12:59:39 -0400 Subject: [PATCH 7/8] diagnostics: include output file name in dump output --- lib/diagnostics.zsh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/diagnostics.zsh b/lib/diagnostics.zsh index 53c6548de..f38239110 100644 --- a/lib/diagnostics.zsh +++ b/lib/diagnostics.zsh @@ -101,7 +101,9 @@ function _omz_diag_dump_one_big_text() { builtin echo oh-my-zsh diagnostic dump builtin echo - + builtin echo $outfile + builtin echo + # Basic system and zsh information command date command uname -a From 46ddd88fe056ee84064536ce9b34f86bba6b53ca Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Fri, 4 Sep 2015 14:13:00 -0400 Subject: [PATCH 8/8] diagnostics: switch to shasum, filter sysinfo using lines shasum seems more widely available than md5/md5sum, and we don't have to worry about dealing with the different signatures and output formats of md5 and md5sum then. sysinfo outputs localized message labels, so we can't just grep for "OS Type". But OS is the first thing it outputs, so we can probably just grab those lines by line number. Switched to doing that. --- lib/diagnostics.zsh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/diagnostics.zsh b/lib/diagnostics.zsh index f38239110..afc33829b 100644 --- a/lib/diagnostics.zsh +++ b/lib/diagnostics.zsh @@ -117,13 +117,16 @@ function _omz_diag_dump_one_big_text() { # Installed programs programs=(sh zsh ksh bash sed cat grep ls find git posh) + local progfile="" extra_str="" sha_str="" for program in $programs; do - local md5_str="" md5="" link_str="" extra_str="" + extra_str="" sha_str="" progfile=$(builtin which $program) if [[ $? == 0 ]]; then if [[ -e $progfile ]]; then - if builtin whence md5 &>/dev/null; then - extra_str+=" $(md5 -q $progfile)" + if builtin whence shasum &>/dev/null; then + sha_str=($(command shasum $progfile)) + sha_str=$sha_str[1] + extra_str+=" SHA $sha_str" fi if [[ -h "$progfile" ]]; then extra_str+=" ( -> ${progfile:A} )" @@ -314,7 +317,7 @@ function _omz_diag_dump_os_specific_version() { builtin echo "OS Version: $osname $osver build $(sw_vers -buildVersion)" ;; cygwin) - command systeminfo | command grep "^OS Name\|^OS Version" + command systeminfo | command head -4 | command tail -2 ;; esac