Skip to content

Commit

Permalink
Add support for 1.9 manifest in rest source parsing and winget utils …
Browse files Browse the repository at this point in the history
…interop (#4906)
  • Loading branch information
yao-msft authored and ryfu-msft committed Oct 25, 2024
1 parent 874acff commit ede0074
Show file tree
Hide file tree
Showing 19 changed files with 861 additions and 9 deletions.
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
3 changes: 3 additions & 0 deletions src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
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

0 comments on commit ede0074

Please sign in to comment.