Repository: conan-io/conan

Issue:
tools.which also returns dirs
Hi, 

`tools.which` can returns a folder path if his basename match. For example, on Windows, it returns `C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\Git` which is a directory.

You can reproduce with:
```python
import os
from conans import tools

tools.mkdir("C:\Dev")
tools.mkdir("C:\Dev\Git")
with tools.environment_append({"PATH": "C:\Dev\;"+tools.get_env("PATH")}):
    git = tools.which("git") # returns "C:\Dev\git"

    print(os.path.isfile(git)) # Is False
```

I work with:
 * Conan 1.3.3
 * Windows 10 1709

Thanks !


Discussion:
Thanks! it is quite easy to solve it, so we will solve it for the next release.

Resolving patch:
diff --git a/conans/client/tools/files.py b/conans/client/tools/files.py
--- a/conans/client/tools/files.py
+++ b/conans/client/tools/files.py
@@ -253,7 +253,7 @@ def collect_libs(conanfile, folder="lib"):
 def which(filename):
     """ same affect as posix which command or shutil.which from python3 """
     def verify(filepath):
-        if os.path.exists(filepath) and os.access(filepath, os.X_OK):
+        if os.path.isfile(filepath) and os.access(filepath, os.X_OK):
             return os.path.join(path, filename)
         return None
 


Test patch:
diff --git a/conans/test/util/tools_test.py b/conans/test/util/tools_test.py
--- a/conans/test/util/tools_test.py
+++ b/conans/test/util/tools_test.py
@@ -21,7 +21,7 @@
 from conans.test.utils.test_files import temp_folder
 from conans.test.utils.tools import TestClient, TestBufferConanOutput
 
-from conans.test.utils.context_manager import which
+from conans.tools import which
 from conans.tools import OSInfo, SystemPackageTool, replace_in_file, AptTool, ChocolateyTool,\
     set_global_instances
 from conans.util.files import save, load, md5
diff --git a/conans/test/util/which_test.py b/conans/test/util/which_test.py
--- a/conans/test/util/which_test.py
+++ b/conans/test/util/which_test.py
@@ -7,6 +7,7 @@
 import platform
 from conans import tools
 from conans.test.utils.test_files import temp_folder
+from conans.util.files import mkdir
 
 
 class WhichTest(unittest.TestCase):
@@ -45,3 +46,12 @@ def test_which_non_executable(self):
         self._touch(fullname)
         with tools.environment_append({'PATH': tmp_dir}):
             self.assertIsNone(tools.which('example.sh'))
+
+    def test_which_not_dir(self):
+        tmp_dir = temp_folder()
+        dev_dir = os.path.join(tmp_dir, "Dev")
+        dev_git_dir = os.path.join(dev_dir, "Git")
+        mkdir(dev_git_dir)
+        with tools.environment_append({'PATH': dev_dir}):
+            self.assertEqual(dev_dir, tools.get_env("PATH"))
+            self.assertIsNone(tools.which('git'))
diff --git a/conans/test/utils/context_manager.py b/conans/test/utils/context_manager.py
--- a/conans/test/utils/context_manager.py
+++ b/conans/test/utils/context_manager.py
@@ -2,15 +2,18 @@
 import glob
 import copy
 
+from conans.tools import which
+
 
 class CustomEnvPath():
-    '''
+    """
     Class to create a custom environment with 3 paramenters:
         -paths_to_add: list with all the paths that you need in the environments
         -paths_to_remove: list with all the paths that you need to remove from the environment
         -cmds_to_remove: list of commands that you need to remove from paths.
          This class looks for its path and remove it from paths.
-    '''
+    """
+
     def __init__(self, paths_to_add=None, paths_to_remove=None,
                  var_to_add=None, var_to_remove=None, cmds_to_remove=None):
         self._original_env = copy.deepcopy(os.environ)
@@ -42,27 +45,3 @@ def __enter__(self):
 
     def __exit__(self, _type, value, traceback):
         os.environ = self._original_env
-
-
-def which(program):
-    path_found = []
-
-    def is_exe(fpath):
-        return os.path.exists(fpath) and os.access(fpath, os.X_OK)
-
-    fpath, _ = os.path.split(program)
-    if fpath:
-        if is_exe(program):
-            path_found.append(fpath)
-    else:
-        _, ext = os.path.splitext(program)
-        if ext:
-            file_to_find = program
-        else:
-            file_to_find = "%s.*" % program
-        for path in os.environ["PATH"].split(os.pathsep):
-            for _file in glob.glob(os.path.join(path, file_to_find)):
-                if is_exe(os.path.join(path, _file)):
-                    path_found.append(path)
-
-    return path_found