commit 9dcbf99b2831af395fc996917da7dfe8fc085ffc
parent 8650938fa43524e009013f5d3255c52206732bad
Author: Chacón <lechacon@users.noreply.github.com>
Date: Wed, 19 Jan 2022 18:32:45 -0800
Allow upgrades in packages that register a different installer type (#1796)
* Modified the applicability check in `InstalledTypeComparator` to also consider the installer types listed under `AppsAndFeaturesEntries`
* Extended string returned from `ExplainInapplicable` to also mention the installed type and other types accepted by the manifest.
Closes #1242. Validated that upgrading PowerToys (mentioned in that issue) worked correctly using a local manifest edited to include the `AppsAndFeaturesEntries` and installed type `msi`.
Diffstat:
5 files changed, 88 insertions(+), 2 deletions(-)
diff --git a/src/AppInstallerCLICore/Workflows/ManifestComparator.cpp b/src/AppInstallerCLICore/Workflows/ManifestComparator.cpp
@@ -210,18 +210,40 @@ 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))
{
return InapplicabilityFlags::None;
}
+ auto itr = std::find_if(
+ installer.AppsAndFeaturesEntries.begin(),
+ installer.AppsAndFeaturesEntries.end(),
+ [=](AppsAndFeaturesEntry arpEntry) { return Manifest::IsInstallerTypeCompatible(arpEntry.InstallerType, m_installedType); });
+ if (itr != installer.AppsAndFeaturesEntries.end())
+ {
+ return InapplicabilityFlags::None;
+ }
+
return InapplicabilityFlags::InstalledType;
}
std::string ExplainInapplicable(const Manifest::ManifestInstaller& installer) override
{
- std::string result = "Installed package type is not compatible with ";
- result += Manifest::InstallerTypeToString(installer.InstallerType);
+ std::string result = "Installed package type '" + std::string{ Manifest::InstallerTypeToString(m_installedType) } +
+ "' is not compatible with installer type " + std::string{ Manifest::InstallerTypeToString(installer.InstallerType) };
+
+ std::string arpInstallerTypes;
+ for (const auto& entry : installer.AppsAndFeaturesEntries)
+ {
+ arpInstallerTypes += " " + std::string{ Manifest::InstallerTypeToString(entry.InstallerType) };
+ }
+
+ if (!arpInstallerTypes.empty())
+ {
+ result += ", or with accepted type(s)" + arpInstallerTypes;
+ }
+
return result;
}
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
@@ -515,6 +515,9 @@
<CopyFileToFolders Include="TestData\UpdateFlowTest_Exe.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
+ <CopyFileToFolders Include="TestData\UpdateFlowTest_Exe_ARPInstallerType.yaml">
+ <DeploymentContent>true</DeploymentContent>
+ </CopyFileToFolders>
<CopyFileToFolders Include="TestData\UpdateFlowTest_Exe_2.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
@@ -435,6 +435,9 @@
<CopyFileToFolders Include="TestData\UpdateFlowTest_Exe.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
+ <CopyFileToFolders Include="TestData\UpdateFlowTest_Exe_ARPInstallerType.yaml">
+ <Filter>TestData</Filter>
+ </CopyFileToFolders>
<CopyFileToFolders Include="TestData\UpdateFlowTest_Exe_2.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
diff --git a/src/AppInstallerCLITests/TestData/UpdateFlowTest_Exe_ARPInstallerType.yaml b/src/AppInstallerCLITests/TestData/UpdateFlowTest_Exe_ARPInstallerType.yaml
@@ -0,0 +1,22 @@
+# Similar content to UpdateFlowTest_Exe.yaml, but with an AppsAndFeaturesEntry specifying installer type
+PackageIdentifier: AppInstallerCliTest.TestExeInstaller
+PackageVersion: 2.0.0.0
+PackageLocale: en-US
+PackageName: AppInstaller Test Installer
+Publisher: Microsoft Corporation
+Moniker: AICLITestExe
+License: Test
+AppsAndFeaturesEntries:
+ - InstallerType: msix
+InstallerSwitches:
+ Custom: /custom /ver2.0.0.0
+ SilentWithProgress: /silentwithprogress
+ Silent: /silence
+ Update: /update
+Installers:
+ - Architecture: x86
+ InstallerUrl: https://ThisIsNotUsed
+ InstallerType: exe
+ InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
+ManifestType: singleton
+ManifestVersion: 1.1.0
diff --git a/src/AppInstallerCLITests/WorkFlow.cpp b/src/AppInstallerCLITests/WorkFlow.cpp
@@ -210,6 +210,21 @@ namespace
PackageMatchFilter(PackageMatchField::Id, MatchType::Exact, "AppInstallerCliTest.TestExeInstaller")));
}
+ if (input == "TestExeInstallerWithDifferentInstalledType")
+ {
+ auto manifest = YamlParser::CreateFromPath(TestDataFile("InstallFlowTest_Exe.yaml"));
+ auto manifest2 = YamlParser::CreateFromPath(TestDataFile("UpdateFlowTest_Exe_ARPInstallerType.yaml"));
+ result.Matches.emplace_back(
+ ResultMatch(
+ TestPackage::Make(
+ manifest,
+ TestPackage::MetadataMap{ { PackageVersionMetadata::InstalledType, "Msix" } },
+ std::vector<Manifest>{ manifest2, manifest },
+ shared_from_this()
+ ),
+ PackageMatchFilter(PackageMatchField::Id, MatchType::Exact, "AppInstallerCliTest.TestExeInstaller")));
+ }
+
if (input == "TestExeInstallerWithNothingInstalled")
{
auto manifest = YamlParser::CreateFromPath(TestDataFile("InstallFlowTest_Exe.yaml"));
@@ -1495,6 +1510,27 @@ TEST_CASE("UpdateFlow_UpdateExeInstallerTypeNotApplicableSpecificVersion", "[Upd
REQUIRE(context.GetTerminationHR() == APPINSTALLER_CLI_ERROR_UPDATE_NOT_APPLICABLE);
}
+TEST_CASE("UpdateFlow_UpdateExeWithDifferentInstalledType", "[UpdateFlow][workflow]")
+{
+ // Tests installer applicability when installed type is different but listed in the manifest
+ TestCommon::TempFile updateResultPath("TestExeInstalled.txt");
+
+ std::ostringstream updateOutput;
+ TestContext context{ updateOutput, std::cin };
+ auto previousThreadGlobals = context.SetForCurrentThread();
+ OverrideForCompositeInstalledSource(context);
+ OverrideForShellExecute(context);
+ context.Args.AddArg(Execution::Args::Type::Query, "TestExeInstallerWithDifferentInstalledType"sv);
+
+ UpgradeCommand update({});
+ update.Execute(context);
+ INFO(updateOutput.str());
+
+ // Verify Installer is called.
+ REQUIRE(context.GetTerminationHR() == S_OK);
+ REQUIRE(std::filesystem::exists(updateResultPath.GetPath()));
+}
+
TEST_CASE("UpdateFlow_UpdateExeSpecificVersionNotFound", "[UpdateFlow][workflow]")
{
TestCommon::TempFile updateResultPath("TestExeInstalled.txt");