diff --git a/Source/cmExportBuildPackageInfoGenerator.cxx b/Source/cmExportBuildPackageInfoGenerator.cxx index a8546c0b13..29951d3e2e 100644 --- a/Source/cmExportBuildPackageInfoGenerator.cxx +++ b/Source/cmExportBuildPackageInfoGenerator.cxx @@ -32,7 +32,7 @@ bool cmExportBuildPackageInfoGenerator::GenerateMainFile(std::ostream& os) return false; } - if (!this->CheckDefaultTargets()) { + if (!this->CheckPackage()) { return false; } diff --git a/Source/cmExportInstallPackageInfoGenerator.cxx b/Source/cmExportInstallPackageInfoGenerator.cxx index 7fab8dc9de..66dd05fc91 100644 --- a/Source/cmExportInstallPackageInfoGenerator.cxx +++ b/Source/cmExportInstallPackageInfoGenerator.cxx @@ -66,7 +66,7 @@ bool cmExportInstallPackageInfoGenerator::GenerateMainFile(std::ostream& os) } } - if (!this->CheckDefaultTargets()) { + if (!this->CheckPackage()) { return false; } diff --git a/Source/cmExportPackageInfoGenerator.cxx b/Source/cmExportPackageInfoGenerator.cxx index d63b2d597c..a3ad46e82f 100644 --- a/Source/cmExportPackageInfoGenerator.cxx +++ b/Source/cmExportPackageInfoGenerator.cxx @@ -16,6 +16,8 @@ #include #include +#include "cmsys/RegularExpression.hxx" + #include "cmArgumentParserTypes.h" #include "cmExportSet.h" #include "cmFindPackageStack.h" @@ -88,6 +90,63 @@ void BuildArray(Json::Value& object, std::string const& property, } } } + +bool CheckSimpleVersion(std::string const& version) +{ + cmsys::RegularExpression regex("^[0-9]+([.][0-9]+)*([-+].*)?$"); + return regex.find(version); +} +} + +bool cmExportPackageInfoGenerator::CheckVersion() const +{ + if (!this->PackageVersion.empty()) { + std::string const& schema = [&] { + if (this->PackageVersionSchema.empty()) { + return std::string{ "simple" }; + } + return cmSystemTools::LowerCase(this->PackageVersionSchema); + }(); + bool (*validator)(std::string const&) = nullptr; + bool result = true; + + if (schema == "simple"_s) { + validator = &CheckSimpleVersion; + } else if (schema == "dpkg"_s || schema == "rpm"_s || + schema == "pep440"_s) { + // TODO + // We don't validate these at this time. Eventually, we would like to do + // so, but will probably need to introduce a policy whether to treat + // invalid versions as an error. + } else if (schema != "custom"_s) { + this->IssueMessage(MessageType::AUTHOR_WARNING, + cmStrCat("Package \""_s, this->GetPackageName(), + "\" uses unrecognized version schema \""_s, + this->PackageVersionSchema, "\"."_s)); + } + + if (validator) { + if (!(*validator)(this->PackageVersion)) { + this->ReportError(cmStrCat("Package \""_s, this->GetPackageName(), + "\" version \""_s, this->PackageVersion, + "\" does not conform to the \""_s, schema, + "\" schema."_s)); + result = false; + } + if (!this->PackageVersionCompat.empty() && + !(*validator)(this->PackageVersionCompat)) { + this->ReportError( + cmStrCat("Package \""_s, this->GetPackageName(), + "\" compatibility version \""_s, this->PackageVersionCompat, + "\" does not conform to the \""_s, schema, "\" schema."_s)); + result = false; + } + } + + return result; + } + + return true; } bool cmExportPackageInfoGenerator::CheckDefaultTargets() const diff --git a/Source/cmExportPackageInfoGenerator.h b/Source/cmExportPackageInfoGenerator.h index 0614e27f0a..8ef85fa000 100644 --- a/Source/cmExportPackageInfoGenerator.h +++ b/Source/cmExportPackageInfoGenerator.h @@ -47,7 +47,10 @@ protected: // Methods to implement export file code generation. bool GenerateImportFile(std::ostream& os) override; - bool CheckDefaultTargets() const; + bool CheckPackage() const + { + return this->CheckVersion() && this->CheckDefaultTargets(); + } Json::Value GeneratePackageInfo() const; Json::Value* GenerateImportTarget(Json::Value& components, @@ -82,6 +85,9 @@ protected: cmGeneratorTarget const* linkedTarget) override; private: + bool CheckVersion() const; + bool CheckDefaultTargets() const; + void GenerateInterfaceLinkProperties( bool& result, Json::Value& component, cmGeneratorTarget const* target, ImportPropertyMap const& properties) const; diff --git a/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake b/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake index b38ef80cc3..20a959a675 100644 --- a/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake +++ b/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake @@ -4,6 +4,10 @@ include(RunCMake) run_cmake(ExperimentalGate) run_cmake(ExperimentalWarning) +# Test version check author warning +# TODO Move to be with other tests when experimental gate is removed. +run_cmake(VersionCheckWarning) + # Enable experimental feature and suppress warnings set(RunCMake_TEST_OPTIONS -Wno-dev @@ -48,3 +52,6 @@ run_cmake(FileSetHeaders) run_cmake(DependencyVersionCMake) run_cmake(DependencyVersionCps) run_cmake(TransitiveSymbolicComponent) +run_cmake(VersionCheck) +# run_cmake(VersionCheckWarning) +run_cmake(VersionCheckError) diff --git a/Tests/RunCMake/ExportPackageInfo/VersionCheck.cmake b/Tests/RunCMake/ExportPackageInfo/VersionCheck.cmake new file mode 100644 index 0000000000..206b458584 --- /dev/null +++ b/Tests/RunCMake/ExportPackageInfo/VersionCheck.cmake @@ -0,0 +1,38 @@ +add_library(foo INTERFACE) +install(TARGETS foo EXPORT foo DESTINATION .) + +# Try exporting a 'properly' simple version. +export(EXPORT foo PACKAGE_INFO foo1 VERSION 1.2.3) + +# Try exporting a version with many components. +export(EXPORT foo PACKAGE_INFO foo2 VERSION 1.21.23.33.37.42.9.0.12) + +# Try exporting a version with a label. +export(EXPORT foo PACKAGE_INFO foo3 VERSION "1.2.3+git1234abcd") + +# Try exporting a version with a different label. +export(EXPORT foo PACKAGE_INFO foo4 VERSION "1.2.3-0.example") + +# Try exporting with the schema explicitly specified. +export( + EXPORT foo + PACKAGE_INFO foo5 + VERSION "1.2.3-0.example" + VERSION_SCHEMA "simple" +) + +# Try exporting with a custom-schema version. +export( + EXPORT foo + PACKAGE_INFO foo6 + VERSION "foo!test" + VERSION_SCHEMA "custom" +) + +# Try exporting with a recognized but not-checked schema. +export( + EXPORT foo + PACKAGE_INFO foo7 + VERSION "invalid" + VERSION_SCHEMA "pep440" +) diff --git a/Tests/RunCMake/ExportPackageInfo/VersionCheckError-result.txt b/Tests/RunCMake/ExportPackageInfo/VersionCheckError-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/ExportPackageInfo/VersionCheckError-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/ExportPackageInfo/VersionCheckError-stderr.txt b/Tests/RunCMake/ExportPackageInfo/VersionCheckError-stderr.txt new file mode 100644 index 0000000000..3321d78942 --- /dev/null +++ b/Tests/RunCMake/ExportPackageInfo/VersionCheckError-stderr.txt @@ -0,0 +1,2 @@ +CMake Error in CMakeLists\.txt: + Package "foo" version "1.2.3rc1" does not conform to the "simple" schema\. diff --git a/Tests/RunCMake/ExportPackageInfo/VersionCheckError.cmake b/Tests/RunCMake/ExportPackageInfo/VersionCheckError.cmake new file mode 100644 index 0000000000..1e766e6851 --- /dev/null +++ b/Tests/RunCMake/ExportPackageInfo/VersionCheckError.cmake @@ -0,0 +1,5 @@ +add_library(foo INTERFACE) +install(TARGETS foo EXPORT foo DESTINATION .) + +# Try exporting a non-conforming version. +export(EXPORT foo PACKAGE_INFO foo VERSION "1.2.3rc1") diff --git a/Tests/RunCMake/ExportPackageInfo/VersionCheckWarning-stderr.txt b/Tests/RunCMake/ExportPackageInfo/VersionCheckWarning-stderr.txt new file mode 100644 index 0000000000..0e833c2b52 --- /dev/null +++ b/Tests/RunCMake/ExportPackageInfo/VersionCheckWarning-stderr.txt @@ -0,0 +1,3 @@ +CMake Warning \(dev\) in CMakeLists\.txt: + Package "foo" uses unrecognized version schema "unrecognized"\. +This warning is for project developers\. Use -Wno-dev to suppress it\. diff --git a/Tests/RunCMake/ExportPackageInfo/VersionCheckWarning.cmake b/Tests/RunCMake/ExportPackageInfo/VersionCheckWarning.cmake new file mode 100644 index 0000000000..5a007e3343 --- /dev/null +++ b/Tests/RunCMake/ExportPackageInfo/VersionCheckWarning.cmake @@ -0,0 +1,15 @@ +set( + CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO + "b80be207-778e-46ba-8080-b23bba22639e" +) + +add_library(foo INTERFACE) +install(TARGETS foo EXPORT foo DESTINATION .) + +# Try exporting with an unrecognized schema. +export( + EXPORT foo + PACKAGE_INFO foo + VERSION "irrelevant" + VERSION_SCHEMA "unrecognized" +) diff --git a/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake b/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake index 9608f6b927..7636e81f8a 100644 --- a/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake +++ b/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake @@ -4,6 +4,10 @@ include(RunCMake) run_cmake(ExperimentalGate) run_cmake(ExperimentalWarning) +# Test version check author warning +# TODO Move to be with other tests when experimental gate is removed. +run_cmake(VersionCheckWarning) + # Enable experimental feature and suppress warnings set(RunCMake_TEST_OPTIONS -Wno-dev @@ -57,4 +61,7 @@ run_cmake(DependencyVersionCMake) run_cmake(DependencyVersionCps) run_cmake(TransitiveSymbolicComponent) run_cmake(InstallSymbolicComponent) +run_cmake(VersionCheck) +# run_cmake(VersionCheckWarning) +run_cmake(VersionCheckError) run_cmake_install(Destination) diff --git a/Tests/RunCMake/InstallPackageInfo/VersionCheck.cmake b/Tests/RunCMake/InstallPackageInfo/VersionCheck.cmake new file mode 100644 index 0000000000..13b638e19d --- /dev/null +++ b/Tests/RunCMake/InstallPackageInfo/VersionCheck.cmake @@ -0,0 +1,38 @@ +add_library(foo INTERFACE) +install(TARGETS foo EXPORT foo DESTINATION .) + +# Try exporting a 'properly' simple version. +install(PACKAGE_INFO foo1 EXPORT foo VERSION 1.2.3) + +# Try exporting a version with many components. +install(PACKAGE_INFO foo2 EXPORT foo VERSION 1.21.23.33.37.42.9.0.12) + +# Try exporting a version with a label. +install(PACKAGE_INFO foo3 EXPORT foo VERSION "1.2.3+git1234abcd") + +# Try exporting a version with a different label. +install(PACKAGE_INFO foo4 EXPORT foo VERSION "1.2.3-0.example") + +# Try exporting with the schema explicitly specified. +install( + PACKAGE_INFO foo5 + EXPORT foo + VERSION "1.2.3-0.example" + VERSION_SCHEMA "simple" +) + +# Try exporting with a custom-schema version. +install( + PACKAGE_INFO foo6 + EXPORT foo + VERSION "foo!test" + VERSION_SCHEMA "custom" +) + +# Try exporting with a recognized but not-checked schema. +install( + PACKAGE_INFO foo7 + EXPORT foo + VERSION "invalid" + VERSION_SCHEMA "pep440" +) diff --git a/Tests/RunCMake/InstallPackageInfo/VersionCheckError-result.txt b/Tests/RunCMake/InstallPackageInfo/VersionCheckError-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/InstallPackageInfo/VersionCheckError-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/InstallPackageInfo/VersionCheckError-stderr.txt b/Tests/RunCMake/InstallPackageInfo/VersionCheckError-stderr.txt new file mode 100644 index 0000000000..3321d78942 --- /dev/null +++ b/Tests/RunCMake/InstallPackageInfo/VersionCheckError-stderr.txt @@ -0,0 +1,2 @@ +CMake Error in CMakeLists\.txt: + Package "foo" version "1.2.3rc1" does not conform to the "simple" schema\. diff --git a/Tests/RunCMake/InstallPackageInfo/VersionCheckError.cmake b/Tests/RunCMake/InstallPackageInfo/VersionCheckError.cmake new file mode 100644 index 0000000000..2737f1c7ee --- /dev/null +++ b/Tests/RunCMake/InstallPackageInfo/VersionCheckError.cmake @@ -0,0 +1,5 @@ +add_library(foo INTERFACE) +install(TARGETS foo EXPORT foo DESTINATION .) + +# Try exporting a non-conforming version. +install(PACKAGE_INFO foo EXPORT foo VERSION "1.2.3rc1") diff --git a/Tests/RunCMake/InstallPackageInfo/VersionCheckWarning-stderr.txt b/Tests/RunCMake/InstallPackageInfo/VersionCheckWarning-stderr.txt new file mode 100644 index 0000000000..0e833c2b52 --- /dev/null +++ b/Tests/RunCMake/InstallPackageInfo/VersionCheckWarning-stderr.txt @@ -0,0 +1,3 @@ +CMake Warning \(dev\) in CMakeLists\.txt: + Package "foo" uses unrecognized version schema "unrecognized"\. +This warning is for project developers\. Use -Wno-dev to suppress it\. diff --git a/Tests/RunCMake/InstallPackageInfo/VersionCheckWarning.cmake b/Tests/RunCMake/InstallPackageInfo/VersionCheckWarning.cmake new file mode 100644 index 0000000000..3f5fa94d28 --- /dev/null +++ b/Tests/RunCMake/InstallPackageInfo/VersionCheckWarning.cmake @@ -0,0 +1,15 @@ +set( + CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO + "b80be207-778e-46ba-8080-b23bba22639e" +) + +add_library(foo INTERFACE) +install(TARGETS foo EXPORT foo DESTINATION .) + +# Try exporting with an unrecognized schema. +install( + PACKAGE_INFO foo + EXPORT foo + VERSION "irrelevant" + VERSION_SCHEMA "unrecognized" +)