Skip to content

Commit

Permalink
Add bash completion (#329)
Browse files Browse the repository at this point in the history
Signed-off-by: Addisu Z. Taddese <[email protected]>
  • Loading branch information
azeey authored May 2, 2023
1 parent fe66f33 commit e51c672
Show file tree
Hide file tree
Showing 4 changed files with 256 additions and 12 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ ign_find_package(ignition-tools QUIET)
if (ignition-tools_FOUND)
set (HAVE_IGN_TOOLS TRUE)
endif()
set (IGN_TOOLS_VER 1)

#============================================================================
# Configure the build
Expand Down
62 changes: 53 additions & 9 deletions src/cmd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,60 @@
# Generate a the ruby script.
#===============================================================================
# Generate the ruby script for internal testing.
# Note that the major version of the library is included in the name.
# Ex: cmdfuel0.rb
if (APPLE)
set(IGN_LIBRARY_NAME lib${PROJECT_NAME_LOWER}.dylib)
else()
set(IGN_LIBRARY_NAME lib${PROJECT_NAME_LOWER}.so)
endif()
# Unlike other gz libraries, the ruby script for the fuel_tools library is called cmdfuel.rb instead of cmdfuel_tools.rb
set(CMD_NAME cmdfuel)
set(cmd_script_generated_test "${CMAKE_BINARY_DIR}/test/lib/$<CONFIG>/ruby/ignition/${CMD_NAME}${PROJECT_VERSION_MAJOR}.rb")
set(cmd_script_configured_test "${CMAKE_CURRENT_BINARY_DIR}/test_${CMD_NAME}${PROJECT_VERSION_MAJOR}.rb.configured")

# Set the library_location variable to the full path of the library file within
# the build directory.
set(library_location "$<TARGET_FILE:${PROJECT_LIBRARY_TARGET_NAME}>")

configure_file(
"cmdfuel.rb.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmdfuel${PROJECT_VERSION_MAJOR}.rb" @ONLY)
"${CMD_NAME}.rb.in"
"${cmd_script_configured_test}"
@ONLY)

file(GENERATE
OUTPUT "${cmd_script_generated_test}"
INPUT "${cmd_script_configured_test}")


#===============================================================================
# Used for the installed version.
# Generate the ruby script that gets installed.
# Note that the major version of the library is included in the name.
# Ex: cmdfuel0.rb
set(cmd_script_generated "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${CMD_NAME}${PROJECT_VERSION_MAJOR}.rb")
set(cmd_script_configured "${CMAKE_CURRENT_BINARY_DIR}/${CMD_NAME}${PROJECT_VERSION_MAJOR}.rb.configured")

# Set the library_location variable to the relative path to the library file
# within the install directory structure.
set(library_location "../../../${CMAKE_INSTALL_LIBDIR}/$<TARGET_FILE_NAME:${PROJECT_LIBRARY_TARGET_NAME}>")

configure_file(
"${CMD_NAME}.rb.in"
"${cmd_script_configured}"
@ONLY)

file(GENERATE
OUTPUT "${cmd_script_generated}"
INPUT "${cmd_script_configured}")

# Install the ruby command line library in an unversioned location.
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmdfuel${PROJECT_VERSION_MAJOR}.rb DESTINATION lib/ruby/ignition)
install(FILES ${cmd_script_generated} DESTINATION lib/ruby/ignition)


#===============================================================================
# Bash completion

# Tack version onto and install the bash completion script
configure_file(
"fuel.bash_completion.sh"
"${CMAKE_CURRENT_BINARY_DIR}/fuel${PROJECT_VERSION_MAJOR}.bash_completion.sh" @ONLY)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/fuel${PROJECT_VERSION_MAJOR}.bash_completion.sh
DESTINATION
${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/gz/gz${IGN_TOOLS_VER}.completion.d)
14 changes: 11 additions & 3 deletions src/cmd/cmdfuel.rb.in
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ end
require 'optparse'

# Constants.
LIBRARY_NAME = '@IGN_LIBRARY_NAME@'
LIBRARY_NAME = '@library_location@'
LIBRARY_VERSION = '@PROJECT_VERSION_FULL@'
MAX_PARALLEL_JOBS = 16

Expand Down Expand Up @@ -311,7 +311,15 @@ class Cmd
options = parse(args)

# Read the plugin that handles the command.
plugin = LIBRARY_NAME
if LIBRARY_NAME[0] == '/'
# If the first character is a slash, we'll assume that we've been given an
# absolute path to the library. This is only used during test mode.
plugin = LIBRARY_NAME
else
# We're assuming that the library path is relative to the current
# location of this script.
plugin = File.expand_path(File.join(File.dirname(__FILE__), LIBRARY_NAME))
end
conf_version = LIBRARY_VERSION

