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.
Files changed (644) hide show
  1. checksums.yaml +7 -0
  2. data/.deep-cover.rb +3 -0
  3. data/.gitattributes +1 -0
  4. data/.gitignore +24 -0
  5. data/.simplecov +10 -0
  6. data/.travis.yml +17 -0
  7. data/.yardopts +4 -0
  8. data/Gemfile +15 -0
  9. data/README.md +11 -0
  10. data/Rakefile +47 -177
  11. data/benchmark/{alloc_misc.rb → attic/alloc_misc.rb} +2 -2
  12. data/benchmark/{discovery_latency.rb → attic/discovery_latency.rb} +19 -19
  13. data/benchmark/{garbage_collection.rb → attic/garbage_collection.rb} +9 -9
  14. data/benchmark/{genom.rb → attic/genom.rb} +0 -0
  15. data/benchmark/attic/transactions.rb +62 -0
  16. data/benchmark/plan_basic_operations.rb +28 -0
  17. data/benchmark/relations/graph.rb +63 -0
  18. data/benchmark/ruby/identity.rb +18 -0
  19. data/benchmark/ruby/set_intersect_vs_hash_merge.rb +39 -0
  20. data/benchmark/ruby/yield_vs_block.rb +35 -0
  21. data/benchmark/run +5 -0
  22. data/benchmark/synthetic_plan_modifications_with_transactions.rb +79 -0
  23. data/benchmark/transactions.rb +99 -51
  24. data/bin/roby +38 -197
  25. data/bin/roby-display +14 -0
  26. data/bin/roby-log +3 -176
  27. data/doc/guide/{src → attic}/abstraction/achieve_with.page +1 -1
  28. data/doc/guide/{src → attic}/abstraction/forwarding.page +1 -1
  29. data/doc/guide/{src → attic}/abstraction/hierarchy.page +1 -1
  30. data/doc/guide/{src → attic}/abstraction/index.page +1 -1
  31. data/doc/guide/{src → attic}/abstraction/task_models.page +1 -1
  32. data/doc/guide/{overview.rdoc → attic/cycle/api_overview.rdoc} +6 -1
  33. data/doc/guide/{src → attic}/cycle/cycle-overview.png +0 -0
  34. data/doc/guide/{src → attic}/cycle/cycle-overview.svg +0 -0
  35. data/doc/guide/attic/cycle/error_handling.page +98 -0
  36. data/doc/guide/{src → attic}/cycle/error_instantaneous_repair.png +0 -0
  37. data/doc/guide/{src → attic}/cycle/error_instantaneous_repair.svg +0 -0
  38. data/doc/guide/{src/cycle/error_handling.page → attic/cycle/error_sources.page} +46 -89
  39. data/doc/guide/{src → attic}/cycle/garbage_collection.page +1 -1
  40. data/doc/guide/{src → attic}/cycle/index.page +1 -1
  41. data/doc/guide/{src → attic}/cycle/propagation.page +11 -1
  42. data/doc/guide/{src → attic}/cycle/propagation_diamond.png +0 -0
  43. data/doc/guide/{src → attic}/cycle/propagation_diamond.svg +0 -0
  44. data/doc/guide/attic/plans/building_plans.page +89 -0
  45. data/doc/guide/attic/plans/code.page +192 -0
  46. data/doc/guide/{src/basics → attic/plans}/events.page +3 -4
  47. data/doc/guide/attic/plans/index.page +7 -0
  48. data/doc/guide/{plan_modifications.rdoc → attic/plans/plan_modifications.rdoc} +5 -3
  49. data/doc/guide/{src/basics → attic/plans}/plan_objects.page +2 -1
  50. data/doc/guide/attic/plans/querying_plans.page +5 -0
  51. data/doc/guide/{src/basics → attic/plans}/tasks.page +20 -20
  52. data/doc/guide/config.yaml +7 -4
  53. data/doc/guide/ext/extended_menu.rb +29 -0
  54. data/doc/guide/ext/init.rb +6 -0
  55. data/doc/guide/ext/rdoc_links.rb +7 -6
  56. data/doc/guide/src/advanced_concepts/history.page +5 -0
  57. data/doc/guide/src/advanced_concepts/index.page +11 -0
  58. data/doc/guide/src/advanced_concepts/recognizing_patterns.page +83 -0
  59. data/doc/guide/src/advanced_concepts/scheduling.page +87 -0
  60. data/doc/guide/src/advanced_concepts/transactions.page +5 -0
  61. data/doc/guide/src/advanced_concepts/unreachability.page +42 -0
  62. data/doc/guide/src/base.template +96 -0
  63. data/doc/guide/src/basics_shell_header.txt +5 -7
  64. data/doc/guide/src/building/action_coordination.page +96 -0
  65. data/doc/guide/src/building/actions.page +124 -0
  66. data/doc/guide/src/building/file_layout.page +71 -0
  67. data/doc/guide/src/building/index.page +50 -0
  68. data/doc/guide/src/building/patterns.page +86 -0
  69. data/doc/guide/src/building/patterns_forwarding.png +0 -0
  70. data/doc/guide/src/building/patterns_forwarding.svg +277 -0
  71. data/doc/guide/src/building/runtime.page +95 -0
  72. data/doc/guide/src/building/task_models.page +94 -0
  73. data/doc/guide/src/building/tasks.page +284 -0
  74. data/doc/guide/src/concepts/error_handling.page +100 -0
  75. data/doc/guide/src/concepts/exception_propagation.png +0 -0
  76. data/doc/guide/src/concepts/exception_propagation.svg +445 -0
  77. data/doc/guide/src/concepts/execution.page +85 -0
  78. data/doc/guide/src/concepts/execution.png +0 -0
  79. data/doc/guide/src/concepts/execution.svg +573 -0
  80. data/doc/guide/src/concepts/execution_cycle.png +0 -0
  81. data/doc/guide/src/concepts/garbage_collection.page +57 -0
  82. data/doc/guide/src/concepts/index.page +27 -0
  83. data/doc/guide/src/concepts/plans.page +101 -0
  84. data/doc/guide/src/concepts/policy.page +31 -0
  85. data/doc/guide/src/concepts/reactor.page +61 -0
  86. data/doc/guide/src/concepts/simple_plan_example.png +0 -0
  87. data/doc/guide/src/concepts/simple_plan_example.svg +376 -0
  88. data/doc/guide/src/default.template +9 -74
  89. data/doc/guide/src/event_relations/forward.page +71 -0
  90. data/doc/guide/src/event_relations/index.page +12 -0
  91. data/doc/guide/src/event_relations/scheduling_constraints.page +43 -0
  92. data/doc/guide/src/event_relations/signal.page +55 -0
  93. data/doc/guide/src/event_relations/temporal_constraints.page +77 -0
  94. data/doc/guide/src/htmldoc.metainfo +21 -8
  95. data/doc/guide/src/index.page +8 -3
  96. data/doc/guide/src/{introduction/install.page → installation/index.page} +37 -25
  97. data/doc/guide/src/installation/publications.page +14 -0
  98. data/doc/guide/src/{introduction → installation}/videos.page +14 -7
  99. data/doc/guide/src/interacting/index.page +16 -0
  100. data/doc/guide/src/interacting/run.page +33 -0
  101. data/doc/guide/src/interacting/shell.page +95 -0
  102. data/doc/guide/src/plugins/creating_plugins.page +72 -0
  103. data/doc/guide/src/plugins/index.page +27 -5
  104. data/doc/guide/src/plugins/{fault_tolerance.page → standard_plugins/fault_tolerance.page} +2 -2
  105. data/doc/guide/src/plugins/standard_plugins/index.page +11 -0
  106. data/doc/guide/src/plugins/{subsystems.page → standard_plugins/subsystems.page} +2 -2
  107. data/doc/guide/src/style_screen.css +687 -0
  108. data/doc/guide/src/task_relations/dependency.page +107 -0
  109. data/doc/guide/src/task_relations/executed_by.page +77 -0
  110. data/doc/guide/src/task_relations/index.page +12 -0
  111. data/doc/guide/src/task_relations/new_relations.page +119 -0
  112. data/doc/guide/src/task_relations/planned_by.page +46 -0
  113. data/doc/guide/src/tutorial/app.page +117 -0
  114. data/doc/guide/src/{basics → tutorial}/code_examples.page +6 -5
  115. data/doc/guide/src/{basics → tutorial}/dry.page +15 -15
  116. data/doc/guide/src/{basics → tutorial}/errors.page +43 -68
  117. data/doc/guide/src/tutorial/events.page +195 -0
  118. data/doc/guide/src/{basics → tutorial}/hierarchy.page +53 -52
  119. data/doc/guide/src/tutorial/index.page +13 -0
  120. data/doc/guide/src/tutorial/log_replay/goForward_1.png +0 -0
  121. data/doc/guide/src/tutorial/log_replay/goForward_2.png +0 -0
  122. data/doc/guide/src/tutorial/log_replay/goForward_3.png +0 -0
  123. data/doc/guide/src/{basics → tutorial}/log_replay/goForward_4.png +0 -0
  124. data/doc/guide/src/tutorial/log_replay/goForward_5.png +0 -0
  125. data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_1.png +0 -0
  126. data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_2.png +0 -0
  127. data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_3.png +0 -0
  128. data/doc/guide/src/tutorial/log_replay/moveto_code_error.png +0 -0
  129. data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_1.png +0 -0
  130. data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_2.png +0 -0
  131. data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_3.png +0 -0
  132. data/doc/guide/src/tutorial/log_replay/plan_repair_4.png +0 -0
  133. data/doc/guide/src/tutorial/log_replay/roby_log_main_window.png +0 -0
  134. data/doc/guide/src/{basics → tutorial}/log_replay/roby_log_relation_window.png +0 -0
  135. data/doc/guide/src/{basics → tutorial}/log_replay/roby_replay_event_representation.png +0 -0
  136. data/doc/guide/src/tutorial/relations_display.page +153 -0
  137. data/doc/guide/src/{basics → tutorial}/roby_cycle_overview.png +0 -0
  138. data/doc/guide/src/tutorial/shell.page +121 -0
  139. data/doc/guide/src/{basics → tutorial}/summary.page +1 -1
  140. data/doc/guide/src/tutorial/tasks.page +374 -0
  141. data/lib/roby.rb +102 -47
  142. data/lib/roby/actions.rb +17 -0
  143. data/lib/roby/actions/action.rb +80 -0
  144. data/lib/roby/actions/interface.rb +45 -0
  145. data/lib/roby/actions/library.rb +23 -0
  146. data/lib/roby/actions/models/action.rb +224 -0
  147. data/lib/roby/actions/models/coordination_action.rb +58 -0
  148. data/lib/roby/actions/models/interface.rb +22 -0
  149. data/lib/roby/actions/models/interface_base.rb +294 -0
  150. data/lib/roby/actions/models/library.rb +12 -0
  151. data/lib/roby/actions/models/method_action.rb +90 -0
  152. data/lib/roby/actions/task.rb +114 -0
  153. data/lib/roby/and_generator.rb +125 -0
  154. data/lib/roby/app.rb +2795 -829
  155. data/lib/roby/app/autotest_console_reporter.rb +138 -0
  156. data/lib/roby/app/base.rb +21 -0
  157. data/lib/roby/app/cucumber.rb +2 -0
  158. data/lib/roby/app/cucumber/controller.rb +439 -0
  159. data/lib/roby/app/cucumber/helpers.rb +280 -0
  160. data/lib/roby/app/cucumber/world.rb +32 -0
  161. data/lib/roby/app/debug.rb +136 -0
  162. data/lib/roby/app/gen.rb +2 -0
  163. data/lib/roby/app/rake.rb +178 -38
  164. data/lib/roby/app/robot_config.rb +9 -0
  165. data/lib/roby/app/robot_names.rb +115 -0
  166. data/lib/roby/app/run.rb +3 -2
  167. data/lib/roby/app/scripts.rb +72 -0
  168. data/lib/roby/app/scripts/autotest.rb +173 -0
  169. data/lib/roby/app/scripts/display.rb +2 -0
  170. data/lib/roby/app/scripts/restart.rb +52 -0
  171. data/lib/roby/app/scripts/results.rb +17 -8
  172. data/lib/roby/app/scripts/run.rb +155 -24
  173. data/lib/roby/app/scripts/shell.rb +147 -62
  174. data/lib/roby/app/scripts/test.rb +107 -22
  175. data/lib/roby/app/test_reporter.rb +74 -0
  176. data/lib/roby/app/test_server.rb +159 -0
  177. data/lib/roby/app/vagrant.rb +47 -0
  178. data/lib/roby/backports.rb +16 -0
  179. data/lib/roby/cli/display.rb +190 -0
  180. data/lib/roby/cli/exceptions.rb +17 -0
  181. data/lib/roby/cli/gen/actions/class.rb +5 -0
  182. data/lib/roby/cli/gen/actions/test.rb +6 -0
  183. data/lib/roby/cli/gen/app/.yardopts +6 -0
  184. data/lib/roby/cli/gen/app/README.md +28 -0
  185. data/lib/roby/cli/gen/app/Rakefile +15 -0
  186. data/{app → lib/roby/cli/gen/app}/config/app.yml +29 -39
  187. data/lib/roby/cli/gen/app/models/.gitattributes +1 -0
  188. data/{app → lib/roby/cli/gen/app/scripts}/controllers/.gitattributes +0 -0
  189. data/{app/data/.gitattributes → lib/roby/cli/gen/app/test/.gitignore} +0 -0
  190. data/lib/roby/cli/gen/class/class.rb +6 -0
  191. data/lib/roby/cli/gen/class/test.rb +7 -0
  192. data/lib/roby/cli/gen/helpers.rb +203 -0
  193. data/lib/roby/cli/gen/module/module.rb +5 -0
  194. data/lib/roby/cli/gen/module/test.rb +6 -0
  195. data/lib/roby/cli/gen/roby_app/config/init.rb +17 -0
  196. data/lib/roby/cli/gen/roby_app/config/robots/robot.rb +40 -0
  197. data/lib/roby/cli/gen/task/class.rb +44 -0
  198. data/lib/roby/cli/gen/task/test.rb +6 -0
  199. data/lib/roby/cli/gen_main.rb +120 -0
  200. data/lib/roby/cli/log.rb +276 -0
  201. data/lib/roby/cli/log/flamegraph.html +499 -0
  202. data/lib/roby/cli/log/flamegraph_renderer.rb +88 -0
  203. data/lib/roby/cli/main.rb +153 -0
  204. data/lib/roby/coordination.rb +60 -0
  205. data/lib/roby/coordination/action_script.rb +25 -0
  206. data/lib/roby/coordination/action_state_machine.rb +125 -0
  207. data/lib/roby/coordination/actions.rb +106 -0
  208. data/lib/roby/coordination/base.rb +145 -0
  209. data/lib/roby/coordination/calculus.rb +40 -0
  210. data/lib/roby/coordination/child.rb +28 -0
  211. data/lib/roby/coordination/event.rb +29 -0
  212. data/lib/roby/coordination/fault_handler.rb +25 -0
  213. data/lib/roby/coordination/fault_handling_task.rb +13 -0
  214. data/lib/roby/coordination/fault_response_table.rb +110 -0
  215. data/lib/roby/coordination/models/action_script.rb +64 -0
  216. data/lib/roby/coordination/models/action_state_machine.rb +224 -0
  217. data/lib/roby/coordination/models/actions.rb +191 -0
  218. data/lib/roby/coordination/models/arguments.rb +55 -0
  219. data/lib/roby/coordination/models/base.rb +176 -0
  220. data/lib/roby/coordination/models/capture.rb +86 -0
  221. data/lib/roby/coordination/models/child.rb +35 -0
  222. data/lib/roby/coordination/models/event.rb +41 -0
  223. data/lib/roby/coordination/models/exceptions.rb +42 -0
  224. data/lib/roby/coordination/models/fault_handler.rb +219 -0
  225. data/lib/roby/coordination/models/fault_response_table.rb +77 -0
  226. data/lib/roby/coordination/models/root.rb +22 -0
  227. data/lib/roby/coordination/models/script.rb +283 -0
  228. data/lib/roby/coordination/models/task.rb +184 -0
  229. data/lib/roby/coordination/models/task_from_action.rb +50 -0
  230. data/lib/roby/coordination/models/task_from_as_plan.rb +33 -0
  231. data/lib/roby/coordination/models/task_from_instanciation_object.rb +31 -0
  232. data/lib/roby/coordination/models/task_from_variable.rb +27 -0
  233. data/lib/roby/coordination/models/task_with_dependencies.rb +48 -0
  234. data/lib/roby/coordination/models/variable.rb +32 -0
  235. data/lib/roby/coordination/script.rb +200 -0
  236. data/lib/roby/coordination/script_instruction.rb +12 -0
  237. data/lib/roby/coordination/task.rb +45 -0
  238. data/lib/roby/coordination/task_base.rb +69 -0
  239. data/lib/roby/coordination/task_script.rb +293 -0
  240. data/lib/roby/coordination/task_state_machine.rb +308 -0
  241. data/lib/roby/decision_control.rb +33 -21
  242. data/lib/roby/distributed_object.rb +76 -0
  243. data/lib/roby/droby.rb +17 -0
  244. data/lib/roby/droby/droby_id.rb +6 -0
  245. data/lib/roby/droby/enable.rb +153 -0
  246. data/lib/roby/droby/event_logger.rb +189 -0
  247. data/lib/roby/droby/event_logging.rb +57 -0
  248. data/lib/roby/droby/exceptions.rb +14 -0
  249. data/lib/roby/droby/identifiable.rb +22 -0
  250. data/lib/roby/droby/logfile.rb +141 -0
  251. data/lib/roby/droby/logfile/client.rb +176 -0
  252. data/lib/roby/droby/logfile/file_format.md +97 -0
  253. data/lib/roby/droby/logfile/index.rb +117 -0
  254. data/lib/roby/droby/logfile/reader.rb +139 -0
  255. data/lib/roby/droby/logfile/server.rb +199 -0
  256. data/lib/roby/droby/logfile/writer.rb +114 -0
  257. data/lib/roby/droby/marshal.rb +264 -0
  258. data/lib/roby/droby/marshallable.rb +12 -0
  259. data/lib/roby/droby/null_event_logger.rb +25 -0
  260. data/lib/roby/droby/object_manager.rb +205 -0
  261. data/lib/roby/droby/peer_id.rb +6 -0
  262. data/lib/roby/droby/plan_rebuilder.rb +373 -0
  263. data/lib/roby/droby/rebuilt_plan.rb +160 -0
  264. data/lib/roby/droby/remote_droby_id.rb +6 -0
  265. data/lib/roby/droby/timepoints.rb +205 -0
  266. data/lib/roby/droby/timepoints_ctf.metadata.erb +101 -0
  267. data/lib/roby/droby/timepoints_ctf.rb +125 -0
  268. data/lib/roby/droby/v5.rb +14 -0
  269. data/lib/roby/droby/v5/builtin.rb +120 -0
  270. data/lib/roby/droby/v5/droby_class.rb +45 -0
  271. data/lib/roby/droby/v5/droby_constant.rb +81 -0
  272. data/lib/roby/droby/v5/droby_dump.rb +1026 -0
  273. data/lib/roby/droby/v5/droby_id.rb +44 -0
  274. data/lib/roby/droby/v5/droby_model.rb +82 -0
  275. data/lib/roby/droby/v5/peer_id.rb +10 -0
  276. data/lib/roby/droby/v5/remote_droby_id.rb +42 -0
  277. data/lib/roby/event.rb +79 -957
  278. data/lib/roby/event_constraints.rb +835 -0
  279. data/lib/roby/event_generator.rb +1047 -0
  280. data/lib/roby/event_structure/causal_link.rb +6 -0
  281. data/lib/roby/event_structure/forwarding.rb +6 -0
  282. data/lib/roby/event_structure/precedence.rb +7 -0
  283. data/lib/roby/event_structure/signal.rb +8 -0
  284. data/lib/roby/event_structure/temporal_constraints.rb +640 -0
  285. data/lib/roby/exceptions.rb +446 -152
  286. data/lib/roby/executable_plan.rb +549 -0
  287. data/lib/roby/execution_engine.rb +1997 -950
  288. data/lib/roby/filter_generator.rb +26 -0
  289. data/lib/roby/gui/chronicle_view.rb +225 -0
  290. data/lib/roby/gui/chronicle_widget.rb +925 -0
  291. data/lib/roby/gui/dot_id.rb +11 -0
  292. data/lib/roby/gui/exception_view.rb +44 -0
  293. data/lib/roby/gui/log_display.rb +273 -0
  294. data/lib/roby/gui/model_views.rb +2 -0
  295. data/lib/roby/gui/model_views/action_interface.rb +53 -0
  296. data/lib/roby/gui/model_views/task.rb +47 -0
  297. data/lib/roby/gui/model_views/task.rhtml +41 -0
  298. data/lib/roby/gui/object_info_view.rb +89 -0
  299. data/lib/roby/gui/plan_dot_layout.rb +427 -0
  300. data/lib/roby/gui/plan_rebuilder_widget.rb +357 -0
  301. data/lib/roby/gui/qt4_toMSecsSinceEpoch.rb +8 -0
  302. data/lib/roby/gui/relations_view.rb +278 -0
  303. data/lib/roby/gui/relations_view/relations.ui +139 -0
  304. data/lib/roby/gui/relations_view/relations_canvas.rb +1088 -0
  305. data/lib/roby/gui/relations_view/relations_config.rb +292 -0
  306. data/lib/roby/gui/relations_view/relations_view.ui +53 -0
  307. data/lib/roby/gui/scheduler_view.css +24 -0
  308. data/lib/roby/gui/scheduler_view.rb +46 -0
  309. data/lib/roby/gui/scheduler_view.rhtml +53 -0
  310. data/lib/roby/gui/stepping.rb +93 -0
  311. data/lib/roby/gui/stepping.ui +181 -0
  312. data/lib/roby/gui/styles.rb +81 -0
  313. data/lib/roby/gui/task_display_configuration.rb +42 -0
  314. data/lib/roby/gui/task_state_at.rb +38 -0
  315. data/lib/roby/hooks.rb +26 -0
  316. data/lib/roby/interface.rb +136 -469
  317. data/lib/roby/interface/async.rb +20 -0
  318. data/lib/roby/interface/async/action_monitor.rb +188 -0
  319. data/lib/roby/interface/async/interface.rb +498 -0
  320. data/lib/roby/interface/async/job_monitor.rb +213 -0
  321. data/lib/roby/interface/async/log.rb +238 -0
  322. data/lib/roby/interface/async/new_job_listener.rb +79 -0
  323. data/lib/roby/interface/async/ui_connector.rb +183 -0
  324. data/lib/roby/interface/client.rb +553 -0
  325. data/lib/roby/interface/command.rb +24 -0
  326. data/lib/roby/interface/command_argument.rb +16 -0
  327. data/lib/roby/interface/command_library.rb +92 -0
  328. data/lib/roby/interface/droby_channel.rb +174 -0
  329. data/lib/roby/interface/exceptions.rb +22 -0
  330. data/lib/roby/interface/interface.rb +655 -0
  331. data/lib/roby/interface/job.rb +47 -0
  332. data/lib/roby/interface/rest.rb +10 -0
  333. data/lib/roby/interface/rest/api.rb +29 -0
  334. data/lib/roby/interface/rest/helpers.rb +24 -0
  335. data/lib/roby/interface/rest/server.rb +212 -0
  336. data/lib/roby/interface/server.rb +154 -0
  337. data/lib/roby/interface/shell_client.rb +468 -0
  338. data/lib/roby/interface/shell_subcommand.rb +24 -0
  339. data/lib/roby/interface/subcommand_client.rb +35 -0
  340. data/lib/roby/interface/tcp.rb +168 -0
  341. data/lib/roby/models/arguments.rb +112 -0
  342. data/lib/roby/models/plan_object.rb +83 -0
  343. data/lib/roby/models/task.rb +835 -0
  344. data/lib/roby/models/task_event.rb +62 -0
  345. data/lib/roby/models/task_service.rb +78 -0
  346. data/lib/roby/or_generator.rb +88 -0
  347. data/lib/roby/plan.rb +1751 -864
  348. data/lib/roby/plan_object.rb +611 -0
  349. data/lib/roby/plan_service.rb +200 -0
  350. data/lib/roby/promise.rb +332 -0
  351. data/lib/roby/queries.rb +23 -0
  352. data/lib/roby/queries/and_matcher.rb +32 -0
  353. data/lib/roby/queries/any.rb +27 -0
  354. data/lib/roby/queries/code_error_matcher.rb +58 -0
  355. data/lib/roby/queries/event_generator_matcher.rb +9 -0
  356. data/lib/roby/queries/execution_exception_matcher.rb +165 -0
  357. data/lib/roby/queries/index.rb +165 -0
  358. data/lib/roby/queries/localized_error_matcher.rb +149 -0
  359. data/lib/roby/queries/matcher_base.rb +107 -0
  360. data/lib/roby/queries/none.rb +27 -0
  361. data/lib/roby/queries/not_matcher.rb +30 -0
  362. data/lib/roby/queries/op_matcher.rb +8 -0
  363. data/lib/roby/queries/or_matcher.rb +30 -0
  364. data/lib/roby/queries/plan_object_matcher.rb +363 -0
  365. data/lib/roby/queries/query.rb +188 -0
  366. data/lib/roby/queries/task_event_generator_matcher.rb +86 -0
  367. data/lib/roby/queries/task_matcher.rb +344 -0
  368. data/lib/roby/relations.rb +42 -678
  369. data/lib/roby/relations/bidirectional_directed_adjacency_graph.rb +492 -0
  370. data/lib/roby/relations/directed_relation_support.rb +268 -0
  371. data/lib/roby/relations/event_relation_graph.rb +19 -0
  372. data/lib/roby/relations/fork_merge_visitor.rb +154 -0
  373. data/lib/roby/relations/graph.rb +533 -0
  374. data/lib/roby/relations/models/directed_relation_support.rb +11 -0
  375. data/lib/roby/relations/models/graph.rb +75 -0
  376. data/lib/roby/relations/models/task_relation_graph.rb +18 -0
  377. data/lib/roby/relations/space.rb +380 -0
  378. data/lib/roby/relations/task_relation_graph.rb +20 -0
  379. data/lib/roby/robot.rb +85 -38
  380. data/lib/roby/schedulers/basic.rb +155 -25
  381. data/lib/roby/schedulers/null.rb +20 -0
  382. data/lib/roby/schedulers/reporting.rb +31 -0
  383. data/lib/roby/schedulers/state.rb +129 -0
  384. data/lib/roby/schedulers/temporal.rb +91 -0
  385. data/lib/roby/singletons.rb +87 -0
  386. data/lib/roby/standalone.rb +4 -2
  387. data/lib/roby/standard_errors.rb +405 -82
  388. data/lib/roby/state.rb +6 -3
  389. data/lib/roby/state/conf_model.rb +5 -0
  390. data/lib/roby/state/events.rb +181 -95
  391. data/lib/roby/state/goal_model.rb +77 -0
  392. data/lib/roby/state/open_struct.rb +591 -0
  393. data/lib/roby/state/open_struct_model.rb +68 -0
  394. data/lib/roby/state/pos.rb +45 -45
  395. data/lib/roby/state/shapes.rb +11 -11
  396. data/lib/roby/state/state_model.rb +303 -0
  397. data/lib/roby/state/task.rb +43 -0
  398. data/lib/roby/support.rb +88 -148
  399. data/lib/roby/task.rb +1361 -1750
  400. data/lib/roby/task_arguments.rb +428 -0
  401. data/lib/roby/task_event.rb +127 -0
  402. data/lib/roby/task_event_generator.rb +337 -0
  403. data/lib/roby/task_service.rb +6 -0
  404. data/lib/roby/task_structure/conflicts.rb +104 -0
  405. data/lib/roby/task_structure/dependency.rb +932 -0
  406. data/lib/roby/task_structure/error_handling.rb +118 -0
  407. data/lib/roby/task_structure/executed_by.rb +234 -0
  408. data/lib/roby/task_structure/planned_by.rb +90 -0
  409. data/lib/roby/tasks/aggregator.rb +37 -0
  410. data/lib/roby/tasks/external_process.rb +275 -0
  411. data/lib/roby/tasks/group.rb +27 -0
  412. data/lib/roby/tasks/null.rb +19 -0
  413. data/lib/roby/tasks/parallel.rb +43 -0
  414. data/lib/roby/tasks/sequence.rb +88 -0
  415. data/lib/roby/tasks/simple.rb +21 -0
  416. data/lib/roby/{thread_task.rb → tasks/thread.rb} +50 -24
  417. data/lib/roby/tasks/timeout.rb +17 -0
  418. data/lib/roby/tasks/virtual.rb +55 -0
  419. data/lib/roby/template_plan.rb +7 -0
  420. data/lib/roby/test/aruba_minitest.rb +74 -0
  421. data/lib/roby/test/assertion.rb +16 -0
  422. data/lib/roby/test/assertions.rb +490 -0
  423. data/lib/roby/test/common.rb +368 -591
  424. data/lib/roby/test/dsl.rb +149 -0
  425. data/lib/roby/test/error.rb +18 -0
  426. data/lib/roby/test/event_reporter.rb +83 -0
  427. data/lib/roby/test/execution_expectations.rb +1134 -0
  428. data/lib/roby/test/expect_execution.rb +151 -0
  429. data/lib/roby/test/minitest_helpers.rb +166 -0
  430. data/lib/roby/test/roby_app_helpers.rb +200 -0
  431. data/lib/roby/test/run_planners.rb +155 -0
  432. data/lib/roby/test/self.rb +112 -0
  433. data/lib/roby/test/spec.rb +198 -0
  434. data/lib/roby/test/tasks/empty_task.rb +4 -4
  435. data/lib/roby/test/tasks/goto.rb +28 -27
  436. data/lib/roby/test/teardown_plans.rb +100 -0
  437. data/lib/roby/test/testcase.rb +239 -307
  438. data/lib/roby/test/tools.rb +159 -155
  439. data/lib/roby/test/validate_state_machine.rb +75 -0
  440. data/lib/roby/transaction.rb +1125 -0
  441. data/lib/roby/transaction/event_generator_proxy.rb +63 -0
  442. data/lib/roby/transaction/plan_object_proxy.rb +99 -0
  443. data/lib/roby/transaction/plan_service_proxy.rb +43 -0
  444. data/lib/roby/transaction/proxying.rb +120 -0
  445. data/lib/roby/transaction/task_event_generator_proxy.rb +19 -0
  446. data/lib/roby/transaction/task_proxy.rb +135 -0
  447. data/lib/roby/until_generator.rb +30 -0
  448. data/lib/roby/version.rb +5 -0
  449. data/lib/roby/yard.rb +169 -0
  450. data/lib/yard-roby.rb +1 -0
  451. data/manifest.xml +32 -6
  452. data/roby.gemspec +59 -0
  453. metadata +788 -587
  454. data/Manifest.txt +0 -321
  455. data/NOTES +0 -4
  456. data/README.txt +0 -166
  457. data/TODO.txt +0 -146
  458. data/app/README.txt +0 -24
  459. data/app/Rakefile +0 -8
  460. data/app/config/ROBOT.rb +0 -5
  461. data/app/config/init.rb +0 -33
  462. data/app/config/roby.yml +0 -3
  463. data/app/controllers/ROBOT.rb +0 -2
  464. data/app/planners/ROBOT/main.rb +0 -6
  465. data/app/planners/main.rb +0 -5
  466. data/app/scripts/distributed +0 -3
  467. data/app/scripts/generate/bookmarks +0 -3
  468. data/app/scripts/replay +0 -3
  469. data/app/scripts/results +0 -3
  470. data/app/scripts/run +0 -3
  471. data/app/scripts/server +0 -3
  472. data/app/scripts/shell +0 -3
  473. data/app/scripts/test +0 -3
  474. data/app/tasks/.gitattributes +0 -0
  475. data/app/tasks/ROBOT/.gitattributes +0 -0
  476. data/bin/roby-shell +0 -25
  477. data/doc/guide/src/basics/app.page +0 -139
  478. data/doc/guide/src/basics/index.page +0 -11
  479. data/doc/guide/src/basics/log_replay/goForward_1.png +0 -0
  480. data/doc/guide/src/basics/log_replay/goForward_2.png +0 -0
  481. data/doc/guide/src/basics/log_replay/goForward_3.png +0 -0
  482. data/doc/guide/src/basics/log_replay/goForward_5.png +0 -0
  483. data/doc/guide/src/basics/log_replay/plan_repair_4.png +0 -0
  484. data/doc/guide/src/basics/log_replay/roby_log_main_window.png +0 -0
  485. data/doc/guide/src/basics/relations_display.page +0 -203
  486. data/doc/guide/src/basics/shell.page +0 -102
  487. data/doc/guide/src/default.css +0 -319
  488. data/doc/guide/src/introduction/index.page +0 -29
  489. data/doc/guide/src/introduction/publications.page +0 -14
  490. data/doc/guide/src/relations/dependency.page +0 -89
  491. data/doc/guide/src/relations/index.page +0 -12
  492. data/ext/droby/dump.cc +0 -175
  493. data/ext/droby/extconf.rb +0 -3
  494. data/ext/graph/algorithm.cc +0 -746
  495. data/ext/graph/extconf.rb +0 -7
  496. data/ext/graph/graph.cc +0 -575
  497. data/ext/graph/graph.hh +0 -183
  498. data/ext/graph/iterator_sequence.hh +0 -102
  499. data/ext/graph/undirected_dfs.hh +0 -226
  500. data/ext/graph/undirected_graph.hh +0 -421
  501. data/lib/roby/app/scripts/generate/bookmarks.rb +0 -162
  502. data/lib/roby/app/scripts/replay.rb +0 -31
  503. data/lib/roby/app/scripts/server.rb +0 -18
  504. data/lib/roby/basic_object.rb +0 -151
  505. data/lib/roby/config.rb +0 -14
  506. data/lib/roby/distributed.rb +0 -36
  507. data/lib/roby/distributed/base.rb +0 -448
  508. data/lib/roby/distributed/communication.rb +0 -875
  509. data/lib/roby/distributed/connection_space.rb +0 -616
  510. data/lib/roby/distributed/distributed_object.rb +0 -206
  511. data/lib/roby/distributed/drb.rb +0 -62
  512. data/lib/roby/distributed/notifications.rb +0 -531
  513. data/lib/roby/distributed/peer.rb +0 -555
  514. data/lib/roby/distributed/protocol.rb +0 -529
  515. data/lib/roby/distributed/proxy.rb +0 -343
  516. data/lib/roby/distributed/subscription.rb +0 -311
  517. data/lib/roby/distributed/transaction.rb +0 -498
  518. data/lib/roby/external_process_task.rb +0 -225
  519. data/lib/roby/graph.rb +0 -160
  520. data/lib/roby/log.rb +0 -3
  521. data/lib/roby/log/chronicle.rb +0 -303
  522. data/lib/roby/log/console.rb +0 -74
  523. data/lib/roby/log/data_stream.rb +0 -275
  524. data/lib/roby/log/dot.rb +0 -279
  525. data/lib/roby/log/event_stream.rb +0 -161
  526. data/lib/roby/log/file.rb +0 -396
  527. data/lib/roby/log/gui/basic_display.ui +0 -83
  528. data/lib/roby/log/gui/basic_display_ui.rb +0 -89
  529. data/lib/roby/log/gui/chronicle.rb +0 -26
  530. data/lib/roby/log/gui/chronicle_view.rb +0 -40
  531. data/lib/roby/log/gui/chronicle_view.ui +0 -70
  532. data/lib/roby/log/gui/chronicle_view_ui.rb +0 -90
  533. data/lib/roby/log/gui/data_displays.rb +0 -171
  534. data/lib/roby/log/gui/data_displays.ui +0 -155
  535. data/lib/roby/log/gui/data_displays_ui.rb +0 -146
  536. data/lib/roby/log/gui/notifications.rb +0 -26
  537. data/lib/roby/log/gui/relations.rb +0 -269
  538. data/lib/roby/log/gui/relations.ui +0 -123
  539. data/lib/roby/log/gui/relations_ui.rb +0 -120
  540. data/lib/roby/log/gui/relations_view.rb +0 -185
  541. data/lib/roby/log/gui/relations_view.ui +0 -149
  542. data/lib/roby/log/gui/relations_view_ui.rb +0 -144
  543. data/lib/roby/log/gui/replay.rb +0 -366
  544. data/lib/roby/log/gui/replay_controls.rb +0 -206
  545. data/lib/roby/log/gui/replay_controls.ui +0 -282
  546. data/lib/roby/log/gui/replay_controls_ui.rb +0 -249
  547. data/lib/roby/log/gui/runtime.rb +0 -130
  548. data/lib/roby/log/hooks.rb +0 -186
  549. data/lib/roby/log/logger.rb +0 -203
  550. data/lib/roby/log/notifications.rb +0 -244
  551. data/lib/roby/log/plan_rebuilder.rb +0 -468
  552. data/lib/roby/log/relations.rb +0 -1084
  553. data/lib/roby/log/server.rb +0 -547
  554. data/lib/roby/log/sqlite.rb +0 -47
  555. data/lib/roby/log/timings.rb +0 -233
  556. data/lib/roby/plan-object.rb +0 -371
  557. data/lib/roby/planning.rb +0 -13
  558. data/lib/roby/planning/loops.rb +0 -309
  559. data/lib/roby/planning/model.rb +0 -1012
  560. data/lib/roby/planning/task.rb +0 -180
  561. data/lib/roby/query.rb +0 -655
  562. data/lib/roby/relations/conflicts.rb +0 -67
  563. data/lib/roby/relations/dependency.rb +0 -358
  564. data/lib/roby/relations/ensured.rb +0 -19
  565. data/lib/roby/relations/error_handling.rb +0 -22
  566. data/lib/roby/relations/events.rb +0 -7
  567. data/lib/roby/relations/executed_by.rb +0 -208
  568. data/lib/roby/relations/influence.rb +0 -10
  569. data/lib/roby/relations/planned_by.rb +0 -63
  570. data/lib/roby/state/information.rb +0 -55
  571. data/lib/roby/state/state.rb +0 -367
  572. data/lib/roby/task-operations.rb +0 -186
  573. data/lib/roby/task_index.rb +0 -80
  574. data/lib/roby/test/distributed.rb +0 -230
  575. data/lib/roby/test/tasks/simple_task.rb +0 -23
  576. data/lib/roby/transactions.rb +0 -507
  577. data/lib/roby/transactions/proxy.rb +0 -325
  578. data/plugins/fault_injection/History.txt +0 -4
  579. data/plugins/fault_injection/README.txt +0 -34
  580. data/plugins/fault_injection/Rakefile +0 -12
  581. data/plugins/fault_injection/TODO.txt +0 -0
  582. data/plugins/fault_injection/app.rb +0 -52
  583. data/plugins/fault_injection/fault_injection.rb +0 -89
  584. data/plugins/fault_injection/test/test_fault_injection.rb +0 -78
  585. data/plugins/subsystems/README.txt +0 -37
  586. data/plugins/subsystems/Rakefile +0 -13
  587. data/plugins/subsystems/app.rb +0 -182
  588. data/plugins/subsystems/test/app/README +0 -24
  589. data/plugins/subsystems/test/app/Rakefile +0 -8
  590. data/plugins/subsystems/test/app/config/app.yml +0 -71
  591. data/plugins/subsystems/test/app/config/init.rb +0 -12
  592. data/plugins/subsystems/test/app/config/roby.yml +0 -3
  593. data/plugins/subsystems/test/app/planners/main.rb +0 -20
  594. data/plugins/subsystems/test/app/scripts/distributed +0 -3
  595. data/plugins/subsystems/test/app/scripts/replay +0 -3
  596. data/plugins/subsystems/test/app/scripts/results +0 -3
  597. data/plugins/subsystems/test/app/scripts/run +0 -3
  598. data/plugins/subsystems/test/app/scripts/server +0 -3
  599. data/plugins/subsystems/test/app/scripts/shell +0 -3
  600. data/plugins/subsystems/test/app/scripts/test +0 -3
  601. data/plugins/subsystems/test/app/tasks/services.rb +0 -15
  602. data/plugins/subsystems/test/test_subsystems.rb +0 -78
  603. data/test/distributed/test_communication.rb +0 -195
  604. data/test/distributed/test_connection.rb +0 -284
  605. data/test/distributed/test_execution.rb +0 -378
  606. data/test/distributed/test_mixed_plan.rb +0 -341
  607. data/test/distributed/test_plan_notifications.rb +0 -238
  608. data/test/distributed/test_protocol.rb +0 -525
  609. data/test/distributed/test_query.rb +0 -106
  610. data/test/distributed/test_remote_plan.rb +0 -491
  611. data/test/distributed/test_transaction.rb +0 -466
  612. data/test/mockups/external_process +0 -28
  613. data/test/mockups/tasks.rb +0 -27
  614. data/test/planning/test_loops.rb +0 -432
  615. data/test/planning/test_model.rb +0 -427
  616. data/test/planning/test_task.rb +0 -126
  617. data/test/relations/test_conflicts.rb +0 -42
  618. data/test/relations/test_dependency.rb +0 -324
  619. data/test/relations/test_ensured.rb +0 -38
  620. data/test/relations/test_executed_by.rb +0 -224
  621. data/test/relations/test_planned_by.rb +0 -56
  622. data/test/suite_core.rb +0 -29
  623. data/test/suite_distributed.rb +0 -10
  624. data/test/suite_planning.rb +0 -4
  625. data/test/suite_relations.rb +0 -8
  626. data/test/tasks/test_external_process.rb +0 -126
  627. data/test/tasks/test_thread_task.rb +0 -70
  628. data/test/test_bgl.rb +0 -528
  629. data/test/test_event.rb +0 -969
  630. data/test/test_exceptions.rb +0 -591
  631. data/test/test_execution_engine.rb +0 -987
  632. data/test/test_gui.rb +0 -20
  633. data/test/test_interface.rb +0 -43
  634. data/test/test_log.rb +0 -125
  635. data/test/test_log_server.rb +0 -133
  636. data/test/test_plan.rb +0 -418
  637. data/test/test_query.rb +0 -424
  638. data/test/test_relations.rb +0 -260
  639. data/test/test_state.rb +0 -432
  640. data/test/test_support.rb +0 -16
  641. data/test/test_task.rb +0 -1181
  642. data/test/test_testcase.rb +0 -138
  643. data/test/test_transactions.rb +0 -610
  644. data/test/test_transactions_proxy.rb +0 -216
