Skip to content

Commit

Permalink
Helper to get version number from package.xml (#456)
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Jose Luis Rivero <[email protected]>
Co-authored-by: Jose Luis Rivero <[email protected]>
  • Loading branch information
scpeters and j-rivero authored Oct 29, 2024
1 parent 6e202b7 commit eb7226d
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 0 deletions.
1 change: 1 addition & 0 deletions cmake/GzCMake.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ include(GzPackaging)
include(GzCreateDocs)
include(GzSetCompilerFlags)
include(GzConfigureBuild)
include(GzGetPackageXmlVersion)
include(GzImportTarget)
include(GzPkgConfig)
include(GzSanitizers)
Expand Down
54 changes: 54 additions & 0 deletions cmake/GzGetPackageXmlVersion.cmake
Original file line number Diff line number Diff line change
@@ -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(<package_xml_path> <version_var_prefix>)
#
# Given the path to a package.xml file in <package_xml_path>,
# extract the version number and return the following variables
# prefixed by <version_var_prefix>:
# - <version_var_prefix>_VERSION: the full version number (Major.Minor.Patch)
# - <version_var_prefix>_VERSION_MAJOR: the major version number
# - <version_var_prefix>_VERSION_MINOR: the minor version number
# - <version_var_prefix>_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()
3 changes: 3 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
13 changes: 13 additions & 0 deletions examples/version_from_package_xml/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
32 changes: 32 additions & 0 deletions examples/version_from_package_xml/README.md
Original file line number Diff line number Diff line change
@@ -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
~~~
Empty file.
19 changes: 19 additions & 0 deletions examples/version_from_package_xml/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>version_from_package_xml</name>
<version>8.21.65</version>
<description>Test package for gz-cmake</description>

<maintainer email="[email protected]">Steve Peters</maintainer>

<license>Apache License 2.0</license>

<url type="website">https://github.com/gazebosim/gz-cmake</url>

<buildtool_depend>cmake</buildtool_depend>

<export>
<build_type>cmake</build_type>
</export>
</package>
3 changes: 3 additions & 0 deletions examples/version_from_package_xml/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

gz_create_core_library(INTERFACE)

Empty file.
41 changes: 41 additions & 0 deletions tools/print_package_xml_version.py
Original file line number Diff line number Diff line change
@@ -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 <package>' % root.tag)

if root.find('version') is None:
raise RuntimeError('Invalid package.xml file, no <version> 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='')

0 comments on commit eb7226d

Please sign in to comment.