Skip to content

Commit 180c706

Browse files
authored
Add -path parameter to get specific instance (#192)
Fixes #191
1 parent a6d40ba commit 180c706

File tree

11 files changed

+229
-19
lines changed

11 files changed

+229
-19
lines changed

docker/Tests/vswhere.tests.ps1

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,43 @@ Describe 'vswhere' {
350350
}
351351
}
352352

353+
Context '-path' {
354+
It 'returns nothing for non-installation path' {
355+
$instances = C:\bin\vswhere.exe -path C:\ShouldNotExist -format json | ConvertFrom-Json
356+
$instances | Should BeNullOrEmpty
357+
}
358+
359+
It 'returns normal instance' {
360+
$instances = C:\bin\vswhere.exe -path C:\VS\Enterprise -format json | ConvertFrom-Json
361+
$instances.Count | Should Be 1
362+
$instances[0].InstanceId | Should Be 2
363+
}
364+
365+
It 'returns normal instance for normalized directory' {
366+
$instances = C:\bin\vswhere.exe -path C:\VS\Enterprise\ -format json | ConvertFrom-Json
367+
$instances.Count | Should Be 1
368+
$instances[0].InstanceId | Should Be 2
369+
}
370+
371+
It 'returns normal instance for file path' {
372+
$instances = C:\bin\vswhere.exe -path C:\VS\Enterprise\Common7\Tools\VSDevCmd.bat -format json | ConvertFrom-Json
373+
$instances.Count | Should Be 1
374+
$instances[0].InstanceId | Should Be 2
375+
}
376+
377+
It 'returns incomplete instance' {
378+
$instances = C:\bin\vswhere.exe -path C:\VS\Professional -format json | ConvertFrom-Json
379+
$instances.Count | Should Be 1
380+
$instances[0].InstanceId | Should Be 3
381+
}
382+
383+
It 'returns other instance' {
384+
$instances = C:\bin\vswhere.exe -path C:\BuildTools -format json | ConvertFrom-Json
385+
$instances.Count | Should Be 1
386+
$instances[0].InstanceId | Should Be 4
387+
}
388+
}
389+
353390
# NOTE: microsoft/windowsservercore does not support setting the code page to anything other than 65001.
354391
# Context 'encodes ja-JP' {
355392
# BeforeAll {

src/vswhere.lib/CommandArgs.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ void CommandArgs::Parse(_In_ LPCWSTR wszCommandLine)
2929
CommandParser parser;
3030
auto args = parser.Parse(wszCommandLine);
3131

32-
m_path = parser.get_Path();
32+
m_applicationPath = parser.get_Path();
3333

3434
Parse(args);
3535
}
@@ -39,13 +39,15 @@ void CommandArgs::Parse(_In_ int argc, _In_ LPCWSTR argv[])
3939
CommandParser parser;
4040
auto args = parser.Parse(argc, argv);
4141

42-
m_path = parser.get_Path();
42+
m_applicationPath = parser.get_Path();
4343

4444
Parse(args);
4545
}
4646

