-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathbase_init.sh
More file actions
executable file
·241 lines (206 loc) · 7.53 KB
/
Copy pathbase_init.sh
File metadata and controls
executable file
·241 lines (206 loc) · 7.53 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
#!/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 and BASE_HOST runtime metadata
# - resolve and source the reusable Bash standard library
# - 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 libraries with:
#
# import_base_lib file/lib_file.sh
#
# import_base_lib prefers reusable libraries from base-bash-libs when available
# and falls back to Base's bundled lib/bash tree for compatibility and
# Base-specific runtime/version helpers. 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
readonly __base_init_sourced__=1
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_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_resolve_bash_libs_dir() {
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
}
(cd -L -- "$explicit_dir" && pwd -L)
return $?
fi
candidate="$BASE_HOME/../base-bash-libs/lib/bash"
if base_init_bash_libs_dir_is_usable "$candidate"; then
(cd -L -- "$candidate" && pwd -L)
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
(cd -L -- "$candidate" && pwd -L)
return $?
fi
fi
printf '%s\n' "$BASE_BASH_LIB_DIR"
}
base_init_export_contract() {
local base_home base_os base_host uname_os
base_home="$(base_init_resolve_home)" || return 1
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
;;
Linux)
base_os=linux
;;
*)
base_os="$(printf '%s\n' "$uname_os" | tr '[:upper:]' '[:lower:]')"
;;
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_BASH_LIBS_DIR="$(base_init_resolve_bash_libs_dir)" || return 1
BASE_SHELL_DIR="$BASE_LIB_DIR/shell"
BASE_OS="$base_os"
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_SHELL_DIR BASE_OS 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_SHELL_DIR BASE_OS BASE_HOST BASE_SHELL
}
base_init_source_stdlib() {
local stdlib_path="$BASE_BASH_LIBS_DIR/std/lib_std.sh"
[[ -f "$stdlib_path" ]] || {
base_init_error "Base Bash stdlib '$stdlib_path' was not found."
return 1
}
# shellcheck source=/dev/null
source "$stdlib_path"
}
import_base_lib() {
local relative_path="${1:-}"
local lib_path
[[ -n "$relative_path" ]] || fatal_error "import_base_lib: no library path provided."
[[ "$relative_path" != /* ]] || fatal_error "import_base_lib: expected a path relative to '$BASE_BASH_LIBS_DIR', got '$relative_path'."
case "$relative_path" in
..|../*|*/..|*/../*)
fatal_error "import_base_lib: refusing path outside Base Bash library root: '$relative_path'."
;;
esac
lib_path="$BASE_BASH_LIBS_DIR/$relative_path"
if [[ ! -f "$lib_path" && "$BASE_BASH_LIBS_DIR" != "$BASE_BASH_LIB_DIR" ]]; then
lib_path="$BASE_BASH_LIB_DIR/$relative_path"
fi
[[ -f "$lib_path" ]] || fatal_error "Base library '$relative_path' was not found at '$BASE_BASH_LIBS_DIR/$relative_path' or '$BASE_BASH_LIB_DIR/$relative_path'."
# shellcheck source=/dev/null
source "$lib_path" || fatal_error "Failed to import Base library '$lib_path'."
}
base_init_main() {
base_init_require_bash || return 1
base_init_export_contract || return 1
base_init_source_stdlib "$@" || return 1
add_to_path -p "$BASE_BIN_DIR"
export PATH
}
base_init_main "$@" || return $?