Skip to content

Commit 4a3575f

Browse files
committed
Refactor AutodetectBinary.
In this change: - AutodetectBinary is refactored into several utility functions for finding binaries in BINARY_DIR.
1 parent 3bfcd77 commit 4a3575f

File tree

1 file changed

+89
-34
lines changed

1 file changed

+89
-34
lines changed

ssh-ident

Lines changed: 89 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -848,24 +848,102 @@ class AgentManager(object):
848848
def AutodetectBinary(argv, config):
849849
"""Detects the correct binary to run and sets BINARY_SSH accordingly,
850850
if it is not already set."""
851+
852+
# Set default binary to use, in case the binary can't be found otherwise.
853+
DEFAULT_BINARY = "ssh"
854+
851855
# If BINARY_SSH is set by the user, respect that and do nothing.
852856
if config.Get("BINARY_SSH"):
853857
print("Will run '{0}' as ssh binary - set by user via BINARY_SSH"
854858
.format(config.Get("BINARY_SSH")), loglevel=LOG_DEBUG)
855859
return
856860

857-
# If BINARY_DIR is set, look for the binary in this directory.
861+
# Get name of running programe
858862
runtime_name = argv[0]
859-
if config.Get("BINARY_DIR"):
860-
binary_name = os.path.basename(runtime_name)
861-
binary_path = os.path.join(config.Get("BINARY_DIR"), binary_name)
862-
if not os.path.isfile(binary_path) or not os.access(binary_path, os.X_OK):
863-
binary_path = os.path.join(config.Get("BINARY_DIR"), "ssh")
863+
binary_name = os.path.basename(runtime_name)
864864

