Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests: add fake pip fixture #1558

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -2,6 +2,7 @@ docs/reference.md
demos/*/parts/
demos/*/prime/
demos/*/stage/
demos/*/snap/.snapcraft/
demos/**/*.snap
snap/.snapcraft/
tests/unit/parts/
Expand Down
7 changes: 7 additions & 0 deletions demos/ros2/scripts/bin/launch-system
@@ -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
29 changes: 29 additions & 0 deletions demos/ros2/snap/snapcraft.yaml
@@ -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
15 changes: 15 additions & 0 deletions demos/ros2/src/listener_py/launch/talk_and_listen.py
@@ -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
Empty file.
23 changes: 23 additions & 0 deletions demos/ros2/src/listener_py/nodes/listener.py
@@ -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()
16 changes: 16 additions & 0 deletions demos/ros2/src/listener_py/package.xml
@@ -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>
4 changes: 4 additions & 0 deletions demos/ros2/src/listener_py/setup.cfg
@@ -0,0 +1,4 @@
[develop]
script-dir=$base/lib/listener_py
[install]
install-scripts=$base/lib/listener_py
21 changes: 21 additions & 0 deletions demos/ros2/src/listener_py/setup.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',
],
},
)
18 changes: 18 additions & 0 deletions demos/ros2/src/talker_cpp/CMakeLists.txt
@@ -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()
21 changes: 21 additions & 0 deletions demos/ros2/src/talker_cpp/package.xml
@@ -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>
36 changes: 36 additions & 0 deletions demos/ros2/src/talker_cpp/src/talker.cpp
@@ -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;
}
4 changes: 2 additions & 2 deletions snapcraft/file_utils.py
Expand Up @@ -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):
Expand Down
1 change: 1 addition & 0 deletions snapcraft/plugins/_ros/__init__.py
Expand Up @@ -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
153 changes: 153 additions & 0 deletions snapcraft/plugins/_ros/ros2.py
@@ -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])