From ede0074a9a1d0bbc2f5067c52b6a12b543d9cd3f Mon Sep 17 00:00:00 2001
From: yao-msft <50888816+yao-msft@users.noreply.github.com>
Date: Fri, 25 Oct 2024 13:16:09 -0700
Subject: [PATCH] Add support for 1.9 manifest in rest source parsing and
winget utils interop (#4906)
---
.../AppInstallerCLITests.vcxproj | 1 +
.../AppInstallerCLITests.vcxproj.filters | 3 +
src/AppInstallerCLITests/RestClient.cpp | 2 +-
.../RestInterface_1_9.cpp | 400 ++++++++++++++++++
src/AppInstallerCLITests/YamlManifest.cpp | 31 ++
.../AppInstallerRepositoryCore.vcxproj | 4 +
...AppInstallerRepositoryCore.vcxproj.filters | 18 +
.../ManifestJSONParser.cpp | 7 +-
.../Rest/RestClient.cpp | 7 +-
.../Rest/Schema/1_9/Interface.h | 21 +
.../Schema/1_9/Json/ManifestDeserializer.h | 17 +
.../1_9/Json/ManifestDeserializer_1_9.cpp | 35 ++
.../Rest/Schema/1_9/RestInterface_1_9.cpp | 26 ++
.../Rest/Schema/CommonRestConstants.h | 1 +
.../ManifestUnitTest/V1ManifestReadTest.cs | 23 +-
.../TestCollateral/V1_9ManifestMerged.yaml | 251 +++++++++++
.../WinGetUtilInterop.UnitTests.csproj | 5 +-
src/WinGetUtilInterop/Manifest/V1/Manifest.cs | 9 +-
.../Manifest/V1/ManifestInstaller.cs | 9 +-
19 files changed, 861 insertions(+), 9 deletions(-)
create mode 100644 src/AppInstallerCLITests/RestInterface_1_9.cpp
create mode 100644 src/AppInstallerRepositoryCore/Rest/Schema/1_9/Interface.h
create mode 100644 src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer.h
create mode 100644 src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer_1_9.cpp
create mode 100644 src/AppInstallerRepositoryCore/Rest/Schema/1_9/RestInterface_1_9.cpp
create mode 100644 src/WinGetUtilInterop.UnitTests/TestCollateral/V1_9ManifestMerged.yaml
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
index 9b0e2e2853..043eab3f5a 100644
--- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
+++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
@@ -322,6 +322,7 @@
+
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
index 2bbcd74516..a24784a802 100644
--- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
+++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
@@ -365,6 +365,9 @@
Source Files\CLI
+
+ Source Files\Repository
+
diff --git a/src/AppInstallerCLITests/RestClient.cpp b/src/AppInstallerCLITests/RestClient.cpp
index a45a9e2eba..a864454f76 100644
--- a/src/AppInstallerCLITests/RestClient.cpp
+++ b/src/AppInstallerCLITests/RestClient.cpp
@@ -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;
diff --git a/src/AppInstallerCLITests/RestInterface_1_9.cpp b/src/AppInstallerCLITests/RestInterface_1_9.cpp
new file mode 100644
index 0000000000..e33480dd19
--- /dev/null
+++ b/src/AppInstallerCLITests/RestInterface_1_9.cpp
@@ -0,0 +1,400 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "TestCommon.h"
+#include "TestRestRequestHandler.h"
+#include
+#include
+#include
+#include
+
+using namespace TestCommon;
+using namespace AppInstaller::Http;
+using namespace AppInstaller::Utility;
+using namespace AppInstaller::Manifest;
+using namespace AppInstaller::Repository;
+using namespace AppInstaller::Repository::Rest;
+using namespace AppInstaller::Repository::Rest::Schema;
+using namespace AppInstaller::Repository::Rest::Schema::V1_9;
+
+namespace
+{
+ const std::string TestRestUriString = "http://restsource.com/api";
+
+ struct GoodManifest_AllFields
+ {
+ utility::string_t GetSampleManifest_AllFields()
+ {
+ return _XPLATSTR(
+ R"delimiter(
+ {
+ "Data": {
+ "PackageIdentifier": "Foo.Bar",
+ "Versions": [
+ {
+ "PackageVersion": "3.0.0abc",
+ "DefaultLocale": {
+ "PackageLocale": "en-US",
+ "Publisher": "Foo",
+ "PublisherUrl": "http://publisher.net",
+ "PublisherSupportUrl": "http://publisherSupport.net",
+ "PrivacyUrl": "http://packagePrivacyUrl.net",
+ "Author": "FooBar",
+ "PackageName": "Bar",
+ "PackageUrl": "http://packageUrl.net",
+ "License": "Foo Bar License",
+ "LicenseUrl": "http://licenseUrl.net",
+ "Copyright": "Foo Bar Copyright",
+ "CopyrightUrl": "http://copyrightUrl.net",
+ "ShortDescription": "Foo bar is a foo bar.",
+ "Description": "Foo bar is a placeholder.",
+ "Tags": [
+ "FooBar",
+ "Foo",
+ "Bar"
+ ],
+ "Moniker": "FooBarMoniker",
+ "ReleaseNotes": "Default release notes",
+ "ReleaseNotesUrl": "https://DefaultReleaseNotes.net",
+ "Agreements": [{
+ "AgreementLabel": "DefaultLabel",
+ "Agreement": "DefaultText",
+ "AgreementUrl": "https://DefaultAgreementUrl.net"
+ }],
+ "PurchaseUrl": "http://DefaultPurchaseUrl.net",
+ "InstallationNotes": "Default Installation Notes",
+ "Documentations": [{
+ "DocumentLabel": "Default Document Label",
+ "DocumentUrl": "http://DefaultDocumentUrl.net"
+ }],
+ "Icons": [{
+ "IconUrl": "https://DefaultTestIcon",
+ "IconFileType": "ico",
+ "IconResolution": "custom",
+ "IconTheme": "default",
+ "IconSha256": "69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8123"
+ }]
+ },
+ "Channel": "",
+ "Locales": [
+ {
+ "PackageLocale": "fr-Fr",
+ "Publisher": "Foo French",
+ "PublisherUrl": "http://publisher-fr.net",
+ "PublisherSupportUrl": "http://publisherSupport-fr.net",
+ "PrivacyUrl": "http://packagePrivacyUrl-fr.net",
+ "Author": "FooBar French",
+ "PackageName": "Bar",
+ "PackageUrl": "http://packageUrl-fr.net",
+ "License": "Foo Bar License",
+ "LicenseUrl": "http://licenseUrl-fr.net",
+ "Copyright": "Foo Bar Copyright",
+ "CopyrightUrl": "http://copyrightUrl-fr.net",
+ "ShortDescription": "Foo bar is a foo bar French.",
+ "Description": "Foo bar is a placeholder French.",
+ "Tags": [
+ "FooBarFr",
+ "FooFr",
+ "BarFr"
+ ],
+ "ReleaseNotes": "Release notes",
+ "ReleaseNotesUrl": "https://ReleaseNotes.net",
+ "Agreements": [{
+ "AgreementLabel": "Label",
+ "Agreement": "Text",
+ "AgreementUrl": "https://AgreementUrl.net"
+ }],
+ "PurchaseUrl": "http://purchaseUrl.net",
+ "InstallationNotes": "Installation Notes",
+ "Documentations": [{
+ "DocumentLabel": "Document Label",
+ "DocumentUrl": "http://documentUrl.net"
+ }],
+ "Icons": [{
+ "IconUrl": "https://testIcon",
+ "IconFileType": "png",
+ "IconResolution": "32x32",
+ "IconTheme": "light",
+ "IconSha256": "69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8321"
+ }]
+ }
+ ],)delimiter") _XPLATSTR(R"delimiter(
+ "Installers": [
+ {
+ "InstallerSha256": "011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6",
+ "InstallerUrl": "http://foobar.zip",
+ "Architecture": "x86",
+ "InstallerLocale": "en-US",
+ "Platform": [
+ "Windows.Desktop"
+ ],
+ "MinimumOSVersion": "1078",
+ "InstallerType": "zip",
+ "Scope": "user",
+ "InstallModes": [
+ "interactive"
+ ],
+ "InstallerSwitches": {
+ "Silent": "/s",
+ "SilentWithProgress": "/s",
+ "Interactive": "/i",
+ "InstallLocation": "C:\\Users\\User1",
+ "Log": "/l",
+ "Upgrade": "/u",
+ "Custom": "/custom",
+ "Repair": "/repair"
+ },
+ "InstallerSuccessCodes": [
+ 0
+ ],
+ "UpgradeBehavior": "deny",
+ "Commands": [
+ "command1"
+ ],
+ "Protocols": [
+ "protocol1"
+ ],
+ "FileExtensions": [
+ ".file-extension"
+ ],
+ "Dependencies": {
+ "WindowsFeatures": [
+ "feature1"
+ ],
+ "WindowsLibraries": [
+ "library1"
+ ],
+ "PackageDependencies": [
+ {
+ "PackageIdentifier": "Foo.Baz",
+ "MinimumVersion": "2.0.0"
+ }
+ ],
+ "ExternalDependencies": [
+ "FooBarBaz"
+ ]
+ },
+ "ProductCode": "5b6e0f8a-3bbf-4a17-aefd-024c2b3e075d",
+ "ReleaseDate": "2021-01-01",
+ "InstallerAbortsTerminal": true,
+ "InstallLocationRequired": true,
+ "RequireExplicitUpgrade": true,
+ "UnsupportedOSArchitectures": [ "arm" ],
+ "ElevationRequirement": "elevatesSelf",
+ "AppsAndFeaturesEntries": [{
+ "DisplayName": "DisplayName",
+ "DisplayVersion": "DisplayVersion",
+ "Publisher": "Publisher",
+ "ProductCode": "ProductCode",
+ "UpgradeCode": "UpgradeCode",
+ "InstallerType": "exe"
+ }],
+ "Markets" : {
+ "AllowedMarkets": [ "US" ]
+ },
+ "ExpectedReturnCodes": [{
+ "InstallerReturnCode": 3,
+ "ReturnResponse": "custom",
+ "ReturnResponseUrl": "http://returnResponseUrl.net"
+ }],
+ "NestedInstallerType": "portable",
+ "DisplayInstallWarnings": true,
+ "UnsupportedArguments": [ "log" ],
+ "NestedInstallerFiles": [{
+ "RelativeFilePath": "test\\app.exe",
+ "PortableCommandAlias": "test.exe"
+ }],
+ "InstallationMetadata": {
+ "DefaultInstallLocation": "%TEMP%\\DefaultInstallLocation",
+ "Files": [{
+ "RelativeFilePath": "test\\app.exe",
+ "FileSha256": "011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6",
+ "FileType": "launch",
+ "InvocationParameter": "/parameter",
+ "DisplayName": "test"
+ }]
+ },
+ "DownloadCommandProhibited": true,
+ "RepairBehavior": "uninstaller",
+ "ArchiveBinariesDependOnPath": true
+ }
+ ]
+ }
+ ]
+ },
+ "ContinuationToken": "abcd"
+ })delimiter");
+ }
+
+ void VerifyLocalizations_AllFields(const AppInstaller::Manifest::Manifest& manifest)
+ {
+ REQUIRE(manifest.DefaultLocalization.Locale == "en-US");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Foo");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://publisher.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://publisherSupport.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://packagePrivacyUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "FooBar");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Bar");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://packageUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Foo Bar License");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://licenseUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Foo Bar Copyright");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://copyrightUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Foo bar is a foo bar.");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Foo bar is a placeholder.");
+ REQUIRE(manifest.DefaultLocalization.Get().size() == 3);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0) == "FooBar");
+ REQUIRE(manifest.DefaultLocalization.Get().at(1) == "Foo");
+ REQUIRE(manifest.DefaultLocalization.Get().at(2) == "Bar");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Default release notes");
+ REQUIRE(manifest.DefaultLocalization.Get() == "https://DefaultReleaseNotes.net");
+ REQUIRE(manifest.DefaultLocalization.Get().size() == 1);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).Label == "DefaultLabel");
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).AgreementText == "DefaultText");
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).AgreementUrl == "https://DefaultAgreementUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "http://DefaultPurchaseUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get() == "Default Installation Notes");
+ REQUIRE(manifest.DefaultLocalization.Get().size() == 1);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).DocumentLabel == "Default Document Label");
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).DocumentUrl == "http://DefaultDocumentUrl.net");
+ REQUIRE(manifest.DefaultLocalization.Get().size() == 1);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).Url == "https://DefaultTestIcon");
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).FileType == IconFileTypeEnum::Ico);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).Resolution == IconResolutionEnum::Custom);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).Theme == IconThemeEnum::Default);
+ REQUIRE(manifest.DefaultLocalization.Get().at(0).Sha256 == AppInstaller::Utility::SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8123"));
+
+ REQUIRE(manifest.Localizations.size() == 1);
+ ManifestLocalization frenchLocalization = manifest.Localizations.at(0);
+ REQUIRE(frenchLocalization.Locale == "fr-Fr");
+ REQUIRE(frenchLocalization.Get() == "Foo French");
+ REQUIRE(frenchLocalization.Get() == "http://publisher-fr.net");
+ REQUIRE(frenchLocalization.Get() == "http://publisherSupport-fr.net");
+ REQUIRE(frenchLocalization.Get() == "http://packagePrivacyUrl-fr.net");
+ REQUIRE(frenchLocalization.Get() == "FooBar French");
+ REQUIRE(frenchLocalization.Get() == "Bar");
+ REQUIRE(frenchLocalization.Get() == "http://packageUrl-fr.net");
+ REQUIRE(frenchLocalization.Get() == "Foo Bar License");
+ REQUIRE(frenchLocalization.Get() == "http://licenseUrl-fr.net");
+ REQUIRE(frenchLocalization.Get() == "Foo Bar Copyright");
+ REQUIRE(frenchLocalization.Get() == "http://copyrightUrl-fr.net");
+ REQUIRE(frenchLocalization.Get() == "Foo bar is a foo bar French.");
+ REQUIRE(frenchLocalization.Get() == "Foo bar is a placeholder French.");
+ REQUIRE(frenchLocalization.Get().size() == 3);
+ REQUIRE(frenchLocalization.Get().at(0) == "FooBarFr");
+ REQUIRE(frenchLocalization.Get().at(1) == "FooFr");
+ REQUIRE(frenchLocalization.Get().at(2) == "BarFr");
+ REQUIRE(frenchLocalization.Get() == "Release notes");
+ REQUIRE(frenchLocalization.Get() == "https://ReleaseNotes.net");
+ REQUIRE(frenchLocalization.Get().size() == 1);
+ REQUIRE(frenchLocalization.Get().at(0).Label == "Label");
+ REQUIRE(frenchLocalization.Get().at(0).AgreementText == "Text");
+ REQUIRE(frenchLocalization.Get().at(0).AgreementUrl == "https://AgreementUrl.net");
+ REQUIRE(frenchLocalization.Get() == "http://purchaseUrl.net");
+ REQUIRE(frenchLocalization.Get() == "Installation Notes");
+ REQUIRE(frenchLocalization.Get().size() == 1);
+ REQUIRE(frenchLocalization.Get().at(0).DocumentLabel == "Document Label");
+ REQUIRE(frenchLocalization.Get().at(0).DocumentUrl == "http://documentUrl.net");
+ REQUIRE(frenchLocalization.Get().size() == 1);
+ REQUIRE(frenchLocalization.Get().at(0).Url == "https://testIcon");
+ REQUIRE(frenchLocalization.Get().at(0).FileType == IconFileTypeEnum::Png);
+ REQUIRE(frenchLocalization.Get().at(0).Resolution == IconResolutionEnum::Square32);
+ REQUIRE(frenchLocalization.Get().at(0).Theme == IconThemeEnum::Light);
+ REQUIRE(frenchLocalization.Get().at(0).Sha256 == AppInstaller::Utility::SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8321"));
+ }
+
+ void VerifyInstallers_AllFields(const AppInstaller::Manifest::Manifest& manifest)
+ {
+ REQUIRE(manifest.Installers.size() == 1);
+
+ ManifestInstaller actualInstaller = manifest.Installers.at(0);
+ REQUIRE(actualInstaller.Sha256 == AppInstaller::Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6"));
+ REQUIRE(actualInstaller.Url == "http://foobar.zip");
+ REQUIRE(actualInstaller.Arch == Architecture::X86);
+ REQUIRE(actualInstaller.Locale == "en-US");
+ REQUIRE(actualInstaller.Platform.size() == 1);
+ REQUIRE(actualInstaller.Platform[0] == PlatformEnum::Desktop);
+ REQUIRE(actualInstaller.MinOSVersion == "1078");
+ REQUIRE(actualInstaller.BaseInstallerType == InstallerTypeEnum::Zip);
+ REQUIRE(actualInstaller.Scope == ScopeEnum::User);
+ REQUIRE(actualInstaller.InstallModes.size() == 1);
+ REQUIRE(actualInstaller.InstallModes.at(0) == InstallModeEnum::Interactive);
+ REQUIRE(actualInstaller.Switches.size() == 8);
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Silent) == "/s");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::SilentWithProgress) == "/s");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Interactive) == "/i");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::InstallLocation) == "C:\\Users\\User1");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Log) == "/l");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Update) == "/u");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Custom) == "/custom");
+ REQUIRE(actualInstaller.Switches.at(InstallerSwitchType::Repair) == "/repair");
+ REQUIRE(actualInstaller.InstallerSuccessCodes.size() == 1);
+ REQUIRE(actualInstaller.InstallerSuccessCodes.at(0) == 0);
+ REQUIRE(actualInstaller.UpdateBehavior == UpdateBehaviorEnum::Deny);
+ REQUIRE(actualInstaller.Commands.at(0) == "command1");
+ REQUIRE(actualInstaller.Protocols.at(0) == "protocol1");
+ REQUIRE(actualInstaller.FileExtensions.at(0) == ".file-extension");
+ REQUIRE(actualInstaller.Dependencies.HasExactDependency(DependencyType::WindowsFeature, "feature1"));
+ REQUIRE(actualInstaller.Dependencies.HasExactDependency(DependencyType::WindowsLibrary, "library1"));
+ REQUIRE(actualInstaller.Dependencies.HasExactDependency(DependencyType::Package, "Foo.Baz", "2.0.0"));
+ REQUIRE(actualInstaller.Dependencies.HasExactDependency(DependencyType::External, "FooBarBaz"));
+ REQUIRE(actualInstaller.PackageFamilyName == "");
+ REQUIRE(actualInstaller.ProductCode == "5b6e0f8a-3bbf-4a17-aefd-024c2b3e075d");
+ REQUIRE(actualInstaller.ReleaseDate == "2021-01-01");
+ REQUIRE(actualInstaller.InstallerAbortsTerminal);
+ REQUIRE(actualInstaller.InstallLocationRequired);
+ REQUIRE(actualInstaller.RequireExplicitUpgrade);
+ REQUIRE(actualInstaller.ElevationRequirement == ElevationRequirementEnum::ElevatesSelf);
+ REQUIRE(actualInstaller.UnsupportedOSArchitectures.size() == 1);
+ REQUIRE(actualInstaller.UnsupportedOSArchitectures.at(0) == Architecture::Arm);
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.size() == 1);
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).DisplayName == "DisplayName");
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).DisplayVersion == "DisplayVersion");
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).Publisher == "Publisher");
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).ProductCode == "ProductCode");
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).UpgradeCode == "UpgradeCode");
+ REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).InstallerType == InstallerTypeEnum::Exe);
+ REQUIRE(actualInstaller.Markets.AllowedMarkets.size() == 1);
+ REQUIRE(actualInstaller.Markets.AllowedMarkets.at(0) == "US");
+ REQUIRE(actualInstaller.ExpectedReturnCodes.at(3).ReturnResponseEnum == ExpectedReturnCodeEnum::Custom);
+ REQUIRE(actualInstaller.ExpectedReturnCodes.at(3).ReturnResponseUrl == "http://returnResponseUrl.net");
+ REQUIRE(actualInstaller.NestedInstallerType == InstallerTypeEnum::Portable);
+ REQUIRE(actualInstaller.DisplayInstallWarnings);
+ REQUIRE(actualInstaller.UnsupportedArguments.size() == 1);
+ REQUIRE(actualInstaller.UnsupportedArguments.at(0) == UnsupportedArgumentEnum::Log);
+ REQUIRE(actualInstaller.NestedInstallerFiles.size() == 1);
+ REQUIRE(actualInstaller.NestedInstallerFiles.at(0).RelativeFilePath == "test\\app.exe");
+ REQUIRE(actualInstaller.NestedInstallerFiles.at(0).PortableCommandAlias == "test.exe");
+ REQUIRE(actualInstaller.InstallationMetadata.DefaultInstallLocation == "%TEMP%\\DefaultInstallLocation");
+ REQUIRE(actualInstaller.InstallationMetadata.Files.size() == 1);
+ REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).RelativeFilePath == "test\\app.exe");
+ REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).FileType == InstalledFileTypeEnum::Launch);
+ REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).FileSha256 == AppInstaller::Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6"));
+ REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).InvocationParameter == "/parameter");
+ REQUIRE(actualInstaller.InstallationMetadata.Files.at(0).DisplayName == "test");
+ REQUIRE(actualInstaller.DownloadCommandProhibited);
+ REQUIRE(actualInstaller.RepairBehavior == RepairBehaviorEnum::Uninstaller);
+ REQUIRE(actualInstaller.ArchiveBinariesDependOnPath);
+ }
+ };
+}
+
+TEST_CASE("GetManifests_GoodResponse_V1_9", "[RestSource][Interface_1_9]")
+{
+ GoodManifest_AllFields sampleManifest;
+ utility::string_t sample = sampleManifest.GetSampleManifest_AllFields();
+ HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) };
+ Interface v1_9{ TestRestUriString, std::move(helper), {} };
+ std::vector manifests = v1_9.GetManifests("Foo.Bar");
+ REQUIRE(manifests.size() == 1);
+
+ // Verify manifest is populated
+ Manifest& manifest = manifests[0];
+ REQUIRE(manifest.Id == "Foo.Bar");
+ REQUIRE(manifest.Version == "3.0.0abc");
+ REQUIRE(manifest.Moniker == "FooBarMoniker");
+ REQUIRE(manifest.Channel == "");
+ REQUIRE(manifest.ManifestVersion == AppInstaller::Manifest::ManifestVer{ "1.9.0" });
+ sampleManifest.VerifyLocalizations_AllFields(manifest);
+ sampleManifest.VerifyInstallers_AllFields(manifest);
+}
diff --git a/src/AppInstallerCLITests/YamlManifest.cpp b/src/AppInstallerCLITests/YamlManifest.cpp
index 4764a6980a..deaa572c64 100644
--- a/src/AppInstallerCLITests/YamlManifest.cpp
+++ b/src/AppInstallerCLITests/YamlManifest.cpp
@@ -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"));
diff --git a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj
index f1dc17c57f..d70fb30e56 100644
--- a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj
+++ b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj
@@ -451,6 +451,8 @@
+
+
@@ -544,6 +546,8 @@
+
+
diff --git a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters
index 5abac094cf..1b91d82bcf 100644
--- a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters
+++ b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters
@@ -103,6 +103,12 @@
{34442899-29e5-4183-96ba-a1e8740146be}
+
+ {8edd7018-8836-4b15-84c1-998391e19038}
+
+
+ {7464e3ff-7a60-4bb6-8806-70562382043b}
+
@@ -462,6 +468,12 @@
Microsoft
+
+ Rest\Schema\1_9\Json
+
+
+ Rest\Schema\1_9
+
@@ -722,6 +734,12 @@
Microsoft
+
+ Rest\Schema\1_9\Json
+
+
+ Rest\Schema\1_9
+
diff --git a/src/AppInstallerRepositoryCore/ManifestJSONParser.cpp b/src/AppInstallerRepositoryCore/ManifestJSONParser.cpp
index 79877c0edc..d30a871cdf 100644
--- a/src/AppInstallerRepositoryCore/ManifestJSONParser.cpp
+++ b/src/AppInstallerRepositoryCore/ManifestJSONParser.cpp
@@ -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
{
@@ -46,10 +47,14 @@ namespace AppInstaller::Repository::JSON
{
m_pImpl->m_deserializer = std::make_unique();
}
- else
+ else if (parts.size() > 1 && parts[1].Integer < 9)
{
m_pImpl->m_deserializer = std::make_unique();
}
+ else
+ {
+ m_pImpl->m_deserializer = std::make_unique();
+ }
}
else
{
diff --git a/src/AppInstallerRepositoryCore/Rest/RestClient.cpp b/src/AppInstallerRepositoryCore/Rest/RestClient.cpp
index 602d1fbfeb..c7e796bb16 100644
--- a/src/AppInstallerRepositoryCore/Rest/RestClient.cpp
+++ b/src/AppInstallerRepositoryCore/Rest/RestClient.cpp
@@ -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
@@ -22,7 +23,7 @@ using namespace AppInstaller::Http;
namespace AppInstaller::Repository::Rest
{
// Supported versions
- std::set 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 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;
@@ -176,6 +177,10 @@ namespace AppInstaller::Repository::Rest
{
return std::make_unique(api, helper, information, additionalHeaders, authArgs);
}
+ else if (version == Version_1_9_0)
+ {
+ return std::make_unique(api, helper, information, additionalHeaders, authArgs);
+ }
THROW_HR(APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_VERSION);
}
diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Interface.h b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Interface.h
new file mode 100644
index 0000000000..d9fb755c45
--- /dev/null
+++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Interface.h
@@ -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;
+ };
+}
diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer.h b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer.h
new file mode 100644
index 0000000000..09dd1da76d
--- /dev/null
+++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer.h
@@ -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 DeserializeInstaller(const web::json::value& installerJsonObject) const override;
+
+ Manifest::ManifestVer GetManifestVersion() const override;
+ };
+}
diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer_1_9.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer_1_9.cpp
new file mode 100644
index 0000000000..714d3fe048
--- /dev/null
+++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/Json/ManifestDeserializer_1_9.cpp
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "ManifestDeserializer.h"
+#include
+
+using namespace AppInstaller::Manifest;
+
+namespace AppInstaller::Repository::Rest::Schema::V1_9::Json
+{
+ namespace
+ {
+ // Installer
+ constexpr std::string_view ArchiveBinariesDependOnPath = "ArchiveBinariesDependOnPath"sv;
+ }
+
+ std::optional 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;
+ }
+}
diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_9/RestInterface_1_9.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/RestInterface_1_9.cpp
new file mode 100644
index 0000000000..b741b96530
--- /dev/null
+++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_9/RestInterface_1_9.cpp
@@ -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
+#include
+
+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;
+ }
+}
diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/CommonRestConstants.h b/src/AppInstallerRepositoryCore/Rest/Schema/CommonRestConstants.h
index ab3ab2002e..6ee979b7aa 100644
--- a/src/AppInstallerRepositoryCore/Rest/Schema/CommonRestConstants.h
+++ b/src/AppInstallerRepositoryCore/Rest/Schema/CommonRestConstants.h
@@ -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;
diff --git a/src/WinGetUtilInterop.UnitTests/ManifestUnitTest/V1ManifestReadTest.cs b/src/WinGetUtilInterop.UnitTests/ManifestUnitTest/V1ManifestReadTest.cs
index b6a7a81a49..607a427082 100644
--- a/src/WinGetUtilInterop.UnitTests/ManifestUnitTest/V1ManifestReadTest.cs
+++ b/src/WinGetUtilInterop.UnitTests/ManifestUnitTest/V1ManifestReadTest.cs
@@ -1,4 +1,4 @@
-// -----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
//
@@ -35,6 +35,7 @@ private enum TestManifestVersion
V110,
V160,
V170,
+ V190,
}
///
@@ -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);
}
///
@@ -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];
@@ -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];
@@ -448,6 +464,11 @@ internal class ManifestStrings
///
public const string V170ManifestMerged = "V1_7ManifestMerged.yaml";
+ ///
+ /// Merged v1.9 manifest.
+ ///
+ public const string V190ManifestMerged = "V1_9ManifestMerged.yaml";
+
///
/// Merged v1 manifest without localization.
///
diff --git a/src/WinGetUtilInterop.UnitTests/TestCollateral/V1_9ManifestMerged.yaml b/src/WinGetUtilInterop.UnitTests/TestCollateral/V1_9ManifestMerged.yaml
new file mode 100644
index 0000000000..28e92896a4
--- /dev/null
+++ b/src/WinGetUtilInterop.UnitTests/TestCollateral/V1_9ManifestMerged.yaml
@@ -0,0 +1,251 @@
+PackageIdentifier: microsoft.msixsdk
+PackageVersion: 1.7.32
+PackageLocale: en-US
+Publisher: Microsoft
+PublisherUrl: https://www.microsoft.com
+PublisherSupportUrl: https://www.microsoft.com/support
+PrivacyUrl: https://www.microsoft.com/privacy
+Author: Microsoft
+PackageName: MSIX SDK
+PackageUrl: https://www.microsoft.com/msixsdk/home
+License: MIT License
+LicenseUrl: https://www.microsoft.com/msixsdk/license
+Copyright: Copyright Microsoft Corporation
+CopyrightUrl: https://www.microsoft.com/msixsdk/copyright
+ShortDescription: This is MSIX SDK
+Description: The MSIX SDK project is an effort to enable developers
+Moniker: msixsdk
+Tags:
+ - "appxsdk"
+ - "msixsdk"
+ReleaseNotes: Default release notes
+ReleaseNotesUrl: https://DefaultReleaseNotes.net
+PurchaseUrl: https://DefaultPurchaseUrl.com
+InstallationNotes: Default installation notes
+Documentations:
+ - DocumentLabel: Default document label
+ DocumentUrl: https://DefaultDocumentUrl.com
+Icons:
+ - IconUrl: https://testIcon
+ IconFileType: ico
+ IconResolution: custom
+ IconTheme: default
+ IconSha256: 69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8123
+Agreements:
+ - AgreementLabel: DefaultLabel
+ Agreement: DefaultText
+ AgreementUrl: https://DefaultAgreementUrl.net
+InstallerLocale: en-US
+Platform:
+ - Windows.Desktop
+ - Windows.Universal
+MinimumOSVersion: 10.0.0.0
+InstallerType: zip
+Scope: machine
+InstallModes:
+ - interactive
+ - silent
+ - silentWithProgress
+InstallerSwitches:
+ Custom: /custom
+ SilentWithProgress: /silentwithprogress
+ Silent: /silence
+ Interactive: /interactive
+ Log: /log=
+ InstallLocation: /dir=
+ Upgrade: /upgrade
+ Repair: /repair
+InstallerSuccessCodes:
+ - 1
+ - 0x80070005
+UpgradeBehavior: uninstallPrevious
+Commands:
+ - makemsix
+ - makeappx
+Protocols:
+ - protocol1
+ - protocol2
+FileExtensions:
+ - appx
+ - msix
+ - appxbundle
+ - msixbundle
+Dependencies:
+ WindowsFeatures:
+ - IIS
+ WindowsLibraries:
+ - VC Runtime
+ PackageDependencies:
+ - PackageIdentifier: Microsoft.MsixSdkDep
+ MinimumVersion: 1.0.0
+ ExternalDependencies:
+ - Outside dependencies
+Capabilities:
+ - internetClient
+RestrictedCapabilities:
+ - runFullTrust
+PackageFamilyName: Microsoft.DesktopAppInstaller_8wekyb3d8bbwe
+ProductCode: "{Foo}"
+ReleaseDate: 2021-01-01
+InstallerAbortsTerminal: true
+InstallLocationRequired: true
+RequireExplicitUpgrade: true
+DisplayInstallWarnings: true
+ElevationRequirement: elevatesSelf
+UnsupportedOSArchitectures:
+ - arm
+AppsAndFeaturesEntries:
+ - DisplayName: DisplayName
+ DisplayVersion: DisplayVersion
+ Publisher: Publisher
+ ProductCode: ProductCode
+ UpgradeCode: UpgradeCode
+ InstallerType: exe
+Markets:
+ AllowedMarkets:
+ - US
+ExpectedReturnCodes:
+ - InstallerReturnCode: 2
+ ReturnResponse: contactSupport
+ - InstallerReturnCode: 3
+ ReturnResponse: custom
+ ReturnResponseUrl: https://defaultReturnResponseUrl.com
+UnsupportedArguments:
+ - log
+NestedInstallerType: msi
+NestedInstallerFiles:
+ - RelativeFilePath: RelativeFilePath
+ PortableCommandAlias: PortableCommandAlias
+InstallationMetadata:
+ DefaultInstallLocation: "%ProgramFiles%\\TestApp"
+ Files:
+ - RelativeFilePath: "main.exe"
+ FileSha256: 69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82
+ FileType: launch
+ InvocationParameter: "/arg"
+ DisplayName: "DisplayName"
+DownloadCommandProhibited: true
+ArchiveBinariesDependOnPath: true
+RepairBehavior: uninstaller
+Localization:
+- Agreements:
+ - Agreement: Text
+ AgreementLabel: Label
+ AgreementUrl: https://AgreementUrl.net
+ Author: Microsoft UK
+ Copyright: Copyright Microsoft Corporation UK
+ CopyrightUrl: https://www.microsoft.com/msixsdk/copyright/UK
+ Description: The MSIX SDK project is an effort to enable developers UK
+ License: MIT License UK
+ LicenseUrl: https://www.microsoft.com/msixsdk/license/UK
+ PackageLocale: en-GB
+ PackageName: MSIX SDK UK
+ PackageUrl: https://www.microsoft.com/msixsdk/home/UK
+ PrivacyUrl: https://www.microsoft.com/privacy/UK
+ Publisher: Microsoft UK
+ PublisherSupportUrl: https://www.microsoft.com/support/UK
+ PublisherUrl: https://www.microsoft.com/UK
+ ReleaseNotes: Release notes
+ ReleaseNotesUrl: https://ReleaseNotes.net
+ ShortDescription: This is MSIX SDK UK
+ Tags:
+ - appxsdkUK
+ - msixsdkUK
+ PurchaseUrl: https://PurchaseUrl.com
+ InstallationNotes: Installation notes
+ Documentations:
+ - DocumentLabel: Document label
+ DocumentUrl: https://DocumentUrl.com
+ Icons:
+ - IconUrl: https://testIcon2
+ IconFileType: png
+ IconResolution: 32x32
+ IconTheme: dark
+ IconSha256: 69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8321
+Installers:
+ - Architecture: x86
+ InstallerLocale: en-GB
+ Platform:
+ - Windows.Desktop
+ MinimumOSVersion: 10.0.1.0
+ InstallerType: msix
+ InstallerUrl: https://www.microsoft.com/msixsdk/msixsdkx86.msix
+ InstallerSha256: 69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82
+ SignatureSha256: 69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82
+ Scope: user
+ InstallModes:
+ - interactive
+ InstallerSwitches:
+ Custom: /c
+ SilentWithProgress: /sp
+ Silent: /s
+ Interactive: /i
+ Log: /l=
+ InstallLocation: /d=
+ Upgrade: /u
+ Repair: /r
+ UpgradeBehavior: install
+ Commands:
+ - makemsixPreview
+ - makeappxPreview
+ Protocols:
+ - protocol1preview
+ - protocol2preview
+ FileExtensions:
+ - appxbundle
+ - msixbundle
+ - appx
+ - msix
+ Dependencies:
+ WindowsFeatures:
+ - PreviewIIS
+ WindowsLibraries:
+ - Preview VC Runtime
+ PackageDependencies:
+ - PackageIdentifier: Microsoft.MsixSdkDepPreview
+ MinimumVersion: 1.0.0
+ ExternalDependencies:
+ - Preview Outside dependencies
+ PackageFamilyName: Microsoft.DesktopAppInstallerPreview_8wekyb3d8bbwe
+ Capabilities:
+ - internetClientPreview
+ RestrictedCapabilities:
+ - runFullTrustPreview
+ ReleaseDate: 2021-02-02
+ InstallerAbortsTerminal: false
+ InstallLocationRequired: false
+ NestedInstallerFiles:
+ - RelativeFilePath: RelativeFilePath2
+ PortableCommandAlias: PortableCommandAlias2
+ RequireExplicitUpgrade: false
+ DisplayInstallWarnings: true
+ ElevationRequirement: elevationRequired
+ NestedInstallerType: msi
+ UnsupportedArguments:
+ - location
+ UnsupportedOSArchitectures:
+ - arm64
+ Markets:
+ ExcludedMarkets:
+ - "US"
+ ExpectedReturnCodes:
+ - InstallerReturnCode: 2
+ ReturnResponse: contactSupport
+ DownloadCommandProhibited: true
+ ArchiveBinariesDependOnPath: false
+ RepairBehavior: modify
+ InstallationMetadata:
+ DefaultInstallLocation: "%ProgramFiles%\\TestApp"
+ Files:
+ - RelativeFilePath: "main2.exe"
+ FileSha256: 79D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82
+ FileType: launch2
+ InvocationParameter: "/arg2"
+ DisplayName: "DisplayName2"
+ - Architecture: x64
+ InstallerSha256: 69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82
+ InstallerUrl: https://www.microsoft.com/msixsdk/msixsdkx64.exe
+ InstallerType: exe
+ ProductCode: '{Bar}'
+ManifestType: merged
+ManifestVersion: 1.7.0
\ No newline at end of file
diff --git a/src/WinGetUtilInterop.UnitTests/WinGetUtilInterop.UnitTests.csproj b/src/WinGetUtilInterop.UnitTests/WinGetUtilInterop.UnitTests.csproj
index b3fd2c5990..618c708bc4 100644
--- a/src/WinGetUtilInterop.UnitTests/WinGetUtilInterop.UnitTests.csproj
+++ b/src/WinGetUtilInterop.UnitTests/WinGetUtilInterop.UnitTests.csproj
@@ -1,4 +1,4 @@
-
+
net6.0
@@ -94,6 +94,9 @@
Always
+
+ Always
+
PreserveNewest
diff --git a/src/WinGetUtilInterop/Manifest/V1/Manifest.cs b/src/WinGetUtilInterop/Manifest/V1/Manifest.cs
index 304ca21d52..534d29af4a 100644
--- a/src/WinGetUtilInterop/Manifest/V1/Manifest.cs
+++ b/src/WinGetUtilInterop/Manifest/V1/Manifest.cs
@@ -1,4 +1,4 @@
-// -----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
//
@@ -333,7 +333,12 @@ public class Manifest
///
/// Gets or sets a value indicating whether the installer is prohibited from being downloaded for offline installation.
///
- public bool DownloadCommandProhibited { get; set; }
+ public bool DownloadCommandProhibited { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the install location should be added directly to the PATH environment variable.
+ ///
+ public bool ArchiveBinariesDependOnPath { get; set; }
///
/// Gets or sets the default repair behavior.
diff --git a/src/WinGetUtilInterop/Manifest/V1/ManifestInstaller.cs b/src/WinGetUtilInterop/Manifest/V1/ManifestInstaller.cs
index b618e15170..1f84a1da04 100644
--- a/src/WinGetUtilInterop/Manifest/V1/ManifestInstaller.cs
+++ b/src/WinGetUtilInterop/Manifest/V1/ManifestInstaller.cs
@@ -1,4 +1,4 @@
-// -----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
//
@@ -196,7 +196,12 @@ public class ManifestInstaller
///
/// Gets or sets a value indicating whether the installer is prohibited from being downloaded for offline installation.
///
- public bool DownloadCommandProhibited { get; set; }
+ public bool DownloadCommandProhibited { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the install location should be added directly to the PATH environment variable.
+ ///
+ public bool ArchiveBinariesDependOnPath { get; set; }
///
/// Gets or sets the repair behavior.