dtk-client 0.9.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (310) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/Gemfile +1 -3
  4. data/README.md +2 -121
  5. data/Rakefile +44 -0
  6. data/bin/dtk +10 -88
  7. data/dtk-client.gemspec +21 -44
  8. data/examples/simple/dtk.module.yaml +32 -0
  9. data/{lib/git-logs/git.log → examples/simple/test/README.md} +0 -0
  10. data/examples/spark/dtk.module.yaml +120 -0
  11. data/examples/with_repo_content/deploy/puppet/manifests/hostname.pp +54 -0
  12. data/examples/with_repo_content/dtk.module.yaml +49 -0
  13. data/examples/with_repo_content/test/README.txt +0 -0
  14. data/features/dtk.feature +8 -0
  15. data/features/step_definitions/dtk_steps.rb +6 -0
  16. data/features/support/env.rb +15 -0
  17. data/lib/cli/command/mixin.rb +101 -0
  18. data/lib/cli/command/module/clone.rb +42 -0
  19. data/lib/cli/command/module/install.rb +52 -0
  20. data/lib/cli/command/module/list.rb +31 -0
  21. data/lib/cli/command/module/list_assemblies.rb +39 -0
  22. data/lib/cli/command/module/push.rb +34 -0
  23. data/lib/cli/command/module/uninstall.rb +46 -0
  24. data/lib/cli/command/module.rb +33 -0
  25. data/lib/cli/command/options.rb +33 -0
  26. data/lib/cli/command/service/cancel_task.rb +33 -0
  27. data/lib/cli/command/service/converge.rb +37 -0
  28. data/lib/{parser/adapters/thor/common_option_defs.rb → cli/command/service/create_workspace.rb} +13 -17
  29. data/lib/cli/command/service/destroy.rb +47 -0
  30. data/lib/cli/command/service/edit.rb +47 -0
  31. data/lib/cli/command/service/exec.rb +42 -0
  32. data/lib/cli/command/service/exec_sync.rb +53 -0
  33. data/lib/cli/command/service/list.rb +30 -0
  34. data/lib/cli/command/service/list_actions.rb +39 -0
  35. data/lib/cli/command/service/list_attributes.rb +44 -0
  36. data/lib/cli/command/service/list_component_links.rb +33 -0
  37. data/lib/cli/command/service/list_components.rb +39 -0
  38. data/lib/cli/command/service/list_dependent_modules.rb +33 -0
  39. data/lib/cli/command/service/list_nodes.rb +33 -0
  40. data/lib/cli/command/service/list_violations.rb +33 -0
  41. data/lib/cli/command/service/pull.rb +32 -0
  42. data/lib/cli/command/service/push.rb +37 -0
  43. data/lib/{shell/parse_monkey_patch.rb → cli/command/service/set_default_target.rb} +9 -17
  44. data/lib/cli/command/service/set_required_attributes.rb +32 -0
  45. data/lib/cli/command/service/ssh.rb +42 -0
  46. data/lib/cli/command/service/stage.rb +55 -0
  47. data/lib/cli/command/service/start.rb +33 -0
  48. data/lib/{shell/context_aux.rb → cli/command/service/stop.rb} +10 -23
  49. data/lib/cli/command/service/task_status.rb +39 -0
  50. data/lib/cli/command/service.rb +55 -0
  51. data/lib/{commands.rb → cli/command/subcommand.rb} +22 -25
  52. data/lib/{bundler_monkey_patch.rb → cli/command/token/arg.rb} +6 -6
  53. data/lib/cli/command/token/class_mixin.rb +96 -0
  54. data/lib/cli/command/token/flag.rb +42 -0
  55. data/lib/{execute/command/rest_call.rb → cli/command/token/mixin.rb} +23 -14
  56. data/lib/cli/command/token/switch.rb +35 -0
  57. data/lib/cli/command/token.rb +76 -0
  58. data/lib/cli/command.rb +46 -0
  59. data/lib/cli/context/attributes.rb +50 -0
  60. data/lib/cli/context/type/module.rb +34 -0
  61. data/lib/{commands/thor/state_change.rb → cli/context/type/service.rb} +11 -5
  62. data/lib/cli/context/type/top.rb +32 -0
  63. data/lib/cli/context/type.rb +42 -0
  64. data/lib/cli/context.rb +174 -0
  65. data/lib/cli/directory_parser/file_system.rb +105 -0
  66. data/lib/{execute/command.rb → cli/directory_parser.rb} +14 -17
  67. data/lib/{execute.rb → cli/file_obj.rb} +13 -9
  68. data/lib/cli/processor/plugin/gli.rb +70 -0
  69. data/lib/cli/processor.rb +60 -0
  70. data/lib/cli/runner/dtkn_access.rb +75 -0
  71. data/lib/cli/runner.rb +58 -0
  72. data/lib/cli/version.rb +8 -0
  73. data/lib/{config → client/config}/cacert.pem +0 -0
  74. data/lib/client/config/default.conf +20 -0
  75. data/lib/client/config.rb +106 -0
  76. data/lib/client/configurator.rb +182 -0
  77. data/lib/client/conn.rb +197 -0
  78. data/lib/client/content_generator.rb +127 -0
  79. data/lib/client/error/subclasses.rb +105 -0
  80. data/lib/client/error.rb +98 -0
  81. data/lib/client/git_repo/adapter/git_gem/error_handler.rb +70 -0
  82. data/lib/client/git_repo/adapter/git_gem.rb +179 -0
  83. data/lib/client/git_repo.rb +122 -0
  84. data/lib/client/logger.rb +136 -0
  85. data/lib/client/operation/account.rb +66 -0
  86. data/lib/client/operation/client_module_dir/git_repo.rb +286 -0
  87. data/lib/client/operation/client_module_dir.rb +138 -0
  88. data/lib/client/operation/module/clone_module.rb +52 -0
  89. data/lib/client/operation/module/install/common_module.rb +58 -0
  90. data/lib/client/operation/module/install/external_module.rb +122 -0
  91. data/lib/client/operation/module/install.rb +91 -0
  92. data/lib/client/operation/module/install_from_catalog.rb +76 -0
  93. data/lib/client/operation/module/list.rb +34 -0
  94. data/lib/client/operation/module/list_assemblies.rb +35 -0
  95. data/lib/client/operation/module/push.rb +62 -0
  96. data/lib/client/operation/module/uninstall.rb +44 -0
  97. data/lib/client/operation/module.rb +58 -0
  98. data/lib/{commands/common/thor/reparse.rb → client/operation/module_service_common.rb} +27 -16
  99. data/lib/client/operation/service/cancel_task.rb +29 -0
  100. data/lib/client/operation/service/commit_and_push.rb +128 -0
  101. data/lib/client/operation/service/converge.rb +50 -0
  102. data/lib/{util/common_util.rb → client/operation/service/create_workspace.rb} +13 -13
  103. data/lib/client/operation/service/destroy.rb +42 -0
  104. data/lib/client/operation/service/edit.rb +54 -0
  105. data/lib/client/operation/service/exec.rb +73 -0
  106. data/lib/client/operation/service/list.rb +32 -0
  107. data/lib/client/operation/service/list_actions.rb +34 -0
  108. data/lib/{commands/thor/dependency.rb → client/operation/service/list_attributes.rb} +16 -12
  109. data/lib/client/operation/service/list_component_links.rb +29 -0
  110. data/lib/{commands/common/thor/pull_clone_changes.rb → client/operation/service/list_components.rb} +13 -7
  111. data/lib/client/operation/service/list_dependent_modules.rb +29 -0
  112. data/lib/client/operation/service/list_nodes.rb +29 -0
  113. data/lib/{commands/thor/project.rb → client/operation/service/list_violations.rb} +8 -13
  114. data/lib/client/operation/service/pull.rb +37 -0
  115. data/lib/client/operation/service/set_default_target.rb +31 -0
  116. data/lib/client/operation/service/set_required_attributes.rb +41 -0
  117. data/lib/client/operation/service/ssh.rb +118 -0
  118. data/lib/client/operation/service/stage.rb +54 -0
  119. data/lib/client/operation/service/start.rb +29 -0
  120. data/lib/client/operation/service/stop.rb +30 -0
  121. data/lib/{task_status → client/operation/service/task_status}/refresh_mode.rb +15 -25
  122. data/lib/{task_status → client/operation/service/task_status}/snapshot_mode.rb +4 -5
  123. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/format.rb +1 -1
  124. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/result/action.rb +1 -1
  125. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/result/components.rb +1 -1
  126. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/result/node_level.rb +1 -1
  127. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/result.rb +4 -4
  128. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/steps/action.rb +1 -1
  129. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/steps/components.rb +1 -1
  130. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/steps/node_level.rb +1 -1
  131. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/steps.rb +4 -4
  132. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task.rb +3 -3
  133. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/no_results.rb +1 -1
  134. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/render.rb +1 -1
  135. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/stage/render.rb +1 -1
  136. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/stage.rb +3 -3
  137. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/task_end.rb +1 -1
  138. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/task_start.rb +1 -1
  139. data/lib/{task_status → client/operation/service/task_status}/stream_mode/element.rb +13 -13
  140. data/lib/{task_status → client/operation/service/task_status}/stream_mode.rb +5 -9
  141. data/lib/client/operation/service/task_status.rb +77 -0
  142. data/lib/client/operation/service.rb +54 -0
  143. data/lib/client/operation.rb +67 -0
  144. data/lib/client/operation_args.rb +40 -0
  145. data/lib/{execute/execute_context/result_store.rb → client/render/view/simple.rb} +15 -14
  146. data/lib/client/render/view/table/processor.rb +248 -0
  147. data/lib/client/render/view/table.rb +75 -0
  148. data/lib/client/render.rb +113 -0
  149. data/lib/client/response/error_handler.rb +97 -0
  150. data/lib/client/response/render_helper.rb +78 -0
  151. data/lib/client/response/subclasses.rb +62 -0
  152. data/lib/client/response.rb +83 -0
  153. data/lib/client/session.rb +62 -0
  154. data/lib/client/util/auxiliary.rb +34 -0
  155. data/lib/client/util/console.rb +81 -0
  156. data/lib/client/util/disk_cacher.rb +66 -0
  157. data/lib/client/util/dtk_path.rb +28 -0
  158. data/lib/{search_hash.rb → client/util/hash_with_optional_keys.rb} +29 -21
  159. data/lib/client/util/interactive_wizard.rb +84 -0
  160. data/lib/client/util/module_ref.rb +92 -0
  161. data/lib/client/util/os_util/print.rb +121 -0
  162. data/lib/client/util/os_util.rb +122 -0
  163. data/lib/{commands/thor/utils.rb → client/util/post_body.rb} +1 -1
  164. data/lib/{execute/error_usage.rb → client/util/query_string_hash.rb} +2 -2
  165. data/lib/client/util/remote_dependency.rb +67 -0
  166. data/lib/client/util/ssh_util.rb +89 -0
  167. data/lib/client/util/validation.rb +28 -0
  168. data/lib/client/util.rb +18 -0
  169. data/lib/{util/permission_util.rb → dtk_cli.rb} +10 -9
  170. data/lib/dtk_client.rb +18 -14
  171. data/test/default_test.rb +14 -0
  172. data/test/test_helper.rb +9 -0
  173. metadata +196 -307
  174. data/Gemfile_dev +0 -13
  175. data/bin/dtk-execute +0 -32
  176. data/bin/dtk-shell +0 -31
  177. data/lib/auxiliary.rb +0 -61
  178. data/lib/client.rb +0 -58
  179. data/lib/command_helper.rb +0 -33
  180. data/lib/command_helpers/git_repo/merge.rb +0 -153
  181. data/lib/command_helpers/git_repo.rb +0 -589
  182. data/lib/command_helpers/jenkins_client/config_xml.rb +0 -288
  183. data/lib/command_helpers/jenkins_client.rb +0 -106
  184. data/lib/command_helpers/service_importer.rb +0 -251
  185. data/lib/command_helpers/service_link.rb +0 -33
  186. data/lib/command_helpers/test_module_creator.rb +0 -69
  187. data/lib/command_helpers/test_module_templates/dtk.model.yaml.eruby +0 -10
  188. data/lib/command_helpers/test_module_templates/spec_helper.rb.eruby +0 -10
  189. data/lib/command_helpers/test_module_templates/temp_component_spec.rb.eruby +0 -5
  190. data/lib/commands/common/thor/access_control.rb +0 -133
  191. data/lib/commands/common/thor/action_result_handler.rb +0 -74
  192. data/lib/commands/common/thor/assembly_template.rb +0 -92
  193. data/lib/commands/common/thor/assembly_workspace.rb +0 -1638
  194. data/lib/commands/common/thor/base_command_helper.rb +0 -59
  195. data/lib/commands/common/thor/clone.rb +0 -82
  196. data/lib/commands/common/thor/common.rb +0 -88
  197. data/lib/commands/common/thor/common_base.rb +0 -49
  198. data/lib/commands/common/thor/create_target.rb +0 -70
  199. data/lib/commands/common/thor/edit.rb +0 -255
  200. data/lib/commands/common/thor/inventory_parser.rb +0 -98
  201. data/lib/commands/common/thor/list_diffs.rb +0 -128
  202. data/lib/commands/common/thor/module/import.rb +0 -215
  203. data/lib/commands/common/thor/module.rb +0 -1011
  204. data/lib/commands/common/thor/node.rb +0 -53
  205. data/lib/commands/common/thor/poller.rb +0 -65
  206. data/lib/commands/common/thor/pull_from_remote.rb +0 -152
  207. data/lib/commands/common/thor/puppet_forge.rb +0 -72
  208. data/lib/commands/common/thor/purge_clone.rb +0 -101
  209. data/lib/commands/common/thor/push_clone_changes.rb +0 -162
  210. data/lib/commands/common/thor/push_to_remote.rb +0 -94
  211. data/lib/commands/common/thor/remotes.rb +0 -71
  212. data/lib/commands/common/thor/set_required_attributes.rb +0 -46
  213. data/lib/commands/thor/account.rb +0 -239
  214. data/lib/commands/thor/assembly.rb +0 -361
  215. data/lib/commands/thor/attribute.rb +0 -79
  216. data/lib/commands/thor/component.rb +0 -70
  217. data/lib/commands/thor/component_module.rb +0 -501
  218. data/lib/commands/thor/component_template.rb +0 -174
  219. data/lib/commands/thor/developer.rb +0 -144
  220. data/lib/commands/thor/dtk.rb +0 -152
  221. data/lib/commands/thor/library.rb +0 -125
  222. data/lib/commands/thor/node.rb +0 -504
  223. data/lib/commands/thor/node_group.rb +0 -203
  224. data/lib/commands/thor/node_template.rb +0 -94
  225. data/lib/commands/thor/provider.rb +0 -233
  226. data/lib/commands/thor/remotes.rb +0 -49
  227. data/lib/commands/thor/service.rb +0 -932
  228. data/lib/commands/thor/service_module.rb +0 -900
  229. data/lib/commands/thor/target.rb +0 -250
  230. data/lib/commands/thor/task.rb +0 -116
  231. data/lib/commands/thor/test_module.rb +0 -310
  232. data/lib/commands/thor/workspace.rb +0 -698
  233. data/lib/config/client.conf.header +0 -20
  234. data/lib/config/configuration.rb +0 -99
  235. data/lib/config/default.conf +0 -16
  236. data/lib/config/disk_cacher.rb +0 -80
  237. data/lib/configurator.rb +0 -176
  238. data/lib/context_router.rb +0 -44
  239. data/lib/core.rb +0 -489
  240. data/lib/domain/git_adapter.rb +0 -412
  241. data/lib/domain/git_error_handler.rb +0 -64
  242. data/lib/domain/response/error_handler.rb +0 -86
  243. data/lib/domain/response.rb +0 -285
  244. data/lib/dtk-client/version.rb +0 -20
  245. data/lib/dtk_constants.rb +0 -40
  246. data/lib/dtk_error.rb +0 -114
  247. data/lib/dtk_logger.rb +0 -113
  248. data/lib/error.rb +0 -85
  249. data/lib/execute/cli_pure/cli_rerouter.rb +0 -102
  250. data/lib/execute/command/api_call/map.rb +0 -60
  251. data/lib/execute/command/api_call/service.rb +0 -91
  252. data/lib/execute/command/api_call/translation_term.rb +0 -119
  253. data/lib/execute/command/api_call.rb +0 -60
  254. data/lib/execute/command_processor/rest_call.rb +0 -59
  255. data/lib/execute/command_processor.rb +0 -30
  256. data/lib/execute/execute_context.rb +0 -86
  257. data/lib/execute/script/add_tenant.rb +0 -121
  258. data/lib/execute/script.rb +0 -64
  259. data/lib/parser/adapters/option_parser.rb +0 -70
  260. data/lib/parser/adapters/thor.rb +0 -555
  261. data/lib/require_first.rb +0 -104
  262. data/lib/shell/context.rb +0 -1064
  263. data/lib/shell/domain/active_context.rb +0 -186
  264. data/lib/shell/domain/context_entity.rb +0 -89
  265. data/lib/shell/domain/context_params.rb +0 -223
  266. data/lib/shell/domain/override_tasks.rb +0 -88
  267. data/lib/shell/domain/shadow_entity.rb +0 -76
  268. data/lib/shell/header_shell.rb +0 -44
  269. data/lib/shell/help_monkey_patch.rb +0 -283
  270. data/lib/shell/interactive_wizard.rb +0 -256
  271. data/lib/shell/message_queue.rb +0 -63
  272. data/lib/shell/status_monitor.rb +0 -124
  273. data/lib/shell.rb +0 -261
  274. data/lib/task_status.rb +0 -83
  275. data/lib/util/console.rb +0 -235
  276. data/lib/util/dtk_puppet.rb +0 -65
  277. data/lib/util/module_util.rb +0 -66
  278. data/lib/util/os_util.rb +0 -385
  279. data/lib/util/remote_dependency_util.rb +0 -84
  280. data/lib/util/ssh_util.rb +0 -94
  281. data/lib/view_processor/augmented_simple_list.rb +0 -44
  282. data/lib/view_processor/hash_pretty_print.rb +0 -123
  283. data/lib/view_processor/simple_list.rb +0 -156
  284. data/lib/view_processor/table_print.rb +0 -309
  285. data/lib/view_processor.rb +0 -129
  286. data/puppet/manifests/init.pp +0 -72
  287. data/puppet/manifests/params.pp +0 -16
  288. data/puppet/r8meta.puppet.yml +0 -35
  289. data/puppet/templates/bash_profile.erb +0 -2
  290. data/puppet/templates/client.conf.erb +0 -1
  291. data/puppet/templates/dtkclient.erb +0 -2
  292. data/spec/component_module_spec.rb +0 -34
  293. data/spec/dependency_spec.rb +0 -6
  294. data/spec/dtk_shell_spec.rb +0 -13
  295. data/spec/dtk_spec.rb +0 -33
  296. data/spec/lib/spec_helper.rb +0 -10
  297. data/spec/lib/spec_thor.rb +0 -108
  298. data/spec/node_template_spec.rb +0 -24
  299. data/spec/project_spec.rb +0 -6
  300. data/spec/repo_spec.rb +0 -7
  301. data/spec/response_spec.rb +0 -52
  302. data/spec/service_module_spec.rb +0 -38
  303. data/spec/service_spec.rb +0 -50
  304. data/spec/state_change_spec.rb +0 -7
  305. data/spec/table_print_spec.rb +0 -48
  306. data/spec/target_spec.rb +0 -57
  307. data/spec/task_spec.rb +0 -28
  308. data/views/assembly/augmented_simple_list.rb +0 -12
  309. data/views/assembly_template/augmented_simple_list.rb +0 -12
  310. data/views/list_task/augmented_simple_list.rb +0 -12
