Skip to content

Commit

Permalink
Implement -latest parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
heaths committed Feb 24, 2017
1 parent 1545b2e commit 6d7a05a
Show file tree
Hide file tree
Showing 8 changed files with 376 additions and 52 deletions.
84 changes: 62 additions & 22 deletions docker/Tests/vswhere.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,97 @@
# Licensed under the MIT license. See LICENSE.txt in the project root for license information.

Describe 'vswhere' {
Context 'format: text (default)' {
It 'returns 2 instances' {
Context '(no arguments)' {
It 'returns 2 instances using "text"' {
$instanceIds = C:\bin\vswhere.exe | Select-String 'instanceId: \w+'
$instanceIds.Count | Should Be 2
}

It '-all returns 3 instances' {
It 'returns 2 instances using "json"' {
$instances = C:\bin\vswhere.exe -format json | ConvertFrom-Json
$instances.Count | Should Be 2
}
}

Context '-all' {
It 'returns 3 instances using "text"' {
$instanceIds = C:\bin\vswhere.exe -all | Select-String 'instanceId: \w+'
$instanceIds.Count | Should Be 3
}

It '-products returns 1 instance' {
It 'returns 3 instances using "json"' {
$instances = C:\bin\vswhere.exe -all -format json | ConvertFrom-Json
$instances.Count | Should Be 3
}
}

Context '-products' {
It 'returns 1 instance using "text"' {
$instanceIds = C:\bin\vswhere.exe -products microsoft.visualstudio.product.buildtools | Select-String 'instanceId: \w+'
$instanceIds.Count | Should Be 1
$instanceIds.Matches[0].Value | Should Be 'instanceId: 4'
}

It 'returns 1 instance using "json"' {
$instances = C:\bin\vswhere.exe -products microsoft.visualstudio.product.buildtools -format json | ConvertFrom-Json
$instances.Count | Should Be 1
$instances[0].instanceId | Should Be 4
}
}

It '-requires returns 1 instance' {
Context '-requires' {
It 'returns 1 instance using "text"' {
$instanceIds = C:\bin\vswhere.exe -requires microsoft.visualstudio.workload.nativedesktop | Select-String 'instanceId: \w+'
$instanceIds.Count | Should Be 1
$instanceIds.Matches[0].Value | Should Be 'instanceId: 2'
}

It '-version returns 1 instance' {
$instanceIds = C:\bin\vswhere.exe -version '(15.0.26116,]' | Select-String 'instanceId: \w+'
$instanceIds.Count | Should Be 1
It 'returns 1 instance using "json"' {
$instances = C:\bin\vswhere.exe -requires microsoft.visualstudio.workload.nativedesktop -format json | ConvertFrom-Json
$instances.Count | Should Be 1
$instances[0].instanceId | Should Be 2
}
}

Context 'format: json' {
It 'returns 2 instances' {
$instances = C:\bin\vswhere.exe -format json | ConvertFrom-Json
$instances.Count | Should Be 2
Context '-version' {
It 'returns 1 instance using "text"' {
$instanceIds = C:\bin\vswhere.exe -version '(15.0.26116,]' | Select-String 'instanceId: \w+'
$instanceIds.Count | Should Be 1
$instanceIds.Matches[0].Value | Should Be 'instanceId: 2'
}

It '-all returns 3 instances' {
$instances = C:\bin\vswhere.exe -all -format json | ConvertFrom-Json
$instances.Count | Should Be 3
It 'returns 1 instance using "json"' {
$instances = C:\bin\vswhere.exe -version '(15.0.26116,]' -format json | ConvertFrom-Json
$instances.Count | Should Be 1
$instances[0].instanceId | Should Be 2
}
}

It '-products returns 1 instance' {
$instance = C:\bin\vswhere.exe -products microsoft.visualstudio.product.buildtools -format json | ConvertFrom-Json
$instance.Count | Should Be 1
Context '-latest' {
It 'returns 1 instance using "text"' {
$instanceIds = C:\bin\vswhere.exe -latest | Select-String 'instanceId: \w+'
$instanceIds.Count | Should Be 1
$instanceIds.Matches[0].Value | Should Be 'instanceId: 2'
}

It '-requires returns 1 instance' {
$instances = C:\bin\vswhere.exe -requires microsoft.visualstudio.workload.nativedesktop -format json | ConvertFrom-Json
It 'returns 1 instance using "json"' {
$instances = C:\bin\vswhere.exe -latest -format json | ConvertFrom-Json
$instances.Count | Should Be 1
$instances[0].instanceId | Should Be 2
}
}

Context '-latest -all' {
It 'returns 1 instance using "text"' {
$instanceIds = C:\bin\vswhere.exe -latest -all | Select-String 'instanceId: \w+'
$instanceIds.Count | Should Be 1
$instanceIds.Matches[0].Value | Should Be 'instanceId: 3'
}

It '-version returns 1 instance' {
$instances = C:\bin\vswhere.exe -version '(15.0.26116,]' -format json | ConvertFrom-Json
It 'returns 1 instance using "json"' {
$instances = C:\bin\vswhere.exe -latest -all -format json | ConvertFrom-Json
$instances.Count | Should Be 1
$instances[0].instanceId | Should Be 3
}
}
}
90 changes: 80 additions & 10 deletions src/vswhere.lib/InstanceSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@
using namespace std;
using std::placeholders::_1;

const ci_equal InstanceSelector::s_comparer;

InstanceSelector::InstanceSelector(_In_ const CommandArgs& args, _In_opt_ ISetupHelper* pHelper) :
m_args(args)
m_args(args),
m_ullMinimumVersion(0),
m_ullMaximumVersion(0)
{
// Get the ISetupHelper (if implemented) if a version range is specified.
auto version = args.get_Version();
if (!version.empty())
m_helper = pHelper;
if (m_helper)
{
m_helper = pHelper;
if (m_helper)
auto version = args.get_Version();
if (!version.empty())
{
auto hr = m_helper->ParseVersionRange(version.c_str(), &m_ullMinimumVersion, &m_ullMaximumVersion);
if (FAILED(hr))
Expand All @@ -31,6 +30,65 @@ InstanceSelector::InstanceSelector(_In_ const CommandArgs& args, _In_opt_ ISetup
}
}

bool InstanceSelector::Less(const ISetupInstancePtr& a, const ISetupInstancePtr& b) const
{
static ci_equal equal;
static ci_less less;

bstr_t bstrVersionA, bstrVersionB;
ULONGLONG ullVersionA, ullVersionB;
FILETIME ftDateA, ftDateB;

// Compare versions.
auto hrA = a->GetInstallationVersion(bstrVersionA.GetAddress());
auto hrB = b->GetInstallationVersion(bstrVersionB.GetAddress());
if (SUCCEEDED(hrA) && SUCCEEDED(hrB))
{
if (m_helper)
{
hrA = m_helper->ParseVersion(bstrVersionA, &ullVersionA);
hrB = m_helper->ParseVersion(bstrVersionB, &ullVersionB);
if (SUCCEEDED(hrA) && SUCCEEDED(hrB))
{
if (ullVersionA != ullVersionB)
{
return ullVersionA < ullVersionB;
}
}
else
{
// a is less than b if we can't parse version for a but can for b.
return SUCCEEDED(hrB);
}
}
}
else
{
// a is less than b if we can't get version for a but can for b.
return SUCCEEDED(hrB);
}

// Compare dates.
hrA = a->GetInstallDate(&ftDateA);
hrB = b->GetInstallDate(&ftDateB);
if (SUCCEEDED(hrA) && SUCCEEDED(hrB))
{
auto result = ::CompareFileTime(&ftDateA, &ftDateB);
if (0 == result)
{
auto message = ResourceManager::GetString(IDS_E_UNEXPECTEDDATE);
throw win32_error(E_UNEXPECTED, message);
}

return 0 > result;
}
else
{
// a is less than b if we can't get date for a but can for b.
return SUCCEEDED(hrB);
}
}

vector<ISetupInstancePtr> InstanceSelector::Select(_In_ IEnumSetupInstances* pEnum) const
{
_ASSERT(pEnum);
Expand All @@ -55,6 +113,19 @@ vector<ISetupInstancePtr> InstanceSelector::Select(_In_ IEnumSetupInstances* pEn
}
} while (SUCCEEDED(hr) && celtFetched);

if (m_args.get_Latest() && 1 < instances.size())
{
sort(instances.begin(), instances.end(), [&](const ISetupInstancePtr& a, const ISetupInstancePtr& b) -> bool
{
return Less(a, b);
});

return vector<ISetupInstancePtr>
{
instances.back(),
};
}

return instances;
}

Expand Down Expand Up @@ -168,8 +239,7 @@ bool InstanceSelector::IsVersionMatch(_In_ ISetupInstance* pInstance) const
{
_ASSERT(pInstance);

// m_helper will be NULL if no version range was specified or the interface was not yet implemented.
if (!m_helper)
if (!HasVersionRange())
{
return true;
}
Expand Down
6 changes: 5 additions & 1 deletion src/vswhere.lib/InstanceSelector.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class InstanceSelector
{
}

bool Less(const ISetupInstancePtr& a, const ISetupInstancePtr& b) const;
std::vector<ISetupInstancePtr> Select(_In_ IEnumSetupInstances* pEnum) const;

private:
Expand All @@ -25,8 +26,11 @@ class InstanceSelector
bool IsProductMatch(_In_ ISetupInstance2* pInstance) const;
bool IsWorkloadMatch(_In_ ISetupInstance2* pInstance) const;
bool IsVersionMatch(_In_ ISetupInstance* pInstance) const;
bool HasVersionRange() const
{
return m_ullMinimumVersion != 0 && m_ullMaximumVersion != 0;
}

static const ci_equal s_comparer;
const CommandArgs& m_args;
ULONGLONG m_ullMinimumVersion;
ULONGLONG m_ullMaximumVersion;
Expand Down
Binary file modified src/vswhere.lib/resource.h
Binary file not shown.
Binary file modified src/vswhere.lib/vswhere.lib.rc
Binary file not shown.
Loading

0 comments on commit 6d7a05a

Please sign in to comment.