skarnet / execline

The execline scripting language
https://skarnet.org/software/execline/
ISC License
149 stars 19 forks source link

must rely on path #6

Closed imacks closed 3 years ago

imacks commented 3 years ago

This is a wonderful tool! Is there a way to use execline without installing it in /bin or any dir in PATH? I initially thought that EXECLINE_BINPREFIX can be used to launch execline progs with absolute path, but apparently this is partially true only. Right now, I am using a loader script to add the installation dir to PATH and then call execlineb, but that breaks if the loaded script modifies PATH.

skarnet commented 3 years ago

Execline scripts are really command lines, and execline commands are binaries; so if you want to be able to call execline commands in scripts (such as foreground in the foreground { sleep 1 } echo blah script) then they have to be present in your PATH. You can install execline into whatever directory suits your fancy, as long as you make sure that directory is present in PATH before you run the script.

imacks commented 3 years ago

Yes I figure. It is just that the purpose of --exec-prefix=... --enable-absolute-paths in configure did not turn out to be what I thought to be. Some binaries that loads importas, pipeline, etc. are launched with an absolute path, but I had assumed that all execline binaries will be.

Is there any chance of adding an option to launch all execline binaries with an absolute path? Right now I am setting PATH before executing execlineb, like what you have suggested. The caveat is that if the script itself modifies PATH before it finishes, everything after the modification will break. I can install to a standard PATH such as /bin, but I am worried that will cause conflict further down the road if any of these binaries gets accidentally replaced by another package.

For completeness, here's my current workaround: install to /usr/execline, then have this at /bin/execlineb (s6 portable utils are installed in /bin):

#!/usr/execline/bin/execlineb -S0

/usr/execline/bin/importas -D "" PATH PATH
/usr/execline/bin/ifelse
{
    /usr/execline/bin/pipeline { s6-echo :${PATH}: } 
    s6-grep -q :/usr/execline/bin:
}
{
    /usr/execline/bin/execlineb $@
}

/usr/execline/bin/ifelse { s6-test -n "${PATH}" }
{
    /usr/execline/bin/export PATH "/usr/execline/bin:${PATH}"
    /usr/execline/bin/execlineb $@
}
/usr/execline/bin/export PATH "/usr/execline/bin"
/usr/execline/bin/execlineb $@
skarnet commented 3 years ago

It's just not possible to tell an execline script to launch binaries with an absolute path, because the script is just an argv. In order to do so, you have to encode the absolute paths in the script itself, e.g. /usr/execline/bin/foreground { sleep 1 } echo blah.

Please be aware that some binaries in s6 and s6-rc rely on execline binaries being available in their PATH without invoking execlineb, so your workaround will not work for them. However, if you use --enable-absolute-paths or --enable-slashpackage, they will still work: those options encode absolute paths in binaries that call external programs.

You should not be afraid of installing execline programs into /bin. Their names have been chosen so they don't conflict. There was one conflict at some point, but it was removed, and now execline has precedence on all the names it uses. If a package "replaces" them, it's a problem with your distribution, and you should take it up with them and/or the package that provides the conflicting program.

imacks commented 3 years ago

I take the conflict you said was about import used by PHP? I sometimes wonder how the linux community resolve these sort of naming issues. Programs named by different authors are short, common words and all installed into /bin, but somehow they don't conflict. Thanks for pointing out --enable-absolute-paths. I am already using that compile option in order to make my script above work. Back to topic: one possible implementation I can think of is for every program in the execline suite to check argv[1] against a list of known programs. If it matches, argv[1] will be modified to be prefixed with EXECLINE_BINPREFIX. That way, you only need to specify full path for the first program in the chain. Is there any caveat I'm not seeing?

skarnet commented 3 years ago

It was import indeed, but the conflict was with ImageMagick, not PHP. I eventually decided to abandon execline's import binary because ImageMagick had precedence, even though it irks me that such a specific package does not properly prefix the names of its executables and treads shamelessly on the global namespace.

It seems that I was not clear enough: execline binaries rely on PATH by design. There is nothing to fix here, nothing to solve; execline binaries are not different from any other binaries on your system, and relying on PATH to find them is just the way Unix works; any attempt to work around that would be misguided and needlessly introduce bugs. What I suggest you to work on is your perception that execline binaries don't belong in /bin: they do, just as much as anything else that is installed in /bin, and nothing bad will happen to your system.

imacks commented 3 years ago

tks for clarifying that relying on PATH is by design. I guess there is no issue then.