# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*## Copyright 2026 Canonical Ltd.## This program is free software; you can redistribute it and/or# modify it under the terms of the GNU Lesser General Public# License version 3 as published by the Free Software Foundation.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU# Lesser General Public License for more details.## You should have received a copy of the GNU Lesser General Public License# along with this program. If not, see <http://www.gnu.org/licenses/>."""The colcon plugin implementation."""importpathlibfromtypingimportLiteral,castfromtyping_extensionsimportoverridefrom.baseimportPluginfrom.propertiesimportPluginProperties
[docs]classColconPluginProperties(PluginProperties,frozen=True):"""The part properties used by the colcon plugin."""plugin:Literal["colcon"]="colcon"colcon_cmake_args:list[str]=[]colcon_packages:list[str]=[]colcon_packages_ignore:list[str]=[]# part properties required by the pluginsource:str# type: ignore[reportGeneralTypeIssues]
[docs]classColconPlugin(Plugin):"""A plugin useful for building colcon-based parts."""properties_class=ColconPluginProperties
[docs]@overridedefget_build_snaps(self)->set[str]:"""Return a set of required snaps to install in the build environment."""returnset()
[docs]@overridedefget_build_packages(self)->set[str]:"""Return a set of required packages to install in the build environment."""return{"gcc","g++","cmake","colcon","python3-colcon-core","python3-colcon-cmake","python3-colcon-package-selection","python3-colcon-python-setup-py","python3-colcon-parallel-executor",}
[docs]@overridedefget_build_environment(self)->dict[str,str]:"""Return a dictionary with the environment to use in the build step."""return{"AMENT_PYTHON_EXECUTABLE":"/usr/bin/python3","COLCON_PYTHON_EXECUTABLE":"/usr/bin/python3",}
def_get_source_command(self,path:str)->list[str]:"""Return the command to source the environment for the colcon plugin. Child classes that need to override this could extend or override the returned list. """return[f'if [ -n "${{ROS_DISTRO:-}}" ] && [ -f "{path}/opt/ros/${{ROS_DISTRO:-}}/local_setup.sh" ]; then','AMENT_CURRENT_PREFIX="{wspath}" . "{wspath}/local_setup.sh"'.format(wspath=f"{path}/opt/ros/${{ROS_DISTRO:-}}"),"fi",]def_get_workspace_activation_commands(self)->list[str]:"""Return a list of commands to source a colcon workspace."""activation_commands:list[str]=[]## Source colcon ws in stage-snaps nextactivation_commands.append("##[craft-parts.colcon] Sourcing colcon ws in stage snaps")activation_commands.extend(self._get_source_command("${CRAFT_PART_INSTALL}"))activation_commands.append("")activation_commands.append("##[craft-parts.colcon] Sourcing the colcon workspace")activation_commands.extend(self._get_source_command(""))activation_commands.append("")returnactivation_commands
[docs]@overridedefget_build_commands(self)->list[str]:"""Return a list of commands to run during the build step."""returnself._get_workspace_activation_commands()+self._get_build_commands()
def_get_build_commands(self)->list[str]:options=cast(ColconPluginProperties,self._options)build_command=["colcon","build","--base-paths",f'"{self._part_info.part_src_dir}"',"--build-base",f'"{self._part_info.part_build_dir}"',"--merge-install","--install-base",self._get_install_path().as_posix(),]ifoptions.colcon_packages_ignore:build_command.extend(["--packages-ignore",*options.colcon_packages_ignore])ifoptions.colcon_packages:build_command.extend(["--packages-select",*options.colcon_packages])# compile in release only if user did not set the build type in cmake-argsifnotany("-DCMAKE_BUILD_TYPE="insforsinoptions.colcon_cmake_args):build_command.extend(["--cmake-args","-DCMAKE_BUILD_TYPE=Release",*options.colcon_cmake_args,])eliflen(options.colcon_cmake_args)>0:build_command.extend(["--cmake-args",*options.colcon_cmake_args])# Specify the number of workersbuild_command.extend(["--parallel-workers",f"{self._part_info.parallel_build_count}"])return[" ".join(build_command)]def_get_install_path(self)->pathlib.Path:"""Return the install path for the colcon plugin. Child classes that need to override this should extend the returned path. """returnpathlib.Path(self._part_info.part_install_dir)