Skip to content

Commit

Permalink
Allow upgrades in packages that register a different installer type (#…
Browse files Browse the repository at this point in the history
…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`.
  • Loading branch information
Chacón authored Jan 20, 2022
1 parent 8650938 commit 9dcbf99
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 2 deletions.
26 changes: 24 additions & 2 deletions src/AppInstallerCLICore/Workflows/ManifestComparator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
3 changes: 3 additions & 0 deletions src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
3 changes: 3 additions & 0 deletions src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
@@ -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
36 changes: 36 additions & 0 deletions src/AppInstallerCLITests/WorkFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down Expand Up @@ -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");
Expand Down

0 comments on commit 9dcbf99

Please sign in to comment.