valise-sh 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/loader.sh CHANGED
@@ -85,10 +85,202 @@ _sp_loader_path_is_physical() {
85
85
  return 0
86
86
  }
87
87
 
88
+ _sp_loader_read_record() {
89
+ _splrr_file=$1
90
+ _splrr_name=
91
+ _splrr_requires=
92
+ _splrr_optional=
93
+ _splrr_shells=
94
+ _splrr_platforms=
95
+ _splrr_side_effect=
96
+ _splrr_exports=
97
+ _splrr_updates=
98
+ _splrr_version=
99
+ _splrr_load=
100
+ while IFS= read -r _splrr_line || [ -n "$_splrr_line" ]; do
101
+ case $_splrr_line in
102
+ '' | '#'* | *=*) ;;
103
+ *) continue ;;
104
+ esac
105
+ _splrr_key=${_splrr_line%%=*}
106
+ _splrr_value=${_splrr_line#*=}
107
+ case $_splrr_key in
108
+ name) _splrr_name=$_splrr_value ;;
109
+ requires) _splrr_requires=$_splrr_value ;;
110
+ optional) _splrr_optional=$_splrr_value ;;
111
+ shells) _splrr_shells=$_splrr_value ;;
112
+ platforms) _splrr_platforms=$_splrr_value ;;
113
+ side_effect) _splrr_side_effect=$_splrr_value ;;
114
+ exports) _splrr_exports=$_splrr_value ;;
115
+ updates) _splrr_updates=$_splrr_value ;;
116
+ version) _splrr_version=$_splrr_value ;;
117
+ load) _splrr_load=$_splrr_value ;;
118
+ esac
119
+ done <"$_splrr_file"
120
+ _spl_record_name=$_splrr_name
121
+ _spl_record_requires=$_splrr_requires
122
+ _spl_record_optional=$_splrr_optional
123
+ _spl_record_shells=$_splrr_shells
124
+ _spl_record_platforms=$_splrr_platforms
125
+ _spl_record_side_effect=$_splrr_side_effect
126
+ _spl_record_exports=$_splrr_exports
127
+ _spl_record_updates=$_splrr_updates
128
+ _spl_record_version=$_splrr_version
129
+ _spl_record_load=$_splrr_load
130
+ unset _splrr_file _splrr_line _splrr_key _splrr_value _splrr_name _splrr_requires \
131
+ _splrr_optional _splrr_shells _splrr_platforms _splrr_side_effect _splrr_exports \
132
+ _splrr_updates _splrr_version _splrr_load
133
+ }
134
+
135
+ _sp_loader_reserved_scan() {
136
+ _splrs_file=$1
137
+ _splrs_tab=' '
138
+ _splrs_found=0
139
+ while IFS= read -r _splrs_line || [ -n "$_splrs_line" ]; do
140
+ _splrs_trimmed=$_splrs_line
141
+ while :; do
142
+ case $_splrs_trimmed in
143
+ ' '*) _splrs_trimmed=${_splrs_trimmed# } ;;
144
+ "$_splrs_tab"*) _splrs_trimmed=${_splrs_trimmed#"$_splrs_tab"} ;;
145
+ *) break ;;
146
+ esac
147
+ done
148
+ [ -n "$_splrs_trimmed" ] || continue
149
+ if [ "${IFS+x}" = x ]; then
150
+ _splrs_ifs_was_set=1
151
+ _splrs_old_ifs=${IFS-}
152
+ else
153
+ _splrs_ifs_was_set=0
154
+ _splrs_old_ifs=
155
+ fi
156
+ # Tokens are separated by any blank, as the shell itself treats them. The
157
+ # line is data, so pathname expansion must not run on it.
158
+ IFS=" $_splrs_tab"
159
+ case $- in
160
+ *f*) _splrs_noglob_was_set=1 ;;
161
+ *)
162
+ _splrs_noglob_was_set=0
163
+ set -f
164
+ ;;
165
+ esac
166
+ set -- $_splrs_trimmed
167
+ [ "$_splrs_noglob_was_set" -eq 1 ] || set +f
168
+ if [ "$_splrs_ifs_was_set" -eq 1 ]; then
169
+ IFS=$_splrs_old_ifs
170
+ else
171
+ unset IFS
172
+ fi
173
+ _splrs_first=${1-}
174
+ _splrs_second=${2-}
175
+ _splrs_first=${_splrs_first#\"}
176
+ _splrs_first=${_splrs_first%\"}
177
+ _splrs_first=${_splrs_first#\'}
178
+ _splrs_first=${_splrs_first%\'}
179
+ _splrs_second=${_splrs_second#\"}
180
+ _splrs_second=${_splrs_second%\"}
181
+ _splrs_second=${_splrs_second#\'}
182
+ _splrs_second=${_splrs_second%\'}
183
+ case $_splrs_first in
184
+ command | command'('*)
185
+ case $_splrs_second in
186
+ '('*) _splrs_found=1 ;;
187
+ esac
188
+ case $_splrs_first in
189
+ command'('*) _splrs_found=1 ;;
190
+ esac
191
+ ;;
192
+ unset | unset'('*)
193
+ case $_splrs_second in
194
+ '('*) _splrs_found=1 ;;
195
+ esac
196
+ case $_splrs_first in
197
+ unset'('*) _splrs_found=1 ;;
198
+ esac
199
+ ;;
200
+ return | return'('*)
201
+ case $_splrs_second in
202
+ '('*) _splrs_found=1 ;;
203
+ esac
204
+ case $_splrs_first in
205
+ return'('*) _splrs_found=1 ;;
206
+ esac
207
+ ;;
208
+ eval | eval'('*)
209
+ case $_splrs_second in
210
+ '('*) _splrs_found=1 ;;
211
+ esac
212
+ case $_splrs_first in
213
+ eval'('*) _splrs_found=1 ;;
214
+ esac
215
+ ;;
216
+ builtin | builtin'('*)
217
+ case $_splrs_second in
218
+ '('*) _splrs_found=1 ;;
219
+ esac
220
+ case $_splrs_first in
221
+ builtin'('*) _splrs_found=1 ;;
222
+ esac
223
+ ;;
224
+ readonly | readonly'('*)
225
+ case $_splrs_second in
226
+ '('*) _splrs_found=1 ;;
227
+ esac
228
+ case $_splrs_first in
229
+ readonly'('*) _splrs_found=1 ;;
230
+ esac
231
+ shift
232
+ _splrs_seen_f=0
233
+ for _splrs_word in "$@"; do
234
+ _splrs_word=${_splrs_word#\"}
235
+ _splrs_word=${_splrs_word%\"}
236
+ _splrs_word=${_splrs_word#\'}
237
+ _splrs_word=${_splrs_word%\'}
238
+ if [ "$_splrs_word" = -f ]; then
239
+ _splrs_seen_f=1
240
+ continue
241
+ fi
242
+ if [ "$_splrs_seen_f" -eq 1 ]; then
243
+ case $_splrs_word in
244
+ command | command'('*) _splrs_found=1 ;;
245
+ unset | unset'('*) _splrs_found=1 ;;
246
+ return | return'('*) _splrs_found=1 ;;
247
+ eval | eval'('*) _splrs_found=1 ;;
248
+ builtin | builtin'('*) _splrs_found=1 ;;
249
+ esac
250
+ fi
251
+ done
252
+ ;;
253
+ function)
254
+ case $_splrs_second in
255
+ command | command'('*) _splrs_found=1 ;;
256
+ unset | unset'('*) _splrs_found=1 ;;
257
+ readonly | readonly'('*) _splrs_found=1 ;;
258
+ return | return'('*) _splrs_found=1 ;;
259
+ eval | eval'('*) _splrs_found=1 ;;
260
+ builtin | builtin'('*) _splrs_found=1 ;;
261
+ esac
262
+ ;;
263
+ esac
264
+ if [ "$_splrs_found" -ne 0 ]; then
265
+ break
266
+ fi
267
+ done <"$_splrs_file"
268
+ if [ "$_splrs_found" -eq 0 ]; then
269
+ unset _splrs_file _splrs_tab _splrs_found _splrs_line _splrs_trimmed \
270
+ _splrs_first _splrs_second _splrs_seen_f _splrs_word \
271
+ _splrs_ifs_was_set _splrs_old_ifs _splrs_noglob_was_set
272
+ return 0
273
+ fi
274
+ unset _splrs_file _splrs_tab _splrs_found _splrs_line _splrs_trimmed \
275
+ _splrs_first _splrs_second _splrs_seen_f _splrs_word \
276
+ _splrs_ifs_was_set _splrs_old_ifs _splrs_noglob_was_set
277
+ return 1
278
+ }
279
+
88
280
  sp_loader_load_modules() {
89
281
  if [ "$#" -ne 4 ]; then
90
282
  command printf '%s\n' 'loader: usage: sp_loader_load_modules <root> <wanted-list> <mode> <phase>' >&2
91
- unset -f _sp_loader_path_is_physical 2>/dev/null || :
283
+ unset -f _sp_loader_path_is_physical _sp_loader_read_record _sp_loader_reserved_scan 2>/dev/null || :
92
284
  return 1
93
285
  fi
94
286
 
@@ -125,8 +317,8 @@ sp_loader_load_modules() {
125
317
  strict | permissive) ;;
126
318
  *)
127
319
  command printf 'loader: %s\n' "invalid mode: $_spl_mode" >&2
128
- unset _spl_root _spl_wanted _spl_mode _spl_phase _spl_return _spl_strict_error _spl_current_shell _spl_uname _spl_current_platform _spl_search_path _spl_layer _spl_meta_file _spl_meta_root _spl_dep_exists _spl_existing_load _spl_layer_load _spl_conflict _spl_layer_ifs_was_set _spl_layer_old_ifs _spl_existing_version _spl_layer_version _spl_existing_version_display _spl_layer_version_display
129
- unset -f _sp_loader_path_is_physical 2>/dev/null || :
320
+ unset _spl_root _spl_wanted _spl_mode _spl_phase _spl_return _spl_strict_error _spl_current_shell _spl_uname _spl_current_platform _spl_search_path _spl_layer _spl_meta_file _spl_meta_root _spl_dep_exists _spl_existing_load _spl_layer_load _spl_conflict _spl_layer_ifs_was_set _spl_layer_old_ifs _spl_existing_version _spl_layer_version _spl_existing_version_display _spl_layer_version_display _spl_seen_words _spl_strict_required_words _spl_blocked_words _spl_modules_words _spl_order_words _spl_failed_words
321
+ unset -f _sp_loader_path_is_physical _sp_loader_read_record _sp_loader_reserved_scan 2>/dev/null || :
130
322
  return 1
131
323
  ;;
132
324
  esac
@@ -135,37 +327,42 @@ sp_loader_load_modules() {
135
327
  ordinary) ;;
136
328
  *)
137
329
  command printf 'loader: %s\n' "invalid phase: $_spl_phase" >&2
138
- unset _spl_root _spl_wanted _spl_mode _spl_phase _spl_return _spl_strict_error _spl_current_shell _spl_uname _spl_current_platform _spl_search_path _spl_layer _spl_meta_file _spl_meta_root _spl_dep_exists _spl_existing_load _spl_layer_load _spl_conflict _spl_layer_ifs_was_set _spl_layer_old_ifs _spl_existing_version _spl_layer_version _spl_existing_version_display _spl_layer_version_display
139
- unset -f _sp_loader_path_is_physical 2>/dev/null || :
330
+ unset _spl_root _spl_wanted _spl_mode _spl_phase _spl_return _spl_strict_error _spl_current_shell _spl_uname _spl_current_platform _spl_search_path _spl_layer _spl_meta_file _spl_meta_root _spl_dep_exists _spl_existing_load _spl_layer_load _spl_conflict _spl_layer_ifs_was_set _spl_layer_old_ifs _spl_existing_version _spl_layer_version _spl_existing_version_display _spl_layer_version_display _spl_seen_words _spl_strict_required_words _spl_blocked_words _spl_modules_words _spl_order_words _spl_failed_words
331
+ unset -f _sp_loader_path_is_physical _sp_loader_read_record _sp_loader_reserved_scan 2>/dev/null || :
140
332
  return 1
