From 5a81f142c832e2a384a59094d11882c8bf386e2b Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Wed, 3 Aug 2022 13:17:05 -0700 Subject: [PATCH 1/5] use effectiveInstallertype --- .../Workflows/ArchiveFlow.cpp | 2 +- .../Workflows/DependenciesFlow.cpp | 2 +- .../Workflows/DownloadFlow.cpp | 10 +++--- .../Workflows/InstallFlow.cpp | 8 ++--- .../Workflows/ManifestComparator.cpp | 14 ++++---- .../Workflows/PortableFlow.cpp | 2 +- .../Workflows/ShowFlow.cpp | 2 +- .../Workflows/UpdateFlow.cpp | 2 +- .../Workflows/WorkflowBase.cpp | 4 +-- src/AppInstallerCLITests/ARPChanges.cpp | 2 +- .../ManifestComparator.cpp | 4 +-- .../RestInterface_1_0.cpp | 4 +-- .../RestInterface_1_1.cpp | 2 +- src/AppInstallerCLITests/SQLiteIndex.cpp | 14 ++++---- src/AppInstallerCLITests/YamlManifest.cpp | 26 +++++++------- .../Manifest/Manifest.cpp | 2 +- .../Manifest/ManifestCommon.cpp | 29 +++------------- .../Manifest/ManifestValidation.cpp | 34 +++++++++---------- .../Manifest/ManifestYamlPopulator.cpp | 14 ++++---- .../Public/winget/ManifestCommon.h | 11 +++--- .../Public/winget/ManifestInstaller.h | 7 +++- .../1_0/Json/ManifestDeserializer_1_0.cpp | 4 +-- .../1_1/Json/ManifestDeserializer_1_1.cpp | 2 +- 23 files changed, 91 insertions(+), 110 deletions(-) diff --git a/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp b/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp index 4c08c97fca..5d92da9d0b 100644 --- a/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp @@ -69,7 +69,7 @@ namespace AppInstaller::CLI::Workflow { auto installer = context.Get().value(); - if (IsArchiveType(installer.InstallerType)) + if (IsArchiveType(installer.BaseInstallerType)) { auto const& nestedInstallerFiles = installer.NestedInstallerFiles; if (nestedInstallerFiles.empty()) diff --git a/src/AppInstallerCLICore/Workflows/DependenciesFlow.cpp b/src/AppInstallerCLICore/Workflows/DependenciesFlow.cpp index 075de6f6f0..d9f76a096b 100644 --- a/src/AppInstallerCLICore/Workflows/DependenciesFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/DependenciesFlow.cpp @@ -217,7 +217,7 @@ namespace AppInstaller::CLI::Workflow Logging::Telemetry().LogSelectedInstaller( static_cast(itr->second.Installer.Arch), itr->second.Installer.Url, - Manifest::InstallerTypeToString(itr->second.Installer.InstallerType), + Manifest::InstallerTypeToString(itr->second.Installer.EffectiveInstallerType()), Manifest::ScopeToString(itr->second.Installer.Scope), itr->second.Installer.Locale); diff --git a/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp b/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp index ccd5fc8370..a2c47cc56e 100644 --- a/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp @@ -33,7 +33,7 @@ namespace AppInstaller::CLI::Workflow std::wstring_view GetInstallerFileExtension(Execution::Context& context) { const auto& installer = context.Get(); - switch (installer->InstallerType) + switch (installer->BaseInstallerType) { case InstallerTypeEnum::Burn: case InstallerTypeEnum::Exe: @@ -143,7 +143,7 @@ namespace AppInstaller::CLI::Workflow if (!context.Contains(Execution::Data::InstallerPath)) { const auto& installer = context.Get().value(); - switch (installer.InstallerType) + switch (installer.BaseInstallerType) { case InstallerTypeEnum::Exe: case InstallerTypeEnum::Burn: @@ -183,7 +183,7 @@ namespace AppInstaller::CLI::Workflow void CheckForExistingInstaller(Execution::Context& context) { const auto& installer = context.Get().value(); - if (installer.InstallerType == InstallerTypeEnum::MSStore) + if (installer.EffectiveInstallerType() == InstallerTypeEnum::MSStore) { // No installer is downloaded in this case return; @@ -415,12 +415,12 @@ namespace AppInstaller::CLI::Workflow auto existingFileHash = SHA256::ComputeHash(inStream); context.Add(std::make_pair(installer.Sha256, existingFileHash)); } - else if (installer.InstallerType == InstallerTypeEnum::MSStore) + else if (installer.EffectiveInstallerType() == InstallerTypeEnum::MSStore) { // No installer file in this case return; } - else if (installer.InstallerType == InstallerTypeEnum::Msix && !installer.SignatureSha256.empty()) + else if (installer.EffectiveInstallerType() == InstallerTypeEnum::Msix && !installer.SignatureSha256.empty()) { // We didn't download the installer file before. Just verify the signature hash again. context << GetMsixSignatureHash; diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index 2260d28750..4c91903834 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -77,7 +77,7 @@ namespace AppInstaller::CLI::Workflow { auto installer = context.Get().value(); - if (IsArchiveType(installer.InstallerType)) + if (IsArchiveType(installer.BaseInstallerType)) { context << Workflow::EnsureFeatureEnabled(Settings::ExperimentalFeature::Feature::ZipInstall); @@ -217,7 +217,7 @@ namespace AppInstaller::CLI::Workflow void ShowInstallationDisclaimer(Execution::Context& context) { - auto installerType = context.Get().value().InstallerType; + auto installerType = context.Get().value().EffectiveInstallerType(); if (installerType == InstallerTypeEnum::MSStore) { @@ -387,7 +387,7 @@ namespace AppInstaller::CLI::Workflow void ExecuteInstaller(Execution::Context& context) { - context << Workflow::ExecuteInstallerForType(context.Get().value().InstallerType); + context << Workflow::ExecuteInstallerForType(context.Get().value().BaseInstallerType); } void ArchiveInstall(Execution::Context& context) @@ -645,7 +645,7 @@ namespace AppInstaller::CLI::Workflow // Ensure that installer type might actually write to ARP, otherwise this is a waste of time auto installer = context.Get(); - if (installer && MightWriteToARP(installer->InstallerType)) + if (installer && MightWriteToARP(installer->EffectiveInstallerType())) { Repository::Correlation::ARPCorrelationData data; data.CapturePreInstallSnapshot(); diff --git a/src/AppInstallerCLICore/Workflows/ManifestComparator.cpp b/src/AppInstallerCLICore/Workflows/ManifestComparator.cpp index 11a8ccbdee..e25af3e20f 100644 --- a/src/AppInstallerCLICore/Workflows/ManifestComparator.cpp +++ b/src/AppInstallerCLICore/Workflows/ManifestComparator.cpp @@ -13,7 +13,7 @@ std::ostream& operator<<(std::ostream& out, const AppInstaller::Manifest::Manife { return out << '[' << AppInstaller::Utility::ToString(installer.Arch) << ',' << - AppInstaller::Manifest::InstallerTypeToString(installer.InstallerType) << ',' << + AppInstaller::Manifest::InstallerTypeToString(installer.EffectiveInstallerType()) << ',' << AppInstaller::Manifest::ScopeToString(installer.Scope) << ',' << installer.Locale << ']'; } @@ -30,7 +30,7 @@ namespace AppInstaller::CLI::Workflow { // Unvirtualized resources restricted capability is only supported for >= 10.0.18362 // TODO: Add support for OS versions that don't support virtualization. - if (installer.InstallerType == InstallerTypeEnum::Portable && !Runtime::IsCurrentOSVersionGreaterThanOrEqual(Utility::Version("10.0.18362"))) + if (installer.EffectiveInstallerType() == InstallerTypeEnum::Portable && !Runtime::IsCurrentOSVersionGreaterThanOrEqual(Utility::Version("10.0.18362"))) { return InapplicabilityFlags::OSVersion; } @@ -218,7 +218,7 @@ namespace AppInstaller::CLI::Workflow InapplicabilityFlags IsApplicable(const Manifest::ManifestInstaller& installer) override { // The installer is applicable if it's type or any of its ARP entries' type matches the installed type - if (Manifest::IsInstallerTypeCompatible(installer.InstallerType, m_installedType)) + if (Manifest::IsInstallerTypeCompatible(installer.EffectiveInstallerType(), m_installedType)) { return InapplicabilityFlags::None; } @@ -238,7 +238,7 @@ namespace AppInstaller::CLI::Workflow std::string ExplainInapplicable(const Manifest::ManifestInstaller& installer) override { std::string result = "Installed package type '" + std::string{ Manifest::InstallerTypeToString(m_installedType) } + - "' is not compatible with installer type " + std::string{ Manifest::InstallerTypeToString(installer.InstallerType) }; + "' is not compatible with installer type " + std::string{ Manifest::InstallerTypeToString(installer.EffectiveInstallerType()) }; std::string arpInstallerTypes; for (const auto& entry : installer.AppsAndFeaturesEntries) @@ -256,7 +256,7 @@ namespace AppInstaller::CLI::Workflow bool IsFirstBetter(const Manifest::ManifestInstaller& first, const Manifest::ManifestInstaller& second) override { - return (first.InstallerType == m_installedType && second.InstallerType != m_installedType); + return (first.EffectiveInstallerType() == m_installedType && second.EffectiveInstallerType() != m_installedType); } private: @@ -287,7 +287,7 @@ namespace AppInstaller::CLI::Workflow InapplicabilityFlags IsApplicable(const Manifest::ManifestInstaller& installer) override { // We have to assume the unknown scope will match our required scope, or the entire catalog would stop working for upgrade. - if (installer.Scope == Manifest::ScopeEnum::Unknown || installer.Scope == m_requirement || DoesInstallerIgnoreScopeFromManifest(installer)) + if (installer.Scope == Manifest::ScopeEnum::Unknown || installer.Scope == m_requirement || DoesInstallerTypeIgnoreScopeFromManifest(installer.EffectiveInstallerType())) { return InapplicabilityFlags::None; } @@ -342,7 +342,7 @@ namespace AppInstaller::CLI::Workflow InapplicabilityFlags IsApplicable(const Manifest::ManifestInstaller& installer) override { - if (m_requirement == Manifest::ScopeEnum::Unknown || installer.Scope == m_requirement || DoesInstallerIgnoreScopeFromManifest(installer)) + if (m_requirement == Manifest::ScopeEnum::Unknown || installer.Scope == m_requirement || DoesInstallerTypeIgnoreScopeFromManifest(installer.EffectiveInstallerType())) { return InapplicabilityFlags::None; } diff --git a/src/AppInstallerCLICore/Workflows/PortableFlow.cpp b/src/AppInstallerCLICore/Workflows/PortableFlow.cpp index 23430d2156..7f20ce66aa 100644 --- a/src/AppInstallerCLICore/Workflows/PortableFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/PortableFlow.cpp @@ -653,7 +653,7 @@ namespace AppInstaller::CLI::Workflow void EnsureSupportForPortableInstall(Execution::Context& context) { - auto installerType = context.Get().value().InstallerType; + auto installerType = context.Get().value().EffectiveInstallerType(); if (installerType == InstallerTypeEnum::Portable) { diff --git a/src/AppInstallerCLICore/Workflows/ShowFlow.cpp b/src/AppInstallerCLICore/Workflows/ShowFlow.cpp index 4127834a0f..ec7e07342e 100644 --- a/src/AppInstallerCLICore/Workflows/ShowFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/ShowFlow.cpp @@ -173,7 +173,7 @@ namespace AppInstaller::CLI::Workflow info << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelInstaller << std::endl; if (installer) { - info << " "_liv << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelInstallerType << ' ' << Manifest::InstallerTypeToString(installer->InstallerType) << std::endl; + info << " "_liv << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelInstallerType << ' ' << Manifest::InstallerTypeToString(installer->BaseInstallerType) << std::endl; if (!installer->Locale.empty()) { info << " "_liv << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelInstallerLocale << ' ' << installer->Locale << std::endl; diff --git a/src/AppInstallerCLICore/Workflows/UpdateFlow.cpp b/src/AppInstallerCLICore/Workflows/UpdateFlow.cpp index 4491f9190b..1ed50c78bc 100644 --- a/src/AppInstallerCLICore/Workflows/UpdateFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/UpdateFlow.cpp @@ -73,7 +73,7 @@ namespace AppInstaller::CLI::Workflow Logging::Telemetry().LogSelectedInstaller( static_cast(installer->Arch), installer->Url, - Manifest::InstallerTypeToString(installer->InstallerType), + Manifest::InstallerTypeToString(installer->EffectiveInstallerType()), Manifest::ScopeToString(installer->Scope), installer->Locale); diff --git a/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp b/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp index b13e612a33..bdedb8deb3 100644 --- a/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp +++ b/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp @@ -1027,7 +1027,7 @@ namespace AppInstaller::CLI::Workflow Logging::Telemetry().LogSelectedInstaller( static_cast(installer->Arch), installer->Url, - Manifest::InstallerTypeToString(installer->InstallerType), + Manifest::InstallerTypeToString(installer->EffectiveInstallerType()), Manifest::ScopeToString(installer->Scope), installer->Locale); } @@ -1072,7 +1072,7 @@ namespace AppInstaller::CLI::Workflow { searchRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::ProductCode, MatchType::Exact, installer.ProductCode)); } - else if (installer.InstallerType == Manifest::InstallerTypeEnum::Portable) + else if (installer.EffectiveInstallerType() == Manifest::InstallerTypeEnum::Portable) { const auto& productCode = Utility::MakeSuitablePathPart(manifest.Id + "_" + source.GetIdentifier()); searchRequest.Inclusions.emplace_back(PackageMatchFilter(PackageMatchField::ProductCode, MatchType::CaseInsensitive, Utility::Normalize(productCode))); diff --git a/src/AppInstallerCLITests/ARPChanges.cpp b/src/AppInstallerCLITests/ARPChanges.cpp index cfa3bbd6f7..ed9a56ff40 100644 --- a/src/AppInstallerCLITests/ARPChanges.cpp +++ b/src/AppInstallerCLITests/ARPChanges.cpp @@ -59,7 +59,7 @@ struct TestContext : public Context { // Put installer in to control whether arp change code cares to run Manifest::ManifestInstaller installer; - installer.InstallerType = installerType; + installer.BaseInstallerType = installerType; Add(std::move(installer)); // Put in an empty manifest by default diff --git a/src/AppInstallerCLITests/ManifestComparator.cpp b/src/AppInstallerCLITests/ManifestComparator.cpp index d928d74f5a..591e794bd7 100644 --- a/src/AppInstallerCLITests/ManifestComparator.cpp +++ b/src/AppInstallerCLITests/ManifestComparator.cpp @@ -36,7 +36,7 @@ const ManifestInstaller& AddInstaller( { ManifestInstaller toAdd; toAdd.Arch = architecture; - toAdd.InstallerType = installerType; + toAdd.BaseInstallerType = installerType; toAdd.Scope = scope; toAdd.MinOSVersion = minOSVersion; toAdd.Locale = locale; @@ -63,7 +63,7 @@ void RequireInstaller(const std::optional& actual, const Mani { REQUIRE(actual); REQUIRE(actual->Arch == expected.Arch); - REQUIRE(actual->InstallerType == expected.InstallerType); + REQUIRE(actual->EffectiveInstallerType() == expected.EffectiveInstallerType()); REQUIRE(actual->Scope == expected.Scope); REQUIRE(actual->MinOSVersion == expected.MinOSVersion); REQUIRE(actual->Locale == expected.Locale); diff --git a/src/AppInstallerCLITests/RestInterface_1_0.cpp b/src/AppInstallerCLITests/RestInterface_1_0.cpp index da0e2ed45a..ff71a04205 100644 --- a/src/AppInstallerCLITests/RestInterface_1_0.cpp +++ b/src/AppInstallerCLITests/RestInterface_1_0.cpp @@ -238,7 +238,7 @@ namespace REQUIRE(actualInstaller.Platform.size() == 1); REQUIRE(actualInstaller.Platform[0] == PlatformEnum::Desktop); REQUIRE(actualInstaller.MinOSVersion == "1078"); - REQUIRE(actualInstaller.InstallerType == InstallerTypeEnum::Msix); + REQUIRE(actualInstaller.BaseInstallerType == InstallerTypeEnum::Msix); REQUIRE(actualInstaller.Scope == ScopeEnum::User); REQUIRE(actualInstaller.SignatureSha256 == AppInstaller::Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6")); REQUIRE(actualInstaller.InstallModes.size() == 1); @@ -425,7 +425,7 @@ TEST_CASE("Search_Optimized_ManifestResponse", "[RestSource][Interface_1_0]") REQUIRE(manifest.Installers.size() == 1); REQUIRE(manifest.Installers[0].Arch == Architecture::X64); REQUIRE(manifest.Installers[0].Sha256 == AppInstaller::Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6")); - REQUIRE(manifest.Installers[0].InstallerType == InstallerTypeEnum::Exe); + REQUIRE(manifest.Installers[0].BaseInstallerType == InstallerTypeEnum::Exe); REQUIRE(manifest.Installers[0].Url == "https://installer.example.com/foobar.exe"); } diff --git a/src/AppInstallerCLITests/RestInterface_1_1.cpp b/src/AppInstallerCLITests/RestInterface_1_1.cpp index df62a2e742..b53f2c1a61 100644 --- a/src/AppInstallerCLITests/RestInterface_1_1.cpp +++ b/src/AppInstallerCLITests/RestInterface_1_1.cpp @@ -257,7 +257,7 @@ namespace REQUIRE(actualInstaller.Platform.size() == 1); REQUIRE(actualInstaller.Platform[0] == PlatformEnum::Desktop); REQUIRE(actualInstaller.MinOSVersion == "1078"); - REQUIRE(actualInstaller.InstallerType == InstallerTypeEnum::Msi); + REQUIRE(actualInstaller.BaseInstallerType == InstallerTypeEnum::Msi); REQUIRE(actualInstaller.Scope == ScopeEnum::User); REQUIRE(actualInstaller.InstallModes.size() == 1); REQUIRE(actualInstaller.InstallModes.at(0) == InstallModeEnum::Interactive); diff --git a/src/AppInstallerCLITests/SQLiteIndex.cpp b/src/AppInstallerCLITests/SQLiteIndex.cpp index d04e7da023..6010a659c2 100644 --- a/src/AppInstallerCLITests/SQLiteIndex.cpp +++ b/src/AppInstallerCLITests/SQLiteIndex.cpp @@ -2946,7 +2946,7 @@ TEST_CASE("SQLiteIndex_ManifestArpVersion_Present_Add", "[sqliteindex]") manifest.Id = "Foo"; manifest.Version = "Bar"; manifest.Installers.push_back({}); - manifest.Installers[0].InstallerType = InstallerTypeEnum::Exe; + manifest.Installers[0].BaseInstallerType = InstallerTypeEnum::Exe; manifest.Installers[0].AppsAndFeaturesEntries.push_back({}); manifest.Installers[0].AppsAndFeaturesEntries[0].DisplayVersion = "1.0"; manifest.Installers[0].AppsAndFeaturesEntries.push_back({}); @@ -2987,7 +2987,7 @@ TEST_CASE("SQLiteIndex_ManifestArpVersion_Present_AddThenUpdate", "[sqliteindex] manifest.Id = "Foo"; manifest.Version = "Bar"; manifest.Installers.push_back({}); - manifest.Installers[0].InstallerType = InstallerTypeEnum::Exe; + manifest.Installers[0].BaseInstallerType = InstallerTypeEnum::Exe; manifest.Installers[0].AppsAndFeaturesEntries.push_back({}); manifest.Installers[0].AppsAndFeaturesEntries[0].DisplayVersion = "1.0"; manifest.Installers[0].AppsAndFeaturesEntries.push_back({}); @@ -3066,7 +3066,7 @@ TEST_CASE("SQLiteIndex_RemoveManifestArpVersionKeepUsedDeleteUnused", "[sqlitein manifest.Id = "Foo"; manifest.Version = "10.0"; manifest.Installers.push_back({}); - manifest.Installers[0].InstallerType = InstallerTypeEnum::Exe; + manifest.Installers[0].BaseInstallerType = InstallerTypeEnum::Exe; manifest.Installers[0].AppsAndFeaturesEntries.push_back({}); manifest.Installers[0].AppsAndFeaturesEntries[0].DisplayVersion = "1.0"; manifest.Installers[0].AppsAndFeaturesEntries.push_back({}); @@ -3078,7 +3078,7 @@ TEST_CASE("SQLiteIndex_RemoveManifestArpVersionKeepUsedDeleteUnused", "[sqlitein manifest2.Id = "Foo2"; manifest2.Version = "1.0"; manifest2.Installers.push_back({}); - manifest2.Installers[0].InstallerType = InstallerTypeEnum::Exe; + manifest2.Installers[0].BaseInstallerType = InstallerTypeEnum::Exe; manifest2.Installers[0].AppsAndFeaturesEntries.push_back({}); manifest2.Installers[0].AppsAndFeaturesEntries[0].DisplayVersion = "10.0"; @@ -3116,7 +3116,7 @@ TEST_CASE("SQLiteIndex_ManifestArpVersion_CheckConsistency", "[sqliteindex]") manifest.DefaultLocalization.Add("ArpVersionCheckConsistencyTest"); manifest.Moniker = "testmoniker"; manifest.Installers.push_back({}); - manifest.Installers[0].InstallerType = InstallerTypeEnum::Exe; + manifest.Installers[0].BaseInstallerType = InstallerTypeEnum::Exe; manifest.Installers[0].AppsAndFeaturesEntries.push_back({}); manifest.Installers[0].AppsAndFeaturesEntries[0].DisplayVersion = "1.0"; manifest.Installers[0].AppsAndFeaturesEntries.push_back({}); @@ -3145,7 +3145,7 @@ TEST_CASE("SQLiteIndex_ManifestArpVersion_ValidateManifestAgainstIndex", "[sqlit manifest.Id = "Foo"; manifest.Version = "10.0"; manifest.Installers.push_back({}); - manifest.Installers[0].InstallerType = InstallerTypeEnum::Exe; + manifest.Installers[0].BaseInstallerType = InstallerTypeEnum::Exe; manifest.Installers[0].AppsAndFeaturesEntries.push_back({}); manifest.Installers[0].AppsAndFeaturesEntries[0].DisplayVersion = "1.0"; manifest.Installers[0].AppsAndFeaturesEntries.push_back({}); @@ -3172,7 +3172,7 @@ TEST_CASE("SQLiteIndex_CheckConsistency_FindEmbeddedNull", "[sqliteindex]") manifest.Id = "Foo"; manifest.Version = "10.0"; manifest.Installers.push_back({}); - manifest.Installers[0].InstallerType = InstallerTypeEnum::Exe; + manifest.Installers[0].BaseInstallerType = InstallerTypeEnum::Exe; manifest.Installers[0].AppsAndFeaturesEntries.push_back({}); manifest.Installers[0].AppsAndFeaturesEntries[0].DisplayVersion = "1.0"; manifest.Installers[0].AppsAndFeaturesEntries.push_back({}); diff --git a/src/AppInstallerCLITests/YamlManifest.cpp b/src/AppInstallerCLITests/YamlManifest.cpp index 46a37042f5..ecdcfd8e38 100644 --- a/src/AppInstallerCLITests/YamlManifest.cpp +++ b/src/AppInstallerCLITests/YamlManifest.cpp @@ -70,7 +70,7 @@ TEST_CASE("ReadPreviewGoodManifestAndVerifyContents", "[ManifestValidation]") REQUIRE(manifest.DefaultInstallerInfo.Commands == MultiValue{ "makemsix", "makeappx" }); REQUIRE(manifest.DefaultInstallerInfo.Protocols == MultiValue{ "protocol1", "protocol2" }); REQUIRE(manifest.DefaultInstallerInfo.FileExtensions == MultiValue{ "appx", "appxbundle", "msix", "msixbundle" }); - REQUIRE(manifest.DefaultInstallerInfo.InstallerType == InstallerTypeEnum::Zip); + REQUIRE(manifest.DefaultInstallerInfo.BaseInstallerType == InstallerTypeEnum::Zip); REQUIRE(manifest.DefaultInstallerInfo.PackageFamilyName == "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe"); REQUIRE(manifest.DefaultInstallerInfo.ProductCode == "{Foo}"); REQUIRE(manifest.DefaultInstallerInfo.UpdateBehavior == UpdateBehaviorEnum::UninstallPrevious); @@ -93,7 +93,7 @@ TEST_CASE("ReadPreviewGoodManifestAndVerifyContents", "[ManifestValidation]") REQUIRE(installer1.Url == "https://rubengustorage.blob.core.windows.net/publiccontainer/msixsdkx86.zip"); REQUIRE(installer1.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82")); REQUIRE(installer1.Locale == "en-US"); - REQUIRE(installer1.InstallerType == InstallerTypeEnum::Zip); + REQUIRE(installer1.BaseInstallerType == InstallerTypeEnum::Zip); REQUIRE(installer1.Scope == ScopeEnum::User); REQUIRE(installer1.PackageFamilyName == ""); REQUIRE(installer1.ProductCode == ""); @@ -114,7 +114,7 @@ TEST_CASE("ReadPreviewGoodManifestAndVerifyContents", "[ManifestValidation]") REQUIRE(installer2.Url == "https://rubengustorage.blob.core.windows.net/publiccontainer/msixsdkx64.zip"); REQUIRE(installer2.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF0000")); REQUIRE(installer2.Locale == "en-US"); - REQUIRE(installer2.InstallerType == InstallerTypeEnum::Zip); + REQUIRE(installer2.BaseInstallerType == InstallerTypeEnum::Zip); REQUIRE(installer2.Scope == ScopeEnum::User); REQUIRE(installer2.PackageFamilyName == ""); REQUIRE(installer2.ProductCode == ""); @@ -343,30 +343,30 @@ TEST_CASE("ComplexSystemReference", "[ManifestValidation]") REQUIRE(manifest.Installers.size() == 5); // Zip installer does not inherit - REQUIRE(manifest.Installers[0].InstallerType == InstallerTypeEnum::Zip); + REQUIRE(manifest.Installers[0].BaseInstallerType == InstallerTypeEnum::Zip); REQUIRE(manifest.Installers[0].PackageFamilyName == ""); REQUIRE(manifest.Installers[0].ProductCode == ""); // MSIX installer does inherit - REQUIRE(manifest.Installers[1].InstallerType == InstallerTypeEnum::Msix); + REQUIRE(manifest.Installers[1].BaseInstallerType == InstallerTypeEnum::Msix); REQUIRE(manifest.Installers[1].Arch == Architecture::X86); REQUIRE(manifest.Installers[1].PackageFamilyName == "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe"); REQUIRE(manifest.Installers[1].ProductCode == ""); // MSI installer does inherit - REQUIRE(manifest.Installers[2].InstallerType == InstallerTypeEnum::Msi); + REQUIRE(manifest.Installers[2].BaseInstallerType == InstallerTypeEnum::Msi); REQUIRE(manifest.Installers[2].Arch == Architecture::X86); REQUIRE(manifest.Installers[2].PackageFamilyName == ""); REQUIRE(manifest.Installers[2].ProductCode == "{Foo}"); // MSIX installer with override - REQUIRE(manifest.Installers[3].InstallerType == InstallerTypeEnum::Msix); + REQUIRE(manifest.Installers[3].BaseInstallerType == InstallerTypeEnum::Msix); REQUIRE(manifest.Installers[3].Arch == Architecture::X64); REQUIRE(manifest.Installers[3].PackageFamilyName == "Override_8wekyb3d8bbwe"); REQUIRE(manifest.Installers[3].ProductCode == ""); // MSI installer with override - REQUIRE(manifest.Installers[4].InstallerType == InstallerTypeEnum::Msi); + REQUIRE(manifest.Installers[4].BaseInstallerType == InstallerTypeEnum::Msi); REQUIRE(manifest.Installers[4].Arch == Architecture::X64); REQUIRE(manifest.Installers[4].PackageFamilyName == ""); REQUIRE(manifest.Installers[4].ProductCode == "Override"); @@ -435,7 +435,7 @@ void VerifyV1ManifestContent(const Manifest& manifest, bool isSingleton, Manifes REQUIRE(manifest.DefaultInstallerInfo.Locale == "en-US"); REQUIRE(manifest.DefaultInstallerInfo.Platform == std::vector{ PlatformEnum::Desktop, PlatformEnum::Universal }); REQUIRE(manifest.DefaultInstallerInfo.MinOSVersion == "10.0.0.0"); - REQUIRE(manifest.DefaultInstallerInfo.InstallerType == InstallerTypeEnum::Zip); + REQUIRE(manifest.DefaultInstallerInfo.BaseInstallerType == InstallerTypeEnum::Zip); REQUIRE(manifest.DefaultInstallerInfo.Scope == ScopeEnum::Machine); REQUIRE(manifest.DefaultInstallerInfo.InstallModes == std::vector{ InstallModeEnum::Interactive, InstallModeEnum::Silent, InstallModeEnum::SilentWithProgress }); @@ -534,7 +534,7 @@ void VerifyV1ManifestContent(const Manifest& manifest, bool isSingleton, Manifes REQUIRE(installer1.Locale == "en-GB"); REQUIRE(installer1.Platform == std::vector{ PlatformEnum::Desktop }); REQUIRE(installer1.MinOSVersion == "10.0.1.0"); - REQUIRE(installer1.InstallerType == InstallerTypeEnum::Msix); + REQUIRE(installer1.BaseInstallerType == InstallerTypeEnum::Msix); REQUIRE(installer1.Url == "https://www.microsoft.com/msixsdk/msixsdkx86.msix"); REQUIRE(installer1.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82")); REQUIRE(installer1.SignatureSha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82")); @@ -608,7 +608,7 @@ void VerifyV1ManifestContent(const Manifest& manifest, bool isSingleton, Manifes if (!isSingleton) { ManifestInstaller installer2 = manifest.Installers.at(1); - REQUIRE(installer2.InstallerType == InstallerTypeEnum::Exe); + REQUIRE(installer2.BaseInstallerType == InstallerTypeEnum::Exe); REQUIRE(installer2.Arch == Architecture::X64); REQUIRE(installer2.Url == "https://www.microsoft.com/msixsdk/msixsdkx64.exe"); REQUIRE(installer2.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82")); @@ -639,7 +639,7 @@ void VerifyV1ManifestContent(const Manifest& manifest, bool isSingleton, Manifes if (manifestVer >= ManifestVer{ s_ManifestVersionV1_2 }) { ManifestInstaller installer3 = manifest.Installers.at(2); - REQUIRE(installer3.InstallerType == InstallerTypeEnum::Portable); + REQUIRE(installer3.BaseInstallerType == InstallerTypeEnum::Portable); REQUIRE(installer3.Arch == Architecture::X86); REQUIRE(installer3.Url == "https://www.microsoft.com/msixsdk/msixsdkx86.exe"); REQUIRE(installer3.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82")); @@ -655,7 +655,7 @@ void VerifyV1ManifestContent(const Manifest& manifest, bool isSingleton, Manifes if (manifestVer >= ManifestVer{ s_ManifestVersionV1_3 }) { ManifestInstaller installer4 = manifest.Installers.at(3); - REQUIRE(installer4.InstallerType == InstallerTypeEnum::Zip); + REQUIRE(installer4.BaseInstallerType == InstallerTypeEnum::Zip); REQUIRE(installer4.Arch == Architecture::X64); REQUIRE(installer4.Url == "https://www.microsoft.com/msixsdk/msixsdkx64.exe"); REQUIRE(installer4.Sha256 == SHA256::ConvertToBytes("69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82")); diff --git a/src/AppInstallerCommonCore/Manifest/Manifest.cpp b/src/AppInstallerCommonCore/Manifest/Manifest.cpp index 9551945edb..17f244b8ac 100644 --- a/src/AppInstallerCommonCore/Manifest/Manifest.cpp +++ b/src/AppInstallerCommonCore/Manifest/Manifest.cpp @@ -94,7 +94,7 @@ namespace AppInstaller::Manifest for (auto const& installer : Installers) { - if (DoesInstallerSupportArpVersionRange(installer)) + if (DoesInstallerTypeSupportArpVersionRange(installer.EffectiveInstallerType())) { for (auto const& entry : installer.AppsAndFeaturesEntries) { diff --git a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp index b39ab329f5..11e863e6a5 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp @@ -35,17 +35,6 @@ namespace AppInstaller::Manifest return CompatibilitySet::None; } } - - InstallerTypeEnum GetInstallerTypeFromInstaller(ManifestInstaller installer) - { - InstallerTypeEnum installerType = installer.InstallerType; - if (IsArchiveType(installerType)) - { - installerType = installer.NestedInstallerType; - } - - return installerType; - } } ManifestVer::ManifestVer(std::string_view version) @@ -449,15 +438,13 @@ namespace AppInstaller::Manifest return "Unknown"sv; } - bool DoesInstallerUsePackageFamilyName(ManifestInstaller installer) + bool DoesInstallerTypeUsePackageFamilyName(InstallerTypeEnum installerType) { - InstallerTypeEnum installerType = GetInstallerTypeFromInstaller(installer); return (installerType == InstallerTypeEnum::Msix || installerType == InstallerTypeEnum::MSStore); } - bool DoesInstallerUseProductCode(ManifestInstaller installer) + bool DoesInstallerTypeUseProductCode(InstallerTypeEnum installerType) { - InstallerTypeEnum installerType = GetInstallerTypeFromInstaller(installer); return ( installerType == InstallerTypeEnum::Exe || installerType == InstallerTypeEnum::Inno || @@ -469,9 +456,8 @@ namespace AppInstaller::Manifest ); } - bool DoesInstallerWriteAppsAndFeaturesEntry(ManifestInstaller installer) + bool DoesInstallerTypeWriteAppsAndFeaturesEntry(InstallerTypeEnum installerType) { - InstallerTypeEnum installerType = GetInstallerTypeFromInstaller(installer); return ( installerType == InstallerTypeEnum::Exe || installerType == InstallerTypeEnum::Inno || @@ -483,12 +469,6 @@ namespace AppInstaller::Manifest ); } - bool DoesInstallerSupportArpVersionRange(ManifestInstaller installer) - { - InstallerTypeEnum installerType = GetInstallerTypeFromInstaller(installer); - return DoesInstallerTypeSupportArpVersionRange(installerType); - } - bool DoesInstallerTypeSupportArpVersionRange(InstallerTypeEnum installerType) { return ( @@ -501,9 +481,8 @@ namespace AppInstaller::Manifest ); } - bool DoesInstallerIgnoreScopeFromManifest(ManifestInstaller installer) + bool DoesInstallerIgnoreScopeFromManifest(InstallerTypeEnum installerType) { - InstallerTypeEnum installerType = GetInstallerTypeFromInstaller(installer); return ( installerType == InstallerTypeEnum::Portable ); diff --git a/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp b/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp index 1abd30fe4e..95fd057cee 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp @@ -42,9 +42,9 @@ namespace AppInstaller::Manifest // Todo: use the comparator from ManifestComparator when that one is fully implemented. auto installerCmp = [](const ManifestInstaller& in1, const ManifestInstaller& in2) { - if (in1.InstallerType != in2.InstallerType) + if (in1.EffectiveInstallerType() != in2.EffectiveInstallerType()) { - return in1.InstallerType < in2.InstallerType; + return in1.EffectiveInstallerType() < in2.EffectiveInstallerType(); } if (in1.Arch != in2.Arch) @@ -74,14 +74,14 @@ namespace AppInstaller::Manifest for (auto const& installer : manifest.Installers) { // If not full validation, for future compatibility, skip validating unknown installers. - if (installer.InstallerType == InstallerTypeEnum::Unknown && !fullValidation) + if (installer.EffectiveInstallerType() == InstallerTypeEnum::Unknown && !fullValidation) { continue; } if (!duplicateInstallerFound && !installerSet.insert(installer).second) { - AICLI_LOG(Core, Error, << "Duplicate installer: Type[" << InstallerTypeToString(installer.InstallerType) << + AICLI_LOG(Core, Error, << "Duplicate installer: Type[" << InstallerTypeToString(installer.EffectiveInstallerType()) << "] Architecture[" << Utility::ToString(installer.Arch) << "] Locale[" << installer.Locale << "] Scope[" << ScopeToString(installer.Scope) << "]"); @@ -94,7 +94,7 @@ namespace AppInstaller::Manifest resultErrors.emplace_back(ManifestError::InvalidFieldValue, "Architecture"); } - if (installer.InstallerType == InstallerTypeEnum::Unknown) + if (installer.EffectiveInstallerType() == InstallerTypeEnum::Unknown) { resultErrors.emplace_back(ManifestError::InvalidFieldValue, "InstallerType"); } @@ -106,29 +106,29 @@ namespace AppInstaller::Manifest // Validate system reference strings if they are set at the installer level // Allow PackageFamilyName to be declared with non msix installers to support nested installer scenarios after manifest version 1.1 - if (manifest.ManifestVersion <= ManifestVer{ s_ManifestVersionV1_1 } && !installer.PackageFamilyName.empty() && !DoesInstallerUsePackageFamilyName(installer)) + if (manifest.ManifestVersion <= ManifestVer{ s_ManifestVersionV1_1 } && !installer.PackageFamilyName.empty() && !DoesInstallerTypeUsePackageFamilyName(installer.EffectiveInstallerType())) { - resultErrors.emplace_back(ManifestError::InstallerTypeDoesNotSupportPackageFamilyName, "InstallerType", InstallerTypeToString(installer.InstallerType)); + resultErrors.emplace_back(ManifestError::InstallerTypeDoesNotSupportPackageFamilyName, "InstallerType", InstallerTypeToString(installer.EffectiveInstallerType())); } - if (!installer.ProductCode.empty() && !DoesInstallerUseProductCode(installer)) + if (!installer.ProductCode.empty() && !DoesInstallerTypeUseProductCode(installer.EffectiveInstallerType())) { - resultErrors.emplace_back(ManifestError::InstallerTypeDoesNotSupportProductCode, "InstallerType", InstallerTypeToString(installer.InstallerType)); + resultErrors.emplace_back(ManifestError::InstallerTypeDoesNotSupportProductCode, "InstallerType", InstallerTypeToString(installer.EffectiveInstallerType())); } - if (!installer.AppsAndFeaturesEntries.empty() && !DoesInstallerWriteAppsAndFeaturesEntry(installer)) + if (!installer.AppsAndFeaturesEntries.empty() && !DoesInstallerTypeWriteAppsAndFeaturesEntry(installer.EffectiveInstallerType())) { - resultErrors.emplace_back(ManifestError::InstallerTypeDoesNotWriteAppsAndFeaturesEntry, "InstallerType", InstallerTypeToString(installer.InstallerType)); + resultErrors.emplace_back(ManifestError::InstallerTypeDoesNotWriteAppsAndFeaturesEntry, "InstallerType", InstallerTypeToString(installer.EffectiveInstallerType())); } - if (installer.InstallerType == InstallerTypeEnum::MSStore) + if (installer.EffectiveInstallerType() == InstallerTypeEnum::MSStore) { if (fullValidation) { // MSStore type is not supported in community repo resultErrors.emplace_back( ManifestError::FieldValueNotSupported, "InstallerType", - InstallerTypeToString(installer.InstallerType)); + InstallerTypeToString(installer.EffectiveInstallerType())); } if (installer.ProductId.empty()) @@ -154,14 +154,14 @@ namespace AppInstaller::Manifest } } - if (installer.InstallerType == InstallerTypeEnum::Exe && + if (installer.EffectiveInstallerType() == InstallerTypeEnum::Exe && (installer.Switches.find(InstallerSwitchType::SilentWithProgress) == installer.Switches.end() || installer.Switches.find(InstallerSwitchType::Silent) == installer.Switches.end())) { resultErrors.emplace_back(ManifestError::ExeInstallerMissingSilentSwitches, ValidationError::Level::Warning); } - if (installer.InstallerType == InstallerTypeEnum::Portable) + if (installer.EffectiveInstallerType() == InstallerTypeEnum::Portable) { if (installer.AppsAndFeaturesEntries.size() > 1) { @@ -177,7 +177,7 @@ namespace AppInstaller::Manifest } } - if (IsArchiveType(installer.InstallerType)) + if (IsArchiveType(installer.BaseInstallerType)) { if (installer.NestedInstallerType == InstallerTypeEnum::Unknown) { @@ -304,7 +304,7 @@ namespace AppInstaller::Manifest for (const auto& installer : manifest.Installers) { // Installer msix or msixbundle - if (installer.InstallerType == InstallerTypeEnum::Msix) + if (installer.EffectiveInstallerType() == InstallerTypeEnum::Msix) { auto installerErrors = msixManifestValidation.Validate(manifest, installer); std::move(installerErrors.begin(), installerErrors.end(), std::inserter(errors, errors.end())); diff --git a/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp b/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp index 1436260a92..34a3bcc94c 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp @@ -187,7 +187,7 @@ namespace AppInstaller::Manifest // Common fields across versions std::vector result = { - { "InstallerType", [this](const YAML::Node& value)->ValidationErrors { m_p_installer->InstallerType = ConvertToInstallerTypeEnum(value.as()); return {}; } }, + { "InstallerType", [this](const YAML::Node& value)->ValidationErrors { m_p_installer->BaseInstallerType = ConvertToInstallerTypeEnum(value.as()); return {}; } }, { "PackageFamilyName", [this](const YAML::Node& value)->ValidationErrors { m_p_installer->PackageFamilyName = value.as(); return {}; } }, { "ProductCode", [this](const YAML::Node& value)->ValidationErrors { m_p_installer->ProductCode = value.as(); return {}; } }, }; @@ -922,22 +922,22 @@ namespace AppInstaller::Manifest std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); // Copy in system reference strings from the root if not set in the installer and appropriate - if (installer.PackageFamilyName.empty() && DoesInstallerUsePackageFamilyName(installer)) + if (installer.PackageFamilyName.empty() && DoesInstallerTypeUsePackageFamilyName(installer.EffectiveInstallerType())) { installer.PackageFamilyName = manifest.DefaultInstallerInfo.PackageFamilyName; } - if (installer.ProductCode.empty() && DoesInstallerUseProductCode(installer)) + if (installer.ProductCode.empty() && DoesInstallerTypeUseProductCode(installer.EffectiveInstallerType())) { installer.ProductCode = manifest.DefaultInstallerInfo.ProductCode; } - if (installer.AppsAndFeaturesEntries.empty() && DoesInstallerWriteAppsAndFeaturesEntry(installer)) + if (installer.AppsAndFeaturesEntries.empty() && DoesInstallerTypeWriteAppsAndFeaturesEntry(installer.EffectiveInstallerType())) { installer.AppsAndFeaturesEntries = manifest.DefaultInstallerInfo.AppsAndFeaturesEntries; } - if (IsArchiveType(installer.InstallerType)) + if (IsArchiveType(installer.BaseInstallerType)) { if (installer.NestedInstallerFiles.empty()) { @@ -957,7 +957,7 @@ namespace AppInstaller::Manifest } // Populate installer default switches if not exists - auto defaultSwitches = GetDefaultKnownSwitches(installer.InstallerType); + auto defaultSwitches = GetDefaultKnownSwitches(installer.EffectiveInstallerType()); for (auto const& defaultSwitch : defaultSwitches) { if (installer.Switches.find(defaultSwitch.first) == installer.Switches.end()) @@ -967,7 +967,7 @@ namespace AppInstaller::Manifest } // Populate installer default return codes if not present in ExpectedReturnCodes and InstallerSuccessCodes - auto defaultReturnCodes = GetDefaultKnownReturnCodes(installer.InstallerType); + auto defaultReturnCodes = GetDefaultKnownReturnCodes(installer.EffectiveInstallerType()); for (auto const& defaultReturnCode : defaultReturnCodes) { if (installer.ExpectedReturnCodes.find(defaultReturnCode.first) == installer.ExpectedReturnCodes.end() && diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h index 3116dc4c6c..0bcf7f29f0 100644 --- a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h +++ b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h @@ -303,22 +303,19 @@ namespace AppInstaller::Manifest std::string_view ScopeToString(ScopeEnum scope); // Gets a value indicating whether the given installer uses the PackageFamilyName system reference. - bool DoesInstallerUsePackageFamilyName(ManifestInstaller installer); + bool DoesInstallerTypeUsePackageFamilyName(InstallerTypeEnum installerType); // Gets a value indicating whether the given installer uses the ProductCode system reference. - bool DoesInstallerUseProductCode(ManifestInstaller installer); + bool DoesInstallerTypeUseProductCode(InstallerTypeEnum installerType); // Gets a value indicating whether the given installer writes ARP entry. - bool DoesInstallerWriteAppsAndFeaturesEntry(ManifestInstaller installer); - - // Gets a value indicating whether the given installer supports ARP version range. - bool DoesInstallerSupportArpVersionRange(ManifestInstaller installer); + bool DoesInstallerTypeWriteAppsAndFeaturesEntry(InstallerTypeEnum installerType); // Gets a value indicating whether the given installer type supports ARP version range. bool DoesInstallerTypeSupportArpVersionRange(InstallerTypeEnum installer); // Gets a value indicating whether the given installer ignores the Scope value from the manifest. - bool DoesInstallerIgnoreScopeFromManifest(ManifestInstaller installer); + bool DoesInstallerTypeIgnoreScopeFromManifest(InstallerTypeEnum installerType); // Gets a value indicating whether the given installer type is an archive. bool IsArchiveType(InstallerTypeEnum installerType); diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h b/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h index bad29be434..0f9112adaf 100644 --- a/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h +++ b/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h @@ -40,10 +40,15 @@ namespace AppInstaller::Manifest string_t MinOSVersion; // If present, has more precedence than root - InstallerTypeEnum InstallerType = InstallerTypeEnum::Unknown; + InstallerTypeEnum BaseInstallerType = InstallerTypeEnum::Unknown; InstallerTypeEnum NestedInstallerType = InstallerTypeEnum::Unknown; + InstallerTypeEnum EffectiveInstallerType() const + { + return IsArchiveType(BaseInstallerType) ? NestedInstallerType : BaseInstallerType; + } + std::vector NestedInstallerFiles; ScopeEnum Scope = ScopeEnum::Unknown; diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_0/Json/ManifestDeserializer_1_0.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_0/Json/ManifestDeserializer_1_0.cpp index ce7cc45762..af5e1b1fc1 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_0/Json/ManifestDeserializer_1_0.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_0/Json/ManifestDeserializer_1_0.cpp @@ -321,7 +321,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_0::Json AICLI_LOG(Repo, Error, << "Missing installer type."); return {}; } - installer.InstallerType = ConvertToInstallerType(installerType.value()); + installer.BaseInstallerType = ConvertToInstallerType(installerType.value()); installer.Locale = JSON::GetRawStringValueFromJsonNode(installerJsonObject, JSON::GetUtilityString(InstallerLocale)).value_or(""); // platform @@ -366,7 +366,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_0::Json } // Installer Switches - installer.Switches = Manifest::GetDefaultKnownSwitches(installer.InstallerType); + installer.Switches = Manifest::GetDefaultKnownSwitches(installer.BaseInstallerType); std::optional> switches = JSON::GetJsonValueFromNode(installerJsonObject, JSON::GetUtilityString(InstallerSwitches)); if (switches) diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp index faf5a64d9a..f9e0100649 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp @@ -158,7 +158,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_1::Json } // Populate installer default return codes if not present in ExpectedReturnCodes and InstallerSuccessCodes - auto defaultReturnCodes = GetDefaultKnownReturnCodes(installer.InstallerType); + auto defaultReturnCodes = GetDefaultKnownReturnCodes(installer.BaseInstallerType); for (auto const& defaultReturnCode : defaultReturnCodes) { if (installer.ExpectedReturnCodes.find(defaultReturnCode.first) == installer.ExpectedReturnCodes.end() && From 871ae240704925a01c896b427d63331fec07f26d Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Wed, 3 Aug 2022 15:08:57 -0700 Subject: [PATCH 2/5] finish changes and enable test --- src/AppInstallerCLIE2ETests/InstallCommand.cs | 12 +----------- src/AppInstallerCLIE2ETests/Test.runsettings | 4 +++- src/AppInstallerCLITests/RestInterface_1_0.cpp | 2 +- src/AppInstallerCLITests/RestInterface_1_1.cpp | 4 ++-- src/AppInstallerCLITests/WorkFlow.cpp | 2 +- .../Manifest/ManifestCommon.cpp | 2 +- .../Manifest/ManifestValidation.cpp | 13 +++++++++---- .../Schema/1_1/Json/ManifestDeserializer_1_1.cpp | 2 +- 8 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/AppInstallerCLIE2ETests/InstallCommand.cs b/src/AppInstallerCLIE2ETests/InstallCommand.cs index dc89c45304..503276b9eb 100644 --- a/src/AppInstallerCLIE2ETests/InstallCommand.cs +++ b/src/AppInstallerCLIE2ETests/InstallCommand.cs @@ -96,11 +96,6 @@ public void InstallNullSoft() [Test] public void InstallMSI() { - if (string.IsNullOrEmpty(TestCommon.MsiInstallerPath)) - { - Assert.Ignore("MSI installer not available"); - } - var installDir = TestCommon.GetRandomTestDir(); var result = TestCommon.RunAICLICommand("install", $"TestMsiInstaller --silent -l {installDir}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); @@ -355,14 +350,9 @@ public void InstallZipWithInvalidRelativeFilePath() Assert.True(result.StdOut.Contains("Invalid relative file path to the nested installer; path points to a location outside of the install directory")); } - [Test, Ignore("Re-enable as part of fixing #2392")] + [Test] public void InstallZipWithMsi() { - if (string.IsNullOrEmpty(TestCommon.MsiInstallerPath)) - { - Assert.Ignore("MSI installer not available"); - } - var installDir = TestCommon.GetRandomTestDir(); var result = TestCommon.RunAICLICommand("install", $"AppInstallerTest.TestZipInstallerWithMsi --silent -l {installDir}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); diff --git a/src/AppInstallerCLIE2ETests/Test.runsettings b/src/AppInstallerCLIE2ETests/Test.runsettings index 671fbed493..d28a7443e7 100644 --- a/src/AppInstallerCLIE2ETests/Test.runsettings +++ b/src/AppInstallerCLIE2ETests/Test.runsettings @@ -15,7 +15,8 @@ InvokeCommandInDesktopPackage: Bool to indicate using Invoke-CommandInDesktopPackage for test execution. This is used when AppExecutionAlias is not available, or disabled. StaticFileRootPath: Path to the set of static test files that will be served as the source for testing purposes. - MsixTestInstallerPath : The MSIX (or APPX) Installer executable under test. + MsiTestInstallerPath: The Msi Installer executable under test. + MsixTestInstallerPath: The MSIX (or APPX) Installer executable under test. ExeTestInstallerPath: The Exe Installer executable under test. PackageCertificatePath: Signing Certificate Path used to certify Index Source Package --> @@ -27,6 +28,7 @@ + diff --git a/src/AppInstallerCLITests/RestInterface_1_0.cpp b/src/AppInstallerCLITests/RestInterface_1_0.cpp index ff71a04205..ed266b6d7d 100644 --- a/src/AppInstallerCLITests/RestInterface_1_0.cpp +++ b/src/AppInstallerCLITests/RestInterface_1_0.cpp @@ -520,6 +520,6 @@ TEST_CASE("GetManifests_GoodResponse_UnknownInstaller", "[RestSource][Interface_ // Verify manifest is populated and manifest validation passed Manifest manifest = manifests[0]; REQUIRE(manifest.Installers.size() == 1); - REQUIRE(manifest.Installers.at(0).InstallerType == InstallerTypeEnum::Unknown); + REQUIRE(manifest.Installers.at(0).BaseInstallerType == InstallerTypeEnum::Unknown); REQUIRE(manifest.Installers.at(0).ProductId.empty()); } \ No newline at end of file diff --git a/src/AppInstallerCLITests/RestInterface_1_1.cpp b/src/AppInstallerCLITests/RestInterface_1_1.cpp index b53f2c1a61..77dd2c5fd7 100644 --- a/src/AppInstallerCLITests/RestInterface_1_1.cpp +++ b/src/AppInstallerCLITests/RestInterface_1_1.cpp @@ -494,7 +494,7 @@ TEST_CASE("GetManifests_GoodRequest_OnlyMarketRequired", "[RestSource][Interface REQUIRE(manifest.Installers.size() == 1); REQUIRE(manifest.Installers[0].Arch == Architecture::X64); REQUIRE(manifest.Installers[0].Sha256 == AppInstaller::Utility::SHA256::ConvertToBytes("011048877dfaef109801b3f3ab2b60afc74f3fc4f7b3430e0c897f5da1df84b6")); - REQUIRE(manifest.Installers[0].InstallerType == InstallerTypeEnum::Exe); + REQUIRE(manifest.Installers[0].BaseInstallerType == InstallerTypeEnum::Exe); REQUIRE(manifest.Installers[0].Url == "https://installer.example.com/foobar.exe"); } @@ -534,7 +534,7 @@ TEST_CASE("GetManifests_GoodResponse_MSStoreType", "[RestSource][Interface_1_1]" // Verify manifest is populated and manifest validation passed Manifest manifest = manifests[0]; REQUIRE(manifest.Installers.size() == 1); - REQUIRE(manifest.Installers.at(0).InstallerType == InstallerTypeEnum::MSStore); + REQUIRE(manifest.Installers.at(0).BaseInstallerType == InstallerTypeEnum::MSStore); REQUIRE(manifest.Installers.at(0).ProductId == "9nblggh4nns1"); } diff --git a/src/AppInstallerCLITests/WorkFlow.cpp b/src/AppInstallerCLITests/WorkFlow.cpp index 2eab2c28b1..a49adda074 100644 --- a/src/AppInstallerCLITests/WorkFlow.cpp +++ b/src/AppInstallerCLITests/WorkFlow.cpp @@ -191,7 +191,7 @@ namespace ResultMatch( TestPackage::Make( manifest, - TestPackage::MetadataMap{ { PackageVersionMetadata::InstalledType, "Zip" } }, + TestPackage::MetadataMap{ { PackageVersionMetadata::InstalledType, "Exe" } }, std::vector{ manifest2, manifest }, shared_from_this() ), diff --git a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp index 11e863e6a5..70fa00bb4a 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp @@ -481,7 +481,7 @@ namespace AppInstaller::Manifest ); } - bool DoesInstallerIgnoreScopeFromManifest(InstallerTypeEnum installerType) + bool DoesInstallerTypeIgnoreScopeFromManifest(InstallerTypeEnum installerType) { return ( installerType == InstallerTypeEnum::Portable diff --git a/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp b/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp index 95fd057cee..0370d46730 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp @@ -161,16 +161,21 @@ namespace AppInstaller::Manifest resultErrors.emplace_back(ManifestError::ExeInstallerMissingSilentSwitches, ValidationError::Level::Warning); } + // The command field restriction only applies if the base installer type is Portable. + if (installer.BaseInstallerType == InstallerTypeEnum::Portable) + { + if (installer.Commands.size() > 1) + { + resultErrors.emplace_back(ManifestError::ExceededCommandsLimit); + } + } + if (installer.EffectiveInstallerType() == InstallerTypeEnum::Portable) { if (installer.AppsAndFeaturesEntries.size() > 1) { resultErrors.emplace_back(ManifestError::ExceededAppsAndFeaturesEntryLimit); } - if (installer.Commands.size() > 1) - { - resultErrors.emplace_back(ManifestError::ExceededCommandsLimit); - } if (installer.Scope != ScopeEnum::Unknown) { resultErrors.emplace_back(ManifestError::ScopeNotSupported, ValidationError::Level::Warning); diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp index f9e0100649..fcc92ccf86 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp @@ -158,7 +158,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_1::Json } // Populate installer default return codes if not present in ExpectedReturnCodes and InstallerSuccessCodes - auto defaultReturnCodes = GetDefaultKnownReturnCodes(installer.BaseInstallerType); + auto defaultReturnCodes = GetDefaultKnownReturnCodes(installer.EffectiveInstallerType()); for (auto const& defaultReturnCode : defaultReturnCodes) { if (installer.ExpectedReturnCodes.find(defaultReturnCode.first) == installer.ExpectedReturnCodes.end() && From 6c27563168307dfc5bca7fdcb1f7da9d24bd351e Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Wed, 3 Aug 2022 15:14:55 -0700 Subject: [PATCH 3/5] revert to base installerType for 1.1 schema --- .../Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp index fcc92ccf86..f9e0100649 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp @@ -158,7 +158,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_1::Json } // Populate installer default return codes if not present in ExpectedReturnCodes and InstallerSuccessCodes - auto defaultReturnCodes = GetDefaultKnownReturnCodes(installer.EffectiveInstallerType()); + auto defaultReturnCodes = GetDefaultKnownReturnCodes(installer.BaseInstallerType); for (auto const& defaultReturnCode : defaultReturnCodes) { if (installer.ExpectedReturnCodes.find(defaultReturnCode.first) == installer.ExpectedReturnCodes.end() && From f58bda99144a529a84d1cd6818bbcb2a6acaacf7 Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Thu, 4 Aug 2022 16:58:32 -0700 Subject: [PATCH 4/5] add displayName --- src/AppInstallerCLIE2ETests/ListCommand.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/AppInstallerCLIE2ETests/ListCommand.cs b/src/AppInstallerCLIE2ETests/ListCommand.cs index a3858d95fc..5fa6197317 100644 --- a/src/AppInstallerCLIE2ETests/ListCommand.cs +++ b/src/AppInstallerCLIE2ETests/ListCommand.cs @@ -22,6 +22,8 @@ public void ListAfterInstall() string productCode = guid.ToString(); var installDir = TestCommon.GetRandomTestDir(); + // DisplayName must be set to avoid conflicts with other packages that use the same exe installer. + string displayName = "TestExeInstaller"; string localAppDataPath = System.Environment.GetEnvironmentVariable(Constants.LocalAppData); string logFilePath = System.IO.Path.Combine(localAppDataPath, Constants.E2ETestLogsPath); logFilePath = System.IO.Path.Combine(logFilePath, "ListAfterInstall-" + System.IO.Path.GetRandomFileName() + ".log"); @@ -29,7 +31,7 @@ public void ListAfterInstall() var result = TestCommon.RunAICLICommand("list", productCode); Assert.AreEqual(Constants.ErrorCode.ERROR_NO_APPLICATIONS_FOUND, result.ExitCode); - result = TestCommon.RunAICLICommand("install", $"AppInstallerTest.TestExeInstaller --override \"/InstallDir {installDir} /ProductID {productCode} /LogFile {logFilePath}\""); + result = TestCommon.RunAICLICommand("install", $"AppInstallerTest.TestExeInstaller --override \"/InstallDir {installDir} /ProductID {productCode} /LogFile {logFilePath} /DisplayName {displayName}\""); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); result = TestCommon.RunAICLICommand("list", productCode); From 96c42b9d8e36483de309f6db6bf450d0c373b575 Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Thu, 11 Aug 2022 13:11:00 -0700 Subject: [PATCH 5/5] address PR feedback --- src/AppInstallerCLICore/Resources.h | 1 + .../Workflows/ArchiveFlow.cpp | 7 +++ .../Workflows/ShowFlow.cpp | 13 ++++- .../Shared/Strings/en-us/winget.resw | 3 + .../AppInstallerCLITests.vcxproj | 3 + .../AppInstallerCLITests.vcxproj.filters | 3 + ...owTest_Zip_UnsupportedNestedInstaller.yaml | 21 +++++++ src/AppInstallerCLITests/WorkFlow.cpp | 57 +++++++++++++++++++ .../Manifest/ManifestCommon.cpp | 14 +++++ .../Public/winget/ManifestCommon.h | 3 + .../1_0/Json/ManifestDeserializer_1_0.cpp | 2 +- .../1_1/Json/ManifestDeserializer_1_1.cpp | 2 +- 12 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 src/AppInstallerCLITests/TestData/InstallFlowTest_Zip_UnsupportedNestedInstaller.yaml diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index a445a33960..2367f53d76 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -195,6 +195,7 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(NameArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(NestedInstallerNotFound); WINGET_DEFINE_RESOURCE_STRINGID(NestedInstallerNotSpecified); + WINGET_DEFINE_RESOURCE_STRINGID(NestedInstallerNotSupported); WINGET_DEFINE_RESOURCE_STRINGID(NoApplicableInstallers); WINGET_DEFINE_RESOURCE_STRINGID(NoExperimentalFeaturesMessage); WINGET_DEFINE_RESOURCE_STRINGID(NoInstalledPackageFound); diff --git a/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp b/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp index 5d92da9d0b..3f11a0430d 100644 --- a/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp @@ -71,6 +71,13 @@ namespace AppInstaller::CLI::Workflow if (IsArchiveType(installer.BaseInstallerType)) { + if (!IsNestedInstallerTypeSupported(installer.NestedInstallerType)) + { + AICLI_LOG(CLI, Error, << "Nested installer type not supported: " << installer.NestedInstallerType); + context.Reporter.Error() << Resource::String::NestedInstallerNotSupported << std::endl; + AICLI_TERMINATE_CONTEXT(ERROR_NOT_SUPPORTED); + } + auto const& nestedInstallerFiles = installer.NestedInstallerFiles; if (nestedInstallerFiles.empty()) { diff --git a/src/AppInstallerCLICore/Workflows/ShowFlow.cpp b/src/AppInstallerCLICore/Workflows/ShowFlow.cpp index ec7e07342e..5cb7a910c3 100644 --- a/src/AppInstallerCLICore/Workflows/ShowFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/ShowFlow.cpp @@ -173,7 +173,18 @@ namespace AppInstaller::CLI::Workflow info << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelInstaller << std::endl; if (installer) { - info << " "_liv << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelInstallerType << ' ' << Manifest::InstallerTypeToString(installer->BaseInstallerType) << std::endl; + Manifest::InstallerTypeEnum effectiveInstallerType = installer->EffectiveInstallerType(); + Manifest::InstallerTypeEnum baseInstallerType = installer->BaseInstallerType; + if (effectiveInstallerType == baseInstallerType) + { + info << " "_liv << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelInstallerType << ' ' << Manifest::InstallerTypeToString(effectiveInstallerType) << std::endl; + } + else + { + info << " "_liv << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelInstallerType << ' ' << Manifest::InstallerTypeToString(effectiveInstallerType) << " (" << + Manifest::InstallerTypeToString(baseInstallerType) << ')' << std::endl; + } + if (!installer->Locale.empty()) { info << " "_liv << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelInstallerLocale << ' ' << installer->Locale << std::endl; diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index 2eed8113b5..f5705c9943 100644 --- a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +++ b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -1397,4 +1397,7 @@ Please specify one of them using the `--source` option to proceed. The following packages have an upgrade available, but require explicit targeting for upgrade: "require explicit targeting for upgrade" means that the package will not be upgraded with all others unless an extra flag is added, or the package is mentioned explicitly + + The nested installer type is not supported + \ No newline at end of file diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj index be21310a47..ede8a06710 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -298,6 +298,9 @@ true + + true + true diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters index 6dd121187b..39c1c9e126 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters @@ -531,6 +531,9 @@ TestData + + TestData + TestData diff --git a/src/AppInstallerCLITests/TestData/InstallFlowTest_Zip_UnsupportedNestedInstaller.yaml b/src/AppInstallerCLITests/TestData/InstallFlowTest_Zip_UnsupportedNestedInstaller.yaml new file mode 100644 index 0000000000..8ac2938fd1 --- /dev/null +++ b/src/AppInstallerCLITests/TestData/InstallFlowTest_Zip_UnsupportedNestedInstaller.yaml @@ -0,0 +1,21 @@ +PackageIdentifier: AppInstallerCliTest.TestZipInstaller +PackageVersion: 1.0.0.0 +PackageLocale: en-US +PackageName: AppInstaller Test Zip Installer +ShortDescription: AppInstaller Test Zip Installer with exe +Publisher: Microsoft Corporation +Moniker: AICLITestZip +License: Test +Installers: + - Architecture: x86 + InstallerUrl: https://ThisIsNotUsed + InstallerType: zip + InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B + NestedInstallerType: msstore + InstallerSwitches: + Custom: /custom /scope=machine + SilentWithProgress: /silentwithprogress + Silent: /silence + Update: /update +ManifestType: singleton +ManifestVersion: 1.3.0 \ No newline at end of file diff --git a/src/AppInstallerCLITests/WorkFlow.cpp b/src/AppInstallerCLITests/WorkFlow.cpp index d61cc2c118..cefc35414d 100644 --- a/src/AppInstallerCLITests/WorkFlow.cpp +++ b/src/AppInstallerCLITests/WorkFlow.cpp @@ -1090,6 +1090,28 @@ TEST_CASE("InstallFlow_Zip_MissingNestedInstaller", "[InstallFlow][workflow]") REQUIRE(installOutput.str().find(Resource::LocString(Resource::String::NestedInstallerNotSpecified).get()) != std::string::npos); } +TEST_CASE("InstallFlow_Zip_UnsupportedNestedInstaller", "[InstallFlow][workflow]") +{ + TestCommon::TempFile installResultPath("TestExeInstalled.txt"); + TestCommon::TestUserSettings testSettings; + testSettings.Set(true); + + std::ostringstream installOutput; + TestContext context{ installOutput, std::cin }; + auto previousThreadGlobals = context.SetForCurrentThread(); + context.Args.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_Zip_UnsupportedNestedInstaller.yaml").GetPath().u8string()); + + InstallCommand install({}); + install.Execute(context); + INFO(installOutput.str()); + + REQUIRE_TERMINATED_WITH(context, ERROR_NOT_SUPPORTED); + + // Verify Installer was not called + REQUIRE(!std::filesystem::exists(installResultPath.GetPath())); + REQUIRE(installOutput.str().find(Resource::LocString(Resource::String::NestedInstallerNotSupported).get()) != std::string::npos); +} + TEST_CASE("InstallFlow_Zip_MultipleNonPortableNestedInstallers", "[InstallFlow][workflow]") { TestCommon::TempFile installResultPath("TestExeInstalled.txt"); @@ -1657,6 +1679,41 @@ TEST_CASE("ShowFlow_Dependencies", "[ShowFlow][workflow][dependencies]") REQUIRE(showOutput.str().find("ExternalDep") != std::string::npos); } +TEST_CASE("ShowFlow_InstallerType", "[ShowFlow][workflow]") +{ + std::ostringstream showOutput; + TestContext context{ showOutput, std::cin }; + auto previousThreadGlobals = context.SetForCurrentThread(); + context.Args.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_Exe.yaml").GetPath().u8string()); + + ShowCommand show({}); + show.Execute(context); + INFO(showOutput.str()); + + // Verify that just the base installed type is shown; + REQUIRE(showOutput.str().find(Resource::LocString(Resource::String::ShowLabelInstallerType)) != std::string::npos); + REQUIRE(showOutput.str().find("exe") != std::string::npos); + + // If the base installer is incorrectly shown, an open parenthesis would appear after the effective installer type + REQUIRE(showOutput.str().find("exe (") == std::string::npos); +} + +TEST_CASE("ShowFlow_NestedInstallerType", "[ShowFlow][workflow]") +{ + std::ostringstream showOutput; + TestContext context{ showOutput, std::cin }; + auto previousThreadGlobals = context.SetForCurrentThread(); + context.Args.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_ZipWithExe.yaml").GetPath().u8string()); + + ShowCommand show({}); + show.Execute(context); + INFO(showOutput.str()); + + // Verify that both the effective and base installer types are shown + REQUIRE(showOutput.str().find(Resource::LocString(Resource::String::ShowLabelInstallerType)) != std::string::npos); + REQUIRE(showOutput.str().find("exe (zip)") != std::string::npos); +} + TEST_CASE("DependencyGraph_SkipInstalled", "[InstallFlow][workflow][dependencyGraph][dependencies]") { TestCommon::TempFile installResultPath("TestExeInstalled.txt"); diff --git a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp index 70fa00bb4a..c3cc446767 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp @@ -493,6 +493,20 @@ namespace AppInstaller::Manifest return (installerType == InstallerTypeEnum::Zip); } + bool IsNestedInstallerTypeSupported(InstallerTypeEnum nestedInstallerType) + { + return ( + nestedInstallerType == InstallerTypeEnum::Exe || + nestedInstallerType == InstallerTypeEnum::Inno || + nestedInstallerType == InstallerTypeEnum::Msi || + nestedInstallerType == InstallerTypeEnum::Nullsoft || + nestedInstallerType == InstallerTypeEnum::Wix || + nestedInstallerType == InstallerTypeEnum::Burn || + nestedInstallerType == InstallerTypeEnum::Portable || + nestedInstallerType == InstallerTypeEnum::Msix + ); + } + bool IsInstallerTypeCompatible(InstallerTypeEnum type1, InstallerTypeEnum type2) { // Unknown type cannot be compatible with any other diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h index 0bcf7f29f0..70ac9ac74d 100644 --- a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h +++ b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h @@ -320,6 +320,9 @@ namespace AppInstaller::Manifest // Gets a value indicating whether the given installer type is an archive. bool IsArchiveType(InstallerTypeEnum installerType); + // Gets a value indicating whether the given nested installer type is supported. + bool IsNestedInstallerTypeSupported(InstallerTypeEnum nestedInstallerType); + // Checks whether 2 installer types are compatible. E.g. inno and exe are update compatible bool IsInstallerTypeCompatible(InstallerTypeEnum type1, InstallerTypeEnum type2); diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_0/Json/ManifestDeserializer_1_0.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_0/Json/ManifestDeserializer_1_0.cpp index af5e1b1fc1..532d4f3715 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_0/Json/ManifestDeserializer_1_0.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_0/Json/ManifestDeserializer_1_0.cpp @@ -366,7 +366,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_0::Json } // Installer Switches - installer.Switches = Manifest::GetDefaultKnownSwitches(installer.BaseInstallerType); + installer.Switches = Manifest::GetDefaultKnownSwitches(installer.EffectiveInstallerType()); std::optional> switches = JSON::GetJsonValueFromNode(installerJsonObject, JSON::GetUtilityString(InstallerSwitches)); if (switches) diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp index f9e0100649..fcc92ccf86 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp @@ -158,7 +158,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_1::Json } // Populate installer default return codes if not present in ExpectedReturnCodes and InstallerSuccessCodes - auto defaultReturnCodes = GetDefaultKnownReturnCodes(installer.BaseInstallerType); + auto defaultReturnCodes = GetDefaultKnownReturnCodes(installer.EffectiveInstallerType()); for (auto const& defaultReturnCode : defaultReturnCodes) { if (installer.ExpectedReturnCodes.find(defaultReturnCode.first) == installer.ExpectedReturnCodes.end() &&