[catkin] 01/05: Imported Upstream version 0.6.14

Jochen Sprickerhof jspricke-guest at moszumanska.debian.org
Thu Apr 23 21:49:31 UTC 2015


This is an automated email from the git hooks/post-receive script.

jspricke-guest pushed a commit to branch master
in repository catkin.

commit 5c56d0538f8e98faa904d48053641e519520df4e
Author: Jochen Sprickerhof <git at jochen.sprickerhof.de>
Date:   Thu Apr 23 23:00:50 2015 +0200

    Imported Upstream version 0.6.14
---
 CHANGELOG.rst                                      |  26 ++++
 bin/catkin_make                                    |   6 +-
 bin/catkin_test_results                            |  11 +-
 cmake/all.cmake                                    |   6 +-
 cmake/catkin_download.cmake                        |  73 ++++++++++
 cmake/catkin_libraries.cmake                       |   4 +-
 cmake/catkin_workspace.cmake                       |   6 +
 .../05.catkin-test-results.bat.develspace.in       |   4 -
 .../05.catkin-test-results.sh.develspace.in        |   4 -
 cmake/templates/__init__.py.in                     |   1 +
 cmake/templates/_setup_util.py.in                  |   1 +
 cmake/templates/generate_cached_setup.py.in        |   1 +
 cmake/templates/pkgConfig.cmake.in                 |   8 +-
 cmake/templates/relay.py.in                        |   1 +
 cmake/templates/script.py.in                       |   1 +
 cmake/templates/setup.sh.in                        |  17 ++-
 cmake/templates/setup.zsh.in                       |   2 +-
 cmake/test/catkin_download_test_data.cmake         |  25 ++--
 cmake/test/download_checkmd5.py                    |   9 +-
 cmake/test/gtest.cmake                             |  60 ++++++--
 cmake/test/tests.cmake                             |   2 +-
 doc/conf.py                                        |  13 +-
 doc/dev_guide/generated_cmake_api.rst              | 160 +++++++++++++++------
 doc/generate_cmake_rst.py                          |  61 +++++---
 doc/howto/format1/downloading_test_data.rst        |   2 +-
 doc/howto/format1/python_nose_configuration.rst    |  10 +-
 doc/howto/format1/rostest_configuration.rst        |  23 +++
 doc/howto/format2/downloading_test_data.rst        |   2 +-
 doc/howto/format2/python_nose_configuration.rst    |  16 ++-
 doc/howto/format2/rostest_configuration.rst        |  23 +++
 doc/user_guide/variables.rst                       |   3 +
 package.xml                                        |   2 +-
 python/catkin/builder.py                           |  14 +-
 python/catkin/find_in_workspaces.py                |   4 +-
 python/catkin/test_results.py                      |  12 +-
 test/unit_tests/test_find_in_workspace.py          |   5 +-
 test/unit_tests/test_test_results.py               |  40 ++++++
 37 files changed, 506 insertions(+), 152 deletions(-)

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 8fea859..378306a 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -2,6 +2,32 @@
 Changelog for package catkin
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+0.6.14 (2015-04-20)
+-------------------
+* support zsh with NOCLOBBER enabled (`#734 <https://github.com/ros/catkin/pull/734>`_())
+
+0.6.13 (2015-04-17)
+-------------------
+* allow setting CATKIN_GLOBAL_LIBEXEC_DESTINATION to libexec (`#713 <https://github.com/ros/catkin/pull/713>`_)
+
+0.6.12 (2015-04-16)
+-------------------
+* remove CATKIN_TEST_RESULTS_DIR environment variable (`#728 <https://github.com/ros/catkin/issues/728>`_)
+* catkin_test_results will output skipped xml files only when --all is being passed (`#733 <https://github.com/ros/catkin/pull/733>`_)
+* extract catkin_add_executable_with_gtest() from catkin_add_gtest() (`#726 <https://github.com/ros/catkin/issues/726>`_)
+* separate download function from tests (`#633 <https://github.com/ros/catkin/issues/633>`_)
+* only install environment hooks for catkin_make(_isolated) completion in the catkin package (`#732 <https://github.com/ros/catkin/issues/732>`_)
+* avoid warning with CMake 3.1 and newer (`#731 <https://github.com/ros/catkin/issues/731>`_)
+* quote command in "Reproduce this error" instructions (`#730 <https://github.com/ros/catkin/issues/730>`_)
+* fix Python error when working with non-ascii characters in catkin workspace path (`#724 <https://github.com/ros/catkin/issues/724>`_)
+* use $TMPDIR for temporary _setup_util.py file if set (`#710 <https://github.com/ros/catkin/issues/710>`_)
+* fix regex for library config types (`#723 <https://github.com/ros/catkin/issues/723>`_)
+* fix potential race condition in download_checkmd5.py (`#715 <https://github.com/ros/catkin/issues/715>`_)
+* output package whitelist / blacklist if set (`#714 <https://github.com/ros/catkin/issues/714>`_)
+* add --verbose option to catkin_test_results to show the content of result files (`#705 <https://github.com/ros/catkin/issues/705>`_)
+* source in reset zsh emulation mode  (`#686 <https://github.com/ros/catkin/issues/686>`_)
+* improve help text for --only-pkg-with-deps (`#706 <https://github.com/ros/catkin/issues/706>`_)
+
 0.6.11 (2014-12-29)
 -------------------
 * fix return code for tests run by ctest (`#703 <https://github.com/ros/catkin/issues/703>`_)
diff --git a/bin/catkin_make b/bin/catkin_make
index 9d03aa0..65c6873 100755
--- a/bin/catkin_make
+++ b/bin/catkin_make
@@ -224,7 +224,11 @@ def _parse_args(args=sys.argv[1:]):
     add('--force-cmake', action='store_true', help="Invoke 'cmake' even if it has been executed before")
     add('--no-color', action='store_true', help='Disables colored output (only for catkin_make and CMake)')
     add('--pkg', nargs='+', help="Invoke 'make' on specific packages only")
-    add('--only-pkg-with-deps', nargs='+', help='Only consider the specific packages and their recursive dependencies and ignore all other packages in the workspace')
+    add('--only-pkg-with-deps', nargs='+',
+        help='Whitelist only the specified packages and their dependencies by '
+             'setting the CATKIN_WHITELIST_PACKAGES variable. This variable is '
+             'stored in CMakeCache.txt and will persist between CMake calls '
+             'unless explicitly cleared; e.g. catkin_make -DCATKIN_WHITELIST_PACKAGES="".')
     add('--cmake-args', dest='cmake_args', nargs='*', type=str,
         help='Arbitrary arguments which are passes to CMake. '
              'It must be passed after other arguments since it collects all following options.')
diff --git a/bin/catkin_test_results b/bin/catkin_test_results
index 8e14e55..95f1e26 100755
--- a/bin/catkin_test_results
+++ b/bin/catkin_test_results
@@ -12,12 +12,10 @@ from catkin.test_results import aggregate_results, print_summary, test_results
 
 
 def main():
-    env_name = 'CATKIN_TEST_RESULTS_DIR'
-    test_results_dir = os.environ[env_name] if env_name in os.environ else False
-
     parser = argparse.ArgumentParser(description='Outputs a summary of the test results. If there are any test errors or failures the scripts return code is 1.')
-    parser.add_argument('test_results_dir', nargs='?' if test_results_dir else None, default=test_results_dir, help='The path to the test results (necessary when the environment variable "%s" is not defined)' % env_name)
-    parser.add_argument('--all', action='store_true', default=False, help='Show all test results even the ones without errors/failures')
+    parser.add_argument('test_results_dir', nargs='?', default=os.curdir, help='The path to the test results')
+    parser.add_argument('--all', action='store_true', default=False, help='Show all test results even the ones without errors/failures as well as skipped xml files')
+    parser.add_argument('--verbose', action='store_true', default=False, help='Show all tests which have errors or failed')
     args = parser.parse_args()
 
     # verify that workspace folder exists
@@ -26,7 +24,8 @@ def main():
         sys.exit('Test results directory "%s" does not exist' % test_results_dir)
 
     try:
-        results = test_results(test_results_dir)
+        results = test_results(
+            test_results_dir, show_verbose=args.verbose, show_all=args.all)
         _, sum_errors, sum_failures = aggregate_results(results)
         print_summary(results, show_stable=args.all)
         if sum_errors or sum_failures:
