From e8aa737b09c0e5116565c92363d1aab806905dc6 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Thu, 23 Jul 2020 10:54:25 -0700 Subject: [PATCH] util.executable.which: handle path separators like /bin/which (#17668) * util.executable.which: handle path separators like /bin/which Co-authored-by: Massimiliano Culpo --- lib/spack/spack/test/util/executable.py | 30 +++++++++++++++++++++++++ lib/spack/spack/util/executable.py | 9 ++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lib/spack/spack/test/util/executable.py b/lib/spack/spack/test/util/executable.py index 5e8795f4bf..ae2859ea4b 100644 --- a/lib/spack/spack/test/util/executable.py +++ b/lib/spack/spack/test/util/executable.py @@ -40,6 +40,36 @@ def test_read_unicode(tmpdir, working_env): assert u'\xc3' == script(output=str).strip() +def test_which_relative_path_with_slash(tmpdir, working_env): + tmpdir.ensure('exe') + path = str(tmpdir.join('exe')) + os.environ['PATH'] = '' + + with tmpdir.as_cwd(): + no_exe = ex.which('./exe') + assert no_exe is None + + fs.set_executable(path) + exe = ex.which('./exe') + assert exe.path == path + + +def test_which_with_slash_ignores_path(tmpdir, working_env): + tmpdir.ensure('exe') + tmpdir.ensure('bin{0}exe'.format(os.path.sep)) + + path = str(tmpdir.join('exe')) + wrong_path = str(tmpdir.join('bin', 'exe')) + os.environ['PATH'] = os.path.dirname(wrong_path) + + fs.set_executable(path) + fs.set_executable(wrong_path) + + with tmpdir.as_cwd(): + exe = ex.which('./exe') + assert exe.path == path + + def test_which(tmpdir): os.environ["PATH"] = str(tmpdir) assert ex.which("spack-test-exe") is None diff --git a/lib/spack/spack/util/executable.py b/lib/spack/spack/util/executable.py index 28656b0a32..097da3337e 100644 --- a/lib/spack/spack/util/executable.py +++ b/lib/spack/spack/util/executable.py @@ -233,10 +233,15 @@ def which_string(*args, **kwargs): path = path.split(os.pathsep) for name in args: - for directory in path: - exe = os.path.join(directory, name) + if os.path.sep in name: + exe = os.path.abspath(name) if os.path.isfile(exe) and os.access(exe, os.X_OK): return exe + else: + for directory in path: + exe = os.path.join(directory, name) + if os.path.isfile(exe) and os.access(exe, os.X_OK): + return exe if required: raise CommandNotFoundError(