Re: [PATCH v2 5/8] builtins/source: parse the -i option

2024-05-18 Thread Robert Elz
Date:Sat, 18 May 2024 23:00:41 +
From:Matheus Afonso Martins Moreira 
Message-ID:  



  | If you resolve the path, you're just reinventing the source builtin.

Nonsense, the real work of the source ('.' really) utility is to
read the file, parse it, and execute it.   None of the proposed
solutions here do that.   What file names work for this purpose is
an irrelevant consideration.

  | It also depends on source actually accepting the absolute path
  | which renders it incompatible with restricted shells.

That's the only point here that has any merit.   And a better solution
to that would be to remove that restriction, which has no purpose that
I can imagine.   The commands run by the source builtin would be restricted,
and whatever they are, could simply be typed as input to the same effect,
so stopping a rbash user from accessing stuff in some common (full path
named) file seems pointless to me.   Just remove that restriction and
this point goes away, and there's no reason left to modify bash in one
particular way (rather than some other way that someone else would prefer).

[Aside: the restriction on rbash using "exec" to replace the shell makes
 no sense either - obviously whatever is exec'd would need to be a command
 the user could run without exec, and assuming that condition is maintained,
 then a user can just do "cmd" and stay in that until they're done, which
 is effectively identical to "exec cmd" except the former keeps the rbash
 process hanging around for no useful purpose.

 I also find it hard to believe that anyone can usefully use any shell
 which doesn't allow stdout to be redirected - what files can be used,
 that can be restricted, but simply banning redirection?   Weird.

 Then again, my general opinion of restricted shells is that they were a
 joke when first invented (long long ago when lots of users shared a
 computer, which is a very rare setup these days) and while the joke has
 become stale, that's still what they are.]

  | I don't really understand why there seems to be so much
  | opposition to this.

It is extra stuff that once added needs to be maintained forever.
Unless it proves useful, and unable to be done some other way,
adding it is typically the wrong thing to do.

  | So why add the source builtin to begin with?

That one is simple ... when it ('.' in sh, "source" in csh) was added
there were no functions, while read & eval might have been enough for
simple one line scripts, they wouldn't work for more complex ones, to
invent your own '.' command that way you'd need to do it in a moderately
complex function, which didn't exist at the time.   And like anything
else, once added, it is there forever.

  | > if I needed something like that, I could write my own, similar ones.
  | And you would run into the limitations described above.

I wouldn't, as I don't care about restricted shells (never have, not
even when I was running a system used by many hundreds of (*evil*)
students).And that's the only real restriction, which should be
removed anyway.

I agree that modifying PATH isn't a great solution - though for any
use I'd have of '.' that wouldn't bother me either (both because I've
never used a '.' command that actually searches PATH, and because I
don't put anything which would require a PATH search in files I use
via '.' - such scripts are simply run as scripts.  '.' is used when
the current shell environment needs to be modified, so is useful for
defining functions, and assigning values to variables (and perhaps
the odd option setting) - almost never anything more than that (at
least for me - so I wouldn't run into the limitations described.)

kre




Re: [PATCH v2 5/8] builtins/source: parse the -i option

2024-05-18 Thread Matheus Afonso Martins Moreira
> distros, sysadmins, and users can already break your scripts
> in plenty of ways -- changing existing shell variables, setting
> shopts your scripts don't account for, etc.  

Existing footguns doesn't justify addition of new ones.
We have the ability to prevent a lot of breakage here.
Shouldn't we take that opportunity?

> By this logic, ALL future shell variables ought to be gated similarly.

Maybe. I haven't really thought that far
but it would probably be a good thing.

> it seems a bit heavy-handed

Why? Most if not all of the other builtins have options.

> Note that "source -i" precludes a sort of mirror situation.
> Someone who sourced scripts via PATH but wanted to
> switch to BASH_SOURCE_PATH would not be able to
> simply move the relevant directories from one variable
> to the other but would have to modify all sourcing scripts
>  -- including third-party ones -- to use "source -i". 

Yes, that's intentional. This ensures that users who wrote code
expecting PATH semantics actually get those semantics.
Then the new variable can be set in the environment
without impacting those users and their scripts.

> If they declined to do this, then they'd have to keep using
> PATH for at least some scripts, possibly indefinitely.

Those should continue to work without any changes.
They should even be compatible with each other:
there should be no problems with sourcing -i a script
which then sources another script normally or uses
one of the module management solutions.

  -- Matheus



Re: [PATCH v2 5/8] builtins/source: parse the -i option

2024-05-18 Thread Matheus Afonso Martins Moreira
> The issue is that what you want, and what I want,
> and what konsolebox wants (and everyone else)
> are all slighty different.

The option solution which I proposed is not really in opposition
to anything that anyone else wants. It will not break anything,
it supports the same inputs and use cases as before, including
the absolute path case you cited.

On the other hand, the variable solution which everyone else
seems to favor _does_ get in the way of what I want to do. 

> And as konsolebox's functions show, all this can be implemented,
> reasonably easily, outside of the bash source code

No. By discussing this I ended up discovering additional reasons
why it should actually be in bash as a builtin feature.

Pure bash solutions have two choices and both of them break stuff.
Either they clobber PATH, or they resolve the file's path on their own
and pass an absolute path to the source builtin. If you clobber PATH,
sourced scripts can't easily find commands anymore. That completely
changes the way that scripts work and therefore the way they must
be written. If you resolve the path, you're just reinventing the source
builtin. It also depends on source actually accepting the absolute path
which renders it incompatible with restricted shells.

The option solution completely avoids all that. It leaves PATH alone,
and as a builtin it can integrate with restricted shells. I even made
BASH_SOURCE_PATH be read only in that context, just like PATH.
And it accomplishes all that in a compatible way that's fully opt in,
anyone who does not want it can simply not use it. Existing code
is not impacted because existing code simply does not pass -i
as an option to the source builtin.

I don't really understand why there seems to be so much
opposition to this. Ability to do something in pure bash is
not an argument against this feature, especially since it
overcomes limitations present in the pure bash solutions.
Those are _real_ limitations, not some "personal hangups"
as others called it. The pure bash solutions simply _cannot_
both of these things, they must sacrifice one of them.

Even if that wasn't the case, it wouldn't be an argument.
By this logic, the source builtin itself should not have been
added either. I mean it's just read and eval, and bash has
both of those primitives built into it already. There's a
comment which even explains source in these terms:
it reads in the file into a string and just evaluates it.
So why add the source builtin to begin with?

> if I needed something like that, I could write my own, similar ones.

And you would run into the limitations described above.

> I think all this just shows that there's no real need to add any
> code to bash at all for this

I don't know about "need" but there are certainly advantages.

> use full path names instead

Incompatible with restricted shells.

  -- Matheus



Re: [PATCH v2 5/8] builtins/source: parse the -i option

2024-05-18 Thread Lawrence Velázquez
On Sat, May 18, 2024, at 11:17 AM, Phi Debian wrote:
> I am xing fingers the consensus, if any of theses takes off,
> is to have [...] protection against alias source='source -i'

This seems out of scope, regardless of what happens with "-i".


> I really depend on actual 'source' behavior, and can't update my packages
> (distributed since long). I don't plan to use BASH_SOURCE_PATH, so if one,
> distro, sysadmin, and ultimatly the user fiddle with BASH_SOURCE_PATH in
> the ENV (*rc files), changing the good'ol 'source' behavior, it would be a
> serious regression to me.

A reasonable concern, but distros, sysadmins, and users can already
break your scripts in plenty of ways -- changing existing shell
variables, setting shopts your scripts don't account for, etc.


> So to me BASH_SOURCE_PATH enablement must be guarded by a never used yet
> option to 'source or dot' (here -i apparently) and an enforcement that no
> alias source='source -i' could ever be possible.

By this logic, ALL future shell variables ought to be gated similarly.
No doubt some would embrace this, but it seems a bit heavy-handed.


> All this is because one writing a 'main' script (#!/bin/bash), sourcing a
> package of mine through my package management system, expecting the current
> source behavior, and later add the loading of a 'libraries' from a friend
> (terminal color jazz) that in turn start to mess around with alias
> source='source -i' and BASH_SOURCE_PATH cold start to break my way of
> finding my packages.

There's only so much you or bash itself can do to prevent users
from breaking their own setups.

Note that "source -i" precludes a sort of mirror situation.  Someone
who sourced scripts via PATH but wanted to switch to BASH_SOURCE_PATH
would not be able to simply move the relevant directories from one
variable to the other but would have to modify all sourcing scripts
-- including third-party ones -- to use "source -i".  If they
declined to do this, then they'd have to keep using PATH for at
least some scripts, possibly indefinitely.


-- 
vq



Re: [PATCH v2 5/8] builtins/source: parse the -i option

2024-05-18 Thread Robert Elz
Date:Sat, 18 May 2024 08:39:57 -0300
From:Matheus Afonso Martins Moreira 
Message-ID:  


  | As the user, it should be my prerogative to set the
  | variable on my environment and/or rc so that I can
  | organize my sourceable scripts however I want

Of course.   The issue is that what you want, and what I want, and
what konsolebox wants (and everyone else) are all slighty different.

And as konsolebox's functions show, all this can be implemented,
reasonably easily, outside of the bash source code, in code that
implements whatever you want.   Those functions aren't what I'd
want (for several reasons, not least because they are very bash
dependent) but if I needed something like that, I could write my
own, similar ones.

I think all this just shows that there's no real need to add any
code to bash at all for this, it is OK as it is now (and everyone
should just continue ignoring the PATH search when using '.' (or
"source") and use full path names instead - whether generated by
a function, or an install script, or simply written that way).

If Chet wants to alter the way this works in bash, he can do it
however seems best to him for what the majority of users are likely
to prefer, or just whatever it is he prefers - I am fairly sure it
wouldn't break the simple ". /path/to/file" usage, which is all we
really need to work to be able to do anything we personally like.

kre




count in vi mode alters prompt

2024-05-18 Thread mohd . akram
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: darwin23.2.0
Compiler: /usr/bin/clang
Compilation CFLAGS: -pipe -Os -DSSH_SOURCE_BASHRC 
-isysroot/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk -arch x86_64
uname output: Darwin Mohameds-MBP 23.4.0 Darwin Kernel Version 23.4.0: Fri Mar 
15 00:11:05 PDT 2024; root:xnu-10063.101.17~1/RELEASE_X86_64 x86_64
Machine Type: x86_64-apple-darwin23.2.0

Bash Version: 5.2
Patch Level: 26
Release Status: release

Description:
When using vi mode in bash, whenever a count is used before a command,
bash replaces the prompt with (arg: n) where n is the count entered.
This causes the entire line to shift, which is particularly jarring if
a long prompt is used, as is common. It should instead silently accept
the count as it does any other input in command mode.

Repeat-By:
1. set -o vi
2. edit a line and use a count before a command



Re: [PATCH v2 5/8] builtins/source: parse the -i option

2024-05-18 Thread Lawrence Velázquez
On Sat, May 18, 2024, at 11:41 AM, Matheus Afonso Martins Moreira wrote:
>> I am xing fingers the consensus, if any of theses takes off,
>> is to have the -i implemented (not omitted)
>
> Me too. Do you know anyone else who could be impacted?
> Consensus might move in that direction if more voices make
> themselves heard on this list.

Consensus does not depend on how many people openly agree with you,
except insofar as additional discussion sways those who disagree.

-- 
vq



Re: [PATCH v2 5/8] builtins/source: parse the -i option

2024-05-18 Thread Matheus Afonso Martins Moreira
> I am xing fingers the consensus, if any of theses takes off,
> is to have the -i implemented (not omitted)

Me too. Do you know anyone else who could be impacted?
Consensus might move in that direction if more voices make
themselves heard on this list.

> if one,  distro, sysadmin, and ultimatly the user
> fiddle with BASH_SOURCE_PATH in the ENV (*rc files),
> changing the good'ol 'source' behavior,
> it would be a serious regression to me.

That's exactly what I mean.
  
> So to me BASH_SOURCE_PATH enablement must be guarded by a never used yet
> option to 'source or dot' (here -i apparently)

Agree.

I initially chose -l which stands for library
but that terminology proved problematic.
So I chose -i which stands for isolated,
the option "isolates" source to only the
directories defined in the new variable.
Maybe there's a better word/character.
Naming things is hard.

> and an enforcement that no alias
> source='source -i' could ever be possible.

I don't really have any objections to that
but I'd say there are probably too many
ways for people to get around such a filter.
It would probably be ineffective.

  -- Matheus



Re: [PATCH v2 5/8] builtins/source: parse the -i option

2024-05-18 Thread Phi Debian
On Sat, May 18, 2024 at 3:23 PM Matheus Afonso Martins Moreira <
math...@matheusmoreira.com> wrote:

>
> > That would cause shell scripts to see it and exhibit a change in
> behavior.
>
> Only if the -i option is not implemented.
> If it is, there will be zero change in behavior
> whether BASH_SOURCE_PATH is set or not.
> Only if the script explicitly passes -i to source
> will the behavior change.
>

I am xing fingers the consensus, if any of theses takes off, is to have the
-i implemented (not omitted) along with a protection against alias
source='source -i'

I really depend on actual 'source' behavior, and can't update my packages
(distributed since long). I don't plan to use BASH_SOURCE_PATH, so if one,
distro, sysadmin, and ultimatly the user fiddle with BASH_SOURCE_PATH in
the ENV (*rc files), changing the good'ol 'source' behavior, it would be a
serious regression to me.

So to me BASH_SOURCE_PATH enablement must be guarded by a never used yet
option to 'source or dot' (here -i apparently) and an enforcement that no
alias source='source -i' could ever be possible.

All this is because one writing a 'main' script (#!/bin/bash), sourcing a
package of mine through my package management system, expecting the current
source behavior, and later add the loading of a 'libraries' from a friend
(terminal color jazz) that in turn start to mess around with alias
source='source -i' and BASH_SOURCE_PATH cold start to break my way of
finding my packages.

An alternative to this would be
BASH_SOURCE_PATH="" don't do nothing with 'source', and allow the
'libraries' designer to do
typeset -r BASH_SOURCE_PATH=""
in the early step of the main script, so nobody will ever be able to do
anything clever with BASH_SOURCE_PATH, or could add import from
incompatible packages system. But even this idea is a pb to me because it
would require a change an my side that is not really doable.

Well in short don't break the old source semantic.


Re: [PATCH v2 5/8] builtins/source: parse the -i option

2024-05-18 Thread Matheus Afonso Martins Moreira
> You've made contradictory statements here.

I don't see how.

> First you said you wanted to put it into your *environment*.

Yes.

> That would cause shell scripts to see it and exhibit a change in behavior.

Only if the -i option is not implemented.
If it is, there will be zero change in behavior
whether BASH_SOURCE_PATH is set or not.
Only if the script explicitly passes -i to source
will the behavior change.

> Next you said you would like to set it in your .bashrc file.
> That's totally different.

How is it different? If I export a variable in .bashrc,
and bash reads and evaluates that file at startup,
then that variable gets exported to the shell and
all processes spawned by it.

> Setting it in .bashrc *without* putting it into the
> environment (no export) is "safe".  It will only affect
> your interactive shell, and not any scripts that you run.

I know. I'm just saying it doesn't have to be that way.

I'm saying that in addition to it being safe if unset or
unexported, it could _also_ be made safe if exported.
The -i option provides that safety by requiring that
source code be changed in order to enable it.
Existing code will never be impacted by the feature
whether the variable is set or not, simply because
they do not pass -i to the source builtin.

  -- Matheus



Re: [PATCH v2 5/8] builtins/source: parse the -i option

2024-05-18 Thread Greg Wooledge
On Sat, May 18, 2024 at 08:39:57AM -0300, Matheus Afonso Martins Moreira wrote:
> > Setting the variable at all is opting in to new behavior, and you do
> > that at your own risk, after reading the documentation and deciding
> > that this is what you want.
> 
> As the user, it should be my prerogative to set the
> variable on my environment and/or rc so that I can
> organize my sourceable scripts however I want and
> have the scripts which enabled the isolated sourcing
> just work no matter where I chose to install them.
> 
> As the user, I should be able to run shell scripts
> regardless of whether they support this or not.
> I should be to set this variable on my .bashrc
> and enjoy the nice infrastructure it provides
> without worrying about whether or not
> some script takes it into account.

You've made contradictory statements here.

First you said you wanted to put it into your *environment*.  That would
cause shell scripts to see it and exhibit a change in behavior.

Next you said you would like to set it in your .bashrc file.  That's
totally different.  Setting it in .bashrc *without* putting it into the
environment (no export) is "safe".  It will only affect your interactive
shell, and not any scripts that you run.



Re: [PATCH v2 5/8] builtins/source: parse the -i option

2024-05-18 Thread Matheus Afonso Martins Moreira
> Setting the variable at all is opting in to new behavior, and you do
> that at your own risk, after reading the documentation and deciding
> that this is what you want.

As the user, it should be my prerogative to set the
variable on my environment and/or rc so that I can
organize my sourceable scripts however I want and
have the scripts which enabled the isolated sourcing
just work no matter where I chose to install them.

As the user, I should be able to run shell scripts
regardless of whether they support this or not.
I should be to set this variable on my .bashrc
and enjoy the nice infrastructure it provides
without worrying about whether or not
some script takes it into account.
I shouldn't be forced to choose between
legacy shell scripts which don't support this
and new shell scripts which do. There's no
technical reason why I shouldn't be able
to run both in the same bash, or even
have one type of script source the other.

Environment variables are recursively passed
down the process tree. If you choose the
variable approach, my choice to "opt in"
will get applied recursively as well.
I'll be making that choice for every
script that I run and every script sourced
by those scripts. That's actually a breaking
change that fails to be compatible.

All that could be achieved without incompatibility
by simply adding the -i option to source. Then my
choice remains mine alone when I pass -i to source
while interacting with bash via the terminal.
Then the script writer's choice becomes theirs alone
when they write their scripts. It becomes a local choice,
not a recursive and inheritable one.

The recursive and inheritable nature of environment variables
are useful for programs _after_ they have chosen to use them.
If the presence of the variable becomes a choice unto itself,
that choice will end up being inadvertently forced on others.

> I do not foresee people setting BASH_SOURCE_PATH
> in their basic interactive shell environments and login
> sessions.

That should definitely be foreseen because that's _exactly_
what I plan to do if this feature gets merged.

I will set it on my .bashrc just like this:

export BASH_SOURCE_PATH="${HOME}"/.local/share/bash/source

Then I will commit that to my dotfiles repository.

> Why would they do that?
> What purpose would it serve?

I will set the variable in order to create a fixed location
for loading libraries. Then I will break up my growing
collection of shell scripts into reusable functions,
put them into separate files and then put those files
in the BASH_SOURCE_PATH. Then I can easily source
those libraries of functions from my bash programs.

The purpose is to be able to more easily write
more complex bash scripts. This will allow me
to write scripts by following a process like:

source -i terminal
source -i options

# use option parsing functions to get inputs
# compute some useful output
# color output with terminal functions

> But you wouldn't want it to be set in your other windows.

I absolutely want it set on every bash process,
including interactive ones.

I always want the ability to source the nice functions
that I put effort into writing and debugging and organizing.
I will even add shorthand aliases for them so that they will
be easy to type on the terminal.

> What I'm imagining here is that the variable will be used almost
exclusively by scripts, to set the location of their resource files,
which they source.

I have nothing against that use case but that's not at all
what I'm imagining. For me this is very much a feature
for the _users_ to help them manage their shell script
collections. It should be in no way exclusive to the scripts.

> They're not useful outside of the script which sources them
> so only that script needs to set BASH_SOURCE_PATH

False. The variable will be extremely and directly useful to me
as a bash user. That's why I proposed and implemented it.

I didn't even intend for the scripts to override it.
The whole idea is scripts would give source some symbol
that represents what they need and source would take care
of loading it so that the functions are available. They need not
care where or even what the scripts are, they can just say:

source -i my-functions

And it gets done.

I have no objections to scripts overriding it at all.
However I don't think that's an argument against
users being able to control their environment just
like they have control over PATH.

  -- Matheus


Re: proposed BASH_SOURCE_PATH

2024-05-18 Thread konsolebox
On Sat, May 18, 2024 at 9:18 AM Martin D Kealey  wrote:
> On Thu, 16 May 2024 at 22:50, konsolebox  wrote:
>>
>> On Thu, May 16, 2024 at 4:59 PM Martin D Kealey  
>> wrote:
>> > As I understood your counter-proposal, it would result in this:
>> > * ./a and ./b/c/d would be treated as relative to $PWD
>>
>> Not to $PWD but the calling script's directory.  source as it is now
>> already refers to $PWD.  `source -i` will refer to the calling
>> script's directory instead.
>
>
> Ok, that seems more reasonable, and seemingly parallels the supposed (*) 
> special-case behaviour of './' elsewhere.
>
>> > * a and b/c/d (any paths not starting with '/' or './') would remain as I 
>> > specified, and be treated as relative to $(dirname $(realpath $0))
>>
>> Only if BASH_SOURCE_PATH is empty will $0 be used as reference because
>> it becomes the default as you have suggested.  But if it isn't, the
>> paths specified in BASH_SOURCE_PATH will be used instead.
>
>
> Strongly agreed; I over-simplified my description.
>
>> `cmd` searches for the binary in PATH, `./cmd` doesn't.
>> `source script` searches for the script in PATH.  `source ./script` doesn't.
>
>
> Yes I get that, but that's because ./script is a particular case of 
> subdir/script, and in POSIX subdir/script isn't searched for. (Supposedly 
> that behaviour is different when not in POSIX mode, but I couldn't confirm 
> that experimentally.)
>
>> Why would you decide to change `source -i ./script` to also search for
>> the script in BASH_SOURCE_PATH just because a bunch of newbies might
>> misinterpret it?
>
>
> To be clear, I was suggesting that "modulegroup/module.bash" should search 
> BASH_SOURCE_PATH; my fairly weak objection was to treating "./module.bash" 
> differently based on its textual form, but it's not the hill I want to die 
> on. If there's precedent elsewhere then I withdraw that objection.
>
> I wonder whether 'source -i' should ignore POSIX mode and behave as if it's 
> always "on"?
>
>> Even without considering source and "cmd"'s current behavior, it
>> doesn't make sense to add an additional option just to make the shell
>> know that you're referring to an explicit path relative to the current
>> directory (or script) or not.
>
>
> Put that way, it does sound a bit odd.
>
>> Also just to make sure things are clear.  I'm referring to "$0" here
>> as the main script's path and not the calling script's path.
>> BASH_SOURCE_PATH can be allowed to have a default value but it doesn't
>> make sense if that "default value" changes meaning depending on the
>> location of the script running.  BASH_SOURCE_PATH's values are
>> supposed to always refer to the same paths regardless if the values
>> are relative or not otherwise that would be a broken behavior.
>> Relative paths in BASH_SOURCE_PATHS if they become allowed should use
>> the main script's directory as reference as well.
>
>
> Hmm, I can see cases for both relative to $0 and relative to whichever file 
> contains the "source" command.
> Is there a consensus on this?

I don't know.  I didn't get a direct reply on this besides yours yet
and I haven't thoroughly read the other thread.  I just think it's the
most sensible way to do it if ever default values and relative paths
in BASH_SOURCE_PATH become supported.

I also now think it's better to not support them at all since the main
script itself is not a reliable reference.  Relying on PWD makes it
worse as well.  Scripts less likely changing directories while calling
`source -i` is not a valid reason to use it.  `source -i` has to work
consistently through and through in all cases.

Please make sure you reply to bug-bash as well and not just to me.


-- 
konsolebox



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