begin
Expand Down Expand Up @@ -405,7 +413,7 @@ class Cmd
end
rescue
puts "Library error: Problem running [#{options['subcommand']}]() "\
"from @IGN_LIBRARY_NAME@."
"from #{plugin}."
end # begin
end # execute
end # class
191 changes: 191 additions & 0 deletions src/cmd/fuel.bash_completion.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
#!/usr/bin/env bash
#
# Copyright (C) 2023 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_FUEL_SUBCOMMANDS="
delete
download
edit
list
meta
upload
"

# TODO: In Fortress+, for each of the completion lists, remove --force-version
# and --versions. Add --help-all. Update ../gz_TEST.cc accordingly.
GZ_FUEL_COMPLETION_LIST="
-c --config
-h --help
-v --verbose
--force-version
--versions
"

GZ_DELETE_COMPLETION_LIST="
--header
-c --config
-h --help
-u --url
--force-version
--versions
"

GZ_DOWNLOAD_COMPLETION_LIST="
--header
-c --config
-h --help
-j --jobs
-t --type
-u --url
--force-version
--versions
"

GZ_EDIT_COMPLETION_LIST="
--header
-b --public
-c --config
-h -help
-m --model
-p --private
-u --url
--force-version
--versions
"

GZ_LIST_COMPLETION_LIST="
-c --config
-h --help
-o --owner
-r --raw
-t --type
-u --url
--force-version
--versions
"

GZ_META_COMPLETION_LIST="
--config2pbtxt
--pbtxt2config
-c --config
-h --help
--force-version
--versions
"

GZ_UPLOAD_COMPLETION_LIST="
--header
-c --config
-h --help
-m --model
-p --private
-u --url
--force-version
--versions
"

function __get_comp_from_list {
if [[ ${COMP_WORDS[COMP_CWORD]} == -* ]]; then
# Specify options (-*) word list for this subcommand
COMPREPLY=($(compgen -W "$@" \
-- "${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_fuel_delete
{
__get_comp_from_list "$GZ_DELETE_COMPLETION_LIST"
}

function _gz_fuel_download
{
__get_comp_from_list "$GZ_DOWNLOAD_COMPLETION_LIST"
}

function _gz_fuel_edit
{
__get_comp_from_list "$GZ_EDIT_COMPLETION_LIST"
}

function _gz_fuel_list
{
__get_comp_from_list "$GZ_LIST_COMPLETION_LIST"
}

function _gz_fuel_meta
{
__get_comp_from_list "$GZ_META_COMPLETION_LIST"
}

function _gz_fuel_upload
{
__get_comp_from_list "$GZ_UPLOAD_COMPLETION_LIST"
}

# This searches the current list of typed words for one of the subcommands
# listed in GZ_FUEL_SUBCOMMANDS. This should work for most cases, but may fail
# if a word that looks like a subocmmand is used as an argument to a flag. Eg.
# `gz fuel --config download list`. Here `download` is an argument to
# `--config`, but this function will think that it's the subcommand. Since this
# seems like a rare scenario, we accept this failure mode.
function __get_subcommand
{
local known_subcmd
local subcmd
for ((i=2; $i<=$COMP_CWORD; i++)); do
for subcmd in $GZ_FUEL_SUBCOMMANDS; do
if [[ "${COMP_WORDS[i]}" == "$subcmd" ]]; then
known_subcmd="$subcmd"
fi
done
done
echo "$known_subcmd"
}

function _gz_fuel
{
if [[ $COMP_CWORD > 2 ]]; then
local known_subcmd=$(__get_subcommand)
if [[ ! -z $known_subcmd ]]; then
local subcmd_func="_gz_fuel_$known_subcmd"
if [[ "$(type -t $subcmd_func)" == 'function' ]]; then
$subcmd_func
return
fi
fi
fi

# If a subcommand is not found, assume we're still completing the subcommands
# or flags for `fuel`.
if [[ ${COMP_WORDS[COMP_CWORD]} == -* ]]; then
COMPREPLY=($(compgen -W "$GZ_FUEL_COMPLETION_LIST" \
-- "${COMP_WORDS[COMP_CWORD]}" ))
else
COMPREPLY=($(compgen -W "${GZ_FUEL_SUBCOMMANDS}" -- ${cur}))
fi
}

0 comments on commit e51c672

Please sign in to comment.