Wrappers are executable scripts that launch a command inside a known envstack environment. They are useful when you want a stable CLI entrypoint without asking users to remember the right stack name every time.
- A tool always starts with the expected environment active
- Stack-selection details stay inside the launcher
- Environment variables can be resolved before building the final command
- Small bootstrap scripts become easy to distribute and reuse
The repository includes an example wrapper at
bin/hello
and a companion stack file at
examples/wrappers/hello.env.
The stack file:
#!/usr/bin/env envstack
include: [default]
all: &all
HELLO: world
LOG_LEVEL: ${LOG_LEVEL:=INFO}
darwin:
<<: *all
PYEXE: /usr/local/bin/python3
linux:
<<: *all
PYEXE: /usr/bin/python
windows:
<<: *all
PYEXE: C:\Python39\python.exeThe wrapper:
#!/usr/bin/env python3
import sys
from envstack.wrapper import Wrapper
class HelloWrapper(Wrapper):
"""A simple wrapper that prints the value of an environment variable."""
def __init__(self, *args, **kwargs):
super(HelloWrapper, self).__init__(*args, **kwargs)
self.shell = True
def executable(self):
"""Return the executable to run."""
return "/usr/bin/python -c 'import os,sys;print(os.getenv(sys.argv[1]))'"
def main():
"""Run the wrapper in the 'hello' env stack."""
hello = HelloWrapper("hello", sys.argv[1:])
return hello.launch()
if __name__ == "__main__":
sys.exit(main())Running it:
$ hello HELLO
worldThe wrapper code never hard-codes HELLO=world. It loads the hello stack,
resolves it, and launches the subprocess with those values in its environment.
- The wrapper subclasses
envstack.wrapper.Wrapper. - It names the stack to load, here
hello. launch()resolves that stack and builds a subprocess environment.- The wrapped command runs with those env vars already applied.
This makes wrappers a good fit for tool launchers, bootstrap scripts, and small command shims around shared environments.
The same pattern works for far more than a demo hello command. In practice,
you can wrap almost any executable so it always runs inside a composed
environment stack.
Common use cases:
- DCC launchers such as
nuke,maya, orhoudini - Project tools that need a specific
PATH,PYTHONPATH, or license setup - Build and render commands that should inherit a known deployment root
- Internal CLIs that should run with stack-selected config by default
At the command line, the simplest form is already:
envstack dev -- python -m pytest
envstack project -- nuke
envstack showA -- /usr/local/bin/custom-tool --flag valueIf you want a stable executable entrypoint instead of asking users to prefix
every command with envstack, create a wrapper script around that executable.
For an argv-style executable, the underlying Wrapper base class can return a
resolved path such as ${TOOL_ROOT}/bin/tool, and the subprocess inherits the
fully resolved stack environment before launch.
For example:
import sys
from envstack.wrapper import Wrapper
class ToolWrapper(Wrapper):
def executable(self):
return "${TOOL_ROOT}/bin/tool"
if __name__ == "__main__":
sys.exit(ToolWrapper("project", sys.argv[1:]).launch())That is the main value of wrappers: any executable can be made to feel "pre-configured" by binding it to a named environment stack.