@@ -0,0 +1,24 @@
1
+ module Roby
2
+ module Interface
3
+ # A command on an {CommandLibrary}
4
+ class Command
5
+ # @return [Symbol] the command name
6
+ attr_reader :name
7
+ # @return [Array<String>] the command description. The first element
8
+ # of the array is used as a command summary
9
+ attr_reader :description
10
+ # @return [Hash<Symbol,CommandArgument>] the set of arguments for
11
+ # this command
12
+ attr_reader :arguments
13
+
14
+ def initialize(name, description, arguments = Hash.new)
15
+ @name, @description, @arguments = name, Array(description), Kernel.normalize_options(arguments)
16
+ end
17
+
18
+ def droby_dump(peer)
19
+ self
20
+ end
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,16 @@
1
+ module Roby
2
+ module Interface
3
+ # An argument of a {Command}
4
+ class CommandArgument
5
+ # @return [Symbol] the argument name
6
+ attr_reader :name
7
+ # @return [Array<String>] the argument description
8
+ attr_reader :description
9
+
10
+ def initialize(name, description)
11
+ @name, @description = name.to_sym, Array(description)
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,92 @@
1
+ module Roby
2
+ module Interface
3
+ # Objects that hold a set of commands
4
+ class CommandLibrary
5
+ class << self
6
+ extend MetaRuby::Attributes
7
+ inherited_attribute(:command, :commands, map: true) { Hash.new }
8
+ inherited_attribute(:subcommand, :subcommands, map: true) { Hash.new }
9
+
10
+ # Declares a command for this interface
11
+ def command(name, *info)
12
+ arguments = if info.last.kind_of?(Hash) then info.pop
13
+ else Hash.new
14
+ end
15
+
16
+ arguments = arguments.map_key do |name, _|
17
+ name.to_sym
18
+ end
19
+ arguments = arguments.map_value do |name, description|
20
+ CommandArgument.new(name.to_sym, Array(description))
21
+ end
22
+ commands[name.to_sym] = Command.new(name.to_sym, info, arguments)
23
+ end
24
+
25
+ # Adds another interface object a subcommand of this command
26
+ # interface
27
+ #
28
+ # @param [String] name the subcommand name. The commands will be
29
+ # available as name.command_name
30
+ # @param [Model<CommandInterface>] interface the command interface model
31
+ def subcommand(name, interface, *description)
32
+ subcommands[name] = [interface, description]
33
+ define_method name do
34
+ subcommands[name].first
35
+ end
36
+ end
37
+ end
38
+
39
+ # @return [Roby::Application] the application
40
+ attr_reader :app
41
+ # @return [Roby::Plan] the {#app}'s plan
42
+ def plan; app.plan end
43
+ # @return [Roby::ExecutionEngine] the {#plan}'s engine
44
+ def execution_engine; plan.execution_engine end
45
+ # @return [Hash<String,CommandInterface>] the set of command subcommands
46
+ # attached to this command interface
47
+ attr_reader :subcommands
48
+
49
+ def initialize(app)
50
+ @app = app
51
+ @subcommands = Hash.new
52
+
53
+ self.class.each_subcommand do |name, (interface_model, description)|
54
+ subcommand(name, interface_model.new(app), description)
55
+ end
56
+ end
57
+
58
+ # Declare a subcommand on this interface
59
+ #
60
+ # Unless with {CommandLibrary.subcommand}, the interface must
61
+ # already be instanciated
62
+ def subcommand(name, interface, description)
63
+ subcommands[name] = [interface, description]
64
+ end
65
+
66
+ # Enumerate the subcommands available on this interface
67
+ #
68
+ # @yieldparam [String] name the subcommand name
69
+ def each_subcommand
70
+ return enum_for(__method__) if !block_given?
71
+ subcommands.each do |name, (interface, description)|
72
+ yield(name, interface, description)
73
+ end
74
+ end
75
+
76
+ InterfaceCommands = Struct.new :name, :description, :commands
77
+
78
+ # The set of commands that exist on self and on its subcommands
79
+ #
80
+ # @return [Hash<String,InterfaceCommands>] the set of commands of
81
+ # self (with key '') and of its subcommands (where the key is not
82
+ # empty)
83
+ def commands
84
+ result = Hash['' => InterfaceCommands.new('', nil, self.class.commands)]
85
+ each_subcommand do |name, interface, description|
86
+ result[name] = InterfaceCommands.new(name, description, interface.commands)
87
+ end
88
+ result
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,174 @@
1
+ module Roby
2
+ module Interface
3
+ # A wrapper on top of raw IO that uses droby marshalling to communicate
4
+ class DRobyChannel
5
+ # @return [#read_nonblock,#write] the channel that allows us to communicate to clients
6
+ attr_reader :io
7
+ # @return [Boolean] true if the local process is the client or the
8
+ # server
9
+ attr_predicate :client?
10
+ # @return [DRoby::Marshal] an object used to marshal or unmarshal
11
+ # objects to/from the connection
12
+ attr_reader :marshaller
13
+ # The maximum byte count that the channel can hold on the write side
14
+ # until it bails out
15
+ attr_reader :max_write_buffer_size
16
+
17
+ def initialize(io, client, marshaller: DRoby::Marshal.new(auto_create_plans: true), max_write_buffer_size: 25*1024**2)
18
+ @io = io
19
+ @io.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
20
+ @client = client
21
+
22
+ @incoming =
23
+ if client?
24
+ WebSocket::Frame::Incoming::Client.new(type: :binary)
25
+ else
26
+ WebSocket::Frame::Incoming::Server.new(type: :binary)
27
+ end
28
+ @marshaller = marshaller
29
+ @max_write_buffer_size = max_write_buffer_size
30
+ @read_buffer = String.new
31
+ @write_buffer = String.new
32
+ @write_thread = nil
33
+ end
34
+
35
+ def write_buffer_size
36
+ @write_buffer.size
37
+ end
38
+
39
+ def to_io
40
+ io.to_io
41
+ end
42
+
43
+ def close
44
+ io.close
45
+ end
46
+
47
+ def closed?
48
+ io.closed?
49
+ end
50
+
51
+ def eof?
52
+ io.eof?
53
+ end
54
+
55
+ def flush
56
+ io.flush
57
+ end
58
+
59
+ # Wait until there is something to read on the channel
60
+ #
61
+ # @param [Numeric,nil] timeout a timeout after which the method
62
+ # will return. Use nil for no timeout
63
+ # @return [Boolean] falsy if the timeout was reached, true
64
+ # otherwise
65
+ def read_wait(timeout: nil)
66
+ !!IO.select([io], [], [], timeout)
67
+ end
68
+
69
+ # Read one packet from {#io} and unmarshal it
70
+ #
71
+ # @return [Object,nil] returns the unmarshalled object, or nil if no
72
+ # full object can be found in the data received so far
73
+ def read_packet(timeout = 0)
74
+ @read_thread ||= Thread.current
75
+ if @read_thread != Thread.current
76
+ raise InternalError, "cross-thread access to droby channel: from #{@read_thread} to #{Thread.current}"
77
+ end
78
+
79
+ deadline = Time.now + timeout if timeout
80
+ remaining_time = timeout
81
+
82
+ if packet = @incoming.next
83
+ return unmarshal_packet(packet)
84
+ end
85
+
86
+ while true
87
+ if IO.select([io], [], [], remaining_time)
88
+ begin
89
+ if io.sysread(1024 ** 2, @read_buffer)
90
+ @incoming << @read_buffer
91
+ end
92
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN
93
+ end
94
+ end
95
+
96
+ if packet = @incoming.next
97
+ return unmarshal_packet(packet)
98
+ end
99
+
100
+ if deadline
101
+ remaining_time = deadline - Time.now
102
+ return if remaining_time < 0
103
+ end
104
+ end
105
+
106
+ rescue SystemCallError, EOFError, IOError
107
+ raise ComError, "closed communication"
108
+ end
109
+
110
+ def unmarshal_packet(packet)
111
+ unmarshalled = begin Marshal.load(packet.to_s)
112
+ rescue TypeError => e
113
+ raise ProtocolError, "failed to unmarshal received packet: #{e.message}"
114
+ end
115
+ marshaller.local_object(unmarshalled)
116
+ end
117
+
118
+ # Write one ruby object (usually an array) as a marshalled packet and
119
+ # send it to {#io}
120
+ #
121
+ # @param [Object] object the object to be sent
122
+ # @return [void]
123
+ def write_packet(object)
124
+ marshalled = Marshal.dump(marshaller.dump(object))
125
+ packet =
126
+ if client?
127
+ WebSocket::Frame::Outgoing::Client.new(data: marshalled, type: :binary)
128
+ else
129
+ WebSocket::Frame::Outgoing::Server.new(data: marshalled, type: :binary)
130
+ end
131
+
132
+ push_write_data(packet.to_s)
133
+ end
134
+
135
+ def reset_thread_guard
136
+ @write_thread = nil
137
+ @read_thread = nil
138
+ end
139
+
140
+ # Push queued data
141
+ #
142
+ # The write I/O is buffered. This method pushes data stored within
143
+ # the internal buffer and/or appends new data to it.
144
+ #
145
+ # @return [Boolean] true if there is still data left in the buffe,
146
+ # false otherwise
147
+ def push_write_data(new_bytes = nil)
148
+ @write_thread ||= Thread.current
149
+ if @write_thread != Thread.current
150
+ raise InternalError, "cross-thread access to droby channel: from #{@write_thread} to #{Thread.current}"
151
+ end
152
+
153
+ @write_buffer.concat(new_bytes) if new_bytes
154
+ written_bytes = io.syswrite(@write_buffer)
155
+
156
+ @write_buffer = @write_buffer[written_bytes..-1]
157
+ !@write_buffer.empty?
158
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN
159
+ if @write_buffer.size > max_write_buffer_size
160
+ raise ComError, "droby_channel reached an internal buffer size of #{@write_buffer.size}, which is bigger than the limit of #{max_write_buffer_size}, bailing out"
161
+ end
162
+ rescue SystemCallError, IOError, EOFError
163
+ raise ComError, "broken communication channel"
164
+ rescue RuntimeError => e
165
+ # Workaround what seems to be a Ruby bug ...
166
+ if e.message =~ /can.t modify frozen IOError/
167
+ raise ComError, "broken communication channel"
168
+ else raise
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
174
+
@@ -0,0 +1,22 @@
1
+ module Roby
2
+ module Interface
3
+ # Exception thrown when something is wrong in the client/server protocol
4
+ class ProtocolError < RuntimeError
5
+ end
6
+
7
+ # Exception thrown when connection cannot be created
8
+ class ConnectionError < RuntimeError
9
+ end
10
+
11
+ # Exception thrown when the IO channel should be considered as broken
12
+ class ComError < RuntimeError
13
+ end
14
+
15
+ # Exception thrown when attempting an operation in an unsupported state
16
+ # (such as e.g. calling an operation on an unattached {Async} object
17
+ # that requires the object to be attached
18
+ class InvalidState < RuntimeError
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,655 @@
1
+ module Roby
2
+ module Interface
3
+ # The job's planning task is ready to be executed
4
+ JOB_PLANNING_READY = :planning_ready
5
+ # The job's planning task is running
6
+ JOB_PLANNING = :planning
7
+ # The job's planning task has failed
8
+ JOB_PLANNING_FAILED = :planning_failed
9
+ # The job's main task is ready to be executed
10
+ JOB_READY = :ready
11
+ # The job is started
12
+ JOB_STARTED = :started
13
+ # The job has finished successfully
14
+ JOB_SUCCESS = :success
15
+ # The job has failed
16
+ JOB_FAILED = :failed
17
+ # The job has finished
18
+ JOB_FINISHED = :finished
19
+ # The job has been finalized (i.e. removed from plan)
20
+ JOB_FINALIZED = :finalized
21
+
22
+ # The job has been dropped, i.e. its mission status has been removed
23
+ JOB_DROPPED = :dropped
24
+
25
+ # Initial notification, when the interface starts monitoring a job
26
+ JOB_MONITORED = :monitored
27
+ # The job got replaced by a task that is not this job
28
+ JOB_LOST = :lost
29
+ # The job placeholder task got replaced, and the replacement is managed
30
+ # under the same job
31
+ JOB_REPLACED = :replaced
32
+
33
+ # Whether the given state indicates that the job's planning is finished
34
+ def self.planning_finished_state?(state)
35
+ ![JOB_PLANNING_READY, JOB_PLANNING, JOB_FINALIZED].include?(state)
36
+ end
37
+
38
+ # Tests if the given state (one of the JOB_ constants) is terminal, e.g.
39
+ # means that the job is finished
40
+ def self.terminal_state?(state)
41
+ [JOB_PLANNING_FAILED, JOB_FAILED, JOB_SUCCESS, JOB_FINISHED, JOB_FINALIZED].include?(state)
42
+ end
43
+
44
+ # Tests if the given state (one of the JOB_ constants) means that the
45
+ # job finished successfully
46
+ def self.success_state?(state)
47
+ [JOB_SUCCESS].include?(state)
48
+ end
49
+
50
+ # Tests if the given state (one of the JOB_ constants) means that the
51
+ # job finished with error
52
+ def self.error_state?(state)
53
+ [JOB_PLANNING_FAILED, JOB_FAILED].include?(state)
54
+ end
55
+
56
+ # Tests if the given state (one of the JOB_ constants) means that the
57
+ # job is still running
58
+ def self.running_state?(state)
59
+ [JOB_STARTED].include?(state)
60
+ end
61
+
62
+ # Tests if the given state (one of the JOB_ constants) means that the
63
+ # job has been finalized (removed from plan)
64
+ def self.finalized_state?(state)
65
+ [JOB_FINALIZED].include?(state)
66
+ end
67
+
68
+ # The server-side implementation of the command-based interface
69
+ #
70
+ # This exports all the services and/or APIs that are available through e.g.
71
+ # the Roby shell. It does not do any marshalling/demarshalling
72
+ #
73
+ # Most methods can be accessed outside of the Roby execution thread. Methods
74
+ # that cannot will be noted in their documentation
75
+ #
76
+ # == About job management
77
+ # One of the tasks of this class is to do job management. Jobs are the
78
+ # unit that is used to interact with a running Roby instance at a high
79
+ # level, as e.g. through a shell or a GUI. In Roby, jobs are represented
80
+ # by tasks that provide the {Job} task service and have a
81
+ # non-nil job ID. Up to two tasks can be associated with the job. The
82
+ # first is obviously the job task itself, i.e. the task that provides
83
+ # {Job}. Quite often, the job task will be a planning task
84
+ # (actually, one can see that {Actions::Task} provides
85
+ # {Job}). In this case, the planned task will be also
86
+ # associated with the job as its placeholder: while the job task
87
+ # represents the job's deployment status, the placeholder task will
88
+ # represent the job's execution status.
89
+ class Interface < CommandLibrary
90
+ # @return [#call] the blocks that listen to job notifications. They are
91
+ # added with {#on_job_notification} and removed with
92
+ # {#remove_job_listener}
93
+ attr_reader :job_listeners
94
+
95
+ # @return [#call] the blocks that listen to end-of-cycle
96
+ # notifications. They are added with {#on_cycle_end} and
97
+ # removed with {#remove_cycle_end}
98
+ attr_reader :cycle_end_listeners
99
+
100
+ # @api private
101
+ #
102
+ # @return [Set<Integer>] the set of tracked jobs
103
+ # @see tracked_job?
104
+ attr_reader :tracked_jobs
105
+ # @api private
106
+ #
107
+ # The set of pending job notifications for this cycle
108
+ attr_reader :job_notifications
109
+
110
+ # Creates an interface from an existing Roby application
111
+ #
112
+ # @param [Roby::Application] app the application
113
+ def initialize(app)
114
+ super(app)
115
+ app.plan.add_trigger Roby::Interface::Job do |task|
116
+ if task.job_id && (planned_task = task.planned_task)
117
+ monitor_job(task, planned_task, new_task: true)
118
+ end
119
+ end
120
+ execution_engine.at_cycle_end do
121
+ push_pending_job_notifications
122
+ notify_cycle_end
123
+ end
124
+
125
+ @tracked_jobs = Set.new
126
+ @job_notifications = Array.new
127
+ @job_listeners = Array.new
128
+ @job_monitoring_state = Hash.new
129
+ @cycle_end_listeners = Array.new
130
+ end
131
+
132
+ State = Struct.new :service, :monitored, :job_id, :job_name do
133
+ def monitored?
134
+ monitored
135
+ end
136
+ end
137
+
138
+ # Returns the port of the log server
139
+ #
140
+ # @return [Integer,nil] the port, or nil if there is no log server
141
+ def log_server_port
142
+ app.log_server_port
143
+ end
144
+ command :log_server_port, 'returns the port of the log server',
145
+ advanced: true
146
+
147
+ # The set of actions available on {#app}
148
+ #
149
+ # @return [Array<Roby::Actions::Models::Action>]
150
+ def actions
151
+ result = []
152
+ app.planners.each do |planner_model|
153
+ planner_model.each_registered_action do |_, act|
154
+ result << act
155
+ end
156
+ end
157
+ result
158
+ end
159
+ command :actions, 'lists a summary of the available actions'
160
+
161
+ # Starts a job
162
+ #
163
+ # @return [Integer] the job ID
164
+ def start_job(m, arguments = Hash.new)
165
+ execution_engine.execute do
166
+ task, planning_task = app.prepare_action(m, mission: true, job_id: Job.allocate_job_id, **arguments)
167
+ planning_task.job_id
168
+ end
169
+ end
170
+
171
+ # Kill a job
172
+ #
173
+ # It removes the job from the list of missions and kills the job's
174
+ # main task
175
+ #
176
+ # @param [Integer] job_id the ID of the job that should be
177
+ # terminated
178
+ # @return [Boolean] true if the job was found and terminated, and
179
+ # false otherwise
180
+ # @see drop_job
181
+ def kill_job(job_id)
182
+ if task = find_job_placeholder_by_id(job_id)
183
+ plan.unmark_mission_task(task)
184
+ task.stop! if task.running?
185
+ true
186
+ else false
187
+ end
188
+ end
189
+ command :kill_job, 'forcefully kills the given job',
190
+ job_id: 'the job ID. It is the return value of the xxx! command and can also be obtained by calling jobs'
191
+
192
+ # Drop a job
193
+ #
194
+ # It removes the job from the list of missions but does not
195
+ # explicitely kill it
196
+ #
197
+ # @param [Integer] job_id the ID of the job that should be
198
+ # terminated
199
+ # @return [Boolean] true if the job was found and terminated, and
200
+ # false otherwise
201
+ # @see kill_job
202
+ def drop_job(job_id)
203
+ return if !(task = find_job_by_id(job_id))
204
+
205
+ placeholder_task = task.planned_task
206
+ if !placeholder_task
207
+ plan.unmark_mission_task(task)
208
+ return true
209
+ end
210
+
211
+ placeholder_task.remove_planning_task(task)
212
+ if job_ids_of_task(placeholder_task).empty?
213
+ plan.unmark_mission_task(placeholder_task)
214
+ true
215
+ else false
216
+ end
217
+ end
218
+ command :drop_job, "remove this job from the list of jobs, this does not necessarily kill the job's main task",
219
+ job_id: 'the job ID. It is the return value of the xxx! command and can also be obtained by calling jobs'
220
+
221
+ # Enumerates the job listeners currently registered through
222
+ # {#on_job_notification}
223
+ #
224
+ # @yieldparam [#call] the job listener object
225
+ def each_job_listener(&block)
226
+ job_listeners.each(&block)
227
+ end
228
+
229
+ # Dispatch the given job-related notification to all listeners
230
+ #
231
+ # Listeners are registered with {#on_job_notification}
232
+ def job_notify(kind, job_id, job_name, *args)
233
+ job_notifications << [kind, job_id, job_name, args]
234
+ end
235
+
236
+ # @api private
237
+ #
238
+ # Called in at_cycle_end to push job notifications
239
+ def push_pending_job_notifications
240
+ final_tracked_jobs = tracked_jobs.dup
241
+
242
+ # Re-track jobs for which we have a recapture event
243
+ job_notifications.each do |event, job_id, *|
244
+ if event == JOB_MONITORED
245
+ tracked_jobs << job_id
246
+ final_tracked_jobs << job_id
247
+ elsif event == JOB_DROPPED || event == JOB_LOST || event == JOB_FINALIZED
248
+ final_tracked_jobs.delete(job_id)
249
+ end
250
+ end
251
+
252
+ job_notifications = self.job_notifications.find_all do |event, job_id, *|
253
+ if event == JOB_DROPPED
254
+ !final_tracked_jobs.include?(job_id)
255
+ else
256
+ tracked_jobs.include?(job_id)
257
+ end
258
+ end
259
+ self.job_notifications.clear
260
+
261
+ each_job_listener do |listener|
262
+ job_notifications.each do |kind, job_id, job_name, args|
263
+ listener.call(kind, job_id, job_name, *args)
264
+ end
265
+ end
266
+
267
+ @tracked_jobs = final_tracked_jobs
268
+ end
269
+
270
+ # (see Application#on_ui_event)
271
+ def on_ui_event(&block)
272
+ app.on_ui_event(&block)
273
+ end
274
+
275
+ # (see Application#remove_ui_event_listener)
276
+ def remove_ui_event_listener(block)
277
+ app.remove_ui_event_listener(block)
278
+ end
279
+
280
+ # (see Application#on_notification)
281
+ def on_notification(&block)
282
+ app.on_notification(&block)
283
+ end
284
+
285
+ # (see Application#remove_notification_listener)
286
+ def remove_notification_listener(listener)
287
+ app.remove_notification_listener(listener)
288
+ end
289
+
290
+ # Registers a block to be called when a job changes state
291
+ #
292
+ # All callbacks will be called with at minimum
293
+ #
294
+ # @overload on_job_notification
295
+ # @yieldparam kind one of the JOB_* constants
296
+ # @yieldparam [Integer] job_id the job ID (unique)
297
+ # @yieldparam [String] job_name the job name (non-unique)
298
+ #
299
+ # Generic interface. Some of the notifications, detailed below,
300
+ # have additional parameters (after the job_name argument)
301
+ #
302
+ # @overload on_job_notification
303
+ # @yieldparam JOB_MONITORED
304
+ # @yieldparam [Integer] job_id the job ID (unique)
305
+ # @yieldparam [String] job_name the job name (non-unique)
306
+ # @yieldparam [Task] task the job's placeholder task
307
+ # @yieldparam [Task] job_task the job task
308
+ #
309
+ # Interface for JOB_MONITORED notifications, called when the job
310
+ # task is initially detected
311
+ #
312
+ # @overload on_job_notification
313
+ # @yieldparam JOB_REPLACED or JOB_LOST
314
+ # @yieldparam [Integer] job_id the job ID (unique)
315
+ # @yieldparam [String] job_name the job name (non-unique)
316
+ # @yieldparam [Task] task the new task this job is now tracking
317
+ #
318
+ # Interface for JOB_REPLACED and JOB_LOST notifications
319
+ #
320
+ # @return [Object] the listener ID that can be given to
321
+ # {#remove_job_listener}
322
+ def on_job_notification(&block)
323
+ job_listeners << block
324
+ block
325
+ end
326
+
327
+ # Remove a job listener added with {#on_job_notification}
328
+ #
329
+ # @param [Object] listener the listener ID returned by
330
+ # {#on_job_notification}
331
+ def remove_job_listener(listener)
332
+ job_listeners.delete(listener)
333
+ end
334
+
335
+ # Returns all the job IDs of this task
336
+ #
337
+ # @param [Roby::Task] task the job task itself, or its placeholder
338
+ # task
339
+ # @return [Array<Integer>] the task's job IDs. May be empty if
340
+ # the task is not a job task, or if its job ID is not set
341
+ def job_ids_of_task(task)
342
+ if task.fullfills?(Job)
343
+ [task.job_id]
344
+ else
345
+ task.each_planning_task.map do |planning_task|
346
+ if planning_task.fullfills?(Job)
347
+ planning_task.job_id
348
+ end
349
+ end.compact
350
+ end
351
+ end
352
+
353
+ # Returns the job ID of a task, where the task can either be a
354
+ # placeholder for the job or the job task itself
355
+ #
356
+ # @return [Integer,nil] the task's job ID or nil if (1) the task is
357
+ # not a job task or (2) its job ID is not set
358
+ def job_id_of_task(task)
359
+ job_ids_of_task(task).first
360
+ end
361
+
362
+ # Monitor the given task as a job
363
+ #
364
+ # It must be called within the Roby execution thread
365
+ def monitor_job(planning_task, task, new_task: false)
366
+ # NOTE: this method MUST queue job notifications
367
+ # UNCONDITIONALLY. Job tracking is done on a per-cycle basis (in
368
+ # at_cycle_end) by {#push_pending_job_notifications}
369
+
370
+ job_id = planning_task.job_id
371
+ job_name = planning_task.job_name
372
+
373
+ # This happens when a placeholder/planning pair is replaced by
374
+ # another, but the job ID is inherited. We do this when e.g.
375
+ # running an action that returns another planning pair
376
+ if (state = @job_monitoring_state[job_id])
377
+ track_planning_state(
378
+ state.job_id, state.job_name, state.service, planning_task)
379
+ return
380
+ end
381
+
382
+ service = PlanService.new(task)
383
+ @job_monitoring_state[job_id] =
384
+ State.new(service, false, job_id, job_name)
385
+ service.when_finalized do
386
+ @job_monitoring_state.delete(job_id)
387
+ end
388
+
389
+ service.on_plan_status_change(initial: true) do |status|
390
+ state = @job_monitoring_state[job_id]
391
+ if !state.monitored? && (status == :mission)
392
+ job_notify(JOB_MONITORED, job_id, job_name, service.task,
393
+ service.task.planning_task)
394
+ job_notify(job_state(service.task), job_id, job_name)
395
+ state.monitored = true
396
+ elsif state.monitored? && (status != :mission)
397
+ job_notify(JOB_DROPPED, job_id, job_name)
398
+ state.monitored = false
399
+ end
400
+ end
401
+
402
+ track_planning_state(job_id, job_name, service, planning_task)
403
+
404
+ service.on_replacement do |_current, new|
405
+ if plan.mission_task?(new) && job_ids_of_task(new).include?(job_id)
406
+ job_notify(JOB_REPLACED, job_id, job_name, new)
407
+ job_notify(job_state(new), job_id, job_name)
408
+ else
409
+ job_notify(JOB_LOST, job_id, job_name, new)
410
+ end
411
+ end
412
+ service.on(:start) do |ev|
413
+ job_notify(JOB_STARTED, job_id, job_name)
414
+ end
415
+ service.on(:success) do |ev|
416
+ job_notify(JOB_SUCCESS, job_id, job_name)
417
+ end
418
+ service.on(:failed) do |ev|
419
+ job_notify(JOB_FAILED, job_id, job_name)
420
+ end
421
+ service.when_finalized do
422
+ job_notify(JOB_FINALIZED, job_id, job_name)
423
+ end
424
+ end
425
+
426
+ private def track_planning_state(job_id, job_name, service, planning_task)
427
+ planning_task.start_event.on do |ev|
428
+ job_task = planning_task.planned_task
429
+ if job_task == service.task
430
+ job_notify(JOB_PLANNING, job_id, job_name)
431
+ end
432
+ end
433
+ planning_task.success_event.on do |ev|
434
+ job_task = planning_task.planned_task
435
+ if job_task == service.task
436
+ if job_task.pending? || job_task.starting?
437
+ job_notify(JOB_READY, job_id, job_name)
438
+ end
439
+ end
440
+ end
441
+ planning_task.stop_event.on do |ev|
442
+ job_task = planning_task.planned_task
443
+ if job_task == service.task && !ev.task.success?
444
+ job_notify(JOB_PLANNING_FAILED, job_id, job_name)
445
+ end
446
+ end
447
+
448
+ PlanService.new(planning_task).when_finalized do
449
+ job_task = planning_task.planned_task
450
+ if job_task == service.task
451
+ job_notify(JOB_FINALIZED, job_id, job_name)
452
+ end
453
+ end
454
+ end
455
+
456
+ def job_state(task)
457
+ if !task.plan
458
+ return JOB_FINALIZED
459
+ elsif !plan.mission_task?(task)
460
+ return JOB_DROPPED
461
+ elsif task.success_event.emitted?
462
+ return JOB_SUCCESS
463
+ elsif task.failed_event.emitted?
464
+ return JOB_FAILED
465
+ elsif task.stop_event.emitted?
466
+ return JOB_FINISHED
467
+ elsif task.running?
468
+ return JOB_STARTED
469
+ elsif task.pending?
470
+ if planner = task.planning_task
471
+ if planner.success?
472
+ return JOB_READY
473
+ elsif planner.stop?
474
+ return JOB_PLANNING_FAILED
475
+ elsif planner.running?
476
+ return JOB_PLANNING
477
+ else
478
+ return JOB_PLANNING_READY
479
+ end
480
+ else return JOB_READY
481
+ end
482
+ end
483
+ end
484
+
485
+ # The jobs currently running on {#app}'s plan
486
+ #
487
+ # @return [Hash<Integer,(Symbol,Roby::Task,Roby::Task)>] the mapping
488
+ # from job ID to the job's state (as returned by {#job_state}), the
489
+ # placeholder job task and the job task itself
490
+ def jobs
491
+ result = Hash.new
492
+ execution_engine.execute do
493
+ planning_tasks = plan.find_tasks(Job).to_a
494
+ planning_tasks.each do |job_task|
495
+ job_id = job_task.job_id
496
+ next if !job_id
497
+ placeholder_job_task = job_task.planned_task || job_task
498
+ result[job_id] = [job_state(placeholder_job_task), placeholder_job_task, job_task]
499
+ end
500
+ end
501
+ result
502
+ end
503
+ command :jobs, 'returns the list of non-finished jobs'
504
+
505
+ def find_job_info_by_id(id)
506
+ execution_engine.execute do
507
+ if planning_task = plan.find_tasks(Job).with_arguments(job_id: id).to_a.first
508
+ task = planning_task.planned_task || planning_task
509
+ return job_state(task), task, planning_task
510
+ end
511
+ end
512
+ end
513
+
514
+ # Finds a job task by its ID
515
+ #
516
+ # @param [Integer] id
517
+ # @return [Roby::Task,nil]
518
+ def find_job_by_id(id)
519
+ execution_engine.execute do
520
+ return plan.find_tasks(Job).with_arguments(job_id: id).to_a.first
521
+ end
522
+ end
523
+
524
+ # Finds the task that represents the given job ID
525
+ #
526
+ # It can be different than the job task when e.g. the job task is a
527
+ # planning task
528
+ def find_job_placeholder_by_id(id)
529
+ if task = find_job_by_id(id)
530
+ return task.planned_task || task
531
+ end
532
+ end
533
+
534
+ # Reload all models from this Roby application
535
+ #
536
+ # Do NOT do this while the robot does critical things
537
+ def reload_models
538
+ execution_engine.execute do
539
+ app.reload_models
540
+ end
541
+ nil
542
+ end
543
+
544
+ # @deprecated use {#reload_actions} instead
545
+ def reload_planners
546
+ reload_actions
547
+ end
548
+
549
+ # Reload the actions defined under the actions/ subfolder
550
+ def reload_actions
551
+ execution_engine.execute do
552
+ app.reload_actions
553
+ end
554
+ actions
555
+ end
556
+ command :reload_actions, 'reloads the files in models/actions/'
557
+
558
+ # Notification about plan exceptions
559
+ #
560
+ # @yieldparam [Symbol] kind one of {ExecutionEngine::EXCEPTION_NONFATAL},
561
+ # {ExecutionEngine::EXCEPTION_FATAL} or {ExecutionEngine::EXCEPTION_HANDLED}
562
+ # @yieldparam [Roby::ExecutionException] error the exception
563
+ # @yieldparam [Array<Roby::Task>] tasks the tasks that are involved in this exception
564
+ # @yieldparam [Set<Integer>] job_ids the job ID of the involved jobs
565
+ #
566
+ # @see ExecutionEngine#on_exception
567
+ def on_exception(&block)
568
+ execution_engine.execute do
569
+ execution_engine.on_exception(on_error: :raise) do |kind, exception, tasks|
570
+ involved_job_ids = tasks.flat_map do |t|
571
+ job_ids_of_task(t) if t.plan
572
+ end.compact.to_set
573
+ block.call(kind, exception, tasks, involved_job_ids)
574
+ end
575
+ end
576
+ end
577
+
578
+ # @see ExecutionEngine#remove_exception_listener
579
+ def remove_exception_listener(listener)
580
+ execution_engine.execute do
581
+ execution_engine.remove_exception_listener(listener)
582
+ end
583
+ end
584
+
585
+ # Add a handler called at each end of cycle
586
+ #
587
+ # Interface-related objects that need to be notified must use this
588
+ # method instead of using {ExecutionEngine#at_cycle_end} on
589
+ # {#execution_engine}, because the listener is guaranteed to be ordered
590
+ # properly w.r.t. {#push_pending_job_notifications}
591
+ #
592
+ # @param [#call] block the listener
593
+ # @yieldparam [ExecutionEngine] the underlying execution execution_engine
594
+ # @return [Object] and ID that can be passed to {#remove_cycle_end}
595
+ def on_cycle_end(&block)
596
+ execution_engine.execute do
597
+ cycle_end_listeners << block
598
+ block
599
+ end
600
+ end
601
+
602
+ # @api private
603
+ #
604
+ # Notify the end-of-cycle to the listeners registered with
605
+ # {#on_cycle_end}
606
+ def notify_cycle_end
607
+ cycle_end_listeners.each do |listener|
608
+ listener.call
609
+ end
610
+ end
611
+
612
+ # Remove a handler that has been added to {#on_cycle_end}
613
+ def remove_cycle_end(listener)
614
+ cycle_end_listeners.delete(listener)
615
+ end
616
+
617
+ # Requests for the Roby application to quit
618
+ def quit
619
+ execution_engine.quit
620
+ end
621
+ command :quit, 'requests that the Roby application quits'
622
+
623
+ # Requests for the Roby application to quit
624
+ def restart
625
+ app.restart
626
+ end
627
+ command :restart, "restart this app's process"
628
+
629
+ # This is implemented on ShellClient directly
630
+ command 'describe', 'gives details about the given action',
631
+ action: 'the action itself'
632
+
633
+ # This is implemented on Server directly
634
+ command 'enable_notifications', 'enables the forwarding of notifications'
635
+ command 'disable_notifications', 'disables the forwarding of notifications'
636
+
637
+ # Enable or disable backtrace filtering
638
+ def enable_backtrace_filtering(enable: true)
639
+ app.filter_backtraces = enable
640
+ end
641
+ command :enable_backtrace_filtering, 'enable or disable backtrace filtering',
642
+ enable: 'true to enable, false to disable',
643
+ advanced: true
644
+
645
+ # Returns the app's log directory
646
+ def log_dir
647
+ app.log_dir
648
+ end
649
+ command :log_dir, "the app's log directory",
650
+ advanced: true
651
+ end
652
+ end
653
+ end
654
+
655
+