4747
void CommandArgs::Parse(_In_ vector<CommandParser::Token> args)
4848
{
49+
bool hasSelection = false;
50+
4951
for (auto it = args.begin(); it != args.end(); ++it)
5052
{
5153
auto& arg = *it;
@@ -60,26 +62,32 @@ void CommandArgs::Parse(_In_ vector<CommandParser::Token> args)
6062
if (ArgumentEquals(arg.Value, L"all"))
6163
{
6264
m_all = true;
65+
hasSelection = true;
6366
}
6467
else if (ArgumentEquals(arg.Value, L"products"))
6568
{
6669
ParseArgumentArray(it, args.end(), arg, m_products);
70+
hasSelection = true;
6771
}
6872
else if (ArgumentEquals(arg.Value, L"requires"))
6973
{
7074
ParseArgumentArray(it, args.end(), arg, m_requires);
75+
hasSelection = true;
7176
}
7277
else if (ArgumentEquals(arg.Value, L"requiresAny"))
7378
{
7479
m_requiresAny = true;
80+
hasSelection = true;
7581
}
7682
else if (ArgumentEquals(arg.Value, L"version"))
7783
{
7884
m_version = ParseArgument(it, args.end(), arg);
85+
hasSelection = true;
7986
}
8087
else if (ArgumentEquals(arg.Value, L"latest"))
8188
{
8289
m_latest = true;
90+
hasSelection = true;
8391
}
8492
else if (ArgumentEquals(arg.Value, L"sort"))
8593
{
@@ -88,10 +96,16 @@ void CommandArgs::Parse(_In_ vector<CommandParser::Token> args)
8896
else if (ArgumentEquals(arg.Value, L"legacy"))
8997
{
9098
m_legacy = true;
99+
hasSelection = true;
100+
}
101+
else if (ArgumentEquals(arg.Value, L"path"))
102+
{
103+
m_path = ParseArgument(it, args.end(), arg);
91104
}
92105
else if (ArgumentEquals(arg.Value, L"prerelease"))
93106
{
94107
m_prerelease = true;
108+
hasSelection = true;
95109
}
96110
else if (ArgumentEquals(arg.Value, L"format"))
97111
{
@@ -170,6 +184,12 @@ void CommandArgs::Parse(_In_ vector<CommandParser::Token> args)
170184
{
171185
m_format = L"value";
172186
}
187+
188+
if (hasSelection && !m_path.empty())
189+
{
190+
auto message = ResourceManager::GetString(IDS_E_PATHINCOMPATIBLE);
191+
throw win32_error(ERROR_INVALID_PARAMETER, message);
192+
}
173193
}
174194

175195
void CommandArgs::Usage(_In_ Console& console) const

src/vswhere.lib/CommandArgs.h

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@ class CommandArgs
2323
}
2424

2525
CommandArgs(const CommandArgs& obj) :
26-
m_path(obj.m_path),
26+
m_applicationPath(obj.m_applicationPath),
2727
m_all(obj.m_all),
2828
m_productsAll(obj.m_productsAll),
2929
m_products(obj.m_products),
3030
m_requires(obj.m_requires),
3131
m_version(obj.m_version),
3232
m_latest(obj.m_latest),
33-
m_sort(obj.m_sort),
3433
m_legacy(obj.m_legacy),
34+
m_path(obj.m_path),
35+
m_sort(obj.m_sort),
3536
m_prerelease(obj.m_prerelease),
3637
m_format(obj.m_format),
3738
m_property(obj.m_property),
@@ -42,9 +43,9 @@ class CommandArgs
4243
{
4344
}
4445

45-
const std::wstring& get_Path() const noexcept
46+
const std::wstring& get_ApplicationPath() const noexcept
4647
{
47-
return m_path;
48+
return m_applicationPath;
4849
}
4950

5051
const bool get_All() const noexcept
@@ -82,14 +83,19 @@ class CommandArgs
8283
return m_latest;
8384
}
8485

85-
const bool get_Sort() const noexcept
86+
const bool get_Legacy() const noexcept
8687
{
87-
return m_sort;
88+
return m_legacy;
8889
}
8990

90-
const bool get_Legacy() const noexcept
91+
const std::wstring& get_Path() const noexcept
9192
{
92-
return m_legacy;
93+
return m_path;
94+
}
95+
96+
const bool get_Sort() const noexcept
97+
{
98+
return m_sort;
9399
}
94100

95101
const bool get_Prerelease() const noexcept
@@ -143,16 +149,17 @@ class CommandArgs
143149

144150
void Parse(_In_ std::vector<CommandParser::Token> args);
145151

146-
std::wstring m_path;
152+
std::wstring m_applicationPath;
147153
bool m_all;
148154
bool m_productsAll;
149155
std::vector<std::wstring> m_products;
150156
std::vector<std::wstring> m_requires;
151157
bool m_requiresAny;
152158
std::wstring m_version;
153159
bool m_latest;
154-
bool m_sort;
155160
bool m_legacy;
161+
std::wstring m_path;
162+
bool m_sort;
156163
bool m_prerelease;
157164
std::wstring m_format;
158165
std::wstring m_property;

src/vswhere.lib/resource.h

90 Bytes
Binary file not shown.

src/vswhere.lib/vswhere.lib.rc

500 Bytes
Binary file not shown.

src/vswhere/Program.cpp

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using namespace std;
99

1010
void GetEnumerator(_In_ const CommandArgs& args, _In_ ISetupConfigurationPtr& query, _In_ IEnumSetupInstancesPtr& e);
11+
wstring GetFullPath(_In_ const wstring& path);
1112
void WriteLogo(_In_ const CommandArgs& args, _In_ Console& console, _In_ Module& module);
1213

1314
int wmain(_In_ int argc, _In_ LPCWSTR argv[])
@@ -55,11 +56,26 @@ int wmain(_In_ int argc, _In_ LPCWSTR argv[])
5556
helper.Attach(new VersionRange);
5657
}
5758

