v01
This commit is contained in:
172
thirdparty/ros/ros_comm/utilities/roswtf/CHANGELOG.rst
vendored
Normal file
172
thirdparty/ros/ros_comm/utilities/roswtf/CHANGELOG.rst
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Changelog for package roswtf
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
1.12.14 (2018-08-23)
|
||||
--------------------
|
||||
|
||||
1.12.13 (2018-02-21)
|
||||
--------------------
|
||||
|
||||
1.12.12 (2017-11-16)
|
||||
--------------------
|
||||
|
||||
1.12.11 (2017-11-07)
|
||||
--------------------
|
||||
|
||||
1.12.10 (2017-11-06)
|
||||
--------------------
|
||||
|
||||
1.12.9 (2017-11-06)
|
||||
-------------------
|
||||
|
||||
1.12.8 (2017-11-06)
|
||||
-------------------
|
||||
* improve roswtf tests (`#1102 <https://github.com/ros/ros_comm/pull/1102>`_)
|
||||
|
||||
1.12.7 (2017-02-17)
|
||||
-------------------
|
||||
|
||||
1.12.6 (2016-10-26)
|
||||
-------------------
|
||||
|
||||
1.12.5 (2016-09-30)
|
||||
-------------------
|
||||
|
||||
1.12.4 (2016-09-19)
|
||||
-------------------
|
||||
|
||||
1.12.3 (2016-09-17)
|
||||
-------------------
|
||||
|
||||
1.12.2 (2016-06-03)
|
||||
-------------------
|
||||
|
||||
1.12.1 (2016-04-18)
|
||||
-------------------
|
||||
|
||||
1.12.0 (2016-03-18)
|
||||
-------------------
|
||||
|
||||
1.11.18 (2016-03-17)
|
||||
--------------------
|
||||
|
||||
1.11.17 (2016-03-11)
|
||||
--------------------
|
||||
|
||||
1.11.16 (2015-11-09)
|
||||
--------------------
|
||||
|
||||
1.11.15 (2015-10-13)
|
||||
--------------------
|
||||
|
||||
1.11.14 (2015-09-19)
|
||||
--------------------
|
||||
* add optional dependency on geneus to make roswtf tests pass in jade
|
||||
|
||||
1.11.13 (2015-04-28)
|
||||
--------------------
|
||||
|
||||
1.11.12 (2015-04-27)
|
||||
--------------------
|
||||
|
||||
1.11.11 (2015-04-16)
|
||||
--------------------
|
||||
* support IPv6 addresses containing percentage symbols (`#585 <https://github.com/ros/ros_comm/issues/585>`_)
|
||||
|
||||
1.11.10 (2014-12-22)
|
||||
--------------------
|
||||
|
||||
1.11.9 (2014-08-18)
|
||||
-------------------
|
||||
|
||||
1.11.8 (2014-08-04)
|
||||
-------------------
|
||||
|
||||
1.11.7 (2014-07-18)
|
||||
-------------------
|
||||
|
||||
1.11.6 (2014-07-10)
|
||||
-------------------
|
||||
|
||||
1.11.5 (2014-06-24)
|
||||
-------------------
|
||||
|
||||
1.11.4 (2014-06-16)
|
||||
-------------------
|
||||
* Python 3 compatibility (`#426 <https://github.com/ros/ros_comm/issues/426>`_, `#427 <https://github.com/ros/ros_comm/issues/427>`_)
|
||||
|
||||
1.11.3 (2014-05-21)
|
||||
-------------------
|
||||
|
||||
1.11.2 (2014-05-08)
|
||||
-------------------
|
||||
|
||||
1.11.1 (2014-05-07)
|
||||
-------------------
|
||||
* update roswtf test for upcoming rospack 2.2.3
|
||||
* add architecture_independent flag in package.xml (`#391 <https://github.com/ros/ros_comm/issues/391>`_)
|
||||
|
||||
1.11.0 (2014-03-04)
|
||||
-------------------
|
||||
* make rostest in CMakeLists optional (`ros/rosdistro#3010 <https://github.com/ros/rosdistro/issues/3010>`_)
|
||||
|
||||
1.10.0 (2014-02-11)
|
||||
-------------------
|
||||
|
||||
1.9.54 (2014-01-27)
|
||||
-------------------
|
||||
* fix roswtf checks to not require release-only python packages to be installed
|
||||
* add missing run/test dependencies on rosbuild to get ROS_ROOT environment variable
|
||||
|
||||
1.9.53 (2014-01-14)
|
||||
-------------------
|
||||
|
||||
1.9.52 (2014-01-08)
|
||||
-------------------
|
||||
|
||||
1.9.51 (2014-01-07)
|
||||
-------------------
|
||||
* do not warn about not existing stacks folder in a catkin workspace
|
||||
|
||||
1.9.50 (2013-10-04)
|
||||
-------------------
|
||||
|
||||
1.9.49 (2013-09-16)
|
||||
-------------------
|
||||
|
||||
1.9.48 (2013-08-21)
|
||||
-------------------
|
||||
|
||||
1.9.47 (2013-07-03)
|
||||
-------------------
|
||||
* check for CATKIN_ENABLE_TESTING to enable configure without tests
|
||||
|
||||
1.9.46 (2013-06-18)
|
||||
-------------------
|
||||
|
||||
1.9.45 (2013-06-06)
|
||||
-------------------
|
||||
|
||||
1.9.44 (2013-03-21)
|
||||
-------------------
|
||||
* fix ROS_ROOT check to access trailing 'rosbuild'
|
||||
|
||||
1.9.43 (2013-03-13)
|
||||
-------------------
|
||||
|
||||
1.9.42 (2013-03-08)
|
||||
-------------------
|
||||
|
||||
1.9.41 (2013-01-24)
|
||||
-------------------
|
||||
|
||||
1.9.40 (2013-01-13)
|
||||
-------------------
|
||||
* add checks for pip packages and rosdep
|
||||
* fix check for catkin_pkg
|
||||
* fix for thread race condition causes incorrect graph connectivity analysis
|
||||
|
||||
1.9.39 (2012-12-29)
|
||||
-------------------
|
||||
* first public release for Groovy
|
||||
11
thirdparty/ros/ros_comm/utilities/roswtf/CMakeLists.txt
vendored
Normal file
11
thirdparty/ros/ros_comm/utilities/roswtf/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 2.8.3)
|
||||
project(roswtf)
|
||||
find_package(catkin REQUIRED)
|
||||
catkin_package()
|
||||
catkin_python_setup()
|
||||
|
||||
if(CATKIN_ENABLE_TESTING)
|
||||
find_package(rostest)
|
||||
add_rostest(test/roswtf.test)
|
||||
catkin_add_nosetests(test)
|
||||
endif()
|
||||
32
thirdparty/ros/ros_comm/utilities/roswtf/package.xml
vendored
Normal file
32
thirdparty/ros/ros_comm/utilities/roswtf/package.xml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<package>
|
||||
<name>roswtf</name>
|
||||
<version>1.12.14</version>
|
||||
<description>
|
||||
roswtf is a tool for diagnosing issues with a running ROS system. Think of it as a FAQ implemented in code.
|
||||
</description>
|
||||
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
|
||||
<license>BSD</license>
|
||||
|
||||
<url>http://ros.org/wiki/roswtf</url>
|
||||
<author>Ken Conley</author>
|
||||
|
||||
<buildtool_depend version_gte="0.5.68">catkin</buildtool_depend>
|
||||
|
||||
<build_depend>rostest</build_depend>
|
||||
|
||||
<run_depend>python-paramiko</run_depend>
|
||||
<run_depend>python-rospkg</run_depend>
|
||||
<run_depend>rosbuild</run_depend>
|
||||
<run_depend>rosgraph</run_depend>
|
||||
<run_depend>roslaunch</run_depend>
|
||||
<run_depend>roslib</run_depend>
|
||||
<run_depend>rosnode</run_depend>
|
||||
<run_depend>rosservice</run_depend>
|
||||
|
||||
<test_depend>cmake_modules</test_depend> <!-- since the other packages recursively depend on it roswtf needs to find it during its own tests -->
|
||||
|
||||
<export>
|
||||
<rosdoc config="rosdoc.yaml"/>
|
||||
<architecture_independent/>
|
||||
</export>
|
||||
</package>
|
||||
1
thirdparty/ros/ros_comm/utilities/roswtf/rosdoc.yaml
vendored
Normal file
1
thirdparty/ros/ros_comm/utilities/roswtf/rosdoc.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
- builder: epydoc
|
||||
35
thirdparty/ros/ros_comm/utilities/roswtf/scripts/roswtf
vendored
Executable file
35
thirdparty/ros/ros_comm/utilities/roswtf/scripts/roswtf
vendored
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import roswtf
|
||||
roswtf.roswtf_main()
|
||||
13
thirdparty/ros/ros_comm/utilities/roswtf/setup.py
vendored
Normal file
13
thirdparty/ros/ros_comm/utilities/roswtf/setup.py
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from distutils.core import setup
|
||||
from catkin_pkg.python_setup import generate_distutils_setup
|
||||
|
||||
d = generate_distutils_setup(
|
||||
packages=['roswtf'],
|
||||
package_dir={'': 'src'},
|
||||
scripts=['scripts/roswtf'],
|
||||
requires=['genmsg', 'genpy', 'roslib', 'rospkg']
|
||||
)
|
||||
|
||||
setup(**d)
|
||||
242
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/__init__.py
vendored
Normal file
242
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/__init__.py
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Revision $Id$
|
||||
|
||||
"""
|
||||
roswtf command-line tool.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import rospkg
|
||||
import rosgraph.names
|
||||
|
||||
def yaml_results(ctx):
|
||||
cd = ctx.as_dictionary()
|
||||
d = {}
|
||||
d['warnings'] = {}
|
||||
d['errors'] = {}
|
||||
wd = d['warnings']
|
||||
for warn in ctx.warnings:
|
||||
wd[warn.format_msg%cd] = warn.return_val
|
||||
ed = d['warnings']
|
||||
for err in ctx.warnings:
|
||||
ed[err.format_msg%cd] = err.return_val
|
||||
import yaml
|
||||
print(yaml.dump(d))
|
||||
|
||||
def print_results(ctx):
|
||||
if not ctx.warnings and not ctx.errors:
|
||||
print("No errors or warnings")
|
||||
else:
|
||||
if ctx.warnings:
|
||||
print("Found %s warning(s).\nWarnings are things that may be just fine, but are sometimes at fault\n" % len(ctx.warnings))
|
||||
for warn in ctx.warnings:
|
||||
print('\033[1mWARNING\033[0m', warn.msg)
|
||||
print('')
|
||||
|
||||
if ctx.errors:
|
||||
print("Found %s error(s).\n"%len(ctx.errors))
|
||||
for e in ctx.errors:
|
||||
print('\033[31m\033[1mERROR\033[0m', e.msg)
|
||||
#print("ERROR:", e.msg
|
||||
|
||||
def roswtf_main():
|
||||
try:
|
||||
import std_msgs.msg
|
||||
import rosgraph_msgs.msg
|
||||
except ImportError:
|
||||
print("ERROR: The core ROS message libraries (std_msgs and rosgraph_msgs) have not been built.")
|
||||
sys.exit(1)
|
||||
|
||||
from roswtf.context import WtfException
|
||||
try:
|
||||
_roswtf_main()
|
||||
except WtfException as e:
|
||||
print(str(e), file=sys.stderr)
|
||||
|
||||
def _roswtf_main():
|
||||
launch_files = names = None
|
||||
# performance optimization
|
||||
rospack = rospkg.RosPack()
|
||||
all_pkgs = rospack.list()
|
||||
|
||||
import optparse
|
||||
parser = optparse.OptionParser(usage="usage: roswtf [launch file]", description="roswtf is a tool for verifying a ROS installation and running system. Checks provided launchfile if provided, else current stack or package.")
|
||||
# #2268
|
||||
parser.add_option("--all",
|
||||
dest="all_packages", default=False,
|
||||
action="store_true",
|
||||
help="run roswtf against all packages")
|
||||
# #2270
|
||||
parser.add_option("--no-plugins",
|
||||
dest="disable_plugins", default=False,
|
||||
action="store_true",
|
||||
help="disable roswtf plugins")
|
||||
|
||||
parser.add_option("--offline",
|
||||
dest="offline", default=False,
|
||||
action="store_true",
|
||||
help="only run offline tests")
|
||||
|
||||
#TODO: --all-pkgs option
|
||||
options, args = parser.parse_args()
|
||||
if args:
|
||||
launch_files = args
|
||||
if 0:
|
||||
# disable names for now as don't have any rules yet
|
||||
launch_files = [a for a in args if os.path.isfile(a)]
|
||||
names = [a for a in args if not a in launch_files]
|
||||
names = [rosgraph.names.script_resolve_name('/roswtf', n) for n in names]
|
||||
|
||||
from roswtf.context import WtfContext
|
||||
from roswtf.environment import wtf_check_environment, invalid_url, ros_root_check
|
||||
from roswtf.graph import wtf_check_graph
|
||||
import roswtf.rosdep_db
|
||||
import roswtf.py_pip_deb_checks
|
||||
import roswtf.network
|
||||
import roswtf.packages
|
||||
import roswtf.roslaunchwtf
|
||||
import roswtf.stacks
|
||||
import roswtf.plugins
|
||||
if not options.disable_plugins:
|
||||
static_plugins, online_plugins = roswtf.plugins.load_plugins()
|
||||
else:
|
||||
static_plugins, online_plugins = [], []
|
||||
|
||||
# - do a ros_root check first and abort if it fails as rest of tests are useless after that
|
||||
error = ros_root_check(None, ros_root=os.environ['ROS_ROOT'])
|
||||
if error:
|
||||
print("ROS_ROOT is invalid: "+str(error))
|
||||
sys.exit(1)
|
||||
|
||||
all_warnings = []
|
||||
all_errors = []
|
||||
|
||||
if launch_files:
|
||||
ctx = WtfContext.from_roslaunch(launch_files)
|
||||
#TODO: allow specifying multiple roslaunch files
|
||||
else:
|
||||
curr_package = rospkg.get_package_name('.')
|
||||
if curr_package:
|
||||
print("Package:", curr_package)
|
||||
ctx = WtfContext.from_package(curr_package)
|
||||
#TODO: load all .launch files in package
|
||||
elif os.path.isfile('stack.xml'):
|
||||
curr_stack = os.path.basename(os.path.abspath('.'))
|
||||
print("Stack:", curr_stack)
|
||||
ctx = WtfContext.from_stack(curr_stack)
|
||||
else:
|
||||
print("No package or stack in context")
|
||||
ctx = WtfContext.from_env()
|
||||
if options.all_packages:
|
||||
print("roswtf will run against all packages")
|
||||
ctx.pkgs = all_pkgs
|
||||
|
||||
# static checks
|
||||
wtf_check_environment(ctx)
|
||||
roswtf.rosdep_db.wtf_check(ctx)
|
||||
roswtf.py_pip_deb_checks.wtf_check(ctx)
|
||||
roswtf.network.wtf_check(ctx)
|
||||
roswtf.packages.wtf_check(ctx)
|
||||
roswtf.stacks.wtf_check(ctx)
|
||||
roswtf.roslaunchwtf.wtf_check_static(ctx)
|
||||
for p in static_plugins:
|
||||
p(ctx)
|
||||
|
||||
print("="*80)
|
||||
print("Static checks summary:\n")
|
||||
print_results(ctx)
|
||||
|
||||
# Save static results and start afresh for online checks
|
||||
all_warnings.extend(ctx.warnings)
|
||||
all_errors.extend(ctx.errors)
|
||||
del ctx.warnings[:]
|
||||
del ctx.errors[:]
|
||||
|
||||
# test online
|
||||
print("="*80)
|
||||
|
||||
try:
|
||||
|
||||
if options.offline or not ctx.ros_master_uri or invalid_url(ctx.ros_master_uri) or not rosgraph.is_master_online():
|
||||
online_checks = False
|
||||
else:
|
||||
online_checks = True
|
||||
if online_checks:
|
||||
online_checks = True
|
||||
print("Beginning tests of your ROS graph. These may take awhile...")
|
||||
|
||||
# online checks
|
||||
wtf_check_graph(ctx, names=names)
|
||||
elif names:
|
||||
# TODO: need to rework this logic
|
||||
print("\nCannot communicate with master, unable to diagnose [%s]"%(', '.join(names)))
|
||||
return
|
||||
else:
|
||||
print("\nROS Master does not appear to be running.\nOnline graph checks will not be run.\nROS_MASTER_URI is [%s]"%(ctx.ros_master_uri))
|
||||
return
|
||||
|
||||
# spin up a roswtf node so we can subscribe to messages
|
||||
import rospy
|
||||
rospy.init_node('roswtf', anonymous=True)
|
||||
|
||||
online_checks = True
|
||||
roswtf.roslaunchwtf.wtf_check_online(ctx)
|
||||
|
||||
for p in online_plugins:
|
||||
online_checks = True
|
||||
p(ctx)
|
||||
|
||||
if online_checks:
|
||||
# done
|
||||
print("\nOnline checks summary:\n")
|
||||
print_results(ctx)
|
||||
|
||||
except roswtf.context.WtfException as e:
|
||||
print(str(e), file=sys.stderr)
|
||||
print("\nAborting checks, partial results summary:\n")
|
||||
print_results(ctx)
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
print(str(e), file=sys.stderr)
|
||||
print("\nAborting checks, partial results summary:\n")
|
||||
print_results(ctx)
|
||||
|
||||
#TODO: print results in YAML if run remotely
|
||||
#yaml_results(ctx)
|
||||
306
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/context.py
vendored
Normal file
306
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/context.py
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Revision $Id$
|
||||
|
||||
"""
|
||||
L{WtfContext} object, which is commonly used throughout the roswtf
|
||||
APIs to pass state.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import rospkg
|
||||
import rospkg.environment
|
||||
|
||||
import rosgraph
|
||||
|
||||
import roslaunch.depends
|
||||
import roslaunch.substitution_args
|
||||
|
||||
from roswtf.model import WtfWarning
|
||||
|
||||
class WtfException(Exception):
|
||||
"""
|
||||
Base exception class of roswtf-related issues.
|
||||
"""
|
||||
pass
|
||||
|
||||
class WtfContext(object):
|
||||
"""
|
||||
WtfContext stores common state about the ROS filesystem and online
|
||||
environment. The primary use of this is for convenience (not
|
||||
having to load this state manually) and performance (not having to
|
||||
do the same calculation repeatedly).
|
||||
"""
|
||||
__slots__ = ['pkg', 'pkg_dir', 'pkgs',
|
||||
'stack', 'stack_dir', 'stacks',
|
||||
'manifest_file', 'manifest',
|
||||
'env', 'ros_root', 'ros_package_path', 'pythonpath',
|
||||
'ros_master_uri',
|
||||
'roslaunch_uris',
|
||||
'launch_files',
|
||||
'launch_file_deps',
|
||||
'launch_file_missing_deps',
|
||||
'system_state',
|
||||
'service_providers',
|
||||
'topics', 'services',
|
||||
'nodes', 'uri_node_map',
|
||||
'expected_edges',
|
||||
'actual_edges',
|
||||
'unconnected_subscriptions',
|
||||
'use_sim_time',
|
||||
'warnings', 'errors',
|
||||
'rospack', 'rosstack']
|
||||
|
||||
def __init__(self):
|
||||
# main package we are running
|
||||
self.pkg = None
|
||||
self.pkg_dir = None
|
||||
# main stack we are running
|
||||
self.stack = None
|
||||
self.stack_dir = None
|
||||
|
||||
# - list of all packages involved in this check
|
||||
self.pkgs = []
|
||||
# - list of all stacks involved in this check
|
||||
self.stacks = []
|
||||
|
||||
# manifest location of package that we are running
|
||||
self.manifest_file = None
|
||||
# manifest of package that we are running
|
||||
self.manifest = None
|
||||
|
||||
# environment variables
|
||||
self.env = {}
|
||||
|
||||
# provide these for convenience
|
||||
self.ros_root = None
|
||||
self.ros_package_path = None
|
||||
self.pythonpath = None
|
||||
|
||||
# launch file that is being run
|
||||
self.launch_files = None
|
||||
self.launch_file_deps = None
|
||||
self.launch_file_missing_deps = None
|
||||
|
||||
# online state
|
||||
self.roslaunch_uris = None
|
||||
self.system_state = None #master.getSystemState
|
||||
self.topics = None
|
||||
self.services = None
|
||||
self.service_providers = None #names of nodes with services
|
||||
self.nodes = None
|
||||
self.uri_node_map = {}
|
||||
self.expected_edges = None
|
||||
self.actual_edges = None
|
||||
self.unconnected_subscriptions = None
|
||||
self.use_sim_time = None
|
||||
|
||||
# caching rospack instance
|
||||
self.rospack = self.rosstack = None
|
||||
|
||||
# warnings that we have collected so far
|
||||
self.warnings = []
|
||||
# errors that we have collected so far
|
||||
self.errors = []
|
||||
|
||||
def as_dictionary(self):
|
||||
"""
|
||||
@return: dictionary representation of context, which is
|
||||
useful for producing error messages
|
||||
@rtype: dict
|
||||
"""
|
||||
return dict((s, getattr(self, s)) for s in self.__slots__)
|
||||
|
||||
@staticmethod
|
||||
def from_roslaunch(roslaunch_files, env=None):
|
||||
"""
|
||||
@param roslaunch_file: roslaunch_file to load from
|
||||
@type roslaunch_file: str
|
||||
"""
|
||||
if env is None:
|
||||
env = os.environ
|
||||
|
||||
# can't go any further if launch file doesn't validate
|
||||
l, c = roslaunch.XmlLoader(), roslaunch.ROSLaunchConfig()
|
||||
for f in roslaunch_files:
|
||||
try:
|
||||
l.load(f, c, verbose=False)
|
||||
except roslaunch.RLException as e:
|
||||
raise WtfException("Unable to load roslaunch file [%s]: %s"%(f, str(e)))
|
||||
|
||||
ctx = WtfContext()
|
||||
ctx.rospack = rospkg.RosPack(rospkg.get_ros_paths(env))
|
||||
ctx.rosstack = rospkg.RosStack(rospkg.get_ros_paths(env))
|
||||
|
||||
ctx.launch_files = roslaunch_files
|
||||
_load_roslaunch(ctx, roslaunch_files)
|
||||
# ctx.pkg and ctx.stack initialized by _load_roslaunch
|
||||
_load_pkg(ctx, ctx.pkg)
|
||||
if ctx.stack:
|
||||
_load_stack(ctx, ctx.stack)
|
||||
_load_env(ctx, env)
|
||||
return ctx
|
||||
|
||||
@staticmethod
|
||||
def from_stack(stack, env=None):
|
||||
"""
|
||||
Initialize WtfContext from stack.
|
||||
@param stack: stack name
|
||||
@type stack: str
|
||||
@raise WtfException: if context state cannot be initialized
|
||||
"""
|
||||
if env is None:
|
||||
env = os.environ
|
||||
|
||||
ctx = WtfContext()
|
||||
ctx.rospack = rospkg.RosPack(rospkg.get_ros_paths(env))
|
||||
ctx.rosstack = rospkg.RosStack(rospkg.get_ros_paths(env))
|
||||
|
||||
_load_stack(ctx, stack)
|
||||
try:
|
||||
ctx.pkgs = ctx.rosstack.packages_of(stack)
|
||||
except rospkg.ResourceNotFound:
|
||||
# this should be handled elsewhere
|
||||
ctx.pkgs = []
|
||||
_load_env(ctx, env)
|
||||
return ctx
|
||||
|
||||
@staticmethod
|
||||
def from_package(pkg, env=None):
|
||||
"""
|
||||
Initialize WtfContext from package name.
|
||||
|
||||
@param pkg: package name
|
||||
@type pkg: str
|
||||
@raise WtfException: if context state cannot be initialized
|
||||
"""
|
||||
if env is None:
|
||||
env = os.environ
|
||||
|
||||
ctx = WtfContext()
|
||||
ctx.rospack = rospkg.RosPack(rospkg.get_ros_paths(env))
|
||||
ctx.rosstack = rospkg.RosStack(rospkg.get_ros_paths(env))
|
||||
|
||||
_load_pkg(ctx, pkg)
|
||||
stack = ctx.rospack.stack_of(pkg)
|
||||
if stack:
|
||||
_load_stack(ctx, stack)
|
||||
_load_env(ctx, env)
|
||||
return ctx
|
||||
|
||||
@staticmethod
|
||||
def from_env(env=None):
|
||||
"""
|
||||
Initialize WtfContext from environment.
|
||||
|
||||
@raise WtfException: if context state cannot be initialized
|
||||
"""
|
||||
if env is None:
|
||||
env = os.environ
|
||||
|
||||
ctx = WtfContext()
|
||||
ctx.rospack = rospkg.RosPack(rospkg.get_ros_paths(env))
|
||||
ctx.rosstack = rospkg.RosStack(rospkg.get_ros_paths(env))
|
||||
|
||||
_load_env(ctx, env)
|
||||
return ctx
|
||||
|
||||
def _load_roslaunch(ctx, roslaunch_files):
|
||||
"""
|
||||
Utility for initializing WtfContext state from roslaunch file
|
||||
"""
|
||||
try:
|
||||
base_pkg, file_deps, missing = roslaunch.depends.roslaunch_deps(roslaunch_files)
|
||||
ctx.pkg = base_pkg
|
||||
ctx.launch_file_deps = file_deps
|
||||
ctx.launch_file_missing_deps = missing
|
||||
except roslaunch.substitution_args.SubstitutionException as se:
|
||||
raise WtfException("Cannot load roslaunch file(s): "+str(se))
|
||||
except roslaunch.depends.RoslaunchDepsException as e:
|
||||
raise WtfException(str(e))
|
||||
|
||||
def _load_pkg(ctx, pkg):
|
||||
"""
|
||||
Utility for initializing WtfContext state
|
||||
@raise WtfException: if context state cannot be initialized
|
||||
"""
|
||||
r = ctx.rospack
|
||||
ctx.pkg = pkg
|
||||
try:
|
||||
ctx.pkgs = [pkg] + r.get_depends(pkg)
|
||||
except rospkg.ResourceNotFound as e:
|
||||
raise WtfException("Cannot find dependencies for package [%s]: missing %s"%(pkg, e))
|
||||
try:
|
||||
ctx.pkg_dir = r.get_path(pkg)
|
||||
ctx.manifest_file = os.path.join(ctx.pkg_dir, 'manifest.xml')
|
||||
ctx.manifest = r.get_manifest(pkg)
|
||||
except rospkg.ResourceNotFound:
|
||||
raise WtfException("Cannot locate manifest file for package [%s]"%pkg)
|
||||
except rospkg.InvalidManifest as e:
|
||||
raise WtfException("Package [%s] has an invalid manifest: %s"%(pkg, e))
|
||||
|
||||
def _load_stack(ctx, stack):
|
||||
"""
|
||||
Utility for initializing WtfContext state
|
||||
@raise WtfException: if context state cannot be initialized
|
||||
"""
|
||||
r = ctx.rosstack
|
||||
ctx.stack = stack
|
||||
try:
|
||||
ctx.stacks = [stack] + r.get_depends(stack, implicit=True)
|
||||
except rospkg.ResourceNotFound as e:
|
||||
raise WtfException("Cannot load dependencies of stack [%s]: %s"%(stack, e))
|
||||
try:
|
||||
ctx.stack_dir = r.get_path(stack)
|
||||
except rospkg.ResourceNotFound:
|
||||
raise WtfException("[%s] appears to be a stack, but it's not on your ROS_PACKAGE_PATH"%stack)
|
||||
|
||||
|
||||
def _load_env(ctx, env):
|
||||
"""
|
||||
Utility for initializing WtfContext state
|
||||
|
||||
@raise WtfException: if context state cannot be initialized
|
||||
"""
|
||||
ctx.env = env
|
||||
try:
|
||||
ctx.ros_root = env[rospkg.environment.ROS_ROOT]
|
||||
except KeyError:
|
||||
raise WtfException("ROS_ROOT is not set")
|
||||
ctx.ros_package_path = env.get(rospkg.environment.ROS_PACKAGE_PATH, None)
|
||||
ctx.pythonpath = env.get('PYTHONPATH', None)
|
||||
ctx.ros_master_uri = env.get(rosgraph.ROS_MASTER_URI, None)
|
||||
|
||||
|
||||
220
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/environment.py
vendored
Normal file
220
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/environment.py
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Revision $Id$
|
||||
|
||||
"""
|
||||
Rules for checking ROS environment state.
|
||||
"""
|
||||
|
||||
import os
|
||||
import socket
|
||||
import stat
|
||||
import string
|
||||
import sys
|
||||
|
||||
from os.path import isdir, isfile
|
||||
from roswtf.rules import warning_rule, error_rule
|
||||
|
||||
#TODO: unit tests
|
||||
|
||||
def paths(path):
|
||||
"""
|
||||
@return: paths contained in path variable. path must conform to OS
|
||||
conventions for path separation (i.e. colon-separated on Unix)
|
||||
@rtype: [str]
|
||||
"""
|
||||
if path:
|
||||
return path.split(os.pathsep)
|
||||
return []
|
||||
|
||||
def is_executable(path):
|
||||
"""
|
||||
@return: True if path has executable permissions
|
||||
@rtype: bool
|
||||
"""
|
||||
mode = os.stat(path)[stat.ST_MODE]
|
||||
return mode & (stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH)
|
||||
|
||||
try:
|
||||
from urllib.parse import urlparse #Python 3
|
||||
except ImportError:
|
||||
from urlparse import urlparse #Python 2
|
||||
|
||||
def invalid_url(url):
|
||||
"""
|
||||
@return: error message if \a url is not a valid url. \a url is
|
||||
allowed to be empty as that check is considered separately.
|
||||
@rtype: str
|
||||
"""
|
||||
if not url:
|
||||
return #caught by different rule
|
||||
p = urlparse(url)
|
||||
if p[0] != 'http':
|
||||
return "protocol is not 'http'"
|
||||
if not p[1]:
|
||||
return "address is missing"
|
||||
if not ':' in p[1]:
|
||||
return "port number is missing"
|
||||
try:
|
||||
splits = p[1].split(':')
|
||||
if len(splits) != 2:
|
||||
return "invalid address string [%s]"%p[1]
|
||||
int(splits[1])
|
||||
except ValueError:
|
||||
return "port number [%s] is invalid"%(splits[1])
|
||||
|
||||
# Error-checking functions for more advanced checks
|
||||
|
||||
def ros_root_check(ctx, ros_root=None):
|
||||
"""
|
||||
@param ros_root: override ctx, useful for when ctx is not created yet
|
||||
@type ros_root: str
|
||||
"""
|
||||
if ros_root is not None:
|
||||
path = ros_root
|
||||
else:
|
||||
path = ctx.ros_root
|
||||
if os.path.basename(os.path.normpath(path)) not in ['ros', 'rosbuild']:
|
||||
return "ROS_ROOT [%s] must end in directory named 'ros'"%path
|
||||
|
||||
def _writable_dir_check(ctx, path, name):
|
||||
"""
|
||||
If path is not None, validate that it is a writable directory
|
||||
"""
|
||||
if path is None:
|
||||
return
|
||||
if isfile(path):
|
||||
return "%s [%s] must point to a directory, not a file"%(name, path)
|
||||
if not os.access(path, os.W_OK):
|
||||
return "%s [%s] is not writable"%(name, path)
|
||||
|
||||
def ros_home_check(ctx):
|
||||
return _writable_dir_check(ctx, ctx.env.get('ROS_HOME', None), 'ROS_HOME')
|
||||
def ros_log_dir_check(ctx):
|
||||
return _writable_dir_check(ctx, ctx.env.get('ROS_LOG_DIR', None), 'ROS_LOG_DIR')
|
||||
def ros_test_results_dir_check(ctx):
|
||||
return _writable_dir_check(ctx, ctx.env.get('ROS_TEST_RESULTS_DIR', None), 'ROS_TEST_RESULTS_DIR')
|
||||
|
||||
def pythonpath_check(ctx):
|
||||
# used to have a lot more checks here, but trying to phase out need for roslib on custom PYTHONPATH
|
||||
path = ctx.pythonpath
|
||||
roslib_count = len(set([p for p in paths(path) if 'roslib' in p.split(os.sep)]))
|
||||
if roslib_count > 1:
|
||||
return "Multiple roslib directories in PYTHONPATH (there should only be one)"
|
||||
|
||||
def rosconsole_config_file_check(ctx):
|
||||
if 'ROSCONSOLE_CONFIG_FILE' in ctx.env:
|
||||
return not isfile(ctx.env['ROSCONSOLE_CONFIG_FILE'])
|
||||
|
||||
def path_check(ctx):
|
||||
# rosdeb setup can clobber local ros stuff, so try and detect this
|
||||
path = ctx.env['PATH']
|
||||
idx = path.find('/usr/bin')
|
||||
if idx < 0:
|
||||
return
|
||||
if os.path.exists('/usr/lib/ros/'):
|
||||
rr_idx = path.find(ctx.ros_root)
|
||||
if rr_idx > -1 and rr_idx > idx:
|
||||
return True
|
||||
|
||||
def ros_master_uri_hostname(ctx):
|
||||
uri = ctx.ros_master_uri
|
||||
parsed = urlparse(uri)
|
||||
p = urlparse(uri)
|
||||
if not p[1]:
|
||||
return #caught by different rule
|
||||
if not ':' in p[1]:
|
||||
return #caught by different rule
|
||||
try:
|
||||
splits = p[1].split(':')
|
||||
if len(splits) != 2:
|
||||
return #caught by different rule
|
||||
#TODO IPV6: only check for IPv6 when IPv6 is enabled
|
||||
socket.getaddrinfo(splits[0], 0, 0, 0, socket.SOL_TCP)
|
||||
|
||||
except socket.gaierror:
|
||||
return "Unknown host %s"%splits[0]
|
||||
|
||||
# Error/Warning Rules
|
||||
|
||||
environment_warnings = [
|
||||
(path_check,
|
||||
"PATH has /usr/bin set before ROS_ROOT/bin, which can cause problems as there is system install of ROS on this machine. You may wish to put ROS_ROOT/bin first"),
|
||||
(lambda ctx: ctx.ros_package_path is None,
|
||||
"ROS_PACKAGE_PATH is not set. This is not required, but is unusual"),
|
||||
(lambda ctx: len(paths(ctx.ros_package_path)) == 0,
|
||||
"ROS_PACKAGE_PATH is empty. This is not required, but is unusual"),
|
||||
(lambda ctx: not ctx.ros_master_uri,
|
||||
"ROS_MASTER_URI is empty. This is not required, but is unusual"),
|
||||
(ros_master_uri_hostname,
|
||||
"Cannot resolve hostname in ROS_MASTER_URI [%(ros_master_uri)s]"),
|
||||
(rosconsole_config_file_check,
|
||||
"ROS_CONSOLE_CONFIG_FILE does not point to an existing file"),
|
||||
]
|
||||
|
||||
environment_errors = [
|
||||
# ROS_ROOT
|
||||
(lambda ctx: not isdir(ctx.ros_root),
|
||||
"ROS_ROOT [%(ros_root)s] does not point to a directory"),
|
||||
(ros_root_check,
|
||||
"ROS_ROOT is invalid: "),
|
||||
|
||||
# ROS_PACKAGE_PATH
|
||||
(lambda ctx: [d for d in paths(ctx.ros_package_path) if d and isfile(d)],
|
||||
"Path(s) in ROS_PACKAGE_PATH [%(ros_package_path)s] points to a file instead of a directory: "),
|
||||
(lambda ctx: [d for d in paths(ctx.ros_package_path) if d and not isdir(d) and not (os.path.basename(d) == 'stacks' and os.path.exists(os.path.join(os.path.dirname(d), '.catkin')))],
|
||||
"Not all paths in ROS_PACKAGE_PATH [%(ros_package_path)s] point to an existing directory: "),
|
||||
|
||||
# PYTHONPATH
|
||||
(lambda ctx: [d for d in paths(ctx.pythonpath) if d and not isdir(d)],
|
||||
"Not all paths in PYTHONPATH [%(pythonpath)s] point to a directory: "),
|
||||
(pythonpath_check,
|
||||
"PYTHONPATH [%(pythonpath)s] is invalid: "),
|
||||
|
||||
# ROS_HOME, ROS_LOG_DIR, ROS_TEST_RESULTS_DIR
|
||||
(ros_home_check, "ROS_HOME is invalid: "),
|
||||
(ros_log_dir_check, "ROS_LOG_DIR is invalid: "),
|
||||
(ros_test_results_dir_check, "ROS_TEST_RESULTS_DIR is invalid: "),
|
||||
|
||||
(lambda ctx: invalid_url(ctx.ros_master_uri),
|
||||
"ROS_MASTER_URI [%(ros_master_uri)s] is not a valid URL: "),
|
||||
|
||||
]
|
||||
|
||||
def wtf_check_environment(ctx):
|
||||
#TODO: check ROS_BOOST_ROOT
|
||||
for r in environment_warnings:
|
||||
warning_rule(r, r[0](ctx), ctx)
|
||||
for r in environment_errors:
|
||||
error_rule(r, r[0](ctx), ctx)
|
||||
|
||||
417
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/graph.py
vendored
Normal file
417
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/graph.py
vendored
Normal file
@@ -0,0 +1,417 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Revision $Id$
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import with_statement
|
||||
|
||||
import os
|
||||
import itertools
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
try:
|
||||
from xmlrpc.client import ServerProxy
|
||||
except ImportError:
|
||||
from xmlrpclib import ServerProxy
|
||||
|
||||
import rospkg.environment
|
||||
|
||||
import rosgraph
|
||||
import rosgraph.rosenv
|
||||
import rosgraph.network
|
||||
|
||||
import rosnode
|
||||
import rosservice
|
||||
|
||||
from roswtf.context import WtfException
|
||||
from roswtf.environment import paths, is_executable
|
||||
from roswtf.model import WtfWarning, WtfError
|
||||
from roswtf.rules import warning_rule, error_rule
|
||||
|
||||
def _businfo(ctx, node, bus_info):
|
||||
# [[connectionId1, destinationId1, direction1, transport1, ...]... ]
|
||||
edges = []
|
||||
for info in bus_info:
|
||||
#connection_id = info[0]
|
||||
dest_id = info[1]
|
||||
if dest_id.startswith('http://'):
|
||||
if dest_id in ctx.uri_node_map:
|
||||
dest_id = ctx.uri_node_map[dest_id]
|
||||
else:
|
||||
dest_id = 'unknown (%s)'%dest_id
|
||||
direction = info[2]
|
||||
#transport = info[3]
|
||||
topic = info[4]
|
||||
if len(info) > 5:
|
||||
connected = info[5]
|
||||
else:
|
||||
connected = True #backwards compatibility
|
||||
|
||||
if connected:
|
||||
if direction == 'i':
|
||||
edges.append((topic, dest_id, node))
|
||||
elif direction == 'o':
|
||||
edges.append((topic, node, dest_id))
|
||||
elif direction == 'b':
|
||||
print("cannot handle bidirectional edges", file=sys.stderr)
|
||||
else:
|
||||
raise Exception()
|
||||
|
||||
return edges
|
||||
|
||||
def unexpected_edges(ctx):
|
||||
if not ctx.system_state or not ctx.nodes:
|
||||
return
|
||||
unexpected = set(ctx.actual_edges) - set(ctx.expected_edges)
|
||||
return ["%s->%s (%s)"%(p, s, t) for (t, p, s) in unexpected]
|
||||
|
||||
def missing_edges(ctx):
|
||||
if not ctx.system_state or not ctx.nodes:
|
||||
return
|
||||
missing = set(ctx.expected_edges) - set(ctx.actual_edges)
|
||||
return ["%s->%s (%s)"%(p, s, t) for (t, p, s) in missing]
|
||||
|
||||
def ping_check(ctx):
|
||||
if not ctx.system_state or not ctx.nodes:
|
||||
return
|
||||
_, unpinged = rosnode.rosnode_ping_all()
|
||||
return unpinged
|
||||
|
||||
def simtime_check(ctx):
|
||||
if ctx.use_sim_time:
|
||||
master = rosgraph.Master('/roswtf')
|
||||
try:
|
||||
pubtopics = master.getPublishedTopics('/')
|
||||
except rosgraph.MasterException:
|
||||
ctx.errors.append(WtfError("Cannot talk to ROS master"))
|
||||
raise WtfException("roswtf lost connection to the ROS Master at %s"%rosgraph.rosenv.get_master_uri())
|
||||
|
||||
for topic, _ in pubtopics:
|
||||
if topic in ['/time', '/clock']:
|
||||
return
|
||||
return True
|
||||
|
||||
## contact each service and make sure it returns a header
|
||||
def probe_all_services(ctx):
|
||||
master = rosgraph.Master('/roswtf')
|
||||
errors = []
|
||||
for service_name in ctx.services:
|
||||
try:
|
||||
service_uri = master.lookupService(service_name)
|
||||
except:
|
||||
ctx.errors.append(WtfError("cannot contact ROS Master at %s"%rosgraph.rosenv.get_master_uri()))
|
||||
raise WtfException("roswtf lost connection to the ROS Master at %s"%rosgraph.rosenv.get_master_uri())
|
||||
|
||||
try:
|
||||
headers = rosservice.get_service_headers(service_name, service_uri)
|
||||
if not headers:
|
||||
errors.append("service [%s] did not return service headers"%service_name)
|
||||
except rosgraph.network.ROSHandshakeException as e:
|
||||
errors.append("service [%s] appears to be malfunctioning"%service_name)
|
||||
except Exception as e:
|
||||
errors.append("service [%s] appears to be malfunctioning: %s"%(service_name, e))
|
||||
return errors
|
||||
|
||||
def unconnected_subscriptions(ctx):
|
||||
ret = ''
|
||||
whitelist = ['/reset_time']
|
||||
if ctx.use_sim_time:
|
||||
for sub, l in ctx.unconnected_subscriptions.items():
|
||||
l = [t for t in l if t not in whitelist]
|
||||
if l:
|
||||
ret += ' * %s:\n'%sub
|
||||
ret += ''.join([" * %s\n"%t for t in l])
|
||||
else:
|
||||
for sub, l in ctx.unconnected_subscriptions.items():
|
||||
l = [t for t in l if t not in ['/time', '/clock']]
|
||||
if l:
|
||||
ret += ' * %s:\n'%sub
|
||||
ret += ''.join([" * %s\n"%t for t in l])
|
||||
return ret
|
||||
|
||||
graph_warnings = [
|
||||
(unconnected_subscriptions, "The following node subscriptions are unconnected:\n"),
|
||||
(unexpected_edges, "The following nodes are unexpectedly connected:"),
|
||||
]
|
||||
|
||||
graph_errors = [
|
||||
(simtime_check, "/use_simtime is set but no publisher of /clock is present"),
|
||||
(ping_check, "Could not contact the following nodes:"),
|
||||
(missing_edges, "The following nodes should be connected but aren't:"),
|
||||
(probe_all_services, "Errors connecting to the following services:"),
|
||||
]
|
||||
|
||||
def topic_timestamp_drift(ctx, t):
|
||||
#TODO: get msg_class, if msg_class has header, receive a message
|
||||
# and compare its time to ros time
|
||||
if 0:
|
||||
rospy.Subscriber(t, msg_class)
|
||||
|
||||
#TODO: these are mainly future enhancements. It's unclear to me whether or not this will be
|
||||
#useful as most of the generic rules are capable of targetting these problems as well.
|
||||
#The only rule that in particular seems useful is the timestamp drift. It may be too
|
||||
#expensive otherwise to run, though it would be interesting to attempt to receive a
|
||||
#message from every single topic.
|
||||
|
||||
#TODO: parameter audit?
|
||||
service_errors = [
|
||||
]
|
||||
service_warnings = [
|
||||
]
|
||||
topic_errors = [
|
||||
(topic_timestamp_drift, "Timestamp drift:")
|
||||
]
|
||||
topic_warnings = [
|
||||
]
|
||||
node_errors = [
|
||||
]
|
||||
node_warnings = [
|
||||
]
|
||||
|
||||
## cache sim_time calculation sot that multiple rules can use
|
||||
def _compute_sim_time(ctx):
|
||||
param_server = rosgraph.Master('/roswtf')
|
||||
ctx.use_sim_time = False
|
||||
try:
|
||||
val = simtime = param_server.getParam('/use_sim_time')
|
||||
if val:
|
||||
ctx.use_sim_time = True
|
||||
except:
|
||||
pass
|
||||
|
||||
def _compute_system_state(ctx):
|
||||
socket.setdefaulttimeout(3.0)
|
||||
master = rosgraph.Master('/roswtf')
|
||||
|
||||
# store system state
|
||||
try:
|
||||
val = master.getSystemState()
|
||||
except rosgraph.MasterException:
|
||||
return
|
||||
ctx.system_state = val
|
||||
|
||||
pubs, subs, srvs = val
|
||||
|
||||
# compute list of topics and services
|
||||
topics = []
|
||||
for t, _ in itertools.chain(pubs, subs):
|
||||
topics.append(t)
|
||||
services = []
|
||||
service_providers = []
|
||||
for s, l in srvs:
|
||||
services.append(s)
|
||||
service_providers.extend(l)
|
||||
ctx.topics = topics
|
||||
ctx.services = services
|
||||
ctx.service_providers = service_providers
|
||||
|
||||
# compute list of nodes
|
||||
nodes = []
|
||||
for s in val:
|
||||
for t, l in s:
|
||||
nodes.extend(l)
|
||||
ctx.nodes = list(set(nodes)) #uniq
|
||||
|
||||
# - compute reverse mapping of URI->nodename
|
||||
count = 0
|
||||
start = time.time()
|
||||
for n in ctx.nodes:
|
||||
count += 1
|
||||
try:
|
||||
val = master.lookupNode(n)
|
||||
except socket.error:
|
||||
ctx.errors.append(WtfError("cannot contact ROS Master at %s"%rosgraph.rosenv.get_master_uri()))
|
||||
raise WtfException("roswtf lost connection to the ROS Master at %s"%rosgraph.rosenv.get_master_uri())
|
||||
ctx.uri_node_map[val] = n
|
||||
end = time.time()
|
||||
# - time thresholds currently very arbitrary
|
||||
if count:
|
||||
if ((end - start) / count) > 1.:
|
||||
ctx.warnings.append(WtfError("Communication with master is very slow (>1s average)"))
|
||||
elif (end - start) / count > .5:
|
||||
ctx.warnings.append(WtfWarning("Communication with master is very slow (>0.5s average)"))
|
||||
|
||||
import threading
|
||||
class NodeInfoThread(threading.Thread):
|
||||
def __init__(self, n, ctx, master, actual_edges, lock):
|
||||
threading.Thread.__init__(self)
|
||||
self.master = master
|
||||
self.actual_edges = actual_edges
|
||||
self.lock = lock
|
||||
self.n = n
|
||||
self.done = False
|
||||
self.ctx = ctx
|
||||
|
||||
def run(self):
|
||||
ctx = self.ctx
|
||||
master = self.master
|
||||
actual_edges = self.actual_edges
|
||||
lock = self.lock
|
||||
n = self.n
|
||||
|
||||
try:
|
||||
socket.setdefaulttimeout(3.0)
|
||||
with lock: #Apparently get_api_uri is not thread safe...
|
||||
node_api = rosnode.get_api_uri(master, n)
|
||||
|
||||
|
||||
if not node_api:
|
||||
with lock:
|
||||
ctx.errors.append(WtfError("Master does not have lookup information for node [%s]"%n))
|
||||
return
|
||||
|
||||
node = ServerProxy(node_api)
|
||||
start = time.time()
|
||||
socket.setdefaulttimeout(3.0)
|
||||
code, msg, bus_info = node.getBusInfo('/roswtf')
|
||||
end = time.time()
|
||||
with lock:
|
||||
if (end-start) > 1.:
|
||||
ctx.warnings.append(WtfWarning("Communication with node [%s] is very slow"%n))
|
||||
if code != 1:
|
||||
ctx.warnings.append(WtfWarning("Node [%s] would not return bus info"%n))
|
||||
elif not bus_info:
|
||||
if not n in ctx.service_providers:
|
||||
ctx.warnings.append(WtfWarning("Node [%s] is not connected to anything"%n))
|
||||
else:
|
||||
edges = _businfo(ctx, n, bus_info)
|
||||
actual_edges.extend(edges)
|
||||
except socket.error:
|
||||
pass #ignore as we have rules to catch this
|
||||
except Exception as e:
|
||||
ctx.errors.append(WtfError("Communication with [%s] raised an error: %s"%(n, str(e))))
|
||||
finally:
|
||||
self.done = True
|
||||
|
||||
|
||||
## retrieve graph state from master and related nodes once so we don't overload
|
||||
## the network
|
||||
def _compute_connectivity(ctx):
|
||||
socket.setdefaulttimeout(3.0)
|
||||
master = rosgraph.Master('/roswtf')
|
||||
|
||||
# Compute list of expected edges and unconnected subscriptions
|
||||
pubs, subs, _ = ctx.system_state
|
||||
expected_edges = [] # [(topic, publisher, subscriber),]
|
||||
unconnected_subscriptions = {} # { subscriber : [topics] }
|
||||
|
||||
# - build up a dictionary of publishers keyed by topic
|
||||
pub_dict = {}
|
||||
for t, pub_list in pubs:
|
||||
pub_dict[t] = pub_list
|
||||
# - iterate through subscribers and add edge to each publisher of topic
|
||||
for t, sub_list in subs:
|
||||
for sub in sub_list:
|
||||
if t in pub_dict:
|
||||
expected_edges.extend([(t, pub, sub) for pub in pub_dict[t]])
|
||||
elif sub in unconnected_subscriptions:
|
||||
unconnected_subscriptions[sub].append(t)
|
||||
else:
|
||||
unconnected_subscriptions[sub] = [t]
|
||||
|
||||
# compute actual edges
|
||||
actual_edges = []
|
||||
lock = threading.Lock()
|
||||
threads = []
|
||||
for n in ctx.nodes:
|
||||
t =NodeInfoThread(n, ctx, master, actual_edges, lock)
|
||||
threads.append(t)
|
||||
t.start()
|
||||
|
||||
# spend up to a minute waiting for threads to complete. each
|
||||
# thread has a 3-second timeout, but this will spike load
|
||||
timeout_t = time.time() + 60.0
|
||||
while time.time() < timeout_t and [t for t in threads if not t.done]:
|
||||
time.sleep(0.5)
|
||||
|
||||
ctx.expected_edges = expected_edges
|
||||
ctx.actual_edges = actual_edges
|
||||
ctx.unconnected_subscriptions = unconnected_subscriptions
|
||||
|
||||
def _compute_online_context(ctx):
|
||||
# have to compute sim time first
|
||||
_compute_sim_time(ctx)
|
||||
_compute_system_state(ctx)
|
||||
_compute_connectivity(ctx)
|
||||
|
||||
def wtf_check_graph(ctx, names=None):
|
||||
master_uri = ctx.ros_master_uri
|
||||
#TODO: master rules
|
||||
# - check for stale master state
|
||||
|
||||
# TODO: get the type for each topic from each publisher and see if they match up
|
||||
|
||||
master = rosgraph.Master('/roswtf')
|
||||
try:
|
||||
master.getPid()
|
||||
except rospkg.MasterException:
|
||||
warning_rule((True, "Cannot communicate with master, ignoring online checks"), True, ctx)
|
||||
return
|
||||
|
||||
# fill in ctx info so we only have to compute once
|
||||
print("analyzing graph...")
|
||||
_compute_online_context(ctx)
|
||||
print("... done analyzing graph")
|
||||
|
||||
if names:
|
||||
check_topics = [t for t in names if t in ctx.topics]
|
||||
check_services = [t for t in names if t in ctx.services]
|
||||
check_nodes = [t for t in names if t in ctx.nodes]
|
||||
unknown = [t for t in names if t not in check_topics + check_services + check_nodes]
|
||||
if unknown:
|
||||
raise WtfException("The following names were not found in the list of nodes, topics, or services:\n%s"%(''.join([" * %s\n"%t for t in unknown])))
|
||||
|
||||
for t in check_topics:
|
||||
for r in topic_warnings:
|
||||
warning_rule(r, r[0](ctx, t), ctx)
|
||||
for r in topic_errors:
|
||||
error_rule(r, r[0](ctx, t), ctx)
|
||||
for s in check_services:
|
||||
for r in service_warnings:
|
||||
warning_rule(r, r[0](ctx, s), ctx)
|
||||
for r in service_errors:
|
||||
error_rule(r, r[0](ctx, s), ctx)
|
||||
for n in check_nodes:
|
||||
for r in node_warnings:
|
||||
warning_rule(r, r[0](ctx, n), ctx)
|
||||
for r in node_errors:
|
||||
error_rule(r, r[0](ctx, n), ctx)
|
||||
|
||||
|
||||
print("running graph rules...")
|
||||
for r in graph_warnings:
|
||||
warning_rule(r, r[0](ctx), ctx)
|
||||
for r in graph_errors:
|
||||
error_rule(r, r[0](ctx), ctx)
|
||||
print("... done running graph rules")
|
||||
63
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/model.py
vendored
Normal file
63
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/model.py
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Revision $Id$
|
||||
|
||||
"""
|
||||
Error and Warning representation. The roswtf.rules module simplifies
|
||||
the process of creating instances of L{WtfError}s and L{WtfWarning}s,
|
||||
but these objects can be used directly if desired.
|
||||
"""
|
||||
|
||||
class WtfError(object):
|
||||
def __init__(self, msg, format_msg=None, return_val=None):
|
||||
self.msg = msg
|
||||
if format_msg is None:
|
||||
self.format_msg = msg
|
||||
else:
|
||||
self.format_msg = format_msg
|
||||
if return_val is None:
|
||||
self.return_val = True
|
||||
else:
|
||||
self.return_val = return_val
|
||||
|
||||
class WtfWarning(object):
|
||||
def __init__(self, msg, format_msg=None, return_val=None):
|
||||
self.msg = msg
|
||||
if format_msg is None:
|
||||
self.format_msg = msg
|
||||
else:
|
||||
self.format_msg = format_msg
|
||||
if return_val is None:
|
||||
self.return_val = True
|
||||
else:
|
||||
self.return_val = return_val
|
||||
114
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/network.py
vendored
Normal file
114
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/network.py
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Revision $Id: environment.py 4428 2009-05-05 05:48:36Z jfaustwg $
|
||||
|
||||
import os
|
||||
import socket
|
||||
import stat
|
||||
import string
|
||||
import sys
|
||||
|
||||
import rosgraph
|
||||
import rosgraph.network
|
||||
|
||||
from roswtf.rules import warning_rule, error_rule
|
||||
|
||||
# #1220
|
||||
def ip_check(ctx):
|
||||
# best we can do is compare roslib's routine against socket resolution and make sure they agree
|
||||
local_addrs = rosgraph.network.get_local_addresses()
|
||||
|
||||
resolved_ips = [host[4][0] for host in socket.getaddrinfo(socket.gethostname(), 0, 0, 0, socket.SOL_TCP)]
|
||||
global_ips = [ ip for ip in resolved_ips if not ip.startswith('127.') and not ip == '::1']
|
||||
|
||||
remote_ips = list(set(global_ips) - set(local_addrs))
|
||||
if remote_ips:
|
||||
retval = "Local hostname [%s] resolves to [%s], which does not appear to be a local IP address %s." % (socket.gethostname(), ','.join(remote_ips), str(local_addrs))
|
||||
# IPv6 support % to denote zone/scope ids. The value is expanded
|
||||
# in other functions, this is why we are using replace command in
|
||||
# the return. For more info https://github.com/ros/ros_comm/pull/598
|
||||
return retval.replace('%', '%%')
|
||||
|
||||
# suggestion by mquigley based on laptop dhcp issues
|
||||
def ros_hostname_check(ctx):
|
||||
"""Make sure that ROS_HOSTNAME resolves to a local IP address"""
|
||||
if not rosgraph.ROS_HOSTNAME in ctx.env:
|
||||
return
|
||||
|
||||
hostname = ctx.env[rosgraph.ROS_HOSTNAME]
|
||||
try:
|
||||
resolved_ips = [host[4][0] for host in socket.getaddrinfo(hostname, 0, 0, 0, socket.SOL_TCP)]
|
||||
except socket.gaierror:
|
||||
return "ROS_HOSTNAME [%s] cannot be resolved to an IP address"%(hostname)
|
||||
|
||||
# best we can do is compare roslib's routine against socket resolution and make sure they agree
|
||||
local_addrs = rosgraph.network.get_local_addresses()
|
||||
|
||||
remote_ips = list(set(resolved_ips) - set(local_addrs))
|
||||
if remote_ips:
|
||||
return "ROS_HOSTNAME [%s] resolves to [%s], which does not appear to be a local IP address %s."%(hostname, ','.join(remote_ips), str(local_addrs))
|
||||
|
||||
def ros_ip_check(ctx):
|
||||
"""Make sure that ROS_IP is a local IP address"""
|
||||
if not rosgraph.ROS_IP in ctx.env:
|
||||
return
|
||||
|
||||
ip = ctx.env[rosgraph.ROS_IP]
|
||||
|
||||
# best we can do is compare roslib's routine against socket resolution and make sure they agree
|
||||
addrs = rosgraph.network.get_local_addresses()
|
||||
|
||||
if ip not in addrs:
|
||||
return "ROS_IP [%s] does not appear to be a local IP address %s."%(ip, str(addrs))
|
||||
|
||||
# Error/Warning Rules
|
||||
|
||||
warnings = [
|
||||
(ros_hostname_check,
|
||||
"ROS_HOSTNAME may be incorrect: "),
|
||||
(ros_ip_check,
|
||||
"ROS_IP may be incorrect: "),
|
||||
|
||||
]
|
||||
|
||||
errors = [
|
||||
(ip_check,
|
||||
"Local network configuration is invalid: "),
|
||||
]
|
||||
|
||||
def wtf_check(ctx):
|
||||
for r in warnings:
|
||||
warning_rule(r, r[0](ctx), ctx)
|
||||
for r in errors:
|
||||
error_rule(r, r[0](ctx), ctx)
|
||||
|
||||
199
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/packages.py
vendored
Normal file
199
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/packages.py
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Revision $Id$
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
from roswtf.environment import paths, is_executable
|
||||
from roswtf.rules import warning_rule, error_rule
|
||||
|
||||
import roslib.msgs
|
||||
import roslib.srvs
|
||||
from roslib.packages import get_pkg_dir, InvalidROSPkgException, PACKAGE_FILE
|
||||
|
||||
## look for unknown tags in manifest
|
||||
def manifest_valid(ctx):
|
||||
errors = []
|
||||
if ctx.manifest is not None:
|
||||
errors = ["<%s>"%t.tagName for t in ctx.manifest.unknown_tags]
|
||||
return errors
|
||||
|
||||
def _manifest_msg_srv_export(ctx, type_):
|
||||
exist = []
|
||||
for pkg in ctx.pkgs:
|
||||
pkg_dir = roslib.packages.get_pkg_dir(pkg)
|
||||
d = os.path.join(pkg_dir, type_)
|
||||
if os.path.isdir(d):
|
||||
files = os.listdir(d)
|
||||
if filter(lambda x: x.endswith('.'+type_), files):
|
||||
try:
|
||||
m_file = roslib.manifest.manifest_file(pkg, True)
|
||||
except InvalidROSPkgException:
|
||||
# ignore wet package from further investigation
|
||||
env = os.environ
|
||||
pkg_path = get_pkg_dir(pkg, True, ros_root=env['ROS_ROOT'])
|
||||
if os.path.exists(os.path.join(pkg_path, PACKAGE_FILE)):
|
||||
continue
|
||||
raise
|
||||
m = roslib.manifest.parse_file(m_file)
|
||||
cflags = m.get_export('cpp', 'cflags')
|
||||
include = '-I${prefix}/%s/cpp'%type_
|
||||
if filter(lambda x: include in x, cflags):
|
||||
exist.append(pkg)
|
||||
return exist
|
||||
|
||||
def manifest_msg_srv_export(ctx):
|
||||
msgs = set(_manifest_msg_srv_export(ctx, 'msg'))
|
||||
srvs = set(_manifest_msg_srv_export(ctx, 'srv'))
|
||||
errors = []
|
||||
|
||||
for pkg in msgs & srvs:
|
||||
errors.append('%s: -I${prefix}/msg/cpp -I${prefix}/srv/cpp'%pkg)
|
||||
for pkg in msgs - srvs:
|
||||
errors.append('%s: -I${prefix}/msg/cpp'%pkg)
|
||||
for pkg in srvs - msgs:
|
||||
errors.append('%s: -I${prefix}/srv/cpp'%pkg)
|
||||
return errors
|
||||
|
||||
|
||||
def _check_for_rpath_flags(pkg, lflags):
|
||||
if not lflags:
|
||||
return
|
||||
L_arg = '-L'
|
||||
Wl_arg = '-Wl'
|
||||
rpath_arg = '-rpath'
|
||||
lflags_args = lflags.split()
|
||||
# Collect the args we care about
|
||||
L_args = []
|
||||
rpath_args = []
|
||||
i = 0
|
||||
while i < len(lflags_args):
|
||||
f = lflags_args[i]
|
||||
if f.startswith(L_arg) and len(f) > len(L_arg):
|
||||
# normpath avoids problems with trailing slash vs. no trailing
|
||||
# slash, #2284
|
||||
L_args.append(os.path.normpath(f[len(L_arg):]))
|
||||
elif f == L_arg and (i+1) < len(lflags_args):
|
||||
i += 1
|
||||
# normpath avoids problems with trailing slash vs. no trailing
|
||||
# slash, #2284
|
||||
L_args.append(os.path.normpath(lflags_args[i]))
|
||||
elif f.startswith(Wl_arg) and len(f) > len(Wl_arg):
|
||||
# -Wl can be followed by multiple, comma-separated arguments,
|
||||
# #2284.
|
||||
args = f.split(',')
|
||||
j = 1
|
||||
while j < (len(args) - 1):
|
||||
if args[j] == rpath_arg:
|
||||
# normpath avoids problems with trailing slash vs. no trailing
|
||||
# slash, #2284
|
||||
rpath_args.append(os.path.normpath(args[j+1]))
|
||||
j += 2
|
||||
else:
|
||||
j += 1
|
||||
i += 1
|
||||
# Check for parallelism; not efficient, but these strings are short
|
||||
for f in L_args:
|
||||
if f not in rpath_args:
|
||||
return '%s: found flag "-L%s", but no matching "-Wl,-rpath,%s"'%(pkg, f,f)
|
||||
for f in rpath_args:
|
||||
if f not in L_args:
|
||||
return '%s: found flag "-Wl,-rpath,%s", but no matching "-L%s"'%(pkg, f,f)
|
||||
|
||||
def manifest_rpath_flags(ctx):
|
||||
warn = []
|
||||
for pkg in ctx.pkgs:
|
||||
# Use rospack to get lflags, so that they can be bash-expanded
|
||||
# first, #2286.
|
||||
import subprocess
|
||||
lflags = subprocess.Popen(['rospack', 'export', '--lang=cpp', '--attrib=lflags', pkg], stdout=subprocess.PIPE).communicate()[0]
|
||||
err_msg = _check_for_rpath_flags(pkg, lflags)
|
||||
if err_msg:
|
||||
warn.append(err_msg)
|
||||
return warn
|
||||
|
||||
def cmakelists_package_valid(ctx):
|
||||
missing = []
|
||||
for pkg in ctx.pkgs:
|
||||
found = False
|
||||
pkg_dir = roslib.packages.get_pkg_dir(pkg)
|
||||
p = os.path.join(pkg_dir, 'CMakeLists.txt')
|
||||
if not os.path.isfile(p):
|
||||
continue #covered by cmakelists_exists
|
||||
f = open(p)
|
||||
try:
|
||||
for l in f:
|
||||
# ignore all whitespace
|
||||
l = l.strip().replace(' ', '')
|
||||
|
||||
if l.startswith('rospack('):
|
||||
found = True
|
||||
if not l.startswith('rospack(%s)'%pkg):
|
||||
missing.append(pkg)
|
||||
break
|
||||
# there may be more than 1 rospack() declaration, so scan through entire
|
||||
# CMakeLists
|
||||
elif l.startswith("rosbuild_init()"):
|
||||
found = True
|
||||
finally:
|
||||
f.close()
|
||||
# rospack exists outside our build system
|
||||
if 'rospack' in missing:
|
||||
missing.remove('rospack')
|
||||
return missing
|
||||
|
||||
warnings = [
|
||||
# disabling as it is too common and regular
|
||||
(cmakelists_package_valid,
|
||||
"The following packages have incorrect rospack() declarations in CMakeLists.txt.\nPlease switch to using rosbuild_init():"),
|
||||
|
||||
(manifest_msg_srv_export,
|
||||
'The following packages have msg/srv-related cflags exports that are no longer necessary\n\t<export>\n\t\t<cpp cflags="..."\n\t</export>:'),
|
||||
(manifest_valid, "%(pkg)s/manifest.xml has unrecognized tags:"),
|
||||
|
||||
]
|
||||
errors = [
|
||||
(manifest_rpath_flags, "The following packages have rpath issues in manifest.xml:"),
|
||||
]
|
||||
|
||||
def wtf_check(ctx):
|
||||
# no package in context to verify
|
||||
if not ctx.pkgs:
|
||||
return
|
||||
|
||||
for r in warnings:
|
||||
warning_rule(r, r[0](ctx), ctx)
|
||||
for r in errors:
|
||||
error_rule(r, r[0](ctx), ctx)
|
||||
|
||||
95
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/plugins.py
vendored
Normal file
95
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/plugins.py
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Revision $Id$
|
||||
|
||||
"""
|
||||
Plugin loader for roswtf.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import roslib
|
||||
import rospkg
|
||||
|
||||
def load_plugins():
|
||||
"""
|
||||
@return: list of static roswtf plugins, list of online
|
||||
roswtf plugins
|
||||
@rtype: [fn], [fn]
|
||||
"""
|
||||
rospack = rospkg.RosPack()
|
||||
to_check = rospack.get_depends_on('roswtf', implicit=False)
|
||||
static_plugins = []
|
||||
online_plugins = []
|
||||
for pkg in to_check:
|
||||
m = rospack.get_manifest(pkg)
|
||||
p_module = m.get_export('roswtf', 'plugin')
|
||||
if not p_module:
|
||||
continue
|
||||
elif len(p_module) != 1:
|
||||
print("Cannot load plugin [%s]: invalid 'plugin' attribute"%(pkg), file=sys.stderr)
|
||||
continue
|
||||
p_module = p_module[0]
|
||||
try:
|
||||
# load that packages namespace
|
||||
roslib.load_manifest(pkg)
|
||||
|
||||
# import the specified plugin module
|
||||
mod = __import__(p_module)
|
||||
for sub_mod in p_module.split('.')[1:]:
|
||||
mod = getattr(mod, sub_mod)
|
||||
|
||||
# retrieve the roswtf_plugin_static and roswtf_plugin_online functions
|
||||
s_attr = o_attr = None
|
||||
try:
|
||||
s_attr = getattr(mod, 'roswtf_plugin_static')
|
||||
except AttributeError: pass
|
||||
try:
|
||||
o_attr = getattr(mod, 'roswtf_plugin_online')
|
||||
except AttributeError: pass
|
||||
if s_attr:
|
||||
static_plugins.append(s_attr)
|
||||
if o_attr:
|
||||
online_plugins.append(o_attr)
|
||||
if s_attr is None and o_attr is None:
|
||||
print("Cannot load plugin [%s]: no 'roswtf_plugin_static' or 'roswtf_plugin_online' attributes [%s]"%(p_module), file=sys.stderr)
|
||||
else:
|
||||
print("Loaded plugin", p_module)
|
||||
|
||||
except Exception:
|
||||
print("Unable to load plugin [%s] from package [%s]"%(p_module, pkg), file=sys.stderr)
|
||||
return static_plugins, online_plugins
|
||||
|
||||
170
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/py_pip_deb_checks.py
vendored
Normal file
170
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/py_pip_deb_checks.py
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2012, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
Checks to see if core Python scripts have:
|
||||
1) Been installed
|
||||
2) Have been installed via Debians on Ubuntu
|
||||
3) Have not been installed via pip on Ubuntu
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import subprocess
|
||||
import importlib
|
||||
import os
|
||||
import sys
|
||||
|
||||
python_prefix = 'python'
|
||||
if sys.version_info[0] == 3:
|
||||
python_prefix += '3'
|
||||
|
||||
#A dictionary of core ROS python packages and their corresponding .deb packages
|
||||
py_to_deb_core_packages = {
|
||||
'catkin_pkg': '%s-catkin-pkg' % python_prefix,
|
||||
'rospkg': '%s-rospkg' % python_prefix,
|
||||
'rosdep2': '%s-rosdep' % python_prefix,
|
||||
}
|
||||
# optional ROS python packages and their corresponding .deb packages
|
||||
py_to_deb_optional_packages = {
|
||||
'rosinstall': '%s-rosinstall' % python_prefix,
|
||||
}
|
||||
|
||||
#A dictionary of release ROS python packages and their corresponding .deb packages
|
||||
py_to_deb_release_packages = {
|
||||
'bloom': '%s-bloom' % python_prefix,
|
||||
'rosrelease': '%s-rosrelease' % python_prefix,
|
||||
}
|
||||
|
||||
|
||||
def get_host_os():
|
||||
"""Determines the name of the host operating system"""
|
||||
import rospkg.os_detect
|
||||
os_detector = rospkg.os_detect.OsDetect()
|
||||
return (os_detector.detect_os())[0]
|
||||
|
||||
|
||||
def is_host_os_ubuntu():
|
||||
"""Indicates if the host operating system is Ubuntu"""
|
||||
return (get_host_os() == 'ubuntu')
|
||||
|
||||
|
||||
def is_debian_package_installed(deb_pkg):
|
||||
"""Uses dpkg to determine if a package has been installed"""
|
||||
return (subprocess.call(
|
||||
'dpkg -l ' + deb_pkg,
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE) == 0)
|
||||
|
||||
|
||||
def is_a_pip_path_on_ubuntu(path):
|
||||
"""Indicates if a path (either directory or file) is in the same place
|
||||
pip installs Python code"""
|
||||
return ('/usr/local' in path)
|
||||
|
||||
|
||||
def is_python_package_installed(python_pkg):
|
||||
"""Indicates if a Python package is importable in the current
|
||||
environment."""
|
||||
try:
|
||||
importlib.import_module(python_pkg)
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
|
||||
def is_python_package_installed_via_pip_on_ubuntu(python_pkg):
|
||||
"""Indicates if am importable package has been installed through pip on
|
||||
Ubuntu"""
|
||||
try:
|
||||
pkg_handle = importlib.import_module(python_pkg)
|
||||
return is_a_pip_path_on_ubuntu(pkg_handle.__file__)
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
|
||||
# Error/Warning Rules
|
||||
def python_module_install_check(ctx):
|
||||
"""Make sure core Python modules are installed"""
|
||||
warn_str = ''
|
||||
for py_pkg in py_to_deb_core_packages:
|
||||
if not is_python_package_installed(py_pkg):
|
||||
warn_str = warn_str + py_pkg + ' -- '
|
||||
if (warn_str != ''):
|
||||
return warn_str
|
||||
|
||||
|
||||
def deb_install_check_on_ubuntu(ctx):
|
||||
"""Make sure on Debian python packages are installed"""
|
||||
if (is_host_os_ubuntu()):
|
||||
warn_str = ''
|
||||
for py_pkg in py_to_deb_core_packages:
|
||||
deb_pkg = py_to_deb_core_packages[py_pkg]
|
||||
if not is_debian_package_installed(deb_pkg):
|
||||
warn_str = warn_str + py_pkg + ' (' + deb_pkg + ') -- '
|
||||
if (warn_str != ''):
|
||||
return warn_str
|
||||
|
||||
|
||||
def pip_install_check_on_ubuntu(ctx):
|
||||
"""Make sure on Ubuntu, Python packages are install with apt and not pip"""
|
||||
if (is_host_os_ubuntu()):
|
||||
warn_str = ''
|
||||
pt_to_deb_package_names = list(py_to_deb_core_packages.keys()) + \
|
||||
list(py_to_deb_optional_packages.keys()) + list(py_to_deb_release_packages.keys())
|
||||
for py_pkg in pt_to_deb_package_names:
|
||||
if is_python_package_installed_via_pip_on_ubuntu(py_pkg):
|
||||
warn_str = warn_str + py_pkg + ' -- '
|
||||
if (warn_str != ''):
|
||||
return warn_str
|
||||
|
||||
warnings = [
|
||||
(python_module_install_check,
|
||||
"You are missing core ROS Python modules: "),
|
||||
(pip_install_check_on_ubuntu,
|
||||
"You have pip installed packages on Ubuntu, "
|
||||
"remove and install using Debian packages: "),
|
||||
(deb_install_check_on_ubuntu,
|
||||
"You are missing Debian packages for core ROS Python modules: "),
|
||||
]
|
||||
|
||||
errors = []
|
||||
|
||||
|
||||
def wtf_check(ctx):
|
||||
"""Check implementation function for roswtf"""
|
||||
from roswtf.rules import warning_rule, error_rule
|
||||
for r in warnings:
|
||||
warning_rule(r, r[0](ctx), ctx)
|
||||
for r in errors:
|
||||
error_rule(r, r[0](ctx), ctx)
|
||||
63
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/rosdep_db.py
vendored
Normal file
63
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/rosdep_db.py
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2012, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
Checks if rosdep database has been initialized
|
||||
"""
|
||||
import os
|
||||
|
||||
|
||||
def get_user_home_directory():
|
||||
"""Returns cross-platform user home directory """
|
||||
return os.path.expanduser("~")
|
||||
|
||||
|
||||
def rosdep_database_updated_check(ctx):
|
||||
"""Makes sure rosdep database is updated"""
|
||||
if not os.path.exists((os.path.join(get_user_home_directory(), '.ros', 'rosdep', 'sources.cache', 'index'))):
|
||||
return "Please update rosdep database with 'rosdep update'."
|
||||
|
||||
|
||||
warnings = []
|
||||
|
||||
errors = [(rosdep_database_updated_check,
|
||||
"ROS Dep database not updated: "),
|
||||
]
|
||||
|
||||
|
||||
def wtf_check(ctx):
|
||||
"""Check implementation function for roswtf"""
|
||||
from roswtf.rules import warning_rule, error_rule
|
||||
for r in warnings:
|
||||
warning_rule(r, r[0](ctx), ctx)
|
||||
for r in errors:
|
||||
error_rule(r, r[0](ctx), ctx)
|
||||
299
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/roslaunchwtf.py
vendored
Normal file
299
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/roslaunchwtf.py
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Revision $Id$
|
||||
|
||||
import os
|
||||
import itertools
|
||||
import socket
|
||||
import stat
|
||||
import sys
|
||||
try:
|
||||
from xmlrpc.client import ServerProxy
|
||||
except ImportError:
|
||||
from xmlrpclib import ServerProxy
|
||||
|
||||
from os.path import isfile, isdir
|
||||
|
||||
import roslib.packages
|
||||
import roslaunch
|
||||
import roslaunch.netapi
|
||||
|
||||
from roswtf.environment import paths, is_executable
|
||||
from roswtf.rules import warning_rule, error_rule
|
||||
|
||||
## check if node is cannot be located in package
|
||||
def roslaunch_missing_node_check(ctx):
|
||||
nodes = []
|
||||
for filename, rldeps in ctx.launch_file_deps.items():
|
||||
nodes.extend(rldeps.nodes)
|
||||
errors = []
|
||||
for pkg, node_type in nodes:
|
||||
paths = roslib.packages.find_node(pkg, node_type)
|
||||
if not paths:
|
||||
errors.append("node [%s] in package [%s]"%(node_type, pkg))
|
||||
return errors
|
||||
|
||||
## check if two nodes with same name in package
|
||||
def roslaunch_duplicate_node_check(ctx):
|
||||
nodes = []
|
||||
for filename, rldeps in ctx.launch_file_deps.items():
|
||||
nodes.extend(rldeps.nodes)
|
||||
warnings = []
|
||||
for pkg, node_type in nodes:
|
||||
paths = roslib.packages.find_node(pkg, node_type)
|
||||
if len(paths) > 1:
|
||||
warnings.append("node [%s] in package [%s]\n"%(node_type, pkg))
|
||||
return warnings
|
||||
|
||||
def pycrypto_check(ctx):
|
||||
try:
|
||||
import Crypto
|
||||
except ImportError as e:
|
||||
return True
|
||||
|
||||
def paramiko_check(ctx):
|
||||
try:
|
||||
import paramiko
|
||||
except ImportError as e:
|
||||
return True
|
||||
def paramiko_system_keys(ctx):
|
||||
try:
|
||||
import paramiko
|
||||
ssh = paramiko.SSHClient()
|
||||
try:
|
||||
ssh.load_system_host_keys() #default location
|
||||
except:
|
||||
return True
|
||||
except: pass
|
||||
|
||||
def paramiko_ssh(ctx, address, port, username, password):
|
||||
try:
|
||||
import paramiko
|
||||
ssh = paramiko.SSHClient()
|
||||
|
||||
import roslaunch.remoteprocess
|
||||
err_msg = roslaunch.remoteprocess.ssh_check_known_hosts(ssh, address, port, username=username)
|
||||
if err_msg:
|
||||
return err_msg
|
||||
|
||||
if not password: #use SSH agent
|
||||
ssh.connect(address, port, username)
|
||||
else: #use SSH with login/pass
|
||||
ssh.connect(address, port, username, password)
|
||||
|
||||
except paramiko.BadHostKeyException:
|
||||
return "Unable to verify host key for [%s:%s]"%(address, port)
|
||||
except paramiko.AuthenticationException:
|
||||
return "Authentication to [%s:%s] failed"%(address, port)
|
||||
except paramiko.SSHException as e:
|
||||
return "[%s:%s]: %s"%(address, port, e)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def _load_roslaunch_config(ctx):
|
||||
config = roslaunch.ROSLaunchConfig()
|
||||
loader = roslaunch.XmlLoader()
|
||||
# TODO load roscore
|
||||
for launch_file in ctx.launch_files:
|
||||
loader.load(launch_file, config, verbose=False)
|
||||
try:
|
||||
config.assign_machines()
|
||||
except roslaunch.RLException as e:
|
||||
return config, []
|
||||
machines = []
|
||||
for n in itertools.chain(config.nodes, config.tests):
|
||||
if n.machine not in machines:
|
||||
machines.append(n.machine)
|
||||
return config, machines
|
||||
|
||||
def roslaunch_load_check(ctx):
|
||||
config = roslaunch.ROSLaunchConfig()
|
||||
loader = roslaunch.XmlLoader()
|
||||
# TODO load roscore
|
||||
for launch_file in ctx.launch_files:
|
||||
loader.load(launch_file, config, verbose=False)
|
||||
try:
|
||||
config.assign_machines()
|
||||
except roslaunch.RLException as e:
|
||||
return str(e)
|
||||
|
||||
def roslaunch_machine_name_check(ctx):
|
||||
config, machines = _load_roslaunch_config(ctx)
|
||||
bad = []
|
||||
for m in machines:
|
||||
try:
|
||||
#TODO IPV6: only check for IPv6 when IPv6 is enabled
|
||||
socket.getaddrinfo(m.address, 0, 0, 0, socket.SOL_TCP)
|
||||
except socket.gaierror:
|
||||
bad.append(m.address)
|
||||
return ''.join([' * %s\n'%b for b in bad])
|
||||
|
||||
def roslaunch_ssh_check(ctx):
|
||||
import roslaunch.core
|
||||
if not ctx.launch_files:
|
||||
return # not relevant
|
||||
config, machines = _load_roslaunch_config(ctx)
|
||||
err_msgs = []
|
||||
for m in machines:
|
||||
socket.setdefaulttimeout(3.)
|
||||
# only check if the machine requires ssh to connect
|
||||
if not roslaunch.core.is_machine_local(m):
|
||||
err_msg = paramiko_ssh(ctx, m.address, m.ssh_port, m.user, m.password)
|
||||
if err_msg:
|
||||
err_msgs.append(err_msg)
|
||||
return err_msgs
|
||||
|
||||
def roslaunch_missing_pkgs_check(ctx):
|
||||
# rospack depends does not return depends that it cannot find, so
|
||||
# we have to manually determine this
|
||||
config, machines = _load_roslaunch_config(ctx)
|
||||
missing = []
|
||||
for n in config.nodes:
|
||||
pkg = n.package
|
||||
try:
|
||||
roslib.packages.get_pkg_dir(pkg, required=True)
|
||||
except:
|
||||
missing.append(pkg)
|
||||
return missing
|
||||
|
||||
def roslaunch_config_errors(ctx):
|
||||
config, machines = _load_roslaunch_config(ctx)
|
||||
return config.config_errors
|
||||
|
||||
def roslaunch_missing_deps_check(ctx):
|
||||
missing = []
|
||||
for pkg, miss in ctx.launch_file_missing_deps.items():
|
||||
if miss:
|
||||
missing.append("%s/manifest.xml: %s"%(pkg, ', '.join(miss)))
|
||||
return missing
|
||||
|
||||
def roslaunch_respawn_check(ctx):
|
||||
respawn = []
|
||||
for uri in ctx.roslaunch_uris:
|
||||
try:
|
||||
r = ServerProxy(uri)
|
||||
code, msg, val = r.list_processes()
|
||||
active, _ = val
|
||||
respawn.extend([a for a in active if a[1] > 1])
|
||||
#TODO: children processes
|
||||
#code, msg, val = r.list_children()
|
||||
except:
|
||||
pass # error for another rule
|
||||
return ["%s (%s)"%(a[0], a[1]) for a in respawn]
|
||||
|
||||
def roslaunch_uris_check(ctx):
|
||||
# check for any roslaunch processes that cannot be contacted
|
||||
bad = []
|
||||
# uris only contains the parent launches
|
||||
for uri in ctx.roslaunch_uris:
|
||||
try:
|
||||
r = ServerProxy(uri)
|
||||
code, msg, val = r.list_children()
|
||||
# check the children launches
|
||||
if code == 1:
|
||||
for child_uri in val:
|
||||
try:
|
||||
r = ServerProxy(uri)
|
||||
code, msg, val = r.get_pid()
|
||||
except:
|
||||
bad.append(child_uri)
|
||||
except:
|
||||
bad.append(uri)
|
||||
return bad
|
||||
|
||||
def roslaunch_dead_check(ctx):
|
||||
dead = []
|
||||
for uri in ctx.roslaunch_uris:
|
||||
try:
|
||||
r = ServerProxy(uri)
|
||||
code, msg, val = r.list_processes()
|
||||
_, dead_list = val
|
||||
dead.extend([d[0] for d in dead_list])
|
||||
#TODO: children processes
|
||||
#code, msg, val = r.list_children()
|
||||
except:
|
||||
pass # error for another rule
|
||||
return dead
|
||||
|
||||
online_roslaunch_warnings = [
|
||||
(roslaunch_respawn_check,"These nodes have respawned at least once:"),
|
||||
(roslaunch_dead_check,"These nodes have died:"),
|
||||
# disabling for now as roslaunches don't do cleanup
|
||||
#(roslaunch_uris_check,"These roslaunch processes can no longer be contacted and may have exited:"),
|
||||
]
|
||||
|
||||
online_roslaunch_errors = [
|
||||
(roslaunch_ssh_check,"SSH failures:"),
|
||||
]
|
||||
|
||||
static_roslaunch_warnings = [
|
||||
(roslaunch_duplicate_node_check, "Multiple nodes of same name in packages:"),
|
||||
(pycrypto_check, "pycrypto is not installed"),
|
||||
(paramiko_check, "paramiko is not installed"),
|
||||
(paramiko_system_keys, "cannot load SSH host keys -- your known_hosts file may be corrupt") ,
|
||||
(roslaunch_config_errors, "Loading your launch files reported the following configuration errors:"),
|
||||
]
|
||||
static_roslaunch_errors = [
|
||||
# Disabling, because we've removed package dependencies from manifests.
|
||||
#(roslaunch_missing_deps_check,
|
||||
# "Package %(pkg)s is missing roslaunch dependencies.\nPlease add the following tags to %(pkg)s/manifest.xml:"),
|
||||
(roslaunch_missing_pkgs_check,
|
||||
"Cannot find the following required packages:"),
|
||||
(roslaunch_missing_node_check, "Several nodes in your launch file could not be located. These are either typed incorrectly or need to be built:"),
|
||||
(roslaunch_machine_name_check,"Cannot resolve the following hostnames:"),
|
||||
(roslaunch_load_check, "roslaunch load failed"),
|
||||
]
|
||||
|
||||
def wtf_check_static(ctx):
|
||||
if not ctx.launch_files:
|
||||
return
|
||||
|
||||
#NOTE: roslaunch files are already loaded separately into context
|
||||
|
||||
#TODO: check each machine name
|
||||
#TODO: bidirectional ping for each machine
|
||||
|
||||
for r in static_roslaunch_warnings:
|
||||
warning_rule(r, r[0](ctx), ctx)
|
||||
for r in static_roslaunch_errors:
|
||||
error_rule(r, r[0](ctx), ctx)
|
||||
|
||||
def _load_online_ctx(ctx):
|
||||
ctx.roslaunch_uris = roslaunch.netapi.get_roslaunch_uris()
|
||||
|
||||
def wtf_check_online(ctx):
|
||||
_load_online_ctx(ctx)
|
||||
for r in online_roslaunch_warnings:
|
||||
warning_rule(r, r[0](ctx), ctx)
|
||||
for r in online_roslaunch_errors:
|
||||
error_rule(r, r[0](ctx), ctx)
|
||||
101
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/rules.py
vendored
Normal file
101
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/rules.py
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Revision $Id$
|
||||
|
||||
"""
|
||||
Common library for writing rule-style checks for generating warnings
|
||||
and errors. Use of this style streamlines reporting.
|
||||
|
||||
The pattern for rules is simple: a rule provides a function that
|
||||
implements the rule and a format string. If the function returns a
|
||||
non-zero value, that value is combined with the format string to
|
||||
produced an error reporting string. There are other conveniences as
|
||||
well. If the rule returns a list or a tuple, that will be transformed
|
||||
into a human-readable list.
|
||||
|
||||
This library is a layer on top of the base L{WtfWarning} and
|
||||
L{WtfError} representation in roswtf.model.
|
||||
"""
|
||||
|
||||
from roswtf.model import WtfWarning, WtfError
|
||||
|
||||
def _check_rule(rule, ret, ctx, ctx_list, level):
|
||||
if ret:
|
||||
d = ctx.as_dictionary()
|
||||
|
||||
def isstring(s):
|
||||
"""Small helper version to check an object is a string in
|
||||
a way that works for both Python 2 and 3
|
||||
"""
|
||||
try:
|
||||
return isinstance(s, basestring)
|
||||
except NameError:
|
||||
return isinstance(s, str)
|
||||
|
||||
if type(ret) in (tuple, list):
|
||||
f_msg = rule[1]
|
||||
ret_str = '\n'.join([" * %s"%r for r in ret])
|
||||
ctx_list.append(level(f_msg%d + "\n" + ret_str+'\n', f_msg, ret))
|
||||
elif isstring(ret):
|
||||
f_msg = rule[1]
|
||||
ctx_list.append(level(f_msg%d + ret%d, f_msg, ret))
|
||||
else:
|
||||
f_msg = rule[1]
|
||||
ctx_list.append(level(f_msg%d, f_msg, ret))
|
||||
|
||||
def warning_rule(rule, ret, ctx):
|
||||
"""
|
||||
Check return value of rule and update ctx if rule failed.
|
||||
|
||||
@param rule: Rule/message pair.
|
||||
@type rule: (rule_fn, format_msg)
|
||||
@param ret: return value of rule. If value is non-zero, rule failed
|
||||
@param ret: Any
|
||||
@param ctx: context for which rule failed
|
||||
@param ctx: L{WtfContext}
|
||||
"""
|
||||
_check_rule(rule, ret, ctx, ctx.warnings, WtfWarning)
|
||||
|
||||
def error_rule(rule, ret, ctx):
|
||||
"""
|
||||
Check return value of rule and update ctx if rule failed.
|
||||
|
||||
@param rule: Rule/message pair.
|
||||
@type rule: (rule_fn, format_msg)
|
||||
@param ret: return value of rule. If value is non-zero, rule failed
|
||||
@type ret: Any
|
||||
@param ctx: context for which rule failed
|
||||
@type ctx: L{WtfContext}
|
||||
"""
|
||||
_check_rule(rule, ret, ctx, ctx.errors, WtfError)
|
||||
|
||||
101
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/stacks.py
vendored
Normal file
101
thirdparty/ros/ros_comm/utilities/roswtf/src/roswtf/stacks.py
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Revision $Id: packages.py 6258 2009-09-22 22:08:20Z kwc $
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
from roswtf.environment import paths, is_executable
|
||||
from roswtf.rules import warning_rule, error_rule
|
||||
|
||||
import rospkg
|
||||
|
||||
_packages_of_cache = {}
|
||||
def _packages_of(rosstack, d):
|
||||
if d in _packages_of_cache:
|
||||
return _packages_of_cache[d]
|
||||
else:
|
||||
_packages_of_cache[d] = pkgs = rosstack.packages_of(d)
|
||||
return pkgs
|
||||
|
||||
def manifest_depends(ctx):
|
||||
# This rule should probably be cache optimized
|
||||
errors = []
|
||||
rospack = rospkg.RosPack()
|
||||
rosstack = rospkg.RosStack()
|
||||
|
||||
stack_list = rosstack.list()
|
||||
#print stack_list
|
||||
for s in ctx.stacks:
|
||||
try:
|
||||
s_deps = []
|
||||
s_pkgs = _packages_of(rosstack, s)
|
||||
for p in s_pkgs:
|
||||
s_deps.extend(rospack.get_depends(p, implicit=False))
|
||||
m = rosstack.get_manifest(s)
|
||||
m_file = os.path.join(rosstack.get_path(s), 'stack.xml')
|
||||
for d in m.depends:
|
||||
if not d.name in stack_list:
|
||||
errors.append("%s (%s does not exist)"%(m_file, d))
|
||||
elif d.name in ['ros', 'ros_comm']:
|
||||
# ros dependency always exists. ros_comm
|
||||
# dependency has implicit connections (msggen), so
|
||||
# we ignore.
|
||||
continue
|
||||
else:
|
||||
pkgs = _packages_of(rosstack, d.name)
|
||||
# check no longer works due to rosdeps chains
|
||||
#if not [p for p in pkgs if p in s_deps]:
|
||||
# errors.append("%s (%s appears to be an unnecessary depend)"%(m_file, d))
|
||||
except rospkg.ResourceNotFound:
|
||||
# report with a different rule
|
||||
pass
|
||||
return errors
|
||||
|
||||
warnings = [
|
||||
(manifest_depends, "The following stack.xml file list invalid dependencies:"),
|
||||
|
||||
]
|
||||
errors = [
|
||||
]
|
||||
|
||||
def wtf_check(ctx):
|
||||
# no package in context to verify
|
||||
if not ctx.stacks:
|
||||
return
|
||||
|
||||
for r in warnings:
|
||||
warning_rule(r, r[0](ctx), ctx)
|
||||
for r in errors:
|
||||
error_rule(r, r[0](ctx), ctx)
|
||||
|
||||
0
thirdparty/ros/ros_comm/utilities/roswtf/test/__init__.py
vendored
Normal file
0
thirdparty/ros/ros_comm/utilities/roswtf/test/__init__.py
vendored
Normal file
141
thirdparty/ros/ros_comm/utilities/roswtf/test/check_roswtf_command_line_online.py
vendored
Executable file
141
thirdparty/ros/ros_comm/utilities/roswtf/test/check_roswtf_command_line_online.py
vendored
Executable file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
PKG = 'roswtf'
|
||||
NAME = 'test_roswtf_command_line_online'
|
||||
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
import unittest
|
||||
|
||||
import rospkg
|
||||
import rospy
|
||||
import rostest
|
||||
|
||||
import std_msgs.msg
|
||||
|
||||
from subprocess import Popen, PIPE, check_call, call
|
||||
|
||||
def run_for(cmd, secs):
|
||||
popen = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
|
||||
timeout_t = time.time() + secs
|
||||
while time.time() < timeout_t:
|
||||
time.sleep(0.1)
|
||||
os.kill(popen.pid, signal.SIGKILL)
|
||||
|
||||
class TestRostopicOnline(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.vals = set()
|
||||
self.msgs = {}
|
||||
|
||||
## test that the rosmsg command works
|
||||
def test_cmd_help(self):
|
||||
cmd = 'roswtf'
|
||||
output = Popen([cmd, '-h'], stdout=PIPE).communicate()[0]
|
||||
self.assert_('Options' in output)
|
||||
|
||||
def test_offline(self):
|
||||
# this test is disabled for now; now that test_roswtf is part
|
||||
# of ros_comm, the tricks before that were used no longer work
|
||||
cmd = 'roswtf'
|
||||
|
||||
# pass in special test key to roswtf for ROS_PACKAGE_PATH
|
||||
env = os.environ.copy()
|
||||
|
||||
rospack = rospkg.RosPack()
|
||||
# add all dependencies to ros package path
|
||||
pkgs = ['roswtf',
|
||||
'rosgraph', 'roslaunch', 'roslib', 'rosnode', 'rosservice',
|
||||
'rosbag', 'rosbag_storage', 'roslz4', 'rosconsole', 'roscpp', 'rosgraph_msgs', 'roslang', 'rosmaster', 'rosmsg', 'rosout', 'rosparam', 'rospy', 'rostest', 'rostopic', 'topic_tools', 'xmlrpcpp',
|
||||
'cpp_common', 'roscpp_serialization', 'roscpp_traits', 'rostime', # roscpp_core
|
||||
'rosbuild', 'rosclean', 'rosunit', # ros
|
||||
'rospack', 'std_msgs', 'message_runtime', 'message_generation', 'gencpp', 'genlisp', 'genpy', 'genmsg', 'catkin',
|
||||
]
|
||||
paths = [rospack.get_path(pkg) for pkg in pkgs]
|
||||
try:
|
||||
path = rospack.get_path('cmake_modules')
|
||||
except rospkg.ResourceNotFound:
|
||||
pass
|
||||
else:
|
||||
paths.append(path)
|
||||
try:
|
||||
path = rospack.get_path('geneus')
|
||||
except rospkg.ResourceNotFound:
|
||||
pass
|
||||
else:
|
||||
paths.append(path)
|
||||
try:
|
||||
path = rospack.get_path('gennodejs')
|
||||
except rospkg.ResourceNotFound:
|
||||
pass
|
||||
else:
|
||||
paths.append(path)
|
||||
env['ROS_PACKAGE_PATH'] = os.pathsep.join(paths)
|
||||
|
||||
cwd = rospack.get_path('roswtf')
|
||||
kwds = { 'env': env, 'stdout': PIPE, 'stderr': PIPE, 'cwd': cwd}
|
||||
|
||||
# run roswtf nakedly in the roswtf directory. Running in
|
||||
# ROS_ROOT effectively make roswtf have dependencies on
|
||||
# every package in the ROS stack, which doesn't work.
|
||||
|
||||
output, err = Popen([cmd], **kwds).communicate()
|
||||
self._check_output([cmd], output, err)
|
||||
|
||||
# run roswtf on a simple launch file online
|
||||
rospack = rospkg.RosPack()
|
||||
p = os.path.join(rospack.get_path('roswtf'), 'test', 'min.launch')
|
||||
output = Popen([cmd, p], **kwds).communicate()[0]
|
||||
self._check_output([cmd, p], output)
|
||||
|
||||
def _check_output(self, cmd, output, error=None):
|
||||
# do both a positive and negative test
|
||||
self.assert_(
|
||||
'No errors or warnings' in output or 'Found 1 error' in output,
|
||||
'CMD[%s] OUTPUT[%s]%s' %
|
||||
(' '.join(cmd), output, '\nstderr[%s]' % error if error else ''))
|
||||
allowed_errors = 0
|
||||
if 'Found 1 error' in output:
|
||||
self.assert_(output.count('ERROR') == 1, 'OUTPUT[%s]' % output)
|
||||
self.assert_(
|
||||
'ROS Dep database not updated' in output,
|
||||
'OUTPUT[%s]' % output)
|
||||
allowed_errors += 1
|
||||
if 'No errors or warnings' in output:
|
||||
self.assert_(output.count('ERROR') <= allowed_errors, 'OUTPUT[%s]' % output)
|
||||
|
||||
if __name__ == '__main__':
|
||||
rostest.run(PKG, NAME, TestRostopicOnline, sys.argv)
|
||||
4
thirdparty/ros/ros_comm/utilities/roswtf/test/min.launch
vendored
Normal file
4
thirdparty/ros/ros_comm/utilities/roswtf/test/min.launch
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
<launch>
|
||||
<!-- $(anon talker) creates an anonymous name for this node -->
|
||||
<node name="$(anon talker)" pkg="rospy" type="talker.py" />
|
||||
</launch>
|
||||
3
thirdparty/ros/ros_comm/utilities/roswtf/test/roswtf.test
vendored
Normal file
3
thirdparty/ros/ros_comm/utilities/roswtf/test/roswtf.test
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<launch>
|
||||
<test test-name="roswtf_command_line_online" pkg="roswtf" type="check_roswtf_command_line_online.py" />
|
||||
</launch>
|
||||
125
thirdparty/ros/ros_comm/utilities/roswtf/test/test_roswtf_command_line_offline.py
vendored
Normal file
125
thirdparty/ros/ros_comm/utilities/roswtf/test/test_roswtf_command_line_offline.py
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2009, Willow Garage, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Willow Garage, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import time
|
||||
|
||||
from subprocess import Popen, PIPE, check_call, call
|
||||
|
||||
import rospkg
|
||||
|
||||
def get_test_path():
|
||||
return os.path.abspath(os.path.dirname(__file__))
|
||||
def get_roswtf_path():
|
||||
return os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
||||
|
||||
class TestRoswtfOffline(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
## test that the rosmsg command works
|
||||
def test_cmd_help(self):
|
||||
cmd = 'roswtf'
|
||||
output = Popen([cmd, '-h'], stdout=PIPE).communicate()[0]
|
||||
output = output.decode()
|
||||
self.assert_('Options' in output)
|
||||
|
||||
def test_offline(self):
|
||||
cmd = 'roswtf'
|
||||
|
||||
# point at a different 'master'
|
||||
env = os.environ.copy()
|
||||
env['ROS_MASTER_URI'] = 'http://localhost:11312'
|
||||
|
||||
rospack = rospkg.RosPack()
|
||||
# add all dependencies to ros package path
|
||||
pkgs = ['roswtf',
|
||||
'rosgraph', 'roslaunch', 'roslib', 'rosnode', 'rosservice',
|
||||
'rosbag', 'rosbag_storage', 'roslz4', 'rosconsole', 'roscpp', 'rosgraph_msgs', 'roslang', 'rosmaster', 'rosmsg', 'rosout', 'rosparam', 'rospy', 'rostest', 'rostopic', 'topic_tools', 'xmlrpcpp',
|
||||
'cpp_common', 'roscpp_serialization', 'roscpp_traits', 'rostime', # roscpp_core
|
||||
'rosbuild', 'rosclean', 'rosunit', # ros
|
||||
'rospack', 'std_msgs', 'message_runtime', 'message_generation', 'gencpp', 'genlisp', 'genpy', 'genmsg', 'catkin',
|
||||
]
|
||||
paths = [rospack.get_path(pkg) for pkg in pkgs]
|
||||
try:
|
||||
path = rospack.get_path('cmake_modules')
|
||||
except rospkg.ResourceNotFound:
|
||||
pass
|
||||
else:
|
||||
paths.append(path)
|
||||
try:
|
||||
path = rospack.get_path('geneus')
|
||||
except rospkg.ResourceNotFound:
|
||||
pass
|
||||
else:
|
||||
paths.append(path)
|
||||
try:
|
||||
path = rospack.get_path('gennodejs')
|
||||
except rospkg.ResourceNotFound:
|
||||
pass
|
||||
else:
|
||||
paths.append(path)
|
||||
env['ROS_PACKAGE_PATH'] = os.pathsep.join(paths)
|
||||
|
||||
cwd = get_roswtf_path()
|
||||
kwds = { 'env': env, 'stdout': PIPE, 'stderr': PIPE, 'cwd': cwd}
|
||||
|
||||
# run roswtf nakedly
|
||||
output = Popen([cmd], **kwds).communicate()
|
||||
output = [o.decode() for o in output]
|
||||
|
||||
# there should either be no errors or warnings or
|
||||
# there should be exactly one error about rosdep not being initialized
|
||||
self._check_output(output[0])
|
||||
|
||||
# run roswtf on a simple launch file offline
|
||||
p = os.path.join(get_test_path(), 'min.launch')
|
||||
output = Popen([cmd, p], **kwds).communicate()[0]
|
||||
output = output.decode()
|
||||
self._check_output(output)
|
||||
|
||||
def _check_output(self, output):
|
||||
# do both a positive and negative test
|
||||
self.assert_(
|
||||
'No errors or warnings' in output or 'Found 1 error' in output,
|
||||
'OUTPUT[%s]' % output)
|
||||
if 'No errors or warnings' in output:
|
||||
self.assert_('ERROR' not in output, 'OUTPUT[%s]' % output)
|
||||
if 'Found 1 error' in output:
|
||||
self.assert_(output.count('ERROR') == 1, 'OUTPUT[%s]' % output)
|
||||
self.assert_(
|
||||
'Error: the rosdep view is empty' not in output,
|
||||
'OUTPUT[%s]' % output)
|
||||
Reference in New Issue
Block a user