roby 0.8.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.deep-cover.rb +3 -0
- data/.gitattributes +1 -0
- data/.gitignore +24 -0
- data/.simplecov +10 -0
- data/.travis.yml +17 -0
- data/.yardopts +4 -0
- data/Gemfile +15 -0
- data/README.md +11 -0
- data/Rakefile +47 -177
- data/benchmark/{alloc_misc.rb → attic/alloc_misc.rb} +2 -2
- data/benchmark/{discovery_latency.rb → attic/discovery_latency.rb} +19 -19
- data/benchmark/{garbage_collection.rb → attic/garbage_collection.rb} +9 -9
- data/benchmark/{genom.rb → attic/genom.rb} +0 -0
- data/benchmark/attic/transactions.rb +62 -0
- data/benchmark/plan_basic_operations.rb +28 -0
- data/benchmark/relations/graph.rb +63 -0
- data/benchmark/ruby/identity.rb +18 -0
- data/benchmark/ruby/set_intersect_vs_hash_merge.rb +39 -0
- data/benchmark/ruby/yield_vs_block.rb +35 -0
- data/benchmark/run +5 -0
- data/benchmark/synthetic_plan_modifications_with_transactions.rb +79 -0
- data/benchmark/transactions.rb +99 -51
- data/bin/roby +38 -197
- data/bin/roby-display +14 -0
- data/bin/roby-log +3 -176
- data/doc/guide/{src → attic}/abstraction/achieve_with.page +1 -1
- data/doc/guide/{src → attic}/abstraction/forwarding.page +1 -1
- data/doc/guide/{src → attic}/abstraction/hierarchy.page +1 -1
- data/doc/guide/{src → attic}/abstraction/index.page +1 -1
- data/doc/guide/{src → attic}/abstraction/task_models.page +1 -1
- data/doc/guide/{overview.rdoc → attic/cycle/api_overview.rdoc} +6 -1
- data/doc/guide/{src → attic}/cycle/cycle-overview.png +0 -0
- data/doc/guide/{src → attic}/cycle/cycle-overview.svg +0 -0
- data/doc/guide/attic/cycle/error_handling.page +98 -0
- data/doc/guide/{src → attic}/cycle/error_instantaneous_repair.png +0 -0
- data/doc/guide/{src → attic}/cycle/error_instantaneous_repair.svg +0 -0
- data/doc/guide/{src/cycle/error_handling.page → attic/cycle/error_sources.page} +46 -89
- data/doc/guide/{src → attic}/cycle/garbage_collection.page +1 -1
- data/doc/guide/{src → attic}/cycle/index.page +1 -1
- data/doc/guide/{src → attic}/cycle/propagation.page +11 -1
- data/doc/guide/{src → attic}/cycle/propagation_diamond.png +0 -0
- data/doc/guide/{src → attic}/cycle/propagation_diamond.svg +0 -0
- data/doc/guide/attic/plans/building_plans.page +89 -0
- data/doc/guide/attic/plans/code.page +192 -0
- data/doc/guide/{src/basics → attic/plans}/events.page +3 -4
- data/doc/guide/attic/plans/index.page +7 -0
- data/doc/guide/{plan_modifications.rdoc → attic/plans/plan_modifications.rdoc} +5 -3
- data/doc/guide/{src/basics → attic/plans}/plan_objects.page +2 -1
- data/doc/guide/attic/plans/querying_plans.page +5 -0
- data/doc/guide/{src/basics → attic/plans}/tasks.page +20 -20
- data/doc/guide/config.yaml +7 -4
- data/doc/guide/ext/extended_menu.rb +29 -0
- data/doc/guide/ext/init.rb +6 -0
- data/doc/guide/ext/rdoc_links.rb +7 -6
- data/doc/guide/src/advanced_concepts/history.page +5 -0
- data/doc/guide/src/advanced_concepts/index.page +11 -0
- data/doc/guide/src/advanced_concepts/recognizing_patterns.page +83 -0
- data/doc/guide/src/advanced_concepts/scheduling.page +87 -0
- data/doc/guide/src/advanced_concepts/transactions.page +5 -0
- data/doc/guide/src/advanced_concepts/unreachability.page +42 -0
- data/doc/guide/src/base.template +96 -0
- data/doc/guide/src/basics_shell_header.txt +5 -7
- data/doc/guide/src/building/action_coordination.page +96 -0
- data/doc/guide/src/building/actions.page +124 -0
- data/doc/guide/src/building/file_layout.page +71 -0
- data/doc/guide/src/building/index.page +50 -0
- data/doc/guide/src/building/patterns.page +86 -0
- data/doc/guide/src/building/patterns_forwarding.png +0 -0
- data/doc/guide/src/building/patterns_forwarding.svg +277 -0
- data/doc/guide/src/building/runtime.page +95 -0
- data/doc/guide/src/building/task_models.page +94 -0
- data/doc/guide/src/building/tasks.page +284 -0
- data/doc/guide/src/concepts/error_handling.page +100 -0
- data/doc/guide/src/concepts/exception_propagation.png +0 -0
- data/doc/guide/src/concepts/exception_propagation.svg +445 -0
- data/doc/guide/src/concepts/execution.page +85 -0
- data/doc/guide/src/concepts/execution.png +0 -0
- data/doc/guide/src/concepts/execution.svg +573 -0
- data/doc/guide/src/concepts/execution_cycle.png +0 -0
- data/doc/guide/src/concepts/garbage_collection.page +57 -0
- data/doc/guide/src/concepts/index.page +27 -0
- data/doc/guide/src/concepts/plans.page +101 -0
- data/doc/guide/src/concepts/policy.page +31 -0
- data/doc/guide/src/concepts/reactor.page +61 -0
- data/doc/guide/src/concepts/simple_plan_example.png +0 -0
- data/doc/guide/src/concepts/simple_plan_example.svg +376 -0
- data/doc/guide/src/default.template +9 -74
- data/doc/guide/src/event_relations/forward.page +71 -0
- data/doc/guide/src/event_relations/index.page +12 -0
- data/doc/guide/src/event_relations/scheduling_constraints.page +43 -0
- data/doc/guide/src/event_relations/signal.page +55 -0
- data/doc/guide/src/event_relations/temporal_constraints.page +77 -0
- data/doc/guide/src/htmldoc.metainfo +21 -8
- data/doc/guide/src/index.page +8 -3
- data/doc/guide/src/{introduction/install.page → installation/index.page} +37 -25
- data/doc/guide/src/installation/publications.page +14 -0
- data/doc/guide/src/{introduction → installation}/videos.page +14 -7
- data/doc/guide/src/interacting/index.page +16 -0
- data/doc/guide/src/interacting/run.page +33 -0
- data/doc/guide/src/interacting/shell.page +95 -0
- data/doc/guide/src/plugins/creating_plugins.page +72 -0
- data/doc/guide/src/plugins/index.page +27 -5
- data/doc/guide/src/plugins/{fault_tolerance.page → standard_plugins/fault_tolerance.page} +2 -2
- data/doc/guide/src/plugins/standard_plugins/index.page +11 -0
- data/doc/guide/src/plugins/{subsystems.page → standard_plugins/subsystems.page} +2 -2
- data/doc/guide/src/style_screen.css +687 -0
- data/doc/guide/src/task_relations/dependency.page +107 -0
- data/doc/guide/src/task_relations/executed_by.page +77 -0
- data/doc/guide/src/task_relations/index.page +12 -0
- data/doc/guide/src/task_relations/new_relations.page +119 -0
- data/doc/guide/src/task_relations/planned_by.page +46 -0
- data/doc/guide/src/tutorial/app.page +117 -0
- data/doc/guide/src/{basics → tutorial}/code_examples.page +6 -5
- data/doc/guide/src/{basics → tutorial}/dry.page +15 -15
- data/doc/guide/src/{basics → tutorial}/errors.page +43 -68
- data/doc/guide/src/tutorial/events.page +195 -0
- data/doc/guide/src/{basics → tutorial}/hierarchy.page +53 -52
- data/doc/guide/src/tutorial/index.page +13 -0
- data/doc/guide/src/tutorial/log_replay/goForward_1.png +0 -0
- data/doc/guide/src/tutorial/log_replay/goForward_2.png +0 -0
- data/doc/guide/src/tutorial/log_replay/goForward_3.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/goForward_4.png +0 -0
- data/doc/guide/src/tutorial/log_replay/goForward_5.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_1.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_2.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_3.png +0 -0
- data/doc/guide/src/tutorial/log_replay/moveto_code_error.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_1.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_2.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_3.png +0 -0
- data/doc/guide/src/tutorial/log_replay/plan_repair_4.png +0 -0
- data/doc/guide/src/tutorial/log_replay/roby_log_main_window.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/roby_log_relation_window.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/roby_replay_event_representation.png +0 -0
- data/doc/guide/src/tutorial/relations_display.page +153 -0
- data/doc/guide/src/{basics → tutorial}/roby_cycle_overview.png +0 -0
- data/doc/guide/src/tutorial/shell.page +121 -0
- data/doc/guide/src/{basics → tutorial}/summary.page +1 -1
- data/doc/guide/src/tutorial/tasks.page +374 -0
- data/lib/roby.rb +102 -47
- data/lib/roby/actions.rb +17 -0
- data/lib/roby/actions/action.rb +80 -0
- data/lib/roby/actions/interface.rb +45 -0
- data/lib/roby/actions/library.rb +23 -0
- data/lib/roby/actions/models/action.rb +224 -0
- data/lib/roby/actions/models/coordination_action.rb +58 -0
- data/lib/roby/actions/models/interface.rb +22 -0
- data/lib/roby/actions/models/interface_base.rb +294 -0
- data/lib/roby/actions/models/library.rb +12 -0
- data/lib/roby/actions/models/method_action.rb +90 -0
- data/lib/roby/actions/task.rb +114 -0
- data/lib/roby/and_generator.rb +125 -0
- data/lib/roby/app.rb +2795 -829
- data/lib/roby/app/autotest_console_reporter.rb +138 -0
- data/lib/roby/app/base.rb +21 -0
- data/lib/roby/app/cucumber.rb +2 -0
- data/lib/roby/app/cucumber/controller.rb +439 -0
- data/lib/roby/app/cucumber/helpers.rb +280 -0
- data/lib/roby/app/cucumber/world.rb +32 -0
- data/lib/roby/app/debug.rb +136 -0
- data/lib/roby/app/gen.rb +2 -0
- data/lib/roby/app/rake.rb +178 -38
- data/lib/roby/app/robot_config.rb +9 -0
- data/lib/roby/app/robot_names.rb +115 -0
- data/lib/roby/app/run.rb +3 -2
- data/lib/roby/app/scripts.rb +72 -0
- data/lib/roby/app/scripts/autotest.rb +173 -0
- data/lib/roby/app/scripts/display.rb +2 -0
- data/lib/roby/app/scripts/restart.rb +52 -0
- data/lib/roby/app/scripts/results.rb +17 -8
- data/lib/roby/app/scripts/run.rb +155 -24
- data/lib/roby/app/scripts/shell.rb +147 -62
- data/lib/roby/app/scripts/test.rb +107 -22
- data/lib/roby/app/test_reporter.rb +74 -0
- data/lib/roby/app/test_server.rb +159 -0
- data/lib/roby/app/vagrant.rb +47 -0
- data/lib/roby/backports.rb +16 -0
- data/lib/roby/cli/display.rb +190 -0
- data/lib/roby/cli/exceptions.rb +17 -0
- data/lib/roby/cli/gen/actions/class.rb +5 -0
- data/lib/roby/cli/gen/actions/test.rb +6 -0
- data/lib/roby/cli/gen/app/.yardopts +6 -0
- data/lib/roby/cli/gen/app/README.md +28 -0
- data/lib/roby/cli/gen/app/Rakefile +15 -0
- data/{app → lib/roby/cli/gen/app}/config/app.yml +29 -39
- data/lib/roby/cli/gen/app/models/.gitattributes +1 -0
- data/{app → lib/roby/cli/gen/app/scripts}/controllers/.gitattributes +0 -0
- data/{app/data/.gitattributes → lib/roby/cli/gen/app/test/.gitignore} +0 -0
- data/lib/roby/cli/gen/class/class.rb +6 -0
- data/lib/roby/cli/gen/class/test.rb +7 -0
- data/lib/roby/cli/gen/helpers.rb +203 -0
- data/lib/roby/cli/gen/module/module.rb +5 -0
- data/lib/roby/cli/gen/module/test.rb +6 -0
- data/lib/roby/cli/gen/roby_app/config/init.rb +17 -0
- data/lib/roby/cli/gen/roby_app/config/robots/robot.rb +40 -0
- data/lib/roby/cli/gen/task/class.rb +44 -0
- data/lib/roby/cli/gen/task/test.rb +6 -0
- data/lib/roby/cli/gen_main.rb +120 -0
- data/lib/roby/cli/log.rb +276 -0
- data/lib/roby/cli/log/flamegraph.html +499 -0
- data/lib/roby/cli/log/flamegraph_renderer.rb +88 -0
- data/lib/roby/cli/main.rb +153 -0
- data/lib/roby/coordination.rb +60 -0
- data/lib/roby/coordination/action_script.rb +25 -0
- data/lib/roby/coordination/action_state_machine.rb +125 -0
- data/lib/roby/coordination/actions.rb +106 -0
- data/lib/roby/coordination/base.rb +145 -0
- data/lib/roby/coordination/calculus.rb +40 -0
- data/lib/roby/coordination/child.rb +28 -0
- data/lib/roby/coordination/event.rb +29 -0
- data/lib/roby/coordination/fault_handler.rb +25 -0
- data/lib/roby/coordination/fault_handling_task.rb +13 -0
- data/lib/roby/coordination/fault_response_table.rb +110 -0
- data/lib/roby/coordination/models/action_script.rb +64 -0
- data/lib/roby/coordination/models/action_state_machine.rb +224 -0
- data/lib/roby/coordination/models/actions.rb +191 -0
- data/lib/roby/coordination/models/arguments.rb +55 -0
- data/lib/roby/coordination/models/base.rb +176 -0
- data/lib/roby/coordination/models/capture.rb +86 -0
- data/lib/roby/coordination/models/child.rb +35 -0
- data/lib/roby/coordination/models/event.rb +41 -0
- data/lib/roby/coordination/models/exceptions.rb +42 -0
- data/lib/roby/coordination/models/fault_handler.rb +219 -0
- data/lib/roby/coordination/models/fault_response_table.rb +77 -0
- data/lib/roby/coordination/models/root.rb +22 -0
- data/lib/roby/coordination/models/script.rb +283 -0
- data/lib/roby/coordination/models/task.rb +184 -0
- data/lib/roby/coordination/models/task_from_action.rb +50 -0
- data/lib/roby/coordination/models/task_from_as_plan.rb +33 -0
- data/lib/roby/coordination/models/task_from_instanciation_object.rb +31 -0
- data/lib/roby/coordination/models/task_from_variable.rb +27 -0
- data/lib/roby/coordination/models/task_with_dependencies.rb +48 -0
- data/lib/roby/coordination/models/variable.rb +32 -0
- data/lib/roby/coordination/script.rb +200 -0
- data/lib/roby/coordination/script_instruction.rb +12 -0
- data/lib/roby/coordination/task.rb +45 -0
- data/lib/roby/coordination/task_base.rb +69 -0
- data/lib/roby/coordination/task_script.rb +293 -0
- data/lib/roby/coordination/task_state_machine.rb +308 -0
- data/lib/roby/decision_control.rb +33 -21
- data/lib/roby/distributed_object.rb +76 -0
- data/lib/roby/droby.rb +17 -0
- data/lib/roby/droby/droby_id.rb +6 -0
- data/lib/roby/droby/enable.rb +153 -0
- data/lib/roby/droby/event_logger.rb +189 -0
- data/lib/roby/droby/event_logging.rb +57 -0
- data/lib/roby/droby/exceptions.rb +14 -0
- data/lib/roby/droby/identifiable.rb +22 -0
- data/lib/roby/droby/logfile.rb +141 -0
- data/lib/roby/droby/logfile/client.rb +176 -0
- data/lib/roby/droby/logfile/file_format.md +97 -0
- data/lib/roby/droby/logfile/index.rb +117 -0
- data/lib/roby/droby/logfile/reader.rb +139 -0
- data/lib/roby/droby/logfile/server.rb +199 -0
- data/lib/roby/droby/logfile/writer.rb +114 -0
- data/lib/roby/droby/marshal.rb +264 -0
- data/lib/roby/droby/marshallable.rb +12 -0
- data/lib/roby/droby/null_event_logger.rb +25 -0
- data/lib/roby/droby/object_manager.rb +205 -0
- data/lib/roby/droby/peer_id.rb +6 -0
- data/lib/roby/droby/plan_rebuilder.rb +373 -0
- data/lib/roby/droby/rebuilt_plan.rb +160 -0
- data/lib/roby/droby/remote_droby_id.rb +6 -0
- data/lib/roby/droby/timepoints.rb +205 -0
- data/lib/roby/droby/timepoints_ctf.metadata.erb +101 -0
- data/lib/roby/droby/timepoints_ctf.rb +125 -0
- data/lib/roby/droby/v5.rb +14 -0
- data/lib/roby/droby/v5/builtin.rb +120 -0
- data/lib/roby/droby/v5/droby_class.rb +45 -0
- data/lib/roby/droby/v5/droby_constant.rb +81 -0
- data/lib/roby/droby/v5/droby_dump.rb +1026 -0
- data/lib/roby/droby/v5/droby_id.rb +44 -0
- data/lib/roby/droby/v5/droby_model.rb +82 -0
- data/lib/roby/droby/v5/peer_id.rb +10 -0
- data/lib/roby/droby/v5/remote_droby_id.rb +42 -0
- data/lib/roby/event.rb +79 -957
- data/lib/roby/event_constraints.rb +835 -0
- data/lib/roby/event_generator.rb +1047 -0
- data/lib/roby/event_structure/causal_link.rb +6 -0
- data/lib/roby/event_structure/forwarding.rb +6 -0
- data/lib/roby/event_structure/precedence.rb +7 -0
- data/lib/roby/event_structure/signal.rb +8 -0
- data/lib/roby/event_structure/temporal_constraints.rb +640 -0
- data/lib/roby/exceptions.rb +446 -152
- data/lib/roby/executable_plan.rb +549 -0
- data/lib/roby/execution_engine.rb +1997 -950
- data/lib/roby/filter_generator.rb +26 -0
- data/lib/roby/gui/chronicle_view.rb +225 -0
- data/lib/roby/gui/chronicle_widget.rb +925 -0
- data/lib/roby/gui/dot_id.rb +11 -0
- data/lib/roby/gui/exception_view.rb +44 -0
- data/lib/roby/gui/log_display.rb +273 -0
- data/lib/roby/gui/model_views.rb +2 -0
- data/lib/roby/gui/model_views/action_interface.rb +53 -0
- data/lib/roby/gui/model_views/task.rb +47 -0
- data/lib/roby/gui/model_views/task.rhtml +41 -0
- data/lib/roby/gui/object_info_view.rb +89 -0
- data/lib/roby/gui/plan_dot_layout.rb +427 -0
- data/lib/roby/gui/plan_rebuilder_widget.rb +357 -0
- data/lib/roby/gui/qt4_toMSecsSinceEpoch.rb +8 -0
- data/lib/roby/gui/relations_view.rb +278 -0
- data/lib/roby/gui/relations_view/relations.ui +139 -0
- data/lib/roby/gui/relations_view/relations_canvas.rb +1088 -0
- data/lib/roby/gui/relations_view/relations_config.rb +292 -0
- data/lib/roby/gui/relations_view/relations_view.ui +53 -0
- data/lib/roby/gui/scheduler_view.css +24 -0
- data/lib/roby/gui/scheduler_view.rb +46 -0
- data/lib/roby/gui/scheduler_view.rhtml +53 -0
- data/lib/roby/gui/stepping.rb +93 -0
- data/lib/roby/gui/stepping.ui +181 -0
- data/lib/roby/gui/styles.rb +81 -0
- data/lib/roby/gui/task_display_configuration.rb +42 -0
- data/lib/roby/gui/task_state_at.rb +38 -0
- data/lib/roby/hooks.rb +26 -0
- data/lib/roby/interface.rb +136 -469
- data/lib/roby/interface/async.rb +20 -0
- data/lib/roby/interface/async/action_monitor.rb +188 -0
- data/lib/roby/interface/async/interface.rb +498 -0
- data/lib/roby/interface/async/job_monitor.rb +213 -0
- data/lib/roby/interface/async/log.rb +238 -0
- data/lib/roby/interface/async/new_job_listener.rb +79 -0
- data/lib/roby/interface/async/ui_connector.rb +183 -0
- data/lib/roby/interface/client.rb +553 -0
- data/lib/roby/interface/command.rb +24 -0
- data/lib/roby/interface/command_argument.rb +16 -0
- data/lib/roby/interface/command_library.rb +92 -0
- data/lib/roby/interface/droby_channel.rb +174 -0
- data/lib/roby/interface/exceptions.rb +22 -0
- data/lib/roby/interface/interface.rb +655 -0
- data/lib/roby/interface/job.rb +47 -0
- data/lib/roby/interface/rest.rb +10 -0
- data/lib/roby/interface/rest/api.rb +29 -0
- data/lib/roby/interface/rest/helpers.rb +24 -0
- data/lib/roby/interface/rest/server.rb +212 -0
- data/lib/roby/interface/server.rb +154 -0
- data/lib/roby/interface/shell_client.rb +468 -0
- data/lib/roby/interface/shell_subcommand.rb +24 -0
- data/lib/roby/interface/subcommand_client.rb +35 -0
- data/lib/roby/interface/tcp.rb +168 -0
- data/lib/roby/models/arguments.rb +112 -0
- data/lib/roby/models/plan_object.rb +83 -0
- data/lib/roby/models/task.rb +835 -0
- data/lib/roby/models/task_event.rb +62 -0
- data/lib/roby/models/task_service.rb +78 -0
- data/lib/roby/or_generator.rb +88 -0
- data/lib/roby/plan.rb +1751 -864
- data/lib/roby/plan_object.rb +611 -0
- data/lib/roby/plan_service.rb +200 -0
- data/lib/roby/promise.rb +332 -0
- data/lib/roby/queries.rb +23 -0
- data/lib/roby/queries/and_matcher.rb +32 -0
- data/lib/roby/queries/any.rb +27 -0
- data/lib/roby/queries/code_error_matcher.rb +58 -0
- data/lib/roby/queries/event_generator_matcher.rb +9 -0
- data/lib/roby/queries/execution_exception_matcher.rb +165 -0
- data/lib/roby/queries/index.rb +165 -0
- data/lib/roby/queries/localized_error_matcher.rb +149 -0
- data/lib/roby/queries/matcher_base.rb +107 -0
- data/lib/roby/queries/none.rb +27 -0
- data/lib/roby/queries/not_matcher.rb +30 -0
- data/lib/roby/queries/op_matcher.rb +8 -0
- data/lib/roby/queries/or_matcher.rb +30 -0
- data/lib/roby/queries/plan_object_matcher.rb +363 -0
- data/lib/roby/queries/query.rb +188 -0
- data/lib/roby/queries/task_event_generator_matcher.rb +86 -0
- data/lib/roby/queries/task_matcher.rb +344 -0
- data/lib/roby/relations.rb +42 -678
- data/lib/roby/relations/bidirectional_directed_adjacency_graph.rb +492 -0
- data/lib/roby/relations/directed_relation_support.rb +268 -0
- data/lib/roby/relations/event_relation_graph.rb +19 -0
- data/lib/roby/relations/fork_merge_visitor.rb +154 -0
- data/lib/roby/relations/graph.rb +533 -0
- data/lib/roby/relations/models/directed_relation_support.rb +11 -0
- data/lib/roby/relations/models/graph.rb +75 -0
- data/lib/roby/relations/models/task_relation_graph.rb +18 -0
- data/lib/roby/relations/space.rb +380 -0
- data/lib/roby/relations/task_relation_graph.rb +20 -0
- data/lib/roby/robot.rb +85 -38
- data/lib/roby/schedulers/basic.rb +155 -25
- data/lib/roby/schedulers/null.rb +20 -0
- data/lib/roby/schedulers/reporting.rb +31 -0
- data/lib/roby/schedulers/state.rb +129 -0
- data/lib/roby/schedulers/temporal.rb +91 -0
- data/lib/roby/singletons.rb +87 -0
- data/lib/roby/standalone.rb +4 -2
- data/lib/roby/standard_errors.rb +405 -82
- data/lib/roby/state.rb +6 -3
- data/lib/roby/state/conf_model.rb +5 -0
- data/lib/roby/state/events.rb +181 -95
- data/lib/roby/state/goal_model.rb +77 -0
- data/lib/roby/state/open_struct.rb +591 -0
- data/lib/roby/state/open_struct_model.rb +68 -0
- data/lib/roby/state/pos.rb +45 -45
- data/lib/roby/state/shapes.rb +11 -11
- data/lib/roby/state/state_model.rb +303 -0
- data/lib/roby/state/task.rb +43 -0
- data/lib/roby/support.rb +88 -148
- data/lib/roby/task.rb +1361 -1750
- data/lib/roby/task_arguments.rb +428 -0
- data/lib/roby/task_event.rb +127 -0
- data/lib/roby/task_event_generator.rb +337 -0
- data/lib/roby/task_service.rb +6 -0
- data/lib/roby/task_structure/conflicts.rb +104 -0
- data/lib/roby/task_structure/dependency.rb +932 -0
- data/lib/roby/task_structure/error_handling.rb +118 -0
- data/lib/roby/task_structure/executed_by.rb +234 -0
- data/lib/roby/task_structure/planned_by.rb +90 -0
- data/lib/roby/tasks/aggregator.rb +37 -0
- data/lib/roby/tasks/external_process.rb +275 -0
- data/lib/roby/tasks/group.rb +27 -0
- data/lib/roby/tasks/null.rb +19 -0
- data/lib/roby/tasks/parallel.rb +43 -0
- data/lib/roby/tasks/sequence.rb +88 -0
- data/lib/roby/tasks/simple.rb +21 -0
- data/lib/roby/{thread_task.rb → tasks/thread.rb} +50 -24
- data/lib/roby/tasks/timeout.rb +17 -0
- data/lib/roby/tasks/virtual.rb +55 -0
- data/lib/roby/template_plan.rb +7 -0
- data/lib/roby/test/aruba_minitest.rb +74 -0
- data/lib/roby/test/assertion.rb +16 -0
- data/lib/roby/test/assertions.rb +490 -0
- data/lib/roby/test/common.rb +368 -591
- data/lib/roby/test/dsl.rb +149 -0
- data/lib/roby/test/error.rb +18 -0
- data/lib/roby/test/event_reporter.rb +83 -0
- data/lib/roby/test/execution_expectations.rb +1134 -0
- data/lib/roby/test/expect_execution.rb +151 -0
- data/lib/roby/test/minitest_helpers.rb +166 -0
- data/lib/roby/test/roby_app_helpers.rb +200 -0
- data/lib/roby/test/run_planners.rb +155 -0
- data/lib/roby/test/self.rb +112 -0
- data/lib/roby/test/spec.rb +198 -0
- data/lib/roby/test/tasks/empty_task.rb +4 -4
- data/lib/roby/test/tasks/goto.rb +28 -27
- data/lib/roby/test/teardown_plans.rb +100 -0
- data/lib/roby/test/testcase.rb +239 -307
- data/lib/roby/test/tools.rb +159 -155
- data/lib/roby/test/validate_state_machine.rb +75 -0
- data/lib/roby/transaction.rb +1125 -0
- data/lib/roby/transaction/event_generator_proxy.rb +63 -0
- data/lib/roby/transaction/plan_object_proxy.rb +99 -0
- data/lib/roby/transaction/plan_service_proxy.rb +43 -0
- data/lib/roby/transaction/proxying.rb +120 -0
- data/lib/roby/transaction/task_event_generator_proxy.rb +19 -0
- data/lib/roby/transaction/task_proxy.rb +135 -0
- data/lib/roby/until_generator.rb +30 -0
- data/lib/roby/version.rb +5 -0
- data/lib/roby/yard.rb +169 -0
- data/lib/yard-roby.rb +1 -0
- data/manifest.xml +32 -6
- data/roby.gemspec +59 -0
- metadata +788 -587
- data/Manifest.txt +0 -321
- data/NOTES +0 -4
- data/README.txt +0 -166
- data/TODO.txt +0 -146
- data/app/README.txt +0 -24
- data/app/Rakefile +0 -8
- data/app/config/ROBOT.rb +0 -5
- data/app/config/init.rb +0 -33
- data/app/config/roby.yml +0 -3
- data/app/controllers/ROBOT.rb +0 -2
- data/app/planners/ROBOT/main.rb +0 -6
- data/app/planners/main.rb +0 -5
- data/app/scripts/distributed +0 -3
- data/app/scripts/generate/bookmarks +0 -3
- data/app/scripts/replay +0 -3
- data/app/scripts/results +0 -3
- data/app/scripts/run +0 -3
- data/app/scripts/server +0 -3
- data/app/scripts/shell +0 -3
- data/app/scripts/test +0 -3
- data/app/tasks/.gitattributes +0 -0
- data/app/tasks/ROBOT/.gitattributes +0 -0
- data/bin/roby-shell +0 -25
- data/doc/guide/src/basics/app.page +0 -139
- data/doc/guide/src/basics/index.page +0 -11
- data/doc/guide/src/basics/log_replay/goForward_1.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_2.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_3.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_5.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_4.png +0 -0
- data/doc/guide/src/basics/log_replay/roby_log_main_window.png +0 -0
- data/doc/guide/src/basics/relations_display.page +0 -203
- data/doc/guide/src/basics/shell.page +0 -102
- data/doc/guide/src/default.css +0 -319
- data/doc/guide/src/introduction/index.page +0 -29
- data/doc/guide/src/introduction/publications.page +0 -14
- data/doc/guide/src/relations/dependency.page +0 -89
- data/doc/guide/src/relations/index.page +0 -12
- data/ext/droby/dump.cc +0 -175
- data/ext/droby/extconf.rb +0 -3
- data/ext/graph/algorithm.cc +0 -746
- data/ext/graph/extconf.rb +0 -7
- data/ext/graph/graph.cc +0 -575
- data/ext/graph/graph.hh +0 -183
- data/ext/graph/iterator_sequence.hh +0 -102
- data/ext/graph/undirected_dfs.hh +0 -226
- data/ext/graph/undirected_graph.hh +0 -421
- data/lib/roby/app/scripts/generate/bookmarks.rb +0 -162
- data/lib/roby/app/scripts/replay.rb +0 -31
- data/lib/roby/app/scripts/server.rb +0 -18
- data/lib/roby/basic_object.rb +0 -151
- data/lib/roby/config.rb +0 -14
- data/lib/roby/distributed.rb +0 -36
- data/lib/roby/distributed/base.rb +0 -448
- data/lib/roby/distributed/communication.rb +0 -875
- data/lib/roby/distributed/connection_space.rb +0 -616
- data/lib/roby/distributed/distributed_object.rb +0 -206
- data/lib/roby/distributed/drb.rb +0 -62
- data/lib/roby/distributed/notifications.rb +0 -531
- data/lib/roby/distributed/peer.rb +0 -555
- data/lib/roby/distributed/protocol.rb +0 -529
- data/lib/roby/distributed/proxy.rb +0 -343
- data/lib/roby/distributed/subscription.rb +0 -311
- data/lib/roby/distributed/transaction.rb +0 -498
- data/lib/roby/external_process_task.rb +0 -225
- data/lib/roby/graph.rb +0 -160
- data/lib/roby/log.rb +0 -3
- data/lib/roby/log/chronicle.rb +0 -303
- data/lib/roby/log/console.rb +0 -74
- data/lib/roby/log/data_stream.rb +0 -275
- data/lib/roby/log/dot.rb +0 -279
- data/lib/roby/log/event_stream.rb +0 -161
- data/lib/roby/log/file.rb +0 -396
- data/lib/roby/log/gui/basic_display.ui +0 -83
- data/lib/roby/log/gui/basic_display_ui.rb +0 -89
- data/lib/roby/log/gui/chronicle.rb +0 -26
- data/lib/roby/log/gui/chronicle_view.rb +0 -40
- data/lib/roby/log/gui/chronicle_view.ui +0 -70
- data/lib/roby/log/gui/chronicle_view_ui.rb +0 -90
- data/lib/roby/log/gui/data_displays.rb +0 -171
- data/lib/roby/log/gui/data_displays.ui +0 -155
- data/lib/roby/log/gui/data_displays_ui.rb +0 -146
- data/lib/roby/log/gui/notifications.rb +0 -26
- data/lib/roby/log/gui/relations.rb +0 -269
- data/lib/roby/log/gui/relations.ui +0 -123
- data/lib/roby/log/gui/relations_ui.rb +0 -120
- data/lib/roby/log/gui/relations_view.rb +0 -185
- data/lib/roby/log/gui/relations_view.ui +0 -149
- data/lib/roby/log/gui/relations_view_ui.rb +0 -144
- data/lib/roby/log/gui/replay.rb +0 -366
- data/lib/roby/log/gui/replay_controls.rb +0 -206
- data/lib/roby/log/gui/replay_controls.ui +0 -282
- data/lib/roby/log/gui/replay_controls_ui.rb +0 -249
- data/lib/roby/log/gui/runtime.rb +0 -130
- data/lib/roby/log/hooks.rb +0 -186
- data/lib/roby/log/logger.rb +0 -203
- data/lib/roby/log/notifications.rb +0 -244
- data/lib/roby/log/plan_rebuilder.rb +0 -468
- data/lib/roby/log/relations.rb +0 -1084
- data/lib/roby/log/server.rb +0 -547
- data/lib/roby/log/sqlite.rb +0 -47
- data/lib/roby/log/timings.rb +0 -233
- data/lib/roby/plan-object.rb +0 -371
- data/lib/roby/planning.rb +0 -13
- data/lib/roby/planning/loops.rb +0 -309
- data/lib/roby/planning/model.rb +0 -1012
- data/lib/roby/planning/task.rb +0 -180
- data/lib/roby/query.rb +0 -655
- data/lib/roby/relations/conflicts.rb +0 -67
- data/lib/roby/relations/dependency.rb +0 -358
- data/lib/roby/relations/ensured.rb +0 -19
- data/lib/roby/relations/error_handling.rb +0 -22
- data/lib/roby/relations/events.rb +0 -7
- data/lib/roby/relations/executed_by.rb +0 -208
- data/lib/roby/relations/influence.rb +0 -10
- data/lib/roby/relations/planned_by.rb +0 -63
- data/lib/roby/state/information.rb +0 -55
- data/lib/roby/state/state.rb +0 -367
- data/lib/roby/task-operations.rb +0 -186
- data/lib/roby/task_index.rb +0 -80
- data/lib/roby/test/distributed.rb +0 -230
- data/lib/roby/test/tasks/simple_task.rb +0 -23
- data/lib/roby/transactions.rb +0 -507
- data/lib/roby/transactions/proxy.rb +0 -325
- data/plugins/fault_injection/History.txt +0 -4
- data/plugins/fault_injection/README.txt +0 -34
- data/plugins/fault_injection/Rakefile +0 -12
- data/plugins/fault_injection/TODO.txt +0 -0
- data/plugins/fault_injection/app.rb +0 -52
- data/plugins/fault_injection/fault_injection.rb +0 -89
- data/plugins/fault_injection/test/test_fault_injection.rb +0 -78
- data/plugins/subsystems/README.txt +0 -37
- data/plugins/subsystems/Rakefile +0 -13
- data/plugins/subsystems/app.rb +0 -182
- data/plugins/subsystems/test/app/README +0 -24
- data/plugins/subsystems/test/app/Rakefile +0 -8
- data/plugins/subsystems/test/app/config/app.yml +0 -71
- data/plugins/subsystems/test/app/config/init.rb +0 -12
- data/plugins/subsystems/test/app/config/roby.yml +0 -3
- data/plugins/subsystems/test/app/planners/main.rb +0 -20
- data/plugins/subsystems/test/app/scripts/distributed +0 -3
- data/plugins/subsystems/test/app/scripts/replay +0 -3
- data/plugins/subsystems/test/app/scripts/results +0 -3
- data/plugins/subsystems/test/app/scripts/run +0 -3
- data/plugins/subsystems/test/app/scripts/server +0 -3
- data/plugins/subsystems/test/app/scripts/shell +0 -3
- data/plugins/subsystems/test/app/scripts/test +0 -3
- data/plugins/subsystems/test/app/tasks/services.rb +0 -15
- data/plugins/subsystems/test/test_subsystems.rb +0 -78
- data/test/distributed/test_communication.rb +0 -195
- data/test/distributed/test_connection.rb +0 -284
- data/test/distributed/test_execution.rb +0 -378
- data/test/distributed/test_mixed_plan.rb +0 -341
- data/test/distributed/test_plan_notifications.rb +0 -238
- data/test/distributed/test_protocol.rb +0 -525
- data/test/distributed/test_query.rb +0 -106
- data/test/distributed/test_remote_plan.rb +0 -491
- data/test/distributed/test_transaction.rb +0 -466
- data/test/mockups/external_process +0 -28
- data/test/mockups/tasks.rb +0 -27
- data/test/planning/test_loops.rb +0 -432
- data/test/planning/test_model.rb +0 -427
- data/test/planning/test_task.rb +0 -126
- data/test/relations/test_conflicts.rb +0 -42
- data/test/relations/test_dependency.rb +0 -324
- data/test/relations/test_ensured.rb +0 -38
- data/test/relations/test_executed_by.rb +0 -224
- data/test/relations/test_planned_by.rb +0 -56
- data/test/suite_core.rb +0 -29
- data/test/suite_distributed.rb +0 -10
- data/test/suite_planning.rb +0 -4
- data/test/suite_relations.rb +0 -8
- data/test/tasks/test_external_process.rb +0 -126
- data/test/tasks/test_thread_task.rb +0 -70
- data/test/test_bgl.rb +0 -528
- data/test/test_event.rb +0 -969
- data/test/test_exceptions.rb +0 -591
- data/test/test_execution_engine.rb +0 -987
- data/test/test_gui.rb +0 -20
- data/test/test_interface.rb +0 -43
- data/test/test_log.rb +0 -125
- data/test/test_log_server.rb +0 -133
- data/test/test_plan.rb +0 -418
- data/test/test_query.rb +0 -424
- data/test/test_relations.rb +0 -260
- data/test/test_state.rb +0 -432
- data/test/test_support.rb +0 -16
- data/test/test_task.rb +0 -1181
- data/test/test_testcase.rb +0 -138
- data/test/test_transactions.rb +0 -610
- data/test/test_transactions_proxy.rb +0 -216
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
module Roby
|
|
2
|
+
module Interface
|
|
3
|
+
module Async
|
|
4
|
+
# Listener object for {Interface#on_job}
|
|
5
|
+
class NewJobListener
|
|
6
|
+
# @return [Interface] the interface we are connected to
|
|
7
|
+
attr_reader :interface
|
|
8
|
+
# @return [String,nil] the name of the action whose job we are
|
|
9
|
+
# tracking. If nil, tracks all actions.
|
|
10
|
+
attr_reader :action_name
|
|
11
|
+
# @return [#call] the notification callback
|
|
12
|
+
attr_reader :block
|
|
13
|
+
|
|
14
|
+
# The last ID of the jobs received by this listener.
|
|
15
|
+
#
|
|
16
|
+
# This is used to avoid double-notifications of new jobs. The
|
|
17
|
+
# assumption is that the job IDs are ever-increasing and that
|
|
18
|
+
# they are fed in-order to {#call}.
|
|
19
|
+
attr_reader :last_job_id
|
|
20
|
+
|
|
21
|
+
def initialize(interface, action_name, block)
|
|
22
|
+
@interface = interface
|
|
23
|
+
@action_name = action_name
|
|
24
|
+
@block = block
|
|
25
|
+
@last_job_id = -1
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Resets the listener so that it can be used on a new connection
|
|
29
|
+
#
|
|
30
|
+
# This currently only resets {#last_job_id}
|
|
31
|
+
def reset
|
|
32
|
+
@last_job_id = -1
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Tests whether this listener has already seen the job with the
|
|
36
|
+
# given ID
|
|
37
|
+
#
|
|
38
|
+
# @param [Integer] job_id
|
|
39
|
+
# @see last_job_id
|
|
40
|
+
def seen_job_with_id?(job_id)
|
|
41
|
+
last_job_id >= job_id
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Tests whether the provided job matches what this listener
|
|
45
|
+
# wants
|
|
46
|
+
def matches?(job)
|
|
47
|
+
!action_name || (job.action_name == action_name)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Call the listener for the given job
|
|
51
|
+
#
|
|
52
|
+
# @param [JobMonitor] job
|
|
53
|
+
def call(job)
|
|
54
|
+
@last_job_id = job.job_id
|
|
55
|
+
block.call(job)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Tell this listener that the given job was received, but
|
|
59
|
+
# ignored.
|
|
60
|
+
#
|
|
61
|
+
# This is an optimization to avoid re-considering this listener
|
|
62
|
+
# for the given job
|
|
63
|
+
def ignored(job)
|
|
64
|
+
@last_job_id = job.job_id
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Start listening for jobs
|
|
68
|
+
def start
|
|
69
|
+
interface.add_new_job_listener(self)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Stop listening for jobs
|
|
73
|
+
def stop
|
|
74
|
+
interface.remove_new_job_listener(self)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
module Roby
|
|
2
|
+
module Interface
|
|
3
|
+
module Async
|
|
4
|
+
# Creates a connection between a Syskit job and a Qt-based GUI
|
|
5
|
+
#
|
|
6
|
+
# A job is a placeholder for an action with some arguments set. It
|
|
7
|
+
# is created by {Interface#connect_to_ui}. More than one job can exist
|
|
8
|
+
# based on a given action (as long as they differ by their
|
|
9
|
+
# arguments), but a given job can be started by the GUI only once.
|
|
10
|
+
#
|
|
11
|
+
# @example represent an action with some argument(s) set
|
|
12
|
+
# action = <name_of_action>!(x: 10)
|
|
13
|
+
#
|
|
14
|
+
# @example start a job from an action when a button is pressed
|
|
15
|
+
# connect widget, SIGNAL('clicked()'), START(action)
|
|
16
|
+
#
|
|
17
|
+
# @example allow a job to be restarted (otherwise an existing job must be manually killed first)
|
|
18
|
+
# connect widget, SIGNAL('clicked()'), START(action), restart: true
|
|
19
|
+
#
|
|
20
|
+
# @example kill the job when a button is pressed
|
|
21
|
+
# connect widget, SIGNAL('clicked()'), KILL(action)
|
|
22
|
+
#
|
|
23
|
+
# @example call a block with a job monitoring object when its state changes
|
|
24
|
+
# connect PROGRESS(job) do |action|
|
|
25
|
+
# # 'action' is an ActionMonitor
|
|
26
|
+
# end
|
|
27
|
+
#
|
|
28
|
+
# @example set an action's argument from a signal (by default, requires the user to press the 'start' button afterwards)
|
|
29
|
+
# connect widget, SIGNAL('textChanged(QString)'), ARGUMENT(action,:z),
|
|
30
|
+
# getter: ->(z) { Integer(z) }
|
|
31
|
+
#
|
|
32
|
+
# @example set an action's argument from a signal, and restart the action right away
|
|
33
|
+
# connect widget, SIGNAL('textChanged(QString)'), ARGUMENT(action,:z),
|
|
34
|
+
# getter: ->(z) { Integer(z) },
|
|
35
|
+
# auto_apply: true
|
|
36
|
+
class UIConnector
|
|
37
|
+
ActionConnector = Struct.new :connector, :action, :options do
|
|
38
|
+
def interface
|
|
39
|
+
connector.interface
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class StartCommand < ActionConnector
|
|
44
|
+
def run
|
|
45
|
+
if !options[:restart] && action.exists? && !action.terminated?
|
|
46
|
+
return
|
|
47
|
+
end
|
|
48
|
+
action.restart
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class DropCommand < ActionConnector
|
|
53
|
+
def run
|
|
54
|
+
if action.exists? && !action.terminated?
|
|
55
|
+
action.drop
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class KillCommand < ActionConnector
|
|
61
|
+
def run
|
|
62
|
+
if action.exists? && !action.terminated?
|
|
63
|
+
action.kill
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class SetArgumentCommand < ActionConnector
|
|
69
|
+
attr_reader :argument_name
|
|
70
|
+
def initialize(connector, action, argument_name, getter: nil)
|
|
71
|
+
super(connector, action, getter: nil)
|
|
72
|
+
@argument_name = argument_name.to_sym
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def run(arg)
|
|
76
|
+
if getter = options[:getter]
|
|
77
|
+
arg = getter.call(arg)
|
|
78
|
+
if !arg
|
|
79
|
+
Interface.warn "not setting argument #{action}.#{argument_name}: getter returned nil"
|
|
80
|
+
return
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
action.arguments[argument_name] = arg
|
|
84
|
+
if options[:auto_apply]
|
|
85
|
+
StartAction.new(connector, action, restart: true).run
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
class ProgressMonitorCommand < ActionConnector
|
|
91
|
+
attr_accessor :callback
|
|
92
|
+
|
|
93
|
+
def connect
|
|
94
|
+
action.on_progress do
|
|
95
|
+
update
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def update
|
|
100
|
+
callback.call(action)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
attr_reader :interface
|
|
105
|
+
attr_reader :widget
|
|
106
|
+
|
|
107
|
+
def initialize(interface, widget)
|
|
108
|
+
@interface = interface
|
|
109
|
+
@widget = widget
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def on_reachable(&block)
|
|
113
|
+
interface.on_reachable(&block)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def on_unreachable(&block)
|
|
117
|
+
interface.on_unreachable(&block)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def connect(*args, &block)
|
|
121
|
+
if args.first.kind_of?(Qt::Widget)
|
|
122
|
+
# Signature from a widget's signal to Syskit
|
|
123
|
+
widget = args.shift
|
|
124
|
+
signal = args.shift
|
|
125
|
+
action = args.shift
|
|
126
|
+
action.options = args.shift || Hash.new
|
|
127
|
+
if widget.respond_to?(:to_widget)
|
|
128
|
+
widget = widget.to_widget
|
|
129
|
+
end
|
|
130
|
+
widget.connect(signal) do |*args|
|
|
131
|
+
action.run(*args)
|
|
132
|
+
end
|
|
133
|
+
else
|
|
134
|
+
# Signature from syskit to a block
|
|
135
|
+
action = args.shift
|
|
136
|
+
action.options = args.shift
|
|
137
|
+
action.callback = block
|
|
138
|
+
action.connect
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def START(action)
|
|
143
|
+
StartCommand.new(self, action)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def DROP(action)
|
|
147
|
+
DropCommand.new(self, action)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def KILL(action)
|
|
151
|
+
KillCommand.new(self, action)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def PROGRESS(action)
|
|
155
|
+
ProgressMonitorCommand.new(self, action)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def ARGUMENT(action, argument_name)
|
|
159
|
+
SetArgumentCommand.new(self, action, argument_name)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def respond_to_missing?(m, include_private = false)
|
|
163
|
+
(m =~ /!$/) || widget.respond_to?(m)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def method_missing(m, *args, &block)
|
|
167
|
+
if m =~ /!$/
|
|
168
|
+
ActionMonitor.new(interface, m.to_s[0..-2], *args)
|
|
169
|
+
elsif widget.respond_to?(m)
|
|
170
|
+
widget.public_send(m, *args, &block)
|
|
171
|
+
else
|
|
172
|
+
super
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def to_widget
|
|
177
|
+
widget
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
module Roby
|
|
2
|
+
module Interface
|
|
3
|
+
# The client-side object that allows to access an interface (e.g. a Roby
|
|
4
|
+
# app) from another process than the Roby controller
|
|
5
|
+
class Client
|
|
6
|
+
# @return [DRobyChannel] the IO to the server
|
|
7
|
+
attr_reader :io
|
|
8
|
+
# @return [Array<Roby::Actions::Model::Action>] set of known actions
|
|
9
|
+
attr_reader :actions
|
|
10
|
+
# @return [Hash] the set of available commands
|
|
11
|
+
attr_reader :commands
|
|
12
|
+
# @return [Array<Integer,Array>] list of existing job progress
|
|
13
|
+
# information. The integer is an ID that can be used to refer to the
|
|
14
|
+
# job progress information. It is always growing and will never
|
|
15
|
+
# collide with a job progress and exception ID
|
|
16
|
+
attr_reader :job_progress_queue
|
|
17
|
+
# @return [Array<Integer,Array>] list of existing notifications. The
|
|
18
|
+
# integer is an ID that can be used to refer to the notification.
|
|
19
|
+
# It is always growing and will never collide with an exception ID
|
|
20
|
+
attr_reader :notification_queue
|
|
21
|
+
# @return [Array<Integer,Array>] list of existing exceptions. The
|
|
22
|
+
# integer is an ID that can be used to refer to the exception.
|
|
23
|
+
# It is always growing and will never collide with a notification ID
|
|
24
|
+
attr_reader :exception_queue
|
|
25
|
+
# @return [Array<Integer,Array>] list of queued UI events. The
|
|
26
|
+
# integer is an ID that can be used to refer to the exception.
|
|
27
|
+
# It is always growing and will never collide with a notification ID
|
|
28
|
+
attr_reader :ui_event_queue
|
|
29
|
+
|
|
30
|
+
# @return [Integer] index of the last processed cycle
|
|
31
|
+
attr_reader :cycle_index
|
|
32
|
+
# @return [Time] time of the last processed cycle
|
|
33
|
+
attr_reader :cycle_start_time
|
|
34
|
+
# @return [Array<Hash>] list of the pending async calls
|
|
35
|
+
attr_reader :pending_async_calls
|
|
36
|
+
|
|
37
|
+
# Create a client endpoint to a Roby interface [Server]
|
|
38
|
+
#
|
|
39
|
+
# @param [DRobyChannel] io a channel to the server
|
|
40
|
+
# @param [String] id a unique identifier for this client
|
|
41
|
+
# (e.g. host:port of the local endpoint when using TCP). It is
|
|
42
|
+
# passed to the server through {Server#handshake}
|
|
43
|
+
#
|
|
44
|
+
# @see Interface.connect_with_tcp_to
|
|
45
|
+
def initialize(io, id)
|
|
46
|
+
@pending_async_calls = Array.new
|
|
47
|
+
@io = io
|
|
48
|
+
@message_id = 0
|
|
49
|
+
@notification_queue = Array.new
|
|
50
|
+
@job_progress_queue = Array.new
|
|
51
|
+
@exception_queue = Array.new
|
|
52
|
+
@ui_event_queue = Array.new
|
|
53
|
+
|
|
54
|
+
@actions, @commands = call([], :handshake, id)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Whether the communication channel to the server is closed
|
|
58
|
+
def closed?
|
|
59
|
+
io.closed?
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Close the communication channel
|
|
63
|
+
def close
|
|
64
|
+
io.close
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# The underlying IO object
|
|
68
|
+
def to_io
|
|
69
|
+
io.to_io
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Tests whether the interface has an action with that name
|
|
73
|
+
def has_action?(name)
|
|
74
|
+
!!find_action_by_name(name)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Find an action by its name
|
|
78
|
+
#
|
|
79
|
+
# This is a local operation using the information gathered at
|
|
80
|
+
# connection time
|
|
81
|
+
#
|
|
82
|
+
# @param [String] name the name of the action to look for
|
|
83
|
+
# @return [Actions::Models::Action,nil]
|
|
84
|
+
def find_action_by_name(name)
|
|
85
|
+
actions.find { |act| act.name == name }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Finds all actions whose name matches a pattern
|
|
89
|
+
#
|
|
90
|
+
# @param [#===] matcher the matching object (usually a Regexp or
|
|
91
|
+
# String)
|
|
92
|
+
# @return [Array<Actions::Models::Action>]
|
|
93
|
+
def find_all_actions_matching(matcher)
|
|
94
|
+
actions.find_all { |act| matcher === act.name }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @api private
|
|
98
|
+
#
|
|
99
|
+
# Process a message as received on {#io}
|
|
100
|
+
#
|
|
101
|
+
# @return [Boolean] whether the message was a cycle_end message
|
|
102
|
+
def process_packet(m, *args)
|
|
103
|
+
if m == :cycle_end
|
|
104
|
+
@cycle_index, @cycle_start_time = *args
|
|
105
|
+
return true
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
if m == :bad_call
|
|
109
|
+
if !pending_async_calls.empty?
|
|
110
|
+
process_pending_async_call(args.first, nil)
|
|
111
|
+
else
|
|
112
|
+
e = args.first
|
|
113
|
+
raise e, e.message, (e.backtrace + caller)
|
|
114
|
+
end
|
|
115
|
+
elsif m == :reply
|
|
116
|
+
if !pending_async_calls.empty?
|
|
117
|
+
process_pending_async_call(nil, args.first)
|
|
118
|
+
else
|
|
119
|
+
yield args.first
|
|
120
|
+
end
|
|
121
|
+
elsif m == :job_progress
|
|
122
|
+
queue_job_progress(*args)
|
|
123
|
+
elsif m == :notification
|
|
124
|
+
queue_notification(*args)
|
|
125
|
+
elsif m == :ui_event
|
|
126
|
+
queue_ui_event(*args)
|
|
127
|
+
elsif m == :exception
|
|
128
|
+
queue_exception(*args)
|
|
129
|
+
else
|
|
130
|
+
raise ProtocolError, "unexpected reply from #{io}: #{m} (#{args.map(&:to_s).join(",")})"
|
|
131
|
+
end
|
|
132
|
+
false
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Wait until there is data to process on the IO channel
|
|
136
|
+
#
|
|
137
|
+
# @param [Numeric,nil] timeout a timeout after which the method
|
|
138
|
+
# will return. Use nil for no timeout
|
|
139
|
+
# @return [Boolean] falsy if the timeout was reached, true
|
|
140
|
+
# otherwise
|
|
141
|
+
def wait(timeout: nil)
|
|
142
|
+
io.read_wait(timeout: timeout)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# @api private
|
|
146
|
+
#
|
|
147
|
+
# Remove and call the block of a pending async call
|
|
148
|
+
def process_pending_async_call(error, result)
|
|
149
|
+
current_call = pending_async_calls.shift
|
|
150
|
+
current_call[:block].call(error, result)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Polls for new data on the IO channel
|
|
154
|
+
#
|
|
155
|
+
# @return [Object] a call reply
|
|
156
|
+
# @raise [ComError] if the link seem to be broken
|
|
157
|
+
# @raise [ProtocolError] if some errors happened when validating the
|
|
158
|
+
# protocol
|
|
159
|
+
def poll(expected_count = 0)
|
|
160
|
+
result = nil
|
|
161
|
+
timeout = if expected_count > 0 then nil
|
|
162
|
+
else 0
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
has_cycle_end = false
|
|
166
|
+
while packet = io.read_packet(timeout)
|
|
167
|
+
has_cycle_end = process_packet(*packet) do |reply_value|
|
|
168
|
+
if result
|
|
169
|
+
raise ProtocolError, "got more than one sync reply in a single poll call"
|
|
170
|
+
end
|
|
171
|
+
result = reply_value
|
|
172
|
+
expected_count -= 1
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
if expected_count <= 0
|
|
176
|
+
break if has_cycle_end
|
|
177
|
+
timeout = 0
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
return result, has_cycle_end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# @api private
|
|
184
|
+
#
|
|
185
|
+
# Allocation of unique IDs for notification messages
|
|
186
|
+
def allocate_message_id
|
|
187
|
+
@message_id += 1
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# @api private
|
|
191
|
+
#
|
|
192
|
+
# Push a job notification to {#job_progress_queue}
|
|
193
|
+
#
|
|
194
|
+
# See the yield parameters of {Interface#on_job_notification} for
|
|
195
|
+
# the overall argument format.
|
|
196
|
+
def queue_job_progress(kind, job_id, job_name, *args)
|
|
197
|
+
job_progress_queue.push [allocate_message_id, [kind, job_id, job_name, *args]]
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Whether some job progress information is currently queued
|
|
201
|
+
def has_job_progress?
|
|
202
|
+
!job_progress_queue.empty?
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Remove and return the oldest job information message
|
|
206
|
+
#
|
|
207
|
+
# @return [(Integer,Array)] a unique and monotonically-increasing
|
|
208
|
+
# message ID and the arguments to job progress as specified on
|
|
209
|
+
# {Interface#on_job_notification}.
|
|
210
|
+
def pop_job_progress
|
|
211
|
+
job_progress_queue.shift
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# @api private
|
|
215
|
+
#
|
|
216
|
+
# Push a generic notification to {#notification_queue}
|
|
217
|
+
def queue_notification(source, level, message)
|
|
218
|
+
notification_queue.push [allocate_message_id, [source, level, message]]
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Whether some generic notifications have been queued
|
|
222
|
+
def has_notifications?
|
|
223
|
+
!notification_queue.empty?
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Remove and return the oldest generic notification message
|
|
227
|
+
#
|
|
228
|
+
# @return [(Integer,Array)] a unique and monotonically-increasing
|
|
229
|
+
# message ID and the generic notification information as specified
|
|
230
|
+
# by (Application#notify)
|
|
231
|
+
def pop_notification
|
|
232
|
+
notification_queue.shift
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# @api private
|
|
236
|
+
#
|
|
237
|
+
# Push a UI event to {#ui_event_queue}
|
|
238
|
+
def queue_ui_event(event_name, *args)
|
|
239
|
+
ui_event_queue.push [allocate_message_id, [event_name, *args]]
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Whether some UI events have been queued
|
|
243
|
+
def has_ui_event?
|
|
244
|
+
!ui_event_queue.empty?
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Remove the oldest UI event and return it
|
|
248
|
+
def pop_ui_event
|
|
249
|
+
ui_event_queue.shift
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# @api private
|
|
253
|
+
#
|
|
254
|
+
# Push an exception notification to {#exception_queue}
|
|
255
|
+
#
|
|
256
|
+
# It can be retrieved with {#pop_exception}
|
|
257
|
+
#
|
|
258
|
+
# See the yield parameters of {Interface#on_exception} for
|
|
259
|
+
# the overall argument format.
|
|
260
|
+
def queue_exception(kind, error, tasks, job_ids)
|
|
261
|
+
exception_queue.push [allocate_message_id, [kind, error, tasks, job_ids]]
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Whether some exception notifications have been queued
|
|
265
|
+
def has_exceptions?
|
|
266
|
+
!exception_queue.empty?
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# Remove and return the oldest exception notification
|
|
270
|
+
#
|
|
271
|
+
# @return [(Integer,Array)] a unique and monotonically-increasing
|
|
272
|
+
# message ID and the generic notification information as specified
|
|
273
|
+
# by (Interface#on_exception)
|
|
274
|
+
def pop_exception
|
|
275
|
+
exception_queue.shift
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Method called when trying to start an action that does not exist
|
|
279
|
+
class NoSuchAction < NoMethodError; end
|
|
280
|
+
|
|
281
|
+
# Start the given job within the batch
|
|
282
|
+
#
|
|
283
|
+
# @param [Symbol] action_name the action name
|
|
284
|
+
# @param [Hash<Symbol,Object>] arguments the action arguments
|
|
285
|
+
#
|
|
286
|
+
# @raise [NoSuchAction] if the requested action does not exist
|
|
287
|
+
def start_job(action_name, **arguments)
|
|
288
|
+
if find_action_by_name(action_name)
|
|
289
|
+
call([], :start_job, action_name, arguments)
|
|
290
|
+
else raise NoSuchAction, "there is no action called #{action_name} on #{self}"
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# @api private
|
|
295
|
+
#
|
|
296
|
+
# Call a method on the interface or on one of the interface's
|
|
297
|
+
# subcommands
|
|
298
|
+
#
|
|
299
|
+
# @param [Array<String>] path path to the subcommand. Empty means on
|
|
300
|
+
# the interface object itself.
|
|
301
|
+
# @param [Symbol] m command or action name. Actions are always
|
|
302
|
+
# formatted as action_name!
|
|
303
|
+
# @param [Object] args the command or action arguments
|
|
304
|
+
# @return [Object] the command result, or -- in the case of an
|
|
305
|
+
# action -- the job ID for the newly created action
|
|
306
|
+
def call(path, m, *args)
|
|
307
|
+
if m.to_s =~ /(.*)!$/
|
|
308
|
+
action_name = $1
|
|
309
|
+
start_job(action_name, *args)
|
|
310
|
+
else
|
|
311
|
+
io.write_packet([path, m, *args])
|
|
312
|
+
result, _ = poll(1)
|
|
313
|
+
result
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# @api private
|
|
318
|
+
#
|
|
319
|
+
# Asynchronously call a method on the interface or on one of the
|
|
320
|
+
# interface's subcommands
|
|
321
|
+
#
|
|
322
|
+
# @param [Array<String>] path path to the subcommand. Empty means on
|
|
323
|
+
# the interface object itself.
|
|
324
|
+
# @param [Symbol] m command or action name. Actions are always
|
|
325
|
+
# formatted as action_name!
|
|
326
|
+
# @param [Object] args the command or action arguments
|
|
327
|
+
# @return [Object] an Object associated with the call @see async_call_pending?
|
|
328
|
+
def async_call(path, m, *args, &block)
|
|
329
|
+
raise RuntimeError, "no callback block given" unless block_given?
|
|
330
|
+
if m.to_s =~ /(.*)!$/
|
|
331
|
+
action_name = $1
|
|
332
|
+
if find_action_by_name(action_name)
|
|
333
|
+
path = []
|
|
334
|
+
m = :start_job
|
|
335
|
+
args = [action_name, *args]
|
|
336
|
+
else raise NoSuchAction, "there is no action called #{action_name} on #{self}"
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
io.write_packet([path, m, *args])
|
|
340
|
+
pending_async_calls << { block: block, path: path, m: m, args: args }
|
|
341
|
+
pending_async_calls.last.freeze
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# @api private
|
|
345
|
+
#
|
|
346
|
+
# Whether the async call is still pending
|
|
347
|
+
# @param [Object] call the Object associated with the call
|
|
348
|
+
# @return [Boolean] true if the async call is pending,
|
|
349
|
+
# false otherwise
|
|
350
|
+
def async_call_pending?(a_call)
|
|
351
|
+
pending_async_calls.any? { |item| item.equal?(a_call) }
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
# @api private
|
|
355
|
+
#
|
|
356
|
+
# Object used to gather commands in a batch
|
|
357
|
+
#
|
|
358
|
+
# @see Client#create_batch Client#process_batch
|
|
359
|
+
class BatchContext < BasicObject
|
|
360
|
+
# Creates a new batch context
|
|
361
|
+
#
|
|
362
|
+
# @param [Object] context the underlying interface object
|
|
363
|
+
def initialize(context)
|
|
364
|
+
@context = context
|
|
365
|
+
@calls = ::Array.new
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def empty?
|
|
369
|
+
@calls.empty?
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
# The set of operations that have been gathered so far
|
|
373
|
+
def __calls
|
|
374
|
+
@calls
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Pushes an operation in the batch
|
|
378
|
+
def __push(path, m, *args)
|
|
379
|
+
@calls << [path, m, *args]
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
# Start the given job within the batch
|
|
383
|
+
#
|
|
384
|
+
# Note that as all batch operations, order does NOT matter
|
|
385
|
+
#
|
|
386
|
+
# @raise [NoSuchAction] if the action does not exist
|
|
387
|
+
def start_job(action_name, *args)
|
|
388
|
+
if @context.has_action?(action_name)
|
|
389
|
+
__push([], :start_job, action_name, *args)
|
|
390
|
+
else
|
|
391
|
+
::Kernel.raise ::Roby::Interface::Client::NoSuchAction, "there is no action called #{action_name} on #{@context}"
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Drop the given job within the batch
|
|
396
|
+
#
|
|
397
|
+
# Note that as all batch operations, order does NOT matter
|
|
398
|
+
def drop_job(job_id)
|
|
399
|
+
__push([], :drop_job, job_id)
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# Kill the given job within the batch
|
|
403
|
+
#
|
|
404
|
+
# Note that as all batch operations, order does NOT matter
|
|
405
|
+
def kill_job(job_id)
|
|
406
|
+
__push([], :kill_job, job_id)
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
def respond_to_missing?(m, include_private)
|
|
410
|
+
(m =~ /(.*)!$/) || super
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# @api private
|
|
414
|
+
#
|
|
415
|
+
# Provides the action_name! syntax to start jobs
|
|
416
|
+
def method_missing(m, *args)
|
|
417
|
+
if m =~ /(.*)!$/
|
|
418
|
+
start_job($1, *args)
|
|
419
|
+
else
|
|
420
|
+
::Kernel.raise ::NoMethodError.new(m), "#{m} either does not exist, or is not supported in batch context (only starting and killing jobs is)"
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# Process the batch and return the list of return values for all
|
|
425
|
+
# the calls in {#__calls}
|
|
426
|
+
def __process
|
|
427
|
+
@context.process_batch(self)
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
class Return
|
|
431
|
+
include Enumerable
|
|
432
|
+
|
|
433
|
+
Element = Struct.new :call, :return_value
|
|
434
|
+
|
|
435
|
+
def self.from_calls_and_return(calls, return_values)
|
|
436
|
+
elements = calls.zip(return_values).map do |c, r|
|
|
437
|
+
Element.new(c, r)
|
|
438
|
+
end
|
|
439
|
+
new(elements)
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def initialize(elements)
|
|
443
|
+
@elements = elements
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
def each(&block)
|
|
447
|
+
return enum_for(__method__) if !block_given?
|
|
448
|
+
@elements.each { |e| yield(e.return_value) }
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
def each_element(&block)
|
|
452
|
+
@elements.each(&block)
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def [](index)
|
|
456
|
+
@elements[index].return_value
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
def call_at(index)
|
|
460
|
+
@elements[index].call
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
def return_value_at(index)
|
|
464
|
+
@elements[index].return_value
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
def filter(call: nil)
|
|
468
|
+
filtered = @elements.find_all do |e|
|
|
469
|
+
e.call[1] == call
|
|
470
|
+
end
|
|
471
|
+
Return.new(filtered)
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
def started_jobs_id
|
|
475
|
+
filter(call: :start_job).to_a
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
def killed_jobs_id
|
|
479
|
+
filter(call: :kill_job).each_element.
|
|
480
|
+
map { |e| e.call[2] }
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
def dropped_jobs_id
|
|
484
|
+
filter(call: :drop_job).each_element.
|
|
485
|
+
map { |e| e.call[2] }
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
Job = Struct.new :job_id, :state, :placeholder_task, :task do
|
|
491
|
+
def action_model
|
|
492
|
+
task.action_model
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
# Enumerate the current jobs
|
|
497
|
+
def each_job
|
|
498
|
+
return enum_for(__method__) if !block_given?
|
|
499
|
+
jobs.each do |job_id, (job_state, placeholder_task, job_task)|
|
|
500
|
+
yield(Job.new(job_id, job_state, placeholder_task, job_task))
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
# Find all the jobs that match the given action name
|
|
505
|
+
#
|
|
506
|
+
# @return [Array<Job>]
|
|
507
|
+
def find_all_jobs_by_action_name(action_name)
|
|
508
|
+
each_job.find_all do |j|
|
|
509
|
+
j.action_model.name == action_name
|
|
510
|
+
end
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
# Create a batch context
|
|
514
|
+
#
|
|
515
|
+
# Messages sent to the returned object are validated as much as
|
|
516
|
+
# possible and gathered in a list. Call {#process_batch} to send all
|
|
517
|
+
# the gathered calls at once to the remote server
|
|
518
|
+
#
|
|
519
|
+
# @return [BatchContext]
|
|
520
|
+
def create_batch
|
|
521
|
+
BatchContext.new(self)
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
# Send all commands gathered in a batch for processing on the remote
|
|
525
|
+
# server
|
|
526
|
+
#
|
|
527
|
+
# @param [BatchContext] batch
|
|
528
|
+
# @return [Array] the return values of each of the calls gathered in
|
|
529
|
+
# the batch
|
|
530
|
+
def process_batch(batch)
|
|
531
|
+
ret = call([], :process_batch, batch.__calls)
|
|
532
|
+
BatchContext::Return.from_calls_and_return(batch.__calls, ret)
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
def reload_actions
|
|
536
|
+
@actions = call([], :reload_actions)
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
def find_subcommand_by_name(name)
|
|
540
|
+
commands[name]
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
def method_missing(m, *args)
|
|
544
|
+
if sub = find_subcommand_by_name(m.to_s)
|
|
545
|
+
SubcommandClient.new(self, m.to_s, sub.description, sub.commands)
|
|
546
|
+
else
|
|
547
|
+
call([], m, *args)
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
end
|
|
551
|
+
end
|
|
552
|
+
end
|
|
553
|
+
|