diff --git a/cmake/all.cmake b/cmake/all.cmake
index 7118a6d..6910906 100644
--- a/cmake/all.cmake
+++ b/cmake/all.cmake
@@ -111,6 +111,7 @@ foreach(filename
     atomic_configure_file
     catkin_add_env_hooks
     catkin_destinations
+    catkin_download
     catkin_generate_environment
     catkin_install_python
     catkin_libraries
@@ -194,12 +195,9 @@ set(CATKIN_ENV ${SETUP_DIR}/env_cached.${script_ext} CACHE INTERNAL "catkin envi
 if(CATKIN_BUILD_BINARY_PACKAGE)
   set(catkin_skip_install_env_hooks "SKIP_INSTALL")
 endif()
-if(CMAKE_HOST_UNIX)
+if(CMAKE_HOST_UNIX AND PROJECT_NAME STREQUAL "catkin")
   catkin_add_env_hooks(05.catkin_make SHELLS bash DIRECTORY ${catkin_EXTRAS_DIR}/env-hooks ${catkin_skip_install_env_hooks})
   catkin_add_env_hooks(05.catkin_make_isolated SHELLS bash DIRECTORY ${catkin_EXTRAS_DIR}/env-hooks ${catkin_skip_install_env_hooks})
-  catkin_add_env_hooks(05.catkin-test-results SHELLS sh DIRECTORY ${catkin_EXTRAS_DIR}/env-hooks ${catkin_skip_install_env_hooks})
-else()
-  catkin_add_env_hooks(05.catkin-test-results SHELLS bat DIRECTORY ${catkin_EXTRAS_DIR}/env-hooks ${catkin_skip_install_env_hooks})
 endif()
 
 # requires stamp and environment files
diff --git a/cmake/catkin_download.cmake b/cmake/catkin_download.cmake
new file mode 100644
index 0000000..8758124
--- /dev/null
+++ b/cmake/catkin_download.cmake
@@ -0,0 +1,73 @@
+#
+# Download a file containing data from a URL.
+#
+# It is commonly used to download larger data files which should not be
+# stored in the repository.
+#
+# .. note:: It is not recommended to rely on downloaded data during
+#   a configure / make cycle since this prevents building the package
+#   when no network connectivity is available.
+#
+# .. note:: The target will be registered as a dependency
+#   of the "download_extra_data" target.
+#
+# :param target: the target name
+# :type target: string
+# :param url: the url to download
+# :type url: string
+#
+# :param DESTINATION: the directory where the file is downloaded to
+#   (default: ${PROJECT_BINARY_DIR})
+# :type DESTINATION: string
+# :param FILENAME: the filename of the downloaded file
+#   (default: the basename of the url)
+# :type FILENAME: string
+# :param MD5: the expected md5 hash to compare against
+#   (default: empty, skipping the check)
+# :type MD5: string
+#
+# Additionally, options EXCLUDE_FROM_ALL and REQUIRED can be specified.
+#
+# @public
+function(catkin_download target url)
+  cmake_parse_arguments(ARG
+    "EXCLUDE_FROM_ALL;REQUIRED" "DESTINATION;FILENAME;MD5" "" ${ARGN})
+  if(ARG_UNPARSED_ARGUMENTS)
+    message(FATAL_ERROR
+      "catkin_download() called with unused arguments: ${ARG_UNPARSED_ARGUMENTS}")
+  endif()
+
+  if(NOT ARG_DESTINATION)
+    set(ARG_DESTINATION ${PROJECT_BINARY_DIR})
+  endif()
+
+  if(NOT ARG_FILENAME)
+    get_filename_component(ARG_FILENAME ${url} NAME)
+  endif()
+
+  set(required "")
+  if(NOT ARG_REQUIRED)
+    set(required "--ignore-error")
+  endif()
+
+  set(output "${ARG_DESTINATION}/${ARG_FILENAME}")
+
+  # With this, the command is always called, even when the output is up to date.
+  # this is because we want to check the md5 sum if it's given, and redownload
+  # the target if the md5 sum does not match.
+  add_custom_target(${target}
+    COMMAND ${PYTHON} ${catkin_EXTRAS_DIR}/test/download_checkmd5.py ${url} ${output} ${ARG_MD5} ${required}
+    VERBATIM)
+
+  if(ARG_EXCLUDE_FROM_ALL)
+    set_target_properties(${target} PROPERTIES EXCLUDE_FROM_ALL TRUE)
+  endif()
+
+  if(TARGET download_extra_data)
+    add_dependencies(download_extra_data ${target})
+  endif()
+endfunction()
+
+if(NOT TARGET download_extra_data)
+  add_custom_target(download_extra_data)
+endif()
diff --git a/cmake/catkin_libraries.cmake b/cmake/catkin_libraries.cmake
index 723d40a..a8467f2 100644
--- a/cmake/catkin_libraries.cmake
+++ b/cmake/catkin_libraries.cmake
@@ -75,7 +75,7 @@ macro(catkin_pack_libraries_with_build_configuration VAR)
   set(_index 0)
   while(${_index} LESS ${_count})
     list(GET _argn ${_index} lib)
-    if("${lib}" MATCHES "^debug|optimized|general$")
+    if("${lib}" MATCHES "^(debug|optimized|general)$")
       math(EXPR _index "${_index} + 1")
       if(${_index} EQUAL ${_count})
         message(FATAL_ERROR "catkin_pack_libraries_with_build_configuration() the list of libraries '${_argn}' ends with '${lib}' which is a build configuration keyword and must be followed by a library")
@@ -124,7 +124,7 @@ endmacro()
 macro(catkin_replace_imported_library_targets VAR)
   set(${VAR} "")
   foreach(lib ${ARGN})
-    if((NOT "${lib}" MATCHES "^debug|optimized|general$") AND TARGET ${lib})
+    if((NOT "${lib}" MATCHES "^(debug|optimized|general)$") AND TARGET ${lib})
       # sometimes cmake dependencies define imported targets, in which
       # case the imported library information is not the target name, but
       # the information embedded in cmake properties inside the imported library
diff --git a/cmake/catkin_workspace.cmake b/cmake/catkin_workspace.cmake
index 088e00d..d346ff0 100644
--- a/cmake/catkin_workspace.cmake
+++ b/cmake/catkin_workspace.cmake
@@ -24,6 +24,12 @@ function(catkin_workspace)
 
   set(CATKIN_WHITELIST_PACKAGES "" CACHE STRING "List of ';' separated packages to build")
   set(CATKIN_BLACKLIST_PACKAGES "" CACHE STRING "List of ';' separated packages to exclude")
+  if(NOT "${CATKIN_WHITELIST_PACKAGES}" STREQUAL "")
+    message(STATUS "Using CATKIN_WHITELIST_PACKAGES: ${CATKIN_WHITELIST_PACKAGES}")
+  endif()
+  if(NOT "${CATKIN_BLACKLIST_PACKAGES}" STREQUAL "")
+    message(STATUS "Using CATKIN_BLACKLIST_PACKAGES: ${CATKIN_BLACKLIST_PACKAGES}")
+  endif()
 
   assert(catkin_EXTRAS_DIR)
   em_expand(
diff --git a/cmake/env-hooks/05.catkin-test-results.bat.develspace.in b/cmake/env-hooks/05.catkin-test-results.bat.develspace.in
deleted file mode 100644
index e2eb023..0000000
--- a/cmake/env-hooks/05.catkin-test-results.bat.develspace.in
+++ /dev/null
@@ -1,4 +0,0 @@
-REM generated from catkin/cmake/env-hooks/05.catkin-test-results.bat.develspace.in
-
-set CATKIN_TEST_RESULTS_DIR="@CATKIN_TEST_RESULTS_DIR@"
-set ROS_TEST_RESULTS_DIR=%CATKIN_TEST_RESULTS_DIR%
diff --git a/cmake/env-hooks/05.catkin-test-results.sh.develspace.in b/cmake/env-hooks/05.catkin-test-results.sh.develspace.in
deleted file mode 100644
index dcbf018..0000000
--- a/cmake/env-hooks/05.catkin-test-results.sh.develspace.in
+++ /dev/null
@@ -1,4 +0,0 @@
-# generated from catkin/cmake/env-hooks/05.catkin-test-results.sh.develspace.in
-
-export CATKIN_TEST_RESULTS_DIR="@CATKIN_TEST_RESULTS_DIR@"
-export ROS_TEST_RESULTS_DIR="$CATKIN_TEST_RESULTS_DIR"
diff --git a/cmake/templates/__init__.py.in b/cmake/templates/__init__.py.in
index 68f2f65..46e84b2 100644
--- a/cmake/templates/__init__.py.in
+++ b/cmake/templates/__init__.py.in
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # generated from catkin/cmake/template/__init__.py.in
 # keep symbol table as clean as possible by deleting all unnecessary symbols
 
diff --git a/cmake/templates/_setup_util.py.in b/cmake/templates/_setup_util.py.in
index 46c8628..47721ad 100755
--- a/cmake/templates/_setup_util.py.in
+++ b/cmake/templates/_setup_util.py.in
@@ -1,4 +1,5 @@
 #!@PYTHON_EXECUTABLE@
+# -*- coding: utf-8 -*-
 
 # Software License Agreement (BSD License)
 #
diff --git a/cmake/templates/generate_cached_setup.py.in b/cmake/templates/generate_cached_setup.py.in
index c2848e0..62c3246 100644
--- a/cmake/templates/generate_cached_setup.py.in
+++ b/cmake/templates/generate_cached_setup.py.in
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 from __future__ import print_function
 import argparse
 import os
diff --git a/cmake/templates/pkgConfig.cmake.in b/cmake/templates/pkgConfig.cmake.in
index 91f6d65..d99b811 100644
--- a/cmake/templates/pkgConfig.cmake.in
+++ b/cmake/templates/pkgConfig.cmake.in
@@ -34,7 +34,7 @@ macro(_pack_libraries_with_build_configuration VAR)
   set(_index 0)
   while(${_index} LESS ${_count})
     list(GET _argn ${_index} lib)
-    if("${lib}" MATCHES "^debug|optimized|general$")
+    if("${lib}" MATCHES "^(debug|optimized|general)$")
       math(EXPR _index "${_index} + 1")
       if(${_index} EQUAL ${_count})
         message(FATAL_ERROR "_pack_libraries_with_build_configuration() the list of libraries '${ARGN}' ends with '${lib}' which is a build configuration keyword and must be followed by a library")
@@ -91,13 +91,13 @@ endif()
 # flag project as catkin-based to distinguish if a find_package()-ed project is a catkin project
 set(@PROJECT_NAME at _FOUND_CATKIN_PROJECT TRUE)
 
-if(NOT "@PROJECT_CMAKE_CONFIG_INCLUDE_DIRS@" STREQUAL "")
+if(NOT "@PROJECT_CMAKE_CONFIG_INCLUDE_DIRS@ " STREQUAL " ")
   set(@PROJECT_NAME at _INCLUDE_DIRS "")
   set(_include_dirs "@PROJECT_CMAKE_CONFIG_INCLUDE_DIRS@")
   foreach(idir ${_include_dirs})
     if(IS_ABSOLUTE ${idir} AND IS_DIRECTORY ${idir})
       set(include ${idir})
-    elseif("${idir}" STREQUAL "@CATKIN_GLOBAL_INCLUDE_DESTINATION@")
+    elseif("${idir} " STREQUAL "@CATKIN_GLOBAL_INCLUDE_DESTINATION@ ")
       get_filename_component(include "${@PROJECT_NAME at _DIR}/../../../@CATKIN_GLOBAL_INCLUDE_DESTINATION@" ABSOLUTE)
       if(NOT IS_DIRECTORY ${include})
         message(FATAL_ERROR "Project '@PROJECT_NAME@' specifies '${idir}' as an include dir, which is not found.  It does not exist in '${include}'.  Ask the maintainer '@PROJECT_MAINTAINER@' to fix it.")
@@ -112,7 +112,7 @@ endif()
 set(libraries "@PKG_CONFIG_LIBRARIES@")
 foreach(library ${libraries})
   # keep build configuration keywords, target names and absolute libraries as-is
-  if("${library}" MATCHES "^debug|optimized|general$")
+  if("${library}" MATCHES "^(debug|optimized|general)$")
     list(APPEND @PROJECT_NAME at _LIBRARIES ${library})
   elseif(TARGET ${library})
     list(APPEND @PROJECT_NAME at _LIBRARIES ${library})
diff --git a/cmake/templates/relay.py.in b/cmake/templates/relay.py.in
index 5221f48..296fc3c 100644
--- a/cmake/templates/relay.py.in
+++ b/cmake/templates/relay.py.in
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # creates a relay to a python script source file, acting as that file.
 # The purpose is that of a symlink
 with open("@PYTHON_SCRIPT@", 'r') as fh:
diff --git a/cmake/templates/script.py.in b/cmake/templates/script.py.in
index dc3a277..c8f79be 100755
--- a/cmake/templates/script.py.in
+++ b/cmake/templates/script.py.in
@@ -1,4 +1,5 @@
 #!/usr/bin/env python
+# -*- coding: utf-8 -*-
 # creates a relay to a python script source file, acting as that file.
 # The purpose is that of a symlink
 with open("@PYTHON_SCRIPT@", 'r') as fh:
diff --git a/cmake/templates/setup.sh.in b/cmake/templates/setup.sh.in
index a47611b..25cd770 100644
--- a/cmake/templates/setup.sh.in
+++ b/cmake/templates/setup.sh.in
@@ -44,12 +44,19 @@ if [ -z "$CATKIN_SHELL" ]; then
 fi
 
 # invoke Python script to generate necessary exports of environment variables
-_SETUP_TMP=`mktemp /tmp/setup.sh.XXXXXXXXXX`
+# use TMPDIR if it exists, otherwise fall back to /tmp
+if [ -d "${TMPDIR}" ]; then
+  _TMPDIR="${TMPDIR}"
+else
+  _TMPDIR=/tmp
+fi
+_SETUP_TMP=`mktemp "${_TMPDIR}/setup.sh.XXXXXXXXXX"`
+unset _TMPDIR
 if [ $? -ne 0 -o ! -f "$_SETUP_TMP" ]; then
   echo "Could not create temporary file: $_SETUP_TMP"
   return 1
 fi
-CATKIN_SHELL=$CATKIN_SHELL "$_SETUP_UTIL" $@ > $_SETUP_TMP
+CATKIN_SHELL=$CATKIN_SHELL "$_SETUP_UTIL" $@ >> "$_SETUP_TMP"
 _RC=$?
 if [ $_RC -ne 0 ]; then
   if [ $_RC -eq 2 ]; then
@@ -59,14 +66,14 @@ if [ $_RC -ne 0 ]; then
   fi
   unset _RC
   unset _SETUP_UTIL
-  rm -f $_SETUP_TMP
+  rm -f "$_SETUP_TMP"
   unset _SETUP_TMP
   return 1
 fi
 unset _RC
 unset _SETUP_UTIL
-. $_SETUP_TMP
-rm -f $_SETUP_TMP
+. "$_SETUP_TMP"
+rm -f "$_SETUP_TMP"
 unset _SETUP_TMP
 
 # source all environment hooks
diff --git a/cmake/templates/setup.zsh.in b/cmake/templates/setup.zsh.in
index 952f72a..9f780b7 100644
--- a/cmake/templates/setup.zsh.in
+++ b/cmake/templates/setup.zsh.in
@@ -5,4 +5,4 @@ CATKIN_SHELL=zsh
 
 # source setup.sh from same directory as this file
 _CATKIN_SETUP_DIR=$(builtin cd -q "`dirname "$0"`" > /dev/null && pwd)
-source "$_CATKIN_SETUP_DIR/setup.sh"
+emulate -R zsh -c 'source "$_CATKIN_SETUP_DIR/setup.sh"'
diff --git a/cmake/test/catkin_download_test_data.cmake b/cmake/test/catkin_download_test_data.cmake
index 9d39052..b71e31b 100644
--- a/cmake/test/catkin_download_test_data.cmake
+++ b/cmake/test/catkin_download_test_data.cmake
@@ -6,8 +6,12 @@ _generate_function_if_testing_is_disabled("catkin_download_test_data")
 # It is commonly used to download larger data files for unit tests
 # which should not be stored in the repository.
 #
+# .. note:: It is not recommended to rely on downloaded data during
+#   a configure / make cycle since this prevents building the package
+#   when no network connectivity is available.
+#
 # .. note:: The target will be registered as a dependency
-#   of the "tests" target.
+#   of the "tests" and "download_extra_data" targets, but not of "all" target.
 #
 # .. note:: If the tests should be run on the ROS buildfarm the URL
 #   must be publically and reliably accessible.
@@ -27,25 +31,14 @@ _generate_function_if_testing_is_disabled("catkin_download_test_data")
 #   (default: empty, skipping the check)
 # :type MD5: string
 #
+# Additionally, option REQUIRED can be specified.
+#
 # @public
 function(catkin_download_test_data target url)
   _warn_if_skip_testing("catkin_download_test_data")
 
-  cmake_parse_arguments(ARG "" "DESTINATION;FILENAME;MD5" "" ${ARGN})
-  if(ARG_UNPARSED_ARGUMENTS)
-    message(FATAL_ERROR "catkin_download_test_data() called with unused arguments: ${ARG_UNPARSED_ARGUMENTS}")
-  endif()
-  if(NOT ARG_DESTINATION)
-    set(ARG_DESTINATION ${PROJECT_BINARY_DIR})
-  endif()
-  if(NOT ARG_FILENAME)
-    get_filename_component(ARG_FILENAME ${url} NAME)
-  endif()
-  set(output "${ARG_DESTINATION}/${ARG_FILENAME}")
-  add_custom_command(OUTPUT ${output}
-    COMMAND ${PYTHON_EXECUTABLE} ${catkin_EXTRAS_DIR}/test/download_checkmd5.py ${url} ${output} ${ARG_MD5}
-    VERBATIM)
-  add_custom_target(${target} DEPENDS ${output})
+  catkin_download("${target}" "${url}" ${ARGN} EXCLUDE_FROM_ALL)
+
   if(TARGET tests)
     add_dependencies(tests ${target})
   endif()
diff --git a/cmake/test/download_checkmd5.py b/cmake/test/download_checkmd5.py
index 548d4bf..7394315 100755
--- a/cmake/test/download_checkmd5.py
+++ b/cmake/test/download_checkmd5.py
@@ -1,6 +1,7 @@
 #!/usr/bin/env python
 
 from __future__ import print_function
+import errno
 import os
 import sys
 try:
@@ -87,8 +88,12 @@ def download_md5(uri, dest):
     """
     # Create intermediate directories as necessary, #2970
     dirname = os.path.dirname(dest)
-    if len(dirname) and not os.path.exists(dirname):
-        os.makedirs(dirname)
+    if len(dirname):
+        try:
+            os.makedirs(dirname)
+        except OSError as e:
+            if e.errno != errno.EEXIST:
+                raise
 
     sys.stdout.write('Downloading %s to %s...' % (uri, dest))
     sys.stdout.flush()
diff --git a/cmake/test/gtest.cmake b/cmake/test/gtest.cmake
index c834722..f9c5ff5 100644
--- a/cmake/test/gtest.cmake
+++ b/cmake/test/gtest.cmake
@@ -25,37 +25,67 @@ _generate_function_if_testing_is_disabled("catkin_add_gtest")
 function(catkin_add_gtest target)
   _warn_if_skip_testing("catkin_add_gtest")
 
+  # XXX look for optional TIMEOUT argument, #2645
+  cmake_parse_arguments(ARG "" "TIMEOUT;WORKING_DIRECTORY" "" ${ARGN})
+  if(ARG_TIMEOUT)
+    message(WARNING "TIMEOUT argument to catkin_add_gtest() is ignored")
+  endif()
+
+  catkin_add_executable_with_gtest(${target} ${ARG_UNPARSED_ARGUMENTS} EXCLUDE_FROM_ALL)
+
+  if(TARGET ${target})
+    # make sure the target is built before running tests
+    add_dependencies(tests ${target})
+
+    # XXX we DONT use rosunit to call the executable to get process control, #1629, #3112
+    get_target_property(_target_path ${target} RUNTIME_OUTPUT_DIRECTORY)
+    set(cmd "${_target_path}/${target} --gtest_output=xml:${CATKIN_TEST_RESULTS_DIR}/${PROJECT_NAME}/gtest-${target}.xml")
+    catkin_run_tests_target("gtest" ${target} "gtest-${target}.xml" COMMAND ${cmd} DEPENDENCIES ${target} WORKING_DIRECTORY ${ARG_WORKING_DIRECTORY})
+  endif()
+endfunction()
+
+#
+# Add a GTest executable target.
+#
+# An executable target is created with the source files, it is linked
+# against GTest.
+# If you also want to register the executable as a test use
+# ``catkin_add_gtest()`` instead.
+#
+# :param target: the target name
+# :type target: string
+# :param source_files: a list of source files used to build the test
+#   executable
+# :type source_files: list of strings
+#
+# Additionally, the option EXCLUDE_FROM_ALL can be specified.
+# @public
+#
+function(catkin_add_executable_with_gtest target)
   if(NOT GTEST_FOUND AND NOT GTEST_FROM_SOURCE_FOUND)
     message(WARNING "skipping gtest '${target}' in project '${PROJECT_NAME}'")
     return()
   endif()
 
   if(NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY)
-    message(FATAL_ERROR "catkin_add_gtest() must be called after catkin_package() so that default output directories for the test binaries are defined")
+    message(FATAL_ERROR "catkin_add_executable_with_gtest() must be called after catkin_package() so that default output directories for the executables are defined")
   endif()
 
-  # XXX look for optional TIMEOUT argument, #2645
-  cmake_parse_arguments(_gtest "" "TIMEOUT;WORKING_DIRECTORY" "" ${ARGN})
-  if(_gtest_TIMEOUT)
-    message(WARNING "TIMEOUT argument to catkin_add_gtest() is ignored")
-  endif()
+  cmake_parse_arguments(ARG "EXCLUDE_FROM_ALL" "" "" ${ARGN})
 
   # create the executable, with basic + gtest build flags
   include_directories(${GTEST_INCLUDE_DIRS})
   link_directories(${GTEST_LIBRARY_DIRS})
-  add_executable(${target} EXCLUDE_FROM_ALL ${_gtest_UNPARSED_ARGUMENTS})
+  add_executable(${target} ${ARG_UNPARSED_ARGUMENTS})
+  if(ARG_EXCLUDE_FROM_ALL)
+    set_target_properties(${target} PROPERTIES EXCLUDE_FROM_ALL TRUE)
+  endif()
+
   assert(GTEST_LIBRARIES)
   target_link_libraries(${target} ${GTEST_LIBRARIES} ${THREADS_LIBRARY})
 
-  # make sure gtest is built before the test target
+  # make sure gtest is built before the target
   add_dependencies(${target} gtest gtest_main)
-  # make sure the target is built before running tests
-  add_dependencies(tests ${target})
-
-  # XXX we DONT use rosunit to call the executable to get process control, #1629, #3112
-  get_target_property(_target_path ${target} RUNTIME_OUTPUT_DIRECTORY)
-  set(cmd "${_target_path}/${target} --gtest_output=xml:${CATKIN_TEST_RESULTS_DIR}/${PROJECT_NAME}/gtest-${target}.xml")
-  catkin_run_tests_target("gtest" ${target} "gtest-${target}.xml" COMMAND ${cmd} DEPENDENCIES ${target} WORKING_DIRECTORY ${_gtest_WORKING_DIRECTORY})
 endfunction()
 
 find_package(GTest QUIET)
diff --git a/cmake/test/tests.cmake b/cmake/test/tests.cmake
index 894c5fe..5a3aa4a 100644
--- a/cmake/test/tests.cmake
+++ b/cmake/test/tests.cmake
@@ -84,7 +84,7 @@ endif()
 # Create a test target, integrate it with the run_tests infrastructure
 # and post-process the junit result.
 #
-# All test results go under ${CATKIN_TEST_RESULTS_DIR}/${PROJECT_NAME}/..
+# All test results go under ${CATKIN_TEST_RESULTS_DIR}/${PROJECT_NAME}
 #
 # This function is only used internally by the various
 # catkin_add_*test() functions.
diff --git a/doc/conf.py b/doc/conf.py
index 471d70d..f4e4e83 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -15,6 +15,7 @@ import catkin_sphinx
 import os
 import sys
 import subprocess
+import time
 from xml.etree.ElementTree import ElementTree
 
 # -- General configuration -----------------------------------------------------
@@ -47,14 +48,6 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'catkin'
-gitcmd = 'git log -n1 --pretty=format:%cD'.split()
-
-lastmod = subprocess.Popen(gitcmd, stdout=subprocess.PIPE).communicate()[0]
-dochash = subprocess.Popen('git log -n1 --pretty=format:%H'.split(),
-                           stdout=subprocess.PIPE).communicate()[0]
-
-print "dochash=", dochash
-copyright = u'2010, Willow Garage -- ' + ' Version ' + dochash + ", " + ' '.join(lastmod.split(' ')[:4])
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -62,8 +55,10 @@ copyright = u'2010, Willow Garage -- ' + ' Version ' + dochash + ", " + ' '.join
 try:
     root = ElementTree(None, os.path.join('..', 'package.xml'))
     version = root.findtext('version')
+    author_names = [a.text for a in root.findall('author')]
+    copyright = u'2010-%s, %s' % (time.strftime('%Y'), ', '.join(author_names))
 except Exception as e:
-    raise RuntimeError('Could not extract version from package.xml:\n%s' % e)
+    raise RuntimeError('Could not extract version and authors from package.xml:\n%s' % e)
 
 # The full version, including alpha/beta/rc tags.
 release = version
diff --git a/doc/dev_guide/generated_cmake_api.rst b/doc/dev_guide/generated_cmake_api.rst
index 8bc9972..bfbfceb 100644
--- a/doc/dev_guide/generated_cmake_api.rst
+++ b/doc/dev_guide/generated_cmake_api.rst
@@ -7,14 +7,17 @@ This page was auto-generated from cmake source files using generate_cmake_rst.py
 .. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
 .. contents::
+   :local:
 
 
 Public CMake functions / macros
 -------------------------------
 
  * :cmake:macro:`catkin_add_env_hooks`
+ * :cmake:macro:`catkin_add_executable_with_gtest`
  * :cmake:macro:`catkin_add_gtest`
  * :cmake:macro:`catkin_add_nosetests`
+ * :cmake:macro:`catkin_download`
  * :cmake:macro:`catkin_download_test_data`
  * :cmake:macro:`catkin_filter_libraries_for_build_configuration`
  * :cmake:macro:`catkin_install_python`
@@ -29,7 +32,7 @@ Public CMake functions / macros
 .. _`catkin_add_env_hooks_ref`:
 
 `catkin_add_env_hooks`
-----------------------
+~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_add_env_hooks(file_prefix)
 
@@ -83,10 +86,36 @@ Public CMake functions / macros
 
 
 
+.. _`catkin_add_executable_with_gtest_ref`:
+
+`catkin_add_executable_with_gtest`
+----------------------------------
+
+.. cmake:macro:: catkin_add_executable_with_gtest(target)
+
+ *[function defined in test/gtest.cmake]*
+
+
+ Add a GTest executable target.
+
+ An executable target is created with the source files, it is linked
+ against GTest.
+ If you also want to register the executable as a test use
+ ``catkin_add_gtest()`` instead.
+
+ :param target: the target name
+ :type target: string
+ :param source_files: a list of source files used to build the test
+   executable
+ :type source_files: list of strings
+
+ Additionally, the option EXCLUDE_FROM_ALL can be specified.
+
+
 .. _`catkin_add_gtest_ref`:
 
 `catkin_add_gtest`
-------------------
+~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_add_gtest(target)
 
@@ -117,7 +146,7 @@ Public CMake functions / macros
 .. _`catkin_add_nosetests_ref`:
 
 `catkin_add_nosetests`
-----------------------
+~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_add_nosetests(path)
 
@@ -148,10 +177,50 @@ Public CMake functions / macros
 
 
 
+.. _`catkin_download_ref`:
+
+`catkin_download`
+~~~~~~~~~~~~~~~~~
+
+.. cmake:macro:: catkin_download(target, url)
+
+ *[function defined in catkin_download.cmake]*
+
+
+ Download a file containing data from a URL.
+
+ It is commonly used to download larger data files which should not be
+ stored in the repository.
+
+ .. note:: It is not recommended to rely on downloaded data during
+   a configure / make cycle since this prevents building the package
+   when no network connectivity is available.
+
+ .. note:: The target will be registered as a dependency
+   of the "download_extra_data" target.
+
+ :param target: the target name
+ :type target: string
+ :param url: the url to download
+ :type url: string
+
+ :param DESTINATION: the directory where the file is downloaded to
+   (default: ${PROJECT_BINARY_DIR})
+ :type DESTINATION: string
+ :param FILENAME: the filename of the downloaded file
+   (default: the basename of the url)
+ :type FILENAME: string
+ :param MD5: the expected md5 hash to compare against
+   (default: empty, skipping the check)
+ :type MD5: string
+
+ Additionally, options EXCLUDE_FROM_ALL and REQUIRED can be specified.
+
+
 .. _`catkin_download_test_data_ref`:
 
 `catkin_download_test_data`
----------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_download_test_data(target, url)
 
@@ -167,11 +236,13 @@ Public CMake functions / macros
    (default: empty, skipping the check)
  :type MD5: string
 
+ Additionally, option REQUIRED can be specified.
+
 
 .. _`catkin_filter_libraries_for_build_configuration_ref`:
 
 `catkin_filter_libraries_for_build_configuration`
--------------------------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_filter_libraries_for_build_configuration(VAR)
 
@@ -193,7 +264,7 @@ Public CMake functions / macros
 .. _`catkin_install_python_ref`:
 
 `catkin_install_python`
------------------------
+~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_install_python(signature)
 
@@ -205,7 +276,9 @@ Public CMake functions / macros
 
  The signature:
 
-   catkin_install_python(PROGRAMS files... DESTINATION <dir> [OPTIONAL])
+   catkin_install_python(PROGRAMS files... DESTINATION <dir>
+     [OPTIONAL]
+   )
 
  See the documentation for CMake install() function for more information.
 
@@ -214,7 +287,7 @@ Public CMake functions / macros
 .. _`catkin_metapackage_ref`:
 
 `catkin_metapackage`
---------------------
+~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_metapackage()
 
@@ -237,7 +310,7 @@ Public CMake functions / macros
 .. _`catkin_pack_libraries_with_build_configuration_ref`:
 
 `catkin_pack_libraries_with_build_configuration`
-------------------------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_pack_libraries_with_build_configuration(VAR)
 
@@ -258,7 +331,7 @@ Public CMake functions / macros
 .. _`catkin_package_ref`:
 
 `catkin_package`
-----------------
+~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_package()
 
@@ -345,7 +418,7 @@ Public CMake functions / macros
 .. _`catkin_package_xml_ref`:
 
 `catkin_package_xml`
---------------------
+~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_package_xml()
 
@@ -379,7 +452,7 @@ Public CMake functions / macros
 .. _`catkin_python_setup_ref`:
 
 `catkin_python_setup`
----------------------
+~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_python_setup()
 
@@ -405,7 +478,7 @@ Public CMake functions / macros
 .. _`catkin_replace_imported_library_targets_ref`:
 
 `catkin_replace_imported_library_targets`
------------------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_replace_imported_library_targets(VAR)
 
@@ -424,7 +497,7 @@ Public CMake functions / macros
 .. _`catkin_unpack_libraries_with_build_configuration_ref`:
 
 `catkin_unpack_libraries_with_build_configuration`
---------------------------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_unpack_libraries_with_build_configuration(VAR)
 
@@ -458,7 +531,7 @@ Non-public CMake functions / macros
 .. _`_generate_function_if_testing_is_disabled_ref`:
 
 `_generate_function_if_testing_is_disabled`
--------------------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: _generate_function_if_testing_is_disabled(funcname)
 
@@ -470,7 +543,7 @@ Non-public CMake functions / macros
 .. _`_set_cmake_policy_to_new_if_available_ref`:
 
 `_set_cmake_policy_to_new_if_available`
----------------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: _set_cmake_policy_to_new_if_available(policy)
 
@@ -481,7 +554,7 @@ Non-public CMake functions / macros
 .. _`_warn_if_skip_testing_ref`:
 
 `_warn_if_skip_testing`
------------------------
+~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: _warn_if_skip_testing(funcname)
 
@@ -493,7 +566,7 @@ Non-public CMake functions / macros
 .. _`catkin_destinations_ref`:
 
 `catkin_destinations`
----------------------
+~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_destinations()
 
@@ -534,7 +607,7 @@ Non-public CMake functions / macros
 .. _`catkin_run_tests_target_ref`:
 
 `catkin_run_tests_target`
--------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_run_tests_target(type, name, xunit_filename)
 
@@ -544,7 +617,7 @@ Non-public CMake functions / macros
  Create a test target, integrate it with the run_tests infrastructure
  and post-process the junit result.
 
- All test results go under ${CATKIN_TEST_RESULTS_DIR}/${PROJECT_NAME}/..
+ All test results go under ${CATKIN_TEST_RESULTS_DIR}/${PROJECT_NAME}
 
  This function is only used internally by the various
  catkin_add_*test() functions.
@@ -553,7 +626,7 @@ Non-public CMake functions / macros
 .. _`catkin_workspace_ref`:
 
 `catkin_workspace`
-------------------
+~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_workspace()
 
@@ -561,8 +634,9 @@ Non-public CMake functions / macros
 
 
  Search all subfolders in the workspace for ``package.xml`` files.
- Based on the dependencies specified in the ``build_depends`` and
- ``buildtool_depends`` tags it performs a topological sort and calls
+ Based on the dependencies specified in the ``build_depends``,
+ ``buildtool_depends`` and (as of package format version 2)
+ ``test_depends`` tags it performs a topological sort and calls
  ``add_subdirectory()`` for each directory.
 
  The functions is only called in catkin's ``toplevel.cmake``, which
@@ -573,7 +647,7 @@ Non-public CMake functions / macros
 .. _`list_append_deduplicate_ref`:
 
 `list_append_deduplicate`
--------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: list_append_deduplicate(listname)
 
@@ -591,7 +665,7 @@ Non-public CMake functions / macros
 .. _`list_append_unique_ref`:
 
 `list_append_unique`
---------------------
+~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: list_append_unique(listname)
 
@@ -609,7 +683,7 @@ Non-public CMake functions / macros
 .. _`stamp_ref`:
 
 `stamp`
--------
+~~~~~~~
 
 .. cmake:macro:: stamp(path)
 
@@ -626,7 +700,7 @@ Non-public CMake functions / macros
 .. _`string_starts_with_ref`:
 
 `string_starts_with`
---------------------
+~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: string_starts_with(str, prefix, var)
 
@@ -649,7 +723,7 @@ Not documented CMake functions / macros
 .. _`_catkin_package_ref`:
 
 `_catkin_package`
------------------
+~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: _catkin_package()
 
@@ -658,7 +732,7 @@ Not documented CMake functions / macros
 .. _`_catkin_package_xml_ref`:
 
 `_catkin_package_xml`
----------------------
+~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: _catkin_package_xml(dest_dir)
 
@@ -667,7 +741,7 @@ Not documented CMake functions / macros
 .. _`_strip_path_prefix_ref`:
 
 `_strip_path_prefix`
---------------------
+~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: _strip_path_prefix(var, value, prefix)
 
@@ -676,7 +750,7 @@ Not documented CMake functions / macros
 .. _`assert_ref`:
 
 `assert`
---------
+~~~~~~~~
 
 .. cmake:macro:: assert(VAR)
 
@@ -685,7 +759,7 @@ Not documented CMake functions / macros
 .. _`assert_file_exists_ref`:
 
 `assert_file_exists`
---------------------
+~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: assert_file_exists(FILENAME, MESSAGE)
 
@@ -694,7 +768,7 @@ Not documented CMake functions / macros
 .. _`assert_unset_ref`:
 
 `assert_unset`
---------------
+~~~~~~~~~~~~~~
 
 .. cmake:macro:: assert_unset(VAR)
 
@@ -703,7 +777,7 @@ Not documented CMake functions / macros
 .. _`atomic_configure_file_ref`:
 
 `atomic_configure_file`
------------------------
+~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: atomic_configure_file(input, output)
 
@@ -712,7 +786,7 @@ Not documented CMake functions / macros
 .. _`catkin_doxygen_ref`:
 
 `catkin_doxygen`
-----------------
+~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_doxygen(TARGET_NAME, SEARCH_DIRS)
 
@@ -721,7 +795,7 @@ Not documented CMake functions / macros
 .. _`catkin_generate_environment_ref`:
 
 `catkin_generate_environment`
------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_generate_environment()
 
@@ -730,7 +804,7 @@ Not documented CMake functions / macros
 .. _`catkin_stack_ref`:
 
 `catkin_stack`
---------------
+~~~~~~~~~~~~~~
 
 .. cmake:macro:: catkin_stack()
 
@@ -739,7 +813,7 @@ Not documented CMake functions / macros
 .. _`configure_shared_library_build_settings_ref`:
 
 `configure_shared_library_build_settings`
------------------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: configure_shared_library_build_settings()
 
@@ -748,7 +822,7 @@ Not documented CMake functions / macros
 .. _`debug_message_ref`:
 
 `debug_message`
----------------
+~~~~~~~~~~~~~~~
 
 .. cmake:macro:: debug_message(level)
 
@@ -757,7 +831,7 @@ Not documented CMake functions / macros
 .. _`em_expand_ref`:
 
 `em_expand`
------------
+~~~~~~~~~~~
 
 .. cmake:macro:: em_expand(context_in, context_out, em_file_in, file_out)
 
@@ -766,7 +840,7 @@ Not documented CMake functions / macros
 .. _`find_program_required_ref`:
 
 `find_program_required`
------------------------
+~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: find_program_required(ARG_VAR, ARG_PROGRAM_NAME)
 
@@ -775,7 +849,7 @@ Not documented CMake functions / macros
 .. _`find_python_module_ref`:
 
 `find_python_module`
---------------------
+~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: find_python_module(module)
 
@@ -784,7 +858,7 @@ Not documented CMake functions / macros
 .. _`list_insert_in_workspace_order_ref`:
 
 `list_insert_in_workspace_order`
---------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. cmake:macro:: list_insert_in_workspace_order(listname)
 
diff --git a/doc/generate_cmake_rst.py b/doc/generate_cmake_rst.py
index 7f803aa..3d51bd1 100755
--- a/doc/generate_cmake_rst.py
+++ b/doc/generate_cmake_rst.py
@@ -34,6 +34,7 @@
 
 from __future__ import print_function
 import argparse
+import json
 import os
 import re
 import sys
@@ -41,7 +42,7 @@ import sys
 '''Simple superficial API doc generator for .cmake files'''
 
 
-def crawl_for_cmake(path):
+def crawl_for_cmake(path, excluded_files=None):
     '''
     Crawls over path, looking for files named *.cmake,
     returns tuple of full and relative path.
@@ -49,7 +50,8 @@ def crawl_for_cmake(path):
     cmake_files = []
     for (parentdir, _, files) in os.walk(path):
         for filename in files:
-            if not filename.endswith('.cmake'):
+            if not filename.endswith('.cmake') or \
+                    (excluded_files and filename in excluded_files):
                 continue
             fullpath = os.path.join(parentdir, filename)
             relpath = os.path.relpath(fullpath, path)
@@ -57,7 +59,7 @@ def crawl_for_cmake(path):
     return cmake_files
 
 
-def generate_rst(files):
+def generate_rst(files, skip_private=False, skip_undocumented=False):
     '''
     Each of the CMake files is traversed line by line, looking for
     lines like function(...) or macro(...).  For each of these,
@@ -92,7 +94,7 @@ def generate_rst(files):
                     if dec_type == 'function' or dec_type == 'macro':
                         rst = []
                         # directives defined in catkin-sphinx
-                        dec_line = '.. _`%s_ref`:\n\n`%s`\n%s\n\n.. cmake:macro:: %s(%s)' % (dec_args[0],dec_args[0], '-' * (len(dec_args[0]) + 2), dec_args[0], ', '.join(dec_args[1:]))
+                        dec_line = '.. _`%s_ref`:\n\n`%s`\n%s\n\n.. cmake:macro:: %s(%s)' % (dec_args[0],dec_args[0], '~' * (len(dec_args[0]) + 2), dec_args[0], ', '.join(dec_args[1:]))
                         rst.append(dec_line)
                         rst.append('')
                         rst.append(' *[%s defined in %s]*' % (dec_type, relpath))
@@ -120,6 +122,7 @@ def generate_rst(files):
     rst.append('.. ' + '!' * 70)
     rst.append('')
     rst.append('.. contents::')
+    rst.append('   :local:')
     rst.append('')
     rst.append('')
     rst.append('Public CMake functions / macros')
@@ -130,23 +133,26 @@ def generate_rst(files):
     for name in sorted(public.keys()):
         rst.append('')
         rst.extend(public[name])
-
-    rst.append('')
-    rst.append('Non-public CMake functions / macros')
-    rst.append('-----------------------------------')
     rst.append('')
-    for name in sorted(documented.keys()):
-        rst.append(' * :cmake:macro:`%s`' % name)
-    for name in sorted(documented.keys()):
-        rst.append('')
-        rst.extend(documented[name])
 
-    rst.append('')
-    rst.append('Not documented CMake functions / macros')
-    rst.append('---------------------------------------')
-    for name in sorted(undocumented.keys()):
+    if not skip_private:
+        rst.append('Non-public CMake functions / macros')
+        rst.append('-----------------------------------')
+        rst.append('')
+        for name in sorted(documented.keys()):
+            rst.append(' * :cmake:macro:`%s`' % name)
+        for name in sorted(documented.keys()):
+            rst.append('')
+            rst.extend(documented[name])
+        rst.append('')
+    
+    if not skip_undocumented:
+        rst.append('Not documented CMake functions / macros')
+        rst.append('---------------------------------------')
+        for name in sorted(undocumented.keys()):
+            rst.append('')
+            rst.extend(undocumented[name])
         rst.append('')
-        rst.extend(undocumented[name])
 
     return rst
 
@@ -155,10 +161,25 @@ if __name__ == '__main__':
     parser = argparse.ArgumentParser(description='Crawls a path for .cmake files and extract documentation of functions and macros into reStructured text.')
     parser.add_argument('path', nargs='?', default='.', help='The path to be crawled')
     parser.add_argument('-o', '--output', help='The name of the generated rst file')
+    parser.add_argument('--skip_private', action="store_true", help='Skip documented items not marked with @public')
+    parser.add_argument('--skip_undocumented', action="store_true", help='Skip items without documentation.')
+
     args = parser.parse_args()
 
-    cmake_files = crawl_for_cmake(args.path)
-    lines = generate_rst(cmake_files)
+    exclusions = '{}/.sphinx_exclusions.json'.format(args.path)
+    excluded_files = []
+    if os.path.exists(exclusions):
+        try:
+            with open(exclusions, 'r') as f:
+                excluded_files = json.load(f)
+        except (TypeError, ValueError) as err:
+            print('unable to load exclusions\nerr={}\n'
+                  'make sure the file <{}> is valid json or remove it'.
+                  format(err, exclusions), file=sys.stderr)
+            sys.exit(-1)
+
+    cmake_files = crawl_for_cmake(args.path, excluded_files)
+    lines = generate_rst(cmake_files, args.skip_private, args.skip_undocumented)
     if args.output:
         with open(args.output, 'w') as f:
             f.write('\n'.join(lines))
diff --git a/doc/howto/format1/downloading_test_data.rst b/doc/howto/format1/downloading_test_data.rst
index 4d97154..9ed9c35 100644
--- a/doc/howto/format1/downloading_test_data.rst
+++ b/doc/howto/format1/downloading_test_data.rst
@@ -29,7 +29,7 @@ your project name to avoid conflicts with other packages.
 The second parameter is the URL to read.  If you release your package
 to the ROS build farm, make sure this URL is available reliably.
 Otherwise, tests will fail randomly, annoying everyone.  Contact
-``ros-release at code.ros.org`` if you need to host some data near the
+``ros-release at lists.ros.org`` if you need to host some data near the
 build servers.
 
 The MD5 argument is a good way to avoid testing with corrupted data.
diff --git a/doc/howto/format1/python_nose_configuration.rst b/doc/howto/format1/python_nose_configuration.rst
index 0104e51..bf18792 100644
--- a/doc/howto/format1/python_nose_configuration.rst
+++ b/doc/howto/format1/python_nose_configuration.rst
@@ -22,12 +22,20 @@ CMakeLists.txt
 Declare each nose test like this::
 
   if (CATKIN_ENABLE_TESTING)
-    catkin_add_nosetests(test_your_node tests/test_your_node.py)
+    catkin_add_nosetests(tests/test_your_node.py)
   endif()
 
 This example assumes your tests are defined in the ``tests/``
 subdirectory in your source tree.
 
+You can also let nosetest find all tests recursively::
+
+  if (CATKIN_ENABLE_TESTING)
+    catkin_add_nosetests(tests)
+  endif()
+
+For more info, please have a look at the :ref:`API <catkin_add_nosetests_ref>`.
+
 .. _Nosetest: http://www.ros.org/wiki/nosetest
 .. _roscore: http://www.ros.org/wiki/roscore
 .. _unittest: http://www.ros.org/wiki/unittest
diff --git a/doc/howto/format1/rostest_configuration.rst b/doc/howto/format1/rostest_configuration.rst
index 7ec34b5..bf6769d 100644
--- a/doc/howto/format1/rostest_configuration.rst
+++ b/doc/howto/format1/rostest_configuration.rst
@@ -38,6 +38,29 @@ Finally, declare your rostest launch scripts::
     add_rostest(tests/your_second_rostest.test)
   endif()
 
+In case you have a test that accepts arguments, you can pass them like
+this::
+
+  add_rostest(tests/your_rostest.test ARGS arg1:=true arg2:=false)
+
+If your rostest needs extra data in order to run, you can use the
+``catkin_download_test_data()`` to download the data.
+Read more about :ref:`downloading_test_data_2`.
+Then you can add a dependency between the rostest target and the
+target from ``catkin_download_test_data()``, in order to download the
+data before the rostest runs::
+
+  if (CATKIN_ENABLE_TESTING)
+    find_package(rostest REQUIRED)
+
+    catkin_download_test_data(
+      ${PROJECT_NAME}_32e.pcap
+      http://download.ros.org/data/velodyne/32e.pcap
+      MD5 e41d02aac34f0967c03a5597e1d554a9)
+
+    add_rostest(tests/your_rostest.test DEPENDENCIES ${PROJECT_NAME}_32e.pcap)
+  endif()
+
 If your rostest should contain a gtest executable you can use the
 following convenient function::
 
diff --git a/doc/howto/format2/downloading_test_data.rst b/doc/howto/format2/downloading_test_data.rst
index ae9d4dd..1b2a8c1 100644
--- a/doc/howto/format2/downloading_test_data.rst
+++ b/doc/howto/format2/downloading_test_data.rst
@@ -29,7 +29,7 @@ your project name to avoid conflicts with other packages.
 The second parameter is the URL to read.  If you release your package
 to the ROS build farm, make sure this URL is available reliably.
 Otherwise, tests will fail randomly, annoying everyone.  Contact
-``ros-release at code.ros.org`` if you need to host some data near the
+``ros-release at lists.ros.org`` if you need to host some data near the
 build servers.
 
 The MD5 argument is a good way to avoid testing with corrupted data.
diff --git a/doc/howto/format2/python_nose_configuration.rst b/doc/howto/format2/python_nose_configuration.rst
index b2ed231..20ccb54 100644
--- a/doc/howto/format2/python_nose_configuration.rst
+++ b/doc/howto/format2/python_nose_configuration.rst
@@ -22,12 +22,20 @@ CMakeLists.txt
 Declare each nose test like this::
 
   if (CATKIN_ENABLE_TESTING)
-    catkin_add_nosetests(test_your_node tests/test_your_node.py)
+    catkin_add_nosetests(tests/test_your_node.py)
   endif()
 
 This example assumes your tests are defined in the ``tests/``
 subdirectory in your source tree.
 
-.. _Nosetest: http://wiki.ros.org/nosetest
-.. _roscore: http://wiki.ros.org/roscore
-.. _unittest: http://wiki.ros.org/unittest
+You can also let nosetest find all tests recursively::
+
+  if (CATKIN_ENABLE_TESTING)
+    catkin_add_nosetests(tests)
+  endif()
+
+For more info, please have a look at the :ref:`API <catkin_add_nosetests_ref>`.
+
+.. _Nosetest: http://www.ros.org/wiki/nosetest
+.. _roscore: http://www.ros.org/wiki/roscore
+.. _unittest: http://www.ros.org/wiki/unittest
diff --git a/doc/howto/format2/rostest_configuration.rst b/doc/howto/format2/rostest_configuration.rst
index bd5e45b..4b358f4 100644
--- a/doc/howto/format2/rostest_configuration.rst
+++ b/doc/howto/format2/rostest_configuration.rst
@@ -34,6 +34,29 @@ the conditional testing block::
     add_rostest(tests/your_second_rostest.test)
   endif()
 
+In case you have a test that accepts arguments, you can pass them like
+this::
+
+  add_rostest(tests/your_rostest.test ARGS arg1:=true arg2:=false)
+
+If your rostest needs extra data in order to run, you can use the
+``catkin_download_test_data()`` to download the data.
+Read more about :ref:`downloading_test_data_2`.
+Then you can add a dependency between the rostest target and the
+target from ``catkin_download_test_data()``, in order to download the
+data before the rostest runs::
+
+  if (CATKIN_ENABLE_TESTING)
+    find_package(rostest REQUIRED)
+
+    catkin_download_test_data(
+      ${PROJECT_NAME}_32e.pcap
+      http://download.ros.org/data/velodyne/32e.pcap
+      MD5 e41d02aac34f0967c03a5597e1d554a9)
+
+    add_rostest(tests/your_rostest.test DEPENDENCIES ${PROJECT_NAME}_32e.pcap)
+  endif()
+
 If your rostest also uses a gtest_ executable, there is a convenience
 function::
 
diff --git a/doc/user_guide/variables.rst b/doc/user_guide/variables.rst
index 62f8df0..14641f9 100644
--- a/doc/user_guide/variables.rst
+++ b/doc/user_guide/variables.rst
@@ -71,6 +71,9 @@ They only contain relative paths and are supposed to be relative to the ``${CMAK
 
    This is set to ``lib``.
    On non-Debian distributions it could be set to ``libexec``.
+   Note that setting this variable to anything but ``lib`` or ``libexec`` will
+   not work as expected since tools like ``catkin_find`` will only consider
+   these two locations.
    This variable should not be used directly, use ``CATKIN_PACKAGE_BIN_DESTINATION`` instead.
 
 .. cmake:data:: CATKIN_GLOBAL_PYTHON_DESTINATION
diff --git a/package.xml b/package.xml
index c0bf80b..4f7e82c 100644
--- a/package.xml
+++ b/package.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <package format="2">
   <name>catkin</name>
-  <version>0.6.11</version>
+  <version>0.6.14</version>
   <description>Low-level build system macros and infrastructure for ROS.</description>
   <maintainer email="dthomas at osrfoundation.org">Dirk Thomas</maintainer>
   <license>BSD</license>
diff --git a/python/catkin/builder.py b/python/catkin/builder.py
index b0032a3..8eb2426 100644
--- a/python/catkin/builder.py
+++ b/python/catkin/builder.py
@@ -37,6 +37,10 @@ import multiprocessing
 import os
 import platform
 import re
+try:
+    from shlex import quote
+except ImportError:
+    from pipes import quote
 import stat
 try:
     from StringIO import StringIO
@@ -234,7 +238,7 @@ def run_command(cmd, cwd, quiet=False, colorize=False, add_env=None):
     if proc.returncode:
         if quiet:
             print(out.getvalue())
-        raise subprocess.CalledProcessError(proc.returncode, ' '.join(cmd))
+        raise subprocess.CalledProcessError(proc.returncode, cmd)
     return out.getvalue() if quiet else ''
 
 blue_arrow = '@!@{bf}==>@|@!'
@@ -922,9 +926,13 @@ def build_workspace_isolated(
                 _print_build_error(package, e)
                 # Let users know how to reproduce
                 # First add the cd to the build folder of the package
-                cmd = 'cd ' + os.path.join(buildspace, package.name) + ' && '
+                cmd = 'cd ' + quote(os.path.join(buildspace, package.name)) + ' && '
                 # Then reproduce the command called
-                cmd += ' '.join(e.cmd) if isinstance(e.cmd, list) else e.cmd
+                if isinstance(e.cmd, list):
+                    # quote arguments to allow copy-n-paste of command
+                    cmd += ' '.join([quote(arg) for arg in e.cmd])
+                else:
+                    cmd += e.cmd
                 print(fmt("\n@{rf}Reproduce this error by running:"))
                 print(fmt("@{gf}@!==> @|") + cmd + "\n")
                 sys.exit('Command failed, exiting.')
diff --git a/python/catkin/find_in_workspaces.py b/python/catkin/find_in_workspaces.py
index a875731..4d5623e 100644
--- a/python/catkin/find_in_workspaces.py
+++ b/python/catkin/find_in_workspaces.py
@@ -118,9 +118,11 @@ def find_in_workspaces(search_dirs=None, project=None, path=None, _workspaces=ge
     existing_paths = []
     try:
         for workspace in (_workspaces or []):
+            if 'libexec' in search_dirs:
+                search_dirs.insert(search_dirs.index('libexec'), 'lib')
             for sub in search_dirs:
                 # search in workspace
-                p = os.path.join(workspace, sub if sub != 'libexec' else 'lib')
+                p = os.path.join(workspace, sub)
                 if project:
                     p = os.path.join(p, project)
                 if path:
diff --git a/python/catkin/test_results.py b/python/catkin/test_results.py
index 03dff3d..d81d4db 100644
--- a/python/catkin/test_results.py
+++ b/python/catkin/test_results.py
@@ -113,12 +113,13 @@ def read_junit(filename):
     return (num_tests, num_errors, num_failures)
 
 
-def test_results(test_results_dir):
+def test_results(test_results_dir, show_verbose=False, show_all=False):
     '''
     Collects test results by parsing all xml files in given path,
     attempting to interpret them as junit results.
 
     :param test_results_dir: str foldername
+    :param show_verbose: bool show output for tests which had errors or failed
     :returns: dict {rel_path, (num_tests, num_errors, num_failures)}
     '''
     results = {}
@@ -131,9 +132,16 @@ def test_results(test_results_dir):
             try:
                 num_tests, num_errors, num_failures = read_junit(filename_abs)
             except Exception as e:
-                print('Skipping "%s": %s' % (name, str(e)))
+                if show_all:
+                    print('Skipping "%s": %s' % (name, str(e)))
                 continue
             results[name] = (num_tests, num_errors, num_failures)
+            if show_verbose and (num_errors + num_failures > 0):
+                print("Full test results for '%s'" % (name))
+                print('-------------------------------------------------')
+                with open(filename_abs, 'r') as f:
+                    print(f.read())
+                print('-------------------------------------------------')
     return results
 
 
diff --git a/test/unit_tests/test_find_in_workspace.py b/test/unit_tests/test_find_in_workspace.py
index a7bffaf..6cda6f9 100644
--- a/test/unit_tests/test_find_in_workspace.py
+++ b/test/unit_tests/test_find_in_workspace.py
@@ -57,9 +57,12 @@ class FindInWorkspaceTest(unittest.TestCase):
         self.assertEqual(['bar/include/foo/foopath',
                           'bar/etc/foo/foopath',
                           'bar/lib/foo/foopath',
+                          'bar/libexec/foo/foopath',
                           'baz/include/foo/foopath',
                           'baz/etc/foo/foopath',
-                          'baz/lib/foo/foopath'], checked)
+                          'baz/lib/foo/foopath',
+                          'baz/lib/foo/foopath',
+                          'baz/libexec/foo/foopath'], checked)
         checked = []
         existing = find_in_workspaces(['share', 'etc', 'lib'], None, 'foopath', _workspaces=['bar', 'baz'], considered_paths=checked)
         self.assertEqual([], existing)
diff --git a/test/unit_tests/test_test_results.py b/test/unit_tests/test_test_results.py
index 0cb7f6c..324c40d 100644
--- a/test/unit_tests/test_test_results.py
+++ b/test/unit_tests/test_test_results.py
@@ -1,3 +1,4 @@
+# coding:utf-8
 import os
 import sys
 import unittest
@@ -44,6 +45,45 @@ class TestResultsTest(unittest.TestCase):
         finally:
             shutil.rmtree(rootdir)
 
+    def test_test_results_detail(self):
+        try:
+            oldstdout = sys.stdout
+            sys.stdout = StringIO()
+            rootdir = tempfile.mkdtemp()
+            test_xml = 'test.xml'
+            test_suites = '<testsuites tests="5" failures="3" errors="1" time="35" name="AllTests"></testsuites>'
+            result_file = os.path.join(rootdir, test_xml)
+            with open(result_file, 'w') as fhand:
+                fhand.write(test_suites)
+            results = catkin_test_results.test_results(rootdir, show_verbose=True)
+            self.assertEqual({test_xml: (5, 1, 3)}, results)
+            summary = sys.stdout.getvalue()
+            self.assertTrue(test_xml in summary, summary)
+            self.assertTrue(test_suites in summary, summary)
+        finally:
+            shutil.rmtree(rootdir)
+            sys.stdout = oldstdout
+
+    def test_test_results_detail_with_non_ascii(self):
+        try:
+            oldstdout = sys.stdout
+            sys.stdout = StringIO()
+            rootdir = tempfile.mkdtemp()
+            test_xml = 'test.xml'
+            test_suites = '<testsuites tests="5" failures="3" errors="1" time="35" name="AllTests"><testsuite></testsuite><system-out><![CDATA[robotロボット机器人]]></system-out></testsuites>'
+            result_file = os.path.join(rootdir, test_xml)
+            with open(result_file, 'w') as fhand:
+                fhand.write(test_suites)
+            results = catkin_test_results.test_results(rootdir, show_verbose=True)
+            self.assertEqual({test_xml: (5, 1, 3)}, results)
+            summary = sys.stdout.getvalue()
+            self.assertTrue(test_xml in summary, summary)
+            self.assertTrue(test_suites in summary, summary)
+        finally:
+            shutil.rmtree(rootdir)
+            sys.stdout = oldstdout
+            print(summary)
+
     def test_print_summary(self):
         results = {'test1.xml': (5, 1, 3), 'test2.xml': (7, 2, 4)}
         try:

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/ros/catkin.git



More information about the debian-science-commits mailing list