Skip to content

Commit

Permalink
Fix command -v compatibility with dash shell
Browse files Browse the repository at this point in the history
Fix the `command -v` exit status handling to account for dash being
`/bin/sh` (this is e.g. the default on Debian).  Unlike bash, dash exits
with status 127 if the requested program does not exist -- and testinfra
wrongly interpreted that as `command` being unavailable.

Instead of attempting to use `command -v` and `which` in order, peform
an additional (cached) `command -v command` invocation to determine
whether `command` is available.  Furthermore, assume that `command -v`
can return any non-zero status for command not existing, per POSIX.

This fixes exists() and find_command() raising an exception on systems
using dash as `/bin/sh` and lacking `which(1)`.

Fixes #668
  • Loading branch information
mgorny authored and philpep committed Dec 6, 2022
1 parent 351e8c6 commit df425e3
Showing 1 changed file with 14 additions and 9 deletions.
23 changes: 14 additions & 9 deletions testinfra/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import testinfra.backend
import testinfra.modules
from testinfra.utils import cached_property


class Host:
Expand All @@ -27,26 +28,30 @@ def __init__(self, backend):
def __repr__(self):
return "<testinfra.host.Host {}>".format(self.backend.get_pytest_id())

@cached_property
def has_command_v(self):
"""Return True if `command -v` is available"""
return self.run("command -v command").rc == 0

def exists(self, command):
"""Return True if given command exist in $PATH"""
rc = self.run_expect([0, 1, 127], "command -v %s", command).rc
if rc == 127:
return self.run_expect([0, 1], "which %s", command).rc == 0
if self.has_command_v:
out = self.run("command -v %s", command)
else:
return rc == 0
out = self.run_expect([0, 1], "which %s", command)
return out.rc == 0

def find_command(self, command, extrapaths=("/sbin", "/usr/sbin")):
"""Return path of given command
raise ValueError if command cannot be found
"""
out = self.run_expect([0, 1, 127], "command -v %s", command)
if self.has_command_v:
out = self.run("command -v %s", command)
else:
out = self.run_expect([0, 1], "which %s", command)
if out.rc == 0:
return out.stdout.rstrip("\r\n")
if out.rc == 127:
out = self.run_expect([0, 1], "which %s", command)
if out.rc == 0:
return out.stdout.rstrip("\r\n")
for basedir in extrapaths:
path = os.path.join(basedir, command)
if self.exists(path):
Expand Down

0 comments on commit df425e3

Please sign in to comment.