141
333
  ;;
142
334
  esac
143
335
 
144
336
  if ! command -v sp_metadata_read >/dev/null 2>&1; then
145
337
  command printf '%s\n' 'loader: sp_metadata_read is not available; source lib/metadata.sh first' >&2
146
- unset _spl_root _spl_wanted _spl_mode _spl_phase _spl_return _spl_strict_error _spl_current_shell _spl_uname _spl_current_platform _spl_search_path _spl_layer _spl_meta_file _spl_meta_root _spl_dep_exists _spl_existing_load _spl_layer_load _spl_conflict _spl_layer_ifs_was_set _spl_layer_old_ifs _spl_existing_version _spl_layer_version _spl_existing_version_display _spl_layer_version_display
147
- unset -f _sp_loader_path_is_physical 2>/dev/null || :
338
+ unset _spl_root _spl_wanted _spl_mode _spl_phase _spl_return _spl_strict_error _spl_current_shell _spl_uname _spl_current_platform _spl_search_path _spl_layer _spl_meta_file _spl_meta_root _spl_dep_exists _spl_existing_load _spl_layer_load _spl_conflict _spl_layer_ifs_was_set _spl_layer_old_ifs _spl_existing_version _spl_layer_version _spl_existing_version_display _spl_layer_version_display _spl_seen_words _spl_strict_required_words _spl_blocked_words _spl_modules_words _spl_order_words _spl_failed_words
339
+ unset -f _sp_loader_path_is_physical _sp_loader_read_record _sp_loader_reserved_scan 2>/dev/null || :
148
340
  return 1
149
341
  fi
150
342
 
151
343
  _spl_tmp_parent=${TMPDIR:-/tmp}
152
344
  _spl_tmp=$(umask 077 && command mktemp -d \
153
345
  "$_spl_tmp_parent/shell-profile-loader.XXXXXX") || {
154
- unset _spl_root _spl_wanted _spl_mode _spl_phase _spl_return _spl_strict_error _spl_current_shell _spl_uname _spl_current_platform _spl_tmp_parent _spl_tmp _spl_search_path _spl_layer _spl_meta_file _spl_meta_root _spl_dep_exists _spl_existing_load _spl_layer_load _spl_conflict _spl_layer_ifs_was_set _spl_layer_old_ifs _spl_existing_version _spl_layer_version _spl_existing_version_display _spl_layer_version_display
155
- unset -f _sp_loader_path_is_physical 2>/dev/null || :
346
+ unset _spl_root _spl_wanted _spl_mode _spl_phase _spl_return _spl_strict_error _spl_current_shell _spl_uname _spl_current_platform _spl_tmp_parent _spl_tmp _spl_search_path _spl_layer _spl_meta_file _spl_meta_root _spl_dep_exists _spl_existing_load _spl_layer_load _spl_conflict _spl_layer_ifs_was_set _spl_layer_old_ifs _spl_existing_version _spl_layer_version _spl_existing_version_display _spl_layer_version_display _spl_seen_words _spl_strict_required_words _spl_blocked_words _spl_modules_words _spl_order_words _spl_failed_words
347
+ unset -f _sp_loader_path_is_physical _sp_loader_read_record _sp_loader_reserved_scan 2>/dev/null || :
156
348
  return 1
157
349
  }
158
350
  _spl_cleanup_tmp=$_spl_tmp
159
351
  _spl_tmp_sentinel=$_spl_tmp/.shell-profile-loader-owned
352
+ _spl_seen_words=
353
+ _spl_strict_required_words=
354
+ _spl_blocked_words=
355
+ _spl_modules_words=
356
+ _spl_order_words=
357
+ _spl_failed_words=
160
358
  : >"$_spl_tmp_sentinel" || _spl_return=1
161
- command mkdir -p "$_spl_tmp/meta" "$_spl_tmp/deps" "$_spl_tmp/optional" "$_spl_tmp/roots" || _spl_return=1
359
+ command mkdir -p "$_spl_tmp/meta" "$_spl_tmp/deps" "$_spl_tmp/optional" "$_spl_tmp/run" "$_spl_tmp/roots" || _spl_return=1
162
360
  : >"$_spl_tmp/queue"
163
- : >"$_spl_tmp/seen"
164
361
  : >"$_spl_tmp/modules"
165
362
  : >"$_spl_tmp/blocked"
363
+ : >"$_spl_tmp/platform_blocked"
166
364
  : >"$_spl_tmp/order"
167
365
  : >"$_spl_tmp/failed"
168
- : >"$_spl_tmp/strict_required"
169
366
  : >"$_spl_tmp/layers"
170
367
 
171
368
  # Validate the layer search path fail-closed: every colon-separated element
@@ -269,7 +466,7 @@ sp_loader_load_modules() {
269
466
  for _spl_word in $_spl_wanted; do
270
467
  if sp_metadata_validate_identifier "$_spl_word"; then
271
468
  command printf '%s\n' "$_spl_word" >>"$_spl_tmp/queue"
272
- command printf '%s\n' "$_spl_word" >>"$_spl_tmp/strict_required"
469
+ _spl_strict_required_words="$_spl_strict_required_words $_spl_word"
273
470
  else
274
471
  command printf 'loader: %s\n' "invalid wanted module: $_spl_word" >&2
275
472
  _spl_return=1
@@ -290,10 +487,10 @@ sp_loader_load_modules() {
290
487
  : >"$_spl_tmp/newqueue"
291
488
  while IFS= read -r _spl_mod || [ -n "$_spl_mod" ]; do
292
489
  [ -n "$_spl_mod" ] || continue
293
- if command grep -qx "$_spl_mod" "$_spl_tmp/seen" 2>/dev/null; then
294
- continue
295
- fi
296
- command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/seen"
490
+ case " $_spl_seen_words " in
491
+ *" $_spl_mod "*) continue ;;
492
+ esac
493
+ _spl_seen_words="$_spl_seen_words $_spl_mod"
297
494
  # Multi-root resolution (T07): search the primary root then each layer
298
495
  # root in priority order. First hit wins; a second hit whose metadata
299
496
  # or body differs by even one byte is a hard error naming both paths
@@ -307,7 +504,7 @@ sp_loader_load_modules() {
307
504
  _spl_meta_file=
308
505
  _spl_meta_root=
309
506
  if [ -L "$_spl_root/module.d/$_spl_mod.meta" ] || { [ -e "$_spl_root/module.d/$_spl_mod.meta" ] && ! _sp_loader_path_is_physical "$_spl_root" "$_spl_root/module.d/$_spl_mod.meta"; }; then
310
- command printf 'loader: %s\n' "$_spl_mod: metadata path contains a symlink"
507
+ command printf 'loader: %s\n' "$_spl_mod: metadata path contains a symlink" >&2
311
508
  _spl_return=1
312
509
  _spl_strict_error=1
313
510
  elif [ -f "$_spl_root/module.d/$_spl_mod.meta" ]; then
@@ -326,8 +523,10 @@ sp_loader_load_modules() {
326
523
  if [ -n "$_spl_meta_file" ]; then
327
524
  _spl_conflict=0
328
525
  if ! command cmp -s "$_spl_meta_file" "$_spl_layer/module.d/$_spl_mod.meta"; then
329
- _spl_existing_version=$(command sed -n 's/^version=//p' "$_spl_meta_file")
330
- _spl_layer_version=$(command sed -n 's/^version=//p' "$_spl_layer/module.d/$_spl_mod.meta")
526
+ _sp_loader_read_record "$_spl_meta_file"
527
+ _spl_existing_version=$_spl_record_version
528
+ _sp_loader_read_record "$_spl_layer/module.d/$_spl_mod.meta"
529
+ _spl_layer_version=$_spl_record_version
331
530
  if sp_metadata_validate_version "$_spl_existing_version" 2>/dev/null &&
332
531
  sp_metadata_validate_version "$_spl_layer_version" 2>/dev/null &&
333
532
  [ "$_spl_existing_version" != "$_spl_layer_version" ]; then
@@ -349,8 +548,10 @@ sp_loader_load_modules() {
349
548
  fi
350
549
  _spl_conflict=1
351
550
  else
352
- _spl_existing_load=$(command sed -n 's/^load=//p' "$_spl_meta_file")
353
- _spl_layer_load=$(command sed -n 's/^load=//p' "$_spl_layer/module.d/$_spl_mod.meta")
551
+ _sp_loader_read_record "$_spl_meta_file"
552
+ _spl_existing_load=$_spl_record_load
553
+ _sp_loader_read_record "$_spl_layer/module.d/$_spl_mod.meta"
554
+ _spl_layer_load=$_spl_record_load
354
555
  if [ -n "$_spl_existing_load" ] && [ -n "$_spl_layer_load" ]; then
355
556
  if ! _sp_loader_path_is_physical "$_spl_meta_root" "$_spl_meta_root/$_spl_existing_load" ||
356
557
  ! _sp_loader_path_is_physical "$_spl_layer" "$_spl_layer/$_spl_layer_load"; then
@@ -391,37 +592,42 @@ sp_loader_load_modules() {
391
592
  done <"$_spl_tmp/layers"
392
593
  if [ "$_spl_return" -ne 0 ]; then
393
594
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/blocked"
595
+ _spl_blocked_words="$_spl_blocked_words $_spl_mod"
394
596
  continue
395
597
  fi
396
598
  fi
397
599
  if [ -z "$_spl_meta_file" ]; then
398
600
  command printf 'loader: %s\n' "$_spl_mod: metadata file missing" >&2
399
601
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/blocked"
400
- [ "$_spl_mode" = strict ] && command grep -qx "$_spl_mod" "$_spl_tmp/strict_required" 2>/dev/null && _spl_strict_error=1
602
+ _spl_blocked_words="$_spl_blocked_words $_spl_mod"
603
+ [ "$_spl_mode" = strict ] && case " $_spl_strict_required_words " in *" $_spl_mod "*) _spl_strict_error=1 ;; esac
401
604
  continue
402
605
  fi
403
606
  command printf '%s\n' "$_spl_meta_root" >>"$_spl_tmp/roots/$_spl_mod"
404
607
  _spl_record=$_spl_tmp/meta/$_spl_mod
405
608
  if ! sp_metadata_read "$_spl_meta_file" >"$_spl_record"; then
406
609
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/blocked"
407
- [ "$_spl_mode" = strict ] && command grep -qx "$_spl_mod" "$_spl_tmp/strict_required" 2>/dev/null && _spl_strict_error=1
610
+ _spl_blocked_words="$_spl_blocked_words $_spl_mod"
611
+ [ "$_spl_mode" = strict ] && case " $_spl_strict_required_words " in *" $_spl_mod "*) _spl_strict_error=1 ;; esac
408
612
  continue
409
613
  fi
410
- _spl_record_name=$(command sed -n 's/^name=//p' "$_spl_record")
614
+ _sp_loader_read_record "$_spl_record"
615
+ command printf 'load=%s\nexports=%s\n' \
616
+ "$_spl_record_load" "$_spl_record_exports" \
617
+ >"$_spl_tmp/run/$_spl_mod"
411
618
  if [ "$_spl_record_name" != "$_spl_mod" ]; then
412
619
  command printf 'loader: %s\n' "$_spl_mod: metadata name mismatch: $_spl_record_name" >&2
413
620
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/blocked"
414
- [ "$_spl_mode" = strict ] && command grep -qx "$_spl_mod" "$_spl_tmp/strict_required" 2>/dev/null && _spl_strict_error=1
621
+ _spl_blocked_words="$_spl_blocked_words $_spl_mod"
622
+ [ "$_spl_mode" = strict ] && case " $_spl_strict_required_words " in *" $_spl_mod "*) _spl_strict_error=1 ;; esac
415
623
  continue
416
624
  fi
417
- _spl_side_effect=$(command sed -n 's/^side_effect=//p' "$_spl_record")
418
- if [ "$_spl_phase" = ordinary ] && ! sp_metadata_validate_source_side_effect "$_spl_side_effect"; then
625
+ if [ "$_spl_phase" = ordinary ] && ! sp_metadata_validate_source_side_effect "$_spl_record_side_effect"; then
419
626
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/blocked"
420
- [ "$_spl_mode" = strict ] && command grep -qx "$_spl_mod" "$_spl_tmp/strict_required" 2>/dev/null && _spl_strict_error=1
627
+ _spl_blocked_words="$_spl_blocked_words $_spl_mod"
628
+ [ "$_spl_mode" = strict ] && case " $_spl_strict_required_words " in *" $_spl_mod "*) _spl_strict_error=1 ;; esac
421
629
  continue
422
630
  fi
423
- _spl_shells=$(command sed -n 's/^shells=//p' "$_spl_record")
424
- _spl_platforms=$(command sed -n 's/^platforms=//p' "$_spl_record")
425
631
  _spl_shell_match=0
426
632
  _spl_platform_match=0
427
633
  if [ "${IFS+x}" = x ]; then
@@ -432,11 +638,11 @@ sp_loader_load_modules() {
432
638
  _spl_match_old_ifs=
433
639
  fi
434
640
  IFS=' '
435
- for _spl_value in $_spl_shells; do
641
+ for _spl_value in $_spl_record_shells; do
436
642
  [ "$_spl_value" = sh ] && _spl_shell_match=1
437
643
  [ "$_spl_value" = "$_spl_current_shell" ] && _spl_shell_match=1
438
644
  done
439
- for _spl_value in $_spl_platforms; do
645
+ for _spl_value in $_spl_record_platforms; do
440
646
  [ "$_spl_value" = any ] && _spl_platform_match=1
441
647
  [ "$_spl_value" = "$_spl_current_platform" ] && _spl_platform_match=1
442
648
  [ "$_spl_value" = bsd ] && case "$_spl_current_platform" in bsd | freebsd | openbsd | netbsd) _spl_platform_match=1 ;; esac
@@ -449,20 +655,25 @@ sp_loader_load_modules() {
449
655
  if [ "$_spl_shell_match" -ne 1 ]; then
450
656
  command printf 'loader: %s\n' "$_spl_mod: unsupported shell for $_spl_current_shell" >&2
451
657
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/blocked"
452
- [ "$_spl_mode" = strict ] && command grep -qx "$_spl_mod" "$_spl_tmp/strict_required" 2>/dev/null && _spl_strict_error=1
658
+ _spl_blocked_words="$_spl_blocked_words $_spl_mod"
659
+ [ "$_spl_mode" = strict ] && case " $_spl_strict_required_words " in *" $_spl_mod "*) _spl_strict_error=1 ;; esac
453
660
  continue
454
661
  fi
455
662
  if [ "$_spl_platform_match" -ne 1 ]; then
456
- command printf 'loader: %s\n' "$_spl_mod: unsupported platform for $_spl_current_platform" >&2
663
+ # Record the skip; whether to report it depends on the complete
664
+ # required closure, which is only known after discovery. A module
665
+ # reached only as an optional dependency is expected to be absent on
666
+ # some hosts, and reporting it would print at every shell startup.
667
+ command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/platform_blocked"
457
668
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/blocked"
458
- [ "$_spl_mode" = strict ] && command grep -qx "$_spl_mod" "$_spl_tmp/strict_required" 2>/dev/null && _spl_strict_error=1
669
+ _spl_blocked_words="$_spl_blocked_words $_spl_mod"
670
+ [ "$_spl_mode" = strict ] && case " $_spl_strict_required_words " in *" $_spl_mod "*) _spl_strict_error=1 ;; esac
459
671
  continue
