|
19 | 19 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
20 | 20 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21 | 21 |
|
| 22 | +#!/bin/bash |
| 23 | +dsl:(){ ((!$#))||local __dsl__=("$@");${__blk__:+::};} |
| 24 | +shopt -q expand_aliases||{ unalias -a;shopt -s expand_aliases;};builtin alias\ |
| 25 | + +='{ ::__;::(){ ((!$#))||{ local __blarg__=("$@");shift;"${__dsl__[@]-::no-dsl}" + '\ |
| 26 | + ~='{ ::__;::(){ ((!$#))||{ local __blarg__=("$@");shift; '\ |
| 27 | + '{{=return;return;};__blk__=;set -- "${__blarg__[@]:1}"; ' '}}=};__blk__=1;:: . "$@";__::;}'\ |
| 28 | + -='"${__dsl__[@]-::no-dsl}" - ' |
| 29 | +::__(){ __bstk__[__bsp__++]="${__blk__:+__blk__=1;$(declare -f ::)}";} |
| 30 | +__::(){ local s=$?;__blk__=;${__bstk__[--__bsp__]:+eval "${__bstk__[__bsp__]}"};return $s;} |
| 31 | +__bsp__=;:${__dsl__+} |
22 | 32 | #!/usr/bin/env bash
|
23 | 33 |
|
24 | 34 | realpath.location(){ realpath.follow "$1"; realpath.absolute "$REPLY" ".."; }
|
@@ -163,41 +173,169 @@ done
|
163 | 173 | for lv in ${!LOCO_@}; do unset "$lv"; done
|
164 | 174 |
|
165 | 175 | LOCO_SCRIPT=$0
|
| 176 | +{ if [[ $OSTYPE != cygwin && $OSTYPE != msys && -e /dev/fd/0 ]]; then source /dev/fd/0; else source <(cat); fi; } <<'# --- EOF dotenv ---' |
166 | 177 | #!/usr/bin/env bash
|
167 |
| -event(){ case $1 in error|quote|encode);; *) |
168 |
| - __ev.encode "${2-}";local f n='' e=bashup_event_$REPLY;f=${e/event/flag} |
| 178 | +
|
| 179 | +__dotenv= |
| 180 | +__dotenv_file= |
| 181 | +__dotenv_cmd=.env |
| 182 | +
|
| 183 | +.env() { |
| 184 | + REPLY=() |
| 185 | + [[ $__dotenv_file || ${1-} == -* ]] || .env.--file .env || return |
| 186 | + if declare -F -- ".env.${1-}" >/dev/null; then .env."$@"; return ; fi |
| 187 | + .env --help >&2; return 64 |
| 188 | +} |
| 189 | +
|
| 190 | +.env.-f() { .env.--file "$@"; } |
| 191 | +.env.-h() { .env.--help "$@"; } |
| 192 | +.env.--help() { |
| 193 | + echo "Usage: |
| 194 | + $__dotenv_cmd [-f|--file FILE] COMMAND [ARGS...] |
| 195 | + $__dotenv_cmd -h|--help |
| 196 | +
|
| 197 | +Options: |
| 198 | + -f, --file FILE Use a file other than .env |
| 199 | +
|
| 200 | +Read Commands: |
| 201 | + get KEY Get raw value of KEY (or fail) |
| 202 | + parse [KEY...] Get trimmed KEY=VALUE lines for named keys (or all) |
| 203 | + export [KEY...] Export the named keys (or all) in shell format |
| 204 | +
|
| 205 | +Write Commands: |
| 206 | + set [+]KEY[=VALUE]... Set or unset values (in-place w/.bak); + sets default |
| 207 | + puts STRING Append STRING to the end of the file |
| 208 | + generate KEY [CMD...] Set KEY to the output of CMD unless it already exists; |
| 209 | + return the new or existing value." |
| 210 | +} |
| 211 | +
|
| 212 | +.env.get() { |
| 213 | + .env::arg "get requires a key" "$@" && |
| 214 | + [[ "$__dotenv" =~ ^(.*(^|$'\n'))([ ]*)"$1="(.*)$ ]] && |
| 215 | + REPLY=${BASH_REMATCH[4]%%$'\n'*} && REPLY=${REPLY%"${REPLY##*[![:space:]]}"} |
| 216 | +} |
| 217 | +
|
| 218 | +.env.parse() { |
| 219 | + local line key |
| 220 | + while IFS= read -r line; do |
| 221 | + line=${line#"${line%%[![:space:]]*}"} # trim leading whitespace |
| 222 | + line=${line%"${line##*[![:space:]]}"} # trim trailing whitespace |
| 223 | + if [[ ! "$line" || "$line" == '#'* ]]; then continue ; fi |
| 224 | + if (($#)); then |
| 225 | + for key; do |
| 226 | + if [[ $key == "${line%%=*}" ]]; then REPLY+=("$line"); break; |
| 227 | + fi |
| 228 | + done |
| 229 | + else |
| 230 | + REPLY+=("$line") |
| 231 | + fi |
| 232 | + done <<<"$__dotenv" |
| 233 | + ((${#REPLY[@]})) |
| 234 | +} |
| 235 | +
|
| 236 | +.env.export() { ! .env.parse "$@" || export "${REPLY[@]}"; } |
| 237 | +
|
| 238 | +.env.set() { |
| 239 | + .env::file load || return ; local key saved=$__dotenv |
| 240 | + while (($#)); do |
| 241 | + key=${1#+}; key=${key%%=*} |
| 242 | + if .env.get "$key"; then |
| 243 | + REPLY=() |
| 244 | + if [[ $1 == +* ]]; then shift; continue # skip if already found |
| 245 | + elif [[ $1 == *=* ]]; then |
| 246 | + __dotenv=${BASH_REMATCH[1]}${BASH_REMATCH[3]}$1$'\n'${BASH_REMATCH[4]#*$'\n'} |
| 247 | + else |
| 248 | + __dotenv=${BASH_REMATCH[1]}${BASH_REMATCH[4]#*$'\n'} |
| 249 | + continue # delete all occurrences |
| 250 | + fi |
| 251 | + elif [[ $1 == *=* ]]; then |
| 252 | + __dotenv+="${1#+}"$'\n' |
| 253 | + fi |
| 254 | + shift |
| 255 | + done |
| 256 | + [[ $__dotenv == "$saved" ]] || .env::file save |
| 257 | +} |
| 258 | +
|
| 259 | +.env.puts() { echo "${1-}">>"$__dotenv_file" && __dotenv+="$1"$'\n'; } |
| 260 | +
|
| 261 | +.env.generate() { |
| 262 | + .env::arg "key required for generate" "$@" || return |
| 263 | + .env.get "$1" && return || REPLY=$("${@:2}") || return |
| 264 | + .env::one "generate: ouptut of '${*:2}' has more than one line" "$REPLY" || return |
| 265 | + .env.puts "$1=$REPLY" |
| 266 | +} |
| 267 | +
|
| 268 | +.env.--file() { |
| 269 | + .env::arg "filename required for --file" "$@" || return |
| 270 | + __dotenv_file=$1; .env::file load || return |
| 271 | + (($#<2)) || .env "${@:2}" |
| 272 | +} |
| 273 | +
|
| 274 | +.env::arg() { [[ "${2-}" ]] || { echo "$__dotenv_cmd: $1" >&2; return 64; }; } |
| 275 | +
|
| 276 | +.env::one() { [[ "$2" != *$'\n'* ]] || .env::arg "$1"; } |
| 277 | +
|
| 278 | +.env::file() { |
| 279 | + local REPLY=$__dotenv_file |
| 280 | + case "$1" in |
| 281 | + load) |
| 282 | + __dotenv=; ! [[ -f "$REPLY" ]] || __dotenv="$(<"$REPLY")"$'\n' || return ;; |
| 283 | + save) |
| 284 | + if [[ -L "$REPLY" ]] && declare -F -- realpath.resolved >/dev/null; then |
| 285 | + realpath.resolved "$REPLY" |
| 286 | + fi |
| 287 | + { [[ ! -f "$REPLY" ]] || cp -p "$REPLY" "$REPLY.bak"; } && |
| 288 | + printf %s "$__dotenv" >"$REPLY.bak" && mv "$REPLY.bak" "$REPLY" |
| 289 | + esac |
| 290 | +} |
| 291 | +
|
| 292 | +if [[ $BASH_SOURCE == "$0" ]]; then |
| 293 | + set -eu |
| 294 | + __dotenv_cmd=${0##*/} |
| 295 | + .env.export() { .env.parse "$@" || return 0; printf 'export %q\n' "${REPLY[@]}"; exit; } |
| 296 | + .env "$@" || exit $? |
| 297 | + ${REPLY[@]+printf '%s\n' "${REPLY[@]}"} |
| 298 | +fi |
| 299 | +# --- EOF dotenv --- |
| 300 | +#!/usr/bin/env bash |
| 301 | +event(){ case $1 in error|quote|encode|decode);; *) |
| 302 | + __ev.encode "${2-}";local f n='' e=bashup_event_$REPLY'[1]';f=${e/event/flag} |
169 | 303 | case $1 in emit) shift;${!f-};eval "${!e-}"; return ;;on|once|off|has)
|
170 | 304 | case "${3-}" in @_) n='$#';; @*[^0-9]*);; @[0-9]*) n=$((${3#@}));; esac; ${n:+
|
171 | 305 | set -- "$1" "$2" "${@:4}" }
|
172 | 306 | case $1/$# in
|
173 |
| - has/[12]) REPLY=;; */[12]) set -- error "${2-}: missing callback";; |
| 307 | + on*/[12]) set -- error "${2-}: missing callback";; */[12]) REPLY=;; |
174 | 308 | *) __ev.quote "${@:3}";((${n/\$#/1}))&&REPLY+=' "${@:2:'"$n"'}"';REPLY+=$'\n'
|
175 | 309 | esac
|
176 | 310 | esac
|
177 | 311 | esac ;__ev."$@";}
|
178 | 312 | __ev.error(){ echo "$1">&2;return "${2:-64}";}
|
179 | 313 | __ev.quote(){ REPLY=; ${@+printf -v REPLY ' %q' "$@"}; REPLY=${REPLY# };}
|
180 | 314 | __ev.has(){ [[ ${!e-} && $'\n'"${!e}" == *$'\n'"$REPLY"* && ! ${!f-} ]];}
|
| 315 | +__ev.get(){ ${!f-};REPLY=${!e-};} |
181 | 316 | __ev.on(){ __ev.has && return;if [[ ! ${!f-} ]];then eval "$e"+='$REPLY';else eval "${!e-};$REPLY";fi;}
|
182 |
| -__ev.off(){ __ev.has||return 0; n="${!e}"; n=${n#"$REPLY"}; eval "$e"=$'"${n//\n"$REPLY"/\n}"';} |
183 |
| -__ev.fire(){ ${!f-};set -- "$e" "${@:2}"; while [[ ${!1-} ]];do eval "$1=;${!1}"; done ;} |
| 317 | +__ev.off(){ __ev.has||return 0; n="${!e}"; n=${REPLY:+"${n#"$REPLY"}"}; eval "$e"=$'"${n//\n"$REPLY"/\n}"';[[ ${!e} ]]||unset "${e%\[1]}";} |
| 318 | +__ev.fire(){ ${!f-};set -- "$e" "${@:2}"; while [[ ${!1-} ]];do eval "unset ${1%\[1]};${!1}"; done ;} |
184 | 319 | __ev.all(){ ${!f-};e=${!e-};eval "${e//$'\n'/||return; }";}
|
185 | 320 | __ev.any(){ ${!f-};e=${!e-};eval "${e//$'\n'/&&return|| } ! :";}
|
186 | 321 | __ev.resolve(){
|
187 | 322 | ${!f-};__ev.fire "$@";__ev.quote "$@"
|
188 |
| - readonly "$f=eval __ev.error 'event \"'$1'\" already resolved' 70;return" "$e=set -- $REPLY" |
| 323 | + printf -v n "eval __ev.error 'event \"%s\" already resolved' 70;return" "$1"; eval "${f}"='$n' |
| 324 | + printf -v n 'set -- %s' "$REPLY"; eval "${e}"='$n';readonly "${f%\[1]}" "${e%\[1]}" |
189 | 325 | }
|
190 | 326 | __ev.resolved(){ [[ ${!f-} ]];}
|
191 | 327 | __ev.once(){ n=${n:-0} n=${n/\$#/_}; event on "$1" "@$n" __ev_once $# "@$n" "$@";}
|
192 | 328 | __ev_once(){ event off "$3" "$2" __ev_once "${@:1:$1+2}"; "${@:4}";}
|
193 | 329 | __ev_jit(){
|
194 |
| - local r=${__ev_jit-} s=$1;((${#r}<250))||__ev_jit= |
| 330 | + local q r=${__ev_jit-} s=$1;((${#r}<250))||__ev_jit= |
195 | 331 | while [[ "$s" ]]; do
|
196 |
| - r=${s::1};s=${s//$r/};printf -v r 'REPLY=${REPLY//%q/_%02x_};' "$r" "'$r";eval "$r";__ev_jit+=$r |
| 332 | + r=${s::1};s=${s:1};printf -v q %q "$r";eval 's=${s//'"$q}";printf -v r 'REPLY=${REPLY//%s/_%02x};' "${q/#[~]/[~]}" "'$r";eval "$r";__ev_jit+="$r" |
197 | 333 | done
|
198 |
| - eval '__ev.encode(){ local LC_ALL=C;REPLY=${1//_/__};'\ |
| 334 | + eval '__ev.encode(){ local LC_ALL=C;REPLY=${1//_/_5f};'\ |
199 | 335 | "${__ev_jit-}"' [[ $REPLY != *[^_[:alnum:]]* ]] || __ev_jit "${REPLY//[_[:alnum:]]/}";}'
|
200 | 336 | };__ev_jit ''
|
| 337 | +__ev.decode(){ REPLY=();while (($#));do printf -v n %b "${1//_/\\x}";REPLY+=("$n");shift;done;} |
| 338 | +__ev.list(){ eval 'set -- "${!'"${e%\[1]}"'@}"';__ev.decode "${@#bashup_event_}";} |
201 | 339 | run() {
|
202 | 340 | if [[ ! ${DEVKIT_IS_PAGING-} ]] && event has "before_$1" paged-command; then
|
203 | 341 | dk use: tty
|
@@ -228,12 +366,13 @@ log() { echo "$1" >&2; }
|
228 | 366 |
|
229 | 367 | paged-command() { while (($#)); do before "$1" paged-command; shift; done; }
|
230 | 368 |
|
231 |
| -on() { event on "$@"; } |
232 |
| -off() { event off "$@"; } |
| 369 | +on() { if (($#==1)); then dsl: event-dsl on "$1"; else event on "$@"; fi; } |
| 370 | +off(){ if (($#==1)); then dsl: event-dsl off "$1"; else event off "$@"; fi; } |
233 | 371 |
|
234 |
| -before() { event on "before_$@"; } |
235 |
| -after() { event on "after_$@"; } |
| 372 | +before() { on "before_$@"; } |
| 373 | +after() { on "after_$@"; } |
236 | 374 |
|
| 375 | +event-dsl() { [[ $3 != + ]] || abort "Can't nest event blocks" 64; event "$1" "$2" "${@:4}"; } |
237 | 376 | trap 'event emit "EXIT"' EXIT
|
238 | 377 |
|
239 | 378 | # Commands that should have a bootstrap first:
|
@@ -261,16 +400,25 @@ on "clean" clean-deps
|
261 | 400 | after "clean" hash -r
|
262 | 401 | after "clean" linkbin .devkit/dk
|
263 | 402 |
|
| 403 | +on boot dk-fetch-deps |
| 404 | +dk-fetch-deps() { |
| 405 | + local BUILD_DEPS; .env -f "package.sh" export BUILD_DEPS |
| 406 | + IFS=: read -ra BUILD_DEPS <<<"${BUILD_DEPS-}"; set -- ${BUILD_DEPS[@]+"${BUILD_DEPS[@]}"} |
| 407 | + for REPLY; do github "$REPLY"; done |
| 408 | +} |
264 | 409 | basher() {
|
265 | 410 | require basher github basherpm/basher master bin/basher
|
266 | 411 | "$BASHER_INSTALL_BIN/basher" "$@"
|
267 | 412 | }
|
268 | 413 |
|
269 | 414 | github() {
|
270 |
| - [[ -d "$BASHER_PACKAGES_PATH/$1/.git" ]] && return |
271 |
| - mkdir -p "$BASHER_PACKAGES_PATH/$1" |
272 |
| - git clone -q --depth=1 -b "${2:-master}" "https://github.com/$1" "$BASHER_PACKAGES_PATH/$1" |
273 |
| - local bin; for bin in "${@:3}"; do linkbin "$BASHER_PACKAGES_PATH/$1/$bin"; done |
| 415 | + [[ $1 != *@* ]] || set -- "${1%%@*}" "${1#*@}" "${@:2}" |
| 416 | + [[ -d "$BASHER_PACKAGES_PATH/$1/.git" ]] && return |
| 417 | + mkdir -p "$BASHER_PACKAGES_PATH/$1" |
| 418 | + git clone -q --depth=1 ${2:+-b "$2"} "https://github.com/$1" "$BASHER_PACKAGES_PATH/$1" |
| 419 | + local BINS; .env -f "$BASHER_PACKAGES_PATH/$1/package.sh" export BINS |
| 420 | + IFS=: read -ra BINS <<<"${BINS-}"; set -- "$1" "${2-}" ${BINS[@]+"${BINS[@]}"} "${@:3}" |
| 421 | + for REPLY in "${@:3}"; do ${REPLY:+linkbin "$BASHER_PACKAGES_PATH/$1/$REPLY"}; done |
274 | 422 | }
|
275 | 423 | go() { require-any go; unset -f go; command go "$@"; }
|
276 | 424 | linkbin() {
|
|
0 commit comments