1
#!/bin/sh
2
#shellcheck disable=SC2004,SC2016
3

4 0
[ "$PPID" ] || { echo "Unsupported shell. (Bourne shell?)" >&2; exit 1; }
5

6 0
set -e -u -f
7

8 0
if [ "${1:-}" = "-" ]; then
9 0
  echo 'IFS= read -r shebang < "$0"'
10 0
  echo 'case $shebang in \#\!*) shell=${shebang#??};; *) shell="";; esac'
11 0
  echo "exec \$shell \"$0\" \"\$0\" \"\$@\""
12 0
  return 0
13
fi
14

15 0
export SHELLSPEC_VERSION='0.28.0-dev'
16 0
export SHELLSPEC_SELF=''
17 0
export SHELLSPEC_ROOT=''
18 0
export SHELLSPEC_PROJECT_ROOT=''
19 0
export SHELLSPEC_PROJECT_NAME=''
20 0
export SHELLSPEC_LIB=''
21 0
export SHELLSPEC_LIBEXEC=''
22 0
export SHELLSPEC_PATH=''
23 0
export SHELLSPEC_GRAMMAR_DSLS=''
24 0
export SHELLSPEC_GRAMMAR_DIRECTIVES=''
25 0
export SHELLSPEC_GRAMMAR_BLOCKS=''
26 0
export SHELLSPEC_SPECDIR=''
27 0
export SHELLSPEC_LOAD_PATH=''
28 0
export SHELLSPEC_DEFECT_SANDBOX=''
29 0
export SHELLSPEC_PATH_IS_READONLY=''
30 0
export SHELLSPEC_SUPPORT_BIN=''
31 0
export SHELLSPEC_SUPPORT_BINDIR=''
32 0
export SHELLSPEC_UNREADONLY_PATH=''
33 0
export SHELLSPEC_MSLEEP=''
34 0
export SHELLSPEC_BUILTIN_PRINTF=''
35 0
export SHELLSPEC_BUILTIN_PRINT=''
36 0
export SHELLSPEC_BUILTIN_TYPESETF=''
37 0
export SHELLSPEC_TIME=''
38 0
export SHELLSPEC_REPORTDIR=''
39 0
export SHELLSPEC_BANNER_FILE=''
40 0
export SHELLSPEC_LIST=''
41 0
export SHELLSPEC_COUNT_FILE=''
42 0
export SHELLSPEC_UNIXTIME=''
43 0
export SHELLSPEC_DEBUG_TRAP=''
44 0
export SHELLSPEC_INFILE=file
45 0
export SHELLSPEC_COVERAGE_SETUP=''
46 0
export SHELLSPEC_COVERAGE_SHELL_OPTIONS=''
47 0
export SHELLSPEC_COVERAGE_DIR=''
48 0
export SHELLSPEC_KCOV_COMPATIBLE_SHELL=''
49 0
export SHELLSPEC_KCOV_VERSION=''
50 0
export SHELLSPEC_OUTPUT_FD=9
51 0
export SHELLSPEC_PROFILER_REPORT=".shellspec-profiler.log"
52 0
export SHELLSPEC_DEFECT_READONLY=''
53 0
export SHELLSPEC_DEFECT_BUILTIN=''
54 0
export SHELLSPEC_DEFECT_REDEFINE=''
55 0
export SHELLSPEC_DEFECT_SHELLFLAG=''
56 0
export SHELLSPEC_DEFECT_ERREXIT=''
57 0
export SHELLSPEC_DEFECT_ZSHEXIT=''
58 0
export SHELLSPEC_DEFECT_SUBSHELL=''
59 0
export SHELLSPEC_DEFECT_SETE=''
60 0
export SHELLSPEC_DEFECT_XTRACE=''
61 0
export SHELLSPEC_DEFECT_EXPORTP=''
62 0
export SHELLSPEC_DEFECT_SIGNAL=''
63 0
export SHELLSPEC_SHEBANG_MULTIARG=''
64 0
export SHELLSPEC_BUSYBOX_W32=''
65 0
export SHELLSPEC_SHOPT_AVAILABLE=''
66 0
export SHELLSPEC_FAILGLOB_AVAILABLE=''
67 0
export SHELLSPEC_NOMATCH_AVAILABLE=''
68 0
export SHELLSPEC_PATHSEP=":"
69 0
export SHELLSPEC_QUICK_FILE=".shellspec-quick.log"
70 0
export SHELLSPEC_REPAIR=''
71 0
export SHELLSPEC_INFO=''
72 0
export SHELLSPEC_TTY=''
73 0
export SHELLSPEC_DEV_TTY="/dev/null"
74 0
export SHELLSPEC_XTRACE_ON=''
75 0
export SHELLSPEC_XTRACE_OFF=''
76 0
export SHELLSPEC_XTRACEFD=2
77 0
export SHELLSPEC_XTRACEFD_VAR=''
78 0
export SHELLSPEC_CLONE_TYPE=''
79