data/lib/shell/context.rb DELETED
@@ -1,1064 +0,0 @@
1
- #
2
- # Copyright (C) 2010-2016 dtk contributors
3
- #
4
- # This file is part of the dtk project.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
- require File.expand_path('../commands/thor/dtk', File.dirname(__FILE__))
19
- require File.expand_path('../auxiliary', File.dirname(__FILE__))
20
- require 'json'
21
-
22
- module DTK
23
- module Shell
24
-
25
- class Context
26
- include DTK::Client::Auxiliary
27
- include DTK::Client::CommandBase
28
-
29
- # client commands
30
- CLIENT_COMMANDS = ['cc','exit','clear','pushc','popc','dirs','help']
31
- # CLIENT_COMMANDS = ['cc','exit','clear','help']
32
- DEV_COMMANDS = ['restart']
33
- DTK_ROOT_PROMPT = "dtk:/>"
34
- COMMAND_HISTORY_LIMIT = 200
35
- HISTORY_LOCATION = DTK::Client::OsUtil.dtk_local_folder + "shell_history"
36
- ROOT_TASKS = DTK::Client::Dtk.task_names
37
- ALL_COMMANDS = ROOT_TASKS + DTK::Client::Dtk.additional_entities
38
- IDENTIFIERS_ONLY = ['cc','cd','pushc']
39
-
40
-
41
- SYM_LINKS = [
42
- { :alias => :workspace, :path => 'workspace/workspace' }
43
- ]
44
-
45
- # current holds context (list of commands) for active context e.g. dtk:\library>
46
- attr_accessor :current
47
- attr_accessor :active_context
48
- attr_accessor :cached_tasks
49
- attr_accessor :dirs
50
-
51
-
52
- def initialize(skip_caching=false)
53
- @cached_tasks, @dirs = DTK::Shell::CachedTasks.new, []
54
- @active_context = ActiveContext.new
55
- @previous_context = nil
56
-
57
- # member used to hold current commands loaded for current command
58
- @context_commands = []
59
- @conn = DTK::Client::Session.get_connection()
60
-
61
- # if connection parameters are not set up properly, print warning and exit dtk_shell
62
- exit if validate_connection(@conn)
63
-
64
- unless skip_caching
65
- @cached_tasks.store('dtk', ROOT_TASKS.sort)
66
-
67
- ALL_COMMANDS.each do |task_name|
68
- # we exclude help since there is no command class for it
69
- next if task_name.eql? "help"
70
- Context.require_command_class(task_name)
71
-
72
- get_latest_tasks(task_name)
73
- end
74
- end
75
- end
76
-
77
- def self.get_command_class(command_name)
78
- ::DTK::Client::OsUtil.get_dtk_class(command_name)
79
- end
80
-
81
- def self.require_command_class(command_name)
82
- # normalize to file_names
83
- file_name = command_name.gsub('-','_')
84
- require File.expand_path("../commands/thor/#{file_name}", File.dirname(__FILE__))
85
- end
86
-
87
- # SYM_LINKS methods is used to calculate aliases that will be used for certain entities
88
- # one of those approaches will be as such
89
- def self.check_for_sym_link(entries)
90
- # remove empty strings from array
91
- entries.reject! { |e| e.empty? }
92
-
93
- if (entries.size > 0)
94
- SYM_LINKS.each do |sym_link|
95
- if entries.first.downcase.to_sym.eql?(sym_link[:alias])
96
- entries[0] = sym_link[:path].split('/')
97
- entries.flatten!
98
- end
99
- end
100
- end
101
-
102
- entries
103
- end
104
-
105
- # take current path and see if it is aliased path
106
- def self.enchance_path_with_alias(path, context_list)
107
- SYM_LINKS.each do |sym_link|
108
- if path.downcase.include?(sym_link[:path])
109
- path = path.gsub(sym_link[:path], sym_link[:alias].to_s)
110
- end
111
- end
112
-
113
- unless context_list.empty?
114
- init_context = context_list.first.name
115
- command_clazz = Context.get_command_class(init_context)
116
- invisible_context = command_clazz.respond_to?(:invisible_context) ? command_clazz.invisible_context() : {}
117
-
118
- invisible_context.each do |ic|
119
- path = path.gsub(/\/#{ic}\//,'/')
120
- end
121
- end
122
-
123
- path
124
- end
125
-
126
- # Validates and changes context
127
- def change_context(args, cmd=[])
128
- begin
129
- # check if we are doing switch context
130
- if args.join("").match(/\A\-\Z/)
131
- revert_context()
132
- return
133
- end
134
-
135
- # remember current context
136
- @previous_context = @active_context.clone_me()
137
-
138
- # jump to root
139
- reset if args.join('').match(/^\//)
140
-
141
- # begin
142
- # hack: used just to avoid entering assembly/id/node or workspace/node context (remove when include this contexts again)
143
- first_c, warning_message = nil, nil
144
- first_c = @active_context.context_list().first.name unless @active_context.context_list().empty?
145
- tmp_active_context = @active_context.clone_me
146
- restricted = is_restricted_context(first_c, args, tmp_active_context)
147
-
148
- args = restricted[:args]
149
- warning_message = restricted[:message]
150
- node_specific = restricted[:node_specific]
151
-
152
- DTK::Client::OsUtil.print_warning(warning_message) if warning_message
153
- # end
154
-
155
- # Validate and change context
156
- @active_context, error_message = prepare_context_change(args, @active_context, node_specific, cmd, true)
157
-
158
- load_context(active_context.last_context_name)
159
-
160
- if error_message
161
- revert_context()
162
- raise DTK::Client::DtkValidationError, error_message
163
- end
164
- rescue DTK::Client::DtkValidationError => e
165
- DTK::Client::OsUtil.print(e.message, :yellow)
166
- rescue DTK::Shell::Error, Exception => e
167
- DtkLogger.instance.error_pp(e.message, e.backtrace)
168
- ensure
169
- return shell_prompt()
170
- end
171
- end
172
-
173
- # this method is used to scan and provide context to be available Readline.complete_proc
174
- def dynamic_autocomplete_context(readline_input, line_buffer=[])
175
- # special case indicator when user starts cc with '/' (go from root)
176
- goes_from_root = readline_input.start_with?('/')
177
- # Cloning existing active context, as all changes shouldn't be permanent, but temporary for autocomplete
178
- active_context_copy = @active_context.clone_me
179
- # Emptying context copy if it goes from root '/'
180
- active_context_copy.clear if goes_from_root
181
- # Invalid context is user leftover to be matched; i.e. 'cc /assembly/te' - 'te' is leftover
182
- invalid_context = ""
183
-
184
- # Validate and change context; skip step if user's input is empty or it is equal to '/'
185
- active_context_copy, error_message, invalid_context = prepare_context_change([readline_input], active_context_copy, nil, line_buffer) unless (readline_input.empty? || readline_input == "/")
186
-
187
- # using extended_context when we want to use autocomplete from other context
188
- # e.g. we are in assembly/apache context and want to create-component we will use extended context to add
189
- # component-templates to autocomplete
190
- extended_candidates, new_context, line_buffer_first = {}, nil, nil
191
- command_clazz = Context.get_command_class(active_context_copy.last_command_name)
192
-
193
- unless (line_buffer.empty? || line_buffer.strip().empty?)
194
- line_buffer = line_buffer.split(' ')
195
- line_buffer_last = line_buffer.last
196
- line_buffer_first = line_buffer.first
197
- line_buffer_first.gsub!('-','_') unless (line_buffer_first.nil? || line_buffer_first.empty?)
198
- end
199
-
200
- unless command_clazz.nil?
201
- extended_context = command_clazz.respond_to?(:extended_context) ? command_clazz.extended_context() : {}
202
-
203
- unless extended_context.empty?
204
- extended_context = extended_context[:context] || {}
205
- extended_context.select!{|k,v| line_buffer.include?(k.to_s)} if extended_context.respond_to?(:select!)
206
-
207
- if (extended_context[line_buffer_last] && !line_buffer_first.eql?(line_buffer_last))
208
- new_context = extended_context[line_buffer_last]
209
- elsif (extended_context[line_buffer[line_buffer.size-2]] && !line_buffer_first.eql?(extended_context[line_buffer[line_buffer.size-2]]))
210
- new_context = extended_context[line_buffer[line_buffer.size-2]]
211
- else
212
- new_context = extended_context[line_buffer_first.to_sym] unless line_buffer_first.nil? || line_buffer_first.empty?
213
- end
214
-
215
- unless new_context.nil?
216
- if new_context.is_a?(String)
217
- active_context_copy.push_new_context(new_context, new_context)
218
- elsif new_context.is_a?(Hash)
219
- context_candidates = load_extended_context_commands(new_context, active_context_copy)
220
- results_filter = (readline_input.match(/\/$/) && invalid_context.empty?) ? "" : readline_input.split("/").last
221
- results_filter ||= ""
222
- context_candidates = context_candidates.grep( /^#{Regexp.escape(results_filter)}/ )
223
- return context_candidates
224
- end
225
- end
226
- end
227
- end
228
-
229
- return get_ac_candidates(active_context_copy, readline_input, invalid_context, goes_from_root, line_buffer_first||{})
230
- end
231
-
232
- # TODO: this is hack used this to hide 'node' context and use just node_identifier
233
- # we should rethink the design of shell context if we are about to use different behaviors like this
234
- def self.check_invisible_context(acc, entries, is_root, line_buffer=[], args=[], current_context_clazz=nil)
235
- check = nil
236
- entries.reject! { |e| e.empty? }
237
- goes_from_root = args.first.start_with?('/')
238
-
239
- unless (line_buffer.empty? && args.empty?)
240
- command = line_buffer.empty? ? args.first : line_buffer.split(' ').first
241
- # command = line_buffer.split(' ').first
242
- current_c_name = acc.last_command_name
243
- current_context = acc.last_context
244
- clazz = DTK::Shell::Context.get_command_class(current_c_name)
245
- command_from_args = nil
246
-
247
- if args.first.include?('/')
248
- command_from_args = goes_from_root ? args.first.split('/')[1] : args.first.split('/').first
249
- clazz_from_args = DTK::Shell::Context.get_command_class(command_from_args) if command_from_args
250
- end
251
-
252
- check = (command.eql?('cd') || command.eql?('cc') || command.eql?('popc') || command.eql?('pushc') || command.eql?('delete-node'))
253
- # used when calling node commands from service or workspace context
254
- # e.g. service/service_name>node1 info will display info about nodes instead of service instance
255
- unless check
256
- if current_c_name.eql?('service') || current_c_name.eql?('workspace')
257
- context_hash_data, error_message, invalid_context = current_context_clazz.validate_value('node', command, acc)
258
- check = true if context_hash_data && !error_message
259
- end
260
- end
261
-
262
- # this delete-node is a hack because we need autocomplete when there is node with name 'node'
263
- # if (command.eql?('cd') || command.eql?('cc') || command.eql?('popc') || command.eql?('pushc') || command.eql?('delete-node'))
264
- if check
265
- if is_root
266
- if entries.size >= 3
267
- node = entries[2]
268
- if (node && clazz_from_args.respond_to?(:valid_child?) && !clazz_from_args.invisible_context_list.empty?)
269
- unless clazz_from_args.valid_children().first.to_s.include?(node)
270
- entries[2] = ["node", node]
271
- entries.flatten!
272
- end
273
- end
274
- end
275
- else
276
- double_dots_count = DTK::Shell::ContextAux.count_double_dots(entries)
277
-
278
- unless double_dots_count > 0
279
- if clazz.respond_to?(:invisible_context)
280
- if current_context.is_command?
281
- node = entries[1]
282
- if (node && clazz.respond_to?(:valid_child?))
283
- unless clazz.valid_children().first.to_s.include?(node)
284
- entries[1] = ["node", node]
285
- entries.flatten!
286
- end
287
- end
288
- elsif current_context.is_identifier?
289
- node = entries[0]
290
- if (node && clazz.respond_to?(:valid_child?))
291
- unless clazz.valid_children().first.to_s.include?(node)
292
- entries[0] = ["node", node]
293
- entries.flatten!
294
- end
295
- end
296
- end
297
- end
298
- end
299
-
300
- end
301
- end
302
-
303
- end
304
-
305
- entries
306
- end
307
-
308
-
309
- def prepare_context_change(args, active_context_copy, node_specific=nil, line_buffer=[], on_complete=false)
310
- # split original cc command
311
- entries = args.first.split(/\//)
312
-
313
- # transform alias to full path
314
- entries = Context.check_for_sym_link(entries) if root?
315
- entries = Context.check_invisible_context(active_context_copy, entries, root?, line_buffer, args, self)
316
-
317
- # if only '/' or just cc skip validation
318
- return active_context_copy if entries.empty?
319
-
320
- current_context_clazz, error_message, current_index = nil, nil, 0
321
- double_dots_count = DTK::Shell::ContextAux.count_double_dots(entries)
322
-
323
- # we remove '..' from our entries
324
- entries = entries.select { |e| !(e.empty? || DTK::Shell::ContextAux.is_double_dot?(e)) }
325
-
326
- # need this for autocomplete from service/node to service/utils
327
- is_utils = active_context_copy.last_command_name.eql?('utils')
328
-
329
- # we go back in context based on '..'
330
- active_context_copy.pop_context(double_dots_count)
331
-
332
- # if cd ../utils from service/node
333
- if active_context_copy.current_command? && active_context_copy.last_command_name.eql?('node')
334
- active_context_copy.pop_context(1)
335
- entries = Context.check_invisible_context(active_context_copy, entries, root?, line_buffer, args, self)
336
- end
337
-
338
- # need this for autocomplete from service/node to service/utils
339
- if is_utils
340
- entries = Context.check_invisible_context(active_context_copy, entries, root?, line_buffer, args, self)
341
- end
342
-
343
- # if cd .. back to node, skip node context and go to assembly/workspace context
344
- if (active_context_copy.last_context && entries)
345
- active_context_copy.pop_context(1) if (node_specific && active_context_copy.last_context.is_command? && active_context_copy.last_command_name.eql?("node") && on_complete)
346
- end
347
-
348
- # special case when using workspace context
349
- # if do cd .. from workspace/workspace identifier go directly to root not to workspace
350
- if active_context_copy.name_list.include?("workspace")
351
- count_workspaces = active_context_copy.name_list.inject(Hash.new(0)) {|h,i| h[i] += 1; h }
352
- active_context_copy.pop_context(1) if count_workspaces['workspace']==1
353
- end
354
-
355
- # we add active commands array to begining, using dup to avoid change by ref.
356
- context_name_list = active_context_copy.name_list
357
- entries = context_name_list + entries
358
-
359
- # we check the size of active commands
360
- ac_size = context_name_list.size
361
-
362
- invalid_context = ""
363
- # check each par for command / value
364
- (0..(entries.size-1)).step(2) do |i|
365
- command = entries[i]
366
- value = entries[i+1]
367
-
368
- clazz = DTK::Shell::Context.get_command_class(command)
369
- error_message, invalid_context = validate_command(clazz, current_context_clazz, command, active_context_copy)
370
-
371
- # restrict utils subcontext in service/service_name/node_group only
372
- if active_context_copy.last_context_is_shadow_entity? && active_context_copy.last_context.shadow_entity().eql?('node_group')
373
- if current_context_clazz.respond_to?(:multi_context_children)
374
- multi_context_children = current_context_clazz.multi_context_children()
375
- if command.eql?('utils') && multi_context_children.include?(command.to_sym)
376
- return active_context_copy, "'#{command}' context is not valid.", invalid_context
377
- end
378
- end
379
- end
380
-
381
- break if error_message
382
- # if we are dealing with new entries add them to active_context
383
- active_context_copy.push_new_context(command, command) if (i >= ac_size)
384
- current_context_clazz = clazz
385
-
386
- if value
387
- # context_hash_data is hash with :name, :identifier values
388
- context_hash_data, error_message, invalid_context = validate_value(command, value, active_context_copy)
389
- if error_message
390
- # hack: used just to avoid entering assembly/id/node or workspace/node context (remove when include this contexts again)
391
- if ((@active_context.last_context_name.eql?("node") || node_specific) && !@active_context.first_context_name().eql?("node") )
392
- active_context_copy.pop_context(1)
393
- end
394
- break
395
- end
396
-
397
- active_context_copy.push_new_context(context_hash_data[:name], command, context_hash_data[:identifier], context_hash_data[:shadow_entity]) if ((i+1) >= ac_size)
398
- end
399
- end
400
-
401
- return active_context_copy, error_message, invalid_context
402
- end
403
-
404
- def validate_command(clazz, current_context_clazz, command, active_context_copy=nil)
405
- error_message = nil
406
- invalid_context = ""
407
-
408
- # if command class did not found or if command ends with '-'
409
- if (clazz.nil? || command.match(/-$/))
410
- error_message = "Context for '#{command}' could not be loaded.";
411
- invalid_context = command
412
- end
413
-
414
- # check if previous context support this one as a child
415
- unless current_context_clazz.nil?
416
- # valid child method is necessery to define parent-child relet.
417
- if current_context_clazz.respond_to?(:valid_child?)
418
- root_clazz = DTK::Shell::Context.get_command_class(active_context_copy.first_command_name)
419
- all_children = root_clazz.all_children() + root_clazz.valid_children()
420
-
421
- valid_all_children = (root_clazz != current_context_clazz) ? all_children.include?(command.to_sym) : true
422
- unless (current_context_clazz.valid_child?(command) && valid_all_children)
423
-
424
- error_message = "'#{command}' context is not valid."
425
- invalid_context = command
426
-
427
- if current_context_clazz.respond_to?(:invisible_context)
428
- ic = current_context_clazz.invisible_context()
429
- ic.each do |c|
430
- if c.to_s.include?(command)
431
- return nil, ""
432
- end
433
- end
434
- end
435
- end
436
- else
437
- error_message = "'#{command}' context is not valid."
438
- invalid_context = command
439
- end
440
- end
441
-
442
- return error_message, invalid_context
443
- end
444
-
445
-
446
- # hack: used just to avoid entering assembly/id/node or workspace/node context (remove when include this contexts again)
447
- def is_restricted_context(first_c, args = [], tmp_active_context=nil)
448
- entries = args.first.split(/\//)
449
- invalid_context = ["workspace/node", "service/node"]
450
- double_dots_count = DTK::Shell::ContextAux.count_double_dots(entries)
451
- only_double_dots = entries.select{|e| !e.to_s.include?('..')}||[]
452
- back_flag = false
453
-
454
- last_from_current, message = nil, nil
455
- unless (root? || double_dots_count==0 || !only_double_dots.empty?)
456
- test_c = @previous_context
457
- test_c.pop_context(double_dots_count)
458
- last_from_current = test_c.last_context_name
459
- back_flag = true
460
- end
461
-
462
- unless args.empty?
463
- first_c ||= entries.first
464
- last_c = last_from_current||entries.last
465
-
466
- invalid_context.each do |ac|
467
- if ac.eql?("#{first_c}/#{last_c}")
468
- unless last_from_current
469
- last_1, last_2 = entries.last(2)
470
- if last_1.eql?(last_2)
471
- args = entries.join('/')
472
- return {:args => [args], :node_specific => true}
473
- end
474
- end
475
- message = "'#{last_c}' context is not valid."
476
- is_valid_id = check_for_id(first_c, last_c, tmp_active_context, args)
477
-
478
- # if ../ to node context, add one more .. to go to previous context (assembly/id or workspace)
479
- if back_flag
480
- message = nil
481
- entries << ".." if is_valid_id==false
482
- else
483
- if is_valid_id==false
484
- entries.pop
485
- else
486
- message = nil
487
- end
488
- end
489
-
490
- args = (entries.size<=1 ? entries : entries.join('/'))
491
- args = args.is_a?(Array) ? args : [args]
492
- if args.empty?
493
- raise DTK::Client::DtkValidationError, message
494
- else
495
- return {:args => args, :message => message, :node_specific => true}
496
- end
497
-
498
- end
499
- end
500
- end
501
-
502
- return {:args => args, :message => message}
503
- end
504
-
505
- def check_for_id(context, command, tmp_active_context, args)
506
- command_clazz = Context.get_command_class(context)
507
- invisible_context = command_clazz.respond_to?(:invisible_context) ? command_clazz.invisible_context.map { |e| e.to_s } : []
508
- entries = args.first.split(/\//)
509
-
510
- entries = Context.check_for_sym_link(entries) if root?
511
- unless invisible_context.empty?
512
- if root?
513
- tmp_active_context.push_new_context(entries[0], entries[0])
514
- context_hash_data, error_message, invalid_context = validate_value(entries[0], entries[1], tmp_active_context)
515
-
516
- return if error_message
517
- tmp_active_context.push_new_context(context_hash_data[:name], entries[0], context_hash_data[:identifier])
518
- context_hash_data, error_message, invalid_context = validate_value(command, command, tmp_active_context)
519
-
520
- return if error_message
521
- tmp_active_context.push_new_context(context_hash_data[:name], command, context_hash_data[:identifier])
522
- end
523
-
524
-
525
- node_ids = get_command_identifiers(invisible_context.first.to_s, tmp_active_context)
526
- node_names = node_ids ? node_ids.collect { |e| e[:name] } : []
527
- end
528
-
529
- return node_names.include?(command)
530
- end
531
-
532
-
533
-
534
- def validate_value(command, value, active_context_copy=nil)
535
- context_hash_data = nil
536
- invalid_context = ""
537
- # check value
538
- if value
539
- context_hash_data = valid_id?(command, value, nil, active_context_copy)
540
- unless context_hash_data
541
- error_message = "Identifier '#{value}' is not valid."
542
- # error_message = "Identifier '#{value}' for context '#{command}' is not valid";
543
- invalid_context = value
544
- end
545
- end
546
-
547
- return context_hash_data, error_message, invalid_context
548
- end
549
-
550
- # load context will load list of commands available for given command (passed)
551
- # to method. Context is list of command available at current tier.
552
- def load_context(command_name=nil)
553
- # when switching to tier 2 we need to use command name from tier one
554
- # e.g. cc library/public, we are caching context under library_1, library_2
555
- # so getting context for 'public' will not work and we use than library
556
- command_name = root? ? 'dtk' : @active_context.last_command_name
557
-
558
- if @active_context.last_context_is_shadow_entity?
559
- @current = ShadowEntity.resolve_tasks(@active_context.last_context)
560
- else
561
- # if there is no new context (current) we use old one
562
- @current = current_context_task_names() || @current
563
- end
564
-
565
- client_commands = CLIENT_COMMANDS
566
- client_commands.concat(DEV_COMMANDS) if DTK::Configuration.get(:development_mode)
567
-
568
- # we add client commands
569
- @current.concat(client_commands).sort!
570
-
571
- # holder for commands to be used since we do not want to remember all of them
572
- @context_commands = @current
573
-
574
- # we load thor command class identifiers for autocomplete context list
575
- command_context = get_command_identifiers(command_name)
576
-
577
- command_name_list = command_context ? command_context.collect { |e| e[:name] } : []
578
- @context_commands.concat(command_name_list) if current_command?
579
-
580
-
581
- # logic behind context loading
582
- #Readline.completer_word_break_characters=" "
583
- Readline.completion_proc = proc { |input| dynamic_autocomplete_context(input, Readline.respond_to?("line_buffer") ? Readline.line_buffer : [])}
584
- end
585
-
586
- def push_context()
587
- raise "DEV WE need to RE-IMPLEMENT this."
588
- @current_path = @active_context.full_path()
589
- @dirs.unshift(@current_path) unless @current_path.nil?
590
- end
591
-
592
- # resets context
593
- def reset
594
- @active_context.clear
595
- load_context()
596
- end
597
-
598
- def revert_context()
599
- if @previous_context
600
- # swap 2 variables
601
- @active_context, @previous_context = @previous_context, @active_context
602
- end
603
- load_context(active_context.last_context_name)
604
- end
605
-
606
- # when e.g assembly is deleted we want it to be removed from list without
607
- # exiting dtk-shell
608
- def reload_cached_tasks(command_name)
609
- # we clear @current since this will be reloaded
610
- @current = nil
611
-
612
- load_context(command_name)
613
- end
614
-
615
- # gets current path for shell
616
- def shell_prompt
617
- return root? ? DTK_ROOT_PROMPT : "dtk:#{@active_context.full_path}>"
618
- end
619
-
620
- def root_tasks
621
- return @cached_tasks['dtk']
622
- end
623
-
624
- # returns true if context is on root at the moment
625
- def root?
626
- return @active_context.empty?
627
- end
628
-
629
- def current_command?
630
- return @active_context.current_command?
631
- end
632
-
633
- def current_identifier?
634
- return @active_context.current_identifier?
635
- end
636
-
637
- def current_alt_identifier?
638
- return @active_context.current_alt_identifier?
639
- end
640
-
641
- # returns list of tasks for given command name
642
- def current_context_task_names()
643
- @cached_tasks.fetch(@active_context.get_task_cache_id(),[]).dup
644
- end
645
-
646
- # checks if method name is valid in current context
647
- def method_valid?(method_name)
648
- # validate method, see if we support given method in current tasks
649
- (current_context_task_names() + ['help']).include?(method_name)
650
- end
651
-
652
-
653
- # adds command to current list of active commands
654
- def push_to_active_context(context_name, entity_name, context_value = nil)
655
- @active_context.push_new_context(context_name, entity_name, context_value)
656
- end
657
-
658
- # remove last active command, and returns it
659
- def pop_from_active_context
660
- return @active_context.pop_context
661
- end
662
-
663
- # calls 'valid_id?' method in Thor class to validate ID/NAME
664
- def valid_id?(thor_command_name,value, override_context_params=nil, active_context_copy=nil)
665
-
666
- command_clazz = Context.get_command_class(thor_command_name)
667
- if command_clazz.list_method_supported?
668
- if override_context_params
669
- context_params = override_context_params
670
- else
671
- context_params = get_command_parameters(thor_command_name, [], active_context_copy)[2]
672
- end
673
-
674
- tmp = command_clazz.valid_id?(value, @conn, context_params)
675
- return tmp
676
- end
677
-
678
- return nil
679
- end
680
-
681
- def get_ac_candidates(active_context_copy, readline_input, invalid_context, goes_from_root, line_buffer=[])
682
- # helper indicator for case when there are more options in current context and cc command is not ended with '/'
683
- cutoff_forcely = false
684
- # input string segment used to filter results candidates
685
- results_filter = (readline_input.match(/\/$/) && invalid_context.empty?) ? "" : readline_input.split("/").last
686
- results_filter ||= ""
687
-
688
- command_clazz = Context.get_command_class(active_context_copy.last_command_name)
689
- extended_context_commands = nil
690
-
691
- unless command_clazz.nil?
692
- extended_context = command_clazz.respond_to?(:extended_context) ? command_clazz.extended_context() : {}
693
-
694
- unless extended_context.empty?
695
- extended_context = extended_context[:command]
696
- extended_context.reject!{|k,v| k.to_s!=line_buffer} if extended_context
697
- extended_context_commands = extended_context[line_buffer.to_sym] unless (line_buffer.empty? || extended_context.nil?)
698
- end
699
- end
700
-
701
- if extended_context_commands
702
- context_candidates = load_extended_context_commands(extended_context_commands, active_context_copy)
703
- else
704
- # If command does not end with '/' check if there are more than one result candidate for current context
705
- if !readline_input.empty? && !readline_input.match(/\/$/) && invalid_context.empty? && !active_context_copy.empty?
706
- context_list = active_context_copy.context_list
707
- context_name = context_list.size == 1 ? nil : context_list[context_list.size-2] # if case when on 1st level, return root candidates
708
- context_candidates = get_ac_candidates_for_context(context_name, active_context_copy)
709
- cutoff_forcely = true
710
- else
711
- # If last context is command, load all identifiers, otherwise, load next possible context command; if no contexts, load root tasks
712
- context_candidates = get_ac_candidates_for_context(active_context_copy.last_context(), active_context_copy)
713
- end
714
- end
715
-
716
- # checking if results will contain context candidates based on input string segment
717
- context_candidates = context_candidates.grep( /^#{Regexp.escape(results_filter)}/ )
718
-
719
- # Show all context tasks if active context orignal and it's copy are on same context, and are not on root,
720
- # and if readline has one split result indicating user is not going trough n-level, but possibly executing a task
721
- task_candidates = []
722
-
723
- #task_candidates = @context_commands if (active_context_copy.last_context_name() == @active_context.last_context_name() && !active_context_copy.empty?)
724
- task_candidates = @context_commands if (active_context_copy.last_context_name() == @active_context.last_context_name() && !active_context_copy.empty? && readline_input.split("/").size <= 1)
725
-
726
- # create results object filtered by user input segment (results_filter)
727
- task_candidates = task_candidates.grep( /^#{Regexp.escape(results_filter)}/ )
728
-
729
- # autocomplete candidates are both context and task candidates; remove duplicates in results
730
- results = context_candidates
731
-
732
- # if command is 'cc/cd/pushc' displat only context candidates
733
- if line_buffer.empty?
734
- results += task_candidates
735
- else
736
- is_cc = line_buffer.split(' ')
737
- results += task_candidates unless (IDENTIFIERS_ONLY.include?(is_cc.first) || extended_context_commands)
738
- end
739
-
740
- # remove duplicate context or task candidates
741
- results.uniq!
742
-
743
- # Send system beep if there are no candidates
744
- if results.empty?
745
- print "\a"
746
- return []
747
- end
748
-
749
- # default value of input user string
750
- input_context_path = readline_input
751
-
752
- # cut off last context if it is leftover (invalid_context),
753
- # or if last context is not finished with '/' and it can have more than option for current context
754
- # i.e. dtk> cc assembly - have 2 candidates: 'assembly' and 'assembly-template'
755
- if !invalid_context.empty? || cutoff_forcely
756
- start_index = goes_from_root ? 1 : 0 # if it starts with / don't take first element after split
757
- input_context_path = readline_input.split("/")[start_index.. -2].join("/")
758
- input_context_path = input_context_path + "/" unless input_context_path.empty?
759
- input_context_path = "/" + input_context_path if goes_from_root
760
- end
761
-
762
- # Augment input string with candidates to satisfy thor
763
- results = results.map { |element| (input_context_path + element) }
764
-
765
- # If there is only one candidate, and candidate is not task operation
766
- #return (results.size() == 1 && !context_candidates.empty?) ? (results.first + "/") : results
767
- return results
768
-
769
- end
770
-
771
- def get_ac_candidates_for_context(context, active_context_copy)
772
- # If last context is command, load all identifiers, otherwise, load next possible context command; if no contexts, load root tasks
773
- if context
774
- if context.is_command?
775
- command_identifiers = get_command_identifiers(context.name, active_context_copy)
776
- n_level_ac_candidates = command_identifiers ? command_identifiers.collect { |e| e[:name] } : []
777
- else
778
- command_clazz = Context.get_command_class(active_context_copy.last_command_name)
779
- root_clazz = DTK::Shell::Context.get_command_class(active_context_copy.first_command_name)
780
- valid_all_children = (root_clazz != command_clazz) ? (root_clazz.all_children() + root_clazz.valid_children()) : []
781
- n_level_ac_candidates = command_clazz.respond_to?(:valid_children) ? command_clazz.valid_children.map { |e| e.to_s } : []
782
-
783
- n_level_ac_candidates.select {|v| valid_all_children.include?(v.to_sym)} unless valid_all_children.empty?
784
- invisible_context = command_clazz.respond_to?(:invisible_context) ? command_clazz.invisible_context.map { |e| e.to_s } : []
785
-
786
- unless invisible_context.empty?
787
- node_ids = get_command_identifiers(invisible_context.first.to_s, active_context_copy)
788
- node_names = node_ids ? node_ids.collect { |e| e[:name] } : []
789
-
790
- n_level_ac_candidates.concat(node_names)
791
- end
792
-
793
- # restrict autocomple to utils subcontext in service/service_name/node_group only
794
- if active_context_copy.last_context_is_shadow_entity? && active_context_copy.last_context().shadow_entity().eql?('node_group')
795
- n_level_ac_candidates.delete('utils')
796
- end
797
-
798
- n_level_ac_candidates
799
- end
800
- else
801
- n_level_ac_candidates = ROOT_TASKS
802
- end
803
- end
804
-
805
- # get class identifiers for given thor command, returns array of identifiers
806
- def get_command_identifiers(thor_command_name, active_context_copy=nil)
807
- begin
808
- command_clazz = Context.get_command_class(thor_command_name)
809
-
810
- if command_clazz && command_clazz.list_method_supported?
811
- # take just hashed arguemnts from multi return method
812
- hashed_args = get_command_parameters(thor_command_name, [], active_context_copy)[2]
813
- return command_clazz.get_identifiers(@conn, hashed_args)
814
- end
815
- rescue DTK::Client::DtkValidationError => e
816
- # TODO Check if handling needed. Error should happen only when autocomplete ID search illigal
817
- end
818
-
819
- return []
820
- end
821
-
822
- def load_extended_context_commands(extended_context_commands, active_context_copy)
823
- candidates = []
824
- entity_name = active_context_copy.last_context
825
- parent_entity = active_context_copy.context_list[1]
826
- response_ruby_obj = nil
827
-
828
- field = extended_context_commands[:field]||'display_name'
829
- endpoint = extended_context_commands[:endpoint]
830
- url = extended_context_commands[:url]
831
- opts = extended_context_commands[:opts]||{}
832
-
833
- if entity_name.is_identifier?
834
- if (parent_entity && parent_entity.is_identifier? && (parent_entity != entity_name))
835
- parent_id_label = "#{endpoint}_id".to_sym
836
- parent_id = parent_entity.identifier
837
- opts[parent_id_label] = parent_id
838
- id_label = "#{entity_name.entity}_id".to_sym
839
- end
840
-
841
- id_label ||= "#{endpoint}_id".to_sym
842
- id = entity_name.identifier
843
- opts[id_label] = id
844
-
845
- response_ruby_obj = DTK::Client::CommandBaseThor.get_cached_response(endpoint, url, opts)
846
- # response_ruby_obj = post rest_url(url), opts
847
- else
848
- response_ruby_obj = DTK::Client::CommandBaseThor.get_cached_response(endpoint, url, opts)
849
- # response_ruby_obj = post rest_url(url), opts
850
- end
851
-
852
- if response_ruby_obj && response_ruby_obj.ok?
853
- response_ruby_obj.data.each do |d|
854
- candidates << d[field]
855
- end
856
- end
857
-
858
- candidates
859
- end
860
-
861
- def get_dtk_command_parameters(entity_name, args)
862
- method_name, entity_name_id = nil, nil
863
- context_params = ContextParams.new
864
-
865
- if (ROOT_TASKS + ['dtk']).include?(entity_name)
866
- Context.require_command_class(entity_name)
867
- available_tasks = Context.get_command_class(entity_name).task_names
868
- if available_tasks.include?(args.first)
869
- method_name = args.shift
870
- else
871
- entity_name_id = args.shift
872
- method_name = args.shift
873
- end
874
- else
875
- raise DTK::Client::DtkError, "Could not find context \"#{entity_name}\"."
876
- end
877
-
878
- # if no method specified use help
879
- method_name ||= 'help'
880
-
881
- context_params.add_context_to_params(entity_name, entity_name)
882
-
883
- if entity_name_id
884
- identifier_response = valid_id?(entity_name, entity_name_id, context_params)
885
- if identifier_response
886
- context_params.add_context_to_params(identifier_response[:name], entity_name, identifier_response[:identifier])
887
- else
888
- raise DTK::Client::DtkError, "Could not validate identifier \"#{entity_name_id}\"."
889
- end
890
- end
891
-
892
- # extract thor options
893
- clazz = Context.get_command_class(entity_name)
894
- options = Context.get_thor_options(clazz, method_name) unless clazz.nil?
895
- args, thor_options, invalid_options = Context.parse_thor_options(args, options)
896
- context_params.method_arguments = args
897
-
898
-
899
- unless available_tasks.include?(method_name)
900
- raise DTK::Client::DtkError, "Could not find task \"#{method_name}\"."
901
- end
902
-
903
- raise DTK::Client::DtkValidationError, "Option '#{invalid_options.first}' is not valid for current command!" unless invalid_options.empty?
904
-
905
- return entity_name, method_name, context_params, thor_options
906
- end
907
-
908
- #
909
- # We use enrich data to help when using dynamic_context loading, Readline.completition_proc
910
- # See bellow for more details
911
- #
912
- def get_command_parameters(cmd,args, active_context_copy=nil)
913
- # To support autocomplete feature, temp active context may be forwarded into method
914
- active_context_copy = @active_context unless active_context_copy
915
-
916
- entity_name, method_name, option_types = nil, nil, nil
917
-
918
- context_params = ContextParams.new
919
-
920
- if root? && !args.empty?
921
- # this means that somebody is calling command with assembly/.. method_name
922
- entity_name = cmd
923
- method_name = args.shift
924
- else
925
- context_params.current_context = active_context_copy.clone_me
926
- entity_name = active_context_copy.name_list.first
927
- entity_name ||= "dtk"
928
- method_name = cmd
929
- end
930
-
931
- # extract thor options
932
- clazz = Context.get_command_class(entity_name)
933
- current_context_command = active_context_copy.last_command_name
934
-
935
- if ((current_context_command != entity_name) && !current_context_command.eql?("utils"))
936
- current_context_clazz = Context.get_command_class(current_context_command)
937
- options = Context.get_thor_options(current_context_clazz, cmd) if current_context_clazz
938
- else
939
- options = Context.get_thor_options(clazz, cmd) if clazz
940
- end
941
-
942
- # set rest of arguments as method options
943
- args, thor_options, invalid_options = Context.parse_thor_options(args, options)
944
- context_params.method_arguments = args
945
-
946
- return entity_name, method_name, context_params, thor_options, invalid_options
947
- end
948
-
949
- private
950
-
951
- #
952
- # method takes parameters that can hold specific thor options
953
- #
954
- def self.parse_thor_options(args, options=nil)
955
- type, invalid_options = nil, []
956
-
957
- # options to handle thor options -m MESSAGE and --list
958
- options_param_args = []
959
- args.each_with_index do |e,i|
960
- if (e.match(/^\-[a-zA-Z]?/) || e.match(/^\-\-/))
961
- type = Context.get_option_type(options, e) unless options.nil?
962
- if type.nil?
963
- options_param_args = nil
964
- invalid_options << e
965
- break
966
- else
967
- options_param_args << e
968
- options_param_args << args[i+1] unless type == :boolean
969
- end
970
- end
971
- end
972
-
973
- # remove thor_options but only once
974
- args = Client::CommonUtil.substract_array_once(args, options_param_args, true) unless options_param_args.nil?
975
-
976
- return args, options_param_args, invalid_options
977
- end
978
-
979
- def self.get_thor_options(clazz, command)
980
- command = command.gsub('-','_')
981
- options = nil
982
- options = clazz.all_tasks[command].options.collect{|k,v|{:alias=>v.aliases,:name=>v.name,:type=>v.type,:switch=>v.switch_name}} unless clazz.all_tasks[command].nil?
983
-
984
- return options
985
- end
986
-
987
- def self.get_option_type(options, option)
988
- @ret = nil
989
-
990
- options.each do |opt|
991
- @ret = opt[:type] if(opt[:alias].first == option || opt[:switch] == option)
992
- end
993
-
994
- return @ret
995
- end
996
-
997
- def self.command_to_id_sym(command_name)
998
- "#{command_name}_id".gsub(/\-/,'_').to_sym
999
- end
1000
-
1001
- def get_latest_tasks(command_name)
1002
- file_name = command_name.gsub('-','_')
1003
- cached_for_command = Context.get_command_class(file_name).tiered_task_names
1004
-
1005
- # gets thor command class and then all the task names for that command
1006
- @cached_tasks.merge!(cached_for_command)
1007
- end
1008
-
1009
-
1010
- # PART OF THE CODE USED FOR WORKING WITH DTK::Shell HISTORY
1011
- public
1012
-
1013
- # this file loads sessions history
1014
- def self.load_session_history()
1015
- unless is_there_history_file()
1016
- puts "[INFO] History file is missing, shell history will be disabled. To enable it create file: '#{HISTORY_LOCATION}'"
1017
- return []
1018
- end
1019
-
1020
- content = File.open(HISTORY_LOCATION,'r').read
1021
- return (content.empty? ? [] : JSON.parse(content))
1022
- end
1023
-
1024
- def self.save_session_history(array_of_commands)
1025
- return [] unless is_there_history_file()
1026
- # we filter the list to remove neighbour duplicates
1027
- filtered_commands = []
1028
- array_of_commands.each_with_index do |a,i|
1029
- filtered_commands << a if (a != array_of_commands[i+1] && is_allowed_command?(a))
1030
- end
1031
-
1032
- # make sure we only save up to 'COMMAND_HISTORY_LIMIT' commands
1033
- if filtered_commands.size > COMMAND_HISTORY_LIMIT
1034
- filtered_commands = filtered_commands[-COMMAND_HISTORY_LIMIT,COMMAND_HISTORY_LIMIT+1]
1035
- end
1036
-
1037
- File.open(HISTORY_LOCATION,'w') { |f| f.write(filtered_commands.to_json) }
1038
- end
1039
-
1040
- private
1041
-
1042
- # list of commands that should be excluded from history
1043
- EXCLUDE_COMMAND_LIST = ['create-provider','create-ec2-provider','create-physical-provider']
1044
-
1045
- def self.is_allowed_command?(full_command_entry)
1046
- found = EXCLUDE_COMMAND_LIST.find { |cmd| full_command_entry.include?(cmd) }
1047
- found.nil?
1048
- end
1049
-
1050
- def self.is_there_history_file()
1051
- unless File.exists? HISTORY_LOCATION
1052
- begin
1053
- File.open(HISTORY_LOCATION, 'w') {}
1054
- return true
1055
- rescue
1056
- return false
1057
- end
1058
- #DtkLogger.instance.info "[INFO] Session shell history has been disabled, please create file '#{HISTORY_LOCATION}' to enable it."
1059
- end
1060
- return true
1061
- end
1062
- end
1063
- end
1064
- end