Skip to content

Commit

Permalink
Added standalone executable (#65)
Browse files Browse the repository at this point in the history
* Added standalone executable

Signed-off-by: ahcorde <[email protected]>

* make linters happy

Signed-off-by: ahcorde <[email protected]>

* Fixed verbosity

Signed-off-by: ahcorde <[email protected]>

* added feedback

Signed-off-by: ahcorde <[email protected]>

* Added ign plugin -h test and feedback

Signed-off-by: ahcorde <[email protected]>

* Fix plugin_exe_location and improve coverage

Signed-off-by: Steve Peters <[email protected]>

Co-authored-by: Steve Peters <[email protected]>
  • Loading branch information
ahcorde and scpeters authored Nov 17, 2021
1 parent ab03ff3 commit 7c81bcb
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 153 deletions.
27 changes: 25 additions & 2 deletions loader/src/cmd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
add_library(ign STATIC ign.cc)
target_include_directories(ign PUBLIC ${CMAKE_SOURCE_DIR}/loader/include)
target_link_libraries(ign PUBLIC
${PROJECT_LIBRARY_TARGET_NAME}
)

set(plugin_executable ign-plugin)
add_executable(${plugin_executable} plugin_main.cc)
target_link_libraries(${plugin_executable}
ign
ignition-utils${IGN_UTILS_VER}::cli
${loader}
)

set(EXE_INSTALL_DIR "${IGN_LIB_INSTALL_DIR}/ignition/${IGN_DESIGNATION}${PROJECT_VERSION_MAJOR}")

install(
TARGETS
${plugin_executable}
DESTINATION
${EXE_INSTALL_DIR}
)

#===============================================================================
# Generate the ruby script for internal testing.
# Note that the major version of the library is included in the name.
Expand All @@ -7,7 +30,7 @@ set(cmd_script_configured_test "${CMAKE_CURRENT_BINARY_DIR}/test_cmd${IGN_DESIGN

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

configure_file(
"cmd${IGN_DESIGNATION}.rb.in"
Expand All @@ -29,7 +52,7 @@ set(cmd_script_configured "${CMAKE_CURRENT_BINARY_DIR}/cmd${IGN_DESIGNATION}${PR

# 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:${loader}>")
set(plugin_exe_location "../../../${EXE_INSTALL_DIR}/$<TARGET_FILE_NAME:${plugin_executable}>")

configure_file(
"cmd${IGN_DESIGNATION}.rb.in"
Expand Down
168 changes: 24 additions & 144 deletions loader/src/cmd/cmdplugin.rb.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/ruby
#!/usr/bin/env ruby

# Copyright (C) 2020 Open Source Robotics Foundation
# Copyright (C) 2021 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.
Expand All @@ -14,172 +14,52 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# We use 'dl' for Ruby <= 1.9.x and 'fiddle' for Ruby >= 2.0.x
if RUBY_VERSION.split('.')[0] < '2'
require 'dl'
require 'dl/import'
include DL
else
require 'fiddle'
require 'fiddle/import'
include Fiddle
end

require 'optparse'
require 'open3'

# Constants.
LIBRARY_NAME = '@library_location@'
LIBRARY_VERSION = '@PROJECT_VERSION_FULL@'
COMMON_OPTIONS =
" -h [ --help ] Print this help message.\n"\
" \n" +
" --force-version <VERSION> Use a specific library version.\n"\
" \n" +
' --versions Show the available versions.'
COMMANDS = { 'plugin' =>
"Print information about plugins.\n\n" +
" ign plugin [options]\n\n" +
"Options:\n\n" +
" -i [ --info ] Get info about a plugin.\n" +
" Requires the -p option.\n" +
"\n" +
" -p [ --plugin ] arg Path to a plugin.\n" +
" Required with -i.\n" +
"\n" +
" -v [ --verbose ] Print verbose info.\n" +
"\n" +
COMMON_OPTIONS
}
COMMANDS = {
"plugin" => "@plugin_exe_location@",
}

#
# Class for the Ignition plugin command line tools.
# Class for the Ignition @IGN_DESIGNATION@ command line tools.
#
class Cmd
#
# Return a structure describing the options.
#
def parse(args)
options = {}

usage = COMMANDS[args[0]]

# Read the command line arguments.
opt_parser = OptionParser.new do |opts|
opts.banner = usage

opts.on('-h', '--help', 'Print this help message') do
puts usage
exit(0)
end

opts.on('-i', '--info', String,
'Print information about a plugin') do |t|
options['info'] = t
end

opts.on('-p plugin', '--plugin', String,
'Plugin name') do |t|
options['plugin'] = t
end

opts.on('-v', '--verbose', 'Print verbose info') do
options["verbose"] = 1
end

end
begin
opt_parser.parse!(args)
rescue
puts usage
exit(-1)
end

# Check that there is at least one command and there is a plugin that knows
# how to handle it.
if ARGV.empty? || !COMMANDS.key?(ARGV[0]) ||
options.empty?
puts usage
exit(-1)
end

options['command'] = ARGV[0]

options
end # parse()

def execute(args)
options = parse(args)

# puts 'Parsed:'
# puts options
command = args[0]
exe_name = COMMANDS[command]

# Read the plugin that handles the command.
if LIBRARY_NAME[0] == '/'
if exe_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
# absolute path to the executable. This is only used during test mode.
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))
exe_name = File.expand_path(File.join(File.dirname(__FILE__), exe_name))
end
conf_version = LIBRARY_VERSION

begin
Importer.dlload plugin
rescue DLError
puts "Library error: [#{plugin}] not found."
if plugin.end_with? ".dylib"
puts "If this script was executed with /usr/bin/ruby, this error may be caused by
macOS System Integrity Protection. One workaround is to use a different
version of ruby, for example:
brew install ruby
and add the following line to your shell profile:
export PATH=/usr/local/opt/ruby/bin:$PATH"
end
exit(-1)
end

# Read the library version.
Importer.extern 'char* ignitionVersion()'
begin
plugin_version = Importer.ignitionVersion.to_s
rescue DLError
puts "Library error: Problem running 'ignitionVersion()' from #{plugin}."
exit(-1)
end
exe_version = `#{exe_name} --version`.strip

# Sanity check: Verify that the version of the yaml file matches the version
# of the library that we are using.
unless plugin_version.eql? conf_version
unless exe_version.eql? conf_version
puts "Error: Version mismatch. Your configuration file version is
[#{conf_version}] but #{plugin} version is [#{plugin_version}]."
[#{conf_version}] but #{exe_name} version is [#{exe_version}]."
exit(-1)
end

begin
case options['command']
when 'plugin'
if options.key?('info')
if not options.key?('plugin')
puts 'ign plugin --info: missing plugin name (-p <plugin>)'
puts 'Try ign plugin --help'
else
options["verbose"] = 0 if !options.key?('verbose')
Importer.extern 'void cmdPluginInfo(const char *, int)'
Importer.cmdPluginInfo(options['plugin'], options["verbose"])
end
else
puts 'Command error: I do not have an implementation '\
'for this command.'
# Drop command from list of arguments
Open3.popen2e(exe_name, *args[1..-1]) do |_in, out_err, wait_thr|
begin
out_err.each do |line|
print line
end
else
puts 'Command error: I do not have an implementation for '\
"command [ign #{options['command']}]."
exit(wait_thr.value.exitstatus)
rescue Interrupt => e
print e.message
exit(-1)
end
rescue
puts "Library error: Problem running [#{options['command']}]() "\
"from #{plugin}."
end
end
end
14 changes: 7 additions & 7 deletions loader/src/ign.cc → loader/src/cmd/ign.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 Open Source Robotics Foundation
* Copyright (C) 2021 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.
Expand All @@ -15,17 +15,17 @@
*
*/

#include <cstring>
#include <iostream>
#include <string>
#include <unordered_set>

#include "ignition/plugin/Loader.hh"
#include "ignition/plugin/config.hh"

using namespace ignition;
using namespace plugin;
#include "ign.hh"

//////////////////////////////////////////////////
extern "C" void IGNITION_PLUGIN_LOADER_VISIBLE cmdPluginInfo(
extern "C" void cmdPluginInfo(
const char *_plugin, int _verbose)
{
if (!_plugin || std::string(_plugin).empty())
Expand Down Expand Up @@ -73,7 +73,7 @@ extern "C" void IGNITION_PLUGIN_LOADER_VISIBLE cmdPluginInfo(
}

//////////////////////////////////////////////////
extern "C" const char IGNITION_PLUGIN_LOADER_VISIBLE *ignitionVersion()
extern "C" const char *ignitionVersion()
{
return IGNITION_PLUGIN_VERSION_FULL;
return strdup(IGNITION_PLUGIN_VERSION_FULL);
}
32 changes: 32 additions & 0 deletions loader/src/cmd/ign.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2021 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.
*
*/

#ifndef IGNITION_PLUGIN_IGN_HH_
#define IGNITION_PLUGIN_IGN_HH_

#include "ignition/plugin/Export.hh"

/// \brief External hook to read the library version.
/// \return C-string representing the version. Ex.: 0.1.2
extern "C" const char *ignitionVersion();

/// \brief Plugin info
/// \param[in] _plugin Name of the plugin
/// \param[in] _verbose Verbosity level
extern "C" void cmdPluginInfo(const char *_plugin, int _verbose);

#endif
Loading

0 comments on commit 7c81bcb

Please sign in to comment.