58-
IEnumSetupInstancesPtr e;
59-
GetEnumerator(args, query, e);
59+
vector<ISetupInstancePtr> instances;
60+
if (args.get_Path().empty())
61+
{
62+
IEnumSetupInstancesPtr e;
63+
GetEnumerator(args, query, e);
64+
65+
InstanceSelector selector(args, helper);
66+
instances = std::move(selector.Select(e));
67+
}
68+
else
69+
{
70+
auto path = GetFullPath(args.get_Path());
6071

61-
InstanceSelector selector(args, helper);
62-
auto instances = selector.Select(e);
72+
ISetupInstancePtr instance;
73+
hr = query->GetInstanceForPath(path.c_str(), &instance);
74+
if (SUCCEEDED(hr))
75+
{
76+
instances.push_back(instance);
77+
}
78+
}
6379

6480
// Create the formatter and optionally show the logo.
6581
auto formatter = Formatter::Create(args.get_Format());
@@ -146,6 +162,33 @@ void GetEnumerator(_In_ const CommandArgs& args, _In_ ISetupConfigurationPtr& qu
146162
}
147163
}
148164

165+
wstring GetFullPath(_In_ const wstring& path)
166+
{
167+
DWORD ret = 0;
168+
wstring fullPath;
169+
170+
for (;;)
171+
{
172+
ret = ::GetFullPathNameW(path.c_str(), fullPath.capacity(), const_cast<LPWSTR>(fullPath.c_str()), NULL);
173+
174+
if (ret == 0)
175+
{
176+
throw win32_error();
177+
}
178+
// If buffer too small, return value contains required character count including terminating null.
179+
else if (ret >= fullPath.capacity())
180+
{
181+
fullPath.resize(ret, L'\0');
182+
}
183+
else
184+
{
185+
break;
186+
}
187+
}
188+
189+
return fullPath;
190+
}
191+
149192
void WriteLogo(_In_ const CommandArgs& args, _In_ Console& console, _In_ Module& module)
150193
{
151194
if (args.get_Logo())

src/vswhere/vswhere.exe.manifest

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
2+
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
3+
<application xmlns="urn:schemas-microsoft-com:asm.v3">
4+
<windowsSettings xmlns:ws2="https://schemas.microsoft.com/SMI/2016/WindowsSettings">
5+
<ws2:longPathAware>true</ws2:longPathAware>
6+
</windowsSettings>
7+
</application>
8+
</assembly>

src/vswhere/vswhere.vcxproj

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@
6868
<SubSystem>Console</SubSystem>
6969
<GenerateDebugInformation>true</GenerateDebugInformation>
7070
</Link>
71+
<Manifest>
72+
<AdditionalManifestFiles>vswhere.exe.manifest</AdditionalManifestFiles>
73+
</Manifest>
7174
</ItemDefinitionGroup>
7275
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
7376
<ClCompile>
@@ -86,6 +89,9 @@
8689
<OptimizeReferences>true</OptimizeReferences>
8790
<GenerateDebugInformation>true</GenerateDebugInformation>
8891
</Link>
92+
<Manifest>
93+
<AdditionalManifestFiles>vswhere.exe.manifest</AdditionalManifestFiles>
94+
</Manifest>
8995
</ItemDefinitionGroup>
9096
<ItemGroup>
9197
<ClInclude Include="resource.h" />
@@ -108,6 +114,9 @@
108114
<None Include="packages.config">
109115
<SubType>Designer</SubType>
110116
</None>
117+
<None Include="vswhere.exe.manifest">
118+
<SubType>Designer</SubType>
119+
</None>
111120
</ItemGroup>
112121
<ItemGroup>
113122
<FilesToSign Include="$(TargetPath)">

src/vswhere/vswhere.vcxproj.filters

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</Filter>
1212
<Filter Include="Resource Files">
1313
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
14-
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
14+
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;manifest</Extensions>
1515
</Filter>
1616
</ItemGroup>
1717
<ItemGroup>
@@ -35,5 +35,8 @@
3535
</ItemGroup>
3636
<ItemGroup>
3737
<None Include="packages.config" />
38+
<None Include="vswhere.exe.manifest">
39+
<Filter>Resource Files</Filter>
40+
</None>
3841
</ItemGroup>
3942
</Project>

0 commit comments

Comments
 (0)