From 3abfc1bfdf355d94265e93009744a4eb988b1397 Mon Sep 17 00:00:00 2001 From: John McPherson Date: Fri, 8 May 2020 15:37:38 -0700 Subject: [PATCH 1/8] checkpoint --- src/AppInstallerCLICore/Resources.cpp | 20 +++++--------- src/AppInstallerCLICore/Resources.h | 39 ++++++++++++++++++--------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/AppInstallerCLICore/Resources.cpp b/src/AppInstallerCLICore/Resources.cpp index 3eafb6a480..d6ded37ea2 100644 --- a/src/AppInstallerCLICore/Resources.cpp +++ b/src/AppInstallerCLICore/Resources.cpp @@ -4,29 +4,23 @@ #include "pch.h" #include "Resources.h" -namespace AppInstaller::CLI + +namespace AppInstaller::CLI::Resource { - const Resources& Resources::GetInstance() + const Loader& Loader::Instance() { - static Resources instance; + static Loader instance; return instance; } - Resources::Resources() + Loader::Loader() { m_wingetLoader = winrt::Windows::ApplicationModel::Resources::ResourceLoader::GetForViewIndependentUse(L"winget"); } - std::string Resources::ResolveWingetString( - std::wstring_view resKey) const - { - return Utility::ConvertToUTF8(ResolveWingetWString(resKey)); - } - - std::wstring Resources::ResolveWingetWString( + std::string Loader::ResolveString( std::wstring_view resKey) const { - std::wstring localized(m_wingetLoader.GetString(resKey)); - return localized; + return Utility::ConvertToUTF8(m_wingetLoader.GetString(resKey)); } } \ No newline at end of file diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index cdc505590a..5fc371ece1 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -3,27 +3,42 @@ #pragma once #include #include -#include -using namespace winrt::Windows::ApplicationModel::Resources; -using namespace winrt::Windows::ApplicationModel::Resources::Core; -namespace AppInstaller::CLI +namespace AppInstaller::CLI::Resource { - class Resources + using namespace std::string_view_literals; + +#define WINGET_WIDE_STRINGIFY_HELP(_id_) L ## _id_ +#define WINGET_WIDE_STRINGIFY(_id_) WINGET_WIDE_STRINGIFY_HELP(_id_) +#define WINGET_DEFINE_RESOURCE_ID(_id_) static constexpr std::wstring_view _id_ = WINGET_WIDE_STRINGIFY(#_id_) ## sv + + // Resource string identifiers + struct String { - public: - static const Resources& GetInstance(); + static constexpr std::wstring_view SearchCommandDescription = L"SearchCommandDescription"sv; + WINGET_DEFINE_RESOURCE_ID(HashHelperDescription); + }; - std::string ResolveWingetString( - std::wstring_view resKey) const; + // A localized string + struct LocString : public std::string + { + LocString(std::wstring_view id); + }; + + // Utility class to load resources + class Loader + { + public: + // Gets the singleton instance of the resource loader. + static const Loader& Instance(); - std::wstring ResolveWingetWString( - std::wstring_view resKey) const; + // Gets the the string resource value. + std::string ResolveString(std::wstring_view resKey) const; private: winrt::Windows::ApplicationModel::Resources::ResourceLoader m_wingetLoader; - Resources(); + Loader(); }; } \ No newline at end of file From 680ff9b8a08ca18e83808430357e720220fa50f0 Mon Sep 17 00:00:00 2001 From: John McPherson Date: Sat, 9 May 2020 15:25:36 -0700 Subject: [PATCH 2/8] checkpoint --- src/AppInstallerCLICore/Command.h | 5 +- .../Commands/HashCommand.cpp | 8 +- .../Commands/HashCommand.h | 4 +- .../Commands/InstallCommand.cpp | 8 +- .../Commands/InstallCommand.h | 4 +- .../Commands/RootCommand.cpp | 4 +- .../Commands/RootCommand.h | 2 +- .../Commands/SearchCommand.cpp | 8 +- .../Commands/SearchCommand.h | 4 +- .../Commands/ShowCommand.h | 4 +- .../Commands/SourceCommand.h | 24 ++--- .../Commands/ValidateCommand.h | 4 +- src/AppInstallerCLICore/Resources.cpp | 5 + src/AppInstallerCLICore/Resources.h | 99 ++++++++++++++++++- .../Shared/Strings/en-us/winget.resw | 15 ++- 15 files changed, 152 insertions(+), 46 deletions(-) diff --git a/src/AppInstallerCLICore/Command.h b/src/AppInstallerCLICore/Command.h index 39f0170a7c..2df0a44d85 100644 --- a/src/AppInstallerCLICore/Command.h +++ b/src/AppInstallerCLICore/Command.h @@ -4,6 +4,7 @@ #include "Argument.h" #include "ExecutionContext.h" #include "Invocation.h" +#include "Resources.h" #include #include @@ -48,8 +49,8 @@ namespace AppInstaller::CLI virtual std::vector> GetCommands() const { return {}; } virtual std::vector GetArguments() const { return {}; } - virtual std::string ShortDescription() const { return {}; } - virtual std::string GetLongDescription() const { return {}; } + virtual Resource::LocString ShortDescription() const { return {}; } + virtual Resource::LocString LongDescription() const { return {}; } virtual void OutputIntroHeader(Execution::Reporter& reporter) const; virtual void OutputHelp(Execution::Reporter& reporter, const CommandException* exception = nullptr) const; diff --git a/src/AppInstallerCLICore/Commands/HashCommand.cpp b/src/AppInstallerCLICore/Commands/HashCommand.cpp index 9b09f92a35..97edb35695 100644 --- a/src/AppInstallerCLICore/Commands/HashCommand.cpp +++ b/src/AppInstallerCLICore/Commands/HashCommand.cpp @@ -17,14 +17,14 @@ namespace AppInstaller::CLI }; } - std::string HashCommand::ShortDescription() const + Resource::LocString HashCommand::ShortDescription() const { - return Resources::GetInstance().ResolveWingetString(L"HashHelperDescription"); + return { Resource::String::HashCommandShortDescription }; } - std::string HashCommand::GetLongDescription() const + Resource::LocString HashCommand::LongDescription() const { - return Resources::GetInstance().ResolveWingetString(L"HashHelperDescription"); + return { Resource::String::HashCommandLongDescription }; } std::string HashCommand::HelpLink() const diff --git a/src/AppInstallerCLICore/Commands/HashCommand.h b/src/AppInstallerCLICore/Commands/HashCommand.h index 6aca85f681..3b395ff9e9 100644 --- a/src/AppInstallerCLICore/Commands/HashCommand.h +++ b/src/AppInstallerCLICore/Commands/HashCommand.h @@ -11,8 +11,8 @@ namespace AppInstaller::CLI virtual std::vector GetArguments() const override; - virtual std::string ShortDescription() const override; - virtual std::string GetLongDescription() const override; + virtual Resource::LocString ShortDescription() const override; + virtual Resource::LocString LongDescription() const override; std::string HelpLink() const override; diff --git a/src/AppInstallerCLICore/Commands/InstallCommand.cpp b/src/AppInstallerCLICore/Commands/InstallCommand.cpp index d0a4df03f1..ff40e05cfc 100644 --- a/src/AppInstallerCLICore/Commands/InstallCommand.cpp +++ b/src/AppInstallerCLICore/Commands/InstallCommand.cpp @@ -36,14 +36,14 @@ namespace AppInstaller::CLI }; } - std::string InstallCommand::ShortDescription() const + Resource::LocString InstallCommand::ShortDescription() const { - return Resources::GetInstance().ResolveWingetString(L"InstallCommandDescription"); + return { Resource::String::InstallCommandShortDescription }; } - std::string InstallCommand::GetLongDescription() const + Resource::LocString InstallCommand::LongDescription() const { - return Resources::GetInstance().ResolveWingetString(L"InstallCommandDescription"); + return { Resource::String::InstallCommandLongDescription }; } std::string InstallCommand::HelpLink() const diff --git a/src/AppInstallerCLICore/Commands/InstallCommand.h b/src/AppInstallerCLICore/Commands/InstallCommand.h index 3dfe8770d3..c02959fc9b 100644 --- a/src/AppInstallerCLICore/Commands/InstallCommand.h +++ b/src/AppInstallerCLICore/Commands/InstallCommand.h @@ -11,8 +11,8 @@ namespace AppInstaller::CLI std::vector GetArguments() const override; - std::string ShortDescription() const override; - std::string GetLongDescription() const override; + Resource::LocString ShortDescription() const override; + Resource::LocString LongDescription() const override; std::string HelpLink() const override; diff --git a/src/AppInstallerCLICore/Commands/RootCommand.cpp b/src/AppInstallerCLICore/Commands/RootCommand.cpp index c88b716e7d..c20f2c9440 100644 --- a/src/AppInstallerCLICore/Commands/RootCommand.cpp +++ b/src/AppInstallerCLICore/Commands/RootCommand.cpp @@ -34,9 +34,9 @@ namespace AppInstaller::CLI }; } - std::string RootCommand::GetLongDescription() const + Resource::LocString RootCommand::LongDescription() const { - return Resources::GetInstance().ResolveWingetString(L"ToolDescription"); + return { Resource::String::ToolDescription }; } std::string RootCommand::HelpLink() const diff --git a/src/AppInstallerCLICore/Commands/RootCommand.h b/src/AppInstallerCLICore/Commands/RootCommand.h index 5c49fd0563..208de4147c 100644 --- a/src/AppInstallerCLICore/Commands/RootCommand.h +++ b/src/AppInstallerCLICore/Commands/RootCommand.h @@ -12,7 +12,7 @@ namespace AppInstaller::CLI std::vector> GetCommands() const override; std::vector GetArguments() const override; - std::string GetLongDescription() const override; + Resource::LocString LongDescription() const override; std::string HelpLink() const override; diff --git a/src/AppInstallerCLICore/Commands/SearchCommand.cpp b/src/AppInstallerCLICore/Commands/SearchCommand.cpp index 17ab79b93c..7e5c888d31 100644 --- a/src/AppInstallerCLICore/Commands/SearchCommand.cpp +++ b/src/AppInstallerCLICore/Commands/SearchCommand.cpp @@ -25,14 +25,14 @@ namespace AppInstaller::CLI }; } - std::string SearchCommand::ShortDescription() const + Resource::LocString SearchCommand::ShortDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SearchCommandDescription"); + return { Resource::String::SearchCommandShortDescription }; } - std::string SearchCommand::GetLongDescription() const + Resource::LocString SearchCommand::LongDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SearchCommandDescription").c_str(); + return { Resource::String::SearchCommandLongDescription }; } std::string SearchCommand::HelpLink() const diff --git a/src/AppInstallerCLICore/Commands/SearchCommand.h b/src/AppInstallerCLICore/Commands/SearchCommand.h index b77bc3a72d..27a0154d39 100644 --- a/src/AppInstallerCLICore/Commands/SearchCommand.h +++ b/src/AppInstallerCLICore/Commands/SearchCommand.h @@ -11,8 +11,8 @@ namespace AppInstaller::CLI virtual std::vector GetArguments() const override; - virtual std::string ShortDescription() const override; - virtual std::string GetLongDescription() const override; + virtual Resource::LocString ShortDescription() const override; + virtual Resource::LocString LongDescription() const override; std::string HelpLink() const override; diff --git a/src/AppInstallerCLICore/Commands/ShowCommand.h b/src/AppInstallerCLICore/Commands/ShowCommand.h index 6e12230562..6c05f1ddd0 100644 --- a/src/AppInstallerCLICore/Commands/ShowCommand.h +++ b/src/AppInstallerCLICore/Commands/ShowCommand.h @@ -11,8 +11,8 @@ namespace AppInstaller::CLI virtual std::vector GetArguments() const override; - virtual std::string ShortDescription() const override; - virtual std::string GetLongDescription() const override; + virtual Resource::LocString ShortDescription() const override; + virtual Resource::LocString LongDescription() const override; std::string HelpLink() const override; diff --git a/src/AppInstallerCLICore/Commands/SourceCommand.h b/src/AppInstallerCLICore/Commands/SourceCommand.h index c49ce3e62f..a0e054aac9 100644 --- a/src/AppInstallerCLICore/Commands/SourceCommand.h +++ b/src/AppInstallerCLICore/Commands/SourceCommand.h @@ -11,8 +11,8 @@ namespace AppInstaller::CLI virtual std::vector> GetCommands() const override; - virtual std::string ShortDescription() const override; - virtual std::string GetLongDescription() const override; + virtual Resource::LocString ShortDescription() const override; + virtual Resource::LocString LongDescription() const override; std::string HelpLink() const override; @@ -26,8 +26,8 @@ namespace AppInstaller::CLI virtual std::vector GetArguments() const override; - virtual std::string ShortDescription() const override; - virtual std::string GetLongDescription() const override; + virtual Resource::LocString ShortDescription() const override; + virtual Resource::LocString LongDescription() const override; std::string HelpLink() const override; @@ -41,8 +41,8 @@ namespace AppInstaller::CLI virtual std::vector GetArguments() const override; - virtual std::string ShortDescription() const override; - virtual std::string GetLongDescription() const override; + virtual Resource::LocString ShortDescription() const override; + virtual Resource::LocString LongDescription() const override; std::string HelpLink() const override; @@ -56,8 +56,8 @@ namespace AppInstaller::CLI virtual std::vector GetArguments() const override; - virtual std::string ShortDescription() const override; - virtual std::string GetLongDescription() const override; + virtual Resource::LocString ShortDescription() const override; + virtual Resource::LocString LongDescription() const override; std::string HelpLink() const override; @@ -71,8 +71,8 @@ namespace AppInstaller::CLI virtual std::vector GetArguments() const override; - virtual std::string ShortDescription() const override; - virtual std::string GetLongDescription() const override; + virtual Resource::LocString ShortDescription() const override; + virtual Resource::LocString LongDescription() const override; std::string HelpLink() const override; @@ -86,8 +86,8 @@ namespace AppInstaller::CLI virtual std::vector GetArguments() const override; - virtual std::string ShortDescription() const override; - virtual std::string GetLongDescription() const override; + virtual Resource::LocString ShortDescription() const override; + virtual Resource::LocString LongDescription() const override; std::string HelpLink() const override; diff --git a/src/AppInstallerCLICore/Commands/ValidateCommand.h b/src/AppInstallerCLICore/Commands/ValidateCommand.h index b50b2bf969..2cc9d3f9f2 100644 --- a/src/AppInstallerCLICore/Commands/ValidateCommand.h +++ b/src/AppInstallerCLICore/Commands/ValidateCommand.h @@ -11,8 +11,8 @@ namespace AppInstaller::CLI virtual std::vector GetArguments() const override; - virtual std::string ShortDescription() const override; - virtual std::string GetLongDescription() const override; + virtual Resource::LocString ShortDescription() const override; + virtual Resource::LocString LongDescription() const override; std::string HelpLink() const override; diff --git a/src/AppInstallerCLICore/Resources.cpp b/src/AppInstallerCLICore/Resources.cpp index d6ded37ea2..d642e8916a 100644 --- a/src/AppInstallerCLICore/Resources.cpp +++ b/src/AppInstallerCLICore/Resources.cpp @@ -7,6 +7,11 @@ namespace AppInstaller::CLI::Resource { + LocString::LocString(std::wstring_view id) + { + m_value = Loader::Instance().ResolveString(id); + } + const Loader& Loader::Instance() { static Loader instance; diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index 5fc371ece1..64e824ce59 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -13,17 +13,108 @@ namespace AppInstaller::CLI::Resource #define WINGET_WIDE_STRINGIFY(_id_) WINGET_WIDE_STRINGIFY_HELP(_id_) #define WINGET_DEFINE_RESOURCE_ID(_id_) static constexpr std::wstring_view _id_ = WINGET_WIDE_STRINGIFY(#_id_) ## sv - // Resource string identifiers + // Resource string identifiers. + // This list can easily be generated by the following PowerShell: + // > [xml]$res = Get-Content + // > $res.root.data.name | % { "WINGET_DEFINE_RESOURCE_ID($_);" } struct String { - static constexpr std::wstring_view SearchCommandDescription = L"SearchCommandDescription"sv; - WINGET_DEFINE_RESOURCE_ID(HashHelperDescription); + WINGET_DEFINE_RESOURCE_ID(AdjoinedNotFlagError); + WINGET_DEFINE_RESOURCE_ID(AdjoinedNotFoundError); + WINGET_DEFINE_RESOURCE_ID(AvailableArguements); + WINGET_DEFINE_RESOURCE_ID(AvailableCommands); + WINGET_DEFINE_RESOURCE_ID(AvailableOptions); + WINGET_DEFINE_RESOURCE_ID(AvailableSubcommands); + WINGET_DEFINE_RESOURCE_ID(ChannelArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(CommandArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(CountArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(ExactArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(ExtraPositionalError); + WINGET_DEFINE_RESOURCE_ID(FileArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(FlagContainAdjoinedError); + WINGET_DEFINE_RESOURCE_ID(ForceArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(HashCommandLongDescription); + WINGET_DEFINE_RESOURCE_ID(HashCommandShortDescription); + WINGET_DEFINE_RESOURCE_ID(HelpArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(HelpForDetails); + WINGET_DEFINE_RESOURCE_ID(HelpLinkPreamble); + WINGET_DEFINE_RESOURCE_ID(IdArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(InstallCommandShortDescription); + WINGET_DEFINE_RESOURCE_ID(InstallCommandLongDescription); + WINGET_DEFINE_RESOURCE_ID(InteractiveArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(InvalidAliasError); + WINGET_DEFINE_RESOURCE_ID(InvalidArgumentSpecifierError); + WINGET_DEFINE_RESOURCE_ID(InvalidNameError); + WINGET_DEFINE_RESOURCE_ID(LanguageArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(LocationArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(LogArgumentDesciption); + WINGET_DEFINE_RESOURCE_ID(ManifestArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(MissingArgumentError); + WINGET_DEFINE_RESOURCE_ID(MonikerArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(MsixArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(NameArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(NoVTArguementDescription); + WINGET_DEFINE_RESOURCE_ID(OverrideArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(PendingWorkError); + WINGET_DEFINE_RESOURCE_ID(PlainArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(PreviewVersion); + WINGET_DEFINE_RESOURCE_ID(QueryArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(RainbowArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(RequiredArgError); + WINGET_DEFINE_RESOURCE_ID(SearchCommandShortDescription); + WINGET_DEFINE_RESOURCE_ID(SearchCommandLongDescription); + WINGET_DEFINE_RESOURCE_ID(ShowCommandLongDescription); + WINGET_DEFINE_RESOURCE_ID(ShowCommandShortDescription); + WINGET_DEFINE_RESOURCE_ID(SilentArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(SingleCharAfterDashError); + WINGET_DEFINE_RESOURCE_ID(SourceAddCommandLongDescription); + WINGET_DEFINE_RESOURCE_ID(SourceAddCommandShortDescription); + WINGET_DEFINE_RESOURCE_ID(SourceArgArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(SourceArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(SourceCommandLongDescription); + WINGET_DEFINE_RESOURCE_ID(SourceCommandShortDescription); + WINGET_DEFINE_RESOURCE_ID(SourceListCommandLongDescription); + WINGET_DEFINE_RESOURCE_ID(SourceListCommandShortDescription); + WINGET_DEFINE_RESOURCE_ID(SourceNameArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(SourceRemoveCommandLongDescription); + WINGET_DEFINE_RESOURCE_ID(SourceRemoveCommandShortDescription); + WINGET_DEFINE_RESOURCE_ID(SourceResetCommandLongDescription); + WINGET_DEFINE_RESOURCE_ID(SourceResetCommandShortDescription); + WINGET_DEFINE_RESOURCE_ID(SourceTypeArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(SourceUpdateCommandLongDescription); + WINGET_DEFINE_RESOURCE_ID(SourceUpdateCommandShortDescription); + WINGET_DEFINE_RESOURCE_ID(TagArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(ToolDescription); + WINGET_DEFINE_RESOURCE_ID(ToolInfoArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(ToolVersionArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(TooManyArgError); + WINGET_DEFINE_RESOURCE_ID(TooManyBehaviorsError); + WINGET_DEFINE_RESOURCE_ID(UnrecognizedCommand); + WINGET_DEFINE_RESOURCE_ID(ValidateCommandLongDescription); + WINGET_DEFINE_RESOURCE_ID(ValidateCommandShortDescription); + WINGET_DEFINE_RESOURCE_ID(ValidateManifestArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(VerboseLogsArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(VersionArgumentDescription); + WINGET_DEFINE_RESOURCE_ID(VersionsArgumentDescription); }; // A localized string - struct LocString : public std::string + struct LocString { + LocString() = default; + LocString(std::wstring_view id); + + LocString(const LocString&) = default; + LocString& operator=(const LocString&) = default; + + LocString(LocString&&) = default; + LocString& operator=(LocString&&) = default; + + const std::string& get() const { return m_value; } + + private: + std::string m_value; }; // Utility class to load resources diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index 6de0b84369..473f277d9b 100644 --- a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +++ b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -161,7 +161,10 @@ Execute the command without prompts - + + Computes the hash of a local file, appropriate for entry into a manifest. It can also compute the hash of the signature file of an MSIX package to enable streaming installations. + + Helper to hash installer files @@ -176,7 +179,10 @@ Filter results by id - + + Installs the selected application, either found by searching a configured source or directly from a manifest. + + Installs the given application @@ -240,7 +246,10 @@ Required argument not provided - + + Searches for applications from configured sources. + + Find and show basic info of apps From 1863ddc56e644bf1b331bc5d89ae56e3e84c5b9d Mon Sep 17 00:00:00 2001 From: John McPherson Date: Sat, 9 May 2020 15:57:19 -0700 Subject: [PATCH 3/8] cp --- src/AppInstallerCLICore/Command.cpp | 8 ++-- src/AppInstallerCLICore/Command.h | 6 +-- .../Commands/InstallCommand.cpp | 2 +- .../Commands/ShowCommand.cpp | 8 ++-- .../Commands/SourceCommand.cpp | 48 +++++++++---------- .../Commands/ValidateCommand.cpp | 8 ++-- src/AppInstallerCLICore/Resources.cpp | 2 +- src/AppInstallerCLICore/Resources.h | 10 +++- 8 files changed, 49 insertions(+), 43 deletions(-) diff --git a/src/AppInstallerCLICore/Command.cpp b/src/AppInstallerCLICore/Command.cpp index e5259a06cf..29a2f874b6 100644 --- a/src/AppInstallerCLICore/Command.cpp +++ b/src/AppInstallerCLICore/Command.cpp @@ -274,7 +274,7 @@ namespace AppInstaller::CLI } // TODO: If we get to a large number of commands, do a fuzzy search much like git - throw CommandException(Resources::GetInstance().ResolveWingetString(L"UnrecognizedCommand"), *itr); + throw CommandException(Resource::String::UnrecognizedCommand, *itr); } // Parse arguments as such: @@ -314,7 +314,7 @@ namespace AppInstaller::CLI if (positionalSearchItr == definedArgs.end()) { - throw CommandException(Resources::GetInstance().ResolveWingetString(L"ExtraPositionalError"), currArg); + throw CommandException(Resource::String::ExtraPositionalError, currArg); } execArgs.AddArg(positionalSearchItr->ExecArgType(), currArg); @@ -322,7 +322,7 @@ namespace AppInstaller::CLI // The currentArg must not be empty, and starts with a - else if (currArg.length() == 1) { - throw CommandException(Resources::GetInstance().ResolveWingetString(L"InvalidArgumentSpecifierError"), currArg); + throw CommandException(Resource::String::InvalidArgumentSpecifierError, currArg); } // Now it must be at least 2 chars else if (currArg[1] != APPINSTALLER_CLI_ARGUMENT_IDENTIFIER_CHAR) @@ -333,7 +333,7 @@ namespace AppInstaller::CLI auto itr = std::find_if(definedArgs.begin(), definedArgs.end(), [&](const Argument& arg) { return (currChar == arg.Alias()); }); if (itr == definedArgs.end()) { - throw CommandException(Resources::GetInstance().ResolveWingetString(L"InvalidAliasError"), currArg); + throw CommandException(Resource::String::InvalidAliasError, currArg); } if (itr->Type() == ArgumentType::Flag) diff --git a/src/AppInstallerCLICore/Command.h b/src/AppInstallerCLICore/Command.h index 2df0a44d85..3b84f6619d 100644 --- a/src/AppInstallerCLICore/Command.h +++ b/src/AppInstallerCLICore/Command.h @@ -19,13 +19,13 @@ namespace AppInstaller::CLI { struct CommandException { - CommandException(std::string message, std::string_view param) : m_message(message), m_param(param) {} + CommandException(Resource::LocString message, std::string_view param) : m_message(std::move(message)), m_param(param) {} - const std::string& Message() const { return m_message; } + const Resource::LocString& Message() const { return m_message; } const std::string_view Param() const { return m_param; } private: - std::string m_message; + Resource::LocString m_message; std::string_view m_param; }; diff --git a/src/AppInstallerCLICore/Commands/InstallCommand.cpp b/src/AppInstallerCLICore/Commands/InstallCommand.cpp index ff40e05cfc..ff27dddf85 100644 --- a/src/AppInstallerCLICore/Commands/InstallCommand.cpp +++ b/src/AppInstallerCLICore/Commands/InstallCommand.cpp @@ -69,7 +69,7 @@ namespace AppInstaller::CLI { if (execArgs.Contains(Execution::Args::Type::Silent) && execArgs.Contains(Execution::Args::Type::Interactive)) { - throw CommandException(Resources::GetInstance().ResolveWingetString(L"TooManyBehaviorsError"), s_InstallCommand_ArgName_SilentAndInteractive); + throw CommandException(Resource::String::TooManyBehaviorsError, s_InstallCommand_ArgName_SilentAndInteractive); } } } diff --git a/src/AppInstallerCLICore/Commands/ShowCommand.cpp b/src/AppInstallerCLICore/Commands/ShowCommand.cpp index 9f0def5330..50d2d11505 100644 --- a/src/AppInstallerCLICore/Commands/ShowCommand.cpp +++ b/src/AppInstallerCLICore/Commands/ShowCommand.cpp @@ -24,14 +24,14 @@ namespace AppInstaller::CLI }; } - std::string ShowCommand::ShortDescription() const + Resource::LocString ShowCommand::ShortDescription() const { - return Resources::GetInstance().ResolveWingetString(L"ShowCommandShortDescription"); + return { Resource::String::ShowCommandShortDescription }; } - std::string ShowCommand::GetLongDescription() const + Resource::LocString ShowCommand::LongDescription() const { - return Resources::GetInstance().ResolveWingetString(L"ShowCommandLongDescription"); + return { Resource::String::ShowCommandLongDescription }; } std::string ShowCommand::HelpLink() const diff --git a/src/AppInstallerCLICore/Commands/SourceCommand.cpp b/src/AppInstallerCLICore/Commands/SourceCommand.cpp index 6e7725dce2..e6811758a1 100644 --- a/src/AppInstallerCLICore/Commands/SourceCommand.cpp +++ b/src/AppInstallerCLICore/Commands/SourceCommand.cpp @@ -24,14 +24,14 @@ namespace AppInstaller::CLI }); } - std::string SourceCommand::ShortDescription() const + Resource::LocString SourceCommand::ShortDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SourceCommandShortDescription"); + return { Resource::String::SourceCommandShortDescription }; } - std::string SourceCommand::GetLongDescription() const + Resource::LocString SourceCommand::LongDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SourceCommandLongDescription"); + return { Resource::String::SourceCommandLongDescription }; } std::string SourceCommand::HelpLink() const @@ -53,14 +53,14 @@ namespace AppInstaller::CLI }; } - std::string SourceAddCommand::ShortDescription() const + Resource::LocString SourceAddCommand::ShortDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SourceAddCommandShortDescription"); + return { Resource::String::SourceAddCommandShortDescription }; } - std::string SourceAddCommand::GetLongDescription() const + Resource::LocString SourceAddCommand::LongDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SourceAddCommandLongDescription"); + return { Resource::String::SourceAddCommandLongDescription }; } std::string SourceAddCommand::HelpLink() const @@ -83,14 +83,14 @@ namespace AppInstaller::CLI }; } - std::string SourceListCommand::ShortDescription() const + Resource::LocString SourceListCommand::ShortDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SourceListCommandShortDescription"); + return { Resource::String::SourceListCommandShortDescription }; } - std::string SourceListCommand::GetLongDescription() const + Resource::LocString SourceListCommand::LongDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SourceListCommandLongDescription"); + return { Resource::String::SourceListCommandLongDescription }; } std::string SourceListCommand::HelpLink() const @@ -112,14 +112,14 @@ namespace AppInstaller::CLI }; } - std::string SourceUpdateCommand::ShortDescription() const + Resource::LocString SourceUpdateCommand::ShortDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SourceUpdateCommandShortDescription"); + return { Resource::String::SourceUpdateCommandShortDescription }; } - std::string SourceUpdateCommand::GetLongDescription() const + Resource::LocString SourceUpdateCommand::LongDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SourceUpdateCommandLongDescription"); + return { Resource::String::SourceUpdateCommandLongDescription }; } std::string SourceUpdateCommand::HelpLink() const @@ -141,14 +141,14 @@ namespace AppInstaller::CLI }; } - std::string SourceRemoveCommand::ShortDescription() const + Resource::LocString SourceRemoveCommand::ShortDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SourceRemoveCommandShortDescription"); + return { Resource::String::SourceRemoveCommandShortDescription }; } - std::string SourceRemoveCommand::GetLongDescription() const + Resource::LocString SourceRemoveCommand::LongDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SourceRemoveCommandLongDescription"); + return { Resource::String::SourceRemoveCommandLongDescription }; } std::string SourceRemoveCommand::HelpLink() const @@ -171,14 +171,14 @@ namespace AppInstaller::CLI }; } - std::string SourceResetCommand::ShortDescription() const + Resource::LocString SourceResetCommand::ShortDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SourceResetCommandShortDescription"); + return { Resource::String::SourceResetCommandShortDescription }; } - std::string SourceResetCommand::GetLongDescription() const + Resource::LocString SourceResetCommand::LongDescription() const { - return Resources::GetInstance().ResolveWingetString(L"SourceResetCommandLongDescription"); + return { Resource::String::SourceResetCommandLongDescription }; } std::string SourceResetCommand::HelpLink() const diff --git a/src/AppInstallerCLICore/Commands/ValidateCommand.cpp b/src/AppInstallerCLICore/Commands/ValidateCommand.cpp index 3c53ed99da..a4faa9717e 100644 --- a/src/AppInstallerCLICore/Commands/ValidateCommand.cpp +++ b/src/AppInstallerCLICore/Commands/ValidateCommand.cpp @@ -16,14 +16,14 @@ namespace AppInstaller::CLI }; } - std::string ValidateCommand::ShortDescription() const + Resource::LocString ValidateCommand::ShortDescription() const { - return Resources::GetInstance().ResolveWingetString(L"ValidateCommandShortDescription"); + return Resource::LocString{ Resource::String::ValidateCommandShortDescription }; } - std::string ValidateCommand::GetLongDescription() const + Resource::LocString ValidateCommand::LongDescription() const { - return Resources::GetInstance().ResolveWingetString(L"ValidateCommandLongDescription"); + return Resource::LocString{ Resource::String::ValidateCommandLongDescription }; } std::string ValidateCommand::HelpLink() const diff --git a/src/AppInstallerCLICore/Resources.cpp b/src/AppInstallerCLICore/Resources.cpp index d642e8916a..fda1ed3e41 100644 --- a/src/AppInstallerCLICore/Resources.cpp +++ b/src/AppInstallerCLICore/Resources.cpp @@ -7,7 +7,7 @@ namespace AppInstaller::CLI::Resource { - LocString::LocString(std::wstring_view id) + LocString::LocString(Id id) { m_value = Loader::Instance().ResolveString(id); } diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index 64e824ce59..128ac7940d 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -11,7 +11,13 @@ namespace AppInstaller::CLI::Resource #define WINGET_WIDE_STRINGIFY_HELP(_id_) L ## _id_ #define WINGET_WIDE_STRINGIFY(_id_) WINGET_WIDE_STRINGIFY_HELP(_id_) -#define WINGET_DEFINE_RESOURCE_ID(_id_) static constexpr std::wstring_view _id_ = WINGET_WIDE_STRINGIFY(#_id_) ## sv +#define WINGET_DEFINE_RESOURCE_ID(_id_) static constexpr Id _id_ = WINGET_WIDE_STRINGIFY(#_id_) ## sv + + // A resource identifier + struct Id : public std::wstring_view + { + constexpr Id(std::wstring_view id) : std::wstring_view(id) {} + }; // Resource string identifiers. // This list can easily be generated by the following PowerShell: @@ -103,7 +109,7 @@ namespace AppInstaller::CLI::Resource { LocString() = default; - LocString(std::wstring_view id); + LocString(Id id); LocString(const LocString&) = default; LocString& operator=(const LocString&) = default; From d7b296c76b4af364f52272b37157f653da05c596 Mon Sep 17 00:00:00 2001 From: John McPherson Date: Mon, 11 May 2020 10:25:17 -0700 Subject: [PATCH 4/8] Types for localized strings added and cleanup for existing use applied --- src/AppInstallerCLICore/Argument.cpp | 62 +++--- src/AppInstallerCLICore/Argument.h | 17 +- src/AppInstallerCLICore/Command.cpp | 36 ++-- .../Commands/RootCommand.cpp | 6 +- src/AppInstallerCLICore/ExecutionReporter.h | 1 + src/AppInstallerCLICore/Resources.cpp | 2 +- src/AppInstallerCLICore/Resources.h | 180 ++++++++++-------- src/AppInstallerCLITests/Command.cpp | 120 ++++++------ 8 files changed, 221 insertions(+), 203 deletions(-) diff --git a/src/AppInstallerCLICore/Argument.cpp b/src/AppInstallerCLICore/Argument.cpp index d72622b1f8..cc174a99fa 100644 --- a/src/AppInstallerCLICore/Argument.cpp +++ b/src/AppInstallerCLICore/Argument.cpp @@ -17,67 +17,67 @@ namespace AppInstaller::CLI switch (type) { case Args::Type::Query: - return Argument{ "query", 'q', Args::Type::Query, Resources::GetInstance().ResolveWingetString(L"QueryArgumentDescription").c_str(), ArgumentType::Positional }; + return Argument{ "query", 'q', Args::Type::Query, Resource::String::QueryArgumentDescription, ArgumentType::Positional }; case Args::Type::Manifest: - return Argument{ "manifest", 'm', Args::Type::Manifest, Resources::GetInstance().ResolveWingetString(L"ManifestArgumentDescription").c_str(), ArgumentType::Standard, Visibility::Help }; + return Argument{ "manifest", 'm', Args::Type::Manifest, Resource::String::ManifestArgumentDescription, ArgumentType::Standard, Visibility::Help }; case Args::Type::Id: - return Argument{ "id", None, Args::Type::Id,Resources::GetInstance().ResolveWingetString(L"IdArgumentDescription").c_str(), ArgumentType::Standard, Visibility::Help }; + return Argument{ "id", None, Args::Type::Id,Resource::String::IdArgumentDescription, ArgumentType::Standard, Visibility::Help }; case Args::Type::Name: - return Argument{ "name", None, Args::Type::Name, Resources::GetInstance().ResolveWingetString(L"NameArgumentDescription").c_str(), ArgumentType::Standard, Visibility::Help }; + return Argument{ "name", None, Args::Type::Name, Resource::String::NameArgumentDescription, ArgumentType::Standard, Visibility::Help }; case Args::Type::Moniker: - return Argument{ "moniker", None, Args::Type::Moniker, Resources::GetInstance().ResolveWingetString(L"MonikerArgumentDescription").c_str(), ArgumentType::Standard, Visibility::Help }; + return Argument{ "moniker", None, Args::Type::Moniker, Resource::String::MonikerArgumentDescription, ArgumentType::Standard, Visibility::Help }; case Args::Type::Tag: - return Argument{ "tag", None, Args::Type::Tag, Resources::GetInstance().ResolveWingetString(L"TagArgumentDescription").c_str(), ArgumentType::Standard, Visibility::Help }; + return Argument{ "tag", None, Args::Type::Tag, Resource::String::TagArgumentDescription, ArgumentType::Standard, Visibility::Help }; case Args::Type::Command: - return Argument{ "command", None, Args::Type::Command, Resources::GetInstance().ResolveWingetString(L"CommandArgumentDescription").c_str(), ArgumentType::Standard, Visibility::Help }; + return Argument{ "command", None, Args::Type::Command, Resource::String::CommandArgumentDescription, ArgumentType::Standard, Visibility::Help }; case Args::Type::Source: - return Argument{ "source", 's', Args::Type::Source, Resources::GetInstance().ResolveWingetString(L"SourceArgumentDescription").c_str(), ArgumentType::Standard }; + return Argument{ "source", 's', Args::Type::Source, Resource::String::SourceArgumentDescription, ArgumentType::Standard }; case Args::Type::Count: - return Argument{ "count", 'n', Args::Type::Count, Resources::GetInstance().ResolveWingetString(L"CountArgumentDescription").c_str(), ArgumentType::Standard }; + return Argument{ "count", 'n', Args::Type::Count, Resource::String::CountArgumentDescription, ArgumentType::Standard }; case Args::Type::Exact: - return Argument{ "exact", 'e', Args::Type::Exact, Resources::GetInstance().ResolveWingetString(L"ExactArgumentDescription").c_str(), ArgumentType::Flag }; + return Argument{ "exact", 'e', Args::Type::Exact, Resource::String::ExactArgumentDescription, ArgumentType::Flag }; case Args::Type::Version: - return Argument{ "version", 'v', Args::Type::Version, Resources::GetInstance().ResolveWingetString(L"VersionArgumentDescription").c_str(), ArgumentType::Standard }; + return Argument{ "version", 'v', Args::Type::Version, Resource::String::VersionArgumentDescription, ArgumentType::Standard }; case Args::Type::Channel: - return Argument{ "channel", 'c', Args::Type::Channel, Resources::GetInstance().ResolveWingetString(L"ChannelArgumentDescription").c_str(), ArgumentType::Standard, Visibility::Hidden }; + return Argument{ "channel", 'c', Args::Type::Channel, Resource::String::ChannelArgumentDescription, ArgumentType::Standard, Visibility::Hidden }; case Args::Type::Interactive: - return Argument{ "interactive", 'i', Args::Type::Interactive, Resources::GetInstance().ResolveWingetString(L"InteractiveArgumentDescription").c_str(), ArgumentType::Flag }; + return Argument{ "interactive", 'i', Args::Type::Interactive, Resource::String::InteractiveArgumentDescription, ArgumentType::Flag }; case Args::Type::Silent: - return Argument{ "silent", 'h', Args::Type::Silent, Resources::GetInstance().ResolveWingetString(L"SilentArgumentDescription").c_str(), ArgumentType::Flag }; + return Argument{ "silent", 'h', Args::Type::Silent, Resource::String::SilentArgumentDescription, ArgumentType::Flag }; case Args::Type::Language: - return Argument{ "lang", 'a', Args::Type::Language, Resources::GetInstance().ResolveWingetString(L"LanguageArgumentDescription").c_str(), ArgumentType::Standard, Visibility::Hidden }; + return Argument{ "lang", 'a', Args::Type::Language, Resource::String::LanguageArgumentDescription, ArgumentType::Standard, Visibility::Hidden }; case Args::Type::Log: - return Argument{ "log", 'o', Args::Type::Log, Resources::GetInstance().ResolveWingetString(L"LogArgumentDesciption").c_str(), ArgumentType::Standard }; + return Argument{ "log", 'o', Args::Type::Log, Resource::String::LogArgumentDesciption, ArgumentType::Standard }; case Args::Type::Override: - return Argument{ "override", None, Args::Type::Override, Resources::GetInstance().ResolveWingetString(L"OverrideArgumentDescription").c_str(), ArgumentType::Standard, Visibility::Help }; + return Argument{ "override", None, Args::Type::Override, Resource::String::OverrideArgumentDescription, ArgumentType::Standard, Visibility::Help }; case Args::Type::InstallLocation: - return Argument{ "location", 'l', Args::Type::InstallLocation, Resources::GetInstance().ResolveWingetString(L"LocationArgumentDescription").c_str(), ArgumentType::Standard }; + return Argument{ "location", 'l', Args::Type::InstallLocation, Resource::String::LocationArgumentDescription, ArgumentType::Standard }; case Args::Type::HashFile: - return Argument{ "file", 'f', Args::Type::HashFile, Resources::GetInstance().ResolveWingetString(L"FileArgumentDescription").c_str(), ArgumentType::Positional, true }; + return Argument{ "file", 'f', Args::Type::HashFile, Resource::String::FileArgumentDescription, ArgumentType::Positional, true }; case Args::Type::Msix: - return Argument{ "msix", 'm', Args::Type::Msix, Resources::GetInstance().ResolveWingetString(L"MsixArgumentDescription").c_str(), ArgumentType::Flag }; + return Argument{ "msix", 'm', Args::Type::Msix, Resource::String::MsixArgumentDescription, ArgumentType::Flag }; case Args::Type::ListVersions: - return Argument{ "versions", None, Args::Type::ListVersions, Resources::GetInstance().ResolveWingetString(L"VersionsArgumentDescription").c_str(), ArgumentType::Flag }; + return Argument{ "versions", None, Args::Type::ListVersions, Resource::String::VersionsArgumentDescription, ArgumentType::Flag }; case Args::Type::Help: - return Argument{ "help", APPINSTALLER_CLI_HELP_ARGUMENT_TEXT_CHAR, Args::Type::Help, Resources::GetInstance().ResolveWingetString(L"HelpArgumentDescription").c_str(), ArgumentType::Flag }; + return Argument{ "help", APPINSTALLER_CLI_HELP_ARGUMENT_TEXT_CHAR, Args::Type::Help, Resource::String::HelpArgumentDescription, ArgumentType::Flag }; case Args::Type::SourceName: - return Argument{ "name", 'n', Args::Type::SourceName,Resources::GetInstance().ResolveWingetString(L"SourceNameArgumentDescription").c_str(), ArgumentType::Positional, false }; + return Argument{ "name", 'n', Args::Type::SourceName,Resource::String::SourceNameArgumentDescription, ArgumentType::Positional, false }; case Args::Type::SourceArg: - return Argument{ "arg", 'a', Args::Type::SourceArg, Resources::GetInstance().ResolveWingetString(L"SourceArgArgumentDescription").c_str(), ArgumentType::Positional, true }; + return Argument{ "arg", 'a', Args::Type::SourceArg, Resource::String::SourceArgArgumentDescription, ArgumentType::Positional, true }; case Args::Type::SourceType: - return Argument{ "type", 't', Args::Type::SourceType, Resources::GetInstance().ResolveWingetString(L"SourceTypeArgumentDescription").c_str(), ArgumentType::Positional }; + return Argument{ "type", 't', Args::Type::SourceType, Resource::String::SourceTypeArgumentDescription, ArgumentType::Positional }; case Args::Type::ValidateManifest: - return Argument{ "manifest", None, Args::Type::ValidateManifest, Resources::GetInstance().ResolveWingetString(L"ValidateManifestArgumentDescription").c_str(), ArgumentType::Positional, true }; + return Argument{ "manifest", None, Args::Type::ValidateManifest, Resource::String::ValidateManifestArgumentDescription, ArgumentType::Positional, true }; case Args::Type::NoVT: - return Argument{ "no-vt", None, Args::Type::NoVT, Resources::GetInstance().ResolveWingetString(L"NoVTArguementDescription").c_str(), ArgumentType::Flag, Visibility::Hidden }; + return Argument{ "no-vt", None, Args::Type::NoVT, Resource::String::NoVTArguementDescription, ArgumentType::Flag, Visibility::Hidden }; case Args::Type::RainbowStyle: - return Argument{ "rainbow", None, Args::Type::RainbowStyle, Resources::GetInstance().ResolveWingetString(L"RainbowArgumentDescription").c_str(), ArgumentType::Flag, Visibility::Hidden }; + return Argument{ "rainbow", None, Args::Type::RainbowStyle, Resource::String::RainbowArgumentDescription, ArgumentType::Flag, Visibility::Hidden }; case Args::Type::PlainStyle: - return Argument{ "plain", None, Args::Type::PlainStyle, Resources::GetInstance().ResolveWingetString(L"PlainArgumentDescription").c_str(), ArgumentType::Flag, Visibility::Hidden }; + return Argument{ "plain", None, Args::Type::PlainStyle, Resource::String::PlainArgumentDescription, ArgumentType::Flag, Visibility::Hidden }; case Args::Type::Force: - return Argument{ "force", None, Args::Type::Force, Resources::GetInstance().ResolveWingetString(L"ForceArgumentDescription").c_str(), ArgumentType::Flag }; + return Argument{ "force", None, Args::Type::Force, Resource::String::ForceArgumentDescription, ArgumentType::Flag }; case Args::Type::VerboseLogs: - return Argument{ "verbose-logs", None, Args::Type::VerboseLogs, Resources::GetInstance().ResolveWingetString(L"VerboseLogsArgumentDescription").c_str(), ArgumentType::Flag }; + return Argument{ "verbose-logs", None, Args::Type::VerboseLogs, Resource::String::VerboseLogsArgumentDescription, ArgumentType::Flag }; default: THROW_HR(E_UNEXPECTED); } diff --git a/src/AppInstallerCLICore/Argument.h b/src/AppInstallerCLICore/Argument.h index 271aed7ea1..8518bafcb5 100644 --- a/src/AppInstallerCLICore/Argument.h +++ b/src/AppInstallerCLICore/Argument.h @@ -2,6 +2,7 @@ // Licensed under the MIT License. #pragma once #include "ExecutionContext.h" +#include "Resources.h" #include #include @@ -43,22 +44,22 @@ namespace AppInstaller::CLI // An argument to a command. struct Argument { - Argument(std::string_view name, char alias, Execution::Args::Type execArgType, std::string desc) : + Argument(std::string_view name, char alias, Execution::Args::Type execArgType, Resource::StringId desc) : m_name(name), m_alias(alias), m_execArgType(execArgType), m_desc(std::move(desc)) {} - Argument(std::string_view name, char alias, Execution::Args::Type execArgType, std::string desc, bool required) : + Argument(std::string_view name, char alias, Execution::Args::Type execArgType, Resource::StringId desc, bool required) : m_name(name), m_alias(alias), m_execArgType(execArgType), m_desc(std::move(desc)), m_required(required) {} - Argument(std::string_view name, char alias, Execution::Args::Type execArgType, std::string desc, ArgumentType type) : + Argument(std::string_view name, char alias, Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type) : m_name(name), m_alias(alias), m_execArgType(execArgType), m_desc(std::move(desc)), m_type(type) {} - Argument(std::string_view name, char alias, Execution::Args::Type execArgType, std::string desc, ArgumentType type, Visibility visibility) : + Argument(std::string_view name, char alias, Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Visibility visibility) : m_name(name), m_alias(alias), m_execArgType(execArgType), m_desc(std::move(desc)), m_type(type), m_visibility(visibility) {} - Argument(std::string_view name, char alias, Execution::Args::Type execArgType, std::string desc, ArgumentType type, bool required) : + Argument(std::string_view name, char alias, Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, bool required) : m_name(name), m_alias(alias), m_execArgType(execArgType), m_desc(std::move(desc)), m_type(type), m_required(required) {} - Argument(std::string_view name, char alias, Execution::Args::Type execArgType, std::string desc, ArgumentType type, Visibility visibility, bool required) : + Argument(std::string_view name, char alias, Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Visibility visibility, bool required) : m_name(name), m_alias(alias), m_execArgType(execArgType), m_desc(std::move(desc)), m_type(type), m_visibility(visibility), m_required(required) {} ~Argument() = default; @@ -78,7 +79,7 @@ namespace AppInstaller::CLI std::string_view Name() const { return m_name; } char Alias() const { return m_alias; } Execution::Args::Type ExecArgType() const { return m_execArgType; } - const std::string& Description() const { return m_desc; } + const Resource::StringId& Description() const { return m_desc; } bool Required() const { return m_required; } ArgumentType Type() const { return m_type; } size_t Limit() const { return m_countLimit; } @@ -90,7 +91,7 @@ namespace AppInstaller::CLI std::string_view m_name; char m_alias; Execution::Args::Type m_execArgType; - std::string m_desc; + Resource::StringId m_desc; bool m_required = false; ArgumentType m_type = ArgumentType::Standard; ::AppInstaller::CLI::Visibility m_visibility = Visibility::Example; diff --git a/src/AppInstallerCLICore/Command.cpp b/src/AppInstallerCLICore/Command.cpp index 29a2f874b6..2070b7e397 100644 --- a/src/AppInstallerCLICore/Command.cpp +++ b/src/AppInstallerCLICore/Command.cpp @@ -27,7 +27,7 @@ namespace AppInstaller::CLI void Command::OutputIntroHeader(Execution::Reporter& reporter) const { reporter.Info() << - "Windows Package Manager v" << Runtime::GetClientVersion() << " " << Resources::GetInstance().ResolveWingetString(L"PreviewVersion") << std::endl << + "Windows Package Manager v" << Runtime::GetClientVersion() << " " << Resource::String::PreviewVersion << std::endl << "Copyright (c) Microsoft Corporation. All rights reserved." << std::endl; } @@ -48,7 +48,7 @@ namespace AppInstaller::CLI // Description auto infoOut = reporter.Info(); infoOut << - GetLongDescription() << std::endl << + LongDescription() << std::endl << std::endl; // Example usage for this command @@ -145,11 +145,11 @@ namespace AppInstaller::CLI { if (Name() == FullName()) { - infoOut << Resources::GetInstance().ResolveWingetString(L"AvailableCommands") << std::endl; + infoOut << Resource::String::AvailableCommands << std::endl; } else { - infoOut << Resources::GetInstance().ResolveWingetString(L"AvailableSubcommands") << std::endl; + infoOut << Resource::String::AvailableSubcommands << std::endl; } size_t maxCommandNameLength = 0; @@ -166,7 +166,7 @@ namespace AppInstaller::CLI infoOut << std::endl << - Resources::GetInstance().ResolveWingetString(L"HelpForDetails") + Resource::String::HelpForDetails << " [" << APPINSTALLER_CLI_HELP_ARGUMENT << ']' << std::endl; } @@ -197,7 +197,7 @@ namespace AppInstaller::CLI if (hasArguments) { - infoOut << Resources::GetInstance().ResolveWingetString(L"AvailableArguements") << std::endl; + infoOut << Resource::String::AvailableArguements << std::endl; size_t i = 0; for (const auto& arg : GetArguments()) @@ -221,7 +221,7 @@ namespace AppInstaller::CLI infoOut << std::endl; } - infoOut << Resources::GetInstance().ResolveWingetString(L"AvailableOptions") << std::endl; + infoOut << Resource::String::AvailableOptions << std::endl; size_t i = 0; for (const auto& arg : GetArguments()) @@ -243,7 +243,7 @@ namespace AppInstaller::CLI std::string helpLink = HelpLink(); if (!helpLink.empty()) { - infoOut << std::endl << Resources::GetInstance().ResolveWingetString(L"HelpLinkPreamble") << ' ' << helpLink << std::endl; + infoOut << std::endl << Resource::String::HelpLinkPreamble << ' ' << helpLink << std::endl; } } @@ -347,11 +347,11 @@ namespace AppInstaller::CLI auto itr2 = std::find_if(definedArgs.begin(), definedArgs.end(), [&](const Argument& arg) { return (currChar == arg.Alias()); }); if (itr2 == definedArgs.end()) { - throw CommandException(Resources::GetInstance().ResolveWingetString(L"AdjoinedNotFoundError"), currArg); + throw CommandException(Resource::String::AdjoinedNotFoundError, currArg); } else if (itr2->Type() != ArgumentType::Flag) { - throw CommandException(Resources::GetInstance().ResolveWingetString(L"AdjoinedNotFlagError"), currArg); + throw CommandException(Resource::String::AdjoinedNotFlagError, currArg); } else { @@ -367,7 +367,7 @@ namespace AppInstaller::CLI } else { - throw CommandException(Resources::GetInstance().ResolveWingetString(L"SingleCharAfterDashError"), currArg); + throw CommandException(Resource::String::SingleCharAfterDashError, currArg); } } else @@ -375,7 +375,7 @@ namespace AppInstaller::CLI ++incomingArgsItr; if (incomingArgsItr == inv.end()) { - throw CommandException(Resources::GetInstance().ResolveWingetString(L"MissingArgumentError"), currArg); + throw CommandException(Resource::String::MissingArgumentError, currArg); } execArgs.AddArg(itr->ExecArgType(), *incomingArgsItr); } @@ -411,7 +411,7 @@ namespace AppInstaller::CLI { if (hasValue) { - throw CommandException(Resources::GetInstance().ResolveWingetString(L"FlagContainAdjoinedError"), currArg); + throw CommandException(Resource::String::FlagContainAdjoinedError, currArg); } execArgs.AddArg(arg.ExecArgType()); @@ -425,7 +425,7 @@ namespace AppInstaller::CLI ++incomingArgsItr; if (incomingArgsItr == inv.end()) { - throw CommandException(Resources::GetInstance().ResolveWingetString(L"MissingArgumentError"), currArg); + throw CommandException(Resource::String::MissingArgumentError, currArg); } execArgs.AddArg(arg.ExecArgType(), *incomingArgsItr); } @@ -436,7 +436,7 @@ namespace AppInstaller::CLI if (!argFound) { - throw CommandException(Resources::GetInstance().ResolveWingetString(L"InvalidNameError"), *incomingArgsItr); + throw CommandException(Resource::String::InvalidNameError, *incomingArgsItr); } } } @@ -472,19 +472,19 @@ namespace AppInstaller::CLI { if (arg.Required() && !execArgs.Contains(arg.ExecArgType())) { - throw CommandException(Resources::GetInstance().ResolveWingetString(L"RequiredArgError"), arg.Name()); + throw CommandException(Resource::String::RequiredArgError, arg.Name()); } if (arg.Limit() < execArgs.GetCount(arg.ExecArgType())) { - throw CommandException(Resources::GetInstance().ResolveWingetString(L"TooManyArgError"), arg.Name()); + throw CommandException(Resource::String::TooManyArgError, arg.Name()); } } } void Command::ExecuteInternal(Execution::Context& context) const { - context.Reporter.Error() << Resources::GetInstance().ResolveWingetString(L"PendingWorkError") << std::endl; + context.Reporter.Error() << Resource::String::PendingWorkError << std::endl; THROW_HR(E_NOTIMPL); } } diff --git a/src/AppInstallerCLICore/Commands/RootCommand.cpp b/src/AppInstallerCLICore/Commands/RootCommand.cpp index c20f2c9440..e2edc4dcb1 100644 --- a/src/AppInstallerCLICore/Commands/RootCommand.cpp +++ b/src/AppInstallerCLICore/Commands/RootCommand.cpp @@ -29,8 +29,8 @@ namespace AppInstaller::CLI { return { - Argument{ "version", 'v', Execution::Args::Type::ListVersions, Resources::GetInstance().ResolveWingetString(L"ToolVersionArgumentDescription").c_str(), ArgumentType::Flag, Visibility::Help }, - Argument{ "info", APPINSTALLER_CLI_ARGUMENT_NO_SHORT_VER, Execution::Args::Type::Info, Resources::GetInstance().ResolveWingetString(L"ToolInfoArgumentDescription").c_str(), ArgumentType::Flag, Visibility::Help }, + Argument{ "version", 'v', Execution::Args::Type::ListVersions, Resource::String::ToolVersionArgumentDescription, ArgumentType::Flag, Visibility::Help }, + Argument{ "info", APPINSTALLER_CLI_ARGUMENT_NO_SHORT_VER, Execution::Args::Type::Info, Resource::String::ToolInfoArgumentDescription, ArgumentType::Flag, Visibility::Help }, }; } @@ -59,7 +59,7 @@ namespace AppInstaller::CLI } else if (context.Args.Contains(Execution::Args::Type::ListVersions)) { - context.Reporter.Info() << 'v' << Runtime::GetClientVersion() << ' ' << Resources::GetInstance().ResolveWingetString(L"PreviewVersion").c_str() << std::endl; + context.Reporter.Info() << 'v' << Runtime::GetClientVersion() << ' ' << Resource::String::PreviewVersion << std::endl; } else { diff --git a/src/AppInstallerCLICore/ExecutionReporter.h b/src/AppInstallerCLICore/ExecutionReporter.h index 4d2ef78465..fa234fab38 100644 --- a/src/AppInstallerCLICore/ExecutionReporter.h +++ b/src/AppInstallerCLICore/ExecutionReporter.h @@ -2,6 +2,7 @@ // Licensed under the MIT License. #pragma once #include "ExecutionProgress.h" +#include "Resources.h" #include "VTSupport.h" #include diff --git a/src/AppInstallerCLICore/Resources.cpp b/src/AppInstallerCLICore/Resources.cpp index fda1ed3e41..0df3402459 100644 --- a/src/AppInstallerCLICore/Resources.cpp +++ b/src/AppInstallerCLICore/Resources.cpp @@ -7,7 +7,7 @@ namespace AppInstaller::CLI::Resource { - LocString::LocString(Id id) + LocString::LocString(StringId id) { m_value = Loader::Instance().ResolveString(id); } diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index 128ac7940d..a826d5dd6c 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -1,9 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #pragma once -#include #include +#include +#include + namespace AppInstaller::CLI::Resource { @@ -11,97 +13,97 @@ namespace AppInstaller::CLI::Resource #define WINGET_WIDE_STRINGIFY_HELP(_id_) L ## _id_ #define WINGET_WIDE_STRINGIFY(_id_) WINGET_WIDE_STRINGIFY_HELP(_id_) -#define WINGET_DEFINE_RESOURCE_ID(_id_) static constexpr Id _id_ = WINGET_WIDE_STRINGIFY(#_id_) ## sv +#define WINGET_DEFINE_RESOURCE_STRINGID(_id_) static constexpr StringId _id_ = WINGET_WIDE_STRINGIFY(#_id_) ## sv // A resource identifier - struct Id : public std::wstring_view + struct StringId : public std::wstring_view { - constexpr Id(std::wstring_view id) : std::wstring_view(id) {} + constexpr StringId(std::wstring_view id) : std::wstring_view(id) {} }; // Resource string identifiers. // This list can easily be generated by the following PowerShell: // > [xml]$res = Get-Content - // > $res.root.data.name | % { "WINGET_DEFINE_RESOURCE_ID($_);" } + // > $res.root.data.name | % { "WINGET_DEFINE_RESOURCE_STRINGID($_);" } struct String { - WINGET_DEFINE_RESOURCE_ID(AdjoinedNotFlagError); - WINGET_DEFINE_RESOURCE_ID(AdjoinedNotFoundError); - WINGET_DEFINE_RESOURCE_ID(AvailableArguements); - WINGET_DEFINE_RESOURCE_ID(AvailableCommands); - WINGET_DEFINE_RESOURCE_ID(AvailableOptions); - WINGET_DEFINE_RESOURCE_ID(AvailableSubcommands); - WINGET_DEFINE_RESOURCE_ID(ChannelArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(CommandArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(CountArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(ExactArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(ExtraPositionalError); - WINGET_DEFINE_RESOURCE_ID(FileArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(FlagContainAdjoinedError); - WINGET_DEFINE_RESOURCE_ID(ForceArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(HashCommandLongDescription); - WINGET_DEFINE_RESOURCE_ID(HashCommandShortDescription); - WINGET_DEFINE_RESOURCE_ID(HelpArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(HelpForDetails); - WINGET_DEFINE_RESOURCE_ID(HelpLinkPreamble); - WINGET_DEFINE_RESOURCE_ID(IdArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(InstallCommandShortDescription); - WINGET_DEFINE_RESOURCE_ID(InstallCommandLongDescription); - WINGET_DEFINE_RESOURCE_ID(InteractiveArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(InvalidAliasError); - WINGET_DEFINE_RESOURCE_ID(InvalidArgumentSpecifierError); - WINGET_DEFINE_RESOURCE_ID(InvalidNameError); - WINGET_DEFINE_RESOURCE_ID(LanguageArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(LocationArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(LogArgumentDesciption); - WINGET_DEFINE_RESOURCE_ID(ManifestArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(MissingArgumentError); - WINGET_DEFINE_RESOURCE_ID(MonikerArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(MsixArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(NameArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(NoVTArguementDescription); - WINGET_DEFINE_RESOURCE_ID(OverrideArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(PendingWorkError); - WINGET_DEFINE_RESOURCE_ID(PlainArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(PreviewVersion); - WINGET_DEFINE_RESOURCE_ID(QueryArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(RainbowArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(RequiredArgError); - WINGET_DEFINE_RESOURCE_ID(SearchCommandShortDescription); - WINGET_DEFINE_RESOURCE_ID(SearchCommandLongDescription); - WINGET_DEFINE_RESOURCE_ID(ShowCommandLongDescription); - WINGET_DEFINE_RESOURCE_ID(ShowCommandShortDescription); - WINGET_DEFINE_RESOURCE_ID(SilentArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(SingleCharAfterDashError); - WINGET_DEFINE_RESOURCE_ID(SourceAddCommandLongDescription); - WINGET_DEFINE_RESOURCE_ID(SourceAddCommandShortDescription); - WINGET_DEFINE_RESOURCE_ID(SourceArgArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(SourceArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(SourceCommandLongDescription); - WINGET_DEFINE_RESOURCE_ID(SourceCommandShortDescription); - WINGET_DEFINE_RESOURCE_ID(SourceListCommandLongDescription); - WINGET_DEFINE_RESOURCE_ID(SourceListCommandShortDescription); - WINGET_DEFINE_RESOURCE_ID(SourceNameArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(SourceRemoveCommandLongDescription); - WINGET_DEFINE_RESOURCE_ID(SourceRemoveCommandShortDescription); - WINGET_DEFINE_RESOURCE_ID(SourceResetCommandLongDescription); - WINGET_DEFINE_RESOURCE_ID(SourceResetCommandShortDescription); - WINGET_DEFINE_RESOURCE_ID(SourceTypeArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(SourceUpdateCommandLongDescription); - WINGET_DEFINE_RESOURCE_ID(SourceUpdateCommandShortDescription); - WINGET_DEFINE_RESOURCE_ID(TagArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(ToolDescription); - WINGET_DEFINE_RESOURCE_ID(ToolInfoArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(ToolVersionArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(TooManyArgError); - WINGET_DEFINE_RESOURCE_ID(TooManyBehaviorsError); - WINGET_DEFINE_RESOURCE_ID(UnrecognizedCommand); - WINGET_DEFINE_RESOURCE_ID(ValidateCommandLongDescription); - WINGET_DEFINE_RESOURCE_ID(ValidateCommandShortDescription); - WINGET_DEFINE_RESOURCE_ID(ValidateManifestArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(VerboseLogsArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(VersionArgumentDescription); - WINGET_DEFINE_RESOURCE_ID(VersionsArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(AdjoinedNotFlagError); + WINGET_DEFINE_RESOURCE_STRINGID(AdjoinedNotFoundError); + WINGET_DEFINE_RESOURCE_STRINGID(AvailableArguements); + WINGET_DEFINE_RESOURCE_STRINGID(AvailableCommands); + WINGET_DEFINE_RESOURCE_STRINGID(AvailableOptions); + WINGET_DEFINE_RESOURCE_STRINGID(AvailableSubcommands); + WINGET_DEFINE_RESOURCE_STRINGID(ChannelArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(CommandArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(CountArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(ExactArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(ExtraPositionalError); + WINGET_DEFINE_RESOURCE_STRINGID(FileArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(FlagContainAdjoinedError); + WINGET_DEFINE_RESOURCE_STRINGID(ForceArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(HashCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(HashCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(HelpArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(HelpForDetails); + WINGET_DEFINE_RESOURCE_STRINGID(HelpLinkPreamble); + WINGET_DEFINE_RESOURCE_STRINGID(IdArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(InstallCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(InstallCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(InteractiveArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(InvalidAliasError); + WINGET_DEFINE_RESOURCE_STRINGID(InvalidArgumentSpecifierError); + WINGET_DEFINE_RESOURCE_STRINGID(InvalidNameError); + WINGET_DEFINE_RESOURCE_STRINGID(LanguageArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(LocationArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(LogArgumentDesciption); + WINGET_DEFINE_RESOURCE_STRINGID(ManifestArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(MissingArgumentError); + WINGET_DEFINE_RESOURCE_STRINGID(MonikerArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(MsixArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(NameArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(NoVTArguementDescription); + WINGET_DEFINE_RESOURCE_STRINGID(OverrideArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(PendingWorkError); + WINGET_DEFINE_RESOURCE_STRINGID(PlainArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(PreviewVersion); + WINGET_DEFINE_RESOURCE_STRINGID(QueryArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(RainbowArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(RequiredArgError); + WINGET_DEFINE_RESOURCE_STRINGID(SearchCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SearchCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(ShowCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(ShowCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SilentArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SingleCharAfterDashError); + WINGET_DEFINE_RESOURCE_STRINGID(SourceAddCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceAddCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceArgArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceListCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceListCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceNameArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceRemoveCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceRemoveCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceResetCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceResetCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceTypeArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceUpdateCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SourceUpdateCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(TagArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(ToolDescription); + WINGET_DEFINE_RESOURCE_STRINGID(ToolInfoArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(ToolVersionArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(TooManyArgError); + WINGET_DEFINE_RESOURCE_STRINGID(TooManyBehaviorsError); + WINGET_DEFINE_RESOURCE_STRINGID(UnrecognizedCommand); + WINGET_DEFINE_RESOURCE_STRINGID(ValidateCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(ValidateCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(ValidateManifestArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(VerboseLogsArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(VersionArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(VersionsArgumentDescription); }; // A localized string @@ -109,7 +111,7 @@ namespace AppInstaller::CLI::Resource { LocString() = default; - LocString(Id id); + LocString(StringId id); LocString(const LocString&) = default; LocString& operator=(const LocString&) = default; @@ -138,4 +140,14 @@ namespace AppInstaller::CLI::Resource Loader(); }; -} \ No newline at end of file +} + +inline std::ostream& operator<<(std::ostream& out, const AppInstaller::CLI::Resource::LocString& ls) +{ + return (out << ls.get()); +} + +inline std::ostream& operator<<(std::ostream& out, AppInstaller::CLI::Resource::StringId si) +{ + return (out << AppInstaller::CLI::Resource::LocString{ si }); +} diff --git a/src/AppInstallerCLITests/Command.cpp b/src/AppInstallerCLITests/Command.cpp index f2de33ad39..1a6c1614b3 100644 --- a/src/AppInstallerCLITests/Command.cpp +++ b/src/AppInstallerCLITests/Command.cpp @@ -7,6 +7,7 @@ #include using namespace std::string_literals; +using namespace std::string_view_literals; using namespace TestCommon; using namespace AppInstaller; using namespace AppInstaller::CLI; @@ -162,13 +163,16 @@ void RequireValueParsedToArg(const std::string& value, const Argument& arg, cons REQUIRE(value == args.GetArg(arg.ExecArgType())); } +// Description used for tests; doesn't need to be anything in particular. +static constexpr Resource::StringId DefaultDesc = L""sv; + TEST_CASE("ParseArguments_MultiplePositional", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, }); std::vector values{ "val1", "val2" }; @@ -184,9 +188,9 @@ TEST_CASE("ParseArguments_ForcePositional", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, }); std::vector values{ "val1", "--", "-std1" }; @@ -202,8 +206,8 @@ TEST_CASE("ParseArguments_TooManyPositional", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, }); std::vector values{ "val1", "--", "-std1" }; @@ -216,9 +220,9 @@ TEST_CASE("ParseArguments_InvalidChar", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, }); std::vector values{ "val1", "-", "-std1" }; @@ -231,9 +235,9 @@ TEST_CASE("ParseArguments_InvalidAlias", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, }); std::vector values{ "val1", "-b", "-std1" }; @@ -246,10 +250,10 @@ TEST_CASE("ParseArguments_MultiFlag", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "flag1", 's', Args::Type::Command, "", ArgumentType::Flag }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, - Argument{ "flag2", 't', Args::Type::Exact, "", ArgumentType::Flag }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "flag1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Flag }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, + Argument{ "flag2", 't', Args::Type::Exact, DefaultDesc, ArgumentType::Flag }, }); std::vector values{ "val1", "-st", "val2" }; @@ -265,10 +269,10 @@ TEST_CASE("ParseArguments_FlagThenUnknown", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "flag1", 's', Args::Type::Command, "", ArgumentType::Flag }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, - Argument{ "flag2", 't', Args::Type::Exact, "", ArgumentType::Flag }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "flag1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Flag }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, + Argument{ "flag2", 't', Args::Type::Exact, DefaultDesc, ArgumentType::Flag }, }); std::vector values{ "val1", "-sr", "val2" }; @@ -281,10 +285,10 @@ TEST_CASE("ParseArguments_FlagThenNonFlag", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "flag1", 's', Args::Type::Command, "", ArgumentType::Flag }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, - Argument{ "flag2", 't', Args::Type::Exact, "", ArgumentType::Flag }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "flag1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Flag }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, + Argument{ "flag2", 't', Args::Type::Exact, DefaultDesc, ArgumentType::Flag }, }); std::vector values{ "val1", "-sp", "val2" }; @@ -297,10 +301,10 @@ TEST_CASE("ParseArguments_NameUsingAliasSpecifier", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, - Argument{ "flag1", 'f', Args::Type::Exact, "", ArgumentType::Flag }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, + Argument{ "flag1", 'f', Args::Type::Exact, DefaultDesc, ArgumentType::Flag }, }); std::vector values{ "another", "-flag1" }; @@ -313,9 +317,9 @@ TEST_CASE("ParseArguments_AliasWithAdjoinedValue", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, }); std::vector values{ "-s=Val1" }; @@ -330,9 +334,9 @@ TEST_CASE("ParseArguments_AliasWithSeparatedValue", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, }); std::vector values{ "-s", "Val1" }; @@ -347,9 +351,9 @@ TEST_CASE("ParseArguments_AliasWithSeparatedValueMissing", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, }); std::vector values{ "-s" }; @@ -362,9 +366,9 @@ TEST_CASE("ParseArguments_NameWithAdjoinedValue", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, }); std::vector values{ "--pos1=Val1" }; @@ -379,10 +383,10 @@ TEST_CASE("ParseArguments_NameFlag", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, - Argument{ "flag1", 'f', Args::Type::Exact, "", ArgumentType::Flag }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, + Argument{ "flag1", 'f', Args::Type::Exact, DefaultDesc, ArgumentType::Flag }, }); std::vector values{ "--flag1", "arbitrary" }; @@ -398,10 +402,10 @@ TEST_CASE("ParseArguments_NameFlagWithAdjoinedValue", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, - Argument{ "flag1", 'f', Args::Type::Exact, "", ArgumentType::Flag }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, + Argument{ "flag1", 'f', Args::Type::Exact, DefaultDesc, ArgumentType::Flag }, }); std::vector values{ "another", "--flag1=arbitrary" }; @@ -414,10 +418,10 @@ TEST_CASE("ParseArguments_NameWithSeparatedValue", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, - Argument{ "flag1", 'f', Args::Type::Exact, "", ArgumentType::Flag }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, + Argument{ "flag1", 'f', Args::Type::Exact, DefaultDesc, ArgumentType::Flag }, }); std::vector values{ "--pos2", "arbitrary" }; @@ -432,10 +436,10 @@ TEST_CASE("ParseArguments_UnknownName", "[command]") { Args args; TestCommand command({ - Argument{ "pos1", 'p', Args::Type::Channel, "", ArgumentType::Positional }, - Argument{ "std1", 's', Args::Type::Command, "", ArgumentType::Standard }, - Argument{ "pos2", 'q', Args::Type::Count, "", ArgumentType::Positional }, - Argument{ "flag1", 'f', Args::Type::Exact, "", ArgumentType::Flag }, + Argument{ "pos1", 'p', Args::Type::Channel, DefaultDesc, ArgumentType::Positional }, + Argument{ "std1", 's', Args::Type::Command, DefaultDesc, ArgumentType::Standard }, + Argument{ "pos2", 'q', Args::Type::Count, DefaultDesc, ArgumentType::Positional }, + Argument{ "flag1", 'f', Args::Type::Exact, DefaultDesc, ArgumentType::Flag }, }); std::vector values{ "another", "--nope" }; From 382ad75fc52ce8abfb0963ae6549af956c5204f4 Mon Sep 17 00:00:00 2001 From: John McPherson Date: Mon, 11 May 2020 12:01:49 -0700 Subject: [PATCH 5/8] Begin enforcement, need to consider how we handle localization independent strings (put in core?) --- src/AppInstallerCLICore/Command.cpp | 2 +- src/AppInstallerCLICore/ExecutionReporter.h | 33 ++++++++++++++++ src/AppInstallerCLICore/Resources.h | 11 +++++- src/AppInstallerCLICore/VTSupport.cpp | 44 ++++++++++----------- src/AppInstallerCLICore/VTSupport.h | 4 +- src/AppInstallerCLITests/Command.cpp | 2 +- 6 files changed, 68 insertions(+), 28 deletions(-) diff --git a/src/AppInstallerCLICore/Command.cpp b/src/AppInstallerCLICore/Command.cpp index 2070b7e397..075ccd38f1 100644 --- a/src/AppInstallerCLICore/Command.cpp +++ b/src/AppInstallerCLICore/Command.cpp @@ -27,7 +27,7 @@ namespace AppInstaller::CLI void Command::OutputIntroHeader(Execution::Reporter& reporter) const { reporter.Info() << - "Windows Package Manager v" << Runtime::GetClientVersion() << " " << Resource::String::PreviewVersion << std::endl << + "Windows Package Manager v" << Runtime::GetClientVersion() << ' ' << Resource::String::PreviewVersion << std::endl << "Copyright (c) Microsoft Corporation. All rights reserved." << std::endl; } diff --git a/src/AppInstallerCLICore/ExecutionReporter.h b/src/AppInstallerCLICore/ExecutionReporter.h index fa234fab38..c77c9c5c05 100644 --- a/src/AppInstallerCLICore/ExecutionReporter.h +++ b/src/AppInstallerCLICore/ExecutionReporter.h @@ -16,6 +16,33 @@ namespace AppInstaller::CLI::Execution { + namespace details + { + // List of approved types for output, others are potentially not localized. + template + struct IsApprovedForOutput + { + static constexpr bool value = false; + }; + +#define WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(_t_) \ + template <> \ + struct IsApprovedForOutput<_t_> \ + { \ + static constexpr bool value = true; \ + } + + // It is assumed that single char values need not be localized, as they are matched + // ordinally or they are punctuation / other. + WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(char); + WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(Resource::StringId); + WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(Resource::LocString); + WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(Resource::LocIndView); + // Normalized strings come from user data and should therefore already by localized + // by how they are chosen (or there is no localized version). + WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(Utility::NormalizedString); + } + // Reporter should be the central place to show workflow status to user. // Todo: need to implement actual console output to show progress bar, etc struct Reporter : public IProgressSink @@ -43,6 +70,12 @@ namespace AppInstaller::CLI::Execution template OutputStream& operator<<(const T& t) { + // TODO: Comment explaining the build error. + //static_assert(details::IsApprovedForOutput>::value, "This type may not be localized, see comment for more information"); + if constexpr (!details::IsApprovedForOutput>::value) + { + AICLI_LOG(CLI, Verbose, << "Needs localization: [" << typeid(T).name() << "] '" << t << '\''); + } ApplyFormat(); m_out << t; return *this; diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index a826d5dd6c..785c3ae422 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -13,12 +13,12 @@ namespace AppInstaller::CLI::Resource #define WINGET_WIDE_STRINGIFY_HELP(_id_) L ## _id_ #define WINGET_WIDE_STRINGIFY(_id_) WINGET_WIDE_STRINGIFY_HELP(_id_) -#define WINGET_DEFINE_RESOURCE_STRINGID(_id_) static constexpr StringId _id_ = WINGET_WIDE_STRINGIFY(#_id_) ## sv +#define WINGET_DEFINE_RESOURCE_STRINGID(_id_) static constexpr StringId _id_ { WINGET_WIDE_STRINGIFY(#_id_) ## sv } // A resource identifier struct StringId : public std::wstring_view { - constexpr StringId(std::wstring_view id) : std::wstring_view(id) {} + explicit constexpr StringId(std::wstring_view id) : std::wstring_view(id) {} }; // Resource string identifiers. @@ -125,6 +125,13 @@ namespace AppInstaller::CLI::Resource std::string m_value; }; + // A localization independent string view. + // Used as a wrapper around strings that do not need localization. + struct LocIndView : public std::string_view + { + explicit constexpr LocIndView(std::string_view sv) : std::string_view(sv) {} + }; + // Utility class to load resources class Loader { diff --git a/src/AppInstallerCLICore/VTSupport.cpp b/src/AppInstallerCLICore/VTSupport.cpp index d41d2b80e1..f7ca740774 100644 --- a/src/AppInstallerCLICore/VTSupport.cpp +++ b/src/AppInstallerCLICore/VTSupport.cpp @@ -87,18 +87,18 @@ namespace AppInstaller::CLI::VirtualTerminal { #define AICLI_VT_SIMPLE_CURSORPOSITON(_c_) AICLI_VT_ESCAPE #_c_ - const Sequence UpOne = AICLI_VT_SIMPLE_CURSORPOSITON(A); - const Sequence DownOne = AICLI_VT_SIMPLE_CURSORPOSITON(B); - const Sequence ForwardOne = AICLI_VT_SIMPLE_CURSORPOSITON(C); - const Sequence BackwardOne = AICLI_VT_SIMPLE_CURSORPOSITON(D); + const Sequence UpOne{ AICLI_VT_SIMPLE_CURSORPOSITON(A) }; + const Sequence DownOne{ AICLI_VT_SIMPLE_CURSORPOSITON(B) }; + const Sequence ForwardOne{ AICLI_VT_SIMPLE_CURSORPOSITON(C) }; + const Sequence BackwardOne{ AICLI_VT_SIMPLE_CURSORPOSITON(D) }; } namespace Visibility { - const Sequence EnableBlink = AICLI_VT_CSI "?12h"; - const Sequence DisableBlink = AICLI_VT_CSI "?12l"; - const Sequence EnableShow = AICLI_VT_CSI "?25h"; - const Sequence DisableShow = AICLI_VT_CSI "?25l"; + const Sequence EnableBlink{ AICLI_VT_CSI "?12h" }; + const Sequence DisableBlink{ AICLI_VT_CSI "?12l" }; + const Sequence EnableShow{ AICLI_VT_CSI "?25h" }; + const Sequence DisableShow{ AICLI_VT_CSI "?25l" }; } } @@ -107,30 +107,30 @@ namespace AppInstaller::CLI::VirtualTerminal // Define a text formatting sequence with an integer id #define AICLI_VT_TEXTFORMAT(_id_) AICLI_VT_CSI #_id_ "m" - const Sequence Default = AICLI_VT_TEXTFORMAT(0); - const Sequence Negative = AICLI_VT_TEXTFORMAT(7); + const Sequence Default{ AICLI_VT_TEXTFORMAT(0) }; + const Sequence Negative{ AICLI_VT_TEXTFORMAT(7) }; Color Color::GetAccentColor() { - static Color accent = GetAccentColorFromSystem(); + static Color accent{ GetAccentColorFromSystem() }; return accent; } namespace Foreground { - const Sequence BrightRed = AICLI_VT_TEXTFORMAT(91); - const Sequence BrightGreen = AICLI_VT_TEXTFORMAT(92); - const Sequence BrightYellow = AICLI_VT_TEXTFORMAT(93); - const Sequence BrightBlue = AICLI_VT_TEXTFORMAT(94); - const Sequence BrightMagenta = AICLI_VT_TEXTFORMAT(95); - const Sequence BrightCyan = AICLI_VT_TEXTFORMAT(96); - const Sequence BrightWhite = AICLI_VT_TEXTFORMAT(97); + const Sequence BrightRed{ AICLI_VT_TEXTFORMAT(91) }; + const Sequence BrightGreen{ AICLI_VT_TEXTFORMAT(92) }; + const Sequence BrightYellow{ AICLI_VT_TEXTFORMAT(93) }; + const Sequence BrightBlue{ AICLI_VT_TEXTFORMAT(94) }; + const Sequence BrightMagenta{ AICLI_VT_TEXTFORMAT(95) }; + const Sequence BrightCyan{ AICLI_VT_TEXTFORMAT(96) }; + const Sequence BrightWhite{ AICLI_VT_TEXTFORMAT(97) }; ConstructedSequence Extended(const Color& color) { std::ostringstream result; result << AICLI_VT_CSI "38;2;" << static_cast(color.R) << ';' << static_cast(color.G) << ';' << static_cast(color.B) << 'm'; - return result.str(); + return ConstructedSequence{ result.str() }; } } @@ -142,8 +142,8 @@ namespace AppInstaller::CLI::VirtualTerminal namespace TextModification { - const Sequence EraseLineForward = AICLI_VT_CSI "0K"; - const Sequence EraseLineBackward = AICLI_VT_CSI "1K"; - const Sequence EraseLineEntirely = AICLI_VT_CSI "2K"; + const Sequence EraseLineForward{ AICLI_VT_CSI "0K" }; + const Sequence EraseLineBackward{ AICLI_VT_CSI "1K" }; + const Sequence EraseLineEntirely{ AICLI_VT_CSI "2K" }; } } diff --git a/src/AppInstallerCLICore/VTSupport.h b/src/AppInstallerCLICore/VTSupport.h index 2831f3d57a..9ddcec271b 100644 --- a/src/AppInstallerCLICore/VTSupport.h +++ b/src/AppInstallerCLICore/VTSupport.h @@ -36,7 +36,7 @@ namespace AppInstaller::CLI::VirtualTerminal struct Sequence { Sequence() = default; - Sequence(const char* c) : m_chars(c) {} + explicit Sequence(const char* c) : m_chars(c) {} const char* Get() const { return m_chars; } @@ -50,7 +50,7 @@ namespace AppInstaller::CLI::VirtualTerminal // A VT sequence that is constructed at runtime. struct ConstructedSequence : public Sequence { - ConstructedSequence(std::string s) : m_str(std::move(s)) { Set(m_str); } + explicit ConstructedSequence(std::string s) : m_str(std::move(s)) { Set(m_str); } private: std::string m_str; diff --git a/src/AppInstallerCLITests/Command.cpp b/src/AppInstallerCLITests/Command.cpp index 1a6c1614b3..188f916fa2 100644 --- a/src/AppInstallerCLITests/Command.cpp +++ b/src/AppInstallerCLITests/Command.cpp @@ -164,7 +164,7 @@ void RequireValueParsedToArg(const std::string& value, const Argument& arg, cons } // Description used for tests; doesn't need to be anything in particular. -static constexpr Resource::StringId DefaultDesc = L""sv; +static constexpr Resource::StringId DefaultDesc{ L""sv }; TEST_CASE("ParseArguments_MultiplePositional", "[command]") { From 9459d53627072bcd60b3eb8cf41675192bff701b Mon Sep 17 00:00:00 2001 From: John McPherson Date: Wed, 13 May 2020 13:51:44 -0700 Subject: [PATCH 6/8] Checkpoint from after machine died --- src/AppInstallerCLICore/ExecutionReporter.h | 6 ++- src/AppInstallerCLICore/Resources.h | 7 --- src/AppInstallerCLICore/pch.h | 1 + src/AppInstallerCLITests/WorkFlow.cpp | 6 ++- .../AppInstallerCommonCore.vcxproj | 1 + .../AppInstallerCommonCore.vcxproj.filters | 3 ++ .../AppInstallerTelemetry.cpp | 8 +-- .../Public/AppInstallerRuntime.h | 7 +-- .../Public/winget/LocIndependent.h | 52 +++++++++++++++++++ src/AppInstallerCommonCore/Runtime.cpp | 40 ++++++++------ .../Microsoft/SQLiteIndexSource.cpp | 10 ++-- .../Public/AppInstallerRepositorySearch.h | 5 +- 12 files changed, 107 insertions(+), 39 deletions(-) create mode 100644 src/AppInstallerCommonCore/Public/winget/LocIndependent.h diff --git a/src/AppInstallerCLICore/ExecutionReporter.h b/src/AppInstallerCLICore/ExecutionReporter.h index c77c9c5c05..2f3f9cb76a 100644 --- a/src/AppInstallerCLICore/ExecutionReporter.h +++ b/src/AppInstallerCLICore/ExecutionReporter.h @@ -5,6 +5,7 @@ #include "Resources.h" #include "VTSupport.h" #include +#include #include @@ -35,9 +36,12 @@ namespace AppInstaller::CLI::Execution // It is assumed that single char values need not be localized, as they are matched // ordinally or they are punctuation / other. WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(char); + // Localized strings (and from an Id for one for convenience). WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(Resource::StringId); WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(Resource::LocString); - WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(Resource::LocIndView); + // Strings explicitly declared as localization independent. + WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(LocIndView); + WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(LocIndString); // Normalized strings come from user data and should therefore already by localized // by how they are chosen (or there is no localized version). WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(Utility::NormalizedString); diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index 785c3ae422..79a8de711d 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -125,13 +125,6 @@ namespace AppInstaller::CLI::Resource std::string m_value; }; - // A localization independent string view. - // Used as a wrapper around strings that do not need localization. - struct LocIndView : public std::string_view - { - explicit constexpr LocIndView(std::string_view sv) : std::string_view(sv) {} - }; - // Utility class to load resources class Loader { diff --git a/src/AppInstallerCLICore/pch.h b/src/AppInstallerCLICore/pch.h index 446163af7f..1a21be21c3 100644 --- a/src/AppInstallerCLICore/pch.h +++ b/src/AppInstallerCLICore/pch.h @@ -46,3 +46,4 @@ #include #include #include +#include diff --git a/src/AppInstallerCLITests/WorkFlow.cpp b/src/AppInstallerCLITests/WorkFlow.cpp index 5b68bdab8e..3fa85b647f 100644 --- a/src/AppInstallerCLITests/WorkFlow.cpp +++ b/src/AppInstallerCLITests/WorkFlow.cpp @@ -14,10 +14,12 @@ #include #include #include +#include using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Management::Deployment; using namespace TestCommon; +using namespace AppInstaller; using namespace AppInstaller::CLI; using namespace AppInstaller::CLI::Execution; using namespace AppInstaller::CLI::Workflow; @@ -41,12 +43,12 @@ struct TestSource : public ISource return m_manifest; } - std::string GetId() override + LocIndString GetId() override { return m_manifest.Id; } - std::string GetName() override + LocIndString GetName() override { return m_manifest.Name; } diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj index cfefb80d8e..f771d597f3 100644 --- a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj +++ b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj @@ -193,6 +193,7 @@ + diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters index b70babfc31..43b45c8b27 100644 --- a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters +++ b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters @@ -99,6 +99,9 @@ Public\winget + + Public\winget + diff --git a/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp b/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp index 6d2d3b9902..99b9df5cd2 100644 --- a/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp +++ b/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp @@ -94,8 +94,8 @@ namespace AppInstaller::Logging void TelemetryTraceLogger::LogStartup() noexcept { - std::string version = Runtime::GetClientVersion(); - std::string packageVersion; + LocIndString version = Runtime::GetClientVersion(); + LocIndString packageVersion; if (Runtime::IsRunningInPackagedContext()) { packageVersion = Runtime::GetPackageVersion(); @@ -107,8 +107,8 @@ namespace AppInstaller::Logging "ClientStartup", GetActivityId(), nullptr, - TraceLoggingCountedString(version.c_str(), static_cast(version.size()), "Version"), - TraceLoggingCountedString(packageVersion.c_str(), static_cast(packageVersion.size()), "PackageVersion"), + TraceLoggingCountedString(version->c_str(), static_cast(version->size()), "Version"), + TraceLoggingCountedString(packageVersion->c_str(), static_cast(packageVersion->size()), "PackageVersion"), TraceLoggingWideString(GetCommandLineW(), "CommandlineArgs"), TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance|PDT_ProductAndServiceUsage), TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)); diff --git a/src/AppInstallerCommonCore/Public/AppInstallerRuntime.h b/src/AppInstallerCommonCore/Public/AppInstallerRuntime.h index c849f84a3d..8b3977f9f5 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerRuntime.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerRuntime.h @@ -2,6 +2,7 @@ // Licensed under the MIT License. #pragma once #include +#include #include #include @@ -14,13 +15,13 @@ namespace AppInstaller::Runtime bool IsRunningInPackagedContext(); // Determines the current version of the client and returns it. - std::string GetClientVersion(); + LocIndString GetClientVersion(); // Determines the current version of the package if running in a packaged context. - std::string GetPackageVersion(); + LocIndString GetPackageVersion(); // Gets a string representation of the OS version for debugging purposes. - std::string GetOSVersion(); + LocIndString GetOSVersion(); // Gets the path to the temp location. std::filesystem::path GetPathToTemp(); diff --git a/src/AppInstallerCommonCore/Public/winget/LocIndependent.h b/src/AppInstallerCommonCore/Public/winget/LocIndependent.h new file mode 100644 index 0000000000..58ccbd5289 --- /dev/null +++ b/src/AppInstallerCommonCore/Public/winget/LocIndependent.h @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include +#include + +namespace AppInstaller +{ + // A localization independent string view. + // Used as a wrapper around strings that do not need localization. + struct LocIndView : public std::string_view + { + explicit constexpr LocIndView(std::string_view sv) : std::string_view(sv) {} + }; + + // Enable easier use of a localization independent view through literals. + inline LocIndView operator ""_liv(const char* chars, size_t size) + { + return LocIndView{ std::string_view{ chars, size } }; + } + + // A localization independent string; either through external localization + // or by virtue of not needing to be localized. + // Intentionally does not allow the value to be modified to prevent accidental + // reintroduction of a localization dependent value. + struct LocIndString + { + LocIndString() = default; + + explicit LocIndString(std::string v) : m_value(std::move(v)) {} + + LocIndString(const LocIndString&) = default; + LocIndString& operator=(const LocIndString&) = default; + + LocIndString(LocIndString&&) = default; + LocIndString& operator=(LocIndString&&) = default; + + const std::string& get() const { return m_value; } + + operator const std::string& () const { return m_value; } + + const std::string* operator->() const { return &m_value; } + + private: + std::string m_value; + }; +} + +inline std::ostream& operator<<(std::ostream& out, const AppInstaller::LocIndString& lis) +{ + return (out << lis.get()); +} diff --git a/src/AppInstallerCommonCore/Runtime.cpp b/src/AppInstallerCommonCore/Runtime.cpp index 94b3ba39e1..8b1bb8426c 100644 --- a/src/AppInstallerCommonCore/Runtime.cpp +++ b/src/AppInstallerCommonCore/Runtime.cpp @@ -181,34 +181,38 @@ namespace AppInstaller::Runtime return result; } - std::string GetClientVersion() + LocIndString GetClientVersion() { using namespace std::string_literals; + // Major and minor come directly from version.h + std::ostringstream strstr; + strstr << VERSION_MAJOR << '.' << VERSION_MINOR << '.'; + + // Build comes from the package for now, if packaged. if (IsRunningInPackagedContext()) { auto version = GetPACKAGE_VERSION(); if (!version) { - return "error"s; + // In the extremely unlikely event of a failure, this is merely a senitinel value + // to indicated such. The only other option is to completely prevent execution, + // which seems unnecessary. + return LocIndString{ "error" }; } - std::ostringstream strstr; - strstr << VERSION_MAJOR << '.' << VERSION_MINOR << '.' << version->Build; - - return strstr.str(); + strstr << version->Build; } else { - std::ostringstream strstr; - strstr << VERSION_MAJOR << '.' << VERSION_MINOR << '.' << VERSION_BUILD; - - return strstr.str(); + strstr << VERSION_BUILD; } + + return LocIndString{ strstr.str() }; } - std::string GetPackageVersion() + LocIndString GetPackageVersion() { using namespace std::string_literals; @@ -218,21 +222,25 @@ namespace AppInstaller::Runtime if (!version) { - return "error"s; + // In the extremely unlikely event of a failure, this is merely a senitinel value + // to indicated such. The only other option is to completely prevent execution, + // which seems unnecessary. + return LocIndString{ "error" }; } std::ostringstream strstr; strstr << GetPackageName() << " v" << version->Major << '.' << version->Minor << '.' << version->Build << '.' << version->Revision; - return strstr.str(); + return LocIndString{ strstr.str() }; } else { - return "none"; + // Calling code should avoid calling in when this is the case. + return LocIndString{ "none" }; } } - std::string GetOSVersion() + LocIndString GetOSVersion() { winrt::Windows::System::Profile::AnalyticsInfo analyticsInfo{}; auto versionInfo = analyticsInfo.VersionInfo(); @@ -249,7 +257,7 @@ namespace AppInstaller::Runtime std::ostringstream strstr; strstr << Utility::ConvertToUTF8(versionInfo.DeviceFamily()) << " v" << parts[3] << '.' << parts[2] << '.' << parts[1] << '.' << parts[0]; - return strstr.str(); + return LocIndString{ strstr.str() }; } std::filesystem::path GetPathToTemp() diff --git a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp index d719a56434..03108569d1 100644 --- a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp +++ b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp @@ -16,14 +16,16 @@ namespace AppInstaller::Repository::Microsoft m_id(id), m_source(source) {} // Inherited via IApplication - std::string GetId() override + LocIndString GetId() override { - return GetSource()->GetIndex().GetIdStringById(m_id).value(); + // Values coming from the index will always be localized/independent. + return LocIndString{ GetSource()->GetIndex().GetIdStringById(m_id).value() }; } - std::string GetName() override + LocIndString GetName() override { - return GetSource()->GetIndex().GetNameStringById(m_id).value(); + // Values coming from the index will always be localized/independent. + return LocIndString{ GetSource()->GetIndex().GetNameStringById(m_id).value() }; } std::optional GetManifest(const Utility::NormalizedString& version, const Utility::NormalizedString& channel) override diff --git a/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h b/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h index b6dd8cd232..56f47e5250 100644 --- a/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h +++ b/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -75,10 +76,10 @@ namespace AppInstaller::Repository virtual ~IApplication() = default; // Gets the id of the application. - virtual std::string GetId() = 0; + virtual LocIndString GetId() = 0; // Gets the name of the application (the latest name). - virtual std::string GetName() = 0; + virtual LocIndString GetName() = 0; // Gets a manifest for this application. // An empty version implies 'latest'. From 1b8d0961accb00fac0dd652cdf1f923e3ba3f7c1 Mon Sep 17 00:00:00 2001 From: John McPherson Date: Mon, 18 May 2020 19:01:48 -0700 Subject: [PATCH 7/8] Last bit of updates before pushing PR --- src/AppInstallerCLICore/Argument.h | 3 +- src/AppInstallerCLICore/Command.cpp | 24 +++---- src/AppInstallerCLICore/Command.h | 6 +- .../Commands/HashCommand.cpp | 9 +-- .../Commands/RootCommand.cpp | 24 ++++--- .../Commands/ValidateCommand.cpp | 6 +- src/AppInstallerCLICore/Core.cpp | 9 +-- src/AppInstallerCLICore/ExecutionReporter.h | 22 +++++-- src/AppInstallerCLICore/Resources.h | 24 ++++++- .../Workflows/InstallFlow.cpp | 8 +-- .../Shared/Strings/en-us/winget.resw | 66 +++++++++++++++++++ .../SQLiteIndexSource.cpp | 4 +- src/AppInstallerCLITests/WorkFlow.cpp | 5 +- .../AppInstallerTelemetry.cpp | 2 + .../Public/AppInstallerRuntime.h | 6 +- .../Public/winget/LocIndependent.h | 19 ++++-- src/AppInstallerCommonCore/Runtime.cpp | 2 + .../Microsoft/SQLiteIndexSource.cpp | 2 + .../Public/AppInstallerRepositorySearch.h | 4 +- 19 files changed, 184 insertions(+), 61 deletions(-) diff --git a/src/AppInstallerCLICore/Argument.h b/src/AppInstallerCLICore/Argument.h index 8518bafcb5..8dd190133d 100644 --- a/src/AppInstallerCLICore/Argument.h +++ b/src/AppInstallerCLICore/Argument.h @@ -76,7 +76,8 @@ namespace AppInstaller::CLI // Gets the common arguments for all commands. static void GetCommon(std::vector& args); - std::string_view Name() const { return m_name; } + // Arguments are not localized at this time. + Utility::LocIndView Name() const { return Utility::LocIndView{ m_name }; } char Alias() const { return m_alias; } Execution::Args::Type ExecArgType() const { return m_execArgType; } const Resource::StringId& Description() const { return m_desc; } diff --git a/src/AppInstallerCLICore/Command.cpp b/src/AppInstallerCLICore/Command.cpp index 075ccd38f1..6eec92c066 100644 --- a/src/AppInstallerCLICore/Command.cpp +++ b/src/AppInstallerCLICore/Command.cpp @@ -7,6 +7,7 @@ namespace AppInstaller::CLI { using namespace std::string_view_literals; + using namespace Utility::literals; Command::Command(std::string_view name, std::string_view parent) : m_name(name) @@ -27,8 +28,8 @@ namespace AppInstaller::CLI void Command::OutputIntroHeader(Execution::Reporter& reporter) const { reporter.Info() << - "Windows Package Manager v" << Runtime::GetClientVersion() << ' ' << Resource::String::PreviewVersion << std::endl << - "Copyright (c) Microsoft Corporation. All rights reserved." << std::endl; + "Windows Package Manager v"_liv << Runtime::GetClientVersion() << ' ' << Resource::String::PreviewVersion << std::endl << + Resource::String::MainCopyrightNotice << std::endl; } void Command::OutputHelp(Execution::Reporter& reporter, const CommandException* exception) const @@ -41,7 +42,7 @@ namespace AppInstaller::CLI if (exception) { reporter.Error() << - exception->Message() << " : '" << exception->Param() << '\'' << std::endl << + exception->Message() << " : '"_liv << exception->Param() << '\'' << std::endl << std::endl; } @@ -52,6 +53,7 @@ namespace AppInstaller::CLI std::endl; // Example usage for this command + // First create the command chain for output std::string commandChain = FullName(); size_t firstSplit = commandChain.find_first_of(ParentSplitChar); if (firstSplit == std::string::npos) @@ -71,7 +73,7 @@ namespace AppInstaller::CLI } // Output the command preamble and command chain - infoOut << "usage: winget" << commandChain; + infoOut << Resource::String::Usage << ": winget"_liv << Utility::LocIndView{ commandChain }; auto commands = GetCommands(); auto arguments = GetArguments(); @@ -89,7 +91,7 @@ namespace AppInstaller::CLI infoOut << '['; } - infoOut << ""; + infoOut << '<' << Resource::String::Command << '>'; if (!arguments.empty()) { @@ -122,7 +124,7 @@ namespace AppInstaller::CLI infoOut << APPINSTALLER_CLI_ARGUMENT_IDENTIFIER_CHAR << arg.Alias(); } - infoOut << "] <" << arg.Name() << '>'; + infoOut << "] <"_liv << arg.Name() << '>'; if (!arg.Required()) { @@ -132,7 +134,7 @@ namespace AppInstaller::CLI else { hasOptions = true; - infoOut << " []"; + infoOut << " [<"_liv << Resource::String::Options << ">]"_liv; break; } } @@ -161,13 +163,13 @@ namespace AppInstaller::CLI for (const auto& command : commands) { size_t fillChars = (maxCommandNameLength - command->Name().length()) + 2; - infoOut << " " << Execution::HelpCommandEmphasis << command->Name() << std::string(fillChars, ' ') << command->ShortDescription() << std::endl; + infoOut << " "_liv << Execution::HelpCommandEmphasis << command->Name() << Utility::LocIndString{ std::string(fillChars, ' ') } << command->ShortDescription() << std::endl; } infoOut << std::endl << Resource::String::HelpForDetails - << " [" << APPINSTALLER_CLI_HELP_ARGUMENT << ']' << std::endl; + << " ["_liv << APPINSTALLER_CLI_HELP_ARGUMENT << ']' << std::endl; } if (!arguments.empty()) @@ -208,7 +210,7 @@ namespace AppInstaller::CLI if (arg.Type() == ArgumentType::Positional) { size_t fillChars = (maxArgNameLength - argName.length()) + 2; - infoOut << " " << Execution::HelpArgumentEmphasis << argName << std::string(fillChars, ' ') << arg.Description() << std::endl; + infoOut << " "_liv << Execution::HelpArgumentEmphasis << argName << Utility::LocIndString{ std::string(fillChars, ' ') } << arg.Description() << std::endl; } } } @@ -232,7 +234,7 @@ namespace AppInstaller::CLI if (arg.Type() != ArgumentType::Positional) { size_t fillChars = (maxArgNameLength - argName.length()) + 2; - infoOut << " " << Execution::HelpArgumentEmphasis << argName << std::string(fillChars, ' ') << arg.Description() << std::endl; + infoOut << " "_liv << Execution::HelpArgumentEmphasis << argName << Utility::LocIndString{ std::string(fillChars, ' ') } << arg.Description() << std::endl; } } } diff --git a/src/AppInstallerCLICore/Command.h b/src/AppInstallerCLICore/Command.h index 3b84f6619d..4bd57e5bc3 100644 --- a/src/AppInstallerCLICore/Command.h +++ b/src/AppInstallerCLICore/Command.h @@ -19,14 +19,16 @@ namespace AppInstaller::CLI { struct CommandException { + // The message should be a localized string, but the parameters are currently not localized. + // We 'convert' the param to a localization independent view here. CommandException(Resource::LocString message, std::string_view param) : m_message(std::move(message)), m_param(param) {} const Resource::LocString& Message() const { return m_message; } - const std::string_view Param() const { return m_param; } + const Utility::LocIndView Param() const { return m_param; } private: Resource::LocString m_message; - std::string_view m_param; + Utility::LocIndView m_param; }; struct Command diff --git a/src/AppInstallerCLICore/Commands/HashCommand.cpp b/src/AppInstallerCLICore/Commands/HashCommand.cpp index 97edb35695..9f94afb683 100644 --- a/src/AppInstallerCLICore/Commands/HashCommand.cpp +++ b/src/AppInstallerCLICore/Commands/HashCommand.cpp @@ -8,6 +8,7 @@ namespace AppInstaller::CLI { using namespace std::string_view_literals; + using namespace Utility::literals; std::vector HashCommand::GetArguments() const { @@ -41,7 +42,7 @@ namespace AppInstaller::CLI auto inputFile = context.Args.GetArg(Execution::Args::Type::HashFile); std::ifstream inStream{ inputFile, std::ifstream::binary }; - context.Reporter.Info() << "File Hash: " + Utility::SHA256::ConvertToString(Utility::SHA256::ComputeHash(inStream)) << std::endl; + context.Reporter.Info() << "Sha256: "_liv << Utility::LocIndString{ Utility::SHA256::ConvertToString(Utility::SHA256::ComputeHash(inStream)) } << std::endl; if (context.Args.Contains(Execution::Args::Type::Msix)) { @@ -51,13 +52,13 @@ namespace AppInstaller::CLI auto signature = msixInfo.GetSignature(); auto signatureHash = Utility::SHA256::ComputeHash(signature.data(), static_cast(signature.size())); - context.Reporter.Info() << "Signature Hash: " + Utility::SHA256::ConvertToString(signatureHash) << std::endl; + context.Reporter.Info() << "SignatureSha256: "_liv << Utility::LocIndString{ Utility::SHA256::ConvertToString(signatureHash) } << std::endl; } catch (const wil::ResultException& re) { context.Reporter.Warn() << - "Failed to calculate MSIX signature hash." << std::endl << - "Please verify that the input file is a valid, signed MSIX." << std::endl; + Resource::String::MsixSignatureHashFailed << std::endl << + Resource::String::VerifyFileSignedMsix << std::endl; AICLI_TERMINATE_CONTEXT(re.GetErrorCode()); } } diff --git a/src/AppInstallerCLICore/Commands/RootCommand.cpp b/src/AppInstallerCLICore/Commands/RootCommand.cpp index 86aedf3096..45b3422f3f 100644 --- a/src/AppInstallerCLICore/Commands/RootCommand.cpp +++ b/src/AppInstallerCLICore/Commands/RootCommand.cpp @@ -9,10 +9,14 @@ #include "SearchCommand.h" #include "HashCommand.h" #include "ValidateCommand.h" + #include "Resources.h" +#include "TableOutput.h" namespace AppInstaller::CLI { + using namespace Utility::literals; + std::vector> RootCommand::GetCommands() const { return InitializeFromMoveOnly>>({ @@ -53,19 +57,23 @@ namespace AppInstaller::CLI auto info = context.Reporter.Info(); info << std::endl << - "Windows: " << Runtime::GetOSVersion() << std::endl; + "Windows: "_liv << Runtime::GetOSVersion() << std::endl; if (Runtime::IsRunningInPackagedContext()) { - info << "Package: " << Runtime::GetPackageVersion() << std::endl; + info << Resource::String::Package << ": "_liv << Runtime::GetPackageVersion() << std::endl; }; - 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; + info << std::endl; + + Execution::TableOutput<2> links{ context.Reporter, { Resource::LocString(Resource::String::Links).get(), "" } }; + + links.OutputLine({ Resource::LocString(Resource::String::PrivacyStatement).get(), "https://aka.ms/winget-privacy" }); + links.OutputLine({ Resource::LocString(Resource::String::LicenseAgreement).get(), "https://aka.ms/winget-license" }); + links.OutputLine({ Resource::LocString(Resource::String::ThirdPartSoftwareNotices).get(), "https://aka.ms/winget-3rdPartyNotice" }); + links.OutputLine({ Resource::LocString(Resource::String::MainHomepage).get(), "https://aka.ms/winget" }); + + links.Complete(); } else if (context.Args.Contains(Execution::Args::Type::ListVersions)) { diff --git a/src/AppInstallerCLICore/Commands/ValidateCommand.cpp b/src/AppInstallerCLICore/Commands/ValidateCommand.cpp index a4faa9717e..1311c49b46 100644 --- a/src/AppInstallerCLICore/Commands/ValidateCommand.cpp +++ b/src/AppInstallerCLICore/Commands/ValidateCommand.cpp @@ -42,17 +42,17 @@ namespace AppInstaller::CLI try { (void)Manifest::Manifest::CreateFromPath(inputFile, true, true); - context.Reporter.Info() << "Manifest validation succeeded." << std::endl; + context.Reporter.Info() << Resource::String::ManifestValidationSuccess << std::endl; } catch (const Manifest::ManifestException& e) { if (e.IsWarningOnly()) { - context.Reporter.Warn() << "Manifest validation succeeded with warnings." << std::endl; + context.Reporter.Warn() << Resource::String::ManifestValidationWarning << std::endl; } else { - context.Reporter.Error() << "Manifest validation failed." << std::endl; + context.Reporter.Error() << Resource::String::ManifestValidationFail << std::endl; } context.Reporter.Info() << e.GetManifestErrorMessage() << std::endl; diff --git a/src/AppInstallerCLICore/Core.cpp b/src/AppInstallerCLICore/Core.cpp index 55c2b62dc5..dd188c89d4 100644 --- a/src/AppInstallerCLICore/Core.cpp +++ b/src/AppInstallerCLICore/Core.cpp @@ -8,6 +8,7 @@ using namespace winrt; using namespace winrt::Windows::Foundation; using namespace AppInstaller::CLI; +using namespace AppInstaller::Utility::literals; namespace AppInstaller::CLI { @@ -117,7 +118,7 @@ namespace AppInstaller::CLI // Even though they are logged at their source, log again here for completeness. Logging::Telemetry().LogException(command->FullName(), "wil::ResultException", re.what()); context.Reporter.Error() << - "An unexpected error occurred while executing the command: " << std::endl << + Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl << GetUserPresentableMessage(re) << std::endl; return re.GetErrorCode(); } @@ -126,7 +127,7 @@ namespace AppInstaller::CLI 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 << + Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl << message << std::endl; return hre.code(); } @@ -134,7 +135,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 << + Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl << GetUserPresentableMessage(e) << std::endl; return APPINSTALLER_CLI_ERROR_COMMAND_FAILED; } @@ -143,7 +144,7 @@ namespace AppInstaller::CLI LOG_CAUGHT_EXCEPTION(); Logging::Telemetry().LogException(command->FullName(), "unknown", {}); context.Reporter.Error() << - "An unexpected error occurred while executing the command" << std::endl; + Resource::String::UnexpectedErrorExecutingCommand << " ???"_liv << std::endl; return APPINSTALLER_CLI_ERROR_COMMAND_FAILED; } diff --git a/src/AppInstallerCLICore/ExecutionReporter.h b/src/AppInstallerCLICore/ExecutionReporter.h index 2f3f9cb76a..8febfc33c4 100644 --- a/src/AppInstallerCLICore/ExecutionReporter.h +++ b/src/AppInstallerCLICore/ExecutionReporter.h @@ -40,8 +40,8 @@ namespace AppInstaller::CLI::Execution WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(Resource::StringId); WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(Resource::LocString); // Strings explicitly declared as localization independent. - WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(LocIndView); - WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(LocIndString); + WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(Utility::LocIndView); + WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(Utility::LocIndString); // Normalized strings come from user data and should therefore already by localized // by how they are chosen (or there is no localized version). WINGET_CREATE_ISAPPROVEDFOROUTPUT_SPECIALIZATION(Utility::NormalizedString); @@ -74,12 +74,20 @@ namespace AppInstaller::CLI::Execution template OutputStream& operator<<(const T& t) { - // TODO: Comment explaining the build error. + // You've found your way here because you tried to output a type that may not localized. + // In order to ensure that all output is localized, only the types with specializations of + // details::IsApprovedForOutput above can be output. + // * If your string is a simple message, it should be put in + // /src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw + // and referenced in /src/AppInstallerCLICore/Resources.h. Then either output the + // Resource::StringId, or load it manually and output the Resource::LocString. + // * If your string is *definitely* localization independent, you can tag it as such with + // the Utility::LocInd(View/String) types. + // * If your string came from outside of the source code, it is best to store it in a + // Utility::NormalizedString so that it has a normalized representation. This also + // informs the output that there is no localized version to use. + // TODO: Convert the rest of the code base and uncomment to enforce localization. //static_assert(details::IsApprovedForOutput>::value, "This type may not be localized, see comment for more information"); - if constexpr (!details::IsApprovedForOutput>::value) - { - AICLI_LOG(CLI, Verbose, << "Needs localization: [" << typeid(T).name() << "] '" << t << '\''); - } ApplyFormat(); m_out << t; return *this; diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index 79a8de711d..2cd12230b1 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -34,6 +34,7 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(AvailableOptions); WINGET_DEFINE_RESOURCE_STRINGID(AvailableSubcommands); WINGET_DEFINE_RESOURCE_STRINGID(ChannelArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(Command); WINGET_DEFINE_RESOURCE_STRINGID(CommandArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(CountArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(ExactArgumentDescription); @@ -47,30 +48,45 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(HelpForDetails); WINGET_DEFINE_RESOURCE_STRINGID(HelpLinkPreamble); WINGET_DEFINE_RESOURCE_STRINGID(IdArgumentDescription); - WINGET_DEFINE_RESOURCE_STRINGID(InstallCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(InstallationDisclaimer1); + WINGET_DEFINE_RESOURCE_STRINGID(InstallationDisclaimer2); + WINGET_DEFINE_RESOURCE_STRINGID(InstallationRequiresHigherWindows); WINGET_DEFINE_RESOURCE_STRINGID(InstallCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(InstallCommandShortDescription); WINGET_DEFINE_RESOURCE_STRINGID(InteractiveArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(InvalidAliasError); WINGET_DEFINE_RESOURCE_STRINGID(InvalidArgumentSpecifierError); WINGET_DEFINE_RESOURCE_STRINGID(InvalidNameError); WINGET_DEFINE_RESOURCE_STRINGID(LanguageArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(LicenseAgreement); + WINGET_DEFINE_RESOURCE_STRINGID(Links); WINGET_DEFINE_RESOURCE_STRINGID(LocationArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(LogArgumentDesciption); + WINGET_DEFINE_RESOURCE_STRINGID(MainCopyrightNotice); + WINGET_DEFINE_RESOURCE_STRINGID(MainHomepage); WINGET_DEFINE_RESOURCE_STRINGID(ManifestArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(ManifestValidationFail); + WINGET_DEFINE_RESOURCE_STRINGID(ManifestValidationSuccess); + WINGET_DEFINE_RESOURCE_STRINGID(ManifestValidationWarning); WINGET_DEFINE_RESOURCE_STRINGID(MissingArgumentError); WINGET_DEFINE_RESOURCE_STRINGID(MonikerArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(MsixArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(MsixSignatureHashFailed); WINGET_DEFINE_RESOURCE_STRINGID(NameArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(NoApplicableInstallers); WINGET_DEFINE_RESOURCE_STRINGID(NoVTArguementDescription); + WINGET_DEFINE_RESOURCE_STRINGID(Options); WINGET_DEFINE_RESOURCE_STRINGID(OverrideArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(Package); WINGET_DEFINE_RESOURCE_STRINGID(PendingWorkError); WINGET_DEFINE_RESOURCE_STRINGID(PlainArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(PreviewVersion); + WINGET_DEFINE_RESOURCE_STRINGID(PrivacyStatement); WINGET_DEFINE_RESOURCE_STRINGID(QueryArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(RainbowArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(RequiredArgError); - WINGET_DEFINE_RESOURCE_STRINGID(SearchCommandShortDescription); WINGET_DEFINE_RESOURCE_STRINGID(SearchCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SearchCommandShortDescription); WINGET_DEFINE_RESOURCE_STRINGID(ShowCommandLongDescription); WINGET_DEFINE_RESOURCE_STRINGID(ShowCommandShortDescription); WINGET_DEFINE_RESOURCE_STRINGID(SilentArgumentDescription); @@ -92,16 +108,20 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(SourceUpdateCommandLongDescription); WINGET_DEFINE_RESOURCE_STRINGID(SourceUpdateCommandShortDescription); WINGET_DEFINE_RESOURCE_STRINGID(TagArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(ThirdPartSoftwareNotices); WINGET_DEFINE_RESOURCE_STRINGID(ToolDescription); WINGET_DEFINE_RESOURCE_STRINGID(ToolInfoArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(ToolVersionArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(TooManyArgError); WINGET_DEFINE_RESOURCE_STRINGID(TooManyBehaviorsError); + WINGET_DEFINE_RESOURCE_STRINGID(UnexpectedErrorExecutingCommand); WINGET_DEFINE_RESOURCE_STRINGID(UnrecognizedCommand); + WINGET_DEFINE_RESOURCE_STRINGID(Usage); WINGET_DEFINE_RESOURCE_STRINGID(ValidateCommandLongDescription); WINGET_DEFINE_RESOURCE_STRINGID(ValidateCommandShortDescription); WINGET_DEFINE_RESOURCE_STRINGID(ValidateManifestArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(VerboseLogsArgumentDescription); + WINGET_DEFINE_RESOURCE_STRINGID(VerifyFileSignedMsix); WINGET_DEFINE_RESOURCE_STRINGID(VersionArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(VersionsArgumentDescription); }; diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index 7120bb5a58..11b653837e 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -20,7 +20,7 @@ namespace AppInstaller::CLI::Workflow if (!manifest.MinOSVersion.empty() && !Runtime::IsCurrentOSVersionGreaterThanOrEqual(Version(manifest.MinOSVersion))) { - context.Reporter.Error() << "Cannot install application, as it requires a higher OS version: " << manifest.MinOSVersion << std::endl; + context.Reporter.Error() << Resource::String::InstallationRequiresHigherWindows << ' ' << manifest.MinOSVersion << std::endl; AICLI_TERMINATE_CONTEXT(HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION)); } } @@ -31,7 +31,7 @@ namespace AppInstaller::CLI::Workflow if (!installer.has_value()) { - context.Reporter.Error() << "No installers are applicable to the current system" << std::endl; + context.Reporter.Error() << Resource::String::NoApplicableInstallers << std::endl; AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_NO_APPLICABLE_INSTALLER); } } @@ -39,8 +39,8 @@ namespace AppInstaller::CLI::Workflow void ShowInstallationDisclaimer(Execution::Context& context) { context.Reporter.Info() << - "This application is licensed to you by its owner." << std::endl << - "Microsoft is not responsible for, nor does it grant any licenses to, third-party packages." << std::endl; + Resource::String::InstallationDisclaimer1 << std::endl << + Resource::String::InstallationDisclaimer2 << std::endl; } void DownloadInstaller(Execution::Context& context) diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index 473f277d9b..cdd17a2e7c 100644 --- a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +++ b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -140,6 +140,10 @@ Use the specified channel; default is general audience + + command + A command to give the software + Filter results by command @@ -179,6 +183,15 @@ Filter results by id + + This application is licensed to you by its owner. + + + Microsoft is not responsible for, nor does it grant any licenses to, third-party packages. + + + Cannot install application, as it requires a higher version of Windows: + Installs the selected application, either found by searching a configured source or directly from a manifest. @@ -200,15 +213,38 @@ Language to install (if supported) + + License Agreement + + + Links + Links to different webpages + Location to install to (if supported) Log location (if supported) + + Copyright (c) Microsoft Corporation. All rights reserved. + + + Homepage + The primary webpage for the software + The path to the manifest of the application + + Manifest validation failed. + + + Manifest validation succeeded. + + + Manifest validation succeeded with warnings. + Argument value required, but none found @@ -218,16 +254,30 @@ Input file will be treated as msix; signature hash will be provided if signed + + Failed to calculate MSIX signature hash. + Filter results by name + + No installers are applicable to the current system. + Disables VirtualTerminal display {Locked="VirtualTerminal"} + + options + Options to change how a command works + Override arguments to be passed on to the installer + + Package + A software package + Oops, we forgot to do this... @@ -237,6 +287,9 @@ Preview + + Privacy Statement + The query used to search for an app @@ -315,6 +368,9 @@ Filter results by tag + + Third Party Notices + WinGet command line utility enables installing applications from the command line. @@ -330,9 +386,16 @@ More than one install behavior argument provided + + An unexpected error occurred while executing the command: + Unrecognized command + + usage + The way to use the software + Validates a manifest using a strict set of guidelines. This is intended to enable you to check your manifest before submitting to a repo. @@ -345,6 +408,9 @@ Enables verbose logging for WinGet + + Please verify that the input file is a valid, signed MSIX. + Use the specified version; default is the latest version diff --git a/src/AppInstallerCLITests/SQLiteIndexSource.cpp b/src/AppInstallerCLITests/SQLiteIndexSource.cpp index 560a52edc6..7f35b6ce84 100644 --- a/src/AppInstallerCLITests/SQLiteIndexSource.cpp +++ b/src/AppInstallerCLITests/SQLiteIndexSource.cpp @@ -87,7 +87,7 @@ TEST_CASE("SQLiteIndexSource_Id", "[sqliteindexsource]") REQUIRE(results.Matches[0].Application); IApplication* app = results.Matches[0].Application.get(); - REQUIRE(app->GetId() == manifest.Id); + REQUIRE(app->GetId().get() == manifest.Id); } TEST_CASE("SQLiteIndexSource_Name", "[sqliteindexsource]") @@ -108,7 +108,7 @@ TEST_CASE("SQLiteIndexSource_Name", "[sqliteindexsource]") REQUIRE(results.Matches[0].Application); IApplication* app = results.Matches[0].Application.get(); - REQUIRE(app->GetName() == manifest.Name); + REQUIRE(app->GetName().get() == manifest.Name); } TEST_CASE("SQLiteIndexSource_Versions", "[sqliteindexsource]") diff --git a/src/AppInstallerCLITests/WorkFlow.cpp b/src/AppInstallerCLITests/WorkFlow.cpp index 3fa85b647f..11655f00c6 100644 --- a/src/AppInstallerCLITests/WorkFlow.cpp +++ b/src/AppInstallerCLITests/WorkFlow.cpp @@ -19,7 +19,6 @@ using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Management::Deployment; using namespace TestCommon; -using namespace AppInstaller; using namespace AppInstaller::CLI; using namespace AppInstaller::CLI::Execution; using namespace AppInstaller::CLI::Workflow; @@ -45,12 +44,12 @@ struct TestSource : public ISource LocIndString GetId() override { - return m_manifest.Id; + return LocIndString{ m_manifest.Id }; } LocIndString GetName() override { - return m_manifest.Name; + return LocIndString{ m_manifest.Name }; } std::vector GetVersions() override diff --git a/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp b/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp index 99b9df5cd2..2e58976b8b 100644 --- a/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp +++ b/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp @@ -28,6 +28,8 @@ std::ostream& operator<<(std::ostream& out, const GUID& guid) namespace AppInstaller::Logging { + using namespace Utility; + namespace { void __stdcall wilResultLoggingCallback(const wil::FailureInfo& info) noexcept diff --git a/src/AppInstallerCommonCore/Public/AppInstallerRuntime.h b/src/AppInstallerCommonCore/Public/AppInstallerRuntime.h index 8b3977f9f5..6092e62831 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerRuntime.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerRuntime.h @@ -15,13 +15,13 @@ namespace AppInstaller::Runtime bool IsRunningInPackagedContext(); // Determines the current version of the client and returns it. - LocIndString GetClientVersion(); + Utility::LocIndString GetClientVersion(); // Determines the current version of the package if running in a packaged context. - LocIndString GetPackageVersion(); + Utility::LocIndString GetPackageVersion(); // Gets a string representation of the OS version for debugging purposes. - LocIndString GetOSVersion(); + Utility::LocIndString GetOSVersion(); // Gets the path to the temp location. std::filesystem::path GetPathToTemp(); diff --git a/src/AppInstallerCommonCore/Public/winget/LocIndependent.h b/src/AppInstallerCommonCore/Public/winget/LocIndependent.h index 58ccbd5289..750e66ad70 100644 --- a/src/AppInstallerCommonCore/Public/winget/LocIndependent.h +++ b/src/AppInstallerCommonCore/Public/winget/LocIndependent.h @@ -4,8 +4,9 @@ #include #include -namespace AppInstaller +namespace AppInstaller::Utility { + // "I solemnly swear that this string is indeed localization independent." // A localization independent string view. // Used as a wrapper around strings that do not need localization. struct LocIndView : public std::string_view @@ -13,12 +14,17 @@ namespace AppInstaller explicit constexpr LocIndView(std::string_view sv) : std::string_view(sv) {} }; - // Enable easier use of a localization independent view through literals. - inline LocIndView operator ""_liv(const char* chars, size_t size) + namespace literals { - return LocIndView{ std::string_view{ chars, size } }; + // "I solemnly swear that this string is indeed localization independent." + // Enable easier use of a localization independent view through literals. + inline LocIndView operator ""_liv(const char* chars, size_t size) + { + return LocIndView{ std::string_view{ chars, size } }; + } } + // "I solemnly swear that this string is indeed localization independent." // A localization independent string; either through external localization // or by virtue of not needing to be localized. // Intentionally does not allow the value to be modified to prevent accidental @@ -38,15 +44,18 @@ namespace AppInstaller const std::string& get() const { return m_value; } operator const std::string& () const { return m_value; } + operator std::string_view() const { return m_value; } const std::string* operator->() const { return &m_value; } + bool operator==(std::string_view sv) { return m_value == sv; } + private: std::string m_value; }; } -inline std::ostream& operator<<(std::ostream& out, const AppInstaller::LocIndString& lis) +inline std::ostream& operator<<(std::ostream& out, const AppInstaller::Utility::LocIndString& lis) { return (out << lis.get()); } diff --git a/src/AppInstallerCommonCore/Runtime.cpp b/src/AppInstallerCommonCore/Runtime.cpp index 8b1bb8426c..0d1fe982e4 100644 --- a/src/AppInstallerCommonCore/Runtime.cpp +++ b/src/AppInstallerCommonCore/Runtime.cpp @@ -10,6 +10,8 @@ namespace AppInstaller::Runtime { + using namespace Utility; + namespace { using namespace std::string_view_literals; diff --git a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp index 03108569d1..32ae79b87e 100644 --- a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp +++ b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp @@ -7,6 +7,8 @@ namespace AppInstaller::Repository::Microsoft { + using namespace Utility; + namespace { // The IApplication impl for SQLiteIndexSource. diff --git a/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h b/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h index 56f47e5250..796ac968d9 100644 --- a/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h +++ b/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h @@ -76,10 +76,10 @@ namespace AppInstaller::Repository virtual ~IApplication() = default; // Gets the id of the application. - virtual LocIndString GetId() = 0; + virtual Utility::LocIndString GetId() = 0; // Gets the name of the application (the latest name). - virtual LocIndString GetName() = 0; + virtual Utility::LocIndString GetName() = 0; // Gets a manifest for this application. // An empty version implies 'latest'. From 6f0b1b36a8005d2699a188835d05923364323d68 Mon Sep 17 00:00:00 2001 From: John McPherson Date: Mon, 18 May 2020 19:09:08 -0700 Subject: [PATCH 8/8] Fix a few tests dented by the changes --- src/AppInstallerCLIE2ETests/InstallCommand.cs | 2 +- src/AppInstallerCLITests/HashCommand.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AppInstallerCLIE2ETests/InstallCommand.cs b/src/AppInstallerCLIE2ETests/InstallCommand.cs index 7327e08a00..40aec5f307 100644 --- a/src/AppInstallerCLIE2ETests/InstallCommand.cs +++ b/src/AppInstallerCLIE2ETests/InstallCommand.cs @@ -54,7 +54,7 @@ public void InstallCommands() installDir = TestCommon.GetRandomTestDir(); result = TestCommon.RunAICLICommand("install", $"InapplicableOsVersion --silent -l {installDir}"); Assert.AreEqual(Constants.ErrorCode.ERROR_OLD_WIN_VERSION, result.ExitCode); - Assert.True(result.StdOut.Contains("Cannot install application, as it requires a higher OS version")); + Assert.True(result.StdOut.Contains("Cannot install application, as it requires a higher version of Windows")); Assert.False(VerifyTestExeInstalled(installDir)); // Install test exe but hash mismatch, passing N should cause the installation to fail diff --git a/src/AppInstallerCLITests/HashCommand.cpp b/src/AppInstallerCLITests/HashCommand.cpp index 998958cf67..40845e56b5 100644 --- a/src/AppInstallerCLITests/HashCommand.cpp +++ b/src/AppInstallerCLITests/HashCommand.cpp @@ -18,6 +18,6 @@ TEST_CASE("HashCommandWithTestMsix", "[Sha256Hash]") hashCommand.Execute(context); - REQUIRE(hashOutput.str().find("File Hash: 6a2d3683fa19bf00e58e07d1313d20a5f5735ebbd6a999d33381d28740ee07ea") != std::string::npos); - REQUIRE(hashOutput.str().find("Signature Hash: 138781c3e6f635240353f3d14d1d57bdcb89413e49be63b375e6a5d7b93b0d07") != std::string::npos); + REQUIRE(hashOutput.str().find("Sha256: 6a2d3683fa19bf00e58e07d1313d20a5f5735ebbd6a999d33381d28740ee07ea") != std::string::npos); + REQUIRE(hashOutput.str().find("SignatureSha256: 138781c3e6f635240353f3d14d1d57bdcb89413e49be63b375e6a5d7b93b0d07") != std::string::npos); } \ No newline at end of file