460
672
  fi
461
673
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/modules"
462
- _spl_requires=$(command sed -n 's/^requires=//p' "$_spl_record")
463
- _spl_optional=$(command sed -n 's/^optional=//p' "$_spl_record")
464
- command printf '%s\n' "$_spl_requires" >"$_spl_tmp/deps/$_spl_mod"
465
- command printf '%s\n' "$_spl_optional" >"$_spl_tmp/optional/$_spl_mod"
674
+ _spl_modules_words="$_spl_modules_words $_spl_mod"
675
+ command printf '%s\n' "$_spl_record_requires" >"$_spl_tmp/deps/$_spl_mod"
676
+ command printf '%s\n' "$_spl_record_optional" >"$_spl_tmp/optional/$_spl_mod"
466
677
 
467
678
  if [ "${IFS+x}" = x ]; then
468
679
  _spl_dep_ifs_was_set=1
@@ -472,10 +683,12 @@ sp_loader_load_modules() {
472
683
  _spl_dep_old_ifs=
473
684
  fi
474
685
  IFS=' '
475
- for _spl_dep in $_spl_requires; do
476
- if command grep -qx "$_spl_mod" "$_spl_tmp/strict_required" 2>/dev/null; then
477
- command printf '%s\n' "$_spl_dep" >>"$_spl_tmp/strict_required"
478
- fi
686
+ for _spl_dep in $_spl_record_requires; do
687
+ case " $_spl_strict_required_words " in
688
+ *" $_spl_mod "*)
689
+ _spl_strict_required_words="$_spl_strict_required_words $_spl_dep"
690
+ ;;
691
+ esac
479
692
  _spl_dep_exists=0
480
693
  if [ -f "$_spl_root/module.d/$_spl_dep.meta" ]; then
481
694
  _spl_dep_exists=1
@@ -491,16 +704,20 @@ sp_loader_load_modules() {
491
704
  fi
492
705
  fi
493
706
  if [ "$_spl_dep_exists" -eq 1 ]; then
494
- if ! command grep -qx "$_spl_dep" "$_spl_tmp/seen" 2>/dev/null; then
707
+ case " $_spl_seen_words " in
708
+ *" $_spl_dep "*) ;;
709
+ *)
495
710
  command printf '%s\n' "$_spl_dep" >>"$_spl_tmp/newqueue"
496
- fi
711
+ ;;
712
+ esac
497
713
  else
498
714
  command printf 'loader: %s\n' "$_spl_mod: missing required dependency $_spl_dep" >&2
499
715
  command printf '%s\n' "$_spl_dep" >>"$_spl_tmp/blocked"
500
- [ "$_spl_mode" = strict ] && command grep -qx "$_spl_mod" "$_spl_tmp/strict_required" 2>/dev/null && _spl_strict_error=1
716
+ _spl_blocked_words="$_spl_blocked_words $_spl_dep"
717
+ [ "$_spl_mode" = strict ] && case " $_spl_strict_required_words " in *" $_spl_mod "*) _spl_strict_error=1 ;; esac
501
718
  fi
502
719
  done
503
- for _spl_dep in $_spl_optional; do
720
+ for _spl_dep in $_spl_record_optional; do
504
721
  _spl_dep_exists=0
505
722
  if [ -f "$_spl_root/module.d/$_spl_dep.meta" ]; then
506
723
  _spl_dep_exists=1
@@ -515,10 +732,18 @@ sp_loader_load_modules() {
515
732
  done <"$_spl_tmp/layers"
516
733
  fi
517
734
  fi
518
- if [ "$_spl_dep_exists" -eq 1 ] && ! command grep -qx "$_spl_dep" "$_spl_tmp/seen" 2>/dev/null; then
519
- command printf '%s\n' "$_spl_dep" >>"$_spl_tmp/newqueue"
735
+ if [ "$_spl_dep_exists" -eq 1 ]; then
736
+ case " $_spl_seen_words " in
737
+ *" $_spl_dep "*) ;;
738
+ *)
739
+ command printf '%s\n' "$_spl_dep" >>"$_spl_tmp/newqueue"
740
+ ;;
741
+ esac
520
742
  fi
521
743
  done
744
+ unset _spl_record_name _spl_record_requires _spl_record_optional _spl_record_shells \
745
+ _spl_record_platforms _spl_record_side_effect _spl_record_exports _spl_record_updates \
746
+ _spl_record_version _spl_record_load
522
747
  if [ "$_spl_dep_ifs_was_set" -eq 1 ]; then
523
748
  IFS=$_spl_dep_old_ifs
524
749
  else
@@ -528,6 +753,60 @@ sp_loader_load_modules() {
528
753
  command mv "$_spl_tmp/newqueue" "$_spl_tmp/queue"
529
754
  done
530
755
 
756
+ # Discovery can reach a module through an optional edge before a required
757
+ # edge promotes its parent. Re-walk the requires graph to a fixpoint so the
758
+ # required closure does not depend on discovery order.
759
+ if [ "$_spl_return" -eq 0 ]; then
760
+ if [ "${IFS+x}" = x ]; then
761
+ _spl_ifs_was_set=1
762
+ _spl_old_ifs=${IFS-}
763
+ else
764
+ _spl_ifs_was_set=0
765
+ _spl_old_ifs=
766
+ fi
767
+ IFS=' '
768
+ _spl_progress=1
769
+ while [ "$_spl_progress" -ne 0 ]; do
770
+ _spl_progress=0
771
+ for _spl_mod in $_spl_strict_required_words; do
772
+ [ -f "$_spl_tmp/deps/$_spl_mod" ] || continue
773
+ IFS= read -r _spl_requires <"$_spl_tmp/deps/$_spl_mod" || :
774
+ for _spl_dep in $_spl_requires; do
775
+ case " $_spl_strict_required_words " in
776
+ *" $_spl_dep "*) ;;
777
+ *)
778
+ _spl_strict_required_words="$_spl_strict_required_words $_spl_dep"
779
+ _spl_progress=1
780
+ ;;
781
+ esac
782
+ done
783
+ done
784
+ done
785
+ if [ "$_spl_ifs_was_set" -eq 1 ]; then
786
+ IFS=$_spl_old_ifs
787
+ else
788
+ unset IFS
789
+ fi
790
+ unset _spl_mod _spl_requires _spl_dep
791
+ fi
792
+
793
+ # A platform skip is reported only when the module belongs to the required
794
+ # closure. Discovery can reach a module through an optional edge before a
795
+ # required edge (or through a required edge that is itself discovered
796
+ # later), so the decision waits until every edge has been walked.
797
+ if [ "$_spl_return" -eq 0 ] && [ -s "$_spl_tmp/platform_blocked" ]; then
798
+ while IFS= read -r _spl_mod || [ -n "$_spl_mod" ]; do
799
+ [ -n "$_spl_mod" ] || continue
800
+ case " $_spl_strict_required_words " in
801
+ *" $_spl_mod "*)
802
+ command printf 'loader: %s\n' "$_spl_mod: unsupported platform for $_spl_current_platform" >&2
803
+ [ "$_spl_mode" = strict ] && _spl_strict_error=1
804
+ ;;
805
+ esac
806
+ done <"$_spl_tmp/platform_blocked"
807
+ unset _spl_mod
808
+ fi
809
+
531
810
  if [ "$_spl_return" -eq 0 ]; then
532
811
  command sort -u "$_spl_tmp/modules" >"$_spl_tmp/remaining"
533
812
  command sort -u "$_spl_tmp/blocked" >"$_spl_tmp/blocked.sorted"
@@ -538,14 +817,22 @@ sp_loader_load_modules() {
538
817
  : >"$_spl_tmp/next_remaining"
539
818
  while IFS= read -r _spl_mod || [ -n "$_spl_mod" ]; do
540
819
  [ -n "$_spl_mod" ] || continue
541
- if command grep -qx "$_spl_mod" "$_spl_tmp/blocked" 2>/dev/null; then
820
+ case " $_spl_blocked_words " in
821
+ *" $_spl_mod "*)
542
822
  _spl_progress=1
