From 0ccbe5a2e1e3e8144cb5433bd1669f62753e8d9a Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Mon, 10 Mar 2025 14:41:53 -0400 Subject: [PATCH] CPS: Refactor argument parsing CPS package metadata involves a fair amount of passing around a particular set of values, as well as shared argument handling, which is only going to increase as additional features are added. In order to reduce code duplication (now and going forward), create a helper class to handle the shared argument parsing and to serve as a container to pass metadata values. --- Source/CMakeLists.txt | 2 + Source/cmExportBuildPackageInfoGenerator.cxx | 10 +- Source/cmExportBuildPackageInfoGenerator.h | 7 +- Source/cmExportCommand.cxx | 88 ++------------- .../cmExportInstallPackageInfoGenerator.cxx | 11 +- Source/cmExportInstallPackageInfoGenerator.h | 9 +- Source/cmExportPackageInfoGenerator.cxx | 18 +-- Source/cmExportPackageInfoGenerator.h | 10 +- Source/cmInstallCommand.cxx | 70 ++---------- .../cmInstallPackageInfoExportGenerator.cxx | 14 +-- Source/cmInstallPackageInfoExportGenerator.h | 9 +- Source/cmPackageInfoArguments.cxx | 104 ++++++++++++++++++ Source/cmPackageInfoArguments.h | 98 +++++++++++++++++ 13 files changed, 251 insertions(+), 199 deletions(-) create mode 100644 Source/cmPackageInfoArguments.cxx create mode 100644 Source/cmPackageInfoArguments.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 59bd8cef59..b1c8290d78 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -409,6 +409,8 @@ add_library( cmNewLineStyle.cxx cmOrderDirectories.cxx cmOrderDirectories.h + cmPackageInfoArguments.cxx + cmPackageInfoArguments.h cmPackageInfoReader.cxx cmPackageInfoReader.h cmPackageState.h diff --git a/Source/cmExportBuildPackageInfoGenerator.cxx b/Source/cmExportBuildPackageInfoGenerator.cxx index f609624775..775360194d 100644 --- a/Source/cmExportBuildPackageInfoGenerator.cxx +++ b/Source/cmExportBuildPackageInfoGenerator.cxx @@ -11,17 +11,13 @@ #include #include "cmGeneratorExpression.h" +#include "cmPackageInfoArguments.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" cmExportBuildPackageInfoGenerator::cmExportBuildPackageInfoGenerator( - std::string packageName, std::string version, std::string versionCompat, - std::string versionSchema, std::vector defaultTargets, - std::vector defaultConfigurations) - : cmExportPackageInfoGenerator( - std::move(packageName), std::move(version), std::move(versionCompat), - std::move(versionSchema), std::move(defaultTargets), - std::move(defaultConfigurations)) + cmPackageInfoArguments arguments) + : cmExportPackageInfoGenerator(std::move(arguments)) { this->SetNamespace(cmStrCat(this->GetPackageName(), "::"_s)); } diff --git a/Source/cmExportBuildPackageInfoGenerator.h b/Source/cmExportBuildPackageInfoGenerator.h index 7bca3e2398..0851d332a8 100644 --- a/Source/cmExportBuildPackageInfoGenerator.h +++ b/Source/cmExportBuildPackageInfoGenerator.h @@ -6,7 +6,6 @@ #include #include -#include #include "cmExportBuildFileGenerator.h" #include "cmExportPackageInfoGenerator.h" @@ -16,6 +15,7 @@ class Value; } class cmGeneratorTarget; +class cmPackageInfoArguments; /** \class cmExportBuildPackageInfoGenerator * \brief Generate a file exporting targets from a build tree. @@ -31,10 +31,7 @@ class cmExportBuildPackageInfoGenerator , public cmExportPackageInfoGenerator { public: - cmExportBuildPackageInfoGenerator( - std::string packageName, std::string version, std::string versionCompat, - std::string versionSchema, std::vector defaultTargets, - std::vector defaultConfigurations); + cmExportBuildPackageInfoGenerator(cmPackageInfoArguments arguments); protected: // Implement virtual methods from the superclass. diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index af81fe31fe..25f09a753a 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -24,10 +24,10 @@ #include "cmExportBuildPackageInfoGenerator.h" #include "cmExportSet.h" #include "cmGeneratedFileStream.h" -#include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmPackageInfoArguments.h" #include "cmPolicies.h" #include "cmRange.h" #include "cmStateTypes.h" @@ -63,24 +63,16 @@ bool cmExportCommand(std::vector const& args, return HandlePackage(args, status); } - struct Arguments + struct Arguments : cmPackageInfoArguments { cm::optional>> Targets; ArgumentParser::NonEmpty ExportSetName; ArgumentParser::NonEmpty Namespace; ArgumentParser::NonEmpty Filename; ArgumentParser::NonEmpty AndroidMKFile; - ArgumentParser::NonEmpty PackageName; - ArgumentParser::NonEmpty Appendix; - ArgumentParser::NonEmpty Version; - ArgumentParser::NonEmpty VersionCompat; - ArgumentParser::NonEmpty VersionSchema; ArgumentParser::NonEmpty CxxModulesDirectory; - ArgumentParser::NonEmpty> DefaultTargets; - ArgumentParser::NonEmpty> DefaultConfigs; bool Append = false; bool ExportOld = false; - bool LowerCase = false; std::vector> PackageDependencyArgs; bool ExportPackageDependencies = false; @@ -104,14 +96,7 @@ bool cmExportCommand(std::vector const& args, } if (cmExperimental::HasSupportEnabled( status.GetMakefile(), cmExperimental::Feature::ExportPackageInfo)) { - parser.Bind("PACKAGE_INFO"_s, &Arguments::PackageName); - parser.Bind("LOWER_CASE_FILE"_s, &Arguments::LowerCase); - parser.Bind("APPENDIX"_s, &Arguments::Appendix); - parser.Bind("VERSION"_s, &Arguments::Version); - parser.Bind("COMPAT_VERSION"_s, &Arguments::VersionCompat); - parser.Bind("VERSION_SCHEMA"_s, &Arguments::VersionSchema); - parser.Bind("DEFAULT_TARGETS"_s, &Arguments::DefaultTargets); - parser.Bind("DEFAULT_CONFIGURATIONS"_s, &Arguments::DefaultConfigs); + cmPackageInfoArguments::Bind(parser); } } else if (args[0] == "SETUP") { parser.Bind("SETUP"_s, &Arguments::ExportSetName); @@ -222,24 +207,7 @@ bool cmExportCommand(std::vector const& args, } if (arguments.PackageName.empty()) { - if (arguments.LowerCase) { - status.SetError("LOWER_CASE_FILE requires PACKAGE_INFO."); - return false; - } - if (!arguments.Appendix.empty()) { - status.SetError("APPENDIX requires PACKAGE_INFO."); - return false; - } - if (!arguments.Version.empty()) { - status.SetError("VERSION requires PACKAGE_INFO."); - return false; - } - if (!arguments.DefaultTargets.empty()) { - status.SetError("DEFAULT_TARGETS requires PACKAGE_INFO."); - return false; - } - if (!arguments.DefaultConfigs.empty()) { - status.SetError("DEFAULT_CONFIGURATIONS requires PACKAGE_INFO."); + if (!arguments.Check(status, false)) { return false; } } else { @@ -251,30 +219,7 @@ bool cmExportCommand(std::vector const& args, status.SetError("PACKAGE_INFO and NAMESPACE are mutually exclusive."); return false; } - if (!arguments.Appendix.empty()) { - if (!arguments.Version.empty()) { - status.SetError("APPENDIX and VERSION are mutually exclusive."); - return false; - } - if (!arguments.DefaultTargets.empty()) { - status.SetError("APPENDIX and DEFAULT_TARGETS " - "are mutually exclusive."); - return false; - } - if (!arguments.DefaultConfigs.empty()) { - status.SetError("APPENDIX and DEFAULT_CONFIGURATIONS " - "are mutually exclusive."); - return false; - } - } - } - if (arguments.Version.empty()) { - if (!arguments.VersionCompat.empty()) { - status.SetError("COMPAT_VERSION requires VERSION."); - return false; - } - if (!arguments.VersionSchema.empty()) { - status.SetError("VERSION_SCHEMA requires VERSION."); + if (!arguments.Check(status)) { return false; } } @@ -293,23 +238,7 @@ bool cmExportCommand(std::vector const& args, if (arguments.PackageName.empty()) { fname = arguments.ExportSetName + ".cmake"; } else { - // Validate the package name. - if (!cmGeneratorExpression::IsValidTargetName(arguments.PackageName) || - arguments.PackageName.find(':') != std::string::npos) { - status.SetError( - cmStrCat(R"(PACKAGE_INFO given invalid package name ")"_s, - arguments.PackageName, R"(".)"_s)); - return false; - } - - std::string const pkgNameOnDisk = - (arguments.LowerCase ? cmSystemTools::LowerCase(arguments.PackageName) - : std::string{ arguments.PackageName }); - if (arguments.Appendix.empty()) { - fname = cmStrCat(pkgNameOnDisk, ".cps"_s); - } else { - fname = cmStrCat(pkgNameOnDisk, '-', arguments.Appendix, ".cps"_s); - } + fname = arguments.GetPackageFileName(); cps = true; } } else { @@ -430,10 +359,7 @@ bool cmExportCommand(std::vector const& args, ebag->SetAppendMode(arguments.Append); ebfg = std::move(ebag); } else if (cps) { - auto ebpg = cm::make_unique( - arguments.PackageName, arguments.Version, arguments.VersionCompat, - arguments.VersionSchema, arguments.DefaultTargets, - arguments.DefaultConfigs); + auto ebpg = cm::make_unique(arguments); ebfg = std::move(ebpg); } else { auto ebcg = cm::make_unique(); diff --git a/Source/cmExportInstallPackageInfoGenerator.cxx b/Source/cmExportInstallPackageInfoGenerator.cxx index 98959d356e..1571c50b2a 100644 --- a/Source/cmExportInstallPackageInfoGenerator.cxx +++ b/Source/cmExportInstallPackageInfoGenerator.cxx @@ -15,6 +15,7 @@ #include "cmInstallExportGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmPackageInfoArguments.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -22,14 +23,8 @@ #include "cmTargetExport.h" cmExportInstallPackageInfoGenerator::cmExportInstallPackageInfoGenerator( - cmInstallExportGenerator* iegen, std::string packageName, - std::string version, std::string versionCompat, std::string versionSchema, - std::vector defaultTargets, - std::vector defaultConfigurations) - : cmExportPackageInfoGenerator( - std::move(packageName), std::move(version), std::move(versionCompat), - std::move(versionSchema), std::move(defaultTargets), - std::move(defaultConfigurations)) + cmInstallExportGenerator* iegen, cmPackageInfoArguments arguments) + : cmExportPackageInfoGenerator(std::move(arguments)) , cmExportInstallFileGenerator(iegen) { } diff --git a/Source/cmExportInstallPackageInfoGenerator.h b/Source/cmExportInstallPackageInfoGenerator.h index d7f9c27039..abdd0151fc 100644 --- a/Source/cmExportInstallPackageInfoGenerator.h +++ b/Source/cmExportInstallPackageInfoGenerator.h @@ -6,13 +6,13 @@ #include #include -#include #include "cmExportInstallFileGenerator.h" #include "cmExportPackageInfoGenerator.h" class cmGeneratorTarget; class cmInstallExportGenerator; +class cmPackageInfoArguments; /** \class cmExportInstallPackageInfoGenerator * \brief Generate files exporting targets from an install tree. @@ -35,11 +35,8 @@ class cmExportInstallPackageInfoGenerator public: /** Construct with the export installer that will install the files. */ - cmExportInstallPackageInfoGenerator( - cmInstallExportGenerator* iegen, std::string packageName, - std::string version, std::string versionCompat, std::string versionSchema, - std::vector defaultTargets, - std::vector defaultConfigurations); + cmExportInstallPackageInfoGenerator(cmInstallExportGenerator* iegen, + cmPackageInfoArguments arguments); /** Compute the globbing expression used to load per-config import files from the main file. */ diff --git a/Source/cmExportPackageInfoGenerator.cxx b/Source/cmExportPackageInfoGenerator.cxx index 9887b8d58d..71df7456e2 100644 --- a/Source/cmExportPackageInfoGenerator.cxx +++ b/Source/cmExportPackageInfoGenerator.cxx @@ -15,6 +15,7 @@ #include #include +#include "cmArgumentParserTypes.h" #include "cmExportSet.h" #include "cmFindPackageStack.h" #include "cmGeneratorExpression.h" @@ -22,6 +23,7 @@ #include "cmList.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmPackageInfoArguments.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" @@ -30,15 +32,13 @@ static std::string const kCPS_VERSION_STR = "0.13.0"; cmExportPackageInfoGenerator::cmExportPackageInfoGenerator( - std::string packageName, std::string version, std::string versionCompat, - std::string versionSchema, std::vector defaultTargets, - std::vector defaultConfigurations) - : PackageName(std::move(packageName)) - , PackageVersion(std::move(version)) - , PackageVersionCompat(std::move(versionCompat)) - , PackageVersionSchema(std::move(versionSchema)) - , DefaultTargets(std::move(defaultTargets)) - , DefaultConfigurations(std::move(defaultConfigurations)) + cmPackageInfoArguments arguments) + : PackageName(std::move(arguments.PackageName)) + , PackageVersion(std::move(arguments.Version)) + , PackageVersionCompat(std::move(arguments.VersionCompat)) + , PackageVersionSchema(std::move(arguments.VersionSchema)) + , DefaultTargets(std::move(arguments.DefaultTargets)) + , DefaultConfigurations(std::move(arguments.DefaultConfigs)) { } diff --git a/Source/cmExportPackageInfoGenerator.h b/Source/cmExportPackageInfoGenerator.h index 1392ba3ecf..1f849c9b67 100644 --- a/Source/cmExportPackageInfoGenerator.h +++ b/Source/cmExportPackageInfoGenerator.h @@ -15,11 +15,13 @@ #include "cmExportFileGenerator.h" #include "cmStateTypes.h" -class cmGeneratorTarget; namespace Json { class Value; } +class cmGeneratorTarget; +class cmPackageInfoArguments; + /** \class cmExportPackageInfoGenerator * \brief Generate Common Package Specification package information files * exporting targets from a build or install tree. @@ -32,11 +34,7 @@ class Value; class cmExportPackageInfoGenerator : virtual public cmExportFileGenerator { public: - cmExportPackageInfoGenerator(std::string packageName, std::string version, - std::string versionCompat, - std::string versionSchema, - std::vector defaultTargets, - std::vector defaultConfigurations); + cmExportPackageInfoGenerator(cmPackageInfoArguments arguments); using cmExportFileGenerator::GenerateImportFile; diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 48586dce8e..3573207588 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -45,6 +45,7 @@ #include "cmList.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmPackageInfoArguments.h" #include "cmPolicies.h" #include "cmRange.h" #include "cmRuntimeDependencyArchive.h" @@ -2174,26 +2175,12 @@ bool HandlePackageInfoMode(std::vector const& args, // This is the PACKAGE_INFO mode. cmInstallCommandArguments ica(helper.DefaultComponentName, *helper.Makefile); - ArgumentParser::NonEmpty pkg; - ArgumentParser::NonEmpty appendix; + cmPackageInfoArguments arguments; ArgumentParser::NonEmpty exportName; - bool lowerCase = false; - ArgumentParser::NonEmpty version; - ArgumentParser::NonEmpty versionCompat; - ArgumentParser::NonEmpty versionSchema; - ArgumentParser::NonEmpty> defaultTargets; - ArgumentParser::NonEmpty> defaultConfigs; ArgumentParser::NonEmpty cxxModulesDirectory; - ica.Bind("PACKAGE_INFO"_s, pkg); + arguments.Bind(ica); ica.Bind("EXPORT"_s, exportName); - ica.Bind("APPENDIX"_s, appendix); - ica.Bind("LOWER_CASE_FILE"_s, lowerCase); - ica.Bind("VERSION"_s, version); - ica.Bind("COMPAT_VERSION"_s, versionCompat); - ica.Bind("VERSION_SCHEMA"_s, versionSchema); - ica.Bind("DEFAULT_TARGETS"_s, defaultTargets); - ica.Bind("DEFAULT_CONFIGURATIONS"_s, defaultConfigs); // ica.Bind("CXX_MODULES_DIRECTORY"_s, cxxModulesDirectory); TODO? std::vector unknownArgs; @@ -2215,51 +2202,10 @@ bool HandlePackageInfoMode(std::vector const& args, return false; } - if (version.empty()) { - if (!versionCompat.empty()) { - status.SetError("COMPAT_VERSION requires VERSION."); - return false; - } - if (!versionSchema.empty()) { - status.SetError("VERSION_SCHEMA requires VERSION."); - return false; - } - } else { - if (!appendix.empty()) { - status.SetError("APPENDIX and VERSION are mutually exclusive."); - return false; - } - } - if (!appendix.empty()) { - if (!defaultTargets.empty()) { - status.SetError("APPENDIX and DEFAULT_TARGETS are mutually exclusive."); - return false; - } - if (!defaultConfigs.empty()) { - status.SetError("APPENDIX and DEFAULT_CONFIGURATIONS " - "are mutually exclusive."); - return false; - } - } - - // Validate the package name. - if (!cmGeneratorExpression::IsValidTargetName(pkg) || - pkg.find(':') != std::string::npos) { - status.SetError( - cmStrCat(args[0], " given invalid package name \"", pkg, "\".")); + if (!arguments.Check(status)) { return false; } - // Construct the case-normalized package name and the file name. - std::string const pkgNameOnDisk = - (lowerCase ? cmSystemTools::LowerCase(pkg) : pkg); - std::string pkgFileName = [&]() -> std::string { - if (appendix.empty()) { - return cmStrCat(pkgNameOnDisk, ".cps"); - } - return cmStrCat(pkgNameOnDisk, '-', appendix, ".cps"); - }(); - // Get or construct the destination path. std::string dest = ica.GetDestination(); if (dest.empty()) { @@ -2267,7 +2213,7 @@ bool HandlePackageInfoMode(std::vector const& args, dest = std::string{ "cps"_s }; } else { dest = cmStrCat(helper.GetLibraryDestination(nullptr), "/cps/", - pkgNameOnDisk); + arguments.GetPackageDirName()); } } @@ -2282,10 +2228,8 @@ bool HandlePackageInfoMode(std::vector const& args, cm::make_unique( &exportSet, dest, ica.GetPermissions(), ica.GetConfigurations(), ica.GetComponent(), message, ica.GetExcludeFromAll(), - std::move(pkgFileName), std::move(pkg), std::move(version), - std::move(versionCompat), std::move(versionSchema), - std::move(defaultTargets), std::move(defaultConfigs), - std::move(cxxModulesDirectory), helper.Makefile->GetBacktrace())); + std::move(arguments), std::move(cxxModulesDirectory), + helper.Makefile->GetBacktrace())); return true; #else diff --git a/Source/cmInstallPackageInfoExportGenerator.cxx b/Source/cmInstallPackageInfoExportGenerator.cxx index 756ef6a727..55dcbd100f 100644 --- a/Source/cmInstallPackageInfoExportGenerator.cxx +++ b/Source/cmInstallPackageInfoExportGenerator.cxx @@ -9,27 +9,23 @@ #include "cmExportInstallFileGenerator.h" #include "cmExportInstallPackageInfoGenerator.h" #include "cmListFileCache.h" +#include "cmPackageInfoArguments.h" class cmExportSet; cmInstallPackageInfoExportGenerator::cmInstallPackageInfoExportGenerator( cmExportSet* exportSet, std::string destination, std::string filePermissions, std::vector const& configurations, std::string component, - MessageLevel message, bool excludeFromAll, std::string filename, - std::string packageName, std::string version, std::string versionCompat, - std::string versionSchema, std::vector defaultTargets, - std::vector defaultConfigurations, + MessageLevel message, bool excludeFromAll, cmPackageInfoArguments arguments, std::string cxxModulesDirectory, cmListFileBacktrace backtrace) : cmInstallExportGenerator( exportSet, std::move(destination), std::move(filePermissions), configurations, std::move(component), message, excludeFromAll, - std::move(filename), packageName + "::", std::move(cxxModulesDirectory), - std::move(backtrace)) + arguments.GetPackageFileName(), arguments.GetNamespace(), + std::move(cxxModulesDirectory), std::move(backtrace)) { this->EFGen = cm::make_unique( - this, std::move(packageName), std::move(version), std::move(versionCompat), - std::move(versionSchema), std::move(defaultTargets), - std::move(defaultConfigurations)); + this, std::move(arguments)); } cmInstallPackageInfoExportGenerator::~cmInstallPackageInfoExportGenerator() = diff --git a/Source/cmInstallPackageInfoExportGenerator.h b/Source/cmInstallPackageInfoExportGenerator.h index a5413d91f8..0209f82ee6 100644 --- a/Source/cmInstallPackageInfoExportGenerator.h +++ b/Source/cmInstallPackageInfoExportGenerator.h @@ -9,6 +9,7 @@ class cmExportSet; class cmListFileBacktrace; +class cmPackageInfoArguments; /** \class cmInstallPackageInfoGenerator * \brief Generate rules for creating CPS package info files. @@ -20,11 +21,9 @@ public: cmExportSet* exportSet, std::string destination, std::string filePermissions, std::vector const& configurations, std::string component, - MessageLevel message, bool excludeFromAll, std::string filename, - std::string packageName, std::string version, std::string versionCompat, - std::string versionSchema, std::vector defaultTargets, - std::vector defaultConfigurations, - std::string cxxModulesDirectory, cmListFileBacktrace backtrace); + MessageLevel message, bool excludeFromAll, + cmPackageInfoArguments arguments, std::string cxxModulesDirectory, + cmListFileBacktrace backtrace); cmInstallPackageInfoExportGenerator( cmInstallPackageInfoExportGenerator const&) = delete; ~cmInstallPackageInfoExportGenerator() override; diff --git a/Source/cmPackageInfoArguments.cxx b/Source/cmPackageInfoArguments.cxx new file mode 100644 index 0000000000..5395c0e26f --- /dev/null +++ b/Source/cmPackageInfoArguments.cxx @@ -0,0 +1,104 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file LICENSE.rst or https://cmake.org/licensing for details. */ +#include "cmPackageInfoArguments.h" + +#include "cmExecutionStatus.h" +#include "cmGeneratorExpression.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +template void cmPackageInfoArguments::Bind(cmArgumentParser&, + cmPackageInfoArguments*); + +bool cmPackageInfoArguments::Check(cmExecutionStatus& status, + bool enable) const +{ + if (!enable) { + // Check if any options were given. + if (this->LowerCase) { + status.SetError("LOWER_CASE_FILE requires PACKAGE_INFO."); + return false; + } + if (!this->Appendix.empty()) { + status.SetError("APPENDIX requires PACKAGE_INFO."); + return false; + } + if (!this->Version.empty()) { + status.SetError("VERSION requires PACKAGE_INFO."); + return false; + } + if (!this->DefaultTargets.empty()) { + status.SetError("DEFAULT_TARGETS requires PACKAGE_INFO."); + return false; + } + if (!this->DefaultConfigs.empty()) { + status.SetError("DEFAULT_CONFIGURATIONS requires PACKAGE_INFO."); + return false; + } + } + + // Check for incompatible options. + if (!this->Appendix.empty()) { + if (!this->Version.empty()) { + status.SetError("APPENDIX and VERSION are mutually exclusive."); + return false; + } + if (!this->DefaultTargets.empty()) { + status.SetError("APPENDIX and DEFAULT_TARGETS " + "are mutually exclusive."); + return false; + } + if (!this->DefaultConfigs.empty()) { + status.SetError("APPENDIX and DEFAULT_CONFIGURATIONS " + "are mutually exclusive."); + return false; + } + } + + // Check for options that require other options. + if (this->Version.empty()) { + if (!this->VersionCompat.empty()) { + status.SetError("COMPAT_VERSION requires VERSION."); + return false; + } + if (!this->VersionSchema.empty()) { + status.SetError("VERSION_SCHEMA requires VERSION."); + return false; + } + } + + // Validate the package name. + if (!this->PackageName.empty()) { + if (!cmGeneratorExpression::IsValidTargetName(this->PackageName) || + this->PackageName.find(':') != std::string::npos) { + status.SetError( + cmStrCat(R"(PACKAGE_INFO given invalid package name ")"_s, + this->PackageName, R"(".)"_s)); + return false; + } + } + + return true; +} + +std::string cmPackageInfoArguments::GetNamespace() const +{ + return cmStrCat(this->PackageName, "::"_s); +} + +std::string cmPackageInfoArguments::GetPackageDirName() const +{ + if (this->LowerCase) { + return cmSystemTools::LowerCase(this->PackageName); + } + return this->PackageName; +} + +std::string cmPackageInfoArguments::GetPackageFileName() const +{ + std::string const pkgNameOnDisk = this->GetPackageDirName(); + if (!this->Appendix.empty()) { + return cmStrCat(pkgNameOnDisk, '-', this->Appendix, ".cps"_s); + } + return cmStrCat(pkgNameOnDisk, ".cps"_s); +} diff --git a/Source/cmPackageInfoArguments.h b/Source/cmPackageInfoArguments.h new file mode 100644 index 0000000000..0d1ee9c0aa --- /dev/null +++ b/Source/cmPackageInfoArguments.h @@ -0,0 +1,98 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file LICENSE.rst or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include +#include + +#include +#include + +#include "cmArgumentParser.h" // IWYU pragma: keep +#include "cmArgumentParserTypes.h" + +class cmExecutionStatus; + +/** \class cmPackageInfoArguments + * \brief Convey information about a package. + * + * This class encapsulates several attributes of package metadata. It is used + * both as a convenience container to convey several values in a single + * container, and also provides utilities to obtain this metadata from commands + * which produce packages (i.e. export and install). + */ +class cmPackageInfoArguments +{ +public: + template ::value>> + static void Bind(cmArgumentParser& parser) + { + cmPackageInfoArguments::Bind(parser, nullptr); + } + + void Bind(cmArgumentParser& parser) + { + cmPackageInfoArguments::Bind(parser, this); + } + + std::string GetNamespace() const; + std::string GetPackageDirName() const; + std::string GetPackageFileName() const; + + /// Ensure that no conflicting options were specified. If \p enable is + /// \c false, forbid specifying any options whatsoever. + bool Check(cmExecutionStatus& status, bool enable = true) const; + + ArgumentParser::NonEmpty PackageName; + ArgumentParser::NonEmpty Appendix; + ArgumentParser::NonEmpty Version; + ArgumentParser::NonEmpty VersionCompat; + ArgumentParser::NonEmpty VersionSchema; + ArgumentParser::NonEmpty> DefaultTargets; + ArgumentParser::NonEmpty> DefaultConfigs; + bool LowerCase = false; + +private: + template + static void Bind(cmArgumentParser& parser, cmPackageInfoArguments* self) + { + Bind(self, parser, "PACKAGE_INFO"_s, &cmPackageInfoArguments::PackageName); + Bind(self, parser, "LOWER_CASE_FILE"_s, + &cmPackageInfoArguments::LowerCase); + Bind(self, parser, "APPENDIX"_s, &cmPackageInfoArguments::Appendix); + Bind(self, parser, "VERSION"_s, &cmPackageInfoArguments::Version); + Bind(self, parser, "COMPAT_VERSION"_s, + &cmPackageInfoArguments::VersionCompat); + Bind(self, parser, "VERSION_SCHEMA"_s, + &cmPackageInfoArguments::VersionSchema); + Bind(self, parser, "DEFAULT_TARGETS"_s, + &cmPackageInfoArguments::DefaultTargets); + Bind(self, parser, "DEFAULT_CONFIGURATIONS"_s, + &cmPackageInfoArguments::DefaultConfigs); + } + + template ::value>> + static void Bind(cmPackageInfoArguments*, cmArgumentParser& parser, + cm::static_string_view name, + U cmPackageInfoArguments::*member) + { + parser.Bind(name, member); + } + + template + static void Bind(cmPackageInfoArguments* self, + cmArgumentParser& parser, cm::static_string_view name, + U cmPackageInfoArguments::*member) + { + parser.Bind(name, (self)->*member); + } +}; + +extern template void cmPackageInfoArguments::Bind( + cmArgumentParser&, cmPackageInfoArguments*);