diff options
author | Brad King <brad.king@kitware.com> | 2022-07-08 13:06:45 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2022-07-08 13:06:52 (GMT) |
commit | 974511a87058d0c861a18862994a7b2d4d6753ef (patch) | |
tree | d162e5e647e5cb58ff9544932645352197c70038 | |
parent | 983a5b1a7e5ae11f996e05af158036574d4c70bf (diff) | |
parent | f46b2e914256322fc8d33b425ec01e9d9c1496ba (diff) | |
download | CMake-974511a87058d0c861a18862994a7b2d4d6753ef.zip CMake-974511a87058d0c861a18862994a7b2d4d6753ef.tar.gz CMake-974511a87058d0c861a18862994a7b2d4d6753ef.tar.bz2 |
Merge topic 'command-arg-parser-maybe-empty'
f46b2e9142 cmArgumentParser: Model maybe-missing string with wrapper type
e6d1e29ffa cmArgumentParser: Model maybe-empty and non-empty lists with wrapper types
Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: buildbot <buildbot@kitware.com>
Merge-request: !7459
-rw-r--r-- | Source/CTest/cmCTestCoverageCommand.h | 3 | ||||
-rw-r--r-- | Source/CTest/cmCTestSubmitCommand.h | 7 | ||||
-rw-r--r-- | Source/CTest/cmCTestUploadCommand.h | 3 | ||||
-rw-r--r-- | Source/cmArgumentParser.cxx | 18 | ||||
-rw-r--r-- | Source/cmArgumentParser.h | 6 | ||||
-rw-r--r-- | Source/cmArgumentParserTypes.h | 24 | ||||
-rw-r--r-- | Source/cmCMakeLanguageCommand.cxx | 3 | ||||
-rw-r--r-- | Source/cmDefinePropertyCommand.cxx | 5 | ||||
-rw-r--r-- | Source/cmExportCommand.cxx | 3 | ||||
-rw-r--r-- | Source/cmFileCommand.cxx | 110 | ||||
-rw-r--r-- | Source/cmInstallCommand.cxx | 60 | ||||
-rw-r--r-- | Source/cmInstallCommandArguments.h | 5 | ||||
-rw-r--r-- | Source/cmParseArgumentsCommand.cxx | 4 | ||||
-rw-r--r-- | Source/cmTargetSourcesCommand.cxx | 5 | ||||
-rw-r--r-- | Tests/CMakeLib/testArgumentParser.cxx | 22 |
15 files changed, 160 insertions, 118 deletions
diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h index dc8f71e..55c68b2 100644 --- a/Source/CTest/cmCTestCoverageCommand.h +++ b/Source/CTest/cmCTestCoverageCommand.h @@ -11,6 +11,7 @@ #include <cm/memory> #include <cm/optional> +#include "cmArgumentParserTypes.h" // IWYU pragma: keep #include "cmCTestHandlerCommand.h" #include "cmCommand.h" @@ -44,5 +45,5 @@ protected: void BindArguments() override; cmCTestGenericHandler* InitializeHandler() override; - cm::optional<std::vector<std::string>> Labels; + cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Labels; }; diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h index 903bb64..b67f182 100644 --- a/Source/CTest/cmCTestSubmitCommand.h +++ b/Source/CTest/cmCTestSubmitCommand.h @@ -10,6 +10,7 @@ #include <cm/optional> +#include "cmArgumentParserTypes.h" #include "cmCTestHandlerCommand.h" class cmCommand; @@ -50,7 +51,7 @@ protected: std::string RetryDelay; std::string SubmitURL; - cm::optional<std::vector<std::string>> Files; - std::vector<std::string> HttpHeaders; - cm::optional<std::vector<std::string>> Parts; + cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Files; + ArgumentParser::MaybeEmpty<std::vector<std::string>> HttpHeaders; + cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Parts; }; diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h index 0dad2bf..a9d1dd2 100644 --- a/Source/CTest/cmCTestUploadCommand.h +++ b/Source/CTest/cmCTestUploadCommand.h @@ -10,6 +10,7 @@ #include <cm/memory> +#include "cmArgumentParserTypes.h" #include "cmCTestHandlerCommand.h" #include "cmCommand.h" @@ -45,5 +46,5 @@ protected: void CheckArguments() override; cmCTestGenericHandler* InitializeHandler() override; - std::vector<std::string> Files; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Files; }; diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx index 1a05dbc..f0c4cfc 100644 --- a/Source/cmArgumentParser.cxx +++ b/Source/cmArgumentParser.cxx @@ -4,6 +4,8 @@ #include <algorithm> +#include "cmArgumentParserTypes.h" + namespace ArgumentParser { auto ActionMap::Emplace(cm::string_view name, Action action) @@ -44,7 +46,21 @@ void Instance::Bind(std::string& val) this->ExpectValue = true; } -void Instance::Bind(std::vector<std::string>& val) +void Instance::Bind(Maybe<std::string>& val) +{ + this->CurrentString = &val; + this->CurrentList = nullptr; + this->ExpectValue = false; +} + +void Instance::Bind(MaybeEmpty<std::vector<std::string>>& val) +{ + this->CurrentString = nullptr; + this->CurrentList = &val; + this->ExpectValue = false; +} + +void Instance::Bind(NonEmpty<std::vector<std::string>>& val) { this->CurrentString = nullptr; this->CurrentList = &val; diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h index 8be5a9c..26148d9 100644 --- a/Source/cmArgumentParser.h +++ b/Source/cmArgumentParser.h @@ -14,6 +14,8 @@ #include <cm/string_view> #include <cmext/string_view> +#include "cmArgumentParserTypes.h" // IWYU pragma: keep + namespace ArgumentParser { class Instance; @@ -37,7 +39,9 @@ public: void Bind(bool& val); void Bind(std::string& val); - void Bind(std::vector<std::string>& val); + void Bind(Maybe<std::string>& val); + void Bind(MaybeEmpty<std::vector<std::string>>& val); + void Bind(NonEmpty<std::vector<std::string>>& val); void Bind(std::vector<std::vector<std::string>>& val); // cm::optional<> records the presence the keyword to which it binds. diff --git a/Source/cmArgumentParserTypes.h b/Source/cmArgumentParserTypes.h new file mode 100644 index 0000000..9afa5c7 --- /dev/null +++ b/Source/cmArgumentParserTypes.h @@ -0,0 +1,24 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +namespace ArgumentParser { + +template <typename T> +struct Maybe : public T +{ +}; + +template <typename T> +struct MaybeEmpty : public T +{ +}; + +template <typename T> +struct NonEmpty : public T +{ +}; + +} // namespace ArgumentParser diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx index 287f45b..76561c3 100644 --- a/Source/cmCMakeLanguageCommand.cxx +++ b/Source/cmCMakeLanguageCommand.cxx @@ -14,6 +14,7 @@ #include <cmext/string_view> #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmDependencyProvider.h" #include "cmExecutionStatus.h" #include "cmGlobalGenerator.h" @@ -237,7 +238,7 @@ bool cmCMakeLanguageCommandSET_DEPENDENCY_PROVIDER( struct SetProviderArgs { std::string Command; - std::vector<std::string> Methods; + ArgumentParser::NonEmpty<std::vector<std::string>> Methods; }; auto const ArgsParser = diff --git a/Source/cmDefinePropertyCommand.cxx b/Source/cmDefinePropertyCommand.cxx index faefcb8..31ee665 100644 --- a/Source/cmDefinePropertyCommand.cxx +++ b/Source/cmDefinePropertyCommand.cxx @@ -8,6 +8,7 @@ #include <cmext/string_view> #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmProperty.h" @@ -51,8 +52,8 @@ bool cmDefinePropertyCommand(std::vector<std::string> const& args, // Parse remaining arguments. bool inherited = false; std::string PropertyName; - std::vector<std::string> BriefDocs; - std::vector<std::string> FullDocs; + ArgumentParser::NonEmpty<std::vector<std::string>> BriefDocs; + ArgumentParser::NonEmpty<std::vector<std::string>> FullDocs; std::string initializeFromVariable; cmArgumentParser<void> parser; diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 4071f99..a58f2b7 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -13,6 +13,7 @@ #include "cmsys/RegularExpression.hxx" #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmExecutionStatus.h" #include "cmExperimental.h" #include "cmExportBuildAndroidMKGenerator.h" @@ -58,7 +59,7 @@ bool cmExportCommand(std::vector<std::string> const& args, struct Arguments { std::string ExportSetName; - cm::optional<std::vector<std::string>> Targets; + cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Targets; std::string Namespace; std::string Filename; std::string AndroidMKFile; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 45ec343..d2aa63c 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -28,8 +28,8 @@ #include "cm_sys_stat.h" -#include "cmAlgorithms.h" #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmCMakePath.h" #include "cmCryptoHash.h" #include "cmELF.h" @@ -2505,7 +2505,7 @@ bool HandleGenerateCommand(std::vector<std::string> const& args, cm::optional<std::string> NewLineStyle; bool NoSourcePermissions = false; bool UseSourcePermissions = false; - std::vector<std::string> FilePermissions; + ArgumentParser::NonEmpty<std::vector<std::string>> FilePermissions; }; static auto const parser = @@ -3052,17 +3052,18 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args, std::string ConflictingDependenciesPrefix; std::string RPathPrefix; std::string BundleExecutable; - std::vector<std::string> Executables; - std::vector<std::string> Libraries; - std::vector<std::string> Directories; - std::vector<std::string> Modules; - std::vector<std::string> PreIncludeRegexes; - std::vector<std::string> PreExcludeRegexes; - std::vector<std::string> PostIncludeRegexes; - std::vector<std::string> PostExcludeRegexes; - std::vector<std::string> PostIncludeFiles; - std::vector<std::string> PostExcludeFiles; - std::vector<std::string> PostExcludeFilesStrict; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Executables; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Libraries; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Directories; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Modules; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PreIncludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PreExcludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeFiles; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeFiles; + ArgumentParser::MaybeEmpty<std::vector<std::string>> + PostExcludeFilesStrict; }; static auto const parser = @@ -3098,25 +3099,10 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args, return false; } - // Arguments that are allowed to be empty lists. Keep entries sorted! - static const std::vector<cm::string_view> LIST_ARGS = { - "DIRECTORIES"_s, - "EXECUTABLES"_s, - "LIBRARIES"_s, - "MODULES"_s, - "POST_EXCLUDE_FILES"_s, - "POST_EXCLUDE_FILES_STRICT"_s, - "POST_EXCLUDE_REGEXES"_s, - "POST_INCLUDE_FILES"_s, - "POST_INCLUDE_REGEXES"_s, - "PRE_EXCLUDE_REGEXES"_s, - "PRE_INCLUDE_REGEXES"_s, - }; - auto kwbegin = keywordsMissingValues.cbegin(); - auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS); - if (kwend != kwbegin) { - status.SetError(cmStrCat("Keywords missing values:\n ", - cmJoin(cmMakeRange(kwbegin, kwend), "\n "))); + if (!keywordsMissingValues.empty()) { + status.SetError( + cmStrCat("Keywords missing values:\n ", + cmJoin(cmMakeRange(keywordsMissingValues), "\n "))); cmSystemTools::SetFatalErrorOccurred(); return false; } @@ -3224,7 +3210,8 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, cm::optional<std::string> Content; bool EscapeQuotes = false; bool AtOnly = false; - std::string NewlineStyle; + // "NEWLINE_STYLE" requires one value, but we use a custom check below. + ArgumentParser::Maybe<std::string> NewlineStyle; }; static auto const parser = @@ -3249,15 +3236,10 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, return false; } - // Arguments that are allowed to be empty lists. Keep entries sorted! - static const std::vector<cm::string_view> LIST_ARGS = { - "NEWLINE_STYLE"_s, // Filter here so we can issue a custom error below. - }; - auto kwbegin = keywordsMissingValues.cbegin(); - auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS); - if (kwend != kwbegin) { - status.SetError(cmStrCat("CONFIGURE keywords missing values:\n ", - cmJoin(cmMakeRange(kwbegin, kwend), "\n "))); + if (!keywordsMissingValues.empty()) { + status.SetError( + cmStrCat("CONFIGURE keywords missing values:\n ", + cmJoin(cmMakeRange(keywordsMissingValues), "\n "))); cmSystemTools::SetFatalErrorOccurred(); return false; } @@ -3360,9 +3342,13 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args, std::string Format; std::string Compression; std::string CompressionLevel; - std::string MTime; + // "MTIME" should require one value, but it has long been accidentally + // accepted without one and treated as if an empty value were given. + // Fixing this would require a policy. + ArgumentParser::Maybe<std::string> MTime; bool Verbose = false; - std::vector<std::string> Paths; + // "PATHS" requires at least one value, but use a custom check below. + ArgumentParser::MaybeEmpty<std::vector<std::string>> Paths; }; static auto const parser = @@ -3387,19 +3373,10 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args, return false; } - // Arguments that are allowed to be empty lists. Keep entries sorted! - static const std::vector<cm::string_view> LIST_ARGS = { - "MTIME"_s, // "MTIME" should not be in this list because it requires one - // value, but it has long been accidentally accepted without - // one and treated as if an empty value were given. - // Fixing this would require a policy. - "PATHS"_s, // "PATHS" is here only so we can issue a custom error below. - }; - auto kwbegin = keywordsMissingValues.cbegin(); - auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS); - if (kwend != kwbegin) { - status.SetError(cmStrCat("Keywords missing values:\n ", - cmJoin(cmMakeRange(kwbegin, kwend), "\n "))); + if (!keywordsMissingValues.empty()) { + status.SetError( + cmStrCat("Keywords missing values:\n ", + cmJoin(cmMakeRange(keywordsMissingValues), "\n "))); cmSystemTools::SetFatalErrorOccurred(); return false; } @@ -3496,7 +3473,7 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args, bool Verbose = false; bool ListOnly = false; std::string Destination; - std::vector<std::string> Patterns; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Patterns; bool Touch = false; }; @@ -3520,13 +3497,10 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args, return false; } - // Arguments that are allowed to be empty lists. Keep entries sorted! - static const std::vector<cm::string_view> LIST_ARGS = { "PATTERNS"_s }; - auto kwbegin = keywordsMissingValues.cbegin(); - auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS); - if (kwend != kwbegin) { - status.SetError(cmStrCat("Keywords missing values:\n ", - cmJoin(cmMakeRange(kwbegin, kwend), "\n "))); + if (!keywordsMissingValues.empty()) { + status.SetError( + cmStrCat("Keywords missing values:\n ", + cmJoin(cmMakeRange(keywordsMissingValues), "\n "))); cmSystemTools::SetFatalErrorOccurred(); return false; } @@ -3620,9 +3594,9 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse, struct Arguments { - std::vector<std::string> Permissions; - std::vector<std::string> FilePermissions; - std::vector<std::string> DirectoryPermissions; + ArgumentParser::NonEmpty<std::vector<std::string>> Permissions; + ArgumentParser::NonEmpty<std::vector<std::string>> FilePermissions; + ArgumentParser::NonEmpty<std::vector<std::string>> DirectoryPermissions; }; static auto const parser = diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 35ddf34..b1044a8 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -19,6 +19,7 @@ #include "cmsys/Glob.hxx" #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmExecutionStatus.h" #include "cmExperimental.h" #include "cmExportSet.h" @@ -57,13 +58,13 @@ namespace { struct RuntimeDependenciesArgs { - std::vector<std::string> Directories; - std::vector<std::string> PreIncludeRegexes; - std::vector<std::string> PreExcludeRegexes; - std::vector<std::string> PostIncludeRegexes; - std::vector<std::string> PostExcludeRegexes; - std::vector<std::string> PostIncludeFiles; - std::vector<std::string> PostExcludeFiles; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Directories; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PreIncludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PreExcludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeFiles; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeFiles; }; auto const RuntimeDependenciesArgHelper = @@ -406,18 +407,18 @@ bool HandleTargetsMode(std::vector<std::string> const& args, struct ArgVectors { - std::vector<std::string> Archive; - std::vector<std::string> Library; - std::vector<std::string> Runtime; - std::vector<std::string> Object; - std::vector<std::string> Framework; - std::vector<std::string> Bundle; - std::vector<std::string> Includes; - std::vector<std::string> PrivateHeader; - std::vector<std::string> PublicHeader; - std::vector<std::string> Resource; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Archive; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Library; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Object; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Bundle; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Includes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PrivateHeader; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PublicHeader; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Resource; + ArgumentParser::MaybeEmpty<std::vector<std::string>> CxxModulesBmi; std::vector<std::vector<std::string>> FileSets; - std::vector<std::string> CxxModulesBmi; }; static auto const argHelper = @@ -441,9 +442,10 @@ bool HandleTargetsMode(std::vector<std::string> const& args, // now parse the generic args (i.e. the ones not specialized on LIBRARY/ // ARCHIVE, RUNTIME etc. (see above) // These generic args also contain the targets and the export stuff - std::vector<std::string> targetList; + ArgumentParser::MaybeEmpty<std::vector<std::string>> targetList; std::string exports; - cm::optional<std::vector<std::string>> runtimeDependenciesArgVector; + cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> + runtimeDependenciesArgVector; std::string runtimeDependencySetArg; std::vector<std::string> unknownArgs; cmInstallCommandArguments genericArgs(helper.DefaultComponentName); @@ -1251,10 +1253,10 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args, struct ArgVectors { - std::vector<std::string> Library; - std::vector<std::string> Runtime; - std::vector<std::string> Framework; - std::vector<std::string> Bundle; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Library; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Bundle; }; static auto const argHelper = cmArgumentParser<ArgVectors>{} @@ -1268,7 +1270,7 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args, // now parse the generic args (i.e. the ones not specialized on LIBRARY, // RUNTIME etc. (see above) - std::vector<std::string> targetList; + ArgumentParser::MaybeEmpty<std::vector<std::string>> targetList; std::string runtimeDependencySetArg; std::vector<std::string> unknownArgs; cmInstallCommandArguments genericArgs(helper.DefaultComponentName); @@ -1509,7 +1511,7 @@ bool HandleFilesMode(std::vector<std::string> const& args, // This is the FILES mode. bool programs = (args[0] == "PROGRAMS"); cmInstallCommandArguments ica(helper.DefaultComponentName); - std::vector<std::string> files; + ArgumentParser::MaybeEmpty<std::vector<std::string>> files; ica.Bind(programs ? "PROGRAMS"_s : "FILES"_s, files); std::vector<std::string> unknownArgs; ica.Parse(args, &unknownArgs); @@ -2140,9 +2142,9 @@ bool HandleRuntimeDependencySetMode(std::vector<std::string> const& args, struct ArgVectors { - std::vector<std::string> Library; - std::vector<std::string> Runtime; - std::vector<std::string> Framework; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Library; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework; }; static auto const argHelper = cmArgumentParser<ArgVectors>{} diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h index 79bd945..6e46aac 100644 --- a/Source/cmInstallCommandArguments.h +++ b/Source/cmInstallCommandArguments.h @@ -8,6 +8,7 @@ #include <vector> #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" class cmInstallCommandArguments : public cmArgumentParser<void> { @@ -44,8 +45,8 @@ private: std::string NamelinkComponent; bool ExcludeFromAll = false; std::string Rename; - std::vector<std::string> Permissions; - std::vector<std::string> Configurations; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Permissions; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Configurations; bool Optional = false; bool NamelinkOnly = false; bool NamelinkSkip = false; diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx index 5ea35e8..31538b6 100644 --- a/Source/cmParseArgumentsCommand.cxx +++ b/Source/cmParseArgumentsCommand.cxx @@ -10,6 +10,7 @@ #include <cm/string_view> #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -41,7 +42,8 @@ namespace { using options_map = std::map<std::string, bool>; using single_map = std::map<std::string, std::string>; -using multi_map = std::map<std::string, std::vector<std::string>>; +using multi_map = + std::map<std::string, ArgumentParser::NonEmpty<std::vector<std::string>>>; using options_set = std::set<cm::string_view>; struct UserArgumentParser : public cmArgumentParser<void> diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx index 74945fa..e2b0213 100644 --- a/Source/cmTargetSourcesCommand.cxx +++ b/Source/cmTargetSourcesCommand.cxx @@ -9,6 +9,7 @@ #include <cmext/string_view> #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmExperimental.h" #include "cmFileSet.h" #include "cmGeneratorExpression.h" @@ -28,8 +29,8 @@ struct FileSetArgs { std::string Type; std::string FileSet; - std::vector<std::string> BaseDirs; - std::vector<std::string> Files; + ArgumentParser::MaybeEmpty<std::vector<std::string>> BaseDirs; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Files; }; auto const FileSetArgsParser = cmArgumentParser<FileSetArgs>() diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx index 52c5861..ecfc5fc 100644 --- a/Tests/CMakeLib/testArgumentParser.cxx +++ b/Tests/CMakeLib/testArgumentParser.cxx @@ -11,6 +11,7 @@ #include <cmext/string_view> #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" namespace { @@ -22,12 +23,14 @@ struct Result std::string String1; cm::optional<std::string> String2; cm::optional<std::string> String3; + ArgumentParser::Maybe<std::string> String4; - std::vector<std::string> List1; - std::vector<std::string> List2; - cm::optional<std::vector<std::string>> List3; - cm::optional<std::vector<std::string>> List4; - cm::optional<std::vector<std::string>> List5; + ArgumentParser::NonEmpty<std::vector<std::string>> List1; + ArgumentParser::NonEmpty<std::vector<std::string>> List2; + cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> List3; + cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> List4; + cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> List5; + cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> List6; std::vector<std::vector<std::string>> Multi1; std::vector<std::vector<std::string>> Multi2; @@ -42,12 +45,14 @@ std::initializer_list<cm::string_view> const args = { "STRING_1", // string arg missing value "STRING_2", "foo", "bar", // string arg + unparsed value, presence captured // "STRING_3", // string arg that is not present + "STRING_4", // string arg allowed to be missing value "LIST_1", // list arg missing values "LIST_2", "foo", "bar", // list arg with 2 elems "LIST_3", "bar", // list arg ... "LIST_3", "foo", // ... with continuation "LIST_4", // list arg missing values, presence captured // "LIST_5", // list arg that is not present + "LIST_6", // list arg allowed to be empty "MULTI_2", // multi list with 0 lists "MULTI_3", "foo", "bar", // multi list with first list with two elems "MULTI_3", "bar", "foo", // multi list with second list with two elems @@ -80,6 +85,7 @@ bool verifyResult(Result const& result, ASSERT_TRUE(result.String2); ASSERT_TRUE(*result.String2 == "foo"); ASSERT_TRUE(!result.String3); + ASSERT_TRUE(result.String4.empty()); ASSERT_TRUE(result.List1.empty()); ASSERT_TRUE(result.List2 == foobar); @@ -88,6 +94,8 @@ bool verifyResult(Result const& result, ASSERT_TRUE(result.List4); ASSERT_TRUE(result.List4->empty()); ASSERT_TRUE(!result.List5); + ASSERT_TRUE(result.List6); + ASSERT_TRUE(result.List6->empty()); ASSERT_TRUE(result.Multi1.empty()); ASSERT_TRUE(result.Multi2.size() == 1); @@ -117,11 +125,13 @@ bool testArgumentParserDynamic() .Bind("STRING_1"_s, result.String1) .Bind("STRING_2"_s, result.String2) .Bind("STRING_3"_s, result.String3) + .Bind("STRING_4"_s, result.String4) .Bind("LIST_1"_s, result.List1) .Bind("LIST_2"_s, result.List2) .Bind("LIST_3"_s, result.List3) .Bind("LIST_4"_s, result.List4) .Bind("LIST_5"_s, result.List5) + .Bind("LIST_6"_s, result.List6) .Bind("MULTI_1"_s, result.Multi1) .Bind("MULTI_2"_s, result.Multi2) .Bind("MULTI_3"_s, result.Multi3) @@ -140,11 +150,13 @@ bool testArgumentParserStatic() .Bind("STRING_1"_s, &Result::String1) .Bind("STRING_2"_s, &Result::String2) .Bind("STRING_3"_s, &Result::String3) + .Bind("STRING_4"_s, &Result::String4) .Bind("LIST_1"_s, &Result::List1) .Bind("LIST_2"_s, &Result::List2) .Bind("LIST_3"_s, &Result::List3) .Bind("LIST_4"_s, &Result::List4) .Bind("LIST_5"_s, &Result::List5) + .Bind("LIST_6"_s, &Result::List6) .Bind("MULTI_1"_s, &Result::Multi1) .Bind("MULTI_2"_s, &Result::Multi2) .Bind("MULTI_3"_s, &Result::Multi3) |