543
823
  continue
544
- fi
824
+ ;;
825
+ esac
545
826
  _spl_ready=1
546
827
  _spl_blocked_by=
547
- _spl_requires=$(command cat "$_spl_tmp/deps/$_spl_mod" 2>/dev/null)
548
- _spl_optional=$(command cat "$_spl_tmp/optional/$_spl_mod" 2>/dev/null)
828
+ _spl_requires=
829
+ [ -f "$_spl_tmp/deps/$_spl_mod" ] && {
830
+ IFS= read -r _spl_requires <"$_spl_tmp/deps/$_spl_mod" || :
831
+ }
832
+ _spl_optional=
833
+ [ -f "$_spl_tmp/optional/$_spl_mod" ] && {
834
+ IFS= read -r _spl_optional <"$_spl_tmp/optional/$_spl_mod" || :
835
+ }
549
836
  if [ "${IFS+x}" = x ]; then
550
837
  _spl_topo_ifs_was_set=1
551
838
  _spl_topo_old_ifs=${IFS-}
@@ -555,18 +842,36 @@ sp_loader_load_modules() {
555
842
  fi
556
843
  IFS=' '
557
844
  for _spl_dep in $_spl_requires; do
558
- if command grep -qx "$_spl_dep" "$_spl_tmp/blocked" 2>/dev/null; then
845
+ case " $_spl_blocked_words " in
846
+ *" $_spl_dep "*)
559
847
  _spl_ready=0
560
848
  _spl_blocked_by=$_spl_dep
561
- elif ! command grep -qx "$_spl_dep" "$_spl_tmp/order" 2>/dev/null; then
849
+ ;;
850
+ esac
851
+ case " $_spl_order_words " in
852
+ *" $_spl_dep "*) ;;
853
+ *)
562
854
  _spl_ready=0
563
- fi
855
+ ;;
856
+ esac
564
857
  done
565
858
  if [ "$_spl_ready" -eq 1 ]; then
566
859
  for _spl_dep in $_spl_optional; do
567
- if command grep -qx "$_spl_dep" "$_spl_tmp/modules" 2>/dev/null && ! command grep -qx "$_spl_dep" "$_spl_tmp/blocked" 2>/dev/null && ! command grep -qx "$_spl_dep" "$_spl_tmp/order" 2>/dev/null; then
568
- _spl_ready=0
569
- fi
860
+ case " $_spl_modules_words " in
861
+ *" $_spl_dep "*)
862
+ case " $_spl_blocked_words " in
863
+ *" $_spl_dep "*) ;;
864
+ *)
865
+ case " $_spl_order_words " in
866
+ *" $_spl_dep "*) ;;
867
+ *)
868
+ _spl_ready=0
869
+ ;;
870
+ esac
871
+ ;;
872
+ esac
873
+ ;;
874
+ esac
570
875
  done
571
876
  fi
572
877
  if [ "$_spl_topo_ifs_was_set" -eq 1 ]; then
@@ -577,13 +882,16 @@ sp_loader_load_modules() {
577
882
  if [ -n "$_spl_blocked_by" ]; then
578
883
  command printf 'loader: %s\n' "$_spl_mod: required dependency unavailable: $_spl_blocked_by" >&2
579
884
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/blocked"
885
+ _spl_blocked_words="$_spl_blocked_words $_spl_mod"
580
886
  command sort -u "$_spl_tmp/blocked" >"$_spl_tmp/blocked.sorted"
581
887
  command mv "$_spl_tmp/blocked.sorted" "$_spl_tmp/blocked"
888
+ [ "$_spl_mode" = strict ] && case " $_spl_strict_required_words " in *" $_spl_mod "*) _spl_strict_error=1 ;; esac
582
889
  _spl_progress=1
583
890
  continue
584
891
  fi
585
892
  if [ "$_spl_ready" -eq 1 ]; then
586
893
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/order"
894
+ _spl_order_words="$_spl_order_words $_spl_mod"
587
895
  _spl_progress=1
588
896
  else
589
897
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/next_remaining"
@@ -593,13 +901,18 @@ sp_loader_load_modules() {
593
901
  : >"$_spl_tmp/next_remaining.optional"
594
902
  while IFS= read -r _spl_mod || [ -n "$_spl_mod" ]; do
595
903
  [ -n "$_spl_mod" ] || continue
596
- if command grep -qx "$_spl_mod" "$_spl_tmp/blocked" 2>/dev/null; then
904
+ case " $_spl_blocked_words " in
905
+ *" $_spl_mod "*)
597
906
  _spl_progress=1
598
907
  continue
599
- fi
908
+ ;;
909
+ esac
600
910
  _spl_ready=1
601
911
  _spl_blocked_by=
602
- _spl_requires=$(command cat "$_spl_tmp/deps/$_spl_mod" 2>/dev/null)
912
+ _spl_requires=
913
+ [ -f "$_spl_tmp/deps/$_spl_mod" ] && {
914
+ IFS= read -r _spl_requires <"$_spl_tmp/deps/$_spl_mod" || :
915
+ }
603
916
  if [ "${IFS+x}" = x ]; then
604
917
  _spl_topo_ifs_was_set=1
605
918
  _spl_topo_old_ifs=${IFS-}
@@ -609,12 +922,18 @@ sp_loader_load_modules() {
609
922
  fi
610
923
  IFS=' '
611
924
  for _spl_dep in $_spl_requires; do
612
- if command grep -qx "$_spl_dep" "$_spl_tmp/blocked" 2>/dev/null; then
925
+ case " $_spl_blocked_words " in
926
+ *" $_spl_dep "*)
613
927
  _spl_ready=0
614
928
  _spl_blocked_by=$_spl_dep
615
- elif ! command grep -qx "$_spl_dep" "$_spl_tmp/order" 2>/dev/null; then
929
+ ;;
930
+ esac
931
+ case " $_spl_order_words " in
932
+ *" $_spl_dep "*) ;;
933
+ *)
616
934
  _spl_ready=0
617
- fi
935
+ ;;
936
+ esac
618
937
  done
619
938
  if [ "$_spl_topo_ifs_was_set" -eq 1 ]; then
620
939
  IFS=$_spl_topo_old_ifs
