puppet-editor-services 2.0.4

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 (109) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +510 -0
  3. data/CODEOWNERS +2 -0
  4. data/CODE_OF_CONDUCT.md +46 -0
  5. data/CONTRIBUTING.md +54 -0
  6. data/Gemfile +53 -0
  7. data/LICENSE +201 -0
  8. data/README.md +308 -0
  9. data/Rakefile +185 -0
  10. data/bin/puppet-debugserver +8 -0
  11. data/bin/puppet-languageserver +7 -0
  12. data/bin/puppet-languageserver-sidecar +7 -0
  13. data/lib/dsp/dsp.rb +7 -0
  14. data/lib/dsp/dsp_base.rb +62 -0
  15. data/lib/dsp/dsp_protocol.rb +4619 -0
  16. data/lib/lsp/lsp.rb +10 -0
  17. data/lib/lsp/lsp_base.rb +63 -0
  18. data/lib/lsp/lsp_custom.rb +170 -0
  19. data/lib/lsp/lsp_enums.rb +143 -0
  20. data/lib/lsp/lsp_protocol.rb +2785 -0
  21. data/lib/lsp/lsp_protocol_callhierarchy.proposed.rb +239 -0
  22. data/lib/lsp/lsp_protocol_colorprovider.rb +100 -0
  23. data/lib/lsp/lsp_protocol_configuration.rb +82 -0
  24. data/lib/lsp/lsp_protocol_declaration.rb +73 -0
  25. data/lib/lsp/lsp_protocol_foldingrange.rb +129 -0
  26. data/lib/lsp/lsp_protocol_implementation.rb +75 -0
  27. data/lib/lsp/lsp_protocol_progress.rb +200 -0
  28. data/lib/lsp/lsp_protocol_selectionrange.rb +79 -0
  29. data/lib/lsp/lsp_protocol_sematictokens.proposed.rb +340 -0
  30. data/lib/lsp/lsp_protocol_typedefinition.rb +75 -0
  31. data/lib/lsp/lsp_protocol_workspacefolders.rb +174 -0
  32. data/lib/lsp/lsp_types.rb +1534 -0
  33. data/lib/puppet-debugserver/debug_session/break_points.rb +137 -0
  34. data/lib/puppet-debugserver/debug_session/flow_control.rb +161 -0
  35. data/lib/puppet-debugserver/debug_session/hook_handlers.rb +295 -0
  36. data/lib/puppet-debugserver/debug_session/puppet_session_run_mode.rb +66 -0
  37. data/lib/puppet-debugserver/debug_session/puppet_session_state.rb +122 -0
  38. data/lib/puppet-debugserver/hooks.rb +132 -0
  39. data/lib/puppet-debugserver/message_handler.rb +277 -0
  40. data/lib/puppet-debugserver/puppet_debug_session.rb +541 -0
  41. data/lib/puppet-debugserver/puppet_monkey_patches.rb +118 -0
  42. data/lib/puppet-languageserver/client_session_state.rb +119 -0
  43. data/lib/puppet-languageserver/crash_dump.rb +50 -0
  44. data/lib/puppet-languageserver/epp/validation_provider.rb +34 -0
  45. data/lib/puppet-languageserver/facter_helper.rb +25 -0
  46. data/lib/puppet-languageserver/global_queues/sidecar_queue.rb +205 -0
  47. data/lib/puppet-languageserver/global_queues/single_instance_queue.rb +126 -0
  48. data/lib/puppet-languageserver/global_queues/validation_queue.rb +102 -0
  49. data/lib/puppet-languageserver/global_queues.rb +16 -0
  50. data/lib/puppet-languageserver/manifest/completion_provider.rb +331 -0
  51. data/lib/puppet-languageserver/manifest/definition_provider.rb +99 -0
  52. data/lib/puppet-languageserver/manifest/document_symbol_provider.rb +228 -0
  53. data/lib/puppet-languageserver/manifest/folding_provider.rb +226 -0
  54. data/lib/puppet-languageserver/manifest/format_on_type_provider.rb +143 -0
  55. data/lib/puppet-languageserver/manifest/hover_provider.rb +221 -0
  56. data/lib/puppet-languageserver/manifest/signature_provider.rb +169 -0
  57. data/lib/puppet-languageserver/manifest/validation_provider.rb +127 -0
  58. data/lib/puppet-languageserver/message_handler.rb +462 -0
  59. data/lib/puppet-languageserver/providers.rb +18 -0
  60. data/lib/puppet-languageserver/puppet_helper.rb +108 -0
  61. data/lib/puppet-languageserver/puppet_lexer_helper.rb +55 -0
  62. data/lib/puppet-languageserver/puppet_monkey_patches.rb +39 -0
  63. data/lib/puppet-languageserver/puppet_parser_helper.rb +212 -0
  64. data/lib/puppet-languageserver/puppetfile/validation_provider.rb +185 -0
  65. data/lib/puppet-languageserver/server_capabilities.rb +48 -0
  66. data/lib/puppet-languageserver/session_state/document_store.rb +272 -0
  67. data/lib/puppet-languageserver/session_state/language_client.rb +239 -0
  68. data/lib/puppet-languageserver/session_state/object_cache.rb +162 -0
  69. data/lib/puppet-languageserver/sidecar_protocol.rb +532 -0
  70. data/lib/puppet-languageserver/uri_helper.rb +46 -0
  71. data/lib/puppet-languageserver-sidecar/cache/base.rb +36 -0
  72. data/lib/puppet-languageserver-sidecar/cache/filesystem.rb +111 -0
  73. data/lib/puppet-languageserver-sidecar/cache/null.rb +27 -0
  74. data/lib/puppet-languageserver-sidecar/facter_helper.rb +41 -0
  75. data/lib/puppet-languageserver-sidecar/puppet_environment_monkey_patches.rb +52 -0
  76. data/lib/puppet-languageserver-sidecar/puppet_helper.rb +281 -0
  77. data/lib/puppet-languageserver-sidecar/puppet_modulepath_monkey_patches.rb +146 -0
  78. data/lib/puppet-languageserver-sidecar/puppet_monkey_patches.rb +9 -0
  79. data/lib/puppet-languageserver-sidecar/puppet_parser_helper.rb +77 -0
  80. data/lib/puppet-languageserver-sidecar/puppet_strings_helper.rb +399 -0
  81. data/lib/puppet-languageserver-sidecar/puppet_strings_monkey_patches.rb +16 -0
  82. data/lib/puppet-languageserver-sidecar/sidecar_protocol_extensions.rb +16 -0
  83. data/lib/puppet-languageserver-sidecar/workspace.rb +89 -0
  84. data/lib/puppet_debugserver.rb +164 -0
  85. data/lib/puppet_editor_services/connection/base.rb +62 -0
  86. data/lib/puppet_editor_services/connection/stdio.rb +25 -0
  87. data/lib/puppet_editor_services/connection/tcp.rb +34 -0
  88. data/lib/puppet_editor_services/handler/base.rb +16 -0
  89. data/lib/puppet_editor_services/handler/debug_adapter.rb +63 -0
  90. data/lib/puppet_editor_services/handler/json_rpc.rb +133 -0
  91. data/lib/puppet_editor_services/logging.rb +45 -0
  92. data/lib/puppet_editor_services/protocol/base.rb +27 -0
  93. data/lib/puppet_editor_services/protocol/debug_adapter.rb +135 -0
  94. data/lib/puppet_editor_services/protocol/debug_adapter_messages.rb +171 -0
  95. data/lib/puppet_editor_services/protocol/json_rpc.rb +241 -0
  96. data/lib/puppet_editor_services/protocol/json_rpc_messages.rb +200 -0
  97. data/lib/puppet_editor_services/server/base.rb +42 -0
  98. data/lib/puppet_editor_services/server/stdio.rb +85 -0
  99. data/lib/puppet_editor_services/server/tcp.rb +349 -0
  100. data/lib/puppet_editor_services/server.rb +15 -0
  101. data/lib/puppet_editor_services/version.rb +36 -0
  102. data/lib/puppet_editor_services.rb +8 -0
  103. data/lib/puppet_languageserver.rb +263 -0
  104. data/lib/puppet_languageserver_sidecar.rb +361 -0
  105. data/puppet-debugserver +11 -0
  106. data/puppet-editor-services.gemspec +29 -0
  107. data/puppet-languageserver +15 -0
  108. data/puppet-languageserver-sidecar +14 -0
  109. metadata +240 -0
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PuppetEditorServices
4
+ PUPPETEDITORSERVICESVERSION = '2.0.4' unless defined? PUPPETEDITORSERVICESVERSION
5
+
6
+ # @api public
7
+ #
8
+ # @return [String] containing the editor services version, e.g. "0.4.0"
9
+ def self.version
10
+ return @editor_services_version if @editor_services_version
11
+
12
+ version_file = File.join(File.dirname(__FILE__), 'VERSION')
13
+ version = read_version_file(version_file)
14
+
15
+ @editor_services_version = version.nil? ? PUPPETEDITORSERVICESVERSION : version
16
+ end
17
+
18
+ # Sets the editor services version
19
+ # Typically only used in testing
20
+ #
21
+ # @return [void]
22
+ #
23
+ # @api private
24
+ def self.version=(version)
25
+ @editor_services_version = version
26
+ end
27
+
28
+ # @api private
29
+ #
30
+ # @return [String] the version -- for example: "0.4.0" or nil if the VERSION
31
+ # file does not exist.
32
+ def self.read_version_file(path)
33
+ File.read(path).chomp if File.exist?(path)
34
+ end
35
+ private_class_method :read_version_file
36
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ %w[
4
+ logging
5
+ version
6
+ ].each do |lib|
7
+ require "puppet_editor_services/#{lib}"
8
+ end
@@ -0,0 +1,263 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ original_verbose = $VERBOSE
5
+ $VERBOSE = nil
6
+
7
+ require 'puppet_editor_services'
8
+ require 'optparse'
9
+ require 'logger'
10
+ ensure
11
+ $VERBOSE = original_verbose
12
+ end
13
+
14
+ module PuppetLanguageServer
15
+ def self.version
16
+ PuppetEditorServices.version
17
+ end
18
+
19
+ # Whether the language server is actually in a state that can be used.
20
+ # Typically this is false when a catastrophic error occurs during startup e.g. Puppet is missing.
21
+ #
22
+ # @return [Bool] Whether the language server is actually in a state that can be used
23
+ def self.active?
24
+ @server_is_active
25
+ end
26
+
27
+ def self.static_data_dir
28
+ @static_data_dir ||= File.expand_path(File.join(__dir__, 'puppet-languageserver', 'static_data'))
29
+ end
30
+
31
+ def self.configure_featureflags(flags)
32
+ @flags = flags
33
+ end
34
+
35
+ def self.featureflag?(flagname)
36
+ return false if @flags.nil? || @flags.empty?
37
+
38
+ @flags.include?(flagname)
39
+ end
40
+
41
+ def self.require_gems(options)
42
+ original_verbose = $VERBOSE
43
+ $VERBOSE = nil
44
+ @server_is_active = false
45
+
46
+ # Use specific Puppet Gem version if possible
47
+ unless options[:puppet_version].nil?
48
+ available_puppet_gems = Gem::Specification
49
+ .select { |item| item.name.casecmp('puppet').zero? }
50
+ .map { |item| item.version.to_s }
51
+ if available_puppet_gems.include?(options[:puppet_version])
52
+ gem 'puppet', options[:puppet_version]
53
+ else
54
+ log_message(:warn, "Unable to use puppet version #{options[:puppet_version]}, as only the following versions are available [#{available_puppet_gems.join(', ')}]")
55
+ end
56
+ end
57
+
58
+ # These libraries do not require the puppet gem and required for the
59
+ # server to respond to clients.
60
+ %w[
61
+ client_session_state
62
+ crash_dump
63
+ message_handler
64
+ server_capabilities
65
+ ].each do |lib|
66
+ require "puppet-languageserver/#{lib}"
67
+ rescue LoadError
68
+ require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver', lib))
69
+ end
70
+
71
+ begin
72
+ require 'lsp/lsp'
73
+ require 'puppet'
74
+ require 'facter'
75
+ rescue LoadError => e
76
+ log_message(:error, "Error while loading a critical gem: #{e} #{e.backtrace}")
77
+ return
78
+ end
79
+
80
+ # These libraries require the puppet and LSP gems.
81
+ %w[
82
+ sidecar_protocol
83
+ global_queues
84
+ puppet_lexer_helper
85
+ puppet_parser_helper
86
+ puppet_helper
87
+ facter_helper
88
+ uri_helper
89
+ puppet_monkey_patches
90
+ providers
91
+ ].each do |lib|
92
+ require "puppet-languageserver/#{lib}"
93
+ rescue LoadError
94
+ require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver', lib))
95
+ end
96
+
97
+ # Validate the feature flags
98
+ unless options[:flags].nil? || options[:flags].empty?
99
+ flags = options[:flags]
100
+ log_message(:debug, "Detected feature flags [#{flags.join(', ')}]")
101
+
102
+ configure_featureflags(flags)
103
+ end
104
+
105
+ @server_is_active = true
106
+ ensure
107
+ $VERBOSE = original_verbose
108
+ end
109
+
110
+ class CommandLineParser
111
+ def self.parse(options)
112
+ # Set defaults here
113
+ args = {
114
+ connection_timeout: 10,
115
+ debug: nil,
116
+ disable_sidecar_cache: false,
117
+ fast_start_langserver: true,
118
+ flags: [],
119
+ ipaddress: 'localhost',
120
+ port: nil,
121
+ puppet_version: nil,
122
+ puppet_settings: [],
123
+ preload_puppet: true,
124
+ stdio: false,
125
+ stop_on_client_exit: true,
126
+ workspace: nil
127
+ }
128
+
129
+ opt_parser = OptionParser.new do |opts|
130
+ opts.banner = 'Usage: puppet-languageserver.rb [options]'
131
+
132
+ opts.on('-pPORT', '--port=PORT', 'TCP Port to listen on. Default is random port') do |port|
133
+ args[:port] = port.to_i
134
+ end
135
+
136
+ opts.on('-ipADDRESS', '--ip=ADDRESS', "IP Address to listen on (0.0.0.0 for all interfaces). Default is #{args[:ipaddress]}") do |ipaddress|
137
+ args[:ipaddress] = ipaddress
138
+ end
139
+
140
+ opts.on('-c', '--no-stop', 'Do not stop the language server once a client disconnects. Default is to stop') do |_misc|
141
+ args[:stop_on_client_exit] = false
142
+ end
143
+
144
+ opts.on('-tTIMEOUT', '--timeout=TIMEOUT', "Stop the language server if a client does not connection within TIMEOUT seconds. A value of zero will not timeout. Default is #{args[:connection_timeout]} seconds") do |timeout|
145
+ args[:connection_timeout] = timeout.to_i
146
+ end
147
+
148
+ opts.on('-d', '--no-preload', '** DEPRECATED ** Do not preload Puppet information when the language server starts. Default is to preload') do |_misc|
149
+ puts '** WARNING ** Using "--no-preload" may cause Puppet Type loading to be incomplete.'
150
+ args[:preload_puppet] = false
151
+ end
152
+
153
+ opts.on('--debug=DEBUG', "Output debug information. Either specify a filename or 'STDOUT'. Default is no debug output") do |debug|
154
+ args[:debug] = debug
155
+ end
156
+
157
+ opts.on('-s', '--slow-start', '** DEPRECATED ** Delay starting the Language Server until Puppet initialisation has completed. Default is to start fast') do |_misc|
158
+ args[:fast_start_langserver] = false
159
+ end
160
+
161
+ opts.on('--stdio', 'Runs the server in stdio mode, without a TCP listener') do |_misc|
162
+ args[:stdio] = true
163
+ end
164
+
165
+ opts.on('--enable-file-cache', '** DEPRECATED ** Enables the file system cache for Puppet Objects (types, class etc.)') do |_misc|
166
+ end
167
+
168
+ # These options are normally passed through to the Sidecar
169
+ opts.on('--[no-]cache', 'Enable or disable all caching inside the sidecar. By default caching is enabled.') do |cache|
170
+ args[:disable_sidecar_cache] = !cache
171
+ end
172
+
173
+ opts.on('--feature-flags=FLAGS', Array, 'A list of comma delimited feature flags') do |flags|
174
+ args[:flags] = flags
175
+ end
176
+
177
+ opts.on('--puppet-settings=TEXT', Array, 'Comma delimited list of settings to pass into Puppet e.g. --vardir,/opt/test-fixture') do |text|
178
+ args[:puppet_settings] = text
179
+ end
180
+
181
+ opts.on('--puppet-version=TEXT', String, 'The version of the Puppet Gem to use (defaults to latest version if not specified or the version does not exist) e.g. --puppet-version=5.4.0') do |text|
182
+ args[:puppet_version] = text
183
+ end
184
+
185
+ opts.on('--local-workspace=PATH', '** DEPRECATED ** The workspace or file path that will be used to provide module-specific functionality. Default is no workspace path.') do |_path|
186
+ end
187
+
188
+ opts.on('-h', '--help', 'Prints this help') do
189
+ puts opts
190
+ exit
191
+ end
192
+
193
+ opts.on('-v', '--version', 'Prints the Langauge Server version') do
194
+ puts PuppetLanguageServer.version
195
+ exit
196
+ end
197
+ end
198
+
199
+ opt_parser.parse!(options.dup)
200
+ args
201
+ end
202
+ end
203
+
204
+ def self.log_message(severity, message)
205
+ PuppetEditorServices.log_message(severity, message)
206
+ end
207
+
208
+ def self.init_puppet(options)
209
+ PuppetEditorServices.init_logging(options)
210
+ log_message(:info, "Language Server is v#{PuppetEditorServices.version}")
211
+ log_message(:debug, 'Loading gems...')
212
+ require_gems(options)
213
+ return unless active?
214
+
215
+ log_message(:info, "Using Puppet v#{Puppet.version}")
216
+ log_message(:info, "Using Facter v#{Facter.version}")
217
+
218
+ raise("Detected Puppet #{Puppet.version} however the Language Server requires Puppet 5.0 and above") if Gem::Version.new(Puppet.version) < Gem::Version.new('5.0.0')
219
+
220
+ log_message(:debug, "Detected additional puppet settings #{options[:puppet_settings]}")
221
+ options[:puppet_settings].nil? ? Puppet.initialize_settings : Puppet.initialize_settings(options[:puppet_settings])
222
+
223
+ log_message(:info, 'Initializing settings...')
224
+
225
+ # Remove all other logging destinations except for ours
226
+ Puppet::Util::Log.destinations.clear
227
+ Puppet::Util::Log.newdestination('null_logger')
228
+
229
+ true
230
+ end
231
+
232
+ def self.rpc_server(options)
233
+ log_message(:info, 'Starting RPC Server...')
234
+ options[:servicename] = 'LANGUAGE SERVER'
235
+
236
+ require 'puppet_editor_services/protocol/json_rpc'
237
+
238
+ server_options = options
239
+ protocol_options = { class: PuppetEditorServices::Protocol::JsonRPC }.merge(options)
240
+ handler_options = { class: PuppetLanguageServer::MessageHandler }.merge(options)
241
+
242
+ unless active?
243
+ handler_options[:class] = PuppetLanguageServer::DisabledMessageHandler
244
+ log_message(:info, 'Configured the Language Server to use the Disabled Message Router')
245
+ end
246
+
247
+ if options[:stdio]
248
+ log_message(:debug, 'Using STDIO Server')
249
+ require 'puppet_editor_services/server/stdio'
250
+ server = ::PuppetEditorServices::Server::Stdio.new(server_options, protocol_options, handler_options)
251
+ trap('INT') { server.stop }
252
+ else
253
+ log_message(:debug, 'Using TCP Server')
254
+ require 'puppet_editor_services/server/tcp'
255
+ # TODO: Add max threads?
256
+ server = ::PuppetEditorServices::Server::Tcp.new(server_options, protocol_options, handler_options)
257
+ trap('INT') { server.stop_services(true) }
258
+ end
259
+ server.start
260
+
261
+ log_message(:info, 'Language Server exited.')
262
+ end
263
+ end
@@ -0,0 +1,361 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ original_verbose = $VERBOSE
5
+ $VERBOSE = nil
6
+
7
+ require 'puppet_editor_services'
8
+ require 'optparse'
9
+ require 'logger'
10
+ require 'json'
11
+
12
+ %w[
13
+ sidecar_protocol
14
+ ].each do |lib|
15
+ require "puppet-languageserver/#{lib}"
16
+ rescue LoadError
17
+ require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver', lib))
18
+ end
19
+ ensure
20
+ $VERBOSE = original_verbose
21
+ end
22
+
23
+ module PuppetLanguageServerSidecar
24
+ def self.version
25
+ PuppetEditorServices.version
26
+ end
27
+
28
+ def self.configure_featureflags(flags)
29
+ @flags = flags
30
+ end
31
+
32
+ def self.featureflag?(flagname)
33
+ return false if @flags.nil? || @flags.empty?
34
+
35
+ @flags.include?(flagname)
36
+ end
37
+
38
+ def self.require_gems(options)
39
+ original_verbose = $VERBOSE
40
+ $VERBOSE = nil
41
+
42
+ # Use specific Puppet Gem version if possible
43
+ unless options[:puppet_version].nil?
44
+ available_puppet_gems = Gem::Specification
45
+ .select { |item| item.name.casecmp('puppet').zero? }
46
+ .map { |item| item.version.to_s }
47
+ if available_puppet_gems.include?(options[:puppet_version])
48
+ gem 'puppet', options[:puppet_version]
49
+ else
50
+ log_message(:warn, "Unable to use puppet version #{options[:puppet_version]}, as only the following versions are available [#{available_puppet_gems.join(', ')}]")
51
+ end
52
+ end
53
+
54
+ require 'puppet'
55
+
56
+ # Validate the feature flags
57
+ unless options[:flags].nil? || options[:flags].empty?
58
+ flags = options[:flags]
59
+ log_message(:debug, "Detected feature flags [#{options[:flags].join(', ')}]")
60
+
61
+ configure_featureflags(flags)
62
+ end
63
+
64
+ require_list = %w[
65
+ cache/base
66
+ cache/null
67
+ cache/filesystem
68
+ puppet_parser_helper
69
+ sidecar_protocol_extensions
70
+ workspace
71
+ facter_helper
72
+ puppet_helper
73
+ puppet_monkey_patches
74
+ puppet_strings_helper
75
+ ]
76
+
77
+ require_list.each do |lib|
78
+ require "puppet-languageserver-sidecar/#{lib}"
79
+ rescue LoadError
80
+ require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver-sidecar', lib))
81
+ end
82
+ ensure
83
+ $VERBOSE = original_verbose
84
+ end
85
+
86
+ ACTION_LIST = %w[
87
+ noop
88
+ default_aggregate
89
+ default_classes
90
+ default_datatypes
91
+ default_functions
92
+ default_types
93
+ node_graph
94
+ resource_list
95
+ workspace_aggregate
96
+ workspace_classes
97
+ workspace_datatypes
98
+ workspace_functions
99
+ workspace_types
100
+ facts
101
+ ].freeze
102
+
103
+ class CommandLineParser
104
+ def self.parse(options)
105
+ # Set defaults here
106
+ args = {
107
+ action: nil,
108
+ action_parameters: PuppetLanguageServer::Sidecar::Protocol::ActionParams.new,
109
+ debug: nil,
110
+ disable_cache: false,
111
+ flags: [],
112
+ output: nil,
113
+ puppet_settings: [],
114
+ puppet_version: nil,
115
+ workspace: nil
116
+ }
117
+
118
+ opt_parser = OptionParser.new do |opts|
119
+ opts.banner = 'Usage: puppet-languageserver-sidecar.rb [options]'
120
+
121
+ opts.on('-a', '--action=NAME', ACTION_LIST, "The action for the sidecar to take. Expected #{ACTION_LIST}") do |name|
122
+ args[:action] = name
123
+ end
124
+
125
+ opts.on('-c', '--action-parameters=JSON', 'JSON Encoded string containing the parameters for the sidecar action') do |json_string|
126
+ ap = PuppetLanguageServer::Sidecar::Protocol::ActionParams.new
127
+ begin
128
+ ap.from_json!(json_string)
129
+ args[:action_parameters] = ap
130
+ rescue StandardError => e
131
+ raise "Unable to parse the action parameters: #{e}"
132
+ end
133
+ end
134
+
135
+ opts.on('-w', '--local-workspace=PATH', 'The workspace or file path that will be used to provide module-specific functionality. Default is no workspace path') do |path|
136
+ args[:workspace] = path
137
+ end
138
+
139
+ opts.on('-o', '--output=PATH', 'The file to save the output from the sidecar. Default is output to STDOUT') do |path|
140
+ args[:output] = path
141
+ end
142
+
143
+ opts.on('-p', '--puppet-settings=TEXT', Array, 'Comma delimited list of settings to pass into Puppet e.g. --vardir,/opt/test-fixture') do |text|
144
+ args[:puppet_settings] = text
145
+ end
146
+
147
+ opts.on('--puppet-version=TEXT', String, 'The version of the Puppet Gem to use (defaults to latest version if not specified or the version does not exist) e.g. --puppet-version=5.4.0') do |text|
148
+ args[:puppet_version] = text
149
+ end
150
+
151
+ opts.on('-f', '--feature-flags=FLAGS', Array, 'A list of comma delimited feature flags to pass the the sidecar') do |flags|
152
+ args[:flags] = flags
153
+ end
154
+
155
+ opts.on('-n', '--[no-]cache', 'Enable or disable all caching inside the sidecar. By default caching is enabled.') do |cache|
156
+ args[:disable_cache] = !cache
157
+ end
158
+
159
+ opts.on('--debug=DEBUG', "Output debug information. Either specify a filename or 'STDOUT'. Default is no debug output") do |debug|
160
+ args[:debug] = debug
161
+ end
162
+
163
+ opts.on('-h', '--help', 'Prints this help') do
164
+ puts opts
165
+ exit
166
+ end
167
+
168
+ opts.on('-v', '--version', 'Prints the Langauge Server version') do
169
+ puts PuppetLanguageServerSidecar.version
170
+ exit
171
+ end
172
+ end
173
+
174
+ opt_parser.parse!(options.dup)
175
+
176
+ raise('The action parameter is mandatory') if args[:action].nil?
177
+
178
+ args
179
+ end
180
+ end
181
+
182
+ def self.log_message(severity, message)
183
+ PuppetEditorServices.log_message(severity, message)
184
+ end
185
+
186
+ def self.init_puppet_sidecar(options)
187
+ PuppetEditorServices.init_logging(options)
188
+ log_message(:info, "Language Server Sidecar is v#{PuppetLanguageServerSidecar.version}")
189
+ log_message(:debug, 'Loading gems...')
190
+ require_gems(options)
191
+ log_message(:info, "Using Puppet v#{Puppet.version}")
192
+
193
+ raise("Detected Puppet #{Puppet.version} however the Language Server Sidecar requires Puppet 5.0 and above") if Gem::Version.new(Puppet.version) < Gem::Version.new('5.0.0')
194
+
195
+ log_message(:debug, "Detected additional puppet settings #{options[:puppet_settings]}")
196
+ options[:puppet_settings].nil? ? Puppet.initialize_settings : Puppet.initialize_settings(options[:puppet_settings])
197
+
198
+ PuppetLanguageServerSidecar::Workspace.detect_workspace(options[:workspace])
199
+ log_message(:debug, 'Detected Module Metadata in the workspace') if PuppetLanguageServerSidecar::Workspace.has_module_metadata?
200
+ log_message(:debug, 'Detected Environment Config in the workspace') if PuppetLanguageServerSidecar::Workspace.has_environmentconf?
201
+
202
+ # Remove all other logging destinations except for ours
203
+ Puppet::Util::Log.destinations.clear
204
+ Puppet::Util::Log.newdestination('null_logger')
205
+
206
+ true
207
+ end
208
+
209
+ def self.inject_workspace_as_module
210
+ return false unless PuppetLanguageServerSidecar::Workspace.has_module_metadata?
211
+
212
+ %w[puppet_modulepath_monkey_patches].each do |lib|
213
+ require "puppet-languageserver-sidecar/#{lib}"
214
+ rescue LoadError
215
+ require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver-sidecar', lib))
216
+ end
217
+
218
+ log_message(:debug, 'Injected the workspace into the module loader')
219
+ true
220
+ end
221
+
222
+ def self.inject_workspace_as_environment
223
+ return false unless PuppetLanguageServerSidecar::Workspace.has_environmentconf?
224
+
225
+ Puppet.settings[:environment] = PuppetLanguageServerSidecar::PuppetHelper::SIDECAR_PUPPET_ENVIRONMENT
226
+
227
+ %w[puppet_environment_monkey_patches].each do |lib|
228
+ require "puppet-languageserver-sidecar/#{lib}"
229
+ rescue LoadError
230
+ require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver-sidecar', lib))
231
+ end
232
+
233
+ log_message(:debug, 'Injected the workspace into the environment loader')
234
+ true
235
+ end
236
+
237
+ def self.execute(options)
238
+ unless Gem::Version.new(Puppet.version) >= Gem::Version.new('5.0.0')
239
+ log_message(:error, 'Only Puppet Version 5.0 and above is supported.')
240
+ return []
241
+ end
242
+
243
+ log_message(:debug, "Executing #{options[:action]} action")
244
+ case options[:action].downcase
245
+ when 'noop'
246
+ []
247
+
248
+ when 'default_aggregate'
249
+ cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
250
+ PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, object_types: PuppetLanguageServerSidecar::PuppetHelper.available_documentation_types)
251
+
252
+ when 'default_classes'
253
+ cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
254
+ PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, object_types: [:class]).classes
255
+
256
+ when 'default_datatypes'
257
+ cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
258
+ PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, object_types: [:datatype]).datatypes
259
+
260
+ when 'default_functions'
261
+ cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
262
+ PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, object_types: [:function]).functions
263
+
264
+ when 'default_types'
265
+ cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
266
+ PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, object_types: [:type]).types
267
+
268
+ when 'node_graph'
269
+ inject_workspace_as_module || inject_workspace_as_environment
270
+ result = PuppetLanguageServerSidecar::Protocol::PuppetNodeGraph.new
271
+ if options[:action_parameters]['source'].nil?
272
+ log_message(:error, 'Missing source action parameter')
273
+ return result.set_error('Missing source action parameter')
274
+ end
275
+ begin
276
+ manifest = File.open(options[:action_parameters]['source'], 'r:UTF-8') { |f| f.read }
277
+ PuppetLanguageServerSidecar::PuppetParserHelper.compile_node_graph(manifest)
278
+ rescue StandardError => e
279
+ log_message(:error, "Unable to compile the manifest. #{e}")
280
+ result.set_error("Unable to compile the manifest. #{e}")
281
+ end
282
+
283
+ when 'resource_list'
284
+ inject_workspace_as_module || inject_workspace_as_environment
285
+ typename = options[:action_parameters]['typename']
286
+ title = options[:action_parameters]['title']
287
+ if typename.nil?
288
+ log_message(:error, 'Missing typename action paramater')
289
+ return []
290
+ end
291
+ PuppetLanguageServerSidecar::PuppetHelper.get_puppet_resource(typename, title)
292
+
293
+ when 'workspace_aggregate'
294
+ return nil unless inject_workspace_as_module || inject_workspace_as_environment
295
+
296
+ cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
297
+ PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache,
298
+ object_types: PuppetLanguageServerSidecar::PuppetHelper.available_documentation_types,
299
+ root_path: PuppetLanguageServerSidecar::Workspace.root_path)
300
+
301
+ when 'workspace_classes'
302
+ return nil unless inject_workspace_as_module || inject_workspace_as_environment
303
+
304
+ cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
305
+ PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache,
306
+ object_types: [:class],
307
+ root_path: PuppetLanguageServerSidecar::Workspace.root_path).classes
308
+
309
+ when 'workspace_datatypes'
310
+ return nil unless inject_workspace_as_module || inject_workspace_as_environment
311
+
312
+ cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
313
+ PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache,
314
+ object_types: [:datatype],
315
+ root_path: PuppetLanguageServerSidecar::Workspace.root_path).datatypes
316
+
317
+ when 'workspace_functions'
318
+ return nil unless inject_workspace_as_module || inject_workspace_as_environment
319
+
320
+ cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
321
+ PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache,
322
+ object_types: [:function],
323
+ root_path: PuppetLanguageServerSidecar::Workspace.root_path).functions
324
+
325
+ when 'workspace_types'
326
+ return nil unless inject_workspace_as_module || inject_workspace_as_environment
327
+
328
+ cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
329
+ PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache,
330
+ object_types: [:type],
331
+ root_path: PuppetLanguageServerSidecar::Workspace.root_path).types
332
+
333
+ when 'facts'
334
+ # Can't cache for facts
335
+ cache = PuppetLanguageServerSidecar::Cache::Null.new
336
+ # Inject the workspace etc. if present
337
+ injected = inject_workspace_as_module
338
+ inject_workspace_as_environment unless injected
339
+ PuppetLanguageServerSidecar::FacterHelper.retrieve_facts(cache)
340
+
341
+ else
342
+ log_message(:error, "Unknown action #{options[:action]}. Expected one of #{ACTION_LIST}")
343
+ end
344
+ end
345
+
346
+ def self.output(result, options)
347
+ if options[:output].nil? || options[:output].empty?
348
+ $stdout.binmode
349
+ $stdout.write(result.to_json)
350
+ else
351
+ File.open(options[:output], 'wb:UTF-8') do |f|
352
+ f.write result.to_json
353
+ end
354
+ end
355
+ end
356
+
357
+ def self.execute_and_output(options)
358
+ output(execute(options), options)
359
+ nil
360
+ end
361
+ end
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Add the debug server into the load path
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
6
+
7
+ require 'puppet_debugserver'
8
+
9
+ PuppetDebugServer.init_puppet(PuppetDebugServer::CommandLineParser.parse(ARGV))
10
+ rpc_thread = PuppetDebugServer.rpc_server_async(PuppetDebugServer::CommandLineParser.parse(ARGV))
11
+ PuppetDebugServer.execute(rpc_thread)