diff options
65 files changed, 546 insertions, 424 deletions
diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx index f0c4cfc..25d5c68 100644 --- a/Source/cmArgumentParser.cxx +++ b/Source/cmArgumentParser.cxx @@ -5,10 +5,13 @@ #include <algorithm> #include "cmArgumentParserTypes.h" +#include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmStringAlgorithms.h" namespace ArgumentParser { -auto ActionMap::Emplace(cm::string_view name, Action action) +auto KeywordActionMap::Emplace(cm::string_view name, KeywordAction action) -> std::pair<iterator, bool> { auto const it = @@ -21,7 +24,7 @@ auto ActionMap::Emplace(cm::string_view name, Action action) : std::make_pair(this->emplace(it, name, std::move(action)), true); } -auto ActionMap::Find(cm::string_view name) const -> const_iterator +auto KeywordActionMap::Find(cm::string_view name) const -> const_iterator { auto const it = std::lower_bound(this->begin(), this->end(), name, @@ -74,20 +77,16 @@ void Instance::Bind(std::vector<std::vector<std::string>>& val) this->ExpectValue = false; } -void Instance::Consume(cm::string_view arg, void* result, - std::vector<std::string>* unparsedArguments, - std::vector<cm::string_view>* keywordsMissingValue, - std::vector<cm::string_view>* parsedKeywords) +void Instance::Consume(cm::string_view arg) { - auto const it = this->Bindings.Find(arg); - if (it != this->Bindings.end()) { - if (parsedKeywords != nullptr) { - parsedKeywords->emplace_back(it->first); - } - it->second(*this, result); - if (this->ExpectValue && keywordsMissingValue != nullptr) { - keywordsMissingValue->emplace_back(it->first); + auto const it = this->Bindings.Keywords.Find(arg); + if (it != this->Bindings.Keywords.end()) { + this->FinishKeyword(); + this->Keyword = it->first; + if (this->ParsedKeywords != nullptr) { + this->ParsedKeywords->emplace_back(it->first); } + it->second(*this); return; } @@ -97,16 +96,40 @@ void Instance::Consume(cm::string_view arg, void* result, this->CurrentList = nullptr; } else if (this->CurrentList != nullptr) { this->CurrentList->emplace_back(arg); - } else if (unparsedArguments != nullptr) { - unparsedArguments->emplace_back(arg); + } else if (this->UnparsedArguments != nullptr) { + this->UnparsedArguments->emplace_back(arg); } + this->ExpectValue = false; +} + +void Instance::FinishKeyword() +{ + if (this->Keyword.empty()) { + return; + } if (this->ExpectValue) { - if (keywordsMissingValue != nullptr) { - keywordsMissingValue->pop_back(); + if (this->ParseResults != nullptr) { + this->ParseResults->AddKeywordError(this->Keyword, + " missing required value\n"); } - this->ExpectValue = false; + if (this->KeywordsMissingValue != nullptr) { + this->KeywordsMissingValue->emplace_back(this->Keyword); + } + } +} + +bool ParseResult::MaybeReportError(cmMakefile& mf) const +{ + if (*this) { + return false; + } + std::string e; + for (auto const& ke : this->KeywordErrors) { + e = cmStrCat(e, "Error after keyword \"", ke.first, "\":\n", ke.second); } + mf.IssueMessage(MessageType::FATAL_ERROR, e); + return true; } } // namespace ArgumentParser diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h index 26148d9..8fda8b7 100644 --- a/Source/cmArgumentParser.h +++ b/Source/cmArgumentParser.h @@ -6,34 +6,116 @@ #include <cassert> #include <functional> +#include <map> #include <string> #include <utility> #include <vector> #include <cm/optional> #include <cm/string_view> +#include <cm/type_traits> #include <cmext/string_view> #include "cmArgumentParserTypes.h" // IWYU pragma: keep +template <typename Result> +class cmArgumentParser; // IWYU pragma: keep + +class cmMakefile; + namespace ArgumentParser { +class ParseResult +{ + std::map<cm::string_view, std::string> KeywordErrors; + +public: + explicit operator bool() const { return this->KeywordErrors.empty(); } + + void AddKeywordError(cm::string_view key, cm::string_view text) + + { + this->KeywordErrors[key] += text; + } + + std::map<cm::string_view, std::string> const& GetKeywordErrors() const + { + return this->KeywordErrors; + } + + bool MaybeReportError(cmMakefile& mf) const; +}; + +template <typename Result> +typename std::enable_if<std::is_base_of<ParseResult, Result>::value, + ParseResult*>::type +AsParseResultPtr(Result& result) +{ + return &result; +} + +template <typename Result> +typename std::enable_if<!std::is_base_of<ParseResult, Result>::value, + ParseResult*>::type +AsParseResultPtr(Result&) +{ + return nullptr; +} + class Instance; -using Action = std::function<void(Instance&, void*)>; +using KeywordAction = std::function<void(Instance&)>; -// using ActionMap = cm::flat_map<cm::string_view, Action>; -class ActionMap : public std::vector<std::pair<cm::string_view, Action>> +// using KeywordActionMap = cm::flat_map<cm::string_view, KeywordAction>; +class KeywordActionMap + : public std::vector<std::pair<cm::string_view, KeywordAction>> { public: - std::pair<iterator, bool> Emplace(cm::string_view name, Action action); + std::pair<iterator, bool> Emplace(cm::string_view name, + KeywordAction action); const_iterator Find(cm::string_view name) const; }; +class ActionMap +{ +public: + KeywordActionMap Keywords; +}; + +class Base +{ +public: + using Instance = ArgumentParser::Instance; + using ParseResult = ArgumentParser::ParseResult; + + ArgumentParser::ActionMap Bindings; + + bool MaybeBind(cm::string_view name, KeywordAction action) + { + return this->Bindings.Keywords.Emplace(name, std::move(action)).second; + } + + void Bind(cm::string_view name, KeywordAction action) + { + bool const inserted = this->MaybeBind(name, std::move(action)); + assert(inserted); + static_cast<void>(inserted); + } +}; + class Instance { public: - Instance(ActionMap const& bindings) + Instance(ActionMap const& bindings, ParseResult* parseResult, + std::vector<std::string>* unparsedArguments, + std::vector<cm::string_view>* keywordsMissingValue, + std::vector<cm::string_view>* parsedKeywords, + void* result = nullptr) : Bindings(bindings) + , ParseResults(parseResult) + , UnparsedArguments(unparsedArguments) + , KeywordsMissingValue(keywordsMissingValue) + , ParsedKeywords(parsedKeywords) + , Result(result) { } @@ -54,22 +136,39 @@ public: this->Bind(*optVal); } - void Consume(cm::string_view arg, void* result, - std::vector<std::string>* unparsedArguments, - std::vector<cm::string_view>* keywordsMissingValue, - std::vector<cm::string_view>* parsedKeywords); + template <typename Range> + void Parse(Range const& args) + { + for (cm::string_view arg : args) { + this->Consume(arg); + } + this->FinishKeyword(); + } private: ActionMap const& Bindings; + ParseResult* ParseResults = nullptr; + std::vector<std::string>* UnparsedArguments = nullptr; + std::vector<cm::string_view>* KeywordsMissingValue = nullptr; + std::vector<cm::string_view>* ParsedKeywords = nullptr; + void* Result = nullptr; + + cm::string_view Keyword; std::string* CurrentString = nullptr; std::vector<std::string>* CurrentList = nullptr; bool ExpectValue = false; + + void Consume(cm::string_view arg); + void FinishKeyword(); + + template <typename Result> + friend class ::cmArgumentParser; }; } // namespace ArgumentParser template <typename Result> -class cmArgumentParser +class cmArgumentParser : private ArgumentParser::Base { public: // I *think* this function could be made `constexpr` when the code is @@ -77,28 +176,24 @@ public: template <typename T> cmArgumentParser& Bind(cm::static_string_view name, T Result::*member) { - bool const inserted = - this->Bindings - .Emplace(name, - [member](ArgumentParser::Instance& instance, void* result) { - instance.Bind(static_cast<Result*>(result)->*member); - }) - .second; - assert(inserted), (void)inserted; + this->Base::Bind(name, [member](Instance& instance) { + instance.Bind(static_cast<Result*>(instance.Result)->*member); + }); return *this; } template <typename Range> - void Parse(Result& result, Range const& args, + bool Parse(Result& result, Range const& args, std::vector<std::string>* unparsedArguments, std::vector<cm::string_view>* keywordsMissingValue = nullptr, std::vector<cm::string_view>* parsedKeywords = nullptr) const { - ArgumentParser::Instance instance(this->Bindings); - for (cm::string_view arg : args) { - instance.Consume(arg, &result, unparsedArguments, keywordsMissingValue, - parsedKeywords); - } + using ArgumentParser::AsParseResultPtr; + ParseResult* parseResultPtr = AsParseResultPtr(result); + Instance instance(this->Bindings, parseResultPtr, unparsedArguments, + keywordsMissingValue, parsedKeywords, &result); + instance.Parse(args); + return parseResultPtr ? static_cast<bool>(*parseResultPtr) : true; } template <typename Range> @@ -111,47 +206,37 @@ public: parsedKeywords); return result; } - -private: - ArgumentParser::ActionMap Bindings; }; template <> -class cmArgumentParser<void> +class cmArgumentParser<void> : private ArgumentParser::Base { public: template <typename T> cmArgumentParser& Bind(cm::static_string_view name, T& ref) { - bool const inserted = this->Bind(cm::string_view(name), ref); - assert(inserted), (void)inserted; + this->Base::Bind(name, [&ref](Instance& instance) { instance.Bind(ref); }); return *this; } template <typename Range> - void Parse(Range const& args, std::vector<std::string>* unparsedArguments, - std::vector<cm::string_view>* keywordsMissingValue = nullptr, - std::vector<cm::string_view>* parsedKeywords = nullptr) const + ParseResult Parse( + Range const& args, std::vector<std::string>* unparsedArguments, + std::vector<cm::string_view>* keywordsMissingValue = nullptr, + std::vector<cm::string_view>* parsedKeywords = nullptr) const { - ArgumentParser::Instance instance(this->Bindings); - for (cm::string_view arg : args) { - instance.Consume(arg, nullptr, unparsedArguments, keywordsMissingValue, - parsedKeywords); - } + ParseResult parseResult; + Instance instance(this->Bindings, &parseResult, unparsedArguments, + keywordsMissingValue, parsedKeywords); + instance.Parse(args); + return parseResult; } protected: template <typename T> bool Bind(cm::string_view name, T& ref) { - return this->Bindings - .Emplace(name, - [&ref](ArgumentParser::Instance& instance, void*) { - instance.Bind(ref); - }) - .second; + return this->MaybeBind(name, + [&ref](Instance& instance) { instance.Bind(ref); }); } - -private: - ArgumentParser::ActionMap Bindings; }; diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx index 033dd6d..58129a0 100644 --- a/Source/cmCMakeHostSystemInformationCommand.cxx +++ b/Source/cmCMakeHostSystemInformationCommand.cxx @@ -474,7 +474,7 @@ bool QueryWindowsRegistry(Range args, cmExecutionStatus& status, } std::string const& key = *args.begin(); - struct Arguments + struct Arguments : public ArgumentParser::ParseResult { std::string ValueName; bool ValueNames = false; @@ -491,19 +491,15 @@ bool QueryWindowsRegistry(Range args, cmExecutionStatus& status, .Bind("SEPARATOR"_s, &Arguments::Separator) .Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable); std::vector<std::string> invalidArgs; - std::vector<cm::string_view> keywordsMissingValue; - Arguments const arguments = - parser.Parse(args.advance(1), &invalidArgs, &keywordsMissingValue); + Arguments const arguments = parser.Parse(args.advance(1), &invalidArgs); if (!invalidArgs.empty()) { status.SetError(cmStrCat("given invalid argument(s) \"", cmJoin(invalidArgs, ", "_s), "\".")); return false; } - if (!keywordsMissingValue.empty()) { - status.SetError(cmStrCat("missing expected value for argument(s) \"", - cmJoin(keywordsMissingValue, ", "_s), "\".")); - return false; + if (arguments.MaybeReportError(status.GetMakefile())) { + return true; } if ((!arguments.ValueName.empty() && (arguments.ValueNames || arguments.SubKeys)) || diff --git a/Source/cmCMakePathCommand.cxx b/Source/cmCMakePathCommand.cxx index adcffa9..b955bcf 100644 --- a/Source/cmCMakePathCommand.cxx +++ b/Source/cmCMakePathCommand.cxx @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCMakePathCommand.h" -#include <algorithm> #include <functional> #include <iomanip> #include <map> @@ -11,6 +10,7 @@ #include <utility> #include <vector> +#include <cm/optional> #include <cm/string_view> #include <cmext/string_view> @@ -43,15 +43,12 @@ public: } template <int Advance = 2> - Result Parse(std::vector<std::string> const& args, - std::vector<cm::string_view>* keywordsMissingValue = nullptr, - std::vector<cm::string_view>* parsedKeywords = nullptr) const + Result Parse(std::vector<std::string> const& args) const { this->Inputs.clear(); return this->cmArgumentParser<Result>::Parse( - cmMakeRange(args).advance(Advance), &this->Inputs, keywordsMissingValue, - parsedKeywords); + cmMakeRange(args).advance(Advance), &this->Inputs); } const std::vector<std::string>& GetInputs() const { return this->Inputs; } @@ -82,52 +79,25 @@ public: template <int Advance = 2> Result Parse(std::vector<std::string> const& args) const { - this->KeywordsMissingValue.clear(); - this->ParsedKeywords.clear(); - return this->CMakePathArgumentParser<Result>::template Parse<Advance>( - args, &this->KeywordsMissingValue, &this->ParsedKeywords); - } - - const std::vector<cm::string_view>& GetKeywordsMissingValue() const - { - return this->KeywordsMissingValue; - } - const std::vector<cm::string_view>& GetParsedKeywords() const - { - return this->ParsedKeywords; + args); } bool checkOutputVariable(const Result& arguments, cmExecutionStatus& status) const { - if (std::find(this->GetKeywordsMissingValue().begin(), - this->GetKeywordsMissingValue().end(), - "OUTPUT_VARIABLE"_s) != - this->GetKeywordsMissingValue().end()) { - status.SetError("OUTPUT_VARIABLE requires an argument."); - return false; - } - - if (std::find(this->GetParsedKeywords().begin(), - this->GetParsedKeywords().end(), - "OUTPUT_VARIABLE"_s) != this->GetParsedKeywords().end() && - arguments.Output.empty()) { + if (arguments.Output && arguments.Output->empty()) { status.SetError("Invalid name for output variable."); return false; } return true; } - -private: - mutable std::vector<cm::string_view> KeywordsMissingValue; - mutable std::vector<cm::string_view> ParsedKeywords; }; -struct OutputVariable +struct OutputVariable : public ArgumentParser::ParseResult { - std::string Output; + cm::optional<std::string> Output; }; // Usable when OUTPUT_VARIABLE is the only option class OutputVariableParser @@ -297,6 +267,9 @@ bool HandleAppendCommand(std::vector<std::string> const& args, const auto arguments = parser.Parse(args); + if (arguments.MaybeReportError(status.GetMakefile())) { + return true; + } if (!parser.checkOutputVariable(arguments, status)) { return false; } @@ -307,7 +280,7 @@ bool HandleAppendCommand(std::vector<std::string> const& args, } status.GetMakefile().AddDefinition( - arguments.Output.empty() ? args[1] : arguments.Output, path.String()); + arguments.Output ? *arguments.Output : args[1], path.String()); return true; } @@ -319,6 +292,9 @@ bool HandleAppendStringCommand(std::vector<std::string> const& args, const auto arguments = parser.Parse(args); + if (arguments.MaybeReportError(status.GetMakefile())) { + return true; + } if (!parser.checkOutputVariable(arguments, status)) { return false; } @@ -334,7 +310,7 @@ bool HandleAppendStringCommand(std::vector<std::string> const& args, } status.GetMakefile().AddDefinition( - arguments.Output.empty() ? args[1] : arguments.Output, path.String()); + arguments.Output ? *arguments.Output : args[1], path.String()); return true; } @@ -346,6 +322,9 @@ bool HandleRemoveFilenameCommand(std::vector<std::string> const& args, const auto arguments = parser.Parse(args); + if (arguments.MaybeReportError(status.GetMakefile())) { + return true; + } if (!parser.checkOutputVariable(arguments, status)) { return false; } @@ -364,7 +343,7 @@ bool HandleRemoveFilenameCommand(std::vector<std::string> const& args, path.RemoveFileName(); status.GetMakefile().AddDefinition( - arguments.Output.empty() ? args[1] : arguments.Output, path.String()); + arguments.Output ? *arguments.Output : args[1], path.String()); return true; } @@ -376,6 +355,9 @@ bool HandleReplaceFilenameCommand(std::vector<std::string> const& args, const auto arguments = parser.Parse(args); + if (arguments.MaybeReportError(status.GetMakefile())) { + return true; + } if (!parser.checkOutputVariable(arguments, status)) { return false; } @@ -395,7 +377,7 @@ bool HandleReplaceFilenameCommand(std::vector<std::string> const& args, parser.GetInputs().empty() ? "" : parser.GetInputs().front()); status.GetMakefile().AddDefinition( - arguments.Output.empty() ? args[1] : arguments.Output, path.String()); + arguments.Output ? *arguments.Output : args[1], path.String()); return true; } @@ -403,9 +385,9 @@ bool HandleReplaceFilenameCommand(std::vector<std::string> const& args, bool HandleRemoveExtensionCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { - struct Arguments + struct Arguments : public ArgumentParser::ParseResult { - std::string Output; + cm::optional<std::string> Output; bool LastOnly = false; }; @@ -415,6 +397,9 @@ bool HandleRemoveExtensionCommand(std::vector<std::string> const& args, Arguments const arguments = parser.Parse(args); + if (arguments.MaybeReportError(status.GetMakefile())) { + return true; + } if (!parser.checkOutputVariable(arguments, status)) { return false; } @@ -438,7 +423,7 @@ bool HandleRemoveExtensionCommand(std::vector<std::string> const& args, } status.GetMakefile().AddDefinition( - arguments.Output.empty() ? args[1] : arguments.Output, path.String()); + arguments.Output ? *arguments.Output : args[1], path.String()); return true; } @@ -446,9 +431,9 @@ bool HandleRemoveExtensionCommand(std::vector<std::string> const& args, bool HandleReplaceExtensionCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { - struct Arguments + struct Arguments : public ArgumentParser::ParseResult { - std::string Output; + cm::optional<std::string> Output; bool LastOnly = false; }; @@ -458,6 +443,9 @@ bool HandleReplaceExtensionCommand(std::vector<std::string> const& args, Arguments const arguments = parser.Parse(args); + if (arguments.MaybeReportError(status.GetMakefile())) { + return true; + } if (!parser.checkOutputVariable(arguments, status)) { return false; } @@ -483,7 +471,7 @@ bool HandleReplaceExtensionCommand(std::vector<std::string> const& args, } status.GetMakefile().AddDefinition( - arguments.Output.empty() ? args[1] : arguments.Output, path.String()); + arguments.Output ? *arguments.Output : args[1], path.String()); return true; } @@ -495,6 +483,9 @@ bool HandleNormalPathCommand(std::vector<std::string> const& args, const auto arguments = parser.Parse(args); + if (arguments.MaybeReportError(status.GetMakefile())) { + return true; + } if (!parser.checkOutputVariable(arguments, status)) { return false; } @@ -512,7 +503,7 @@ bool HandleNormalPathCommand(std::vector<std::string> const& args, auto path = cmCMakePath(inputPath).Normal(); status.GetMakefile().AddDefinition( - arguments.Output.empty() ? args[1] : arguments.Output, path.String()); + arguments.Output ? *arguments.Output : args[1], path.String()); return true; } @@ -523,10 +514,10 @@ bool HandleTransformPathCommand( const std::string& base)>& transform, bool normalizeOption = false) { - struct Arguments + struct Arguments : public ArgumentParser::ParseResult { - std::string Output; - std::string BaseDirectory; + cm::optional<std::string> Output; + cm::optional<std::string> BaseDirectory; bool Normalize = false; }; @@ -538,6 +529,9 @@ bool HandleTransformPathCommand( Arguments arguments = parser.Parse(args); + if (arguments.MaybeReportError(status.GetMakefile())) { + return true; + } if (!parser.checkOutputVariable(arguments, status)) { return false; } @@ -547,17 +541,11 @@ bool HandleTransformPathCommand( return false; } - if (std::find(parser.GetKeywordsMissingValue().begin(), - parser.GetKeywordsMissingValue().end(), "BASE_DIRECTORY"_s) != - parser.GetKeywordsMissingValue().end()) { - status.SetError("BASE_DIRECTORY requires an argument."); - return false; - } - - if (std::find(parser.GetParsedKeywords().begin(), - parser.GetParsedKeywords().end(), - "BASE_DIRECTORY"_s) == parser.GetParsedKeywords().end()) { - arguments.BaseDirectory = status.GetMakefile().GetCurrentSourceDirectory(); + std::string baseDirectory; + if (arguments.BaseDirectory) { + baseDirectory = *arguments.BaseDirectory; + } else { + baseDirectory = status.GetMakefile().GetCurrentSourceDirectory(); } std::string inputPath; @@ -565,13 +553,13 @@ bool HandleTransformPathCommand( return false; } - auto path = transform(cmCMakePath(inputPath), arguments.BaseDirectory); + auto path = transform(cmCMakePath(inputPath), baseDirectory); if (arguments.Normalize) { path = path.Normal(); } status.GetMakefile().AddDefinition( - arguments.Output.empty() ? args[1] : arguments.Output, path.String()); + arguments.Output ? *arguments.Output : args[1], path.String()); return true; } diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index af56e2d..7fbd826 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -47,7 +47,7 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args, return false; } - struct Arguments + struct Arguments : public ArgumentParser::ParseResult { std::vector<std::vector<std::string>> Commands; std::string OutputVariable; @@ -95,14 +95,10 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args, .Bind("COMMAND_ERROR_IS_FATAL"_s, &Arguments::CommandErrorIsFatal); std::vector<std::string> unparsedArguments; - std::vector<cm::string_view> keywordsMissingValue; - Arguments const arguments = - parser.Parse(args, &unparsedArguments, &keywordsMissingValue); + Arguments const arguments = parser.Parse(args, &unparsedArguments); - if (!keywordsMissingValue.empty()) { - status.SetError(cmStrCat(" called with no value for ", - keywordsMissingValue.front(), ".")); - return false; + if (arguments.MaybeReportError(status.GetMakefile())) { + return true; } if (!unparsedArguments.empty()) { status.SetError(" given unknown argument \"" + unparsedArguments.front() + diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index d2aa63c..c7ba424 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -954,42 +954,34 @@ bool HandleRPathChangeCommand(std::vector<std::string> const& args, { // Evaluate arguments. std::string file; - std::string oldRPath; - std::string newRPath; + cm::optional<std::string> oldRPath; + cm::optional<std::string> newRPath; bool removeEnvironmentRPath = false; cmArgumentParser<void> parser; std::vector<std::string> unknownArgs; - std::vector<cm::string_view> missingArgs; - std::vector<cm::string_view> parsedArgs; parser.Bind("FILE"_s, file) .Bind("OLD_RPATH"_s, oldRPath) .Bind("NEW_RPATH"_s, newRPath) .Bind("INSTALL_REMOVE_ENVIRONMENT_RPATH"_s, removeEnvironmentRPath); - parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs, - &parsedArgs); + ArgumentParser::ParseResult parseResult = + parser.Parse(cmMakeRange(args).advance(1), &unknownArgs); if (!unknownArgs.empty()) { status.SetError( cmStrCat("RPATH_CHANGE given unknown argument ", unknownArgs.front())); return false; } - if (!missingArgs.empty()) { - status.SetError(cmStrCat("RPATH_CHANGE \"", missingArgs.front(), - "\" argument not given value.")); - return false; + if (parseResult.MaybeReportError(status.GetMakefile())) { + return true; } if (file.empty()) { status.SetError("RPATH_CHANGE not given FILE option."); return false; } - if (oldRPath.empty() && - std::find(parsedArgs.begin(), parsedArgs.end(), "OLD_RPATH") == - parsedArgs.end()) { + if (!oldRPath) { status.SetError("RPATH_CHANGE not given OLD_RPATH option."); return false; } - if (newRPath.empty() && - std::find(parsedArgs.begin(), parsedArgs.end(), "NEW_RPATH") == - parsedArgs.end()) { + if (!newRPath) { status.SetError("RPATH_CHANGE not given NEW_RPATH option."); return false; } @@ -1003,17 +995,17 @@ bool HandleRPathChangeCommand(std::vector<std::string> const& args, std::string emsg; bool changed; - if (!cmSystemTools::ChangeRPath(file, oldRPath, newRPath, + if (!cmSystemTools::ChangeRPath(file, *oldRPath, *newRPath, removeEnvironmentRPath, &emsg, &changed)) { status.SetError(cmStrCat("RPATH_CHANGE could not write new RPATH:\n ", - newRPath, "\nto the file:\n ", file, "\n", + *newRPath, "\nto the file:\n ", file, "\n", emsg)); success = false; } if (success) { if (changed) { std::string message = - cmStrCat("Set runtime path of \"", file, "\" to \"", newRPath, '"'); + cmStrCat("Set runtime path of \"", file, "\" to \"", *newRPath, '"'); status.GetMakefile().DisplayStatus(message, -1); } ft.Store(file); @@ -1026,31 +1018,25 @@ bool HandleRPathSetCommand(std::vector<std::string> const& args, { // Evaluate arguments. std::string file; - std::string newRPath; + cm::optional<std::string> newRPath; cmArgumentParser<void> parser; std::vector<std::string> unknownArgs; - std::vector<cm::string_view> missingArgs; - std::vector<cm::string_view> parsedArgs; parser.Bind("FILE"_s, file).Bind("NEW_RPATH"_s, newRPath); - parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs, - &parsedArgs); + ArgumentParser::ParseResult parseResult = + parser.Parse(cmMakeRange(args).advance(1), &unknownArgs); if (!unknownArgs.empty()) { status.SetError(cmStrCat("RPATH_SET given unrecognized argument \"", unknownArgs.front(), "\".")); return false; } - if (!missingArgs.empty()) { - status.SetError(cmStrCat("RPATH_SET \"", missingArgs.front(), - "\" argument not given value.")); - return false; + if (parseResult.MaybeReportError(status.GetMakefile())) { + return true; } if (file.empty()) { status.SetError("RPATH_SET not given FILE option."); return false; } - if (newRPath.empty() && - std::find(parsedArgs.begin(), parsedArgs.end(), "NEW_RPATH") == - parsedArgs.end()) { + if (!newRPath) { status.SetError("RPATH_SET not given NEW_RPATH option."); return false; } @@ -1064,16 +1050,16 @@ bool HandleRPathSetCommand(std::vector<std::string> const& args, std::string emsg; bool changed; - if (!cmSystemTools::SetRPath(file, newRPath, &emsg, &changed)) { + if (!cmSystemTools::SetRPath(file, *newRPath, &emsg, &changed)) { status.SetError(cmStrCat("RPATH_SET could not write new RPATH:\n ", - newRPath, "\nto the file:\n ", file, "\n", + *newRPath, "\nto the file:\n ", file, "\n", emsg)); success = false; } if (success) { if (changed) { std::string message = - cmStrCat("Set runtime path of \"", file, "\" to \"", newRPath, '"'); + cmStrCat("Set runtime path of \"", file, "\" to \"", *newRPath, '"'); status.GetMakefile().DisplayStatus(message, -1); } ft.Store(file); @@ -1088,18 +1074,16 @@ bool HandleRPathRemoveCommand(std::vector<std::string> const& args, std::string file; cmArgumentParser<void> parser; std::vector<std::string> unknownArgs; - std::vector<cm::string_view> missingArgs; parser.Bind("FILE"_s, file); - parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs); + ArgumentParser::ParseResult parseResult = + parser.Parse(cmMakeRange(args).advance(1), &unknownArgs); if (!unknownArgs.empty()) { status.SetError( cmStrCat("RPATH_REMOVE given unknown argument ", unknownArgs.front())); return false; } - if (!missingArgs.empty()) { - status.SetError(cmStrCat("RPATH_REMOVE \"", missingArgs.front(), - "\" argument not given value.")); - return false; + if (parseResult.MaybeReportError(status.GetMakefile())) { + return true; } if (file.empty()) { status.SetError("RPATH_REMOVE not given FILE option."); @@ -1136,31 +1120,25 @@ bool HandleRPathCheckCommand(std::vector<std::string> const& args, { // Evaluate arguments. std::string file; - std::string rpath; + cm::optional<std::string> rpath; cmArgumentParser<void> parser; std::vector<std::string> unknownArgs; - std::vector<cm::string_view> missingArgs; - std::vector<cm::string_view> parsedArgs; parser.Bind("FILE"_s, file).Bind("RPATH"_s, rpath); - parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs, - &parsedArgs); + ArgumentParser::ParseResult parseResult = + parser.Parse(cmMakeRange(args).advance(1), &unknownArgs); if (!unknownArgs.empty()) { status.SetError( cmStrCat("RPATH_CHECK given unknown argument ", unknownArgs.front())); return false; } - if (!missingArgs.empty()) { - status.SetError(cmStrCat("RPATH_CHECK \"", missingArgs.front(), - "\" argument not given value.")); - return false; + if (parseResult.MaybeReportError(status.GetMakefile())) { + return true; } if (file.empty()) { status.SetError("RPATH_CHECK not given FILE option."); return false; } - if (rpath.empty() && - std::find(parsedArgs.begin(), parsedArgs.end(), "RPATH") == - parsedArgs.end()) { + if (!rpath) { status.SetError("RPATH_CHECK not given RPATH option."); return false; } @@ -1169,7 +1147,7 @@ bool HandleRPathCheckCommand(std::vector<std::string> const& args, // delete it. This is used during installation to re-install a file // if its RPath will change. if (cmSystemTools::FileExists(file, true) && - !cmSystemTools::CheckRPath(file, rpath)) { + !cmSystemTools::CheckRPath(file, *rpath)) { cmSystemTools::RemoveFile(file); } @@ -1252,7 +1230,7 @@ bool HandleRealPathCommand(std::vector<std::string> const& args, return false; } - struct Arguments + struct Arguments : public ArgumentParser::ParseResult { cm::optional<std::string> BaseDirectory; bool ExpandTilde = false; @@ -1263,17 +1241,15 @@ bool HandleRealPathCommand(std::vector<std::string> const& args, .Bind("EXPAND_TILDE"_s, &Arguments::ExpandTilde); std::vector<std::string> unparsedArguments; - std::vector<cm::string_view> keywordsMissingValue; - auto arguments = parser.Parse(cmMakeRange(args).advance(3), - &unparsedArguments, &keywordsMissingValue); + auto arguments = + parser.Parse(cmMakeRange(args).advance(3), &unparsedArguments); if (!unparsedArguments.empty()) { status.SetError("REAL_PATH called with unexpected arguments"); return false; } - if (!keywordsMissingValue.empty()) { - status.SetError("BASE_DIRECTORY requires a value"); - return false; + if (arguments.MaybeReportError(status.GetMakefile())) { + return true; } if (!arguments.BaseDirectory) { @@ -2495,7 +2471,7 @@ bool HandleGenerateCommand(std::vector<std::string> const& args, return false; } - struct Arguments + struct Arguments : public ArgumentParser::ParseResult { cm::optional<std::string> Output; cm::optional<std::string> Input; @@ -2521,17 +2497,13 @@ bool HandleGenerateCommand(std::vector<std::string> const& args, .Bind("NEWLINE_STYLE"_s, &Arguments::NewLineStyle); std::vector<std::string> unparsedArguments; - std::vector<cm::string_view> keywordsMissingValues; std::vector<cm::string_view> parsedKeywords; Arguments const arguments = parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments, - &keywordsMissingValues, &parsedKeywords); + /*keywordsMissingValue=*/nullptr, &parsedKeywords); - if (!keywordsMissingValues.empty()) { - status.SetError( - cmStrCat("GENERATE keywords missing values:\n ", - cmJoin(cmMakeRange(keywordsMissingValues), "\n "))); - return false; + if (arguments.MaybeReportError(status.GetMakefile())) { + return true; } if (!unparsedArguments.empty()) { @@ -3045,7 +3017,7 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args, "\n ]])"); } - struct Arguments + struct Arguments : public ArgumentParser::ParseResult { std::string ResolvedDependenciesVar; std::string UnresolvedDependenciesVar; @@ -3088,10 +3060,8 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args, .Bind("POST_EXCLUDE_FILES_STRICT"_s, &Arguments::PostExcludeFilesStrict); std::vector<std::string> unrecognizedArguments; - std::vector<cm::string_view> keywordsMissingValues; auto parsedArgs = - parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments, - &keywordsMissingValues); + parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments); auto argIt = unrecognizedArguments.begin(); if (argIt != unrecognizedArguments.end()) { status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\"")); @@ -3099,12 +3069,9 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args, return false; } - if (!keywordsMissingValues.empty()) { - status.SetError( - cmStrCat("Keywords missing values:\n ", - cmJoin(cmMakeRange(keywordsMissingValues), "\n "))); + if (parsedArgs.MaybeReportError(status.GetMakefile())) { cmSystemTools::SetFatalErrorOccurred(); - return false; + return true; } cmRuntimeDependencyArchive archive( @@ -3204,7 +3171,7 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args, bool HandleConfigureCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { - struct Arguments + struct Arguments : public ArgumentParser::ParseResult { cm::optional<std::string> Output; cm::optional<std::string> Content; @@ -3223,10 +3190,8 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, .Bind("NEWLINE_STYLE"_s, &Arguments::NewlineStyle); std::vector<std::string> unrecognizedArguments; - std::vector<cm::string_view> keywordsMissingValues; auto parsedArgs = - parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments, - &keywordsMissingValues); + parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments); auto argIt = unrecognizedArguments.begin(); if (argIt != unrecognizedArguments.end()) { @@ -3236,12 +3201,9 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, return false; } - if (!keywordsMissingValues.empty()) { - status.SetError( - cmStrCat("CONFIGURE keywords missing values:\n ", - cmJoin(cmMakeRange(keywordsMissingValues), "\n "))); + if (parsedArgs.MaybeReportError(status.GetMakefile())) { cmSystemTools::SetFatalErrorOccurred(); - return false; + return true; } if (!parsedArgs.Output) { @@ -3336,7 +3298,7 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, bool HandleArchiveCreateCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { - struct Arguments + struct Arguments : public ArgumentParser::ParseResult { std::string Output; std::string Format; @@ -3362,10 +3324,8 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args, .Bind("PATHS"_s, &Arguments::Paths); std::vector<std::string> unrecognizedArguments; - std::vector<cm::string_view> keywordsMissingValues; auto parsedArgs = - parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments, - &keywordsMissingValues); + parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments); auto argIt = unrecognizedArguments.begin(); if (argIt != unrecognizedArguments.end()) { status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\"")); @@ -3373,12 +3333,9 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args, return false; } - if (!keywordsMissingValues.empty()) { - status.SetError( - cmStrCat("Keywords missing values:\n ", - cmJoin(cmMakeRange(keywordsMissingValues), "\n "))); + if (parsedArgs.MaybeReportError(status.GetMakefile())) { cmSystemTools::SetFatalErrorOccurred(); - return false; + return true; } const char* knownFormats[] = { @@ -3467,7 +3424,7 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args, bool HandleArchiveExtractCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { - struct Arguments + struct Arguments : public ArgumentParser::ParseResult { std::string Input; bool Verbose = false; @@ -3486,10 +3443,8 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args, .Bind("TOUCH"_s, &Arguments::Touch); std::vector<std::string> unrecognizedArguments; - std::vector<cm::string_view> keywordsMissingValues; auto parsedArgs = - parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments, - &keywordsMissingValues); + parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments); auto argIt = unrecognizedArguments.begin(); if (argIt != unrecognizedArguments.end()) { status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\"")); @@ -3497,12 +3452,9 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args, return false; } - if (!keywordsMissingValues.empty()) { - status.SetError( - cmStrCat("Keywords missing values:\n ", - cmJoin(cmMakeRange(keywordsMissingValues), "\n "))); + if (parsedArgs.MaybeReportError(status.GetMakefile())) { cmSystemTools::SetFatalErrorOccurred(); - return false; + return true; } std::string inFile = parsedArgs.Input; @@ -3557,10 +3509,15 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args, return true; } -bool ValidateAndConvertPermissions(const std::vector<std::string>& permissions, - mode_t& perms, cmExecutionStatus& status) +bool ValidateAndConvertPermissions( + cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> const& + permissions, + mode_t& perms, cmExecutionStatus& status) { - for (const auto& i : permissions) { + if (!permissions) { + return true; + } + for (const auto& i : *permissions) { if (!cmFSPermissions::stringToModeT(i, perms)) { status.SetError(i + " is an invalid permission specifier"); cmSystemTools::SetFatalErrorOccurred(); @@ -3592,11 +3549,14 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse, globber.SetRecurse(recurse); globber.SetRecurseListDirs(recurse); - struct Arguments + struct Arguments : public ArgumentParser::ParseResult { - ArgumentParser::NonEmpty<std::vector<std::string>> Permissions; - ArgumentParser::NonEmpty<std::vector<std::string>> FilePermissions; - ArgumentParser::NonEmpty<std::vector<std::string>> DirectoryPermissions; + cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> + Permissions; + cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> + FilePermissions; + cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> + DirectoryPermissions; }; static auto const parser = @@ -3606,21 +3566,20 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse, .Bind("DIRECTORY_PERMISSIONS"_s, &Arguments::DirectoryPermissions); std::vector<std::string> pathEntries; - std::vector<cm::string_view> keywordsMissingValues; - Arguments parsedArgs = parser.Parse(cmMakeRange(args).advance(1), - &pathEntries, &keywordsMissingValues); + Arguments parsedArgs = + parser.Parse(cmMakeRange(args).advance(1), &pathEntries); // check validity of arguments - if (parsedArgs.Permissions.empty() && parsedArgs.FilePermissions.empty() && - parsedArgs.DirectoryPermissions.empty()) // no permissions given + if (!parsedArgs.Permissions && !parsedArgs.FilePermissions && + !parsedArgs.DirectoryPermissions) // no permissions given { status.SetError("No permissions given"); cmSystemTools::SetFatalErrorOccurred(); return false; } - if (!parsedArgs.Permissions.empty() && !parsedArgs.FilePermissions.empty() && - !parsedArgs.DirectoryPermissions.empty()) // all keywords are used + if (parsedArgs.Permissions && parsedArgs.FilePermissions && + parsedArgs.DirectoryPermissions) // all keywords are used { status.SetError("Remove either PERMISSIONS or FILE_PERMISSIONS or " "DIRECTORY_PERMISSIONS from the invocation"); @@ -3628,12 +3587,9 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse, return false; } - if (!keywordsMissingValues.empty()) { - for (const auto& i : keywordsMissingValues) { - status.SetError(cmStrCat(i, " is not given any arguments")); - cmSystemTools::SetFatalErrorOccurred(); - } - return false; + if (parsedArgs.MaybeReportError(status.GetMakefile())) { + cmSystemTools::SetFatalErrorOccurred(); + return true; } // validate permissions @@ -3677,7 +3633,7 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse, if (cmSystemTools::FileExists(i, true)) { bool success = true; const mode_t& filePermissions = - parsedArgs.FilePermissions.empty() ? perms : fperms; + parsedArgs.FilePermissions ? fperms : perms; if (filePermissions) { success = SetPermissions(i, filePermissions, status); } @@ -3689,7 +3645,7 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse, else if (cmSystemTools::FileIsDirectory(i)) { bool success = true; const mode_t& directoryPermissions = - parsedArgs.DirectoryPermissions.empty() ? perms : dperms; + parsedArgs.DirectoryPermissions ? dperms : perms; if (directoryPermissions) { success = SetPermissions(i, directoryPermissions, status); } diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index b1044a8..82adca8 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -2160,11 +2160,9 @@ bool HandleRuntimeDependencySetMode(std::vector<std::string> const& args, // These generic args also contain the runtime dependency set std::string runtimeDependencySetArg; std::vector<std::string> runtimeDependencyArgVector; - std::vector<cm::string_view> parsedArgs; cmInstallCommandArguments genericArgs(helper.DefaultComponentName); genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg); - genericArgs.Parse(genericArgVector, &runtimeDependencyArgVector, nullptr, - &parsedArgs); + genericArgs.Parse(genericArgVector, &runtimeDependencyArgVector); bool success = genericArgs.Finalize(); cmInstallCommandArguments libraryArgs(helper.DefaultComponentName); diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx index ecfc5fc..f0ace50 100644 --- a/Tests/CMakeLib/testArgumentParser.cxx +++ b/Tests/CMakeLib/testArgumentParser.cxx @@ -3,7 +3,9 @@ #include <initializer_list> #include <iostream> +#include <map> #include <string> +#include <utility> #include <vector> #include <cm/optional> @@ -15,7 +17,7 @@ namespace { -struct Result +struct Result : public ArgumentParser::ParseResult { bool Option1 = false; bool Option2 = false; @@ -69,6 +71,11 @@ bool verifyResult(Result const& result, static std::vector<cm::string_view> const missing = { "STRING_1"_s, "LIST_1"_s, "LIST_4"_s }; + static std::map<cm::string_view, std::string> const keywordErrors = { + { "STRING_1"_s, " missing required value\n" }, + { "LIST_1"_s, " missing required value\n" }, + { "LIST_4"_s, " missing required value\n" } + }; #define ASSERT_TRUE(x) \ do { \ @@ -78,6 +85,8 @@ bool verifyResult(Result const& result, } \ } while (false) + ASSERT_TRUE(!result); + ASSERT_TRUE(result.Option1); ASSERT_TRUE(!result.Option2); @@ -110,6 +119,13 @@ bool verifyResult(Result const& result, ASSERT_TRUE(unparsedArguments[0] == "bar"); ASSERT_TRUE(keywordsMissingValue == missing); + ASSERT_TRUE(result.GetKeywordErrors().size() == keywordErrors.size()); + for (auto const& ke : result.GetKeywordErrors()) { + auto const ki = keywordErrors.find(ke.first); + ASSERT_TRUE(ki != keywordErrors.end()); + ASSERT_TRUE(ke.second == ki->second); + } + return true; } @@ -119,54 +135,65 @@ bool testArgumentParserDynamic() std::vector<std::string> unparsedArguments; std::vector<cm::string_view> keywordsMissingValue; - cmArgumentParser<void>{} - .Bind("OPTION_1"_s, result.Option1) - .Bind("OPTION_2"_s, result.Option2) - .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) - .Bind("MULTI_4"_s, result.Multi4) - .Parse(args, &unparsedArguments, &keywordsMissingValue); + static_cast<ArgumentParser::ParseResult&>(result) = + cmArgumentParser<void>{} + .Bind("OPTION_1"_s, result.Option1) + .Bind("OPTION_2"_s, result.Option2) + .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) + .Bind("MULTI_4"_s, result.Multi4) + .Parse(args, &unparsedArguments, &keywordsMissingValue); return verifyResult(result, unparsedArguments, keywordsMissingValue); } +static auto const parserStatic = // + cmArgumentParser<Result>{} + .Bind("OPTION_1"_s, &Result::Option1) + .Bind("OPTION_2"_s, &Result::Option2) + .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) + .Bind("MULTI_4"_s, &Result::Multi4) + /* keep semicolon on own line */; + bool testArgumentParserStatic() { - static auto const parser = // - cmArgumentParser<Result>{} - .Bind("OPTION_1"_s, &Result::Option1) - .Bind("OPTION_2"_s, &Result::Option2) - .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) - .Bind("MULTI_4"_s, &Result::Multi4); - std::vector<std::string> unparsedArguments; std::vector<cm::string_view> keywordsMissingValue; Result const result = - parser.Parse(args, &unparsedArguments, &keywordsMissingValue); + parserStatic.Parse(args, &unparsedArguments, &keywordsMissingValue); + return verifyResult(result, unparsedArguments, keywordsMissingValue); +} +bool testArgumentParserStaticBool() +{ + std::vector<std::string> unparsedArguments; + std::vector<cm::string_view> keywordsMissingValue; + Result result; + ASSERT_TRUE(parserStatic.Parse(result, args, &unparsedArguments, + &keywordsMissingValue) == false); return verifyResult(result, unparsedArguments, keywordsMissingValue); } @@ -184,5 +211,10 @@ int testArgumentParser(int /*unused*/, char* /*unused*/ []) return -1; } + if (!testArgumentParserStaticBool()) { + std::cout << "While executing testArgumentParserStaticBool().\n"; + return -1; + } + return 0; } diff --git a/Tests/RunCMake/File_Archive/create-missing-args-stderr.txt b/Tests/RunCMake/File_Archive/create-missing-args-stderr.txt index ecfe401..fd026f9 100644 --- a/Tests/RunCMake/File_Archive/create-missing-args-stderr.txt +++ b/Tests/RunCMake/File_Archive/create-missing-args-stderr.txt @@ -1,9 +1,19 @@ ^CMake Error at create-missing-args.cmake:[0-9]+ \(file\): - file Keywords missing values: + Error after keyword "COMPRESSION": + + missing required value + + Error after keyword "COMPRESSION_LEVEL": + + missing required value + + Error after keyword "FORMAT": + + missing required value + + Error after keyword "OUTPUT": + + missing required value - OUTPUT - FORMAT - COMPRESSION - COMPRESSION_LEVEL Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/File_Archive/extract-missing-args-stderr.txt b/Tests/RunCMake/File_Archive/extract-missing-args-stderr.txt index 96c779f..0c93ece 100644 --- a/Tests/RunCMake/File_Archive/extract-missing-args-stderr.txt +++ b/Tests/RunCMake/File_Archive/extract-missing-args-stderr.txt @@ -1,7 +1,11 @@ ^CMake Error at extract-missing-args.cmake:[0-9]+ \(file\): - file Keywords missing values: + Error after keyword "DESTINATION": + + missing required value + + Error after keyword "INPUT": + + missing required value - INPUT - DESTINATION Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/File_Configure/BadArgContent-stderr.txt b/Tests/RunCMake/File_Configure/BadArgContent-stderr.txt index dd6a2e7..72292f9 100644 --- a/Tests/RunCMake/File_Configure/BadArgContent-stderr.txt +++ b/Tests/RunCMake/File_Configure/BadArgContent-stderr.txt @@ -1,6 +1,7 @@ CMake Error at BadArgContent.cmake:[0-9]+ \(file\): - file CONFIGURE keywords missing values: + Error after keyword "CONTENT": + + missing required value - CONTENT Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt b/Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt index e1bf7b4..d793f48 100644 --- a/Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt +++ b/Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt @@ -1,6 +1,7 @@ CMake Error at BadArgOutput.cmake:[0-9]+ \(file\): - file CONFIGURE keywords missing values: + Error after keyword "OUTPUT": + + missing required value - OUTPUT Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/File_Generate/EmptyCondition1-stderr.txt b/Tests/RunCMake/File_Generate/EmptyCondition1-stderr.txt index 4278bce..708e6be 100644 --- a/Tests/RunCMake/File_Generate/EmptyCondition1-stderr.txt +++ b/Tests/RunCMake/File_Generate/EmptyCondition1-stderr.txt @@ -1,6 +1,7 @@ CMake Error at EmptyCondition1.cmake:2 \(file\): - file GENERATE keywords missing values: + Error after keyword "CONDITION": + + missing required value - CONDITION Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/File_Generate/NewLineStyle-NoArg-stderr.txt b/Tests/RunCMake/File_Generate/NewLineStyle-NoArg-stderr.txt index 4059bf8..b1b7f80 100644 --- a/Tests/RunCMake/File_Generate/NewLineStyle-NoArg-stderr.txt +++ b/Tests/RunCMake/File_Generate/NewLineStyle-NoArg-stderr.txt @@ -1,6 +1,7 @@ CMake Error at NewLineStyle-NoArg.cmake:[0-9]+ \(file\): - file GENERATE keywords missing values: + Error after keyword "NEWLINE_STYLE": + + missing required value - NEWLINE_STYLE Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2-stderr.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2-stderr.txt index 6a430f1..ea1566d 100644 --- a/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2-stderr.txt +++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2-stderr.txt @@ -1,5 +1,7 @@ CMake Error at Registry_BadQuery2.cmake:[0-9]+ \(cmake_host_system_information\): - cmake_host_system_information missing expected value for argument\(s\) - "VALUE". + Error after keyword "VALUE": + + missing required value + Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadView1-stderr.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadView1-stderr.txt index 5eda4ff..f8c96d8 100644 --- a/Tests/RunCMake/cmake_host_system_information/Registry_BadView1-stderr.txt +++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadView1-stderr.txt @@ -1,5 +1,7 @@ CMake Error at Registry_BadView1.cmake:[0-9]+ \(cmake_host_system_information\): - cmake_host_system_information missing expected value for argument\(s\) - "VIEW". + Error after keyword "VIEW": + + missing required value + Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/cmake_path/BASE_DIRECTORY-no-arg-stderr.txt b/Tests/RunCMake/cmake_path/BASE_DIRECTORY-no-arg-stderr.txt new file mode 100644 index 0000000..ad7d134 --- /dev/null +++ b/Tests/RunCMake/cmake_path/BASE_DIRECTORY-no-arg-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at .+/cmake_path/call-cmake_path.cmake:[0-9]+ \(cmake_path\): + Error after keyword "BASE_DIRECTORY": + + missing required value diff --git a/Tests/RunCMake/cmake_path/OUTPUT_VARIABLE-no-arg-stderr.txt b/Tests/RunCMake/cmake_path/OUTPUT_VARIABLE-no-arg-stderr.txt index e1d6592..63289ef 100644 --- a/Tests/RunCMake/cmake_path/OUTPUT_VARIABLE-no-arg-stderr.txt +++ b/Tests/RunCMake/cmake_path/OUTPUT_VARIABLE-no-arg-stderr.txt @@ -1,2 +1,4 @@ CMake Error at .+/cmake_path/call-cmake_path.cmake:[0-9]+ \(cmake_path\): - cmake_path OUTPUT_VARIABLE requires an argument. + Error after keyword "OUTPUT_VARIABLE": + + missing required value diff --git a/Tests/RunCMake/cmake_path/RunCMakeTest.cmake b/Tests/RunCMake/cmake_path/RunCMakeTest.cmake index 991f46b..8a2dd95 100644 --- a/Tests/RunCMake/cmake_path/RunCMakeTest.cmake +++ b/Tests/RunCMake/cmake_path/RunCMakeTest.cmake @@ -74,6 +74,14 @@ foreach (command IN ITEMS APPEND APPEND_STRING REMOVE_FILENAME REPLACE_FILENAME endforeach() +## BASE_DIRECTORY without argument +set (RunCMake-stderr-file "BASE_DIRECTORY-no-arg-stderr.txt") + +foreach (command IN ITEMS RELATIVE_PATH ABSOLUTE_PATH) + run_cmake_command (${command}-OUTPUT_VARIABLE-no-arg "${CMAKE_COMMAND}" "-DCMAKE_PATH_ARGUMENTS=${command} path BASE_DIRECTORY" -P "${RunCMake_SOURCE_DIR}/call-cmake_path.cmake") +endforeach() + + ## Invalid output variable set (RunCMake-stderr-file "invalid-output-var-stderr.txt") diff --git a/Tests/RunCMake/execute_process/EchoCommand3-stderr.txt b/Tests/RunCMake/execute_process/EchoCommand3-stderr.txt index e27f1e6..62cad52 100644 --- a/Tests/RunCMake/execute_process/EchoCommand3-stderr.txt +++ b/Tests/RunCMake/execute_process/EchoCommand3-stderr.txt @@ -1,2 +1,4 @@ CMake Error at .*EchoCommand.cmake:.*\(execute_process\): - execute_process called with no value for COMMAND_ECHO. + Error after keyword "COMMAND_ECHO": + + missing required value diff --git a/Tests/RunCMake/execute_process/EncodingMissing-stderr.txt b/Tests/RunCMake/execute_process/EncodingMissing-stderr.txt index 1a69579..7f85654 100644 --- a/Tests/RunCMake/execute_process/EncodingMissing-stderr.txt +++ b/Tests/RunCMake/execute_process/EncodingMissing-stderr.txt @@ -1,4 +1,7 @@ ^CMake Error at EncodingMissing.cmake:[0-9]+ \(execute_process\): - execute_process called with no value for ENCODING. + Error after keyword "ENCODING": + + missing required value + Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-all-perms-stderr.txt b/Tests/RunCMake/file-CHMOD/CHMOD-all-perms-stderr.txt deleted file mode 100644 index b22387b..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-all-perms-stderr.txt +++ /dev/null @@ -1,5 +0,0 @@ -CMake Error at CHMOD-all-perms\.cmake:[0-9]+ \(file\): - file Remove either PERMISSIONS or FILE_PERMISSIONS or DIRECTORY_PERMISSIONS - from the invocation -Call Stack \(most recent call first\): - CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-all-perms.cmake b/Tests/RunCMake/file-CHMOD/CHMOD-all-perms.cmake deleted file mode 100644 index b49583d..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-all-perms.cmake +++ /dev/null @@ -1,6 +0,0 @@ -file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) -file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) - -file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a) -file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a PERMISSIONS OWNER_READ - FILE_PERMISSIONS OWNER_READ DIRECTORY_PERMISSIONS OWNER_READ) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-invalid-path-stderr.txt b/Tests/RunCMake/file-CHMOD/CHMOD-invalid-path-stderr.txt deleted file mode 100644 index 8d09e35..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-invalid-path-stderr.txt +++ /dev/null @@ -1,6 +0,0 @@ -CMake Error at CHMOD-invalid-path\.cmake:[0-9]+ \(file\): - file does not exist: - - .*/chmod-tests/I_dont_exist -Call Stack \(most recent call first\): - CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-invalid-path.cmake b/Tests/RunCMake/file-CHMOD/CHMOD-invalid-path.cmake deleted file mode 100644 index 36915c1..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-invalid-path.cmake +++ /dev/null @@ -1,4 +0,0 @@ -file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) -file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) - -file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/I_dont_exist PERMISSIONS OWNER_READ) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-invalid-perms-stderr.txt b/Tests/RunCMake/file-CHMOD/CHMOD-invalid-perms-stderr.txt deleted file mode 100644 index 84ba2a2..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-invalid-perms-stderr.txt +++ /dev/null @@ -1,4 +0,0 @@ -CMake Error at CHMOD-invalid-perms\.cmake:[0-9]+ \(file\): - file INVALID_PERMISSION is an invalid permission specifier -Call Stack \(most recent call first\): - CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-invalid-perms.cmake b/Tests/RunCMake/file-CHMOD/CHMOD-invalid-perms.cmake deleted file mode 100644 index 22cab0b..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-invalid-perms.cmake +++ /dev/null @@ -1,5 +0,0 @@ -file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) -file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) - -file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a) -file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a PERMISSIONS INVALID_PERMISSION) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-no-keyword-stderr.txt b/Tests/RunCMake/file-CHMOD/CHMOD-no-keyword-stderr.txt deleted file mode 100644 index 2c248f8..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-no-keyword-stderr.txt +++ /dev/null @@ -1,4 +0,0 @@ -CMake Error at CHMOD-no-keyword\.cmake:[0-9]+ \(file\): - file No permissions given -Call Stack \(most recent call first\): - CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-no-keyword.cmake b/Tests/RunCMake/file-CHMOD/CHMOD-no-keyword.cmake deleted file mode 100644 index 8b62106..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-no-keyword.cmake +++ /dev/null @@ -1,5 +0,0 @@ -file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) -file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) - -file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a) -file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-no-perms-stderr.txt b/Tests/RunCMake/file-CHMOD/CHMOD-no-perms-stderr.txt deleted file mode 100644 index a18609f..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-no-perms-stderr.txt +++ /dev/null @@ -1,4 +0,0 @@ -CMake Error at CHMOD-no-perms\.cmake:[0-9]+ \(file\): - file No permissions given -Call Stack \(most recent call first\): - CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-no-perms.cmake b/Tests/RunCMake/file-CHMOD/CHMOD-no-perms.cmake deleted file mode 100644 index 9fbd359..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-no-perms.cmake +++ /dev/null @@ -1,5 +0,0 @@ -file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) -file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) - -file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a) -file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a PERMISSIONS) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-ok.cmake b/Tests/RunCMake/file-CHMOD/CHMOD-ok.cmake deleted file mode 100644 index 87e3e57..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-ok.cmake +++ /dev/null @@ -1,5 +0,0 @@ -file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) -file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) - -file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a) -file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a PERMISSIONS OWNER_READ) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-override.cmake b/Tests/RunCMake/file-CHMOD/CHMOD-override.cmake deleted file mode 100644 index d9226b8..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-override.cmake +++ /dev/null @@ -1,6 +0,0 @@ -file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) -file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) - -file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a) -file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a PERMISSIONS OWNER_READ - FILE_PERMISSIONS OWNER_READ OWNER_WRITE) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-write-only-stderr.txt b/Tests/RunCMake/file-CHMOD/CHMOD-write-only-stderr.txt deleted file mode 100644 index 1c87a59..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-write-only-stderr.txt +++ /dev/null @@ -1,6 +0,0 @@ -CMake Error at CHMOD-write-only\.cmake:[0-9]+ \(file\): - file failed to open for reading \(Permission denied\): - - .*/chmod-tests/a -Call Stack \(most recent call first\): - CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-write-only.cmake b/Tests/RunCMake/file-CHMOD/CHMOD-write-only.cmake deleted file mode 100644 index 1289efc..0000000 --- a/Tests/RunCMake/file-CHMOD/CHMOD-write-only.cmake +++ /dev/null @@ -1,6 +0,0 @@ -file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) -file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests) - -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a "CONTENT") -file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a PERMISSIONS OWNER_WRITE) -file(READ ${CMAKE_CURRENT_BINARY_DIR}/chmod-tests/a content) diff --git a/Tests/RunCMake/file-CHMOD/RunCMakeTest.cmake b/Tests/RunCMake/file-CHMOD/RunCMakeTest.cmake index 18deb89..e6b1169 100644 --- a/Tests/RunCMake/file-CHMOD/RunCMakeTest.cmake +++ b/Tests/RunCMake/file-CHMOD/RunCMakeTest.cmake @@ -1,12 +1,14 @@ include(RunCMake) -run_cmake(CHMOD-no-perms) -run_cmake(CHMOD-no-keyword) -run_cmake(CHMOD-all-perms) -run_cmake(CHMOD-invalid-perms) -run_cmake(CHMOD-invalid-path) -run_cmake(CHMOD-ok) -run_cmake(CHMOD-override) +run_cmake_script(no-perms) +run_cmake_script(missing-perms) +run_cmake_script(missing-file-perms) +run_cmake_script(missing-dir-perms) +run_cmake_script(all-perms) +run_cmake_script(invalid-perms) +run_cmake_script(invalid-path) +run_cmake_script(ok) +run_cmake_script(override) if(UNIX) execute_process(COMMAND id -u $ENV{USER} @@ -15,5 +17,5 @@ if(UNIX) endif() if(NOT WIN32 AND NOT MSYS AND NOT "${uid}" STREQUAL "0") - run_cmake(CHMOD-write-only) + run_cmake_script(write-only) endif() diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-write-only-result.txt b/Tests/RunCMake/file-CHMOD/all-perms-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/file-CHMOD/CHMOD-write-only-result.txt +++ b/Tests/RunCMake/file-CHMOD/all-perms-result.txt diff --git a/Tests/RunCMake/file-CHMOD/all-perms-stderr.txt b/Tests/RunCMake/file-CHMOD/all-perms-stderr.txt new file mode 100644 index 0000000..6932a1f --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/all-perms-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at [^ +]*/all-perms\.cmake:[0-9]+ \(file\): + file Remove either PERMISSIONS or FILE_PERMISSIONS or DIRECTORY_PERMISSIONS + from the invocation$ diff --git a/Tests/RunCMake/file-CHMOD/all-perms.cmake b/Tests/RunCMake/file-CHMOD/all-perms.cmake new file mode 100644 index 0000000..5ff81b8 --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/all-perms.cmake @@ -0,0 +1,3 @@ +file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/a) +file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/a PERMISSIONS OWNER_READ + FILE_PERMISSIONS OWNER_READ DIRECTORY_PERMISSIONS OWNER_READ) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-no-perms-result.txt b/Tests/RunCMake/file-CHMOD/invalid-path-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/file-CHMOD/CHMOD-no-perms-result.txt +++ b/Tests/RunCMake/file-CHMOD/invalid-path-result.txt diff --git a/Tests/RunCMake/file-CHMOD/invalid-path-stderr.txt b/Tests/RunCMake/file-CHMOD/invalid-path-stderr.txt new file mode 100644 index 0000000..eb5fb31 --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/invalid-path-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error at [^ +]*/invalid-path\.cmake:[0-9]+ \(file\): + file does not exist: + + [^ +]*/Tests/RunCMake/file-CHMOD/invalid-path-build/I_dont_exist$ diff --git a/Tests/RunCMake/file-CHMOD/invalid-path.cmake b/Tests/RunCMake/file-CHMOD/invalid-path.cmake new file mode 100644 index 0000000..e8b0313 --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/invalid-path.cmake @@ -0,0 +1 @@ +file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/I_dont_exist PERMISSIONS OWNER_READ) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-no-keyword-result.txt b/Tests/RunCMake/file-CHMOD/invalid-perms-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/file-CHMOD/CHMOD-no-keyword-result.txt +++ b/Tests/RunCMake/file-CHMOD/invalid-perms-result.txt diff --git a/Tests/RunCMake/file-CHMOD/invalid-perms-stderr.txt b/Tests/RunCMake/file-CHMOD/invalid-perms-stderr.txt new file mode 100644 index 0000000..daab22e --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/invalid-perms-stderr.txt @@ -0,0 +1,3 @@ +^CMake Error at [^ +]*/invalid-perms\.cmake:[0-9]+ \(file\): + file INVALID_PERMISSION is an invalid permission specifier$ diff --git a/Tests/RunCMake/file-CHMOD/invalid-perms.cmake b/Tests/RunCMake/file-CHMOD/invalid-perms.cmake new file mode 100644 index 0000000..42129b9 --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/invalid-perms.cmake @@ -0,0 +1,2 @@ +file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/a) +file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/a PERMISSIONS INVALID_PERMISSION) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-invalid-perms-result.txt b/Tests/RunCMake/file-CHMOD/missing-dir-perms-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/file-CHMOD/CHMOD-invalid-perms-result.txt +++ b/Tests/RunCMake/file-CHMOD/missing-dir-perms-result.txt diff --git a/Tests/RunCMake/file-CHMOD/missing-dir-perms-stderr.txt b/Tests/RunCMake/file-CHMOD/missing-dir-perms-stderr.txt new file mode 100644 index 0000000..c05bb2d --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/missing-dir-perms-stderr.txt @@ -0,0 +1,5 @@ +^CMake Error at [^ +]*/missing-dir-perms.cmake:[0-9]+ \(file\): + Error after keyword "DIRECTORY_PERMISSIONS": + + missing required value$ diff --git a/Tests/RunCMake/file-CHMOD/missing-dir-perms.cmake b/Tests/RunCMake/file-CHMOD/missing-dir-perms.cmake new file mode 100644 index 0000000..9d0fdad --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/missing-dir-perms.cmake @@ -0,0 +1,2 @@ +file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/a) +file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/a PERMISSIONS OWNER_READ DIRECTORY_PERMISSIONS) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-invalid-path-result.txt b/Tests/RunCMake/file-CHMOD/missing-file-perms-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/file-CHMOD/CHMOD-invalid-path-result.txt +++ b/Tests/RunCMake/file-CHMOD/missing-file-perms-result.txt diff --git a/Tests/RunCMake/file-CHMOD/missing-file-perms-stderr.txt b/Tests/RunCMake/file-CHMOD/missing-file-perms-stderr.txt new file mode 100644 index 0000000..c3f4f0f --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/missing-file-perms-stderr.txt @@ -0,0 +1,5 @@ +^CMake Error at [^ +]*/missing-file-perms.cmake:[0-9]+ \(file\): + Error after keyword "FILE_PERMISSIONS": + + missing required value$ diff --git a/Tests/RunCMake/file-CHMOD/missing-file-perms.cmake b/Tests/RunCMake/file-CHMOD/missing-file-perms.cmake new file mode 100644 index 0000000..bcf35aa --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/missing-file-perms.cmake @@ -0,0 +1,2 @@ +file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/a) +file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/a PERMISSIONS OWNER_READ FILE_PERMISSIONS) diff --git a/Tests/RunCMake/file-CHMOD/CHMOD-all-perms-result.txt b/Tests/RunCMake/file-CHMOD/missing-perms-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/file-CHMOD/CHMOD-all-perms-result.txt +++ b/Tests/RunCMake/file-CHMOD/missing-perms-result.txt diff --git a/Tests/RunCMake/file-CHMOD/missing-perms-stderr.txt b/Tests/RunCMake/file-CHMOD/missing-perms-stderr.txt new file mode 100644 index 0000000..1508b13 --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/missing-perms-stderr.txt @@ -0,0 +1,5 @@ +^CMake Error at [^ +]*/missing-perms.cmake:[0-9]+ \(file\): + Error after keyword "PERMISSIONS": + + missing required value$ diff --git a/Tests/RunCMake/file-CHMOD/missing-perms.cmake b/Tests/RunCMake/file-CHMOD/missing-perms.cmake new file mode 100644 index 0000000..da9f182 --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/missing-perms.cmake @@ -0,0 +1,2 @@ +file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/a) +file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/a FILE_PERMISSIONS OWNER_READ PERMISSIONS) diff --git a/Tests/RunCMake/file-CHMOD/no-perms-result.txt b/Tests/RunCMake/file-CHMOD/no-perms-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/no-perms-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file-CHMOD/no-perms-stderr.txt b/Tests/RunCMake/file-CHMOD/no-perms-stderr.txt new file mode 100644 index 0000000..4c5a139 --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/no-perms-stderr.txt @@ -0,0 +1,3 @@ +^CMake Error at [^ +]*/no-perms\.cmake:[0-9]+ \(file\): + file No permissions given$ diff --git a/Tests/RunCMake/file-CHMOD/no-perms.cmake b/Tests/RunCMake/file-CHMOD/no-perms.cmake new file mode 100644 index 0000000..602cfc2 --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/no-perms.cmake @@ -0,0 +1,2 @@ +file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/a) +file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/a) diff --git a/Tests/RunCMake/file-CHMOD/ok.cmake b/Tests/RunCMake/file-CHMOD/ok.cmake new file mode 100644 index 0000000..7c74d27 --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/ok.cmake @@ -0,0 +1,2 @@ +file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/a) +file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/a PERMISSIONS OWNER_READ) diff --git a/Tests/RunCMake/file-CHMOD/override.cmake b/Tests/RunCMake/file-CHMOD/override.cmake new file mode 100644 index 0000000..67e5a23 --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/override.cmake @@ -0,0 +1,3 @@ +file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/a) +file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/a PERMISSIONS OWNER_READ + FILE_PERMISSIONS OWNER_READ OWNER_WRITE) diff --git a/Tests/RunCMake/file-CHMOD/write-only-result.txt b/Tests/RunCMake/file-CHMOD/write-only-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/write-only-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file-CHMOD/write-only-stderr.txt b/Tests/RunCMake/file-CHMOD/write-only-stderr.txt new file mode 100644 index 0000000..169a092 --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/write-only-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error at [^ +]*/write-only\.cmake:[0-9]+ \(file\): + file failed to open for reading \(Permission denied\): + + [^ +]*/Tests/RunCMake/file-CHMOD/write-only-build/a$ diff --git a/Tests/RunCMake/file-CHMOD/write-only.cmake b/Tests/RunCMake/file-CHMOD/write-only.cmake new file mode 100644 index 0000000..aa9d803 --- /dev/null +++ b/Tests/RunCMake/file-CHMOD/write-only.cmake @@ -0,0 +1,3 @@ +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/a "CONTENT") +file(CHMOD ${CMAKE_CURRENT_BINARY_DIR}/a PERMISSIONS OWNER_WRITE) +file(READ ${CMAKE_CURRENT_BINARY_DIR}/a content) diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs2-stderr.txt b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs2-stderr.txt index c6ad3d0..39f307d 100644 --- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs2-stderr.txt +++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs2-stderr.txt @@ -13,11 +13,21 @@ Call Stack \(most recent call first\): This warning is for project developers\. Use -Wno-dev to suppress it\. CMake Error at badargs2\.cmake:[0-9]+ \(file\): - file Keywords missing values: + Error after keyword "BUNDLE_EXECUTABLE": + + missing required value + + Error after keyword "CONFLICTING_DEPENDENCIES_PREFIX": + + missing required value + + Error after keyword "RESOLVED_DEPENDENCIES_VAR": + + missing required value + + Error after keyword "UNRESOLVED_DEPENDENCIES_VAR": + + missing required value - RESOLVED_DEPENDENCIES_VAR - UNRESOLVED_DEPENDENCIES_VAR - CONFLICTING_DEPENDENCIES_PREFIX - BUNDLE_EXECUTABLE Call Stack \(most recent call first\): CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/REAL_PATH-no-base-dir-stderr.txt b/Tests/RunCMake/file/REAL_PATH-no-base-dir-stderr.txt index 7c58aeb..54a3e5a 100644 --- a/Tests/RunCMake/file/REAL_PATH-no-base-dir-stderr.txt +++ b/Tests/RunCMake/file/REAL_PATH-no-base-dir-stderr.txt @@ -1,2 +1,7 @@ -CMake Error at REAL_PATH-no-base-dir.cmake:[0-9]+ \(file\): - file BASE_DIRECTORY requires a value +^CMake Error at REAL_PATH-no-base-dir.cmake:[0-9]+ \(file\): + Error after keyword "BASE_DIRECTORY": + + missing required value + +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp index b80fc22..b0ed911 100644 --- a/Utilities/IWYU/mapping.imp +++ b/Utilities/IWYU/mapping.imp @@ -91,7 +91,7 @@ { symbol: [ "std::__decay_and_strip<cmFindPackageCommand::PathLabel &>::__type", private, "\"cmConfigure.h\"", public ] }, { symbol: [ "std::__decay_and_strip<cmGlobalNinjaGenerator::TargetAlias &>::__type", private, "\"cmConfigure.h\"", public ] }, { symbol: [ "std::__decay_and_strip<__gnu_cxx::__normal_iterator<const cmCTestTestHandler::cmCTestTestProperties *, std::vector<cmCTestTestHandler::cmCTestTestProperties, std::allocator<cmCTestTestHandler::cmCTestTestProperties> > > &>::__type", private, "\"cmConfigure.h\"", public ] }, - { symbol: [ "std::__decay_and_strip<const __gnu_cxx::__normal_iterator<std::pair<cm::string_view, std::function<void (ArgumentParser::Instance &, void *)> > *, std::vector<std::pair<cm::string_view, std::function<void (ArgumentParser::Instance &, void *)> >, std::allocator<std::pair<cm::string_view, std::function<void (ArgumentParser::Instance &, void *)> > > > > &>::__type", private, "\"cmConfigure.h\"", public ] }, + { symbol: [ "std::__decay_and_strip<const __gnu_cxx::__normal_iterator<std::pair<cm::string_view, std::function<void (ArgumentParser::Instance &)> > *, std::vector<std::pair<cm::string_view, std::function<void (ArgumentParser::Instance &)> >, std::allocator<std::pair<cm::string_view, std::function<void (ArgumentParser::Instance &)> > > > > &>::__type", private, "\"cmConfigure.h\"", public ] }, { symbol: [ "std::__success_type<std::chrono::duration<double, std::ratio<1, 1> > >::type", private, "\"cmConfigure.h\"", public ] }, { symbol: [ "std::__success_type<std::chrono::duration<long, std::ratio<1, 1000000000> > >::type", private, "\"cmConfigure.h\"", public ] }, { symbol: [ "std::enable_if<true, std::chrono::duration<long, std::ratio<1, 1> > >::type", private, "\"cmConfigure.h\"", public ] }, |