From eb7226dee4c91a147b20c2c455e16010412fc390 Mon Sep 17 00:00:00 2001 From: Steve Peters Date: Tue, 29 Oct 2024 14:00:34 -0700 Subject: [PATCH] Helper to get version number from package.xml (#456) This adds a python script and a cmake helper function for getting the version number from a package.xml file. Signed-off-by: Steve Peters Signed-off-by: Jose Luis Rivero Co-authored-by: Jose Luis Rivero --- cmake/GzCMake.cmake | 1 + cmake/GzGetPackageXmlVersion.cmake | 54 +++++++++++++++++++ examples/CMakeLists.txt | 3 ++ .../version_from_package_xml/CMakeLists.txt | 13 +++++ examples/version_from_package_xml/README.md | 32 +++++++++++ .../include/CMakeLists.txt | 0 examples/version_from_package_xml/package.xml | 19 +++++++ .../src/CMakeLists.txt | 3 ++ .../test/CMakeLists.txt | 0 tools/print_package_xml_version.py | 41 ++++++++++++++ 10 files changed, 166 insertions(+) create mode 100644 cmake/GzGetPackageXmlVersion.cmake create mode 100644 examples/version_from_package_xml/CMakeLists.txt create mode 100644 examples/version_from_package_xml/README.md create mode 100644 examples/version_from_package_xml/include/CMakeLists.txt create mode 100644 examples/version_from_package_xml/package.xml create mode 100644 examples/version_from_package_xml/src/CMakeLists.txt create mode 100644 examples/version_from_package_xml/test/CMakeLists.txt create mode 100755 tools/print_package_xml_version.py diff --git a/cmake/GzCMake.cmake b/cmake/GzCMake.cmake index 1ad8506e..da2b6c27 100644 --- a/cmake/GzCMake.cmake +++ b/cmake/GzCMake.cmake @@ -28,6 +28,7 @@ include(GzPackaging) include(GzCreateDocs) include(GzSetCompilerFlags) include(GzConfigureBuild) +include(GzGetPackageXmlVersion) include(GzImportTarget) include(GzPkgConfig) include(GzSanitizers) diff --git a/cmake/GzGetPackageXmlVersion.cmake b/cmake/GzGetPackageXmlVersion.cmake new file mode 100644 index 00000000..b6be331e --- /dev/null +++ b/cmake/GzGetPackageXmlVersion.cmake @@ -0,0 +1,54 @@ +# Copyright (C) 2024 Open Source Robotics Foundation +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################# +# gz_get_package_xml_version( ) +# +# Given the path to a package.xml file in , +# extract the version number and return the following variables +# prefixed by : +# - _VERSION: the full version number (Major.Minor.Patch) +# - _VERSION_MAJOR: the major version number +# - _VERSION_MINOR: the minor version number +# - _VERSION_PATCH: the patch version number +function(gz_get_package_xml_version package_xml_path version_var_prefix) + + if(NOT Python3_Interpreter_FOUND) + find_package(Python3 COMPONENTS Interpreter REQUIRED) + endif() + execute_process( + COMMAND "${Python3_EXECUTABLE}" + "${GZ_CMAKE_TOOLS_DIR}/print_package_xml_version.py" + "${package_xml_path}" + OUTPUT_VARIABLE PACKAGE_XML_version + ERROR_VARIABLE PACKAGE_XML_error + RESULT_VARIABLE PACKAGE_XML_result) + if(NOT ${PACKAGE_XML_result} EQUAL 0) + message("") + message(FATAL_ERROR "Failed to parse version number from package.xml: ${PACKAGE_XML_error}") + endif() + # split version number into list of three numbers + string(REPLACE "." ";" PACKAGE_XML_version_list ${PACKAGE_XML_version}) + + # Create variables for major, minor, and patch version numbers + list(GET PACKAGE_XML_version_list 0 PACKAGE_XML_version_major) + list(GET PACKAGE_XML_version_list 1 PACKAGE_XML_version_minor) + list(GET PACKAGE_XML_version_list 2 PACKAGE_XML_version_patch) + + # Return variables for the full version number as well as major, minor, and patch version numbers + set(${version_var_prefix}_VERSION ${PACKAGE_XML_version} PARENT_SCOPE) + set(${version_var_prefix}_VERSION_MAJOR ${PACKAGE_XML_version_major} PARENT_SCOPE) + set(${version_var_prefix}_VERSION_MINOR ${PACKAGE_XML_version_minor} PARENT_SCOPE) + set(${version_var_prefix}_VERSION_PATCH ${PACKAGE_XML_version_patch} PARENT_SCOPE) + +endfunction() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index c6bc5880..6ec79e18 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -19,6 +19,7 @@ set(example_directories core_static_child comp_deps use_config_ifp + version_from_package_xml ) if (NOT CMAKE_GENERATOR MATCHES "Visual Studio") list(APPEND example_directories @@ -61,6 +62,8 @@ foreach(example ${example_directories}) set(example_tarball_name gz-use_component_depsc-0.1.0.tar.bz2) elseif (${example} STREQUAL "use_config_ifp") set(example_tarball_name gz-find_config-0.1.0.tar.bz2) + elseif (${example} STREQUAL "version_from_package_xml") + set(example_tarball_name gz-version_from_package_xml-8.21.65.tar.bz2) else() set(example_tarball_name) diff --git a/examples/version_from_package_xml/CMakeLists.txt b/examples/version_from_package_xml/CMakeLists.txt new file mode 100644 index 00000000..7900dc1e --- /dev/null +++ b/examples/version_from_package_xml/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.22.1 FATAL_ERROR) + +find_package(gz-cmake4 REQUIRED) +gz_get_package_xml_version(${CMAKE_SOURCE_DIR}/package.xml PACKAGE_XML) + +message(STATUS "PACKAGE_XML_VERSION ${PACKAGE_XML_VERSION}") +message(STATUS "PACKAGE_XML_VERSION_MAJOR ${PACKAGE_XML_VERSION_MAJOR}") +message(STATUS "PACKAGE_XML_VERSION_MINOR ${PACKAGE_XML_VERSION_MINOR}") +message(STATUS "PACKAGE_XML_VERSION_PATCH ${PACKAGE_XML_VERSION_PATCH}") + +project(gz-version_from_package_xml VERSION ${PACKAGE_XML_VERSION}) +gz_configure_project() +gz_configure_build(QUIT_IF_BUILD_ERRORS) diff --git a/examples/version_from_package_xml/README.md b/examples/version_from_package_xml/README.md new file mode 100644 index 00000000..a012d157 --- /dev/null +++ b/examples/version_from_package_xml/README.md @@ -0,0 +1,32 @@ +# version\_from\_package\_xml example + +## Getting a version number from package.xml file + +The package.xml file format (defined in +[ROS REP 127](https://ros.org/reps/rep-0127.html), +[ROS REP 140](https://ros.org/reps/rep-0140.html), and +[ROS REP 149](https://ros.org/reps/rep-0149.html)) +can be used to encode metadata about a package, including its version number. +This example shows how to use the `gz_get_package_xml_version` helper function +to get the version number from a package.xml file and use that to set the +cmake project version. + +The package.xml file in this folder encodes a version number `8.21.65`. +Configuring this example with cmake will parse the package.xml file and +print the cmake variables provided by the helper function. + +~~~ +mkdir build +cd build +cmake .. +~~~ + +You should see the following console output. + +~~~ +-- PACKAGE_XML_VERSION 8.21.65 +-- PACKAGE_XML_VERSION_MAJOR 8 +-- PACKAGE_XML_VERSION_MINOR 21 +-- PACKAGE_XML_VERSION_PATCH 65 +-- gz-version_from_package_xml version 8.21.65 +~~~ diff --git a/examples/version_from_package_xml/include/CMakeLists.txt b/examples/version_from_package_xml/include/CMakeLists.txt new file mode 100644 index 00000000..e69de29b diff --git a/examples/version_from_package_xml/package.xml b/examples/version_from_package_xml/package.xml new file mode 100644 index 00000000..81e69383 --- /dev/null +++ b/examples/version_from_package_xml/package.xml @@ -0,0 +1,19 @@ + + + + version_from_package_xml + 8.21.65 + Test package for gz-cmake + + Steve Peters + + Apache License 2.0 + + https://github.com/gazebosim/gz-cmake + + cmake + + + cmake + + diff --git a/examples/version_from_package_xml/src/CMakeLists.txt b/examples/version_from_package_xml/src/CMakeLists.txt new file mode 100644 index 00000000..abbf74b3 --- /dev/null +++ b/examples/version_from_package_xml/src/CMakeLists.txt @@ -0,0 +1,3 @@ + +gz_create_core_library(INTERFACE) + diff --git a/examples/version_from_package_xml/test/CMakeLists.txt b/examples/version_from_package_xml/test/CMakeLists.txt new file mode 100644 index 00000000..e69de29b diff --git a/tools/print_package_xml_version.py b/tools/print_package_xml_version.py new file mode 100755 index 00000000..c7eabf60 --- /dev/null +++ b/tools/print_package_xml_version.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# Copyright (C) 2024 Open Source Robotics Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License") +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re +import sys +from xml.etree import ElementTree as ET + +if len(sys.argv) != 2: + raise RuntimeError('Expected one argument with the path to a package.xml file') + +file_name = sys.argv[1] + +doc = ET.parse(file_name) +root = doc.getroot() +if root.tag != 'package': + raise RuntimeError('Invalid package.xml file, root tag <%s> should be ' % root.tag) + +if root.find('version') is None: + raise RuntimeError('Invalid package.xml file, no tag found.') + +version_str = root.find('version').text + +# validate version string using regex from catkin_pkg +# https://github.com/ros-infrastructure/catkin_pkg/blob/1.0.0/src/catkin_pkg/package_version.py#L55-L58 +match = re.match(r'^(\d+)\.(\d+)\.(\d+)$', version_str) +if match is None: + raise ValueError('Invalid version string, must be int.int.int: "%s"' % version_str) + +print(version_str, end='')