Re: source -i prototype implementation and other features

2024-05-18 Thread konsolebox
I also uploaded a copy of the script and the patch to gist:

https://gist.github.com/konsolebox/a908cf13e511abdf05daec89a9cbdd8d


-- 
konsolebox



source -i prototype implementation and other features

2024-05-18 Thread konsolebox
This is what I think an acceptable implementation of `source -i`
should look like:


#!/bin/bash

if [[ BASH_VERSINFO -ge 5 && ${SOURCE_EXTENSIONS_LOADED-} != true ]]; then
function source._die {
printf '%s\n' "$1" >&2
exit "${2-1}"
}

function source._get_calling_script_dir {
[[ ${BASH_SOURCE[3]+.} ]] || source._die "Calling script's
location unknown."
[[ ${BASH_SOURCE[3]} == /* ]] || source._die "Calling script's
path not absolute."
_calling_script_dir=${BASH_SOURCE[2]%/*}
_calling_script_dir=${_calling_script_dir:-/}
}

function source._a {
local paths realpath p _calling_script_dir=()
IFS=: read -r paths <<< "$1"

for p in "${paths[@]}"; do
[[ $p ]] || continue

if [[ $p != /* ]]; then
[[ ${_calling_script_dir+.} ]] || source._get_calling_script_dir
p=${_calling_script_dir}/$p
fi

realpath=$(realpath -Pm -- "$p") || source._die "Failed to
get realpath of '$p'."
BASH_SOURCE_PATH+=${BASH_SOURCE_PATH:+:}${realpath}
done
}

function source._I {
declare -gA BASH_SOURCE_INCLUDED
local filename=$2 realpath
shift 2

realpath=$(realpath -Pe -- "${filename}") || \
source._die "Failed to get realpath of '${filename}'."

if [[ -z ${BASH_SOURCE_INCLUDED[${realpath}]+.} ]]; then
BASH_SOURCE_INCLUDED[${realpath}]=.
command source -- "${realpath}" "$@"
fi
}

function source._i {
local callback=$1 filename=$2 main_script_dir=() p
_calling_script_dir=()
shift 2

if [[ ${filename} == @(/*|./*|../*) ]]; then
if [[ $1 != /* ]]; then
[[ ${_calling_script_dir+.} ]] || source._get_calling_script_dir
filename=${_calling_script_dir}/${filename}
fi

[[ -e ${filename} ]] || source._die "File doesn't exist:
${filename}"
"${callback}" -- "${filename}" "$@"
else
IFS=: read -r paths <<< "${BASH_SOURCE_PATH}"
[[ ${#paths[@]} -gt 0 ]] || paths=(.)

for p in "${paths[@]}"; do
[[ $p ]] || continue

if [[ $p != /* ]]; then
if [[ -z ${main_script_dir+.} ]]; then
[[ ${#BASH_SOURCE[@]} -gt 2 ]] || source._die
"Main script's location unknown."
[[ ${BASH_SOURCE[-1]} == /* ]] || source._die
"Main script's path isn't absolute."
main_script_dir=${BASH_SOURCE[-1]%/*}
main_script_dir=${main_script_dir:-/}
fi

p=${main_script_dir}/$p
fi

if [[ -e ${p}/${filename} ]]; then
"${callback}" -- "${p}/${filename}" "$@"
return
fi
done

source._die "File not found in BASH_SOURCE_PATH: ${filename}"
fi
}

function source {
local mode=

while [[ $# -gt 0 ]]; do
case $1 in
-[aA])
[[ ${2+.} ]] || source._die "No argument specified to $1."
[[ $1 == -A ]] && BASH_SOURCE_PATH=
source._a "$2"
shift
;;
-[iI])
mode=${1#-}
;;
--)
shift
break
;;
-?*)
source._die "Invalid option: $1"
;;
*)
break
;;
esac

shift
done

[[ ${1+.} ]] || source._die "Filename argument required"
[[ $1 ]] || source._die "Invalid empty filename"

if [[ ${mode} == i ]]; then
source._i source "$@"
elif [[ ${mode} == I ]]; then
source._i source._I "$@"
else
command source -- "$@"
fi
}

SOURCE_EXTENSIONS_LOADED=true
fi


The other features like `source -I`, `source -a` and `source -A` are optional.

`source -I` is the same as `source -i` but it only allows a file to be
source'd if it hasn't been
included using `source -I` yet.

`source -a` adds paths to BASH_SOURCE_PATH in their realpath format
using the calling script as
reference.

`source -A` works the same as `source -a` except it overrides the
values in BASH_SOURCE_PATH.

Details on how `source -i` works are the following:

- Paths beginning with /, ./, or ../ aren't searched in BASH_SOURCE_PATH.
- Paths beginning with ./ or ../ use the calling script's directory as
  reference.
- Paths not beginning with /, ./, or ../ are searched in  BASH_SOURCE_PATH.
- If BASH_SOURCE_PATH is unset, '.' is used as a default value.
- If a path in BASH_SOURCE_PATH points to a relative location, it uses the
  directory of the main script as reference.  The main script is basically
  ${BA