diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cbf89f6..6fad94f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,12 @@ ign_configure_project(VERSION_SUFFIX) # No project-specific options yet for ign-plugin +if (UNIX AND NOT APPLE) + set (EXTRA_TEST_LIB_DEPS stdc++fs) +else() + set (EXTRA_TEST_LIB_DEPS) +endif() + #============================================================================ # Search for project-specific dependencies #============================================================================ @@ -37,8 +43,11 @@ ign_find_package(DL #-------------------------------------- # Find ignition-tools +# Find if command is available. This is used to enable tests. +# Note that CLI files are installed regardless of whether the dependency is +# available during build time find_program(IGN_TOOLS_PROGRAM ign) - +set(IGN_TOOLS_VER 1) #============================================================================ # Configure the build diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index 4d53cd0b..6420b909 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -20,7 +20,9 @@ target_link_libraries(${loader} ign_build_tests( TYPE UNIT SOURCES ${tests} - LIB_DEPS ${loader} + LIB_DEPS + ${loader} + ${EXTRA_TEST_LIB_DEPS} TEST_LIST test_targets) foreach(test ${test_targets}) diff --git a/loader/conf/CMakeLists.txt b/loader/conf/CMakeLists.txt index fefd7c34..f64809e7 100644 --- a/loader/conf/CMakeLists.txt +++ b/loader/conf/CMakeLists.txt @@ -25,3 +25,13 @@ configure_file( # Install the yaml configuration files in an unversioned location. install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${IGN_DESIGNATION}${PROJECT_VERSION_MAJOR}.yaml DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/ignition/) + +# Tack version onto and install the bash completion script +configure_file( + "plugin.bash_completion.sh" + "${CMAKE_CURRENT_BINARY_DIR}/plugin${PROJECT_VERSION_MAJOR}.bash_completion.sh" @ONLY) +install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/plugin${PROJECT_VERSION_MAJOR}.bash_completion.sh + DESTINATION + ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/gz/gz${IGN_TOOLS_VER}.completion.d) diff --git a/loader/conf/plugin.bash_completion.sh b/loader/conf/plugin.bash_completion.sh new file mode 100644 index 00000000..85723413 --- /dev/null +++ b/loader/conf/plugin.bash_completion.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# +# Copyright (C) 2022 Open Source Robotics Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# bash tab-completion + +# This is a per-library function definition, used in conjunction with the +# top-level entry point in ign-tools. + +# TODO(anyone): Update for ign-plugin2, add --help-all and --version. Remove +# --versions and --force-version +GZ_PLUGIN_COMPLETION_LIST=" + -i --info + -p --plugin + -v --verbose + -h --help + --force-version + --versions +" + +function _gz_plugin +{ + if [[ ${COMP_WORDS[COMP_CWORD]} == -* ]]; then + # Specify options (-*) word list for this subcommand + COMPREPLY=($(compgen -W "$GZ_PLUGIN_COMPLETION_LIST" \ + -- "${COMP_WORDS[COMP_CWORD]}" )) + return + else + # Just use bash default auto-complete, because we never have two + # subcommands in the same line. If that is ever needed, change here to + # detect subsequent subcommands + COMPREPLY=($(compgen -o default -- "${COMP_WORDS[COMP_CWORD]}")) + return + fi +} + +function _gz_plugin_flags +{ + for word in $GZ_PLUGIN_COMPLETION_LIST; do + echo "$word" + done +} diff --git a/loader/src/ign_TEST.cc b/loader/src/ign_TEST.cc index e5036537..9a2adc38 100644 --- a/loader/src/ign_TEST.cc +++ b/loader/src/ign_TEST.cc @@ -15,6 +15,8 @@ * */ +#include +#include #include #include @@ -183,3 +185,38 @@ TEST(ignTest, PluginInfoVerboseDummyPlugins) output.find("There are 2 aliases with a name collision")) << output; } + +////////////////////////////////////////////////// +/// \brief Check --help message and bash completion script for consistent flags +TEST(ignTest, PluginHelpVsCompletionFlags) +{ + // Path to ign executable + std::string ign = std::string(IGN_PATH); + + // Flags in help message + std::string helpOutput = custom_exec_str(ign + " plugin --help " + + g_ignVersion); + + // Call the output function in the bash completion script + std::filesystem::path scriptPath = IGN_PLUGIN_SOURCE_DIR; + scriptPath = scriptPath / "loader" / "conf" / "plugin.bash_completion.sh"; + + // Equivalent to: + // sh -c "bash -c \". /path/to/plugin.bash_completion.sh; _gz_plugin_flags\"" + std::string cmd = "bash -c \". " + scriptPath.string() + + "; _gz_plugin_flags\""; + std::string scriptOutput = custom_exec_str(cmd); + + // Tokenize script output + std::istringstream iss(scriptOutput); + std::vector flags((std::istream_iterator(iss)), + std::istream_iterator()); + + EXPECT_GT(flags.size(), 0u); + + // Match each flag in script output with help message + for (std::string flag : flags) + { + EXPECT_NE(std::string::npos, helpOutput.find(flag)) << helpOutput; + } +}