From c7bfb8acf88ce6f0e46aa5bb4d214e7184e41aea Mon Sep 17 00:00:00 2001 From: Mabel Zhang Date: Tue, 14 Jun 2022 19:05:52 -0400 Subject: [PATCH] Bash completion for flags (#392) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mabel Zhang Signed-off-by: Louise Poubel Co-authored-by: Alejandro Hernández Cordero Co-authored-by: Louise Poubel --- CMakeLists.txt | 5 +++- src/CMakeLists.txt | 28 ++++++++++++++++++ src/cmd/CMakeLists.txt | 12 +++++++- src/cmd/gui.bash_completion.sh | 54 ++++++++++++++++++++++++++++++++++ src/ign_TEST.cc | 34 +++++++++++++++++++++ 5 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 src/cmd/gui.bash_completion.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c76b84f8..046d1bc55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,8 +68,11 @@ ign_find_package(ignition-msgs5 REQUIRED) set(IGN_MSGS_VER ${ignition-msgs5_VERSION_MAJOR}) #-------------------------------------- -# Find if ign command is available +# 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(HAVE_IGN_TOOLS ign) +set (IGN_TOOLS_VER 1) #-------------------------------------- # Find QT diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 61f278399..2d1176c6e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -46,7 +46,35 @@ ign_build_tests(TYPE UNIT LIB_DEPS ${IGNITION-MATH_LIBRARIES} TINYXML2::TINYXML2 + TEST_LIST + gtest_targets ) +foreach(test ${gtest_targets}) + target_compile_definitions(${test} PRIVATE + "PROJECT_SOURCE_DIR=\"${PROJECT_SOURCE_DIR}\"") +endforeach() + +if(TARGET UNIT_ign_TEST) + # Running `ign gazebo` on macOS has problems when run with /usr/bin/ruby + # due to System Integrity Protection (SIP). Try to find ruby from + # homebrew as a workaround. + if (APPLE) + find_program(BREW_RUBY ruby HINTS /usr/local/opt/ruby/bin) + endif() + + target_compile_definitions(UNIT_ign_TEST PRIVATE + "BREW_RUBY=\"${BREW_RUBY} \"") + + target_compile_definitions(UNIT_ign_TEST PRIVATE + "IGN_PATH=\"${HAVE_IGN_TOOLS}\"") + + set(_env_vars) + list(APPEND _env_vars "IGN_CONFIG_PATH=${CMAKE_BINARY_DIR}/test/conf") + + set_tests_properties(UNIT_ign_TEST PROPERTIES + ENVIRONMENT "${_env_vars}") +endif() + add_subdirectory(cmd) add_subdirectory(plugins) diff --git a/src/cmd/CMakeLists.txt b/src/cmd/CMakeLists.txt index 45245a12e..25e6c9d58 100644 --- a/src/cmd/CMakeLists.txt +++ b/src/cmd/CMakeLists.txt @@ -1,4 +1,4 @@ -# Generate a the ruby script. +# Generate the ruby script. # Note that the major version of the library is included in the name. if (APPLE) set(IGN_LIBRARY_NAME lib${PROJECT_NAME_LOWER}.dylib) @@ -11,3 +11,13 @@ configure_file( # Install the ruby command line library in an unversioned location. install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmdgui${PROJECT_VERSION_MAJOR}.rb DESTINATION lib/ruby/ignition) + +# Tack version onto and install the bash completion script +configure_file( + "gui.bash_completion.sh" + "${CMAKE_CURRENT_BINARY_DIR}/gui${PROJECT_VERSION_MAJOR}.bash_completion.sh" @ONLY) +install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/gui${PROJECT_VERSION_MAJOR}.bash_completion.sh + DESTINATION + ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/gz/gz${IGN_TOOLS_VER}.completion.d) diff --git a/src/cmd/gui.bash_completion.sh b/src/cmd/gui.bash_completion.sh new file mode 100644 index 000000000..69b68b24d --- /dev/null +++ b/src/cmd/gui.bash_completion.sh @@ -0,0 +1,54 @@ +#!/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. + +GZ_GUI_COMPLETION_LIST=" + -l --list + -s --standalone + -c --config + -v --verbose + -h --help + --force-version + --versions +" + +function _gz_gui +{ + if [[ ${COMP_WORDS[COMP_CWORD]} == -* ]]; then + # Specify options (-*) word list for this subcommand + COMPREPLY=($(compgen -W "$GZ_GUI_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_gui_flags +{ + for word in $GZ_GUI_COMPLETION_LIST; do + echo "$word" + done +} diff --git a/src/ign_TEST.cc b/src/ign_TEST.cc index eed3196cf..5954542e2 100644 --- a/src/ign_TEST.cc +++ b/src/ign_TEST.cc @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -32,6 +33,9 @@ # define pclose _pclose #endif +static const std::string kIgnCommand( + std::string(BREW_RUBY) + std::string(IGN_PATH)); + ///////////////////////////////////////////////// std::string custom_exec_str(std::string _cmd) { @@ -97,3 +101,33 @@ TEST_F(CmdLine, DETAIL_IGN_UTILS_ADD_DISABLED_PREFIX(list)) EXPECT_TRUE(common::exists(common::joinPaths(this->kFakeHome, ".ignition", "gui"))); } + +////////////////////////////////////////////////// +/// \brief Check --help message and bash completion script for consistent flags +TEST(ignTest, GuiHelpVsCompletionFlags) +{ + // Flags in help message + std::string helpOutput = custom_exec_str(kIgnCommand + " gui --help"); + + // Call the output function in the bash completion script + std::string scriptPath = common::joinPaths(std::string(PROJECT_SOURCE_DIR), + "src", "cmd", "gui.bash_completion.sh"); + + // Equivalent to: + // sh -c "bash -c \". /path/to/gui.bash_completion.sh; _gz_gui_flags\"" + std::string cmd = "bash -c \". " + scriptPath + "; _gz_gui_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; + } +}