865+
# Look for runtime_name or DEFAULT_BINARY in BINARY_DIR.
866+
binary_dir = config.Get("BINARY_DIR")
867+
if binary_dir:
868+
# Use first valid find between the runtime binary and the default binary.
869+
binaries = [FindBinaryInDirectory(binary_dir, name)
870+
for name in (binary_name, DEFAULT_BINARY)]
871+
binary_path = next((path for path in binaries if path is not None), None)
872+
if binary_path:
873+
config.Set("BINARY_SSH", binary_path)
874+
print("Will run '{0}' as ssh binary - detected based on BINARY_DIR"
875+
.format(binary_path), loglevel=LOG_DEBUG)
876+
return
877+
878+
# Look for runtime_name or DEFAULT_BINARY in PATH.
879+
# Use first valid find between the runtime binary and the default binary.
880+
binaries = [FindAutodetectBinaryInPath(name)
881+
for name in (runtime_name, DEFAULT_BINARY)]
882+
binary_path = next((path for path in binaries if path is not None), None)
883+
if binary_path:
865884
config.Set("BINARY_SSH", binary_path)
866-
print("Will run '{0}' as ssh binary - deteced based on BINARY_DIR"
885+
print("Will run '{0}' as ssh binary - detected from argv[0] and $PATH"
867886
.format(config.Get("BINARY_SSH")), loglevel=LOG_DEBUG)
868-
return
887+
else:
888+
message = textwrap.dedent("""\
889+
ssh-ident was invoked in place of the binary {0} (determined from argv[0]).
890+
Neither this binary nor 'ssh' could be found in $PATH.
891+
892+
PATH="{1}"
893+
894+
You need to adjust your setup for ssh-ident to work: consider setting
895+
BINARY_SSH or BINARY_DIR in your config, or running ssh-ident some
896+
other way.""")
897+
print(message.format(argv[0], os.environ['PATH']), loglevel=LOG_ERROR)
898+
sys.exit(255)
899+
900+
901+
def GetNormalizedSystemPath():
902+
"""Returns a the system PATH as a list, with symlinks etc.
903+
being normalized."""
904+
# Paths in PATH may be not-normalized, example: "/usr/bin/../foo",
905+
# or "/opt/scripts///". Normalize them before comparison.
906+
normalized_path = [
907+
os.path.normpath(p) for p in os.environ['PATH'].split(os.pathsep)]
908+
909+
return normalized_path
910+
911+
def FindBinaryInDirectory(binary_dir, binary_name):
912+
"""Looks for an executable with a given name in a given directory and
913+
returns the binary path if it was found."""
914+
binary_path = os.path.join(binary_dir, binary_name)
915+
if os.path.isfile(binary_path) and os.access(binary_path, os.X_OK):
916+
return binary_path
917+
else:
918+
return None
919+
920+
def FindBinaryInPath(binary_name, search_path=None):
921+
"""Looks for an executable with a given name in a given directory and
922+
returns the binary path if it was found."""
923+
if not search_path:
924+
search_path = GetNormalizedSystemPath()
925+
926+
# Find an executable with the desired name.
927+
binary_path = distutils.spawn.find_executable(binary_name, search_path)
928+
929+
return binary_path
930+
931+
def FindBinary(binary_dir, binary_name):
932+
"""Looks for an executable binary_name in binary_dir and PATH and
933+
returns the binary path if it was found."""
934+
if binary_dir:
935+
binary_path = FindBinaryInDirectory(binary_dir, binary_name)
936+
if binary_path:
937+
return binary_path
938+
939+
# Look for binary in PATH.
940+
binary_path = FindBinaryInPath(binary_name)
941+
if binary_path:
942+
return binary_path
943+
944+
def FindAutodetectBinaryInPath(runtime_name):
945+
"""Looks for the correct binary that is supposed to runin PATH and returns
946+
the binary path if it was found."""
869947

870948
# argv[0] could be pretty much anything the caller decides to set
871949
# it to: an absolute path, a relative path (common in older systems),
@@ -907,37 +985,13 @@ def AutodetectBinary(argv, config):
907985
# Remove the path containing the ssh-ident symlink (or whatever) from
908986
# the search path, so we do not cause an infinite loop.
909987
# Note that:
910-
# - paths in PATH may be not-normalized, example: "/usr/bin/../foo",
911-
# or "/opt/scripts///". Normalize them before comparison.
912988
# - paths in PATH may be repeated multiple times. We have to exclude
913989
# all instances of the ssh-ident path.
914-
normalized_path = [
915-
os.path.normpath(p) for p in os.environ['PATH'].split(os.pathsep)]
990+
normalized_path = GetNormalizedSystemPath()
916991
search_path = os.pathsep.join([
917992
p for p in normalized_path if p != ssh_ident_path])
918993

919-
# Find an executable with the desired name.
920-
binary_path = distutils.spawn.find_executable(binary_name, search_path)
921-
if not binary_path:
922-
# Nothing found. Try to find something named 'ssh'.
923-
binary_path = distutils.spawn.find_executable('ssh')
924-
925-
if binary_path:
926-
config.Set("BINARY_SSH", binary_path)
927-
print("Will run '{0}' as ssh binary - deteced from argv[0] and $PATH"
928-
.format(config.Get("BINARY_SSH")), loglevel=LOG_DEBUG)
929-
else:
930-
message = textwrap.dedent("""\
931-
ssh-ident was invoked in place of the binary {0} (determined from argv[0]).
932-
Neither this binary nor 'ssh' could be found in $PATH.
933-
934-
PATH="{1}"
935-
936-
You need to adjust your setup for ssh-ident to work: consider setting
937-
BINARY_SSH or BINARY_DIR in your config, or running ssh-ident some
938-
other way.""")
939-
print(message.format(argv[0], os.environ['PATH']), loglevel=LOG_ERROR)
940-
sys.exit(255)
994+
return FindBinaryInPath(binary_name, search_path)
941995

942996
def ParseCommandLine(argv, config):
943997
"""Parses the command line parameters in argv
@@ -976,6 +1030,7 @@ def main(argv):
9761030
print = SshIdentPrint(config)
9771031

9781032
AutodetectBinary(argv, config)
1033+
9791034
# Check that BINARY_SSH is not ssh-ident.
9801035
# This can happen if the user sets a binary name only (e.g. 'scp') and a
9811036
# symlink with the same name was set up.

0 commit comments

Comments
 (0)