Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add app manager plugin #25

Merged
merged 38 commits into from
Jul 9, 2020
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
18a7853
start plugin launch in app_manager
knorth55 Apr 23, 2020
f22106d
start and stop plugin function
knorth55 Apr 23, 2020
379ba32
add plugin loginfo in app_manager
knorth55 Apr 23, 2020
ba1c3cc
pass app in plugin functions
knorth55 Apr 23, 2020
70ad925
load plugins only when it exits
knorth55 Apr 23, 2020
a258184
add exit_code in stop_plugin_attr
knorth55 Apr 23, 2020
9927c1a
refactor plugin and main running order
knorth55 Apr 26, 2020
9f51924
stop plugin functions when shutdown is called
knorth55 Apr 26, 2020
decd203
launch when plugin
knorth55 Apr 26, 2020
a4f5135
load plugin launch when it exists
knorth55 Apr 26, 2020
b1a44fb
use ctx instead of exit_code
knorth55 Apr 26, 2020
c39ffbb
pass exit_code to ctx
knorth55 Apr 26, 2020
2a3da7e
add plugins in AppDefinition
knorth55 Apr 27, 2020
163e0b8
add _current_plugins and _plugin_context
knorth55 Apr 27, 2020
e44d133
fix exit_code for launch
knorth55 Apr 27, 2020
1cf8ff2
pass launch arguments
knorth55 Apr 27, 2020
95d0961
add plugin_args for app plugins
knorth55 Apr 28, 2020
0d201b6
fix order of plugin_launch
knorth55 Apr 28, 2020
4650559
fix formatting roslaunch_args
knorth55 Apr 28, 2020
0fdf7c7
fix typo
knorth55 Apr 28, 2020
8109e94
fix exit_code
knorth55 Apr 28, 2020
9351594
concat list in launch_args
knorth55 Apr 29, 2020
cb23aae
overwrite roslaunch.config.load_config_default for kinetic
knorth55 May 8, 2020
0e6f46d
add __stop_current for shutdown and __stop_current
knorth55 May 16, 2020
9c2898d
support "module: null" syntax for app definition
knorth55 May 16, 2020
5ec3f1c
add app_manager plugin base class
knorth55 May 16, 2020
b013f76
use logdebug in scripts/app_manager
knorth55 May 28, 2020
77df1cf
refactor scripts/app_manager
knorth55 May 28, 2020
f1f3681
fix typo in src/app_manager/app.py
knorth55 May 28, 2020
baa7d4f
replace logging to rospy.loginfo
knorth55 May 28, 2020
486b4e6
use next and catch exception when plugin type is not found
knorth55 May 28, 2020
6655bb0
start python module first, then plugin launch
knorth55 May 28, 2020
ae299a5
add start_plugin_args and stop_plugin_args
knorth55 May 30, 2020
d6d1780
add start_plugin_arg_yaml and stop_plugin_arg_yaml
knorth55 May 30, 2020
bfd8663
add launch_arg_yaml
knorth55 May 30, 2020
d3830fc
add plugin_order to set plugin order
knorth55 May 30, 2020
87a0eb6
update readme to add plugin doc
knorth55 Jul 5, 2020
8e7d1d7
update readme to add app definitions
knorth55 Jul 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,51 @@ message: "app [app_manager/appA] started"
namespace: "/robot/application"
```

## Plugins

You can define `app_manager` plugins as below in app file such as `test.app`.

```yaml
knorth55 marked this conversation as resolved.
Show resolved Hide resolved
plugins: # plugin definitions
- name: mail_notifier_plugin # name to identify this plugin
type: app_notifier/mail_notifier_plugin # plugin type
launch_args: # arguments for plugin launch file
- foo: hello
launch_arg_yaml: /etc/mail_notifier_launch_arg.yaml # argument yaml file for plugin launch file
# in this case, these arguments will be passed.
# {"hoge": 100, "fuga": 30, "bar": 10} will be passed to start plugin
# {"hoge": 50, "fuga": 30} will be passed to stop plugin
plugin_args: # arguments for plugin function
- hoge: 10
- fuga: 30
start_plugin_args: # arguments for start plugin function
- hoge: 100 # arguments for start plugin function arguments (it overwrites plugin_args hoge: 10 -> 100)
- bar: 10
stop_plugin_args: # arguments for stop plugin function
- hoge: 50 # arguments for stop plugin function arguments (it overwrites plugin_args hoge: 10 -> 50)
plugin_arg_yaml: /etc/mail_notifier_plugin_arg.yaml # argument yaml file for plugin function arguments
- name: rosbag_recorder_plugin # another plugin
type app_recorder/rosbag_recorder_plugin
launch_args:
rosbag_path: /tmp
rosbag_title: test.bag
compress: true
rosbag_topic_names:
- /rosout
- /tf
- /tf_static
plugin_order: # plugin running orders. if you don't set field, plugin will be run in order in plugins field
start_plugin_order: # start plugin running order
- rosbag_recorder_plugin # 1st plugin name
- mail_notifier_plugin #2nd plugin name
stop_plugin_order: # start plugin running order
- rosbag_recorder_plugin
- mail_notifier_plugin
```

Sample plugin repository is [knorth55/app_manager_utils](https://github.com/knorth55/app_manager_utils).

For more detailed information, please read [#25](https://github.com/PR2/app_manager/pull/25).

## Maintainer

Expand Down
26 changes: 21 additions & 5 deletions scripts/app_manager
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import rospkg
from argparse import ArgumentParser
import os
import sys
import yaml

import app_manager
import rospy
Expand All @@ -25,15 +26,23 @@ def main():
args = parser.parse_args(argv[1:])

applist = []
plugin_yamls = []
rospack = rospkg.RosPack()
depend_pkgs = rospack.get_depends_on('app_manager', implicit=False)

rospy.loginfo("Loading from plugin definitions")
for depend_pkg in depend_pkgs:
m = rospack.get_manifest(depend_pkg)
app_dir = m.get_export('app_manager', 'app_dir')
if len(app_dir) != 0:
applist += app_dir
manifest = rospack.get_manifest(depend_pkg)
app_dirs = manifest.get_export('app_manager', 'app_dir')
plugin_yaml = manifest.get_export('app_manager', 'plugin')
if len(app_dirs) != 0:
applist += app_dirs
for app_dir in app_dirs:
rospy.logdebug('Loading app in {}'.format(app_dir))
if len(plugin_yaml) != 0:
plugin_yamls += plugin_yaml
for plugin_y in plugin_yaml:
rospy.logdebug('Loading plugin in {}'.format(plugin_y))

if args.applist is not None:
rospy.loginfo("Loading applist from --applist option")
Expand All @@ -47,6 +56,12 @@ def main():
if len(applist) == 0:
rospy.logwarn('No applist directory found.')

plugins = []
for plugin_yaml in plugin_yamls:
with open(plugin_yaml) as f:
plugin = yaml.safe_load(f)
plugins += plugin

robot_name = rospy.get_param('/robot/name', 'robot')
robot_type = rospy.get_param("/robot/type", None)
if robot_type is None:
Expand Down Expand Up @@ -76,7 +91,8 @@ def main():
rospy.logerr("Failed to load exchange: {}".format(e))
sys.exit(1)

am = app_manager.AppManager(robot_name, interface_master, app_list, exchange)
am = app_manager.AppManager(
robot_name, interface_master, app_list, exchange, plugins)

rospy.on_shutdown(am.shutdown)

Expand Down
1 change: 1 addition & 0 deletions src/app_manager/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from .app import AppDefinition
from .app_manager import AppManager
from .app_list import AppList, get_default_applist_directory
from .app_manager_plugin import AppManagerPlugin
from .exchange import Exchange
from .exceptions import AppException, NotFoundException, \
InvalidAppException, LaunchException, InternalAppException
40 changes: 37 additions & 3 deletions src/app_manager/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ def __repr__(self):

class AppDefinition(object):
__slots__ = ['name', 'display_name', 'description', 'platform',
'launch', 'interface', 'clients', 'icon']
'launch', 'interface', 'clients', 'icon', 'plugins', 'plugin_order']
def __init__(self, name, display_name, description, platform,
launch, interface, clients, icon=None):
launch, interface, clients, icon=None, plugins=None, plugin_order=None):
self.name = name
self.display_name = display_name
self.description = description
Expand All @@ -86,6 +86,8 @@ def __init__(self, name, display_name, description, platform,
self.interface = interface
self.clients = clients
self.icon = icon
self.plugins = plugins
self.plugin_order = plugin_order

def __repr__(self):
d = {}
Expand Down Expand Up @@ -222,6 +224,35 @@ def _AppDefinition_load_clients_entry(app_data, appfile="UNKNOWN"):
clients.append(Client(client_type, manager_data, app_data))
return clients


def _AppDefinition_load_plugins_entry(app_data, appfile="UNKNOWN"):
"""
@raise InvalidAppException: if app definition is invalid.
"""
# load/validate launch entry
try:
plugins = app_data.get('plugins', '')
if plugins == '':
return None
return plugins
except ValueError as e:
raise InvalidAppException("Malformed appfile [%s]: bad plugins entry: %s"%(appfile, e))


def _AppDefinition_load_plugin_order_entry(app_data, appfile="UNKNOWN"):
"""
@raise InvalidAppException: if app definition is invalid.
"""
# load/validate launch entry
try:
plugin_order = app_data.get('plugin_order', '')
if plugin_order == '':
return None
return plugin_order
except ValueError as e:
raise InvalidAppException("Malformed appfile [%s]: bad plugin_order entry: %s"%(appfile, e))


def load_AppDefinition_from_file(appfile, appname):
"""
@raise InvalidAppExcetion: if app definition is invalid.
Expand All @@ -242,9 +273,12 @@ def load_AppDefinition_from_file(appfile, appname):
interface = _AppDefinition_load_interface_entry(app_data, appfile)
clients = _AppDefinition_load_clients_entry(app_data, appfile)
icon = _AppDefinition_load_icon_entry(app_data, appfile)
plugins = _AppDefinition_load_plugins_entry(app_data, appfile)
plugin_order = _AppDefinition_load_plugin_order_entry(app_data, appfile)

return AppDefinition(appname, display_name, description, platform,
launch, interface, clients, icon)
launch, interface, clients, icon,
plugins, plugin_order)

def load_AppDefinition_by_name(appname):
"""
Expand Down
Loading