Backend resolution¶
The registry, sh/backend/init.lua, is the only module that
knows which backends exist. Its rule, from
section 6.6: resolve once, look
up, never re-detect.
When a backend is selected¶
Three moments call select:
require("sh"), insidepcall, so that a host with no usable backend still loads the module and the first command raises the recorded reason (current);sh.set_backend(choice, opts);- an assignment
sh.config = { ... }, whichapply_configturns into a selection of the backend the table names.
A command or a cd never probes anything: run,
chdir, getcwd and
capabilities go straight to the backend in use.
What a choice means¶
resolve dispatches on the type of the choice through
RESOLVE:
- A table of your own (
RESOLVE.table) is checked against the contract and used as it is; see testing and your own backend. - A name (
RESOLVE.string) loadssh.backend.<name>withload. "auto"or nil isLUASH_BACKENDwhen that is set and not empty or"auto", otherwise the first candidate of the platform's order that works (first_available).
The order is one table, ORDER, keyed by
sys.platform(): posix, luv, popen on POSIX systems,
luv, popen on Windows, and luv, posix, popen on Android, where fork
inside an app process is unsupported.
What "works" means¶
candidate accepts a backend when three checks pass:
- the module loads (
load); a failed load is tried again at the next selection, so a library installed later is found; - it is complete: a string
nameand the six functions ofCONTRACT, checked byincomplete, which names what is missing; ready:configure(opts)is called, thenavailable()must return true.
configure runs before available because popen's answer depends on its
strategy: minimal works almost anywhere, shmem only with a writable
/dev/shm. The options are the popen options of sh.config with those of
the call on top (popen_options);
configuration replaces a strategy of "auto" with
LUASH_POPEN_STRATEGY. Both environment variables are read once, when the
registry loads (ENV), and exist for the test matrix and operators.
All three checks run through sys.load_pcall, so that a
library loading while sh.install() is active still sees undefined
globals as nil.
Failure¶
A named backend that does not work is an error naming it and the reason,
such as sh.backend: luv is unavailable: module 'luv' not found; with
"auto" and nothing available, the error lists every candidate's reason.
In both cases the backend in use stays as it was: select
configures it again with its previous options, since the failed attempt may
have reconfigured popen. sh.config is updated only after a selection
succeeded (set_backend).
Listing and preloading¶
available reports the platform's backends that pass the
checks with the options of the backend in use, computed once per selection;
sh.available_backends() returns it. preload loads every
backend of the platform without selecting one. sh.install() calls it
first, so that a script's own require("posix") after install() gets the
loaded module, as with the 1.x library.
How to¶
See what is in use¶
print(sh.backend_name()) -- posix
print(table.concat(sh.available_backends(), " ")) -- posix luv popen
print(sh.capabilities().separate_stderr) -- true
Where nothing was available at load, sh.backend_name() and the first
command raise the recorded reason:
sh.backend: no backend in use: sh.backend: luv is unavailable: module 'luv' not found.
Choose a backend¶
sh.set_backend("luv") selects by name, and
sh.set_backend("popen", { strategy = "standard" }) configures popen at
the same time. Both raise when the choice is unavailable and leave the
backend in use as it was, so a preference with a fallback is a pcall:
if not pcall(sh.set_backend, "luv") then
sh.set_backend("auto") -- whatever works here
end
For one run of a script, from the environment, without a change to the code:
LUASH_BACKEND=popen LUASH_POPEN_STRATEGY=minimal lua script.lua
The variables replace a value of "auto" only: a script that calls
sh.set_backend("posix") is not overridden.
Get a faster backend¶
luaposix and luv are weak dependencies: nothing requires them, and
whichever is present is resolved when sh loads or a backend is
selected. Install one for the interpreter in use, and the next
require("sh") runs commands on pipes alone, with stderr apart and
signals reported:
luarocks install luaposix # or: luarocks install luv
A load that failed is tried again at the next selection, so a running
program picks up a library installed meanwhile with
sh.set_backend("auto").
Require a capability¶
Check the capability, not the name: a popen strategy changes what the same backend can do.
if not sh.capabilities().separate_stderr then
sh.set_backend("popen", { strategy = "standard" })
end
The booleans are stdin, separate_stderr, streaming, exitcode and
signals (section 5), next to name
and, under popen, strategy.
Read an "unavailable" error¶
sh.backend: luv is unavailable: module 'luv' not found: the library is not on this interpreter'spackage.cpath. Rocks are installed per Lua version (luarocks --lua-version 5.1 install luv).sh.backend: popen is unavailable: strategy shmem unavailable: /dev/shm is not a writable directory: the strategy asked for cannot work here.standardnames its temp root the same way, andtmpdirpoints it elsewhere (configuration).sh.backend: no backend available on posix: posix (...); luv (...); popen (...):"auto"found nothing, and the reasons follow in the order tried.sh.backend: the backend table has no available(): a table of your own lacks part of the contract (testing).