commit 69dfb820e68415f44df94734574c15635e1cb4b0
parent 3929ecd1c0f98613d932521c149ed42c55e0949c
Author: yao-msft <50888816+yao-msft@users.noreply.github.com>
Date: Thu, 30 Apr 2020 10:55:39 -0700
Make exe missing silent switch a warning and add tool info (#93)
Diffstat:
11 files changed, 196 insertions(+), 89 deletions(-)
diff --git a/src/AppInstallerCLICore/Command.cpp b/src/AppInstallerCLICore/Command.cpp
@@ -27,8 +27,8 @@ namespace AppInstaller::CLI
void Command::OutputIntroHeader(Execution::Reporter& reporter) const
{
reporter.Info() <<
- "AppInstaller Command Line v" << Runtime::GetClientVersion() << std::endl <<
- "Copyright (c) Microsoft Corporation" << std::endl;
+ "Windows Package Manager v" << Runtime::GetClientVersion() << std::endl <<
+ "Copyright (c) Microsoft Corporation. All rights reserved." << std::endl;
}
void Command::OutputHelp(Execution::Reporter& reporter, const CommandException* exception) const
diff --git a/src/AppInstallerCLICore/Commands/RootCommand.cpp b/src/AppInstallerCLICore/Commands/RootCommand.cpp
@@ -30,6 +30,7 @@ namespace AppInstaller::CLI
return
{
Argument{ "version", 'v', Execution::Args::Type::ListVersions, LOCME("Display the version of the tool"), ArgumentType::Flag, Visibility::Help },
+ Argument{ "info", APPINSTALLER_CLI_ARGUMENT_NO_SHORT_VER, Execution::Args::Type::Info, LOCME("Display general info of the tool"), ArgumentType::Flag, Visibility::Help },
};
}
@@ -40,7 +41,18 @@ namespace AppInstaller::CLI
void RootCommand::ExecuteInternal(Execution::Context& context) const
{
- if (context.Args.Contains(Execution::Args::Type::ListVersions))
+ if (context.Args.Contains(Execution::Args::Type::Info))
+ {
+ OutputIntroHeader(context.Reporter);
+
+ context.Reporter.Info() << std::endl <<
+ "Links:" << std::endl <<
+ " Privacy Statement: https://aka.ms/winget-privacy" << std::endl <<
+ " License agreement: https://aka.ms/winget-license" << std::endl <<
+ " 3rd Party Notices: https://aka.ms/winget-3rdPartyNotice" << std::endl <<
+ " Homepage: https://aka.ms/winget" << std::endl;
+ }
+ else if (context.Args.Contains(Execution::Args::Type::ListVersions))
{
context.Reporter.Info() << 'v' << Runtime::GetClientVersion() << std::endl;
}
diff --git a/src/AppInstallerCLICore/Commands/ValidateCommand.cpp b/src/AppInstallerCLICore/Commands/ValidateCommand.cpp
@@ -36,13 +36,21 @@ namespace AppInstaller::CLI
try
{
- (void)Manifest::Manifest::CreateFromPath(inputFile, true);
+ (void)Manifest::Manifest::CreateFromPath(inputFile, true, true);
context.Reporter.Info() << "Manifest validation succeeded." << std::endl;
}
catch (const Manifest::ManifestException& e)
{
- context.Reporter.Warn() << "Manifest validation failed." << std::endl;
- context.Reporter.Warn() << e.GetManifestErrorMessage() << std::endl;
+ if (e.IsWarningOnly())
+ {
+ context.Reporter.Warn() << "Manifest validation succeeded with warnings." << std::endl;
+ }
+ else
+ {
+ context.Reporter.Error() << "Manifest validation failed." << std::endl;
+ }
+
+ context.Reporter.Info() << e.GetManifestErrorMessage() << std::endl;
}
};
}
diff --git a/src/AppInstallerCLICore/ExecutionArgs.h b/src/AppInstallerCLICore/ExecutionArgs.h
@@ -57,6 +57,7 @@ namespace AppInstaller::CLI::Execution
PlainStyle, // Makes progress display as plain
RainbowStyle, // Makes progress display as a rainbow
Help, // Show command usage
+ Info, // Show general info about WinGet
};
bool Contains(Type arg) const { return (m_parsedArgs.count(arg) != 0); }
diff --git a/src/AppInstallerCLITests/YamlManifest.cpp b/src/AppInstallerCLITests/YamlManifest.cpp
@@ -122,80 +122,110 @@ TEST_CASE("ReadGoodManifestWithSpaces", "[ManifestValidation]")
REQUIRE(manifest.FileExtensions == MultiValue{ "appx", "appxbundle", "msix", "msixbundle" });
}
-void TestManifest(const std::filesystem::path& manifestPath, const std::string& expectedError = {})
+struct ManifestExceptionMatcher : public Catch::MatcherBase<ManifestException>
{
- if (expectedError.empty())
+ ManifestExceptionMatcher(std::string expectedMessage, bool expectedWarningOnly) :
+ m_expectedMessage(expectedMessage), m_expectedWarningOnly(expectedWarningOnly) {}
+
+ // Performs the test for this matcher
+ bool match(ManifestException const& e) const override
+ {
+ return e.GetManifestErrorMessage().find(m_expectedMessage) != std::string::npos &&
+ e.IsWarningOnly() == m_expectedWarningOnly;
+ }
+
+ virtual std::string describe() const override {
+ std::ostringstream ss;
+ ss << std::boolalpha << "Expected exception message: " << m_expectedMessage << "Expected IsWarningOnly: " << m_expectedWarningOnly;
+ return ss.str();
+ }
+
+private:
+ std::string m_expectedMessage;
+ bool m_expectedWarningOnly;
+};
+
+void TestManifest(const std::filesystem::path& manifestPath, const std::string& expectedMessage = {}, bool expectedWarningOnly = false)
+{
+ if (expectedMessage.empty())
{
- CHECK_NOTHROW(Manifest::CreateFromPath(TestDataFile(manifestPath), true));
+ CHECK_NOTHROW(Manifest::CreateFromPath(TestDataFile(manifestPath), true, true));
}
else
{
- CHECK_THROWS_WITH(Manifest::CreateFromPath(TestDataFile(manifestPath), true), Catch::Contains(expectedError));
+ CHECK_THROWS_MATCHES(Manifest::CreateFromPath(TestDataFile(manifestPath), true, true), ManifestException, ManifestExceptionMatcher(expectedMessage, expectedWarningOnly));
}
}
+struct ManifestTestCase
+{
+ std::string TestFile;
+ std::string ExpectedMessage = {};
+ bool IsWarningOnly = false;
+};
+
TEST_CASE("ReadGoodManifests", "[ManifestValidation]")
{
- std::string TestCases[] =
+ ManifestTestCase TestCases[] =
{
- "Manifest-Good-InstallerTypeExeRoot-Silent.yaml",
- "Manifest-Good-InstallerTypeExeRoot-SilentRoot.yaml",
- "Manifest-Good-InstallerTypeExe-Silent.yaml",
- "Manifest-Good-InstallerTypeExe-SilentRoot.yaml",
- "Manifest-Good-Installeruniqueness-DefaultLang.yaml",
- "Manifest-Good-Installeruniqueness-DiffLangs.yaml",
- "Manifest-Good-InstallerUniqueness-DiffScope.yaml",
- "Manifest-Good-Minimum.yaml",
- "Manifest-Good-Minimum-InstallerType.yaml",
- "Manifest-Good-Switches.yaml",
+ { "Manifest-Good-InstallerTypeExeRoot-Silent.yaml" },
+ { "Manifest-Good-InstallerTypeExeRoot-SilentRoot.yaml" },
+ { "Manifest-Good-InstallerTypeExe-Silent.yaml" },
+ { "Manifest-Good-InstallerTypeExe-SilentRoot.yaml" },
+ { "Manifest-Good-Installeruniqueness-DefaultLang.yaml" },
+ { "Manifest-Good-Installeruniqueness-DiffLangs.yaml" },
+ { "Manifest-Good-InstallerUniqueness-DiffScope.yaml" },
+ { "Manifest-Good-Minimum.yaml" },
+ { "Manifest-Good-Minimum-InstallerType.yaml" },
+ { "Manifest-Good-Switches.yaml" },
};
for (auto const& testCase : TestCases)
{
- TestManifest(testCase);
+ TestManifest(testCase.TestFile);
}
}
TEST_CASE("ReadBadManifests", "[ManifestValidation]")
{
- std::pair<std::string, std::string> TestCases[] =
+ ManifestTestCase TestCases[] =
{
- { "Manifest-Bad-ArchInvalid.yaml", "Manifest: Invalid field value. Field: Arch" },
- { "Manifest-Bad-ArchMissing.yaml", "Manifest: Required field missing. Field: Arch" },
- { "Manifest-Bad-Channel-NotSupported.yaml", "Manifest: Field is not supported. Field: Channel" },
- { "Manifest-Bad-DifferentCase-camelCase.yaml", "Manifest: All field names should be PascalCased. Field: installerType" },
- { "Manifest-Bad-DifferentCase-lower.yaml", "Manifest: All field names should be PascalCased. Field: installertype" },
- { "Manifest-Bad-DifferentCase-UPPER.yaml", "Manifest: All field names should be PascalCased. Field: INSTALLERTYPE" },
- { "Manifest-Bad-DuplicateKey.yaml", "Manifest: Duplicate field found in the manifest." },
- { "Manifest-Bad-DuplicateKey-DifferentCase.yaml", "Manifest: Duplicate field found in the manifest." },
- { "Manifest-Bad-DuplicateKey-DifferentCase-lower.yaml", "Manifest: Duplicate field found in the manifest." },
- { "Manifest-Bad-IdInvalid.yaml", "Manifest: Invalid field value. Field: Id" },
- { "Manifest-Bad-IdMissing.yaml", "Manifest: Required field missing. Field: Id" },
- { "Manifest-Bad-InstallersMissing.yaml", "Manifest: Required field missing. Field: Installers" },
- { "Manifest-Bad-InstallerTypeExe-NoSilent.yaml", "Manifest: Silent switches are required for InstallerType exe." },
- { "Manifest-Bad-InstallerTypeExe-NoSilentRoot.yaml", "Manifest: Silent switches are required for InstallerType exe." },
- { "Manifest-Bad-InstallerTypeExeRoot-NoSilent.yaml", "Manifest: Silent switches are required for InstallerType exe." },
- { "Manifest-Bad-InstallerTypeExeRoot-NoSilentRoot.yaml", "Manifest: Silent switches are required for InstallerType exe." },
- { "Manifest-Bad-InstallerTypeInvalid.yaml", "Manifest: Invalid field value. Field: InstallerType" },
- { "Manifest-Bad-InstallerTypeMissing.yaml", "Manifest: Invalid field value. Field: InstallerType" },
- { "Manifest-Bad-InstallerUniqueness.yaml", "Manifest: Duplicate installer entry found." },
- { "Manifest-Bad-InstallerUniqueness-DefaultScope.yaml", "Manifest: Duplicate installer entry found." },
- { "Manifest-Bad-InstallerUniqueness-DefaultValues.yaml", "Manifest: Duplicate installer entry found." },
- { "Manifest-Bad-InstallerUniqueness-SameLang.yaml", "Manifest: Duplicate installer entry found." },
- { "Manifest-Bad-NameMissing.yaml", "Manifest: Required field missing. Field: Name" },
- { "Manifest-Bad-PublisherMissing.yaml", "Manifest: Required field missing. Field: Publisher" },
- { "Manifest-Bad-Sha256Invalid.yaml", "Manifest: Invalid field value. Field: Sha256" },
- { "Manifest-Bad-Sha256Missing.yaml", "Manifest: Required field missing. Field: Sha256" },
- { "Manifest-Bad-SwitchInvalid.yaml", "Manifest: Unknown field. Field: NotASwitch" },
- { "Manifest-Bad-UnknownProperty.yaml", "Manifest: Unknown field. Field: Fake" },
- { "Manifest-Bad-UrlInvalid.yaml", "Manifest: Invalid field value. Field: Url" },
- { "Manifest-Bad-UrlMissing.yaml", "Manifest: Required field missing. Field: Url" },
- { "Manifest-Bad-VersionInvalid.yaml", "Manifest: Invalid field value. Field: Version" },
- { "Manifest-Bad-VersionMissing.yaml", "Manifest: Required field missing. Field: Version" },
+ { "Manifest-Bad-ArchInvalid.yaml", "Invalid field value. Field: Arch" },
+ { "Manifest-Bad-ArchMissing.yaml", "Required field missing. Field: Arch" },
+ { "Manifest-Bad-Channel-NotSupported.yaml", "Field is not supported. Field: Channel" },
+ { "Manifest-Bad-DifferentCase-camelCase.yaml", "All field names should be PascalCased. Field: installerType" },
+ { "Manifest-Bad-DifferentCase-lower.yaml", "All field names should be PascalCased. Field: installertype" },
+ { "Manifest-Bad-DifferentCase-UPPER.yaml", "All field names should be PascalCased. Field: INSTALLERTYPE" },
+ { "Manifest-Bad-DuplicateKey.yaml", "Duplicate field found in the manifest." },
+ { "Manifest-Bad-DuplicateKey-DifferentCase.yaml", "Duplicate field found in the manifest." },
+ { "Manifest-Bad-DuplicateKey-DifferentCase-lower.yaml", "Duplicate field found in the manifest." },
+ { "Manifest-Bad-IdInvalid.yaml", "Invalid field value. Field: Id" },
+ { "Manifest-Bad-IdMissing.yaml", "Required field missing. Field: Id" },
+ { "Manifest-Bad-InstallersMissing.yaml", "Required field missing. Field: Installers" },
+ { "Manifest-Bad-InstallerTypeExe-NoSilent.yaml", "Silent and SilentWithProgress switches are not specified for InstallerType exe.", true },
+ { "Manifest-Bad-InstallerTypeExe-NoSilentRoot.yaml", "Silent and SilentWithProgress switches are not specified for InstallerType exe.", true },
+ { "Manifest-Bad-InstallerTypeExeRoot-NoSilent.yaml", "Silent and SilentWithProgress switches are not specified for InstallerType exe.", true },
+ { "Manifest-Bad-InstallerTypeExeRoot-NoSilentRoot.yaml", "Silent and SilentWithProgress switches are not specified for InstallerType exe.", true },
+ { "Manifest-Bad-InstallerTypeInvalid.yaml", "Invalid field value. Field: InstallerType" },
+ { "Manifest-Bad-InstallerTypeMissing.yaml", "Invalid field value. Field: InstallerType" },
+ { "Manifest-Bad-InstallerUniqueness.yaml", "Duplicate installer entry found." },
+ { "Manifest-Bad-InstallerUniqueness-DefaultScope.yaml", "Duplicate installer entry found." },
+ { "Manifest-Bad-InstallerUniqueness-DefaultValues.yaml", "Duplicate installer entry found." },
+ { "Manifest-Bad-InstallerUniqueness-SameLang.yaml", "Duplicate installer entry found." },
+ { "Manifest-Bad-NameMissing.yaml", "Required field missing. Field: Name" },
+ { "Manifest-Bad-PublisherMissing.yaml", "Required field missing. Field: Publisher" },
+ { "Manifest-Bad-Sha256Invalid.yaml", "Invalid field value. Field: Sha256" },
+ { "Manifest-Bad-Sha256Missing.yaml", "Required field missing. Field: Sha256" },
+ { "Manifest-Bad-SwitchInvalid.yaml", "Unknown field. Field: NotASwitch" },
+ { "Manifest-Bad-UnknownProperty.yaml", "Unknown field. Field: Fake" },
+ { "Manifest-Bad-UrlInvalid.yaml", "Invalid field value. Field: Url" },
+ { "Manifest-Bad-UrlMissing.yaml", "Required field missing. Field: Url" },
+ { "Manifest-Bad-VersionInvalid.yaml", "Invalid field value. Field: Version" },
+ { "Manifest-Bad-VersionMissing.yaml", "Required field missing. Field: Version" },
};
for (auto const& testCase : TestCases)
{
- TestManifest(testCase.first, testCase.second);
+ TestManifest(testCase.TestFile, testCase.ExpectedMessage, testCase.IsWarningOnly);
}
}
diff --git a/src/AppInstallerRepositoryCore/Manifest/Manifest.cpp b/src/AppInstallerRepositoryCore/Manifest/Manifest.cpp
@@ -158,7 +158,7 @@ namespace AppInstaller::Manifest
return resultErrors;
}
- Manifest Manifest::CreateFromPath(const std::filesystem::path& inputFile, bool fullValidation)
+ Manifest Manifest::CreateFromPath(const std::filesystem::path& inputFile, bool fullValidation, bool throwOnWarning)
{
Manifest manifest;
std::vector<ValidationError> errors;
@@ -170,19 +170,23 @@ namespace AppInstaller::Manifest
}
catch (const std::exception& e)
{
- AICLI_LOG(YAML, Error, << "Failed to create manifest from file: " << inputFile.u8string());
THROW_EXCEPTION_MSG(ManifestException(), e.what());
}
if (!errors.empty())
{
- THROW_EXCEPTION(ManifestException(std::move(errors)));
+ ManifestException ex{ std::move(errors) };
+
+ if (throwOnWarning || !ex.IsWarningOnly())
+ {
+ THROW_EXCEPTION(ex);
+ }
}
return manifest;
}
- Manifest Manifest::Create(const std::string& input, bool fullValidation)
+ Manifest Manifest::Create(const std::string& input, bool fullValidation, bool throwOnWarning)
{
Manifest manifest;
std::vector<ValidationError> errors;
@@ -194,13 +198,17 @@ namespace AppInstaller::Manifest
}
catch (const std::exception& e)
{
- AICLI_LOG(YAML, Error, << "Failed to create manifest: " << input);
THROW_EXCEPTION_MSG(ManifestException(), e.what());
}
if (!errors.empty())
{
- THROW_EXCEPTION(ManifestException(std::move(errors)));
+ ManifestException ex{ std::move(errors) };
+
+ if (throwOnWarning || !ex.IsWarningOnly())
+ {
+ THROW_EXCEPTION(ex);
+ }
}
return manifest;
diff --git a/src/AppInstallerRepositoryCore/Manifest/Manifest.h b/src/AppInstallerRepositoryCore/Manifest/Manifest.h
@@ -67,10 +67,11 @@ namespace AppInstaller::Manifest
std::vector<ValidationError> PopulateManifestFields(const YAML::Node& rootNode, bool fullValidation);
- // fullValidation Bool to set if manifest creation should perform extra validation that client does not need.
- // e.g. Channel should be null. Client code does not need this check to work properly.
- static Manifest CreateFromPath(const std::filesystem::path& inputFile, bool fullValidation = false);
+ // fullValidation: Bool to set if manifest creation should perform extra validation that client does not need.
+ // e.g. Channel should be null. Client code does not need this check to work properly.
+ // throwOnWarning: Bool to indicate if an exception should be thrown with only warnings detected in the manifest.
+ static Manifest CreateFromPath(const std::filesystem::path& inputFile, bool fullValidation = false, bool throwOnWarning = false);
- static Manifest Create(const std::string& input, bool fullValidation = false);
+ static Manifest Create(const std::string& input, bool fullValidation = false, bool throwOnWarning = false);
};
}
\ No newline at end of file
diff --git a/src/AppInstallerRepositoryCore/Manifest/ManifestInstaller.cpp b/src/AppInstallerRepositoryCore/Manifest/ManifestInstaller.cpp
@@ -59,7 +59,7 @@ namespace AppInstaller::Manifest
(Switches.find(InstallerSwitchType::SilentWithProgress) == Switches.end() ||
Switches.find(InstallerSwitchType::Silent) == Switches.end()))
{
- resultErrors.emplace_back(ManifestError::ExeInstallerMissingSilentSwitches);
+ resultErrors.emplace_back(ManifestError::ExeInstallerMissingSilentSwitches, ValidationError::Level::Warning);
}
// Check empty string before calling IsValidUrl to avoid duplicate error reporting.
diff --git a/src/AppInstallerRepositoryCore/Manifest/ManifestValidation.h b/src/AppInstallerRepositoryCore/Manifest/ManifestValidation.h
@@ -13,28 +13,53 @@ namespace AppInstaller::Manifest
{
namespace ManifestError
{
- const char* const InvalidRootNode = "Manifest: Encountered unexpected root node.";
- const char* const FieldUnknown = "Manifest: Unknown field.";
- const char* const FieldIsNotPascalCase = "Manifest: All field names should be PascalCased.";
- const char* const FieldDuplicate = "Manifest: Duplicate field found in the manifest.";
- const char* const RequiredFieldEmpty = "Manifest: Required field with empty value.";
- const char* const RequiredFieldMissing = "Manifest: Required field missing.";
- const char* const InvalidFieldValue = "Manifest: Invalid field value.";
- const char* const ExeInstallerMissingSilentSwitches = "Manifest: Silent switches are required for InstallerType exe.";
- const char* const FieldNotSupported = "Manifest: Field is not supported.";
- const char* const DuplicateInstallerEntry = "Manifest: Duplicate installer entry found.";
+ const char* const ErrorMessagePrefix = "Manifest Error: ";
+ const char* const WarningMessagePrefix = "Manifest Warning: ";
+
+ const char* const InvalidRootNode = "Encountered unexpected root node.";
+ const char* const FieldUnknown = "Unknown field.";
+ const char* const FieldIsNotPascalCase = "All field names should be PascalCased.";
+ const char* const FieldDuplicate = "Duplicate field found in the manifest.";
+ const char* const RequiredFieldEmpty = "Required field with empty value.";
+ const char* const RequiredFieldMissing = "Required field missing.";
+ const char* const InvalidFieldValue = "Invalid field value.";
+ const char* const ExeInstallerMissingSilentSwitches = "Silent and SilentWithProgress switches are not specified for InstallerType exe. Please make sure the installer can run unattended.";
+ const char* const FieldNotSupported = "Field is not supported.";
+ const char* const DuplicateInstallerEntry = "Duplicate installer entry found.";
}
struct ValidationError
{
+ enum class Level
+ {
+ Warning,
+ Error
+ };
+
std::string Message;
- std::string Field;
- std::string Value;
- int Line;
- int Column;
+ std::string Field = {};
+ std::string Value = {};
+ int Line = -1;
+ int Column = -1;
+ Level ErrorLevel = Level::Error;
+
+ ValidationError(std::string message) :
+ Message(std::move(message)) {}
+
+ ValidationError(std::string message, Level level) :
+ Message(std::move(message)), ErrorLevel(level) {}
- ValidationError(std::string message, std::string field = {}, std::string value = {}, int line = -1, int column = -1) :
+ ValidationError(std::string message, std::string field) :
+ Message(std::move(message)), Field(std::move(field)) {}
+
+ ValidationError(std::string message, std::string field, std::string value) :
+ Message(std::move(message)), Field(std::move(field)), Value(std::move(value)) {}
+
+ ValidationError(std::string message, std::string field, std::string value, int line, int column) :
Message(std::move(message)), Field(std::move(field)), Value(std::move(value)), Line(line), Column(column) {}
+
+ ValidationError(std::string message, std::string field, std::string value, int line, int column, Level level) :
+ Message(std::move(message)), Field(std::move(field)), Value(std::move(value)), Line(line), Column(column), ErrorLevel(level) {}
};
// This struct contains individual app manifest field info
@@ -55,7 +80,14 @@ namespace AppInstaller::Manifest
struct ManifestException : public wil::ResultException
{
ManifestException(std::vector<ValidationError>&& errors = {}) :
- m_errors(std::move(errors)), wil::ResultException(APPINSTALLER_CLI_ERROR_MANIFEST_FAILED) {}
+ m_errors(std::move(errors)), wil::ResultException(APPINSTALLER_CLI_ERROR_MANIFEST_FAILED)
+ {
+ auto p = [&](ValidationError const& e) {
+ return e.ErrorLevel == ValidationError::Level::Error;
+ };
+
+ m_warningOnly = !m_errors.empty() && std::find_if(m_errors.begin(), m_errors.end(), p) == m_errors.end();
+ }
// Error message without wil diagnostic info
const std::string& GetManifestErrorMessage() const noexcept
@@ -71,7 +103,16 @@ namespace AppInstaller::Manifest
{
for (auto const& error : m_errors)
{
+ if (error.ErrorLevel == ValidationError::Level::Error)
+ {
+ m_manifestErrorMessage += ManifestError::ErrorMessagePrefix;
+ }
+ else if (error.ErrorLevel == ValidationError::Level::Warning)
+ {
+ m_manifestErrorMessage += ManifestError::WarningMessagePrefix;
+ }
m_manifestErrorMessage += error.Message;
+
if (!error.Field.empty())
{
m_manifestErrorMessage += " Field: " + error.Field;
@@ -91,6 +132,11 @@ namespace AppInstaller::Manifest
return m_manifestErrorMessage;
}
+ bool IsWarningOnly() const noexcept
+ {
+ return m_warningOnly;
+ }
+
const char* what() const noexcept override
{
if (m_whatMessage.empty())
@@ -109,5 +155,6 @@ namespace AppInstaller::Manifest
std::vector<ValidationError> m_errors;
mutable std::string m_whatMessage;
mutable std::string m_manifestErrorMessage;
+ bool m_warningOnly;
};
}
\ No newline at end of file
diff --git a/src/WinGetUtil/Exports.cpp b/src/WinGetUtil/Exports.cpp
@@ -160,22 +160,22 @@ extern "C"
WINGET_UTIL_API WinGetValidateManifest(
WINGET_STRING manifestPath,
BOOL* succeeded,
- WINGET_STRING_OUT* failureMessage) try
+ WINGET_STRING_OUT* message) try
{
THROW_HR_IF(E_INVALIDARG, !manifestPath);
THROW_HR_IF(E_INVALIDARG, !succeeded);
try
{
- (void)Manifest::CreateFromPath(manifestPath, true);
+ (void)Manifest::CreateFromPath(manifestPath, true, true);
*succeeded = TRUE;
}
catch (const ManifestException& e)
{
- *succeeded = FALSE;
- if (failureMessage)
+ *succeeded = e.IsWarningOnly();
+ if (message)
{
- *failureMessage = ::SysAllocString(ConvertToUTF16(e.GetManifestErrorMessage()).c_str());
+ *message = ::SysAllocString(ConvertToUTF16(e.GetManifestErrorMessage()).c_str());
}
}
diff --git a/src/WinGetUtil/WinGetUtil.h b/src/WinGetUtil/WinGetUtil.h
@@ -73,7 +73,7 @@ extern "C"
WINGET_UTIL_API WinGetValidateManifest(
WINGET_STRING manifestPath,
BOOL* succeeded,
- WINGET_STRING_OUT* failureMessage);
+ WINGET_STRING_OUT* message);
// Downloads a file to the given path, returning the SHA 256 hash of the file.
WINGET_UTIL_API WinGetDownload(