80 0
export SHELLSPEC_ENV="env"
81 0
export SHELLSPEC_PRINTF="printf"
82 0
export SHELLSPEC_SLEEP="sleep"
83 0
export SHELLSPEC_TRAP="trap"
84 0
export SHELLSPEC_MV="mv"
85 0
export SHELLSPEC_CHMOD="chmod"
86 0
export SHELLSPEC_DATE="date"
87 0
export SHELLSPEC_RM="rm"
88

89
#shellcheck disable=SC2039,SC3028
90 0
export SHELLSPEC_HOSTNAME=${HOSTNAME:-localhost}
91

92
# Based on https://github.com/ko1nksm/readlinkf
93
# Changed the interpretation of symlinks to my preference (Change cd -P to cd)
94
readlinkf() {
95 0
  [ ${1:+x} ] || return 1; p=$1; until [ _"${p%/}" = _"$p" ]; do p=${p%/}; done
96 0
  [ -e "$p" ] && p=$1; [ -d "$1" ] && p=$p/; set 10 "$(pwd)" "${OLDPWD:-}"; PWD=
97 0
  CDPATH="" cd "$2" && while [ "$1" -gt 0 ]; do set "$1" "$2" "$3" "${p%/*}"
98 0
    [ _"$p" = _"$4" ] || { CDPATH="" cd "${4:-/}" || break; p=${p##*/}; }
99 0
    [ ! -L "$p" ] && p=${PWD%/}${p:+/}$p && set "$@" "${p:-/}" && break
100 0
    set $(($1-1)) "$2" "$3" "$p"; p=$(ls -dl "$p") || break; p=${p#*" $4 -> "}
101 0
  done 2>/dev/null; cd "$2" && OLDPWD=$3 && [ ${5+x} ] && printf '%s\n' "$5"
102
}
103

104 0
self=$0
105 0
[ "${BASH_SOURCE:-}" ] && eval "self=\${BASH_SOURCE[0]}"
106 0
( eval "[ \"\${.sh.file:-}\" ]" ) 2>/dev/null && eval "self=\${.sh.file}"
107

108 0
if ! SHELLSPEC_SELF=$(readlinkf "$self"); then
109 0
 echo "Failed to detect shellspec real path." >&2
110 0
 exit 1
111
fi
112

113 0
SHELLSPEC_ROOT="${SHELLSPEC_SELF%/*}"
114 0
SHELLSPEC_LIB="$SHELLSPEC_ROOT/lib"
115 0
SHELLSPEC_REPORTERLIB="$SHELLSPEC_LIB/libexec/reporter"
116

117
# shellcheck source=lib/libexec/shellspec.sh
118 0
. "$SHELLSPEC_LIB/libexec/shellspec.sh"
119
# shellcheck source=lib/libexec/optparser.sh
120 0
. "$SHELLSPEC_LIB/libexec/optparser.sh"
121

122 0
unixtime SHELLSPEC_UNIXTIME
123

124 0
SHELLSPEC_LIBEXEC="$SHELLSPEC_ROOT/libexec"
125 0
SHELLSPEC_UNREADONLY_PATH="$SHELLSPEC_LIBEXEC/shellspec-unreadonly-path.sh"
126 0
SHELLSPEC_PROJECT_ROOT="$PWD"
127 0
SHELLSPEC_PROJECT_NAME="${SHELLSPEC_PROJECT_ROOT##*/}"
128 0
SHELLSPEC_SPECDIR="$SHELLSPEC_PROJECT_ROOT/spec"
129 0
SHELLSPEC_REPORTDIR="$SHELLSPEC_PROJECT_ROOT/report"
130 0
SHELLSPEC_COVERAGE_DIR="$SHELLSPEC_PROJECT_ROOT/coverage"
131 0
SHELLSPEC_LOAD_PATH="$SHELLSPEC_SPECDIR:$SHELLSPEC_LIB:$SHELLSPEC_REPORTERLIB"
132 0
SHELLSPEC_SUPPORT_BIN="$SHELLSPEC_LIB/support-bin.sh"
133 0
SHELLSPEC_SUPPORT_BINDIR="$SHELLSPEC_SPECDIR/support/bin"
134 0
SHELLSPEC_BANNER_FILE="$SHELLSPEC_SPECDIR/banner"
135

136 0
export SHELLSPEC_KCOV_COMMON_OPTS=''
137 0
while IFS= read -r option; do
138 0
  SHELLSPEC_KCOV_COMMON_OPTS="$SHELLSPEC_KCOV_COMMON_OPTS$option "
139
done <<HERE
140
--include-path=.
141
--include-pattern=.sh
142
--exclude-pattern=/.shellspec,/spec/,/coverage/,/report/
143
--path-strip-level=1
144
HERE
145 0
export SHELLSPEC_KCOV_FILENAME="$SHELLSPEC_PROJECT_NAME [specfiles]"
146

147 0
optparser parse_options SHELLSPEC error_message
148

149
error_message() {
150 0
  error "$1${options_file:+" [$options_file]"}"
151
}
152

153
options_file() {
154 0
  options_file=$1
155 0
  read_options_file "$1" parse_options
156 0
  unset options_file
157
}
158 0
enum_options_file options_file
159 0
params=''
160 0
[ $# -gt 0 ] && parse_options "$@"
161 0
if [ "${SHELLSPEC_DOCKER_IMAGE#:}" ]; then
162 0
  case $SHELLSPEC_DOCKER_IMAGE in (:*)
163 0
    SHELLSPEC_DOCKER_IMAGE="shellspec/runtime${SHELLSPEC_DOCKER_IMAGE}"
164
  esac
165 0
  set -- "$@" --docker :
166 0
  cid=$(docker create --rm -it "$SHELLSPEC_DOCKER_IMAGE" shellspec "$@")
167 0
  set -- --exclude spec --exclude .git
168 0
  tar -C "$SHELLSPEC_ROOT" "$@" -c ./ | docker cp - "$cid:/bin/"
169 0
  tar --exclude .git -c ./ | docker cp - "$cid:./"
170 0
  exec docker start -ai "$cid"
171 0
  exit
172
fi
173 0
eval "set -- $params"
174

175 0
export SHELLSPEC_TMPDIR=${SHELLSPEC_TMPDIR%/}
176 0
if [ ! -d "$SHELLSPEC_TMPDIR" ]; then
177 0
  abort "Temporary directory '$SHELLSPEC_TMPDIR' does not exist or is not a directory"
178
fi
179 0
export SHELLSPEC_TMPBASE="$SHELLSPEC_TMPDIR/shellspec.$SHELLSPEC_UNIXTIME.$$"
180 0
export SHELLSPEC_TIME_LOG="$SHELLSPEC_TMPBASE/.shellspec-time.log"
181 0
export SHELLSPEC_PROFILER_LOG="$SHELLSPEC_TMPBASE/.shellspec-profiler.log"
182 0
export SHELLSPEC_DEPRECATION_LOGFILE="$SHELLSPEC_TMPBASE/.shellspec-deprecation.log"
183 0
export SHELLSPEC_PROFILER_SIGNAL="$SHELLSPEC_TMPBASE/.shellspec-profiler.signal"
184 0
export SHELLSPEC_REPORTER_PID="$SHELLSPEC_TMPBASE/.shellspec-reporter.pid"
185 0
export SHELLSPEC_KCOV_IN_FILE="$SHELLSPEC_TMPBASE/kcov/$SHELLSPEC_KCOV_FILENAME"
186

187 0
if [ "${SHELLSPEC_SHELL:-auto}" = "auto" ]; then
188
  # shellcheck disable=SC2039,SC3047
189 0
  if [ "$SHELLSPEC_KCOV" ] && ! (trap '' DEBUG) 2>/dev/null; then
190 0
    for shell in sh bash ksh zsh :; do
191 0
      "$shell" -c "trap '' DEBUG" 2>/dev/null && break
192
    done
193 0
    [ "$shell" = : ] && abort "Current shell is not compatible with Kcov."
194 0
    warn "Current shell is not compatible with Kcov. Using '$shell' instead."
195
  else
196 0
    shell=$(current_shell "$0" "$$")
197
  fi
198 0
  if [ ! "$shell" ] && shell="sh"; then
199 0
    warn "Failed to detect the current shell," \
200
         "because the ps command does not exist or not compatible."
201 0
    warn "Using 'sh' instead. You can specify the shell with --shell option."
202
  fi
203 0
  SHELLSPEC_SHELL=$shell
204
fi
205

206 0
if command_path shell "${SHELLSPEC_SHELL%% *}"; then
207 0
  case $SHELLSPEC_SHELL in (*\ *) shell="$shell ${SHELLSPEC_SHELL#* }"; esac
208 0
  SHELLSPEC_SHELL=$shell
209 0
elif ! $SHELLSPEC_SHELL -c '' >/dev/null 2>&1; then
210 0
  abort "Not found specified shell: $SHELLSPEC_SHELL."
211
fi
212

213
{
214 0
  inspection="$SHELLSPEC_LIBEXEC/shellspec-inspection.sh"
215 0
  if ! eval "$($SHELLSPEC_SHELL "$inspection" || echo false)" &&:; then
216 0
    abort "Shell inspection failed. This shell is not supported.$SHELLSPEC_LF" \
217
      "(It is not a POSIX shell or basic functionality is defective)."
218
  fi
219

220 0
  if [ "$SHELLSPEC_DEFECT_BUILTIN" ]; then
221 0
    warn "Unsupported shell (builtin commands can not redefine)."
222
  fi
223

224 0
  if [ "$SHELLSPEC_DEFECT_READONLY" ]; then
225 0
    warn "Unsupported shell (readonly malfunction)."
226
  fi
227

228 0
  if [ "$SHELLSPEC_DEFECT_SHELLFLAG" ]; then
229 0
    warn "Unsupported shell (shell flag handling broken)."
230
  fi
231

232 0
  if [ "$SHELLSPEC_DEFECT_ERREXIT" ]; then
233 0
    warn "Unsupported shell (errexit handling broken)."
234
  fi
235

236 0
  if [ "$SHELLSPEC_DEFECT_SIGNAL" ]; then
237 0
    SHELLSPEC_TRAP=":"
238 0
    warn "Unsupported shell (signal handling broken)."
239
  fi
240

241 0
  [ "$SHELLSPEC_BUSYBOX_W32" ] && SHELLSPEC_PATHSEP=";"
242 0
  [ "$SHELLSPEC_TTY" ] && SHELLSPEC_DEV_TTY=/dev/tty
243
}
244

245 0
if [ "$SHELLSPEC_DEFECT_SANDBOX" ]; then
246 0
  warn "Some features may fail due to incompatibilities with sandbox features."
247
fi
248

249
# shellcheck disable=SC2153
250 0
if [ "$SHELLSPEC_XTRACE" ]; then
251 0
  if [ ! "$SHELLSPEC_XTRACE_ONLY" ]; then
252 0
    [ "$SHELLSPEC_XTRACEFD_VAR" ] && SHELLSPEC_XTRACEFD=9
253 0
    if [ "$SHELLSPEC_XTRACEFD" = "2" ] && SHELLSPEC_XTRACE_ONLY=1; then
254 0
      warn "Fall back to trace-only mode. All expectations will be skipped."
255
    fi
256
  fi
257

258 0
  if [ "$SHELLSPEC_DEFECT_XTRACE" ]; then
259 0
    warn "If xtrace doesn't work, " \
260
      'execute `set -x` manually inside the function.'
261
  fi
262
fi
263

264 0
if [ "$SHELLSPEC_DEFECT_XTRACE" = "2" ]; then
265 0
  SHELLSPEC_XTRACE_ON='typeset -ft $(typeset +f); '
266 0
  SHELLSPEC_XTRACE_OFF='typeset +ft $(typeset +f); '
267
else
268 0
  if [ "$SHELLSPEC_XTRACEFD_VAR" ]; then
269 0
    SHELLSPEC_XTRACE_ON="$SHELLSPEC_XTRACEFD_VAR=\$SHELLSPEC_XTRACEFD; "
270
  fi
271
fi
272 0
SHELLSPEC_XTRACE_ON="${SHELLSPEC_XTRACE_ON}set -x"
273 0
SHELLSPEC_XTRACE_OFF=": @SHELLSPEC_XTRACE_OFF@; ${SHELLSPEC_XTRACE_OFF}set +x"
274

275 0
if [ ! "$SHELLSPEC_BUILTIN_PRINTF" ]; then
276 0
  command_path SHELLSPEC_PRINTF "printf" || SHELLSPEC_PRINTF="printf"
277
fi
278

279 0
command_path SHELLSPEC_ENV "env" ||:
280 0
command_path SHELLSPEC_MV "mv" ||:
281 0
command_path SHELLSPEC_CHMOD "chmod" ||:
282 0
command_path SHELLSPEC_DATE "date" ||:
283 0
command_path SHELLSPEC_RM "rm" ||:
284 0
command_path SHELLSPEC_SLEEP "sleep" ||:
285

286 0
if command_path "time" || [ "$SHELLSPEC_BUSYBOX_W32" ]; then
287 0
  SHELLSPEC_TIME="time -p"
288
else
289 0
  SHELLSPEC_TIME="$SHELLSPEC_LIBEXEC/shellspec-time.sh"
290 0
  if command_path bash; then
291 0
    SHELLSPEC_TIME="bash $SHELLSPEC_TIME"
292 0
  elif command_path ksh; then
293 0
    SHELLSPEC_TIME="ksh $SHELLSPEC_TIME"
294
  fi
295
fi
296

297 0
if ! signal 0 $$ 2>/dev/null; then
298
  # For example posh 0.13.2 does not implement kill as builtin and
299
  # debian 10 docker image does not have kill command installed by default.
300 0
  warn "kill not found. You may encounter errors with some features."
301
fi
302

303 0
if [ "$SHELLSPEC_KCOV" ]; then
304 0
  kcov_verson=$(kcov_version "$SHELLSPEC_KCOV_PATH") || abort "Kcov not found."
305 0
  if [ "$(kcov_version_number "$kcov_verson")" -lt 35 ]; then
306 0
    kcov_verson=${kcov_verson:-unknown (kcov v30 or below)}
307 0
    abort "Kcov v35 or later required. [current: $kcov_verson]"
308
  fi
309 0
  if [ ! "$SHELLSPEC_KCOV_COMPATIBLE_SHELL" ]; then
310 0
    abort "Require to use bash/zsh/ksh to run kcov (e.g: --shell bash)."
311
  fi
312 0
  SHELLSPEC_KCOV_VERSION=$kcov_verson
313
fi
314

315 0
if [ "$SHELLSPEC_PROFILER" ] && [ "$SHELLSPEC_WORKERS" -gt 0 ]; then
316 0
  abort "Cannot be specified profiler and parallel execution at the same time."
317
fi
318

319 0
case $SHELLSPEC_MODE in (runner | list | translate | syntax-check)
320 0
  [ $# -eq 0 ] && set -- "$SHELLSPEC_DEFAULT_PATH"
321 0
  for p in "$@"; do
322 0
    [ -e "${p%%:*}" ] || abort "Not found path: ${p%%:*}."
323 0
    [ -f "${p%%:*}" ] && SHELLSPEC_PATTERN="$SHELLSPEC_PATTERN|${p%%:*}"
324 0
    case $p in (*:*)
325 0
      [ -d "${p%%:*}" ] && abort "Invalid range for directory: $p."
326 0
      check_range "${p#*:}" || abort "Invalid range: $p."
327
    esac
328
  done
329
esac
330

331 0
case $SHELLSPEC_MODE in (runner | list)
332
  # shellcheck disable=SC2153
333 0
  if [ "$SHELLSPEC_RANDOM" ] && [ ! "$SHELLSPEC_SEED" ]; then
334 0
    random_seed SHELLSPEC_SEED "$SHELLSPEC_UNIXTIME" "$$"
335 0
    info "Randomized with seed $SHELLSPEC_SEED" >&2
336
  fi
337
esac
338 0
[ "$SHELLSPEC_ENV_FROM" ] && exec="load-env" || exec=$SHELLSPEC_MODE
339 0
exec="$SHELLSPEC_LIBEXEC/shellspec-${exec}.sh"
340 0
eval exec "$SHELLSPEC_SHELL" "\"$exec\"" ${1+'"$@"'}

Read our documentation on viewing source code .

Loading