Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for 1.9 manifest in rest source parsing and winget utils interop #4906

Merged
merged 2 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@
<ClCompile Include="RestInterface_1_5.cpp" />
<ClCompile Include="RestInterface_1_6.cpp" />
<ClCompile Include="RestInterface_1_7.cpp" />
<ClCompile Include="RestInterface_1_9.cpp" />
<ClCompile Include="ResumeFlow.cpp" />
<ClCompile Include="Runtime.cpp" />
<ClCompile Include="SearchRequestSerializer.cpp" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,9 @@
<ClCompile Include="Sixel.cpp">
<Filter>Source Files\CLI</Filter>
</ClCompile>
<ClCompile Include="RestInterface_1_9.cpp">
<Filter>Source Files\Repository</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
Expand Down
2 changes: 1 addition & 1 deletion src/AppInstallerCLITests/RestClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ TEST_CASE("GetSupportedInterface", "[RestSource]")
REQUIRE(RestClient::GetSupportedInterface(TestRestUri, {}, info, {}, version, {})->GetVersion() == version);

// Update this test to next version so that we don't forget to add to supported versions before rest e2e tests are available.
Version invalid{ "1.8.0" };
Version invalid{ "1.10.0" };
REQUIRE_THROWS_HR(RestClient::GetSupportedInterface(TestRestUri, {}, info, {}, invalid, {}), APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_VERSION);

Authentication::AuthenticationArguments authArgs;
Expand Down
400 changes: 400 additions & 0 deletions src/AppInstallerCLITests/RestInterface_1_9.cpp

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions src/AppInstallerCLITests/YamlManifest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,37 @@ TEST_CASE("WriteV1_7SingletonManifestAndVerifyContents", "[ManifestCreation]")
VerifyV1ManifestContent(generatedMultiFileManifest, false, ManifestVer{ s_ManifestVersionV1_7 }, true);
}

TEST_CASE("WriteV1_9SingletonManifestAndVerifyContents", "[ManifestCreation]")
{
TempDirectory singletonDirectory{ "SingletonManifest" };
CopyTestDataFilesToFolder({ "ManifestV1_9-Singleton.yaml" }, singletonDirectory);
Manifest singletonManifest = YamlParser::CreateFromPath(singletonDirectory);

TempDirectory exportedSingletonDirectory{ "exportedSingleton" };
std::filesystem::path generatedSingletonManifestPath = exportedSingletonDirectory.GetPath() / "testSingletonManifest.yaml";
YamlWriter::OutputYamlFile(singletonManifest, singletonManifest.Installers[0], generatedSingletonManifestPath);

REQUIRE(std::filesystem::exists(generatedSingletonManifestPath));
Manifest generatedSingletonManifest = YamlParser::CreateFromPath(exportedSingletonDirectory);
VerifyV1ManifestContent(generatedSingletonManifest, true, ManifestVer{ s_ManifestVersionV1_9 }, true);

TempDirectory multiFileDirectory{ "MultiFileManifest" };
CopyTestDataFilesToFolder({
"ManifestV1_9-MultiFile-Version.yaml",
"ManifestV1_9-MultiFile-Installer.yaml",
"ManifestV1_9-MultiFile-DefaultLocale.yaml",
"ManifestV1_9-MultiFile-Locale.yaml" }, multiFileDirectory);

Manifest multiFileManifest = YamlParser::CreateFromPath(multiFileDirectory);
TempDirectory exportedMultiFileDirectory{ "exportedMultiFile" };
std::filesystem::path generatedMultiFileManifestPath = exportedMultiFileDirectory.GetPath() / "testMultiFileManifest.yaml";
YamlWriter::OutputYamlFile(multiFileManifest, multiFileManifest.Installers[0], generatedMultiFileManifestPath);

REQUIRE(std::filesystem::exists(generatedMultiFileManifestPath));
Manifest generatedMultiFileManifest = YamlParser::CreateFromPath(exportedMultiFileDirectory);
VerifyV1ManifestContent(generatedMultiFileManifest, false, ManifestVer{ s_ManifestVersionV1_9 }, true);
}

