Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add upgrade functionality in Com api #1853

Merged
merged 4 commits into from
Jan 21, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/AppInstallerCLICore/Commands/COMInstallCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ namespace AppInstaller::CLI
void COMInstallCommand::ExecuteInternal(Context& context) const
{
context <<
Workflow::GetInstallerHash <<
Workflow::VerifyInstallerHash <<
Workflow::ReverifyInstallerHash <<
Copy link
Member

@JohnMcPMS JohnMcPMS Jan 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This seems overly aggressive on combining tasks. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll leave it as is for bug fix now

Workflow::InstallPackageInstaller;
}
}
4 changes: 3 additions & 1 deletion src/AppInstallerCLICore/Workflows/DownloadFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ namespace AppInstaller::CLI::Workflow
}
}

void GetInstallerHash(Execution::Context& context)
void ReverifyInstallerHash(Execution::Context& context)
{
const auto& installer = context.Get<Execution::Data::Installer>().value();

Expand Down Expand Up @@ -490,6 +490,8 @@ namespace AppInstaller::CLI::Workflow
AICLI_LOG(CLI, Error, << "Installer file not found.");
AICLI_TERMINATE_CONTEXT(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
}

context << VerifyInstallerHash;
}

void RenameDownloadedInstaller(Execution::Context& context)
Expand Down
5 changes: 2 additions & 3 deletions src/AppInstallerCLICore/Workflows/DownloadFlow.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,11 @@ namespace AppInstaller::CLI::Workflow
// Outputs: HashPair
void GetMsixSignatureHash(Execution::Context& context);

// Gets the hash of the downloaded installer.
// Downloading already computes the hash, so this is only needed to re-verify the installer hash.
// Re-verify the installer hash. This is used in Com install commands where download and install are in separate phases.
// Required Args: None
// Inputs: InstallerPath, Installer
// Outputs: HashPair
void GetInstallerHash(Execution::Context& context);
void ReverifyInstallerHash(Execution::Context& context);

// Verifies that the downloaded installer hash matches the hash in the manifest.
// Required Args: None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,12 @@ namespace winrt::Microsoft::Management::Deployment::implementation
{
throw hresult_not_implemented();
}
bool InstallOptions::AllowUpgradeToUnknownVersion()
{
throw hresult_not_implemented();
}
void InstallOptions::AllowUpgradeToUnknownVersion(bool)
{
throw hresult_not_implemented();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation
{
throw hresult_not_implemented();
}

winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::InstallResult, winrt::Microsoft::Management::Deployment::InstallProgress> PackageManager::UpgradePackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::InstallOptions)
{
throw hresult_not_implemented();
}
}
2 changes: 1 addition & 1 deletion src/Microsoft.Management.Deployment/CatalogPackage.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
winrt::Microsoft::Management::Deployment::PackageVersionInfo DefaultInstallVersion();
winrt::Microsoft::Management::Deployment::PackageVersionInfo GetPackageVersionInfo(winrt::Microsoft::Management::Deployment::PackageVersionId const& versionKey);
bool IsUpdateAvailable();

#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
private:
::AppInstaller::Repository::Source m_source;
Expand Down
3 changes: 3 additions & 0 deletions src/Microsoft.Management.Deployment/Converters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ namespace winrt::Microsoft::Management::Deployment::implementation
case APPINSTALLER_CLI_ERROR_NO_APPLICABLE_INSTALLER:
resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::NoApplicableInstallers;
break;
case APPINSTALLER_CLI_ERROR_UPDATE_NOT_APPLICABLE:
resultStatus = winrt::Microsoft::Management::Deployment::InstallResultStatus::NoApplicableUpgrade;
break;
case APPINSTALLER_CLI_ERROR_CANNOT_WRITE_TO_UPLEVEL_INDEX:
case APPINSTALLER_CLI_ERROR_INDEX_INTEGRITY_COMPROMISED:
case APPINSTALLER_CLI_ERROR_YAML_INIT_FAILED:
Expand Down
8 changes: 8 additions & 0 deletions src/Microsoft.Management.Deployment/InstallOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ namespace winrt::Microsoft::Management::Deployment::implementation
{
return m_allowedArchitectures;
}
bool InstallOptions::AllowUpgradeToUnknownVersion()
{
return m_allowUpgradeToUnknownVersion;
}
void InstallOptions::AllowUpgradeToUnknownVersion(bool value)
{
m_allowUpgradeToUnknownVersion = value;
}

