Extending the catkin
command¶
The catkin
command is designed to be easily extendable using the setuptools
entry_points
interface without modifying the catkin_tools
project, itself.
Regardless of what package the entry_point
is defined in, it will be defined in the setup.py
of that package, and will take this form:
from setuptools import setup
setup(
...
entry_points={
...
'catkin_tools.commands.catkin.verbs': [
# Example from catkin_tools' setup.py:
# 'list = catkin_tools.verbs.catkin_list:description',
'my_verb = my_package.some.module:description',
],
},
)
This entry in the setup.py
places a file in the PYTHONPATH
when either the install
or the develop
verb is given to setup.py
.
This file relates the key (in this case my_verb
) to a module and attribute (in this case my_package.some.module
and description
).
Then the catkin
command will use the pkg_resources
modules to retrieve these mapping at run time.
Any entry for the catkin_tools.commands.catkin.verbs
group must point to a description
attribute of a module, where the description
attribute is a dict
.
The description
dict
should take this form (the description from the build
verb for example):
description = dict(
verb='build',
description="Builds a catkin workspace",
main=main,
prepare_arguments=prepare_arguments,
argument_preprocessor=argument_preprocessor,
)
This dict
defines all the information that the catkin
command needs to provide and execute your verb.
The verb
key takes a string which is the verb name (as shown in help and used for invoking the verb).
The description
key takes a string which is the description which is shown in the catkin -h
output.
The main
key takes a callable (function) which is called when the verb is invoked.
The signature of the main callable should be like this:
def main(opts):
# ...
return 0
Where the opts
parameter is the Namespace
object returns from ArgumentParser.parse_args(...)
and should return an exit code which is passed to sys.exit
.
The prepare_arguments
key takes a function with this signature:
def prepare_arguments(parser):
add = parser.add_argument
# What packages to build
add('packages', nargs='*',
help='Workspace packages to build, package dependencies are built as well unless --no-deps is used. '
'If no packages are given, then all the packages are built.')
add('--no-deps', action='store_true', default=False,
help='Only build specified packages, not their dependencies.')
return parser
The above example is a snippet from the build
verb’s prepare_arguments
function.
The purpose of this function is to take a given ArgumentParser
object, which was created by the catkin
command, and add this verb’s argparse
arguments to it and then return it.
Finally, the argument_preprocessor
command is an optional entry in the description
dict
which has this signature:
def argument_preprocessor(args):
"""Processes the arguments for the build verb, before being passed to argparse"""
# CMake/make pass-through flags collect dashed options. They require special
# handling or argparse will complain about unrecognized options.
args = sys.argv[1:] if args is None else args
extract_make_args = extract_cmake_and_make_and_catkin_make_arguments
args, cmake_args, make_args, catkin_make_args = extract_make_args(args)
# Extract make jobs flags.
jobs_flags = extract_jobs_flags(' '.join(args))
if jobs_flags:
args = re.sub(jobs_flags, '', ' '.join(args)).split()
jobs_flags = jobs_flags.split()
extras = {
'cmake_args': cmake_args,
'make_args': make_args + (jobs_flags or []),
'catkin_make_args': catkin_make_args,
}
return args, extras
The above example is the argument_preprocessor
function for the build
verb.
The purpose of the argument_preprocessor
callable is to allow the verb to preprocess its own arguments before they are passed to argparse
.
In the case of the build
verb, it is extracting the CMake and Make arguments before having them passed to argparse
.
The input parameter to this function is the list of arguments which come after the verb, and this function is only called when this verb has been detected as the first positional argument to the catkin
command.
So, you do not need to worry about making sure the arguments you just got are yours.
This function should return a tuple where the first item in the tuple is the potentially modified list of arguments, and the second item is a dictionary of keys and values which should be added as attributes to the opts
parameter which is later passed to the main
callable.
In this way you can take the arguments for your verb, parse them, remove some, add some or whatever, then you can additionally return extra information which needs to get passed around the argparse
parse_args
function.
Most verbs should not need to do this, and in fact the built-in list
verb’s description
dict
does not include one:
description = dict(
verb='list',
description="Lists catkin packages in a given folder",
main=main,
prepare_arguments=prepare_arguments,
)
Hopefully, this information will help you get started when you want to extend the catkin
command with custom verbs.