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,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
+