CoCreatableMicrosoftManagementDeploymentClass(InstallOptions);
}
3 changes: 3 additions & 0 deletions src/Microsoft.Management.Deployment/InstallOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation
hstring AdditionalPackageCatalogArguments();
void AdditionalPackageCatalogArguments(hstring const& value);
winrt::Windows::Foundation::Collections::IVector<winrt::Windows::System::ProcessorArchitecture> AllowedArchitectures();
bool AllowUpgradeToUnknownVersion();
void AllowUpgradeToUnknownVersion(bool value);

#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
private:
Expand All @@ -47,6 +49,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
std::wstring m_additionalPackageCatalogArguments = L"";
Windows::Foundation::Collections::IVector<Windows::System::ProcessorArchitecture> m_allowedArchitectures{
winrt::single_threaded_vector<winrt::Windows::System::ProcessorArchitecture>() };
bool m_allowUpgradeToUnknownVersion = false;
#endif
};
}
Expand Down
56 changes: 55 additions & 1 deletion src/Microsoft.Management.Deployment/PackageManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ namespace winrt::Microsoft::Management::Deployment::implementation
Microsoft::Management::Deployment::PackageVersionInfo packageVersionInfo = GetPackageVersionInfo(package, options);
AddPackageManifestToContext(packageVersionInfo, context.get());

// If the installer has dependencies, DependencySource needs to be set.
Copy link
Member

@JohnMcPMS JohnMcPMS Jan 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there not a way that we can set the actual Source object rather than adding an argument? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's my test manifest is pointing to invalid dependencies. I'll remove this line as it's unnecessary.

context->Args.AddArg(Execution::Args::Type::DependencySource, ::AppInstaller::Utility::ConvertToUTF8(packageVersionInfo.PackageCatalog().Info().Name()));

// Note: AdditionalPackageCatalogArguments is not needed during install since the manifest is already known so no additional calls to the source are needed. The property is deprecated.
return context;
}
Expand Down Expand Up @@ -402,7 +405,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation
std::shared_ptr<Execution::OrchestratorQueueItem> queueItemParam,
winrt::Microsoft::Management::Deployment::CatalogPackage package = nullptr,
winrt::Microsoft::Management::Deployment::InstallOptions options = nullptr,
std::wstring callerProcessInfoString = {})
std::wstring callerProcessInfoString = {},
bool isUpgrade = false)
{
winrt::hresult terminationHR = S_OK;
hstring correlationData = (options) ? options.CorrelationData() : L"";
Expand All @@ -422,6 +426,30 @@ namespace winrt::Microsoft::Management::Deployment::implementation
{
Microsoft::Management::Deployment::PackageVersionInfo packageVersionInfo = GetPackageVersionInfo(package, options);
std::unique_ptr<COMContext> comContext = CreateContextFromInstallOptions(package, options, callerProcessInfoString);

if (isUpgrade)
{
AppInstaller::Utility::VersionAndChannel installedVersion{ winrt::to_string(package.InstalledVersion().Version()), winrt::to_string(package.InstalledVersion().Channel()) };
AppInstaller::Utility::VersionAndChannel upgradeVersion{ winrt::to_string(packageVersionInfo.Version()), winrt::to_string(packageVersionInfo.Channel()) };

if (installedVersion.IsUpdatedBy(upgradeVersion) ||
(options.AllowUpgradeToUnknownVersion() &&
AppInstaller::Utility::ICUCaseInsensitiveEquals(installedVersion.GetChannel().ToString(), upgradeVersion.GetChannel().ToString()) &&
upgradeVersion.GetVersion().IsUnknown()))
{
// Set upgrade flag
comContext->SetFlags(AppInstaller::CLI::Execution::ContextFlag::InstallerExecutionUseUpdate);
// Add installed version
winrt::Microsoft::Management::Deployment::implementation::PackageVersionInfo* installedVersionInfoImpl = get_self<winrt::Microsoft::Management::Deployment::implementation::PackageVersionInfo>(package.InstalledVersion());
std::shared_ptr<::AppInstaller::Repository::IPackageVersion> internalInstalledVersion = installedVersionInfoImpl->GetRepositoryPackageVersion();
comContext->Add<AppInstaller::CLI::Execution::Data::InstalledPackageVersion>(internalInstalledVersion);
}
else
{
co_return GetInstallResult(executionStage, APPINSTALLER_CLI_ERROR_UPDATE_NOT_APPLICABLE, correlationData, false);
Copy link
Member

@JohnMcPMS JohnMcPMS Jan 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we might need to break down the specific cases more for these errors. Specifically, I'm concerned about overloading this error (based on what I think is returning it, so I could be wrong). If the update does not have an applicable installer, do we get this error?

If the caller gives us a version that is less than or equal to the current version, should we have a different error? If the caller does not give us a version, but the latest version is already installed, what error will be produced, if any?
#Resolved

}
}

queueItem = Execution::OrchestratorQueueItemFactory::CreateItemForInstall(std::wstring{ package.Id() }, std::wstring{ packageVersionInfo.PackageCatalog().Info().Id() }, std::move(comContext));
Execution::ContextOrchestrator::Instance().EnqueueAndRunItem(queueItem);

Expand Down Expand Up @@ -552,6 +580,32 @@ namespace winrt::Microsoft::Management::Deployment::implementation
return GetInstallOperation(true /*canCancelQueueItem*/, nullptr /*queueItem*/, package, options, std::move(callerProcessInfoString));
}

winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::InstallResult, winrt::Microsoft::Management::Deployment::InstallProgress> PackageManager::UpgradePackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::InstallOptions options)
{
hstring correlationData = (options) ? options.CorrelationData() : L"";

// options and catalog can both be null, package must be set.
WINGET_RETURN_INSTALL_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package);
// the package should have an installed version to be upgraded.
WINGET_RETURN_INSTALL_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package.InstalledVersion());