TEST_CASE("WriteManifestWithMultipleLocale", "[ManifestCreation]")
{
Manifest multiLocaleManifest = YamlParser::CreateFromPath(TestDataFile("Manifest-Good-MultiLocale.yaml"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,8 @@
<ClInclude Include="Rest\Schema\1_6\Json\ManifestDeserializer.h" />
<ClInclude Include="Rest\Schema\1_7\Interface.h" />
<ClInclude Include="Rest\Schema\1_7\Json\ManifestDeserializer.h" />
<ClInclude Include="Rest\Schema\1_9\Interface.h" />
<ClInclude Include="Rest\Schema\1_9\Json\ManifestDeserializer.h" />
<ClInclude Include="Rest\Schema\AuthenticationInfoParser.h" />
<ClInclude Include="Rest\Schema\CommonRestConstants.h" />
<ClInclude Include="Rest\Schema\InformationResponseDeserializer.h" />
Expand Down Expand Up @@ -544,6 +546,8 @@
<ClCompile Include="Rest\Schema\1_6\RestInterface_1_6.cpp" />
<ClCompile Include="Rest\Schema\1_7\Json\ManifestDeserializer_1_7.cpp" />
<ClCompile Include="Rest\Schema\1_7\RestInterface_1_7.cpp" />
<ClCompile Include="Rest\Schema\1_9\Json\ManifestDeserializer_1_9.cpp" />
<ClCompile Include="Rest\Schema\1_9\RestInterface_1_9.cpp" />
<ClCompile Include="Rest\Schema\AuthenticationInfoParser.cpp" />
<ClCompile Include="Rest\Schema\InformationResponseDeserializer.cpp" />
<ClCompile Include="Rest\Schema\SearchRequestComposer.cpp" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@
<Filter Include="Microsoft\Schema\2_0">
<UniqueIdentifier>{34442899-29e5-4183-96ba-a1e8740146be}</UniqueIdentifier>
</Filter>
<Filter Include="Rest\Schema\1_9">
<UniqueIdentifier>{8edd7018-8836-4b15-84c1-998391e19038}</UniqueIdentifier>
</Filter>
<Filter Include="Rest\Schema\1_9\Json">
<UniqueIdentifier>{7464e3ff-7a60-4bb6-8806-70562382043b}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
Expand Down Expand Up @@ -462,6 +468,12 @@
<ClInclude Include="Microsoft\SQLiteIndexSourceV2.h">
<Filter>Microsoft</Filter>
</ClInclude>
<ClInclude Include="Rest\Schema\1_9\Json\ManifestDeserializer.h">
<Filter>Rest\Schema\1_9\Json</Filter>
</ClInclude>
<ClInclude Include="Rest\Schema\1_9\Interface.h">
<Filter>Rest\Schema\1_9</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
Expand Down Expand Up @@ -722,6 +734,12 @@
<ClCompile Include="Microsoft\SQLiteIndexSourceV2.cpp">
<Filter>Microsoft</Filter>
</ClCompile>
<ClCompile Include="Rest\Schema\1_9\Json\ManifestDeserializer_1_9.cpp">
<Filter>Rest\Schema\1_9\Json</Filter>
</ClCompile>
<ClCompile Include="Rest\Schema\1_9\RestInterface_1_9.cpp">
<Filter>Rest\Schema\1_9</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
Expand Down
7 changes: 6 additions & 1 deletion src/AppInstallerRepositoryCore/ManifestJSONParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "Rest/Schema/1_5/Json/ManifestDeserializer.h"
#include "Rest/Schema/1_6/Json/ManifestDeserializer.h"
#include "Rest/Schema/1_7/Json/ManifestDeserializer.h"
#include "Rest/Schema/1_9/Json/ManifestDeserializer.h"

namespace AppInstaller::Repository::JSON
{
Expand Down Expand Up @@ -46,10 +47,14 @@ namespace AppInstaller::Repository::JSON
{
m_pImpl->m_deserializer = std::make_unique<Rest::Schema::V1_6::Json::ManifestDeserializer>();
}
else
else if (parts.size() > 1 && parts[1].Integer < 9)
{
m_pImpl->m_deserializer = std::make_unique<Rest::Schema::V1_7::Json::ManifestDeserializer>();
}
else
{
m_pImpl->m_deserializer = std::make_unique<Rest::Schema::V1_9::Json::ManifestDeserializer>();
}
}
else
{
Expand Down
7 changes: 6 additions & 1 deletion src/AppInstallerRepositoryCore/Rest/RestClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "Rest/Schema/1_5/Interface.h"
#include "Rest/Schema/1_6/Interface.h"
#include "Rest/Schema/1_7/Interface.h"
#include "Rest/Schema/1_9/Interface.h"
#include "Rest/Schema/InformationResponseDeserializer.h"
#include "Rest/Schema/CommonRestConstants.h"
#include <winget/HttpClientHelper.h>
Expand All @@ -22,7 +23,7 @@ using namespace AppInstaller::Http;
namespace AppInstaller::Repository::Rest
{
// Supported versions
std::set<Version> WingetSupportedContracts = { Version_1_0_0, Version_1_1_0, Version_1_4_0, Version_1_5_0, Version_1_6_0, Version_1_7_0 };
std::set<Version> WingetSupportedContracts = { Version_1_0_0, Version_1_1_0, Version_1_4_0, Version_1_5_0, Version_1_6_0, Version_1_7_0, Version_1_9_0 };

constexpr std::string_view WindowsPackageManagerHeader = "Windows-Package-Manager"sv;
constexpr size_t WindowsPackageManagerHeaderMaxLength = 1024;
Expand Down Expand Up @@ -176,6 +177,10 @@ namespace AppInstaller::Repository::Rest
{
return std::make_unique<Schema::V1_7::Interface>(api, helper, information, additionalHeaders, authArgs);
}
else if (version == Version_1_9_0)
{
return std::make_unique<Schema::V1_9::Interface>(api, helper, information, additionalHeaders, authArgs);
}

THROW_HR(APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_VERSION);
}
Expand Down
21 changes: 21 additions & 0 deletions src/AppInstallerRepositoryCore/Rest/Schema/1_9/Interface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include "Rest/Schema/1_7/Interface.h"

namespace AppInstaller::Repository::Rest::Schema::V1_9
{
// Interface to this schema version exposed through IRestClient.
struct Interface : public V1_7::Interface
{
Interface(const std::string& restApi, const Http::HttpClientHelper& helper, IRestClient::Information information, const Http::HttpClientHelper::HttpRequestHeaders& additionalHeaders = {}, Authentication::AuthenticationArguments authArgs = {});

Interface(const Interface&) = delete;
Interface& operator=(const Interface&) = delete;

Interface(Interface&&) = default;
Interface& operator=(Interface&&) = default;

Utility::Version GetVersion() const override;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include "Rest/Schema/1_7/Json/ManifestDeserializer.h"

namespace AppInstaller::Repository::Rest::Schema::V1_9::Json
{
// Manifest Deserializer.
struct ManifestDeserializer : public V1_7::Json::ManifestDeserializer
{
protected:

std::optional<Manifest::ManifestInstaller> DeserializeInstaller(const web::json::value& installerJsonObject) const override;

Manifest::ManifestVer GetManifestVersion() const override;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "ManifestDeserializer.h"
#include <winget/JsonUtil.h>

using namespace AppInstaller::Manifest;

namespace AppInstaller::Repository::Rest::Schema::V1_9::Json
{
namespace
{
// Installer
constexpr std::string_view ArchiveBinariesDependOnPath = "ArchiveBinariesDependOnPath"sv;
}

std::optional<Manifest::ManifestInstaller> ManifestDeserializer::DeserializeInstaller(const web::json::value& installerJsonObject) const
{
auto result = V1_7::Json::ManifestDeserializer::DeserializeInstaller(installerJsonObject);

if (result)
{
auto& installer = result.value();

installer.ArchiveBinariesDependOnPath = JSON::GetRawBoolValueFromJsonNode(installerJsonObject, JSON::GetUtilityString(ArchiveBinariesDependOnPath)).value_or(false);
}

return result;
}

Manifest::ManifestVer ManifestDeserializer::GetManifestVersion() const
{
return Manifest::s_ManifestVersionV1_9;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "Rest/Schema/1_9/Interface.h"
#include "Rest/Schema/CommonRestConstants.h"
#include "Rest/Schema/IRestClient.h"
#include <winget/HttpClientHelper.h>
#include <winget/JsonUtil.h>

namespace AppInstaller::Repository::Rest::Schema::V1_9
{
Interface::Interface(
const std::string& restApi,
const Http::HttpClientHelper& httpClientHelper,
IRestClient::Information information,
const Http::HttpClientHelper::HttpRequestHeaders& additionalHeaders,
Authentication::AuthenticationArguments authArgs) : V1_7::Interface(restApi, httpClientHelper, std::move(information), additionalHeaders, std::move(authArgs))
{
m_requiredRestApiHeaders[JSON::GetUtilityString(ContractVersion)] = JSON::GetUtilityString(Version_1_9_0.ToString());
}

Utility::Version Interface::GetVersion() const
{
return Version_1_9_0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace AppInstaller::Repository::Rest::Schema
const Utility::Version Version_1_5_0{ "1.5.0" };
const Utility::Version Version_1_6_0{ "1.6.0" };
const Utility::Version Version_1_7_0{ "1.7.0" };
const Utility::Version Version_1_9_0{ "1.9.0" };

// General API response constants
constexpr std::string_view Data = "Data"sv;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// <copyright file="V1ManifestReadTest.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
// </copyright>
Expand Down Expand Up @@ -35,6 +35,7 @@ private enum TestManifestVersion
V110,
V160,
V170,
V190,
}

/// <summary>
Expand Down Expand Up @@ -63,6 +64,11 @@ public void ReadV1ManifestsAndVerifyContents()
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "TestCollateral", ManifestStrings.V170ManifestMerged));

this.ValidateManifestFields(v170manifest, TestManifestVersion.V170);

Manifest v190manifest = Manifest.CreateManifestFromPath(
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "TestCollateral", ManifestStrings.V190ManifestMerged));

this.ValidateManifestFields(v190manifest, TestManifestVersion.V190);
}

/// <summary>
Expand Down Expand Up @@ -266,6 +272,11 @@ private void ValidateManifestFields(Manifest manifest, TestManifestVersion manif
Assert.Equal("uninstaller", manifest.RepairBehavior);
}

if (manifestVersion >= TestManifestVersion.V190)
{
Assert.True(manifest.ArchiveBinariesDependOnPath);
}

// Individual installers
Assert.Equal(2, manifest.Installers.Count);
ManifestInstaller installer1 = manifest.Installers[0];
Expand Down Expand Up @@ -370,6 +381,11 @@ private void ValidateManifestFields(Manifest manifest, TestManifestVersion manif
Assert.Equal("modify", installer1.RepairBehavior);
}

if (manifestVersion >= TestManifestVersion.V190)
{
Assert.False(installer1.ArchiveBinariesDependOnPath);
}

// Additional Localizations
Assert.Single(manifest.Localization);
ManifestLocalization localization1 = manifest.Localization[0];
Expand Down Expand Up @@ -448,6 +464,11 @@ internal class ManifestStrings
/// </summary>
public const string V170ManifestMerged = "V1_7ManifestMerged.yaml";

/// <summary>
/// Merged v1.9 manifest.
/// </summary>
public const string V190ManifestMerged = "V1_9ManifestMerged.yaml";

/// <summary>
/// Merged v1 manifest without localization.
/// </summary>
Expand Down
Loading
Loading