@@ -624,6 +943,7 @@ sp_loader_load_modules() {
624
943
  if [ -n "$_spl_blocked_by" ]; then
625
944
  command printf 'loader: %s\n' "$_spl_mod: required dependency unavailable: $_spl_blocked_by" >&2
626
945
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/blocked"
946
+ _spl_blocked_words="$_spl_blocked_words $_spl_mod"
627
947
  command sort -u "$_spl_tmp/blocked" >"$_spl_tmp/blocked.sorted"
628
948
  command mv "$_spl_tmp/blocked.sorted" "$_spl_tmp/blocked"
629
949
  _spl_progress=1
@@ -631,6 +951,7 @@ sp_loader_load_modules() {
631
951
  fi
632
952
  if [ "$_spl_ready" -eq 1 ]; then
633
953
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/order"
954
+ _spl_order_words="$_spl_order_words $_spl_mod"
634
955
  _spl_progress=1
635
956
  else
636
957
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/next_remaining.optional"
@@ -640,14 +961,18 @@ sp_loader_load_modules() {
640
961
  fi
641
962
  if [ "$_spl_progress" -eq 0 ]; then
642
963
  command printf '%s\n' 'loader: cycle detected in module dependencies' >&2
643
- command cat "$_spl_tmp/remaining" >>"$_spl_tmp/blocked"
964
+ while IFS= read -r _spl_mod || [ -n "$_spl_mod" ]; do
965
+ [ -n "$_spl_mod" ] || continue
966
+ command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/blocked"
967
+ _spl_blocked_words="$_spl_blocked_words $_spl_mod"
968
+ done <"$_spl_tmp/remaining"
644
969
  command sort -u "$_spl_tmp/blocked" >"$_spl_tmp/blocked.sorted"
645
970
  command mv "$_spl_tmp/blocked.sorted" "$_spl_tmp/blocked"
646
971
  if [ "$_spl_mode" = strict ]; then
647
972
  while IFS= read -r _spl_mod || [ -n "$_spl_mod" ]; do
648
- if command grep -qx "$_spl_mod" "$_spl_tmp/strict_required" 2>/dev/null; then
649
- _spl_strict_error=1
650
- fi
973
+ case " $_spl_strict_required_words " in
974
+ *" $_spl_mod "*) _spl_strict_error=1 ;;
975
+ esac
651
976
  done <"$_spl_tmp/remaining"
652
977
  fi
653
978
  : >"$_spl_tmp/remaining"
@@ -661,14 +986,46 @@ sp_loader_load_modules() {
661
986
  _spl_return=1
662
987
  fi
663
988
 
664
- if [ "$_spl_return" -eq 0 ]; then
989
+ if [ "$_spl_return" -eq 0 ] && [ "${VALISE_RELOAD:-}" = 1 ]; then
665
990
  while IFS= read -r _spl_mod || [ -n "$_spl_mod" ]; do
666
991
  [ -n "$_spl_mod" ] || continue
667
- if command grep -qx "$_spl_mod" "$_spl_tmp/blocked" 2>/dev/null; then
668
- continue
992
+ _spl_exports=
993
+ while IFS= read -r _spl_run_line || [ -n "$_spl_run_line" ]; do
994
+ case $_spl_run_line in
995
+ exports=*) _spl_exports=${_spl_run_line#exports=} ;;
996
+ esac
997
+ done <"$_spl_tmp/run/$_spl_mod"
998
+ unset _spl_run_line
999
+ if [ "${IFS+x}" = x ]; then
1000
+ _spl_reload_ifs_was_set=1
1001
+ _spl_reload_old_ifs=${IFS-}
1002
+ else
1003
+ _spl_reload_ifs_was_set=0
1004
+ _spl_reload_old_ifs=
1005
+ fi
1006
+ IFS=' '
1007
+ for _spl_export in $_spl_exports; do
1008
+ unset -f "$_spl_export" 2>/dev/null || :
1009
+ done
1010
+ if [ "$_spl_reload_ifs_was_set" -eq 1 ]; then
1011
+ IFS=$_spl_reload_old_ifs
1012
+ else
1013
+ unset IFS
669
1014
  fi
1015
+ done <"$_spl_tmp/order"
1016
+ fi
1017
+
1018
+ if [ "$_spl_return" -eq 0 ]; then
1019
+ while IFS= read -r _spl_mod || [ -n "$_spl_mod" ]; do
1020
+ [ -n "$_spl_mod" ] || continue
1021
+ case " $_spl_blocked_words " in
1022
+ *" $_spl_mod "*) continue ;;
1023
+ esac
670
1024
  _spl_runtime_skip=0
671
- _spl_requires=$(command cat "$_spl_tmp/deps/$_spl_mod" 2>/dev/null)
1025
+ _spl_requires=
1026
+ [ -f "$_spl_tmp/deps/$_spl_mod" ] && {
1027
+ IFS= read -r _spl_requires <"$_spl_tmp/deps/$_spl_mod" || :
1028
+ }
672
1029
  if [ "${IFS+x}" = x ]; then
673
1030
  _spl_run_ifs_was_set=1
674
1031
  _spl_run_old_ifs=${IFS-}
@@ -678,10 +1035,12 @@ sp_loader_load_modules() {
678
1035
  fi
679
1036
  IFS=' '
680
1037
  for _spl_dep in $_spl_requires; do
681
- if command grep -qx "$_spl_dep" "$_spl_tmp/failed" 2>/dev/null; then
1038
+ case " $_spl_failed_words " in
1039
+ *" $_spl_dep "*)
682
1040
  command printf 'loader: %s\n' "$_spl_mod: required dependency failed: $_spl_dep" >&2
683
1041
  _spl_runtime_skip=1
684
- fi
1042
+ ;;
1043
+ esac
685
1044
  done
686
1045
  if [ "$_spl_run_ifs_was_set" -eq 1 ]; then
687
1046
  IFS=$_spl_run_old_ifs
@@ -690,14 +1049,22 @@ sp_loader_load_modules() {
690
1049
  fi
691
1050
  if [ "$_spl_runtime_skip" -ne 0 ]; then
692
1051
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/failed"
693
- [ "$_spl_mode" = strict ] && command grep -qx "$_spl_mod" "$_spl_tmp/strict_required" 2>/dev/null && _spl_return=1 && break
1052
+ _spl_failed_words="$_spl_failed_words $_spl_mod"
1053
+ [ "$_spl_mode" = strict ] && case " $_spl_strict_required_words " in *" $_spl_mod "*) _spl_return=1 && break ;; esac
694
1054
  continue
695
1055
  fi
696
1056
  _spl_record=$_spl_tmp/meta/$_spl_mod
697
- _spl_load=$(command sed -n 's/^load=//p' "$_spl_record")
698
- _spl_load_hook=$(command sed -n 's/^load_hook=//p' "$_spl_record")
699
- _spl_exports=$(command sed -n 's/^exports=//p' "$_spl_record")
1057
+ _spl_load=
1058
+ _spl_exports=
1059
+ while IFS= read -r _spl_run_line || [ -n "$_spl_run_line" ]; do
1060
+ case $_spl_run_line in
1061
+ load=*) _spl_load=${_spl_run_line#load=} ;;
1062
+ exports=*) _spl_exports=${_spl_run_line#exports=} ;;
1063
+ esac
1064
+ done <"$_spl_tmp/run/$_spl_mod"
1065
+ unset _spl_run_line
700
1066
  _spl_exports_to_cleanup=
1067
+ _spl_wrapper_exports=
701
1068
  _spl_load_status=0
702
1069
  if [ "${IFS+x}" = x ]; then
703
1070
  _spl_export_ifs_was_set=1
@@ -708,7 +1075,20 @@ sp_loader_load_modules() {
708
1075
  fi
709
1076
  IFS=' '
710
1077
  for _spl_export in $_spl_exports; do
711
- if command -v "$_spl_export" >/dev/null 2>&1; then
1078
+ _spl_export_conflict=0
1079
+ if command alias "$_spl_export" >/dev/null 2>&1; then
1080
+ _spl_export_conflict=1
1081
+ fi
1082
+ if _spl_export_lookup=$(command -v "$_spl_export" 2>/dev/null); then
1083
+ case $_spl_export_lookup in
1084
+ alias\ *) _spl_export_conflict=1 ;;
1085
+ */*) _spl_wrapper_exports=${_spl_wrapper_exports:+$_spl_wrapper_exports }$_spl_export ;;
1086
+ *) _spl_export_conflict=1 ;;
1087
+ esac
1088
+ else
1089
+ _spl_export_lookup=
1090
+ fi
1091
+ if [ "$_spl_export_conflict" -ne 0 ]; then
712
1092
  command printf 'loader: %s\n' "$_spl_mod: declared export already exists before load: $_spl_export" >&2
713
1093
  _spl_load_status=1
714
1094
  else
@@ -740,7 +1120,6 @@ sp_loader_load_modules() {
740
1120
  _spl_expected_mod=$_spl_mod
741
1121
  _spl_expected_record=$_spl_record
742
1122
  _spl_expected_load=$_spl_load
743
- _spl_expected_load_hook=$_spl_load_hook
744
1123
  _spl_expected_exports=$_spl_exports
745
1124
  _spl_expected_exports_to_cleanup=$_spl_exports_to_cleanup
746
1125
  _spl_guard_tmp=$_spl_expected_tmp
@@ -763,11 +1142,35 @@ sp_loader_load_modules() {
763
1142
  _spl_guard_mod=$_spl_expected_mod
764
1143
  _spl_guard_record=$_spl_expected_record
765
1144
  _spl_guard_load=$_spl_expected_load
766
- _spl_guard_load_hook=$_spl_expected_load_hook
767
1145
  _spl_guard_exports=$_spl_expected_exports
768
1146
  _spl_guard_exports_to_cleanup=$_spl_expected_exports_to_cleanup
769
- _spl_expected_pwd=$(command pwd -P 2>/dev/null)
1147
+ _spl_guard_wrapper_exports=$_spl_wrapper_exports
1148
+ _spl_guard_seen_words=$_spl_seen_words
1149
+ _spl_guard_strict_required_words=$_spl_strict_required_words
1150
+ _spl_guard_blocked_words=$_spl_blocked_words
1151
+ _spl_guard_modules_words=$_spl_modules_words
1152
+ _spl_guard_order_words=$_spl_order_words
1153
+ _spl_guard_failed_words=$_spl_failed_words
1154
+ _spl_expected_pwd_was_set=0
1155
+ _spl_expected_pwd=
1156
+ if [ "${PWD+x}" = x ]; then
1157
+ _spl_expected_pwd_was_set=1
1158
+ _spl_expected_pwd=${PWD-}
1159
+ fi
1160
+ _spl_expected_oldpwd_was_set=0
1161
+ _spl_expected_oldpwd=
1162
+ if [ "${OLDPWD+x}" = x ]; then
1163
+ _spl_expected_oldpwd_was_set=1
1164
+ _spl_expected_oldpwd=${OLDPWD-}
1165
+ fi
1166
+ _spl_expected_pwd_physical=$(command pwd -P 2>/dev/null)
770
1167
  _spl_expected_pwd_status=$?
1168
+ _spl_guard_expected_pwd_was_set=$_spl_expected_pwd_was_set
1169
+ _spl_guard_expected_pwd=$_spl_expected_pwd
1170
+ _spl_guard_expected_oldpwd_was_set=$_spl_expected_oldpwd_was_set
1171
+ _spl_guard_expected_oldpwd=$_spl_expected_oldpwd
1172
+ _spl_guard_expected_pwd_physical=$_spl_expected_pwd_physical
1173
+ _spl_guard_expected_pwd_status=$_spl_expected_pwd_status
771
1174
  if [ "${IFS+x}" = x ]; then
772
1175
  _spl_expected_ifs_was_set=1
773
1176
  _spl_expected_ifs=${IFS-}
@@ -803,49 +1206,35 @@ sp_loader_load_modules() {
803
1206
  *x*) _spl_expected_xtrace_was_set=1 ;;
804
1207
  *) _spl_expected_xtrace_was_set=0 ;;
805
1208
  esac
806
- _spl_reserved_utility_pattern='^[[:space:]]*(((function[[:space:]]+)?(command|unset|readonly|return|eval)[[:space:]]*[(][)][[:space:]]*[{])|(function[[:space:]]+(command|unset|readonly|return|eval)([[:space:]]|$))|(readonly[[:space:]].*-f[[:space:]].*(command|unset|readonly|return|eval)([[:space:]]|$)))'
807
- if [ "$_spl_load_status" -eq 0 ] && [ -n "$_spl_load_hook" ]; then
808
- if command -v "$_spl_load_hook" >/dev/null 2>&1; then
809
- _spl_hook_body=$_spl_tmp/hook-body
810
- : >"$_spl_hook_body"
811
- case $_spl_current_shell in
812
- bash) command declare -f "$_spl_load_hook" >"$_spl_hook_body" 2>/dev/null || : ;;
813
- zsh) functions "$_spl_load_hook" >"$_spl_hook_body" 2>/dev/null || : ;;
814
- ksh) command typeset -f "$_spl_load_hook" >"$_spl_hook_body" 2>/dev/null || : ;;
815
- esac
816
- if [ -s "$_spl_hook_body" ] && command grep -Eq "$_spl_reserved_utility_pattern" "$_spl_hook_body" 2>/dev/null; then
817
- command printf 'loader: %s\n' "$_spl_mod: load hook defines reserved shell utility" >&2
818
- _spl_load_status=126
819
- else
820
- "$_spl_load_hook" || _spl_load_status=$?
821
- fi
822
- else
823
- command printf 'loader: %s\n' "$_spl_mod: load hook not found: $_spl_load_hook" >&2
824
- _spl_load_status=127
825
- fi
826
- elif [ "$_spl_load_status" -eq 0 ]; then
1209
+ if [ "$_spl_load_status" -eq 0 ] && [ -n "$_spl_load" ]; then
827
1210
  if [ ! -f "$_spl_tmp/roots/$_spl_mod" ]; then
828
1211
  command printf 'loader: %s\n' "$_spl_mod: providing module root was not recorded during discovery" >&2
829
1212
  _spl_load_status=126
830
1213
  else
831
- _spl_load_path=$(command cat "$_spl_tmp/roots/$_spl_mod")/$_spl_load
832
- if ! _sp_loader_path_is_physical "$(command cat "$_spl_tmp/roots/$_spl_mod")" "$_spl_load_path"; then
1214
+ _spl_module_root=
1215
+ IFS= read -r _spl_module_root <"$_spl_tmp/roots/$_spl_mod" || :
1216
+ _spl_load_path=$_spl_module_root/$_spl_load
1217
+ if ! _sp_loader_path_is_physical "$_spl_module_root" "$_spl_load_path"; then
833
1218
  command printf 'loader: %s\n' "$_spl_mod: load path contains a symlink: $_spl_load" >&2
834
1219
  _spl_load_status=126
835
- elif [ -r "$_spl_load_path" ]; then
836
- if command grep -Eq "$_spl_reserved_utility_pattern" "$_spl_load_path" 2>/dev/null; then
837
- command printf 'loader: %s\n' "$_spl_mod: load path defines reserved shell utility" >&2
838
- _spl_load_status=126
1220
+ unset _spl_module_root
1221
+ else
1222
+ unset _spl_module_root
1223
+ if [ -r "$_spl_load_path" ]; then
1224
+ if ! _sp_loader_reserved_scan "$_spl_load_path"; then
1225
+ command printf 'loader: %s\n' "$_spl_mod: load path defines reserved shell utility" >&2
1226
+ _spl_load_status=126
1227
+ else
1228
+ . "$_spl_load_path" || _spl_load_status=$?
1229
+ fi
839
1230
  else
840
- . "$_spl_load_path" || _spl_load_status=$?
1231
+ command printf 'loader: %s\n' "$_spl_mod: load path is not readable: $_spl_load" >&2
1232
+ _spl_load_status=126
841
1233
  fi
842
- else
843
- command printf 'loader: %s\n' "$_spl_mod: load path is not readable: $_spl_load" >&2
844
- _spl_load_status=126
845
1234
  fi
846
1235
  fi
847
1236
  fi
848
- unset -f command 2>/dev/null || :
1237
+ unset -f command builtin 2>/dev/null || :
849
1238
  case $- in
850
1239
  *u*)
851
1240
  _spl_after_nounset_was_set=1
@@ -854,7 +1243,7 @@ sp_loader_load_modules() {
854
1243
  *) _spl_after_nounset_was_set=0 ;;
855
1244
  esac
856
1245
  _spl_private_modified=0
857
- if [ "${_spl_expected_tmp-}" != "${_spl_guard_tmp-}" ] || [ "${_spl_expected_cleanup_tmp-}" != "${_spl_guard_cleanup_tmp-}" ] || [ "${_spl_expected_tmp_parent-}" != "${_spl_guard_tmp_parent-}" ] || [ "${_spl_expected_tmp_sentinel-}" != "${_spl_guard_tmp_sentinel-}" ] || [ "${_spl_expected_root-}" != "${_spl_guard_root-}" ] || [ "${_spl_expected_wanted-}" != "${_spl_guard_wanted-}" ] || [ "${_spl_expected_mode-}" != "${_spl_guard_mode-}" ] || [ "${_spl_expected_phase-}" != "${_spl_guard_phase-}" ] || [ "${_spl_expected_return-}" != "${_spl_guard_return-}" ] || [ "${_spl_expected_strict_error-}" != "${_spl_guard_strict_error-}" ] || [ "${_spl_expected_current_shell-}" != "${_spl_guard_current_shell-}" ] || [ "${_spl_expected_current_platform-}" != "${_spl_guard_current_platform-}" ] || [ "${_spl_expected_mod-}" != "${_spl_guard_mod-}" ] || [ "${_spl_expected_record-}" != "${_spl_guard_record-}" ] || [ "${_spl_expected_load-}" != "${_spl_guard_load-}" ] || [ "${_spl_expected_load_hook-}" != "${_spl_guard_load_hook-}" ] || [ "${_spl_expected_exports-}" != "${_spl_guard_exports-}" ] || [ "${_spl_expected_exports_to_cleanup-}" != "${_spl_guard_exports_to_cleanup-}" ] || [ "${_spl_expected_search_path-}" != "${_spl_guard_search_path-}" ] || [ "${_spl_expected_meta_file-}" != "${_spl_guard_meta_file-}" ] || [ "${_spl_expected_meta_root-}" != "${_spl_guard_meta_root-}" ] || [ "${_spl_expected_layer-}" != "${_spl_guard_layer-}" ] || [ "${_spl_expected_dep_exists-}" != "${_spl_guard_dep_exists-}" ]; then
1246
+ if [ "${_spl_expected_tmp-}" != "${_spl_guard_tmp-}" ] || [ "${_spl_expected_cleanup_tmp-}" != "${_spl_guard_cleanup_tmp-}" ] || [ "${_spl_expected_tmp_parent-}" != "${_spl_guard_tmp_parent-}" ] || [ "${_spl_expected_tmp_sentinel-}" != "${_spl_guard_tmp_sentinel-}" ] || [ "${_spl_expected_root-}" != "${_spl_guard_root-}" ] || [ "${_spl_expected_wanted-}" != "${_spl_guard_wanted-}" ] || [ "${_spl_expected_mode-}" != "${_spl_guard_mode-}" ] || [ "${_spl_expected_phase-}" != "${_spl_guard_phase-}" ] || [ "${_spl_expected_return-}" != "${_spl_guard_return-}" ] || [ "${_spl_expected_strict_error-}" != "${_spl_guard_strict_error-}" ] || [ "${_spl_expected_current_shell-}" != "${_spl_guard_current_shell-}" ] || [ "${_spl_expected_current_platform-}" != "${_spl_guard_current_platform-}" ] || [ "${_spl_expected_mod-}" != "${_spl_guard_mod-}" ] || [ "${_spl_expected_record-}" != "${_spl_guard_record-}" ] || [ "${_spl_expected_load-}" != "${_spl_guard_load-}" ] || [ "${_spl_expected_exports-}" != "${_spl_guard_exports-}" ] || [ "${_spl_expected_exports_to_cleanup-}" != "${_spl_guard_exports_to_cleanup-}" ] || [ "${_spl_wrapper_exports-}" != "${_spl_guard_wrapper_exports-}" ] || [ "${_spl_seen_words-}" != "${_spl_guard_seen_words-}" ] || [ "${_spl_strict_required_words-}" != "${_spl_guard_strict_required_words-}" ] || [ "${_spl_blocked_words-}" != "${_spl_guard_blocked_words-}" ] || [ "${_spl_modules_words-}" != "${_spl_guard_modules_words-}" ] || [ "${_spl_order_words-}" != "${_spl_guard_order_words-}" ] || [ "${_spl_failed_words-}" != "${_spl_guard_failed_words-}" ] || [ "${_spl_expected_pwd_was_set-}" != "${_spl_guard_expected_pwd_was_set-}" ] || [ "${_spl_expected_pwd-}" != "${_spl_guard_expected_pwd-}" ] || [ "${_spl_expected_oldpwd_was_set-}" != "${_spl_guard_expected_oldpwd_was_set-}" ] || [ "${_spl_expected_oldpwd-}" != "${_spl_guard_expected_oldpwd-}" ] || [ "${_spl_expected_pwd_physical-}" != "${_spl_guard_expected_pwd_physical-}" ] || [ "${_spl_expected_pwd_status-}" != "${_spl_guard_expected_pwd_status-}" ] || [ "${_spl_expected_search_path-}" != "${_spl_guard_search_path-}" ] || [ "${_spl_expected_meta_file-}" != "${_spl_guard_meta_file-}" ] || [ "${_spl_expected_meta_root-}" != "${_spl_guard_meta_root-}" ] || [ "${_spl_expected_layer-}" != "${_spl_guard_layer-}" ] || [ "${_spl_expected_dep_exists-}" != "${_spl_guard_dep_exists-}" ]; then
858
1247
  _spl_private_modified=1
859
1248
  _spl_expected_tmp=$_spl_guard_tmp
860
1249
  _spl_expected_cleanup_tmp=$_spl_guard_cleanup_tmp
@@ -876,11 +1265,23 @@ sp_loader_load_modules() {
876
1265
  _spl_expected_mod=$_spl_guard_mod
877
1266
  _spl_expected_record=$_spl_guard_record
878
1267
  _spl_expected_load=$_spl_guard_load
879
- _spl_expected_load_hook=$_spl_guard_load_hook
880
1268
  _spl_expected_exports=$_spl_guard_exports
881
1269
  _spl_expected_exports_to_cleanup=$_spl_guard_exports_to_cleanup
1270
+ _spl_wrapper_exports=$_spl_guard_wrapper_exports
1271
+ _spl_seen_words=$_spl_guard_seen_words
1272
+ _spl_strict_required_words=$_spl_guard_strict_required_words
1273
+ _spl_blocked_words=$_spl_guard_blocked_words
1274
+ _spl_modules_words=$_spl_guard_modules_words
1275
+ _spl_order_words=$_spl_guard_order_words
1276
+ _spl_failed_words=$_spl_guard_failed_words
1277
+ _spl_expected_pwd_was_set=$_spl_guard_expected_pwd_was_set
1278
+ _spl_expected_pwd=$_spl_guard_expected_pwd
1279
+ _spl_expected_oldpwd_was_set=$_spl_guard_expected_oldpwd_was_set
1280
+ _spl_expected_oldpwd=$_spl_guard_expected_oldpwd
1281
+ _spl_expected_pwd_physical=$_spl_guard_expected_pwd_physical
1282
+ _spl_expected_pwd_status=$_spl_guard_expected_pwd_status
882
1283
  fi
883
- if [ "$_spl_tmp" != "$_spl_expected_tmp" ] || [ "$_spl_cleanup_tmp" != "$_spl_expected_cleanup_tmp" ] || [ "$_spl_tmp_parent" != "$_spl_expected_tmp_parent" ] || [ "$_spl_tmp_sentinel" != "$_spl_expected_tmp_sentinel" ] || [ "$_spl_root" != "$_spl_expected_root" ] || [ "$_spl_wanted" != "$_spl_expected_wanted" ] || [ "$_spl_mode" != "$_spl_expected_mode" ] || [ "$_spl_phase" != "$_spl_expected_phase" ] || [ "$_spl_return" != "$_spl_expected_return" ] || [ "$_spl_strict_error" != "$_spl_expected_strict_error" ] || [ "$_spl_current_shell" != "$_spl_expected_current_shell" ] || [ "$_spl_current_platform" != "$_spl_expected_current_platform" ] || [ "$_spl_mod" != "$_spl_expected_mod" ] || [ "$_spl_record" != "$_spl_expected_record" ] || [ "$_spl_load" != "$_spl_expected_load" ] || [ "$_spl_load_hook" != "$_spl_expected_load_hook" ] || [ "$_spl_exports" != "$_spl_expected_exports" ] || [ "$_spl_exports_to_cleanup" != "$_spl_expected_exports_to_cleanup" ] || [ "${_spl_search_path-}" != "${_spl_expected_search_path-}" ] || [ "${_spl_meta_file-}" != "${_spl_expected_meta_file-}" ] || [ "${_spl_meta_root-}" != "${_spl_expected_meta_root-}" ] || [ "${_spl_layer-}" != "${_spl_expected_layer-}" ] || [ "${_spl_dep_exists-}" != "${_spl_expected_dep_exists-}" ]; then
1284
+ if [ "$_spl_tmp" != "$_spl_expected_tmp" ] || [ "$_spl_cleanup_tmp" != "$_spl_expected_cleanup_tmp" ] || [ "$_spl_tmp_parent" != "$_spl_expected_tmp_parent" ] || [ "$_spl_tmp_sentinel" != "$_spl_expected_tmp_sentinel" ] || [ "$_spl_root" != "$_spl_expected_root" ] || [ "$_spl_wanted" != "$_spl_expected_wanted" ] || [ "$_spl_mode" != "$_spl_expected_mode" ] || [ "$_spl_phase" != "$_spl_expected_phase" ] || [ "$_spl_return" != "$_spl_expected_return" ] || [ "$_spl_strict_error" != "$_spl_expected_strict_error" ] || [ "$_spl_current_shell" != "$_spl_expected_current_shell" ] || [ "$_spl_current_platform" != "$_spl_expected_current_platform" ] || [ "$_spl_mod" != "$_spl_expected_mod" ] || [ "$_spl_record" != "$_spl_expected_record" ] || [ "$_spl_load" != "$_spl_expected_load" ] || [ "$_spl_exports" != "$_spl_expected_exports" ] || [ "$_spl_exports_to_cleanup" != "$_spl_expected_exports_to_cleanup" ] || [ "${_spl_search_path-}" != "${_spl_expected_search_path-}" ] || [ "${_spl_meta_file-}" != "${_spl_expected_meta_file-}" ] || [ "${_spl_meta_root-}" != "${_spl_expected_meta_root-}" ] || [ "${_spl_layer-}" != "${_spl_expected_layer-}" ] || [ "${_spl_dep_exists-}" != "${_spl_expected_dep_exists-}" ]; then
884
1285
  _spl_private_modified=1
885
1286
  _spl_tmp=$_spl_expected_tmp
886
1287
  _spl_cleanup_tmp=$_spl_expected_cleanup_tmp
@@ -902,17 +1303,107 @@ sp_loader_load_modules() {
902
1303
  _spl_mod=$_spl_expected_mod
903
1304
  _spl_record=$_spl_expected_record
904
1305
  _spl_load=$_spl_expected_load
905
- _spl_load_hook=$_spl_expected_load_hook
906
1306
  _spl_exports=$_spl_expected_exports
907
1307
  _spl_exports_to_cleanup=$_spl_expected_exports_to_cleanup
908
1308
  fi
909
1309
  _spl_shell_state_modified=0
1310
+ _spl_after_pwd_physical=$(command pwd -P 2>/dev/null)
1311
+ _spl_after_pwd_physical_status=$?
910
1312
  if [ "$_spl_expected_pwd_status" -eq 0 ]; then
911
- _spl_after_pwd=$(command pwd -P 2>/dev/null)
912
- if [ "$_spl_after_pwd" != "$_spl_expected_pwd" ]; then
1313
+ if [ "$_spl_after_pwd_physical_status" -ne 0 ] || [ "$_spl_after_pwd_physical" != "$_spl_expected_pwd_physical" ]; then
1314
+ _spl_shell_state_modified=1
1315
+ fi
1316
+ fi
1317
+ # A module may change directory and come back; that leaves the physical
1318
+ # cwd intact and only moves the logical PWD and OLDPWD, which are restored
1319
+ # below. The logical values are evidence of a move only when the physical
1320
+ # cwd could not be read before the module ran.
1321
+ if [ "$_spl_expected_pwd_status" -ne 0 ]; then
1322
+ if [ "${PWD+x}" = x ]; then
1323
+ _spl_after_pwd_was_set=1
1324
+ else
1325
+ _spl_after_pwd_was_set=0
1326
+ fi
1327
+ if [ "$_spl_after_pwd_was_set" -ne "$_spl_expected_pwd_was_set" ]; then
1328
+ _spl_shell_state_modified=1
1329
+ elif [ "$_spl_expected_pwd_was_set" -eq 1 ] && [ "${PWD-}" != "$_spl_expected_pwd" ]; then
1330
+ _spl_shell_state_modified=1
1331
+ fi
1332
+ if [ "${OLDPWD+x}" = x ]; then
1333
+ _spl_after_oldpwd_was_set=1
1334
+ else
1335
+ _spl_after_oldpwd_was_set=0
1336
+ fi
1337
+ if [ "$_spl_after_oldpwd_was_set" -ne "$_spl_expected_oldpwd_was_set" ]; then
1338
+ _spl_shell_state_modified=1
1339
+ elif [ "$_spl_expected_oldpwd_was_set" -eq 1 ] && [ "${OLDPWD-}" != "$_spl_expected_oldpwd" ]; then
913
1340
  _spl_shell_state_modified=1
914
1341
  fi
915
- CDPATH= command cd "$_spl_expected_pwd" 2>/dev/null || _spl_shell_state_modified=1
1342
+ fi
1343
+ _spl_pwd_cwd_restored=1
1344
+ if [ "$_spl_expected_pwd_status" -eq 0 ]; then
1345
+ if [ "$_spl_after_pwd_physical_status" -ne 0 ] || [ "$_spl_after_pwd_physical" != "$_spl_expected_pwd_physical" ]; then
1346
+ _spl_cwd_restore_attempt=0
1347
+ if [ "$_spl_current_shell" = zsh ]; then
1348
+ if (\builtin cd . >/dev/null 2>&1); then
1349
+ CDPATH= \builtin cd "$_spl_expected_pwd_physical" 2>/dev/null && _spl_cwd_restore_attempt=1
1350
+ fi
1351
+ else
1352
+ CDPATH= command cd "$_spl_expected_pwd_physical" 2>/dev/null && _spl_cwd_restore_attempt=1
1353
+ fi
1354
+ _spl_restored_pwd_physical=$(command pwd -P 2>/dev/null)
1355
+ _spl_restored_pwd_status=$?
1356
+ if [ "$_spl_cwd_restore_attempt" -eq 0 ] || [ "$_spl_restored_pwd_status" -ne 0 ] || [ "$_spl_restored_pwd_physical" != "$_spl_expected_pwd_physical" ]; then
1357
+ _spl_cwd_restore_attempt=0
1358
+ if [ "$_spl_current_shell" != zsh ] && (\builtin cd . >/dev/null 2>&1); then
1359
+ CDPATH= \builtin cd "$_spl_expected_pwd_physical" 2>/dev/null && _spl_cwd_restore_attempt=1
1360
+ fi
1361
+ _spl_restored_pwd_physical=$(command pwd -P 2>/dev/null)
1362
+ _spl_restored_pwd_status=$?
1363
+ fi
1364
+ if [ "$_spl_cwd_restore_attempt" -eq 0 ] || [ "$_spl_restored_pwd_status" -ne 0 ] || [ "$_spl_restored_pwd_physical" != "$_spl_expected_pwd_physical" ]; then
1365
+ _spl_shell_state_modified=1
1366
+ _spl_pwd_cwd_restored=0
1367
+ fi
1368
+ fi
1369
+ else
1370
+ _spl_pwd_cwd_restored=0
1371
+ fi
1372
+ if [ "$_spl_pwd_cwd_restored" -eq 1 ]; then
1373
+ # Assign only when the value differs, and probe first: a module that
1374
+ # made PWD or OLDPWD readonly must fail closed, not abort the loader
1375
+ # before its cleanup runs. The probe is a subshell assignment, so a
1376
+ # readonly variable fails it without touching the caller.
1377
+ _spl_restore_pwd=1
1378
+ if [ "$_spl_expected_pwd_was_set" -eq 1 ]; then
1379
+ if (PWD=$_spl_expected_pwd) >/dev/null 2>&1; then
1380
+ [ "${PWD-}" = "$_spl_expected_pwd" ] || PWD=$_spl_expected_pwd
1381
+ else
1382
+ _spl_restore_pwd=0
1383
+ fi
1384
+ else
1385
+ if (unset PWD) >/dev/null 2>&1; then
1386
+ unset PWD
1387
+ else
1388
+ _spl_restore_pwd=0
1389
+ fi
1390
+ fi
1391
+ [ "$_spl_restore_pwd" -eq 1 ] || _spl_shell_state_modified=1
1392
+ _spl_restore_oldpwd=1
1393
+ if [ "$_spl_expected_oldpwd_was_set" -eq 1 ]; then
1394
+ if (OLDPWD=$_spl_expected_oldpwd) >/dev/null 2>&1; then
1395
+ [ "${OLDPWD-}" = "$_spl_expected_oldpwd" ] || OLDPWD=$_spl_expected_oldpwd
1396
+ else
1397
+ _spl_restore_oldpwd=0
1398
+ fi
1399
+ else
1400
+ if (unset OLDPWD) >/dev/null 2>&1; then
1401
+ unset OLDPWD
1402
+ else
1403
+ _spl_restore_oldpwd=0
1404
+ fi
1405
+ fi
1406
+ [ "$_spl_restore_oldpwd" -eq 1 ] || _spl_shell_state_modified=1
916
1407
  fi
917
1408
  if [ "${IFS+x}" = x ]; then
918
1409
  _spl_after_ifs_was_set=1
@@ -924,11 +1415,21 @@ sp_loader_load_modules() {
924
1415
  elif [ "$_spl_expected_ifs_was_set" -eq 1 ] && [ "${IFS-}" != "$_spl_expected_ifs" ]; then
925
1416
  _spl_shell_state_modified=1
926
1417
  fi
1418
+ _spl_restore_ifs=1
927
1419
  if [ "$_spl_expected_ifs_was_set" -eq 1 ]; then
928
- IFS=$_spl_expected_ifs
1420
+ if (IFS=$_spl_expected_ifs) >/dev/null 2>&1; then
1421
+ [ "${IFS-}" = "$_spl_expected_ifs" ] || IFS=$_spl_expected_ifs
1422
+ else
1423
+ _spl_restore_ifs=0
1424
+ fi
929
1425
  else
930
- unset IFS
1426
+ if (unset IFS) >/dev/null 2>&1; then
1427
+ unset IFS
1428
+ else
1429
+ _spl_restore_ifs=0
1430
+ fi
931
1431
  fi
1432
+ [ "$_spl_restore_ifs" -eq 1 ] || _spl_shell_state_modified=1
932
1433
  case $- in *a*) _spl_after_allexport_was_set=1 ;; *) _spl_after_allexport_was_set=0 ;; esac
933
1434
  case $- in *C*) _spl_after_noclobber_was_set=1 ;; *) _spl_after_noclobber_was_set=0 ;; esac
934
1435
  case $- in *e*) _spl_after_errexit_was_set=1 ;; *) _spl_after_errexit_was_set=0 ;; esac
@@ -968,17 +1469,41 @@ sp_loader_load_modules() {
968
1469
  _spl_export_ifs_was_set=0
969
1470
  _spl_export_old_ifs=
970
1471
  fi
971
- IFS=' '
1472
+ _spl_ifs_ready=1
1473
+ if [ "${IFS+x}" = x ] && [ "${IFS-}" = ' ' ]; then
1474
+ :
1475
+ elif (IFS=' ') >/dev/null 2>&1; then
1476
+ IFS=' '
1477
+ else
1478
+ _spl_ifs_ready=0
1479
+ fi
1480
+ if [ "$_spl_ifs_ready" -eq 0 ] && [ -n "$_spl_exports" ]; then
1481
+ command printf 'loader: %s\n' "$_spl_mod: cannot check declared exports: IFS is readonly" >&2
1482
+ _spl_load_status=1
1483
+ fi
972
1484
  for _spl_export in $_spl_exports; do
973
- if ! command -v "$_spl_export" >/dev/null 2>&1; then
1485
+ if ! _spl_export_lookup=$(command -v "$_spl_export" 2>/dev/null); then
974
1486
  command printf 'loader: %s\n' "$_spl_mod: declared export missing: $_spl_export" >&2
975
1487
  _spl_load_status=1
1488
+ else
1489
+ case " $_spl_wrapper_exports " in
1490
+ *" $_spl_export "*)
1491
+ case $_spl_export_lookup in
1492
+ */*)
1493
+ command printf 'loader: %s\n' "$_spl_mod: declared export was not provided by module: $_spl_export" >&2
1494
+ _spl_load_status=1
1495
+ ;;
1496
+ esac
1497
+ ;;
1498
+ esac
976
1499
  fi
977
1500
  done
978
- if [ "$_spl_export_ifs_was_set" -eq 1 ]; then
979
- IFS=$_spl_export_old_ifs
980
- else
981
- unset IFS
1501
+ if [ "$_spl_ifs_ready" -eq 1 ]; then
1502
+ if [ "$_spl_export_ifs_was_set" -eq 1 ]; then
1503
+ IFS=$_spl_export_old_ifs
1504
+ else
1505
+ unset IFS
1506
+ fi
982
1507
  fi
983
1508
  fi
984
1509
  if [ "$_spl_load_status" -ne 0 ]; then
@@ -989,20 +1514,34 @@ sp_loader_load_modules() {
989
1514
  _spl_export_ifs_was_set=0
990
1515
  _spl_export_old_ifs=
991
1516
  fi
992
- IFS=' '
1517
+ _spl_ifs_ready=1
1518
+ if [ "${IFS+x}" = x ] && [ "${IFS-}" = ' ' ]; then
1519
+ :
1520
+ elif (IFS=' ') >/dev/null 2>&1; then
1521
+ IFS=' '
1522
+ else
1523
+ _spl_ifs_ready=0
1524
+ fi
993
1525
  for _spl_export in $_spl_exports_to_cleanup; do
994
1526
  unset -f "$_spl_export" 2>/dev/null || :
995
1527
  done
996
- if [ "$_spl_export_ifs_was_set" -eq 1 ]; then
997
- IFS=$_spl_export_old_ifs
998
- else
999
- unset IFS
1528
+ if [ "$_spl_ifs_ready" -eq 1 ]; then
1529
+ if [ "$_spl_export_ifs_was_set" -eq 1 ]; then
1530
+ IFS=$_spl_export_old_ifs
1531
+ else
1532
+ unset IFS
1533
+ fi
1000
1534
  fi
1001
1535
  command printf 'loader: %s\n' "$_spl_mod: load failed with status $_spl_load_status" >&2
1002
1536
  command printf '%s\n' "$_spl_mod" >>"$_spl_tmp/failed"
1003
- if [ "$_spl_mode" = strict ] && command grep -qx "$_spl_mod" "$_spl_tmp/strict_required" 2>/dev/null; then
1004
- _spl_return=1
1005
- break
1537
+ _spl_failed_words="$_spl_failed_words $_spl_mod"
1538
+ if [ "$_spl_mode" = strict ]; then
1539
+ case " $_spl_strict_required_words " in
1540
+ *" $_spl_mod "*)
1541
+ _spl_return=1
1542
+ break
1543
+ ;;
1544
+ esac
1006
1545
  fi
1007
1546
  fi
1008
1547
  done <"$_spl_tmp/order"
@@ -1012,7 +1551,18 @@ sp_loader_load_modules() {
1012
1551
  case $_spl_cleanup_tmp in
1013
1552
  "$_spl_tmp_parent"/shell-profile-loader.*)
1014
1553
  if [ -f "$_spl_cleanup_tmp/.shell-profile-loader-owned" ]; then
1015
- command rm -rf "$_spl_cleanup_tmp" 2>/dev/null || :
1554
+ # Resolve rm without PATH: a module may legitimately narrow or replace
1555
+ # PATH, and cleanup must not depend on the value it leaves behind.
1556
+ _spl_cleanup_rm=
1557
+ for _spl_rm_candidate in /bin/rm /usr/bin/rm; do
1558
+ if [ -x "$_spl_rm_candidate" ]; then
1559
+ _spl_cleanup_rm=$_spl_rm_candidate
1560
+ break
1561
+ fi
1562
+ done
1563
+ if [ -n "$_spl_cleanup_rm" ]; then
1564
+ "$_spl_cleanup_rm" -rf "$_spl_cleanup_tmp" 2>/dev/null || :
1565
+ fi
1016
1566
  fi
1017
1567
  ;;
1018
1568
  esac
@@ -1025,16 +1575,24 @@ sp_loader_load_modules() {
1025
1575
  _spl_expected_root _spl_expected_wanted _spl_expected_mode _spl_expected_phase \
1026
1576
  _spl_expected_search_path _spl_expected_meta_file _spl_expected_meta_root _spl_expected_layer _spl_expected_dep_exists \
1027
1577
  _spl_expected_return _spl_expected_strict_error _spl_expected_current_shell _spl_expected_current_platform \
1028
- _spl_expected_mod _spl_expected_record _spl_expected_load _spl_expected_load_hook \
1578
+ _spl_expected_mod _spl_expected_record _spl_expected_load \
1029
1579
  _spl_expected_exports _spl_expected_exports_to_cleanup \
1030
1580
  _spl_guard_tmp _spl_guard_cleanup_tmp _spl_guard_tmp_parent _spl_guard_tmp_sentinel \
1031
1581
  _spl_guard_root _spl_guard_wanted _spl_guard_mode _spl_guard_phase \
1032
1582
  _spl_guard_search_path _spl_guard_meta_file _spl_guard_meta_root _spl_guard_layer _spl_guard_dep_exists \
1033
1583
  _spl_guard_return _spl_guard_strict_error _spl_guard_current_shell _spl_guard_current_platform \
1034
- _spl_guard_mod _spl_guard_record _spl_guard_load _spl_guard_load_hook \
1035
- _spl_guard_exports _spl_guard_exports_to_cleanup \
1036
- _spl_expected_pwd _spl_expected_pwd_status _spl_after_pwd \
1037
- _spl_expected_ifs_was_set _spl_expected_ifs _spl_after_ifs_was_set \
1584
+ _spl_guard_mod _spl_guard_record _spl_guard_load \
1585
+ _spl_guard_exports _spl_guard_exports_to_cleanup _spl_guard_wrapper_exports \
1586
+ _spl_guard_expected_pwd_was_set _spl_guard_expected_pwd \
1587
+ _spl_guard_expected_oldpwd_was_set _spl_guard_expected_oldpwd \
1588
+ _spl_guard_expected_pwd_physical _spl_guard_expected_pwd_status \
1589
+ _spl_expected_pwd _spl_expected_pwd_status _spl_expected_pwd_physical _spl_expected_pwd_was_set \
1590
+ _spl_expected_oldpwd _spl_expected_oldpwd_was_set _spl_after_pwd_physical _spl_after_pwd_physical_status \
1591
+ _spl_after_pwd_was_set _spl_after_oldpwd_was_set _spl_pwd_cwd_restored \
1592
+ _spl_cwd_restore_attempt _spl_restored_pwd_physical _spl_restored_pwd_status \
1593
+ _spl_restore_pwd _spl_restore_oldpwd _spl_restore_ifs _spl_ifs_ready \
1594
+ _spl_cleanup_rm _spl_rm_candidate \
1595
+ _spl_expected_ifs_was_set _spl_expected_ifs _spl_after_ifs_was_set \
1038
1596
  _spl_expected_allexport_was_set _spl_expected_noclobber_was_set _spl_expected_errexit_was_set \
1039
1597
  _spl_expected_glob_was_set _spl_expected_nounset_was_set _spl_expected_verbose_was_set _spl_expected_xtrace_was_set \
1040
1598
  _spl_after_allexport_was_set _spl_after_noclobber_was_set _spl_after_errexit_was_set \
@@ -1046,11 +1604,18 @@ sp_loader_load_modules() {
1046
1604
  _spl_value _spl_requires _spl_optional \
1047
1605
  _spl_dep_ifs_was_set _spl_dep_old_ifs _spl_dep _spl_progress _spl_ready \
1048
1606
  _spl_blocked_by _spl_topo_ifs_was_set _spl_topo_old_ifs _spl_runtime_skip \
1049
- _spl_run_ifs_was_set _spl_run_old_ifs _spl_load _spl_load_hook \
1050
- _spl_exports _spl_exports_to_cleanup _spl_export_ifs_was_set _spl_export_old_ifs _spl_export \
1051
- _spl_load_status _spl_load_path _spl_hook_body _spl_reserved_utility_pattern \
1607
+ _spl_run_ifs_was_set _spl_run_old_ifs _spl_load \
1608
+ _spl_exports _spl_exports_to_cleanup _spl_wrapper_exports _spl_export_ifs_was_set _spl_export_old_ifs _spl_export \
1609
+ _spl_export_lookup _spl_export_conflict _spl_reload_ifs_was_set _spl_reload_old_ifs \
1610
+ _spl_load_status _spl_load_path \
1052
1611
  _spl_search_path _spl_layer _spl_meta_file _spl_meta_root _spl_dep_exists _spl_existing_load _spl_layer_load _spl_conflict _spl_layer_ifs_was_set _spl_layer_old_ifs _spl_existing_version _spl_layer_version _spl_existing_version_display _spl_layer_version_display _spl_layer_glob_was_set
1053
- unset -f _sp_loader_path_is_physical 2>/dev/null || :
1612
+ unset _spl_seen_words _spl_strict_required_words _spl_blocked_words _spl_modules_words \
1613
+ _spl_order_words _spl_failed_words _spl_guard_seen_words _spl_guard_strict_required_words \
1614
+ _spl_guard_blocked_words _spl_guard_modules_words _spl_guard_order_words _spl_guard_failed_words \
1615
+ _spl_record_name _spl_record_requires _spl_record_optional _spl_record_shells \
1616
+ _spl_record_platforms _spl_record_side_effect _spl_record_exports _spl_record_updates \
1617
+ _spl_record_version _spl_record_load _spl_run_line _spl_module_root
1618
+ unset -f _sp_loader_path_is_physical _sp_loader_read_record _sp_loader_reserved_scan 2>/dev/null || :
1054
1619
  return 0
1055
1620
  fi
1056
1621
  unset _spl_root _spl_wanted _spl_mode _spl_phase _spl_strict_error _spl_return \
@@ -1060,15 +1625,23 @@ sp_loader_load_modules() {
1060
1625
  _spl_expected_root _spl_expected_wanted _spl_expected_mode _spl_expected_phase \
1061
1626
  _spl_expected_search_path _spl_expected_meta_file _spl_expected_meta_root _spl_expected_layer _spl_expected_dep_exists \
1062
1627
  _spl_expected_return _spl_expected_strict_error _spl_expected_current_shell _spl_expected_current_platform \
1063
- _spl_expected_mod _spl_expected_record _spl_expected_load _spl_expected_load_hook \
1628
+ _spl_expected_mod _spl_expected_record _spl_expected_load \
1064
1629
  _spl_expected_exports _spl_expected_exports_to_cleanup \
1065
1630
  _spl_guard_tmp _spl_guard_cleanup_tmp _spl_guard_tmp_parent _spl_guard_tmp_sentinel \
1066
1631
  _spl_guard_root _spl_guard_wanted _spl_guard_mode _spl_guard_phase \
1067
1632
  _spl_guard_search_path _spl_guard_meta_file _spl_guard_meta_root _spl_guard_layer _spl_guard_dep_exists \
1068
1633
  _spl_guard_return _spl_guard_strict_error _spl_guard_current_shell _spl_guard_current_platform \
1069
- _spl_guard_mod _spl_guard_record _spl_guard_load _spl_guard_load_hook \
1070
- _spl_guard_exports _spl_guard_exports_to_cleanup \
1071
- _spl_expected_pwd _spl_expected_pwd_status _spl_after_pwd \
1634
+ _spl_guard_mod _spl_guard_record _spl_guard_load \
1635
+ _spl_guard_exports _spl_guard_exports_to_cleanup _spl_guard_wrapper_exports \
1636
+ _spl_guard_expected_pwd_was_set _spl_guard_expected_pwd \
1637
+ _spl_guard_expected_oldpwd_was_set _spl_guard_expected_oldpwd \
1638
+ _spl_guard_expected_pwd_physical _spl_guard_expected_pwd_status \
1639
+ _spl_expected_pwd _spl_expected_pwd_status _spl_expected_pwd_physical _spl_expected_pwd_was_set \
1640
+ _spl_expected_oldpwd _spl_expected_oldpwd_was_set _spl_after_pwd_physical _spl_after_pwd_physical_status \
1641
+ _spl_after_pwd_was_set _spl_after_oldpwd_was_set _spl_pwd_cwd_restored \
1642
+ _spl_cwd_restore_attempt _spl_restored_pwd_physical _spl_restored_pwd_status \
1643
+ _spl_restore_pwd _spl_restore_oldpwd _spl_restore_ifs _spl_ifs_ready \
1644
+ _spl_cleanup_rm _spl_rm_candidate \
1072
1645
  _spl_expected_ifs_was_set _spl_expected_ifs _spl_after_ifs_was_set \
1073
1646
  _spl_expected_allexport_was_set _spl_expected_noclobber_was_set _spl_expected_errexit_was_set \
1074
1647
  _spl_expected_glob_was_set _spl_expected_nounset_was_set _spl_expected_verbose_was_set _spl_expected_xtrace_was_set \
@@ -1081,10 +1654,17 @@ sp_loader_load_modules() {
1081
1654
  _spl_value _spl_requires _spl_optional \
1082
1655
  _spl_dep_ifs_was_set _spl_dep_old_ifs _spl_dep _spl_progress _spl_ready \
1083
1656
  _spl_blocked_by _spl_topo_ifs_was_set _spl_topo_old_ifs _spl_runtime_skip \
1084
- _spl_run_ifs_was_set _spl_run_old_ifs _spl_load _spl_load_hook \
1085
- _spl_exports _spl_exports_to_cleanup _spl_export_ifs_was_set _spl_export_old_ifs _spl_export \
1086
- _spl_load_status _spl_load_path _spl_hook_body _spl_reserved_utility_pattern \
1657
+ _spl_run_ifs_was_set _spl_run_old_ifs _spl_load \
1658
+ _spl_exports _spl_exports_to_cleanup _spl_wrapper_exports _spl_export_ifs_was_set _spl_export_old_ifs _spl_export \
1659
+ _spl_export_lookup _spl_export_conflict _spl_reload_ifs_was_set _spl_reload_old_ifs \
1660
+ _spl_load_status _spl_load_path \
1087
1661
  _spl_search_path _spl_layer _spl_meta_file _spl_meta_root _spl_dep_exists _spl_existing_load _spl_layer_load _spl_conflict _spl_layer_ifs_was_set _spl_layer_old_ifs _spl_existing_version _spl_layer_version _spl_existing_version_display _spl_layer_version_display _spl_layer_glob_was_set
1088
- unset -f _sp_loader_path_is_physical 2>/dev/null || :
1662
+ unset _spl_seen_words _spl_strict_required_words _spl_blocked_words _spl_modules_words \
1663
+ _spl_order_words _spl_failed_words _spl_guard_seen_words _spl_guard_strict_required_words \
1664
+ _spl_guard_blocked_words _spl_guard_modules_words _spl_guard_order_words _spl_guard_failed_words \
1665
+ _spl_record_name _spl_record_requires _spl_record_optional _spl_record_shells \
1666
+ _spl_record_platforms _spl_record_side_effect _spl_record_exports _spl_record_updates \
1667
+ _spl_record_version _spl_record_load _spl_run_line _spl_module_root
1668
+ unset -f _sp_loader_path_is_physical _sp_loader_read_record _sp_loader_reserved_scan 2>/dev/null || :
1089
1669
  return 1
1090
1670
  }