winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 76d92152cb131572a1d5dbbec98e04f33bd2c985
parent 1ea38f17a42e55a5bdef1badebe5fcb770f6689d
Author: JohnMcPMS <johnmcp@microsoft.com>
Date:   Mon,  6 Apr 2020 23:45:37 -0700

Show wil exceptions to the user in a cleaner fashion (#80)


Diffstat:
Msrc/AppInstallerCLICore/Core.cpp | 6+++---
Msrc/AppInstallerCLICore/Workflows/InstallFlow.cpp | 2+-
Msrc/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj | 1+
Msrc/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters | 3+++
Asrc/AppInstallerCommonCore/Errors.cpp | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/AppInstallerCommonCore/Public/AppInstallerErrors.h | 21+++++++++++++++++----
6 files changed, 130 insertions(+), 8 deletions(-)

diff --git a/src/AppInstallerCLICore/Core.cpp b/src/AppInstallerCLICore/Core.cpp @@ -109,12 +109,12 @@ namespace AppInstaller::CLI Logging::Telemetry().LogException(command->FullName(), "wil::ResultException", re.what()); context.Reporter.Error() << "An unexpected error occurred while executing the command: " << std::endl << - re.what() << std::endl; + GetUserPresentableMessage(re) << std::endl; return re.GetErrorCode(); } catch (const winrt::hresult_error& hre) { - std::string message = Utility::ConvertToUTF8(hre.message()); + std::string message = GetUserPresentableMessage(hre); Logging::Telemetry().LogException(command->FullName(), "winrt::hresult_error", message); context.Reporter.Error() << "An unexpected error occurred while executing the command: " << std::endl << @@ -126,7 +126,7 @@ namespace AppInstaller::CLI Logging::Telemetry().LogException(command->FullName(), "std::exception", e.what()); context.Reporter.Error() << "An unexpected error occurred while executing the command: " << std::endl << - e.what() << std::endl; + GetUserPresentableMessage(e) << std::endl; return APPINSTALLER_CLI_ERROR_COMMAND_FAILED; } catch (...) diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -208,7 +208,7 @@ namespace AppInstaller::CLI::Workflow const auto& manifest = context.Get<Execution::Data::Manifest>(); Logging::Telemetry().LogInstallerFailure(manifest.Id, manifest.Version, manifest.Channel, "MSIX", re.GetErrorCode()); - context.Reporter.Error() << Utility::ConvertToUTF8(re.GetFailureInfo().pszMessage) << std::endl; + context.Reporter.Error() << GetUserPresentableMessage(re) << std::endl; AICLI_TERMINATE_CONTEXT(re.GetErrorCode()); } diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj @@ -202,6 +202,7 @@ <ClCompile Include="DateTime.cpp" /> <ClCompile Include="Deployment.cpp" /> <ClCompile Include="Downloader.cpp" /> + <ClCompile Include="Errors.cpp" /> <ClCompile Include="FileLogger.cpp" /> <ClCompile Include="HttpStream\HttpClientWrapper.cpp" /> <ClCompile Include="HttpStream\HttpLocalCache.cpp" /> diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters @@ -149,6 +149,9 @@ <ClCompile Include="Versions.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="Errors.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <None Include="PropertySheet.props" /> diff --git a/src/AppInstallerCommonCore/Errors.cpp b/src/AppInstallerCommonCore/Errors.cpp @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "pch.h" +#include "Public/AppInstallerErrors.h" +#include "Public/AppInstallerStrings.h" + + +namespace AppInstaller +{ + namespace + { + const char* const GetMessageForAppInstallerHR(HRESULT hr) + { + switch (hr) + { + case APPINSTALLER_CLI_ERROR_INTERNAL_ERROR: + return "Internal Error"; + case APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS: + return "Invalid command line arguments"; + case APPINSTALLER_CLI_ERROR_COMMAND_FAILED: + return "Executing command failed"; + case APPINSTALLER_CLI_ERROR_MANIFEST_FAILED: + return "Opening manifest failed"; + case APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED: + return "Running ShellExecute failed"; + case APPINSTALLER_CLI_ERROR_DOWNLOAD_FAILED: + return "Downloading installer failed"; + case APPINSTALLER_CLI_ERROR_CANNOT_WRITE_TO_UPLEVEL_INDEX: + return "Cannot write to index; it is a higher schema version"; + case APPINSTALLER_CLI_ERROR_INDEX_INTEGRITY_COMPROMISED: + return "The index is corrupt"; + case APPINSTALLER_CLI_ERROR_SOURCES_INVALID: + return "The configured source information is corrupt"; + case APPINSTALLER_CLI_ERROR_SOURCE_NAME_ALREADY_EXISTS: + return "The source name is already configured"; + case APPINSTALLER_CLI_ERROR_INVALID_SOURCE_TYPE: + return "The source type is invalid"; + case APPINSTALLER_CLI_ERROR_PACKAGE_IS_BUNDLE: + return "The MSIX file is a bundle, not a package"; + case APPINSTALLER_CLI_ERROR_SOURCE_DATA_MISSING: + return "Data required by the source is missing"; + case APPINSTALLER_CLI_ERROR_NO_APPLICABLE_INSTALLER: + return "None of the installers are applicable for the current system"; + case APPINSTALLER_CLI_ERROR_INSTALLER_HASH_MISMATCH: + return "The installer file's hash does not match the manifest"; + case APPINSTALLER_CLI_ERROR_SOURCE_NAME_DOES_NOT_EXIST: + return "The source name does not exist"; + case APPINSTALLER_CLI_ERROR_SOURCE_ARG_ALREADY_EXISTS: + return "The source location is already configured under another name"; + case APPINSTALLER_CLI_ERROR_NO_APPLICATIONS_FOUND: + return "No applications found"; + case APPINSTALLER_CLI_ERROR_NO_SOURCES_DEFINED: + return "No sources are configured"; + case APPINSTALLER_CLI_ERROR_MULTIPLE_APPLICATIONS_FOUND: + return "Multiple applications found matching the criteria"; + case APPINSTALLER_CLI_ERROR_NO_MANIFEST_FOUND: + return "No manifest found matching the criteria"; + default: + return "Uknown Error Code"; + } + } + + void GetUserPresentableMessageForHR(std::ostringstream& strstr, HRESULT hr) + { + strstr << "0x" << std::hex << std::setw(8) << std::setfill('0') << hr << " : "; + + if (HRESULT_FACILITY(hr) == APPINSTALLER_CLI_ERROR_FACILITY) + { + strstr << GetMessageForAppInstallerHR(hr); + } + else + { + strstr << std::system_category().message(hr); + } + } + } + + std::string GetUserPresentableMessage(const wil::ResultException& re) + { + const auto& info = re.GetFailureInfo(); + + std::ostringstream strstr; + + // We assume that if the exception has a message, that message is relevant to show to the user. + if (info.pszMessage) + { + strstr << Utility::ConvertToUTF8(info.pszMessage) << std::endl; + } + + GetUserPresentableMessageForHR(strstr, re.GetErrorCode()); + + return strstr.str(); + } + + std::string GetUserPresentableMessage(const winrt::hresult_error& hre) + { + return Utility::ConvertToUTF8(hre.message()); + } + + std::string GetUserPresentableMessage(const std::exception& e) + { + return e.what(); + } +} diff --git a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h @@ -1,17 +1,22 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. - #pragma once +#include <wil/result_macros.h> +#include <winrt/base.h> + +#include <exception> +#include <string> -#define APPINSTALLER_CLI_ERROR_FACILITY 0x8A150000 + +#define APPINSTALLER_CLI_ERROR_FACILITY 0xA15 #define APPINSTALLER_CLI_ERROR_INTERNAL_ERROR ((HRESULT)0x8A150001) #define APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS ((HRESULT)0x8A150002) #define APPINSTALLER_CLI_ERROR_COMMAND_FAILED ((HRESULT)0x8A150003) #define APPINSTALLER_CLI_ERROR_MANIFEST_FAILED ((HRESULT)0x8A150004) -#define APPINSTALLER_CLI_ERROR_WORKFLOW_FAILED ((HRESULT)0x8A150005) +//#define APPINSTALLER_CLI_ERROR_WORKFLOW_FAILED ((HRESULT)0x8A150005) // Unused, can be repurposed #define APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED ((HRESULT)0x8A150006) -#define APPINSTALLER_CLI_ERROR_RUNTIME_ERROR ((HRESULT)0x8A150007) +//#define APPINSTALLER_CLI_ERROR_RUNTIME_ERROR ((HRESULT)0x8A150007) // Unused, can be repurposed #define APPINSTALLER_CLI_ERROR_DOWNLOAD_FAILED ((HRESULT)0x8A150008) #define APPINSTALLER_CLI_ERROR_CANNOT_WRITE_TO_UPLEVEL_INDEX ((HRESULT)0x8A150009) #define APPINSTALLER_CLI_ERROR_INDEX_INTEGRITY_COMPROMISED ((HRESULT)0x8A15000A) @@ -28,3 +33,11 @@ #define APPINSTALLER_CLI_ERROR_NO_SOURCES_DEFINED ((HRESULT)0x8A150015) #define APPINSTALLER_CLI_ERROR_MULTIPLE_APPLICATIONS_FOUND ((HRESULT)0x8A150016) #define APPINSTALLER_CLI_ERROR_NO_MANIFEST_FOUND ((HRESULT)0x8A150017) + +namespace AppInstaller +{ + // Gets error messages that are presentable to the user. + std::string GetUserPresentableMessage(const wil::ResultException& re); + std::string GetUserPresentableMessage(const winrt::hresult_error& hre); + std::string GetUserPresentableMessage(const std::exception& e); +}