pyinvoke / invoke

Pythonic task management & command execution.
http://pyinvoke.org
BSD 2-Clause "Simplified" License
4.31k stars 365 forks source link

Change default shell without a config file or Context? #970

Open evadeflow opened 9 months ago

evadeflow commented 9 months ago

I'm trying to do something that feels like it should be simple, but I'm struggling to figure it out. I'm using Invoke 1.7.3 as a library in an app on QNX to run some commands fed to it via MQTT. I'm using Invoke because doing:

from invoke import run

is so much easier than juggling all the subprocess stuff myself(!) But QNX doesn't have /bin/bash, so I have to pass shell='/bin/sh' to every single run() invocation, e.g.:

run("/usr/bin/launch-the-nukes.sh", shell="/bin/sh")

All I want is to configure Invoke so that I don't have to provide the shell argument to run every time. Issue #752 touches on how to do this, but I want to avoid having to push another config file to this embedded system. I've read the Configuration docs, but it seems mostly targeted at folks using the invoke runner rather than library use cases. Any hints much appreciated, thank you. (If somebody answers, I can submit a documentation patch if clarifying this use case seems worthwhile...)

robertschweizer commented 6 months ago

Does the env var INVOKE_RUN_SHELL=/bin/sh work for you?

evadeflow commented 5 months ago

Does the env var INVOKE_RUN_SHELL=/bin/sh work for you?

It doesn't seem to have any effect:

$ INVOKE_RUN_SHELL=/bin/xxx-sh-xxx ipython
Python 3.8.10 (default, Nov 22 2023, 10:22:35)
Type 'copyright', 'credits' or 'license' for more information
IPython 8.12.3 -- An enhanced Interactive Python. Type '?' for help.

In [1]: from invoke import run

In [2]: run('sleep 1')
Out[2]: <Result cmd='sleep 1' exited=0>

In [3]: try:
   ...:     run('this will fail with an error from /bin/bash')
   ...: except Exception as e:
   ...:     print(f"Error: {e}")
   ...:
/bin/bash: this: command not found
Error: Encountered a bad command exit code!

Command: 'this will fail with an error from /bin/bash'

Exit code: 127

Stdout: already printed

Stderr: already printed

In [4]:
robertschweizer commented 5 months ago

For me, it works when using invoke.Context.run() in a tasks.py file, but not when using invoke.run(). So it's really something special about your library use-case.

It feels like a bug, that this env var is respected in tasks.py files, but not when using invoke.run() without a context.