tests: add fake pip fixture #1558

Closed
wants to merge 1 commit into
from
Jump to file or symbol
Failed to load files and symbols.
+584 −2
Split
View
@@ -2,6 +2,7 @@ docs/reference.md
demos/*/parts/
demos/*/prime/
demos/*/stage/
+demos/*/snap/.snapcraft/
demos/**/*.snap
snap/.snapcraft/
tests/unit/parts/
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# The launch file doesn't properly interleave output like we need here. So
+# script it instead.
+
+ros2 run talker_cpp talker &
+ros2 run listener_py listener
@@ -0,0 +1,29 @@
+name: ros2-example
+version: '0.1' # just for humans, typically '1.2+git' or '1.3.2'
+summary: Single-line elevator pitch for your amazing snap # 79 char long summary
+description: |
+ This is my-snap's description. You have a paragraph or two to tell the
+ most important story about your snap. Keep it under 100 words though,
+ we live in tweetspace and your description wants to look good in the snap
+ store.
+
+grade: devel # must be 'stable' to release into candidate/stable channels
+confinement: strict
+
+apps:
+ ros2:
+ command: ros2
+ plugs: [network]
+
+ launch-system:
+ command: launch-system
+ plugs: [network]
+
+parts:
+ my-part:
+ # See 'snapcraft plugins'
+ plugin: ament
+
+ scripts:
+ plugin: dump
+ source: scripts
@@ -0,0 +1,15 @@
+from ros2run.api import get_executable_path
+
+
+def launch(launch_descriptor, argv):
+ ld = launch_descriptor
+ ld.add_process(
+ cmd=[get_executable_path(package_name='talker_cpp', executable_name='talker')],
+ name='talker',
+ )
+ ld.add_process(
+ cmd=[get_executable_path(package_name='listener_py', executable_name='listener')],
+ name='listener',
+ )
+
+ return ld
@@ -0,0 +1,23 @@
+import rclpy
+from std_msgs.msg import String
+
+
+def callback(message):
+ print('I heard: {}'.format(message.data))
+
+
+def main():
+ rclpy.init()
+
+ node = rclpy.Node('listener')
+
+ node.create_subscription(String, 'chatter', callback)
+
+ rclpy.spin(node)
+
+ node.destroy_node()
+ rclpy.shutdown()
+
+
+if __name__ == '__main__':
+ main()
@@ -0,0 +1,16 @@
+<?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>listener_py</name>
+ <version>0.0.0</version>
+ <description>The listener_py package</description>
+ <maintainer email="me@example.com">me</maintainer>
+ <license>GPLv3</license>
+
+ <exec_depend>rclpy</exec_depend>
+ <exec_depend>std_msgs</exec_depend>
+
+ <export>
+ <build_type>ament_python</build_type>
+ </export>
+</package>
@@ -0,0 +1,4 @@
+[develop]
+script-dir=$base/lib/listener_py
+[install]
+install-scripts=$base/lib/listener_py
@@ -0,0 +1,21 @@
+import os
+from setuptools import find_packages
+from setuptools import setup
+
+package_name = 'listener_py'
+
+setup(
+ name=package_name,
+ version='0.0.0',
+ packages=find_packages(),
+ data_files=[
+ (os.path.join('share', package_name), ['package.xml']),
+ (os.path.join('share', package_name, 'launch'), ['launch/talk_and_listen.py']),
+ ],
+ install_requires=['setuptools'],
+ entry_points={
+ 'console_scripts': [
+ 'listener = nodes.listener:main',
+ ],
+ },
+)
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.5)
+
+project(talker_cpp)
+
+find_package(ament_cmake REQUIRED)
+find_package(rclcpp REQUIRED)
+#find_package(rmw REQUIRED)
+find_package(std_msgs REQUIRED)
+
+add_definitions("-std=c++11 -Wall -Wextra")
+
+add_executable(talker src/talker.cpp)
+ament_target_dependencies(talker
+ "rclcpp"
+ "std_msgs")
+install(TARGETS talker DESTINATION lib/${PROJECT_NAME})
+
+ament_package()
@@ -0,0 +1,21 @@
+<?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>talker_cpp</name>
+ <version>0.0.0</version>
+ <description>The talker_cpp package</description>
+ <maintainer email="me@example.com">me</maintainer>
+ <license>GPLv3</license>
+
+ <buildtool_depend>ament_cmake</buildtool_depend>
+
+ <build_depend>rclcpp</build_depend>
+ <build_depend>std_msgs</build_depend>
+
+ <exec_depend>rclcpp</exec_depend>
+ <exec_depend>std_msgs</exec_depend>
+
+ <export>
+ <build_type>ament_cmake</build_type>
+ </export>
+</package>
@@ -0,0 +1,36 @@
+#include <iostream>
+#include <sstream>
+
+#include <rclcpp/rclcpp.hpp>
+#include <std_msgs/msg/string.hpp>
+
+int main(int argc, char * argv[])
+{
+ rclcpp::init(argc, argv);
+
+ auto node = rclcpp::node::Node::make_shared("talker");
+
+ auto publisher = node->create_publisher<std_msgs::msg::String>("chatter", rmw_qos_profile_default);
+
+ rclcpp::WallRate loopRate(1);
+
+ int count = 0;
+ while (rclcpp::ok())
+ {
+ auto message = std::make_shared<std_msgs::msg::String>();
+
+ std::stringstream stream;
+ stream << "Hello world " << count++;
+ message->data = stream.str();
+
+ std::cout << message->data << std::endl;
+
+ publisher->publish(message);
+
+ rclcpp::spin_some(node);
+
+ loopRate.sleep();
+ }
+
+ return 0;
+}
@@ -127,13 +127,13 @@ def link_or_copy(source, destination, follow_symlinks=False):
def link_or_copy_tree(source_tree, destination_tree,
copy_function=link_or_copy):
- """Copy a source tree into a destination, hard-linking if possile.
+ """Copy a source tree into a destination, hard-linking if possible.
:param str source_tree: Source directory to be copied.
:param str destination_tree: Destination directory. If this directory
already exists, the files in `source_tree`
will take precedence.
- :param str boundary: Filesystem boundary no symlinks are allowed to cross.
+ :param callable copy_function: Callable that actually copies.
"""
if not os.path.isdir(source_tree):
@@ -15,3 +15,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from snapcraft.plugins._ros import rosdep # noqa
+from snapcraft.plugins._ros import ros2 # noqa
@@ -0,0 +1,153 @@
+# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
+#
+# Copyright (C) 2017 Canonical Ltd
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import contextlib
+import os
+import logging
+import shutil
+import subprocess
+
+from snapcraft import (
+ repo,
+ sources,
+)
+
+logger = logging.getLogger(__name__)
+
+_ROS2_URL_TEMPLATE = (
+ 'https://raw.githubusercontent.com/ros2/ros2/{version}/ros2.repos'
+)
+
+
+_INSTALL_TOOLS_STEP = 'install-tools'
+_FETCH_ROS2_STEP = 'fetch-ros2'
+_BUILD_ROS2_STEP = 'build-ros2'
+
+
+class Bootstrapper:
+ def __init__(self, *, version, bootstrap_path, ubuntu_sources, project):
+ self._version = version
+ self._ubuntu_sources = ubuntu_sources
+ self._project = project
+
+ self._bootstrap_path = bootstrap_path
+ self._tool_dir = os.path.join(self._bootstrap_path, 'tools')
+ self._state_dir = os.path.join(self._bootstrap_path, 'state')
+ self._underlay_dir = os.path.join(self._bootstrap_path, 'underlay')
+ self._install_dir = os.path.join(self._bootstrap_path, 'install')
+ self._build_dir = os.path.join(self._bootstrap_path, 'build')
+ self._source_dir = os.path.join(self._underlay_dir, 'src')
+
+ def get_build_packages(self):
+ # Include dependencies for FastRTPS
+ packages = ['cmake']
+
+ # Dependencies for FastRTPS
+ packages.extend(['libasio-dev', 'libtinyxml2-dev'])
+
+ # Dependencies for the rest of ros2
+ packages.extend([
+ 'libopencv-dev', 'libpoco-dev', 'libpocofoundation9v5',
+ 'libpocofoundation9v5-dbg', 'python-empy', 'python3-dev',
+ 'python3-empy', 'python3-nose', 'python3-pip',
+ 'python3-setuptools', 'python3-yaml', 'libtinyxml-dev',
+ 'libeigen3-dev'])
+
+ return packages
+
+ def get_stage_packages(self):
+ # Ament is a python3 tool, and it requires setuptools at runtime
+ packages = ['python3', 'python3-setuptools']
+
+ return packages
+
+ def pull(self):
+ self._run_step(
+ self._install_tools,
+ step=_INSTALL_TOOLS_STEP,
+ skip_message='Tools already installed. Skipping...')
+ self._run_step(
+ self._fetch_ros2,
+ step=_FETCH_ROS2_STEP,
+ skip_message='ros2 already fetched. Skipping...')
+
+ def build(self):
+ self._run_step(
+ self._build_ros2,
+ step=_BUILD_ROS2_STEP,
+ skip_message='ros2 already built. Skipping...')
+
+ return self._install_dir
+
+ def _run(self, command):
+ env = os.environ.copy()
+ env['PATH'] = env['PATH'] + ':' + os.path.join(
+ self._tool_dir, 'usr', 'bin')
+ env['PYTHONPATH'] = os.path.join(
+ self._tool_dir, 'usr', 'lib', 'python3', 'dist-packages')
+
+ subprocess.check_call(command, env=env)
+
+ def _step_done(self, step):
+ return os.path.isfile(os.path.join(self._state_dir, step))
+
+ def _set_step_done(self, step):
+ os.makedirs(self._state_dir, exist_ok=True)
+ open(os.path.join(self._state_dir, step), 'w').close()
+
+ def _run_step(self, callable, *, step, skip_message=None):
+ if self._step_done(step):
+ if skip_message:
+ logger.debug(skip_message)
+ else:
+ callable()
+ self._set_step_done(step)
+
+ def clean(self):
+ with contextlib.suppress(FileNotFoundError):
+ shutil.rmtree(self._bootstrap_path)
+
+ def _install_tools(self):
+ logger.info('Preparing to fetch vcstool...')
+ ubuntu = repo.Ubuntu(
+ self._bootstrap_path, sources=self._ubuntu_sources,
+ project_options=self._project)
+
+ logger.info('Fetching vcstool...')
+ ubuntu.get(['python3-vcstool'])
+
+ logger.info('Installing vcstool...')
+ ubuntu.unpack(self._tool_dir)
+
+ def _fetch_ros2(self):
+ os.makedirs(self._source_dir, exist_ok=True)
+ sources.Script(
+ _ROS2_URL_TEMPLATE.format(version=self._version),
+ self._underlay_dir).download()
+
+ logger.info('Fetching ros2 sources....')
+ ros2_repos = os.path.join(self._underlay_dir, 'ros2.repos')
+ self._run(
+ ['vcs', 'import', '--input', ros2_repos, self._source_dir])
+
+ def _build_ros2(self):
+ logger.info('Building ros2 underlay...')
+ ament_path = os.path.join(
+ self._source_dir, 'ament', 'ament_tools', 'scripts',
+ 'ament.py')
+ self._run(
+ [ament_path, 'build', self._source_dir, '--build-space',
+ self._build_dir, '--install-space', self._install_dir])
Oops, something went wrong.