-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathbase_init.sh
More file actions
executable file
·373 lines (315 loc) · 11.8 KB
/
Copy pathbase_init.sh
File metadata and controls
executable file
·373 lines (315 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
#!/usr/bin/env bash
#
# base_init.sh
# Base runtime bootstrap for Bash commands and Base-enabled Bash shells.
#
# Loaded by:
# - bin/basectl before it sources a Base command implementation
# - bin/basectl before it sources an explicit Base-enabled Bash script
# - lib/bash/runtime/bashrc for `basectl` and `basectl shell` sessions
#
# Not loaded by:
# - normal Bash/Zsh dotfile startup managed by lib/shell/*
#
# Runtime contract:
# - validate that the runtime is Bash 4.2 or newer
# - derive or validate BASE_HOME
# - export the BASE_* paths that downstream scripts may rely on
# - export BASE_OS, BASE_PLATFORM, BASE_HOST_ENV, and BASE_HOST runtime metadata
# - resolve and source the reusable Bash standard library
# - require a base-bash-libs release with the v2 `base_` API surface
# - add BASE_BIN_DIR to PATH
# - provide import_base_lib for convention-based Base Bash library imports
#
# Downstream scripts should not rediscover Base's directory layout on their own.
# They should use the exported BASE_* variables and import Base Bash libraries with:
#
# import_base_lib file/lib_file.sh
#
# import_base_lib delegates to the v2 package importer. It reports missing or
# invalid libraries through Base stdlib error handling and fails immediately,
# so callers do not need duplicate checks.
#
[[ -n "${_base_init_sourced:-}" ]] && return 0
_base_init_sourced=1
readonly _base_init_sourced
base_init_error() {
printf 'ERROR: %s\n' "$*" >&2
}
base_init_resolve_path() {
local source_path="${1:-}"
local link_dir
local target
[[ -n "$source_path" ]] || return 1
while [[ -L "$source_path" ]]; do
link_dir="$(cd -- "$(dirname -- "$source_path")" && pwd -P)" || return 1
target="$(readlink "$source_path")" || return 1
if [[ "$target" == /* ]]; then
source_path="$target"
else
source_path="$link_dir/$target"
fi
done
link_dir="$(cd -- "$(dirname -- "$source_path")" && pwd -P)" || return 1
printf '%s/%s\n' "$link_dir" "$(basename -- "$source_path")"
}
base_init_require_bash() {
local current_version
if [[ -z "${BASH_VERSION:-}" ]]; then
base_init_error "Base runtime requires Bash."
return 1
fi
current_version="${BASH_VERSINFO[0]}${BASH_VERSINFO[1]}"
if ((current_version < 42)); then
base_init_error "Base runtime requires Bash 4.2 or newer; current version is ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}."
return 1
fi
}
base_init_linux_os_release_path() {
printf '%s\n' "${BASE_INIT_TEST_OS_RELEASE_PATH:-/etc/os-release}"
}
base_init_linux_kernel_osrelease_path() {
printf '%s\n' "${BASE_INIT_TEST_KERNEL_OSRELEASE_PATH:-/proc/sys/kernel/osrelease}"
}
base_init_linux_proc_version_path() {
printf '%s\n' "${BASE_INIT_TEST_PROC_VERSION_PATH:-/proc/version}"
}
base_init_detect_linux_platform() {
local id id_like os_release_path
local ID="" ID_LIKE=""
os_release_path="$(base_init_linux_os_release_path)" || return 1
if [[ -r "$os_release_path" ]]; then
# shellcheck source=/dev/null
source "$os_release_path"
fi
id="${ID,,}"
id_like="${ID_LIKE,,}"
case " $id $id_like " in
*" ubuntu "*|*" debian "*)
printf 'linux-debian\n'
;;
*)
printf 'linux-unknown\n'
;;
esac
}
base_init_detect_linux_host_env() {
local content path
for path in "$(base_init_linux_kernel_osrelease_path)" "$(base_init_linux_proc_version_path)"; do
[[ -r "$path" ]] || continue
content="$(<"$path")" || continue
content="${content,,}"
case "$content" in
*microsoft-standard-wsl2*|*wsl2*)
printf 'wsl2\n'
return 0
;;
esac
done
printf 'native\n'
}
base_init_resolve_home() {
local source_path
local source_dir
if [[ -n "${BASE_HOME:-}" ]]; then
[[ -d "$BASE_HOME" ]] || {
base_init_error "BASE_HOME '$BASE_HOME' is not a directory or is not accessible."
return 1
}
(cd -L -- "$BASE_HOME" && pwd -L)
return $?
fi
source_path="$(base_init_resolve_path "${BASH_SOURCE[0]}")" || return 1
source_dir="$(cd -- "$(dirname -- "$source_path")" && pwd -P)" || return 1
printf '%s\n' "$source_dir"
}
base_init_homebrew_prefix() {
case "$BASE_HOME" in
*/opt/base/libexec)
printf '%s\n' "${BASE_HOME%/opt/base/libexec}"
;;
*/Cellar/base/*/libexec)
printf '%s\n' "${BASE_HOME%%/Cellar/base/*}"
;;
esac
}
base_init_bash_libs_dir_is_usable() {
local candidate="${1:-}"
[[ -n "$candidate" ]] || return 1
[[ -f "$candidate/std/lib_std.sh" ]]
}
base_init_report_missing_bash_libs() {
local candidate
local homebrew_prefix
base_init_error "Base reusable Bash libraries were not found."
candidate="$BASE_HOME/../base-bash-libs/lib/bash"
base_init_error "Tried sibling base-bash-libs checkout at '$candidate'."
homebrew_prefix="$(base_init_homebrew_prefix || true)"
if [[ -n "$homebrew_prefix" ]]; then
candidate="$homebrew_prefix/opt/base-bash-libs/libexec/lib/bash"
base_init_error "Tried Homebrew base-bash-libs package at '$candidate'."
fi
base_init_error "Clone basefoundry/base-bash-libs next to Base, install it with 'brew install basefoundry/base/base-bash-libs', or set BASE_BASH_LIBS_DIR to a compatible lib/bash directory."
}
base_init_set_bash_libs_contract() {
local candidate
local homebrew_prefix
local explicit_dir="${BASE_BASH_LIBS_DIR:-}"
if [[ -n "$explicit_dir" ]]; then
base_init_bash_libs_dir_is_usable "$explicit_dir" || {
base_init_error "BASE_BASH_LIBS_DIR '$explicit_dir' does not contain std/lib_std.sh."
return 1
}
BASE_BASH_LIBS_DIR="$(cd -L -- "$explicit_dir" && pwd -L)" || return 1
BASE_BASH_LIBS_SOURCE=explicit
return $?
fi
candidate="$BASE_HOME/../base-bash-libs/lib/bash"
if base_init_bash_libs_dir_is_usable "$candidate"; then
BASE_BASH_LIBS_DIR="$(cd -L -- "$candidate" && pwd -L)" || return 1
BASE_BASH_LIBS_SOURCE=sibling
return $?
fi
homebrew_prefix="$(base_init_homebrew_prefix || true)"
if [[ -n "$homebrew_prefix" ]]; then
candidate="$homebrew_prefix/opt/base-bash-libs/libexec/lib/bash"
if base_init_bash_libs_dir_is_usable "$candidate"; then
BASE_BASH_LIBS_DIR="$(cd -L -- "$candidate" && pwd -L)" || return 1
BASE_BASH_LIBS_SOURCE=homebrew
return $?
fi
fi
base_init_report_missing_bash_libs
return 1
}
base_init_export_contract() {
local base_home base_os base_platform base_host base_host_env uname_os
base_home="$(base_init_resolve_home)" || return 1
base_host_env=native
uname_os="$(uname -s)" || {
base_init_error "Unable to determine BASE_OS with uname."
return 1
}
[[ -n "$uname_os" ]] || {
base_init_error "Unable to determine BASE_OS with uname."
return 1
}
case "$uname_os" in
Darwin)
base_os=macos
base_platform=macos
;;
Linux)
base_os=linux
base_platform="$(base_init_detect_linux_platform)" || return 1
base_host_env="$(base_init_detect_linux_host_env)" || return 1
;;
*)
base_os="$(printf '%s\n' "$uname_os" | tr '[:upper:]' '[:lower:]')"
base_platform="$base_os"
;;
esac
base_host="$(hostname -s)" || {
base_init_error "Unable to determine BASE_HOST with hostname."
return 1
}
[[ -n "$base_host" ]] || {
base_init_error "Unable to determine BASE_HOST with hostname."
return 1
}
BASE_HOME="$base_home"
BASE_BIN_DIR="$BASE_HOME/bin"
BASE_CLI_DIR="$BASE_HOME/cli"
BASE_BASH_DIR="$BASE_CLI_DIR/bash"
BASE_BASH_COMMANDS_DIR="$BASE_BASH_DIR/commands"
BASE_LIB_DIR="$BASE_HOME/lib"
BASE_BASH_LIB_DIR="$BASE_LIB_DIR/bash"
base_init_set_bash_libs_contract || return 1
BASE_SHELL_DIR="$BASE_LIB_DIR/shell"
BASE_OS="$base_os"
BASE_PLATFORM="$base_platform"
BASE_HOST_ENV="$base_host_env"
BASE_HOST="$base_host"
BASE_SHELL="${BASE_SHELL:-bash}"
export BASE_HOME BASE_BIN_DIR BASE_CLI_DIR BASE_BASH_DIR BASE_BASH_COMMANDS_DIR
export BASE_LIB_DIR BASE_BASH_LIB_DIR BASE_BASH_LIBS_DIR BASE_BASH_LIBS_SOURCE BASE_SHELL_DIR BASE_OS BASE_PLATFORM BASE_HOST_ENV BASE_HOST BASE_SHELL
readonly BASE_HOME BASE_BIN_DIR BASE_CLI_DIR BASE_BASH_DIR BASE_BASH_COMMANDS_DIR
readonly BASE_LIB_DIR BASE_BASH_LIB_DIR BASE_BASH_LIBS_DIR BASE_BASH_LIBS_SOURCE BASE_SHELL_DIR BASE_OS BASE_PLATFORM BASE_HOST_ENV BASE_HOST BASE_SHELL
}
base_init_source_stdlib() {
local stdlib_path="$BASE_BASH_LIBS_DIR/std/lib_std.sh"
local runtime_source
local -a runtime_args=()
[[ -f "$stdlib_path" ]] || {
base_init_error "Base Bash stdlib '$stdlib_path' was not found."
return 1
}
# shellcheck source=/dev/null
source "$stdlib_path"
runtime_source="${BASE_BASH_LIBS_BOOTSTRAP_SOURCE:-${BASE_BASH_COMMAND_SCRIPT:-$BASE_HOME/base_init.sh}}"
base_init runtime_args --source "$runtime_source" -- "$@" || {
base_init_error "Unable to initialize the base-bash-libs runtime state."
return 1
}
}
base_init_bash_libs_version_is_supported() {
local version="${1:-}"
[[ "$version" =~ ^1[.][0-9]+[.][0-9]+$ ||
"$version" =~ ^2[.][0-9]+[.][0-9]+(-(alpha|beta|rc)[.](0|[1-9][0-9]*))?$ ]]
}
base_init_require_bash_libs_version() {
local loaded_version="${BASE_BASH_LIBS_VERSION:-}"
if ! base_init_bash_libs_version_is_supported "$loaded_version"; then
base_init_error "Base requires base-bash-libs 1.4.0 or a compatible release with the v2 API; loaded version is '$loaded_version'."
return 1
fi
case "$loaded_version" in
1.*)
if ! base_require_version 1.4.0; then
base_init_error "Base requires base-bash-libs 1.4.0 or newer; loaded version is '$loaded_version'."
return 1
fi
;;
2.*)
# The v2 API is valid during the coordinated prerelease and GA
# window. Do not pass its prerelease form to the v1 numeric helper.
;;
esac
}
base_init_source_command_protocol() {
local protocol_path="$BASE_HOME/lib/bash/runtime/command_protocol.sh"
[[ -f "$protocol_path" ]] || {
base_init_error "Base command protocol helper '$protocol_path' was not found."
return 1
}
# shellcheck source=/dev/null
source "$protocol_path"
}
import_base_lib() {
local relative_path="${1:-}"
local lib_path
[[ -n "$relative_path" ]] || base_std_fatal_error "import_base_lib: no library path provided."
[[ "$relative_path" != /* ]] || base_std_fatal_error "import_base_lib: expected a path relative to '$BASE_BASH_LIBS_DIR', got '$relative_path'."
case "$relative_path" in
..|../*|*/..|*/../*)
base_std_fatal_error "import_base_lib: refusing path outside Base Bash library root: '$relative_path'."
;;
esac
lib_path="$BASE_BASH_LIBS_DIR/$relative_path"
[[ -f "$lib_path" ]] || {
base_init_error "Base reusable library '$relative_path' was not found at '$lib_path'."
return 1
}
base_std_import "$relative_path" ||
base_std_fatal_error "Failed to import Base library '$relative_path'."
}
base_init_main() {
base_init_require_bash || return 1
base_init_export_contract || return 1
base_init_source_stdlib "$@" || return 1
base_init_require_bash_libs_version || return 1
base_init_source_command_protocol || return 1
base_std_add_to_path -p "$BASE_BIN_DIR"
export PATH
}
base_init_main "$@" || return $?