Skip to content

Commit

Permalink
Optionally output packages (#201)
Browse files Browse the repository at this point in the history
Helps makes diagnostics for issues like #199 easier.
  • Loading branch information
heaths authored Sep 20, 2019
1 parent 180c706 commit aa4436e
Show file tree
Hide file tree
Showing 16 changed files with 562 additions and 6 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"editor.tabSize": 4,
"files.associations": {
"functional": "cpp",
"string": "cpp"
"string": "cpp",
"unordered_map": "cpp"
}
}
19 changes: 19 additions & 0 deletions src/vswhere.lib/CommandArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,25 @@ void CommandArgs::Parse(_In_ vector<CommandParser::Token> args)

m_property = ParseArgument(it, args.end(), arg);
}
else if (ArgumentEquals(arg.Value, L"include"))
{
vector<wstring> include;
ParseArgumentArray(it, args.end(), arg, include);

for (const auto& value : include)
{
if (ArgumentEquals(value, L"packages"))
{
m_includePackages = true;
}
else
{
auto message = ResourceManager::FormatString(IDS_E_UNSUPPORTEDARG, value.c_str(), L"include");
throw win32_error(ERROR_INVALID_PARAMETER, message);
}

}
}
else if (ArgumentEquals(arg.Value, L"find"))
{
if (m_property.length())
Expand Down
8 changes: 8 additions & 0 deletions src/vswhere.lib/CommandArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class CommandArgs
m_latest(false),
m_legacy(false),
m_prerelease(false),
m_includePackages(false),
m_nologo(false),
m_utf8(false),
m_help(false)
Expand All @@ -36,6 +37,7 @@ class CommandArgs
m_prerelease(obj.m_prerelease),
m_format(obj.m_format),
m_property(obj.m_property),
m_includePackages(obj.m_includePackages),
m_find(obj.m_find),
m_nologo(obj.m_nologo),
m_utf8(obj.m_utf8),
Expand Down Expand Up @@ -118,6 +120,11 @@ class CommandArgs
return m_property;
}

const bool get_IncludePackages() const noexcept
{
return m_includePackages;
}

const std::wstring& get_Find() const noexcept
{
return m_find;
Expand Down Expand Up @@ -163,6 +170,7 @@ class CommandArgs
bool m_prerelease;
std::wstring m_format;
std::wstring m_property;
bool m_includePackages;
std::wstring m_find;
bool m_nologo;
bool m_utf8;
Expand Down
85 changes: 85 additions & 0 deletions src/vswhere.lib/Formatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,11 +258,96 @@ void Formatter::WriteInternal(_In_ const CommandArgs& args, _In_ Console& consol
}
}
}

if (args.get_IncludePackages() && SupportsPackages())
{
if (specified.empty() || s_comparer(specified, L"packages"))
{
WritePackages(args, console, pInstance);
}
}
}

EndObject(console);
}

void Formatter::WritePackage(_In_ Console& console, _In_ ISetupPackageReference* pPackage)
{
StartObject(console, L"package");

bstr_t bstr;
auto hr = pPackage->GetId(bstr.GetAddress());
if (SUCCEEDED(hr))
{
WriteProperty(console, L"id", bstr);
}

hr = pPackage->GetVersion(bstr.GetAddress());
if (SUCCEEDED(hr) && bstr.length())
{
WriteProperty(console, L"version", bstr);
}

hr = pPackage->GetChip(bstr.GetAddress());
if (SUCCEEDED(hr) && bstr.length())
{
WriteProperty(console, L"chip", bstr);
}

hr = pPackage->GetLanguage(bstr.GetAddress());
if (SUCCEEDED(hr) && bstr.length())
{
WriteProperty(console, L"language", bstr);
}

hr = pPackage->GetBranch(bstr.GetAddress());
if (SUCCEEDED(hr) && bstr.length())
{
WriteProperty(console, L"branch", bstr);
}

hr = pPackage->GetType(bstr.GetAddress());
if (SUCCEEDED(hr))
{
WriteProperty(console, L"type", bstr);
}

VARIANT_BOOL vtBool;
hr = pPackage->GetIsExtension(&vtBool);
if (SUCCEEDED(hr) && VARIANT_TRUE == vtBool)
{
WriteProperty(console, L"extension", true);
}

EndObject(console);
}

void Formatter::WritePackages(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance)
{
ISetupInstance2Ptr instance2;
LPSAFEARRAY psaPackages;

auto hr = pInstance->QueryInterface(&instance2);
if (SUCCEEDED(hr))
{
hr = instance2->GetPackages(&psaPackages);
if (SUCCEEDED(hr) && psaPackages->rgsabound[0].cElements)
{
StartArray(console, L"packages");

SafeArray<ISetupPackageReference*> saPackages(psaPackages);
const auto packages = saPackages.Elements();

for (const auto& package : packages)
{
WritePackage(console, package);
}

EndArray(console);
}
}
}

void Formatter::WriteProperty(_In_ Console& console, _In_ const wstring& name, _In_ const variant_t& value)
{
switch (value.vt)
Expand Down
7 changes: 7 additions & 0 deletions src/vswhere.lib/Formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class Formatter
return true;
}

virtual bool SupportsPackages() const
{
return false;
}

protected:
typedef std::function<HRESULT(_In_ ISetupInstance*, _Out_ VARIANT*)> PropertyFunction;
typedef std::vector<std::pair<std::wstring, PropertyFunction>> PropertyArray;
Expand Down Expand Up @@ -82,6 +87,8 @@ class Formatter
HRESULT GetDescription(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtDescription);

