diff --git a/examples/ros/snapcraft.yaml b/examples/ros/snapcraft.yaml
index e4932ce03c..2559ff9dd4 100644
--- a/examples/ros/snapcraft.yaml
+++ b/examples/ros/snapcraft.yaml
@@ -7,9 +7,9 @@ description: A really small ROS example
binaries:
listener:
- exec: opt/ros/indigo/beginner_tutorials/lib/beginner_tutorials/listener
+ exec: rosrun beginner_tutorials listener
talker:
- exec: opt/ros/indigo/beginner_tutorials/lib/beginner_tutorials/talker
+ exec: rosrun beginner_tutorials talker
services:
rosmaster:
diff --git a/examples/ros/src/beginner_tutorials/CMakeLists.txt b/examples/ros/src/beginner_tutorials/CMakeLists.txt
index d42f08453b..f2ddb963fc 100644
--- a/examples/ros/src/beginner_tutorials/CMakeLists.txt
+++ b/examples/ros/src/beginner_tutorials/CMakeLists.txt
@@ -1,4 +1,3 @@
-# %Tag(FULLTEXT)%
cmake_minimum_required(VERSION 2.8.3)
project(beginner_tutorials)
@@ -25,7 +24,6 @@ add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
## Build service client and server
-# %Tag(SRVCLIENT)%
add_executable(add_two_ints_server src/add_two_ints_server.cpp)
target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
add_dependencies(add_two_ints_server beginner_tutorials_gencpp)
@@ -34,6 +32,9 @@ add_executable(add_two_ints_client src/add_two_ints_client.cpp)
target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})
add_dependencies(add_two_ints_client beginner_tutorials_gencpp)
-# %EndTag(SRVCLIENT)%
-
-# %EndTag(FULLTEXT)%
\ No newline at end of file
+## Mark executables for installation
+install(TARGETS talker listener add_two_ints_server add_two_ints_client
+ ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
+ LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
+ RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
+)
diff --git a/snapcraft/plugins/catkin.py b/snapcraft/plugins/catkin.py
index 4d7ff436ea..a627a28d16 100644
--- a/snapcraft/plugins/catkin.py
+++ b/snapcraft/plugins/catkin.py
@@ -32,6 +32,7 @@
import tempfile
import logging
import shutil
+import re
import snapcraft
from snapcraft import repo
@@ -91,7 +92,6 @@ def env(self, root):
'lib',
self.python_version,
'dist-packages')),
- 'DESTDIR={0}'.format(self.installdir),
# ROS needs it but doesn't set it :-/
'CPPFLAGS="-std=c++11 $CPPFLAGS -I{0} -I{1}"'.format(
os.path.join(root, 'usr', 'include', 'c++', self.gcc_version),
@@ -105,6 +105,10 @@ def env(self, root):
root,
self.options.rosversion),
'ROS_MASTER_URI=http://localhost:11311',
+
+ # Various ROS tools (e.g. rospack) keep a cache, and they determine
+ # where the cache goes using $ROS_HOME.
+ 'ROS_HOME=$SNAP_APP_USER_DATA_PATH/.ros',
'_CATKIN_SETUP_DIR={}'.format(os.path.join(
root, 'opt', 'ros', self.options.rosversion)),
'echo FOO=BAR\nif `test -e {0}` ; then\n. {0} ;\nfi\n'.format(
@@ -239,20 +243,19 @@ def build(self):
self._find_package_deps()
self._build_packages_deps()
- # the hacks
- findcmd = ['find', self.installdir, '-name', '*.cmake', '-delete']
- self.run(findcmd)
-
- self.run(
- ['rm', '-f',
- 'opt/ros/' + self.options.rosversion + '/.catkin',
- 'opt/ros/' + self.options.rosversion + '/.rosinstall',
- 'opt/ros/' + self.options.rosversion + '/setup.sh',
- 'opt/ros/' + self.options.rosversion + '/_setup_util.py'],
- cwd=self.installdir)
-
+ # FIXME: Removing this here since it'll clash with the one from
+ # roscore. Remove this line once the roscore plugin is gone.
os.remove(os.path.join(self.installdir, 'usr/bin/xml2-config'))
+ # Fix the shebang in _setup_util.py to be portable
+ with open('{}/opt/ros/{}/_setup_util.py'.format(
+ self.installdir, self.options.rosversion), 'r+') as f:
+ pattern = re.compile(r'#!.*python')
+ replaced = pattern.sub(r'#!/usr/bin/env python', f.read())
+ f.seek(0)
+ f.truncate()
+ f.write(replaced)
+
def _build_packages_deps(self):
# Ugly dependency resolution, just loop through until we can
# find something to build. When we do, build it. Loop until we
@@ -276,26 +279,32 @@ def _build_packages_deps(self):
def _handle_package(self, pkg):
catkincmd = ['catkin_make_isolated']
+ # Install the package
+ catkincmd.append('--install')
+
+ # Specify the package to be built
catkincmd.append('--pkg')
catkincmd.append(pkg)
- # Define the location
+ # Don't clutter the real ROS workspace-- use the Snapcraft build
+ # directory
catkincmd.extend(['--directory', self.builddir])
+ # Specify that the package should be installed along with the rest of
+ # the ROS distro.
+ catkincmd.extend(['--install-space', self.rosdir])
+
# Start the CMake Commands
catkincmd.append('--cmake-args')
- # CMake directories
- catkincmd.append('-DCATKIN_DEVEL_PREFIX={}'.format(self.rosdir))
- catkincmd.append('-DCMAKE_INSTALL_PREFIX={}'.format(self.installdir))
-
- # Dep CMake files
+ # Make sure all ROS dependencies can be found, even without the
+ # workspace setup
for dep in self.dependencies:
catkincmd.append('-D{0}_DIR={1}'.format(
dep.replace('-', '_'),
os.path.join(self.rosdir, 'share', dep, 'cmake')))
- # Compiler fun
+ # Make sure we're using the compilers included in this .snap
catkincmd.extend([
'-DCMAKE_C_FLAGS="$CFLAGS"',
'-DCMAKE_CXX_FLAGS="$CPPFLAGS"',
diff --git a/snapcraft/tests/test_plugin_catkin.py b/snapcraft/tests/test_plugin_catkin.py
index efd05ad168..bc55bb0d47 100644
--- a/snapcraft/tests/test_plugin_catkin.py
+++ b/snapcraft/tests/test_plugin_catkin.py
@@ -29,16 +29,90 @@ class _IOError(IOError):
errno = os.errno.EACCES
-class CatkinTestCase(tests.TestCase):
+class CatkinPluginTestCase(tests.TestCase):
def setUp(self):
super().setUp()
class props:
+ rosversion = 'foo'
catkin_packages = ['my_package']
self.properties = props()
+ patcher = mock.patch('snapcraft.repo.Ubuntu')
+ self.ubuntu_mock = patcher.start()
+ self.addCleanup(patcher.stop)
+
+ def test_pull_debian_dependencies(self):
+ plugin = catkin.CatkinPlugin('test-part', self.properties)
+
+ tmpdir = tempfile.TemporaryDirectory()
+ self.addCleanup(tmpdir.cleanup)
+ plugin.sourcedir = tmpdir.name
+
+ # Create ROS package directory
+ os.mkdir(os.path.join(plugin.sourcedir, "my_package"))
+
+ # Now create my_package's package.xml:
+ with open(os.path.join(plugin.sourcedir, "my_package",
+ "package.xml"), 'w') as f:
+ f.write("""
+
+ buildtool_depend
+ build_depend
+ run_depend
+ """)
+
+ plugin.pull()
+
+ self.ubuntu_mock.assert_has_calls([
+ mock.call().get([
+ 'ros-foo-buildtool-depend',
+ 'ros-foo-build-depend',
+ 'ros-foo-run-depend']),
+ mock.call().unpack(plugin.installdir)])
+
+ def test_pull_local_dependencies(self):
+ self.properties.catkin_packages.append('package_2')
+
+ plugin = catkin.CatkinPlugin('test-part', self.properties)
+
+ tmpdir = tempfile.TemporaryDirectory()
+ self.addCleanup(tmpdir.cleanup)
+ plugin.sourcedir = tmpdir.name
+
+ # Create ROS package directory for both packages
+ os.mkdir(os.path.join(plugin.sourcedir, "my_package"))
+ os.mkdir(os.path.join(plugin.sourcedir, "package_2"))
+
+ # Now create my_package's package.xml, specifying that is depends upon
+ # package_2:
+ with open(os.path.join(plugin.sourcedir, "my_package",
+ "package.xml"), 'w') as f:
+ f.write("""
+
+ package_2
+ """)
+
+ # Finally, create package_2's package.xml, specifying that is has no
+ # dependencies:
+ with open(os.path.join(plugin.sourcedir, "package_2",
+ "package.xml"), 'w') as f:
+ f.write("""
+
+ """)
+
+ plugin.pull()
+
+ self.assertTrue('my_package' in plugin.package_local_deps,
+ 'Expected "my_package" to be in the dependencies')
+ self.assertEqual(plugin.package_local_deps['my_package'],
+ {'package_2'},
+ 'Expected "my_package" to depend upon "package_2"')
+ self.assertFalse(self.ubuntu_mock.called,
+ "Ubuntu packages were unexpectedly pulled down")
+
def test_log_warning_when_unable_to_find_a_catkin_package(self):
fake_logger = fixtures.FakeLogger()
self.useFixture(fake_logger)