Repository: conan-io/conan

Issue:
Conan doesn't detect vswhere in the path
If you install vswhere with choco, the tool is not in the paths Conan looks for. Conan should try to run it directly if `which` responds.


Discussion:

Resolving patch:
diff --git a/conans/client/tools/win.py b/conans/client/tools/win.py
--- a/conans/client/tools/win.py
+++ b/conans/client/tools/win.py
@@ -7,6 +7,7 @@
 
 import deprecation
 
+from conans.client.tools import which
 from conans.client.tools.env import environment_append
 from conans.client.tools.oss import OSInfo, detected_architecture
 from conans.errors import ConanException
@@ -250,15 +251,19 @@ def vswhere(all_=False, prerelease=False, products=None, requires=None, version=
         raise ConanException("The 'legacy' parameter cannot be specified with either the "
                              "'products' or 'requires' parameter")
 
-    program_files = os.environ.get("ProgramFiles(x86)", os.environ.get("ProgramFiles"))
-
+    installer_path = None
+    vswhere_in_path = which("vswhere")
+    program_files = get_env("ProgramFiles(x86)") or get_env("ProgramFiles")
     if program_files:
-        vswhere_path = os.path.join(program_files, "Microsoft Visual Studio", "Installer",
-                                    "vswhere.exe")
-        if not os.path.isfile(vswhere_path):
-            raise ConanException("Cannot locate 'vswhere'")
-    else:
-        raise ConanException("Cannot locate 'Program Files'/'Program Files (x86)' directory")
+        expected_path = os.path.join(program_files, "Microsoft Visual Studio", "Installer",
+                                     "vswhere.exe")
+        if os.path.isfile(expected_path):
+            installer_path = expected_path
+    vswhere_path = installer_path or vswhere_in_path
+
+    if not vswhere_path:
+        raise ConanException("Cannot locate vswhere in 'Program Files'/'Program Files (x86)' "
+                             "directory nor in PATH")
 
     arguments = list()
     arguments.append(vswhere_path)


Test patch:
diff --git a/conans/test/unittests/util/tools_test.py b/conans/test/unittests/util/tools_test.py
--- a/conans/test/unittests/util/tools_test.py
+++ b/conans/test/unittests/util/tools_test.py
@@ -37,6 +37,7 @@
 from conans.test.utils.tools import SVNLocalRepoTestCase, StoppableThreadBottle, \
     TestBufferConanOutput, TestClient, create_local_git_repo, try_remove_readonly
 from conans.tools import get_global_instances
+from conans.util.env_reader import get_env
 from conans.util.files import load, md5, mkdir, save
 
 
@@ -794,6 +795,30 @@ def vswhere_description_strip_test(self):
             json = vswhere()
             self.assertNotIn("descripton", json)
 
+    @unittest.skipUnless(platform.system() == "Windows", "Requires vswhere")
+    def vswhere_path_test(self):
+        # vswhere not found
+        with tools.environment_append({"ProgramFiles": None, "ProgramFiles(x86)": None, "PATH": ""}):
+            with self.assertRaisesRegex(ConanException, "Cannot locate vswhere"):
+                vswhere()
+        # vswhere in ProgramFiles
+        program_files = get_env("ProgramFiles(x86)") or get_env("ProgramFiles")
+        vswhere_path = None
+        if program_files:
+            expected_path = os.path.join(program_files, "Microsoft Visual Studio", "Installer",
+                                         "vswhere.exe")
+            if os.path.isfile(expected_path):
+                vswhere_path = expected_path
+                with tools.environment_append({"PATH": ""}):
+                    self.assertTrue(vswhere())
+        # vswhere in PATH
+        env = {"ProgramFiles": None, "ProgramFiles(x86)": None}
+        if not which("vswhere") and vswhere_path:
+                vswhere_folder = os.path.join(program_files, "Microsoft Visual Studio", "Installer")
+                env.update({"PATH": [vswhere_folder]})
+        with tools.environment_append(env):
+            self.assertTrue(vswhere())
+
     def vcvars_echo_test(self):
         if platform.system() != "Windows":
             return