void WriteInternal(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance);
void WritePackage(_In_ Console& console, _In_ ISetupPackageReference* pPackage);
void WritePackages(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance);
void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ const variant_t& value);
bool WriteProperties(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance);
bool WriteProperties(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupPropertyStore* pProperties, _In_opt_ const std::wstring& prefix = empty_wstring);
Expand Down
5 changes: 5 additions & 0 deletions src/vswhere.lib/JsonFormatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ class JsonFormatter :
return false;
}

bool SupportsPackages() const override
{
return true;
}

protected:
void StartArray(_In_ Console& console, _In_opt_ const std::wstring& name = empty_wstring) override;
void StartObject(_In_ Console& console, _In_opt_ const std::wstring& name = empty_wstring) override;
Expand Down
15 changes: 11 additions & 4 deletions src/vswhere.lib/JsonScope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,28 @@ void JsonScope::StartProperty(_In_ Console& console)

void JsonScope::WriteStartImpl(_In_ Console& console)
{
bool writeKey = false;

WriteSeparator(console);

// Write new line if not the root scope.
if (Parent())
{
if (Parent()->IsObject())
{
writeKey = true;
}

// Write new line if not the root scope.
console.WriteLine();
}

if (m_type == Type::array || Name().empty())
if (writeKey && Name().length())
{
console.Write(L"%ls%lc", Padding().c_str(), StartChar());
console.Write(L"%ls\"%ls\": %lc", Padding().c_str(), Name().c_str(), StartChar());
}
else
{
console.Write(L"%ls\"%ls\": %lc", Padding().c_str(), Name().c_str(), StartChar());
console.Write(L"%ls%lc", Padding().c_str(), StartChar());
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/vswhere.lib/JsonScope.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ class JsonScope :
{
}

bool IsArray() const noexcept
{
return m_type == Type::array;
}

bool IsObject() const noexcept
{
return m_type == Type::object;
Expand Down
5 changes: 5 additions & 0 deletions src/vswhere.lib/XmlFormatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ class XmlFormatter :
return false;
}

bool SupportsPackages() const override
{
return true;
}

protected:
void StartDocument(_In_ Console& console) override;
void StartArray(_In_ Console& console, _In_opt_ const std::wstring& name = empty_wstring) override;
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.
118 changes: 118 additions & 0 deletions test/vswhere.test/JsonFormatterTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -531,4 +531,122 @@ TEST_CLASS(JsonFormatterTests)
Assert::AreEqual(expected.c_str(), actual.c_str());
}
}

BEGIN_TEST_METHOD_ATTRIBUTE(Include_Packages)
TEST_WORKITEM(199)
END_TEST_METHOD_ATTRIBUTE()
TEST_METHOD(Include_Packages)
{
TestPackageReference product1 =
{
{ L"Id", L"Microsoft.VisualStudio.Product.Community" },
};

TestPackageReference a1 =
{
{ L"Id", L"A" },
{ L"Version", L"1.0" },
{ L"Type", L"Workload"},
};

TestPackageReference b1 =
{
{ L"Id", L"B" },
{ L"Version", L"1.0" },
{ L"Type", L"Component"},
};

vector<TestInstance::ElementType> packages1 = { &a1, &b1 };

TestInstance::MapType properties1 =
{
{ L"InstanceId", L"a1b2c3" },
{ L"InstallationName", L"test" },
};

TestInstance instance1(&product1, packages1, properties1);

TestPackageReference product2 =
{
{ L"Id", L"Microsoft.VisualStudio.Product.Enterprise" },
};

TestPackageReference a2 =
{
{ L"Id", L"A" },
{ L"Version", L"1.0" },
{ L"Type", L"Workload"},
};

TestPackageReference b2 =
{
{ L"Id", L"B" },
{ L"Version", L"1.0" },
{ L"Type", L"Component"},
};

vector<TestInstance::ElementType> packages2 = { &a2, &b2 };

TestInstance::MapType properties2 =
{
{ L"InstanceId", L"b1c2d3" },
{ L"InstallationName", L"test" },
};

TestInstance instance2(&product2, packages2, properties2);

vector<ISetupInstancePtr> instances =
{
&instance1,
&instance2,
};

CommandArgs args;
args.Parse(L"vswhere.exe -include packages");

TestConsole console(args);

JsonFormatter sut;
sut.Write(args, console, instances);

auto expected =
L"[\n"
L" {\n"
L" \"instanceId\": \"a1b2c3\",\n"
L" \"installationName\": \"test\",\n"
L" \"productId\": \"Microsoft.VisualStudio.Product.Community\",\n"
L" \"packages\": [\n"
L" {\n"
L" \"id\": \"A\",\n"
L" \"version\": \"1.0\",\n"
L" \"type\": \"Workload\"\n"
L" },\n"
L" {\n"
L" \"id\": \"B\",\n"
L" \"version\": \"1.0\",\n"
L" \"type\": \"Component\"\n"
L" }\n"
L" ]\n"
L" },\n"
L" {\n"
L" \"instanceId\": \"b1c2d3\",\n"
L" \"installationName\": \"test\",\n"
L" \"productId\": \"Microsoft.VisualStudio.Product.Enterprise\",\n"
L" \"packages\": [\n"
L" {\n"
L" \"id\": \"A\",\n"
L" \"version\": \"1.0\",\n"
L" \"type\": \"Workload\"\n"
L" },\n"
L" {\n"
L" \"id\": \"B\",\n"
L" \"version\": \"1.0\",\n"
L" \"type\": \"Component\"\n"
L" }\n"
L" ]\n"
L" }\n"
L"]\n";

Assert::AreEqual(expected, console);
}
};
Loading

0 comments on commit aa4436e

Please sign in to comment.