mirror of
https://github.com/Kitware/CMake.git
synced 2026-07-02 04:38:04 +00:00
cmPackageInfoArguments: Extract common values
Extract those values of cmPackageInfoArguments which are inherited from the project into a new base class. This will allow other users (SBOM support, in particular) to leverage the functionality of inheriting these values without duplicating code or needing to share the exact same value set.
This commit is contained in:
committed by
Taylor Sasser
parent
8c6676b2ea
commit
6d6c37c90d
@@ -430,6 +430,8 @@ add_library(
|
||||
cmProcessOutput.h
|
||||
cmProcessTools.cxx
|
||||
cmProcessTools.h
|
||||
cmProjectInfoArguments.cxx
|
||||
cmProjectInfoArguments.h
|
||||
cmValue.cxx
|
||||
cmValue.h
|
||||
cmProperty.h
|
||||
|
||||
@@ -2,35 +2,20 @@
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#include "cmPackageInfoArguments.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <cm/string_view>
|
||||
|
||||
#include "cmExecutionStatus.h"
|
||||
#include "cmGeneratorExpression.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmStateSnapshot.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmValue.h"
|
||||
|
||||
template void cmPackageInfoArguments::Bind<void>(cmArgumentParser<void>&,
|
||||
cmPackageInfoArguments*);
|
||||
|
||||
namespace {
|
||||
|
||||
bool ArgWasSpecified(std::string const& value)
|
||||
cm::string_view cmPackageInfoArguments::CommandName() const
|
||||
{
|
||||
return !value.empty();
|
||||
return "PACKAGE_INFO"_s;
|
||||
}
|
||||
|
||||
bool ArgWasSpecified(std::vector<std::string> const& value)
|
||||
{
|
||||
return !value.empty();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
#define ENFORCE_REQUIRES(req, value, arg) \
|
||||
do { \
|
||||
if (ArgWasSpecified(value)) { \
|
||||
@@ -60,9 +45,6 @@ bool cmPackageInfoArguments::Check(cmExecutionStatus& status) const
|
||||
"DEFAULT_CONFIGURATIONS");
|
||||
ENFORCE_EXCLUSIVE("APPENDIX", this->ProjectName, "PROJECT");
|
||||
}
|
||||
if (this->NoProjectDefaults) {
|
||||
ENFORCE_EXCLUSIVE("PROJECT", this->ProjectName, "NO_PROJECT_METADATA");
|
||||
}
|
||||
|
||||
// Check for options that require other options.
|
||||
if (this->Version.empty()) {
|
||||
@@ -70,67 +52,12 @@ bool cmPackageInfoArguments::Check(cmExecutionStatus& status) const
|
||||
ENFORCE_REQUIRES("VERSION", this->VersionSchema, "VERSION_SCHEMA");
|
||||
}
|
||||
|
||||
// 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;
|
||||
return cmProjectInfoArguments::Check(status);
|
||||
}
|
||||
|
||||
#undef ENFORCE_REQUIRES
|
||||
#undef ENFORCE_EXCLUSIVE
|
||||
|
||||
bool cmPackageInfoArguments::SetMetadataFromProject(cmExecutionStatus& status)
|
||||
{
|
||||
// Determine what project to use for inherited metadata.
|
||||
if (!this->SetEffectiveProject(status)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->ProjectName.empty()) {
|
||||
// We are not inheriting from a project.
|
||||
return true;
|
||||
}
|
||||
|
||||
cmMakefile& mf = status.GetMakefile();
|
||||
auto mapProjectValue = [&](std::string& arg, cm::string_view suffix) {
|
||||
cmValue const& projectValue =
|
||||
mf.GetDefinition(cmStrCat(this->ProjectName, '_', suffix));
|
||||
if (projectValue) {
|
||||
arg = *projectValue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (this->Version.empty()) {
|
||||
if (mapProjectValue(this->Version, "VERSION"_s)) {
|
||||
mapProjectValue(this->VersionCompat, "COMPAT_VERSION"_s);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->License.empty()) {
|
||||
mapProjectValue(this->License, "SPDX_LICENSE"_s);
|
||||
}
|
||||
|
||||
if (this->Description.empty()) {
|
||||
mapProjectValue(this->Description, "DESCRIPTION"_s);
|
||||
}
|
||||
|
||||
if (this->Website.empty()) {
|
||||
mapProjectValue(this->Website, "HOMEPAGE_URL"_s);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmPackageInfoArguments::SetEffectiveProject(cmExecutionStatus& status)
|
||||
{
|
||||
if (!this->Appendix.empty()) {
|
||||
@@ -138,28 +65,7 @@ bool cmPackageInfoArguments::SetEffectiveProject(cmExecutionStatus& status)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this->NoProjectDefaults) {
|
||||
// User requested that metadata not be inherited.
|
||||
return true;
|
||||
}
|
||||
|
||||
cmMakefile& mf = status.GetMakefile();
|
||||
if (!this->ProjectName.empty()) {
|
||||
// User specified a project; make sure it exists.
|
||||
if (!mf.GetStateSnapshot().CheckProjectName(this->ProjectName)) {
|
||||
status.SetError(cmStrCat(R"(PROJECT given unknown project name ")"_s,
|
||||
this->ProjectName, R"(".)"_s));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// No project was specified; check if the package name is also a project.
|
||||
std::string project = mf.GetStateSnapshot().GetProjectName();
|
||||
if (this->PackageName == project) {
|
||||
this->ProjectName = std::move(project);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return cmProjectInfoArguments::SetEffectiveProject(status);
|
||||
}
|
||||
|
||||
std::string cmPackageInfoArguments::GetNamespace() const
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/string_view>
|
||||
#include <cm/type_traits>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include "cmArgumentParser.h" // IWYU pragma: keep
|
||||
#include "cmArgumentParserTypes.h"
|
||||
|
||||
class cmExecutionStatus;
|
||||
#include "cmProjectInfoArguments.h"
|
||||
|
||||
/** \class cmPackageInfoArguments
|
||||
* \brief Convey information about a package.
|
||||
@@ -23,7 +23,7 @@ class cmExecutionStatus;
|
||||
* container, and also provides utilities to obtain this metadata from commands
|
||||
* which produce packages (i.e. export and install).
|
||||
*/
|
||||
class cmPackageInfoArguments
|
||||
class cmPackageInfoArguments : public cmProjectInfoArguments
|
||||
{
|
||||
public:
|
||||
template <typename T,
|
||||
@@ -31,7 +31,8 @@ public:
|
||||
std::is_base_of<cmPackageInfoArguments, T>::value>>
|
||||
static void Bind(cmArgumentParser<T>& parser)
|
||||
{
|
||||
cmPackageInfoArguments::Bind(parser, nullptr);
|
||||
cmPackageInfoArguments* const self = nullptr;
|
||||
cmPackageInfoArguments::Bind(parser, self);
|
||||
}
|
||||
|
||||
void Bind(cmArgumentParser<void>& parser)
|
||||
@@ -43,76 +44,50 @@ public:
|
||||
std::string GetPackageDirName() const;
|
||||
std::string GetPackageFileName() const;
|
||||
|
||||
/// Ensure that no conflicting options were specified.
|
||||
bool Check(cmExecutionStatus& status) const;
|
||||
bool Check(cmExecutionStatus& status) const override;
|
||||
|
||||
/// Set metadata (not already specified) from either the specified project,
|
||||
/// or from the project which matches the package name.
|
||||
bool SetMetadataFromProject(cmExecutionStatus& status);
|
||||
|
||||
ArgumentParser::NonEmpty<std::string> PackageName;
|
||||
ArgumentParser::NonEmpty<std::string> Appendix;
|
||||
ArgumentParser::NonEmpty<std::string> Version;
|
||||
ArgumentParser::NonEmpty<std::string> VersionCompat;
|
||||
ArgumentParser::NonEmpty<std::string> VersionSchema;
|
||||
ArgumentParser::NonEmpty<std::string> License;
|
||||
ArgumentParser::NonEmpty<std::string> DefaultLicense;
|
||||
ArgumentParser::NonEmpty<std::string> Description;
|
||||
ArgumentParser::NonEmpty<std::string> Website;
|
||||
ArgumentParser::NonEmpty<std::vector<std::string>> DefaultTargets;
|
||||
ArgumentParser::NonEmpty<std::vector<std::string>> DefaultConfigs;
|
||||
bool LowerCase = false;
|
||||
|
||||
ArgumentParser::NonEmpty<std::string> ProjectName;
|
||||
bool NoProjectDefaults = false;
|
||||
protected:
|
||||
cm::string_view CommandName() const override;
|
||||
|
||||
private:
|
||||
bool SetEffectiveProject(cmExecutionStatus& status);
|
||||
bool SetEffectiveProject(cmExecutionStatus& status) override;
|
||||
|
||||
template <typename T>
|
||||
static void Bind(cmArgumentParser<T>& parser, cmPackageInfoArguments* self)
|
||||
{
|
||||
Bind(self, parser, "PACKAGE_INFO"_s, &cmPackageInfoArguments::PackageName);
|
||||
cmProjectInfoArguments* const base = self;
|
||||
|
||||
Bind(base, parser, "PACKAGE_INFO"_s, &cmProjectInfoArguments::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(base, parser, "COMPAT_VERSION"_s,
|
||||
&cmProjectInfoArguments::VersionCompat);
|
||||
Bind(base, parser, "VERSION_SCHEMA"_s,
|
||||
&cmProjectInfoArguments::VersionSchema);
|
||||
Bind(self, parser, "DEFAULT_TARGETS"_s,
|
||||
&cmPackageInfoArguments::DefaultTargets);
|
||||
Bind(self, parser, "DEFAULT_CONFIGURATIONS"_s,
|
||||
&cmPackageInfoArguments::DefaultConfigs);
|
||||
Bind(self, parser, "LICENSE"_s, &cmPackageInfoArguments::License);
|
||||
Bind(self, parser, "DEFAULT_LICENSE"_s,
|
||||
&cmPackageInfoArguments::DefaultLicense);
|
||||
Bind(self, parser, "DESCRIPTION"_s, &cmPackageInfoArguments::Description);
|
||||
Bind(self, parser, "HOMEPAGE_URL"_s, &cmPackageInfoArguments::Website);
|
||||
|
||||
Bind(self, parser, "PROJECT"_s, &cmPackageInfoArguments::ProjectName);
|
||||
Bind(self, parser, "NO_PROJECT_METADATA"_s,
|
||||
&cmPackageInfoArguments::NoProjectDefaults);
|
||||
cmProjectInfoArguments::Bind(parser, self);
|
||||
}
|
||||
|
||||
template <typename T, typename U,
|
||||
typename = cm::enable_if_t<
|
||||
std::is_base_of<cmPackageInfoArguments, T>::value>>
|
||||
static void Bind(cmPackageInfoArguments*, cmArgumentParser<T>& parser,
|
||||
cm::static_string_view name,
|
||||
U cmPackageInfoArguments::*member)
|
||||
using cmProjectInfoArguments::Bind;
|
||||
|
||||
static bool ArgWasSpecified(std::vector<std::string> const& value)
|
||||
{
|
||||
parser.Bind(name, member);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static void Bind(cmPackageInfoArguments* self,
|
||||
cmArgumentParser<void>& parser, cm::static_string_view name,
|
||||
U cmPackageInfoArguments::*member)
|
||||
{
|
||||
parser.Bind(name, (self)->*member);
|
||||
return !value.empty();
|
||||
}
|
||||
using cmProjectInfoArguments::ArgWasSpecified;
|
||||
};
|
||||
|
||||
extern template void cmPackageInfoArguments::Bind<void>(
|
||||
|
||||
129
Source/cmProjectInfoArguments.cxx
Normal file
129
Source/cmProjectInfoArguments.cxx
Normal file
@@ -0,0 +1,129 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#include "cmProjectInfoArguments.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <cm/string_view>
|
||||
|
||||
#include "cmExecutionStatus.h"
|
||||
#include "cmGeneratorExpression.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmStateSnapshot.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmValue.h"
|
||||
|
||||
template void cmProjectInfoArguments::Bind<void>(cmArgumentParser<void>&,
|
||||
cmProjectInfoArguments*);
|
||||
|
||||
#define ENFORCE_REQUIRES(req, value, arg) \
|
||||
do { \
|
||||
if (ArgWasSpecified(value)) { \
|
||||
status.SetError(arg " requires " req "."); \
|
||||
return false; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define ENFORCE_EXCLUSIVE(arg1, value, arg2) \
|
||||
do { \
|
||||
if (ArgWasSpecified(value)) { \
|
||||
status.SetError(arg1 " and " arg2 " are mutually exclusive."); \
|
||||
return false; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
cmProjectInfoArguments::cmProjectInfoArguments() = default;
|
||||
|
||||
bool cmProjectInfoArguments::Check(cmExecutionStatus& status) const
|
||||
{
|
||||
// Check for incompatible options.
|
||||
if (this->NoProjectDefaults) {
|
||||
ENFORCE_EXCLUSIVE("PROJECT", this->ProjectName, "NO_PROJECT_METADATA");
|
||||
}
|
||||
|
||||
// Validate the package name.
|
||||
if (!this->PackageName.empty()) {
|
||||
if (!cmGeneratorExpression::IsValidTargetName(this->PackageName) ||
|
||||
this->PackageName.find(':') != std::string::npos) {
|
||||
status.SetError(cmStrCat(this->CommandName(),
|
||||
" given invalid package name \""_s,
|
||||
this->PackageName, "\"."_s));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef ENFORCE_REQUIRES
|
||||
#undef ENFORCE_EXCLUSIVE
|
||||
|
||||
bool cmProjectInfoArguments::SetMetadataFromProject(cmExecutionStatus& status)
|
||||
{
|
||||
// Determine what project to use for inherited metadata.
|
||||
if (!this->SetEffectiveProject(status)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->ProjectName.empty()) {
|
||||
// We are not inheriting from a project.
|
||||
return true;
|
||||
}
|
||||
|
||||
cmMakefile& mf = status.GetMakefile();
|
||||
auto mapProjectValue = [&](std::string& arg, cm::string_view suffix) {
|
||||
cmValue const& projectValue =
|
||||
mf.GetDefinition(cmStrCat(this->ProjectName, '_', suffix));
|
||||
if (projectValue) {
|
||||
arg = *projectValue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (this->Version.empty()) {
|
||||
if (mapProjectValue(this->Version, "VERSION"_s)) {
|
||||
mapProjectValue(this->VersionCompat, "COMPAT_VERSION"_s);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->License.empty()) {
|
||||
mapProjectValue(this->License, "SPDX_LICENSE"_s);
|
||||
}
|
||||
|
||||
if (this->Description.empty()) {
|
||||
mapProjectValue(this->Description, "DESCRIPTION"_s);
|
||||
}
|
||||
|
||||
if (this->Website.empty()) {
|
||||
mapProjectValue(this->Website, "HOMEPAGE_URL"_s);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmProjectInfoArguments::SetEffectiveProject(cmExecutionStatus& status)
|
||||
{
|
||||
if (this->NoProjectDefaults) {
|
||||
// User requested that metadata not be inherited.
|
||||
return true;
|
||||
}
|
||||
|
||||
cmMakefile& mf = status.GetMakefile();
|
||||
if (!this->ProjectName.empty()) {
|
||||
// User specified a project; make sure it exists.
|
||||
if (!mf.GetStateSnapshot().CheckProjectName(this->ProjectName)) {
|
||||
status.SetError(cmStrCat(R"(PROJECT given unknown project name ")"_s,
|
||||
this->ProjectName, R"(".)"_s));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// No project was specified; check if the package name is also a project.
|
||||
std::string project = mf.GetStateSnapshot().GetProjectName();
|
||||
if (this->PackageName == project) {
|
||||
this->ProjectName = std::move(project);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
103
Source/cmProjectInfoArguments.h
Normal file
103
Source/cmProjectInfoArguments.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/* 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 <string>
|
||||
|
||||
#include <cm/string_view>
|
||||
#include <cm/type_traits>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include "cmArgumentParser.h" // IWYU pragma: keep
|
||||
#include "cmArgumentParserTypes.h"
|
||||
|
||||
class cmExecutionStatus;
|
||||
|
||||
/** \class cmProjectInfoArguments
|
||||
* \brief Convey information about a project.
|
||||
*
|
||||
* This class encapsulates several attributes of project metadata;
|
||||
* specifically, those which can be inherited from the project. It is used as
|
||||
* the base class for classes specific to SBOM and PACKAGE_INFO exports.
|
||||
*/
|
||||
class cmProjectInfoArguments
|
||||
{
|
||||
public:
|
||||
cmProjectInfoArguments();
|
||||
cmProjectInfoArguments(cmProjectInfoArguments const&) = default;
|
||||
cmProjectInfoArguments& operator=(cmProjectInfoArguments const&) = default;
|
||||
cmProjectInfoArguments(cmProjectInfoArguments&&) = default;
|
||||
cmProjectInfoArguments& operator=(cmProjectInfoArguments&&) = default;
|
||||
|
||||
virtual ~cmProjectInfoArguments() = default;
|
||||
|
||||
/// Ensure that no conflicting options were specified.
|
||||
virtual bool Check(cmExecutionStatus& status) const;
|
||||
|
||||
/// Set metadata (not already specified) from either the specified project,
|
||||
/// or from the project which matches the package name.
|
||||
bool SetMetadataFromProject(cmExecutionStatus& status);
|
||||
|
||||
ArgumentParser::NonEmpty<std::string> PackageName;
|
||||
ArgumentParser::NonEmpty<std::string> Version;
|
||||
ArgumentParser::NonEmpty<std::string> VersionCompat;
|
||||
ArgumentParser::NonEmpty<std::string> VersionSchema;
|
||||
ArgumentParser::NonEmpty<std::string> License;
|
||||
ArgumentParser::NonEmpty<std::string> Description;
|
||||
ArgumentParser::NonEmpty<std::string> Website;
|
||||
|
||||
ArgumentParser::NonEmpty<std::string> ProjectName;
|
||||
bool NoProjectDefaults = false;
|
||||
|
||||
protected:
|
||||
virtual cm::string_view CommandName() const = 0;
|
||||
|
||||
virtual bool SetEffectiveProject(cmExecutionStatus& status);
|
||||
|
||||
template <typename T>
|
||||
static void Bind(cmArgumentParser<T>& parser, cmProjectInfoArguments* self)
|
||||
{
|
||||
Bind(self, parser, "VERSION"_s, &cmProjectInfoArguments::Version);
|
||||
Bind(self, parser, "LICENSE"_s, &cmProjectInfoArguments::License);
|
||||
Bind(self, parser, "DESCRIPTION"_s, &cmProjectInfoArguments::Description);
|
||||
Bind(self, parser, "HOMEPAGE_URL"_s, &cmProjectInfoArguments::Website);
|
||||
|
||||
Bind(self, parser, "PROJECT"_s, &cmProjectInfoArguments::ProjectName);
|
||||
Bind(self, parser, "NO_PROJECT_METADATA"_s,
|
||||
&cmProjectInfoArguments::NoProjectDefaults);
|
||||
}
|
||||
|
||||
template <
|
||||
typename Self, typename T, typename U,
|
||||
typename =
|
||||
cm::enable_if_t<std::is_base_of<cmProjectInfoArguments, Self>::value>,
|
||||
typename =
|
||||
cm::enable_if_t<std::is_base_of<cmProjectInfoArguments, T>::value>>
|
||||
static void Bind(Self*, cmArgumentParser<T>& parser,
|
||||
cm::static_string_view name, U Self::*member)
|
||||
{
|
||||
parser.Bind(name, member);
|
||||
}
|
||||
|
||||
template <
|
||||
typename Self, typename T, typename U,
|
||||
typename =
|
||||
cm::enable_if_t<std::is_base_of<cmProjectInfoArguments, Self>::value>,
|
||||
typename =
|
||||
cm::enable_if_t<std::is_base_of<cmProjectInfoArguments, T>::value>>
|
||||
static void Bind(Self* self, cmArgumentParser<void>& parser,
|
||||
cm::static_string_view name, U T::*member)
|
||||
{
|
||||
parser.Bind(name, (self)->*member);
|
||||
}
|
||||
|
||||
static bool ArgWasSpecified(std::string const& value)
|
||||
{
|
||||
return !value.empty();
|
||||
}
|
||||
};
|
||||
|
||||
extern template void cmProjectInfoArguments::Bind<void>(
|
||||
cmArgumentParser<void>&, cmProjectInfoArguments*);
|
||||
Reference in New Issue
Block a user