HRESULT hr = S_OK;
std::wstring callerProcessInfoString;
try
{
// Check for permissions and get caller info for telemetry.
// This must be done before any co_awaits since it requires info from the rpc caller thread.
auto [hrGetCallerId, callerProcessId] = GetCallerProcessId();
WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(hrGetCallerId);
WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(EnsureProcessHasCapability(Capability::PackageManagement, callerProcessId));
callerProcessInfoString = TryGetCallerProcessInfo(callerProcessId);
}
WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED);
WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(hr);

return GetInstallOperation(true /*canCancelQueueItem*/, nullptr /*queueItem*/, package, options, std::move(callerProcessInfoString), true /* isUpgrade */);
}

winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::InstallResult, winrt::Microsoft::Management::Deployment::InstallProgress> PackageManager::GetInstallProgress(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::PackageCatalogInfo catalogInfo)
{
hstring correlationData;
Expand Down
5 changes: 4 additions & 1 deletion src/Microsoft.Management.Deployment/PackageManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ namespace winrt::Microsoft::Management::Deployment::implementation
winrt::Microsoft::Management::Deployment::PackageCatalogReference CreateCompositePackageCatalog(winrt::Microsoft::Management::Deployment::CreateCompositePackageCatalogOptions const& options);
winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::InstallResult, winrt::Microsoft::Management::Deployment::InstallProgress>
InstallPackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::InstallOptions options);
//Contract 2.0
// Contract 2.0
winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::InstallResult, winrt::Microsoft::Management::Deployment::InstallProgress>
GetInstallProgress(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::PackageCatalogInfo catalogInfo);
// Contract 4.0
Copy link
Member

@JohnMcPMS JohnMcPMS Jan 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to 3? Was that the enum value I added? #Resolved

winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::InstallResult, winrt::Microsoft::Management::Deployment::InstallProgress>
UpgradePackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::InstallOptions options);
};
}

Expand Down
15 changes: 14 additions & 1 deletion src/Microsoft.Management.Deployment/PackageManager.idl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT License.
namespace Microsoft.Management.Deployment
{
[contractversion(3)]
[contractversion(4)]
apicontract WindowsPackageManagerContract{};

/// State of the install.
Expand Down Expand Up @@ -59,6 +59,7 @@ namespace Microsoft.Management.Deployment
InstallError,
ManifestError,
NoApplicableInstallers,
NoApplicableUpgrade,
};

/// Result of the install
Expand Down Expand Up @@ -525,6 +526,12 @@ namespace Microsoft.Management.Deployment
// architecture after the first will simply be ignored.
Windows.Foundation.Collections.IVector<Windows.System.ProcessorArchitecture> AllowedArchitectures { get; };
}

[contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 4)]
{
/// Allow the upgrade to continue for upgrade packages with manifest versions Unknown.
Boolean AllowUpgradeToUnknownVersion;
}
}

[contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)]
Expand Down Expand Up @@ -554,6 +561,12 @@ namespace Microsoft.Management.Deployment
/// Get install progress
Windows.Foundation.IAsyncOperationWithProgress<InstallResult, InstallProgress> GetInstallProgress(CatalogPackage package, PackageCatalogInfo catalogInfo);
}

[contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 4)]
{
/// Upgrade the specified package
Windows.Foundation.IAsyncOperationWithProgress<InstallResult, InstallProgress> UpgradePackageAsync(CatalogPackage package, InstallOptions options);
}
}

/// Force midl3 to generate vector marshalling info.
Expand Down