From bee03c1f9ae052867a32081d2f9142d6c7f67156 Mon Sep 17 00:00:00 2001 From: Glenn Sarti Date: Wed, 3 Jan 2018 21:39:19 +0800 Subject: [PATCH] (maint) Fix minor rubocop violations --- .rubocop.yml | 12 +- lib/debugserver/debug_protocol.rb | 93 +++---- lib/languageserver/puppet_version.rb | 2 +- lib/puppet-debugserver.rb | 6 +- lib/puppet-debugserver/debug_hook_handlers.rb | 73 ++--- lib/puppet-debugserver/hooks.rb | 20 +- lib/puppet-debugserver/json_handler.rb | 12 +- lib/puppet-debugserver/message_router.rb | 256 +++++++++++------- .../puppet_debug_breakpoints.rb | 34 +-- .../puppet_debug_session.rb | 205 +++++++------- .../puppet_monkey_patches.rb | 162 ++++++----- lib/puppet-languageserver.rb | 10 +- .../definition_provider.rb | 34 +-- .../document_validator.rb | 3 +- lib/puppet-languageserver/message_router.rb | 9 +- lib/puppet-languageserver/puppet_helper.rb | 29 +- .../puppet_monkey_patches.rb | 62 +++-- .../server_capabilities.rb | 8 +- lib/puppet-vscode/logging.rb | 2 +- lib/puppet-vscode/simple_tcp_server.rb | 12 +- 20 files changed, 562 insertions(+), 482 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index fc4d5251..76685442 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -33,7 +33,7 @@ Metrics/PerceivedComplexity: Enabled: false Metrics/CyclomaticComplexity: Enabled: false - + # Empty method definitions over more than one line is ok Style/EmptyMethod: Enabled: false @@ -59,3 +59,13 @@ Next: # Enforce LF line endings, even when on Windows Layout/EndOfLine: EnforcedStyle: lf + +# We only alias for monkey patching +Style/Alias: + Enabled: false + +# Harder to read when on +Style/SymbolProc: + Enabled: false +Style/HashSyntax: + Enabled: false diff --git a/lib/debugserver/debug_protocol.rb b/lib/debugserver/debug_protocol.rb index 4c1354e8..4bb1660d 100644 --- a/lib/debugserver/debug_protocol.rb +++ b/lib/debugserver/debug_protocol.rb @@ -39,7 +39,7 @@ def self.create(options) result = ProtocolMessage.create(options) raise('command is a required field for Request') if options['command'].nil? - result['command'] = options['command'] + result['command'] = options['command'] result['arguments'] = options['arguments'] unless options['arguments'].nil? result @@ -60,7 +60,7 @@ def self.create(options = {}) result = ProtocolMessage.create(options) raise('event is a required field for Event') if options['event'].nil? - result['event'] = options['event'] + result['event'] = options['event'] result['body'] = options['body'] unless options['body'].nil? result @@ -83,8 +83,8 @@ def self.create(options = {}) # } module Response def self.create_from_request(options, request = nil) - result = ProtocolMessage.create({ 'seq' => -1, 'type' => 'response'}) - + result = ProtocolMessage.create('seq' => -1, 'type' => 'response') + raise('success is a required field for Response') if options['success'].nil? result['request_seq'] = options['request_seq'] unless options['request_seq'].nil? @@ -120,8 +120,8 @@ def self.create_from_request(options, request = nil) # // event: 'initialized'; # } module InitializedEvent - def self.create(options = {}) - result = Event.create({ 'event' => 'initialized', 'seq' => -1 }) + def self.create(_options = {}) + result = Event.create('event' => 'initialized', 'seq' => -1) result end @@ -153,7 +153,7 @@ def self.create(options = {}) # } module StoppedEvent def self.create(options = {}) - result = Event.create({ 'event' => 'stopped', 'seq' => -1 }) + result = Event.create('event' => 'stopped', 'seq' => -1) raise('reason is a required field for StoppedEvent') if options['reason'].nil? result['body'] = {} @@ -177,7 +177,7 @@ def self.create(options) result = Request.create(options) raise('command is a required field for InitializeRequest') if options['command'].nil? - result['command'] = options['command'] + result['command'] = options['command'] result['arguments'] = InitializeRequestArguments.create(options['arguments']) unless options['arguments'].nil? result @@ -232,7 +232,6 @@ def self.create_from_request(options, request = nil) end end - # /** Event message for 'terminated' event types. # The event indicates that debugging of the debuggee has terminated. # */ @@ -247,7 +246,7 @@ def self.create_from_request(options, request = nil) # } module TerminatedEvent def self.create(options = {}) - result = Event.create({ 'event' => 'terminated', 'seq' => -1 }) + result = Event.create('event' => 'terminated', 'seq' => -1) result['body'] = {} result['body']['restart'] = options['restart'] unless options['restart'].nil? @@ -269,14 +268,14 @@ def self.create(options = {}) # } module ThreadEvent def self.create(options = {}) - result = Event.create({ 'event' => 'thread', 'seq' => -1 }) + result = Event.create('event' => 'thread', 'seq' => -1) raise('reason is a required field for ThreadEvent') if options['reason'].nil? raise('threadId is a required field for ThreadEvent') if options['threadId'].nil? - + result['body'] = { 'reason' => options['reason'], - 'threadId' => options['threadId'], + 'threadId' => options['threadId'] } result @@ -301,7 +300,7 @@ def self.create(options = {}) # } module OutputEvent def self.create(options = {}) - result = Event.create({ 'event' => 'output', 'seq' => -1 }) + result = Event.create('event' => 'output', 'seq' => -1) raise('output is a required field for OutputEvent') if options['output'].nil? result['body'] = { 'category' => 'console' } @@ -314,7 +313,6 @@ def self.create(options = {}) end end - # /** Event message for 'exited' event type. # The event indicates that the debuggee has exited. # */ @@ -327,7 +325,7 @@ def self.create(options = {}) # } module ExitedEvent def self.create(options = {}) - result = Event.create({ 'event' => 'exited', 'seq' => -1 }) + result = Event.create('event' => 'exited', 'seq' => -1) raise('exitCode is a required field for ExitedEvent') if options['exitCode'].nil? result['body'] = {} result['body']['exitCode'] = options['exitCode'] @@ -336,7 +334,6 @@ def self.create(options = {}) end end - # /** Launch request; value of command field is 'launch'. */ # export interface LaunchRequest extends Request { # // command: 'launch'; @@ -347,7 +344,7 @@ def self.create(options) result = Request.create(options) raise('command is a required field for InitializeRequest') if options['command'].nil? - result['command'] = options['command'] + result['command'] = options['command'] result['arguments'] = LaunchRequestArguments.create(options['arguments']) unless options['arguments'].nil? result @@ -376,7 +373,6 @@ def self.create_from_request(options, request = nil) end end - # /** SetBreakpoints request; value of command field is 'setBreakpoints'. # Sets multiple breakpoints for a single source and clears all previous breakpoints in that source. # To clear all breakpoint for a source, specify an empty array. @@ -509,7 +505,7 @@ module NextArguments def self.create(options) raise('threadId is a required field for NextArguments') if options['threadId'].nil? - {'threadId' => options['threadId']} + { 'threadId' => options['threadId'] } end end @@ -558,7 +554,7 @@ module StepInArguments def self.create(options) raise('threadId is a required field for StepInArguments') if options['threadId'].nil? - result = {'threadId' => options['threadId']} + result = { 'threadId' => options['threadId'] } result['targetId'] = options['targetId'] unless options['targetId'].nil? result @@ -622,7 +618,7 @@ module StepOutArguments def self.create(options) raise('threadId is a required field for StepOutArguments') if options['threadId'].nil? - {'threadId' => options['threadId']} + { 'threadId' => options['threadId'] } end end @@ -650,7 +646,7 @@ module StackTraceArguments def self.create(options) result = { 'startFrame' => 0, - 'levels' => 0, + 'levels' => 0 } raise('threadId is a required field for StackTraceArguments') if options['threadId'].nil? @@ -663,7 +659,7 @@ def self.create(options) result end end - + # /** Response to 'stackTrace' request. */ # export interface StackTraceResponse extends Response { # body: { @@ -683,7 +679,7 @@ def self.create_from_request(options, request = nil) result['body'] = { 'stackFrames' => options['stackFrames'], - 'totalFrames' => options['stackFrames'].count, + 'totalFrames' => options['stackFrames'].count } result @@ -718,7 +714,7 @@ def self.create(options) module ScopesArguments def self.create(options) raise('frameId is a required field for ScopesArguments') if options['frameId'].nil? - + result = {} result['frameId'] = options['frameId'] @@ -741,7 +737,7 @@ def self.create_from_request(options, request = nil) raise('scopes is a required field for ScopesResponse') if options['scopes'].nil? result['body'] = { - 'scopes' => options['scopes'], + 'scopes' => options['scopes'] } result @@ -785,15 +781,15 @@ def self.create(options) module VariablesArguments def self.create(options) raise('variablesReference is a required field for VariablesArguments') if options['variablesReference'].nil? - + result = {} result['variablesReference'] = options['variablesReference'] - result['filter'] = options['filter'] unless options['filter'].nil? - result['start'] = options['start'] unless options['start'].nil? - result['count'] = options['count'] unless options['count'].nil? - result['format'] = options['format'] unless options['format'].nil? - + result['filter'] = options['filter'] unless options['filter'].nil? + result['start'] = options['start'] unless options['start'].nil? + result['count'] = options['count'] unless options['count'].nil? + result['format'] = options['format'] unless options['format'].nil? + result end end @@ -812,7 +808,7 @@ def self.create_from_request(options, request = nil) raise('variables is a required field for VariablesResponse') if options['variables'].nil? result['body'] = { - 'variables' => options['variables'], + 'variables' => options['variables'] } result @@ -873,14 +869,14 @@ def self.create(options) module EvaluateArguments def self.create(options) raise('expression is a required field for EvaluateArguments') if options['expression'].nil? - + result = {} result['expression'] = options['expression'] result['frameId'] = options['frameId'] unless options['frameId'].nil? result['context'] = options['context'] unless options['context'].nil? result['format'] = options['format'] unless options['format'].nil? - + result end end @@ -910,20 +906,19 @@ def self.create_from_request(options, request = nil) raise('result is a required field for EvaluateResponse') if options['result'].nil? raise('variablesReference is a required field for EvaluateResponse') if options['variablesReference'].nil? - + result['body'] = { 'result' => options['result'], - 'variablesReference' => options['variablesReference'], + 'variablesReference' => options['variablesReference'] } result['body']['type'] = options['type'] unless options['type'].nil? result['body']['namedVariables'] = options['namedVariables'] unless options['namedVariables'].nil? result['body']['indexedVariables'] = options['indexedVariables'] unless options['indexedVariables'].nil? - + result end end - # /** Information about the capabilities of a debug adapter. */ # export interface Capabilities { # /** The debug adapter supports the configurationDoneRequest. */ @@ -1018,7 +1013,7 @@ def self.create_from_request(options, request = nil) raise('breakpoints is a required field for SetBreakpointsResponse') if options['breakpoints'].nil? result['body'] = { - 'breakpoints' => options['breakpoints'], + 'breakpoints' => options['breakpoints'] } result @@ -1157,11 +1152,11 @@ def self.create(options) raise('variablesReference is a required field for Scope') if options['variablesReference'].nil? raise('expensive is a required field for Scope') if options['expensive'].nil? - result['name'] = options['name'] - result['variablesReference'] = options['variablesReference'] - result['expensive'] = options['expensive'] - - ['namedVariables', 'indexedVariables', 'source', 'line', 'column', 'endLine', 'endColumn'].each do |varname| + result['name'] = options['name'] + result['variablesReference'] = options['variablesReference'] + result['expensive'] = options['expensive'] + + %w[namedVariables indexedVariables source line column endLine endColumn].each do |varname| result[varname] = options[varname] unless options[varname].nil? end @@ -1209,8 +1204,8 @@ def self.create(options) result['name'] = options['name'] result['value'] = options['value'] result['variablesReference'] = options['variablesReference'] - - ['type', 'kind', 'evaluateName', 'namedVariables', 'indexedVariables'].each do |varname| + + %w[type kind evaluateName namedVariables indexedVariables'].each do |varname| result[varname] = options[varname] unless options[varname].nil? end @@ -1218,7 +1213,6 @@ def self.create(options) end end - # /** Properties of a breakpoint passed to the setBreakpoints request. */ # export interface SourceBreakpoint { # /** The source line of the breakpoint. */ @@ -1303,6 +1297,5 @@ def self.create(options) result end end - end end diff --git a/lib/languageserver/puppet_version.rb b/lib/languageserver/puppet_version.rb index aa0780c8..46735474 100644 --- a/lib/languageserver/puppet_version.rb +++ b/lib/languageserver/puppet_version.rb @@ -22,7 +22,7 @@ def self.create(options) result['functionsLoaded'] = options['functionsLoaded'] unless options['functionsLoaded'].nil? result['typesLoaded'] = options['typesLoaded'] unless options['typesLoaded'].nil? result['classesLoaded'] = options['classesLoaded'] unless options['classesLoaded'].nil? - + result['languageServerVersion'] = PuppetVSCode.version result diff --git a/lib/puppet-debugserver.rb b/lib/puppet-debugserver.rb index ff0121b8..633be3fc 100644 --- a/lib/puppet-debugserver.rb +++ b/lib/puppet-debugserver.rb @@ -21,7 +21,7 @@ def self.parse(options) ipaddress: '127.0.0.1', stop_on_client_exit: true, connection_timeout: 10, - debug: nil, + debug: nil } opt_parser = OptionParser.new do |opts| @@ -60,11 +60,11 @@ def self.parse(options) end def self.log_message(severity, message) - PuppetVSCode::log_message(severity, message) + PuppetVSCode.log_message(severity, message) end def self.init_puppet(options) - PuppetVSCode::init_logging(options) + PuppetVSCode.init_logging(options) log_message(:info, "Debug Server is v#{PuppetVSCode.version}") true diff --git a/lib/puppet-debugserver/debug_hook_handlers.rb b/lib/puppet-debugserver/debug_hook_handlers.rb index 3818ddb8..92741f1d 100644 --- a/lib/puppet-debugserver/debug_hook_handlers.rb +++ b/lib/puppet-debugserver/debug_hook_handlers.rb @@ -6,22 +6,22 @@ def self.hooks if @hook_handler.nil? @hook_handler = PuppetDebugServer::Hooks.new - @hook_handler.add_hook(:hook_before_apply_exit, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession::on_hook_before_apply_exit(args) } - @hook_handler.add_hook(:hook_breakpoint, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession::hook_breakpoint(args) } - @hook_handler.add_hook(:hook_step_breakpoint, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession::hook_step_breakpoint(args) } - @hook_handler.add_hook(:hook_function_breakpoint, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession::hook_function_breakpoint(args) } - @hook_handler.add_hook(:hook_before_compile, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession::hook_before_compile(args) } - @hook_handler.add_hook(:hook_exception, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession::hook_exception(args) } - @hook_handler.add_hook(:hook_log_message, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession::hook_log_message(args) } - @hook_handler.add_hook(:hook_after_parser_function_reset, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession::hook_after_parser_function_reset(args) } - @hook_handler.add_hook(:hook_before_pops_evaluate, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession::hook_before_pops_evaluate(args) } - @hook_handler.add_hook(:hook_after_pops_evaluate, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession::hook_after_pops_evaluate(args) } + @hook_handler.add_hook(:hook_before_apply_exit, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession.on_hook_before_apply_exit(args) } + @hook_handler.add_hook(:hook_breakpoint, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession.hook_breakpoint(args) } + @hook_handler.add_hook(:hook_step_breakpoint, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession.hook_step_breakpoint(args) } + @hook_handler.add_hook(:hook_function_breakpoint, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession.hook_function_breakpoint(args) } + @hook_handler.add_hook(:hook_before_compile, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession.hook_before_compile(args) } + @hook_handler.add_hook(:hook_exception, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession.hook_exception(args) } + @hook_handler.add_hook(:hook_log_message, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession.hook_log_message(args) } + @hook_handler.add_hook(:hook_after_parser_function_reset, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession.hook_after_parser_function_reset(args) } + @hook_handler.add_hook(:hook_before_pops_evaluate, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession.hook_before_pops_evaluate(args) } + @hook_handler.add_hook(:hook_after_pops_evaluate, :debug_session) { |args| PuppetDebugServer::PuppetDebugSession.hook_after_pops_evaluate(args) } end @hook_handler end def self.hook_before_pops_evaluate(args) - @session_pops_eval_depth = @session_pops_eval_depth + 1 + @session_pops_eval_depth += 1 target = args[1] # Ignore this if there is no positioning information available return unless target.is_a?(Puppet::Pops::Model::Positioned) @@ -36,10 +36,10 @@ def self.hook_before_pops_evaluate(args) # Break if we hit a specific puppet function if target_classname == 'CallNamedFunctionExpression' - # TODO Do we really need to break on a function called breakpoint? + # TODO: Do we really need to break on a function called breakpoint? if target.functor_expr.value == 'breakpoint' # Re-raise the hook as a breakpoint - PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_function_breakpoint, [target.functor_expr.value, ast_classname] +args) + PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_function_breakpoint, [target.functor_expr.value, ast_classname] + args) return else func_names = PuppetDebugServer::PuppetDebugSession.function_breakpoints @@ -47,16 +47,16 @@ def self.hook_before_pops_evaluate(args) next unless func['name'] == target.functor_expr.value # Re-raise the hook as a breakpoint PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_function_breakpoint, [target.functor_expr.value, ast_classname] + args) - return + return # rubocop:disable Lint/NonLocalExitFromIterator end end end - unless target_loc.length == 0 - excluded_classes = ['BlockExpression','HostClassDefinition'] + unless target_loc.length.zero? + excluded_classes = %w[BlockExpression HostClassDefinition] file_path = target_loc.file breakpoints = PuppetDebugServer::PuppetDebugSession.source_breakpoints(file_path) - # TODO should check if it's an object we don't care aount + # TODO: Should check if it's an object we don't care aount unless excluded_classes.include?(target_classname) || breakpoints.nil? || breakpoints.empty? # Calculate the start and end lines of the target target_start_line = target_loc.line @@ -64,11 +64,11 @@ def self.hook_before_pops_evaluate(args) breakpoints.each do |bp| bp_line = bp['line'] - # TODO Hit and conditional BreakPoints? + # TODO: What about Hit and Conditional BreakPoints? if bp_line >= target_start_line && bp_line <= target_end_line # Re-raise the hook as a breakpoint PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_breakpoint, [ast_classname, ''] + args) - return + return # rubocop:disable Lint/NonLocalExitFromIterator end end end @@ -101,7 +101,7 @@ def self.hook_before_pops_evaluate(args) end def self.hook_after_pops_evaluate(args) - @session_pops_eval_depth = @session_pops_eval_depth - 1 + @session_pops_eval_depth -= @session_pops_eval_depth target = args[1] return unless target.is_a?(Puppet::Pops::Model::Positioned) end @@ -109,8 +109,8 @@ def self.hook_after_pops_evaluate(args) def self.hook_after_parser_function_reset(args) func_object = args[0] - # TODO Do we really need to break on a function called breakpoint? - func_object.newfunction(:breakpoint, :type => :rvalue, :arity => -1, :doc => "Breakpoint Function") do |arguments| + # TODO: Do we really need to break on a function called breakpoint? + func_object.newfunction(:breakpoint, :type => :rvalue, :arity => -1, :doc => 'Breakpoint Function') do |arguments| # This function is just a place holder. It gets interpretted at the pops_evaluate hooks but the function # itself still needs to exist though. end @@ -120,10 +120,10 @@ def self.on_hook_before_apply_exit(args) option = args[0] PuppetDebugServer::PuppetDebugSession.connection.send_exited_event(option) - PuppetDebugServer::PuppetDebugSession.connection.send_output_event({ + PuppetDebugServer::PuppetDebugSession.connection.send_output_event( 'category' => 'console', - 'output' => "puppet exited with #{option}", - }) + 'output' => "puppet exited with #{option}" + ) end def self.hook_breakpoint(args) @@ -156,21 +156,22 @@ def self.process_breakpoint_hook(reason, args) end break_description = break_display_text if break_description.empty? - PuppetDebugServer::PuppetDebugSession.raise_and_wait_stopped_event(reason, break_display_text, break_description, { + PuppetDebugServer::PuppetDebugSession.raise_and_wait_stopped_event( + reason, + break_display_text, + break_description, :pops_target => pops_target_object, :scope => scope_object, :pops_depth_level => pops_depth_level, :puppet_stacktrace => Puppet::Pops::PuppetStack.stacktrace - }) + ) end def self.hook_before_compile(args) PuppetDebugServer::PuppetDebugSession.session_compiler = args[0] # Spin-wait for the configurationDone message from the client before we continue compilation - begin - sleep(0.5) - end while !PuppetDebugServer::PuppetDebugSession.client_completed_configuration? + sleep(0.5) until PuppetDebugServer::PuppetDebugSession.client_completed_configuration? end def self.hook_exception(args) @@ -180,14 +181,16 @@ def self.hook_exception(args) error_detail = args[0] PuppetDebugServer::PuppetDebugSession.raise_and_wait_stopped_event( - 'exception', 'Compilation Exception', error_detail.basic_message, { + 'exception', + 'Compilation Exception', + error_detail.basic_message, :session_exception => error_detail, :puppet_stacktrace => Puppet::Pops::PuppetStack.stacktrace_from_backtrace(error_detail) - }) + ) end def self.hook_log_message(args) - return if self.suppress_log_messages + return if suppress_log_messages msg = args[0] str = msg.respond_to?(:multiline) ? msg.multiline : msg.to_s str = msg.source == 'Puppet' ? str : "#{msg.source}: #{str}" @@ -197,10 +200,10 @@ def self.hook_log_message(args) category = 'stderr' category = 'stdout' if msg.level == :notice || msg.level == :info || msg.level == :debug - PuppetDebugServer::PuppetDebugSession.connection.send_output_event({ + PuppetDebugServer::PuppetDebugSession.connection.send_output_event( 'category' => category, 'output' => "#{level}: #{str}\n" - }) + ) end end end diff --git a/lib/puppet-debugserver/hooks.rb b/lib/puppet-debugserver/hooks.rb index e9236f2e..f38b12cf 100644 --- a/lib/puppet-debugserver/hooks.rb +++ b/lib/puppet-debugserver/hooks.rb @@ -1,5 +1,3 @@ -#require 'puppet-debugger/support/errors' - module PuppetDebugServer # This code was inspired from Puppet-Debugger (https://raw.githubusercontent.com/nwops/puppet-debugger/master/lib/puppet-debugger/hooks.rb) which was borrowed from Pry hooks file @@ -77,7 +75,7 @@ def initialize end # Ensure that duplicates have their @hooks object. - def initialize_copy(orig) + def initialize_copy hooks_dup = @hooks.dup @hooks.each do |k, v| hooks_dup[k] = v.dup @@ -96,7 +94,7 @@ def errors # @param [#call] callable The callable. # @yield The block to use as the callable (if no `callable` provided). # @return [PuppetDebugger::Hooks] The receiver. - def add_hook(event_name, hook_name, callable=nil, &block) + def add_hook(event_name, hook_name, callable = nil, &block) event_name = event_name.to_s # do not allow duplicates, but allow multiple `nil` hooks @@ -106,11 +104,11 @@ def add_hook(event_name, hook_name, callable=nil, &block) end if !block && !callable - raise ArgumentError, "Must provide a block or callable." + raise ArgumentError, 'Must provide a block or callable.' end # ensure we only have one anonymous hook - @hooks[event_name].delete_if { |h, k| h.nil? } if hook_name.nil? + @hooks[event_name].delete_if { |h, _k| h.nil? } if hook_name.nil? if block @hooks[event_name] << [hook_name, block] @@ -127,7 +125,7 @@ def add_hook(event_name, hook_name, callable=nil, &block) # @return [Object] The return value of the last executed hook. def exec_hook(event_name, *args, &block) PuppetDebugServer.log_message(:debug, "Starting to executing hook #{event_name}") unless event_name == :hook_log_message - @hooks[event_name.to_s].map do |hook_name, callable| + @hooks[event_name.to_s].map do |_hook_name, callable| begin callable.call(*args, &block) rescue ::RuntimeError => e @@ -148,7 +146,7 @@ def hook_count(event_name) # @param [Symbol] hook_name The name of the hook # @return [#call] a specific hook for a given event. def get_hook(event_name, hook_name) - hook = @hooks[event_name.to_s].find do |current_hook_name, callable| + hook = @hooks[event_name.to_s].find do |current_hook_name, _callable| current_hook_name == hook_name end hook.last if hook @@ -197,8 +195,6 @@ def hook_exists?(event_name, hook_name) protected - def hooks - @hooks - end + attr_reader :hooks end -end \ No newline at end of file +end diff --git a/lib/puppet-debugserver/json_handler.rb b/lib/puppet-debugserver/json_handler.rb index 623659a0..fe7c21a8 100644 --- a/lib/puppet-debugserver/json_handler.rb +++ b/lib/puppet-debugserver/json_handler.rb @@ -74,9 +74,9 @@ def receive_data(data) def send_response(response) # Modify the response - fail('protocol message type was not set to response') unless response['type'] == 'response' + raise('protocol message type was not set to response') unless response['type'] == 'response' response['seq'] = @response_sequence - @response_sequence = @response_sequence + 1 # Not thread safe possibly. It's ok on MRI ruby, not jruby + @response_sequence += @response_sequence # Not thread safe possibly. It's ok on MRI ruby, not jruby response_json = encode_json(response) PuppetDebugServer.log_message(:debug, "--- OUTBOUND\n#{response_json}\n---") @@ -87,9 +87,9 @@ def send_response(response) def send_event(response) # Modify the response - fail('protocol message type was not set to event') unless response['type'] == 'event' + raise('protocol message type was not set to event') unless response['type'] == 'event' response['seq'] = @response_sequence - @response_sequence = @response_sequence + 1 # Not thread safe possibly. It's ok on MRI ruby, not jruby + @response_sequence += 1 # Not thread safe possibly. It's ok on MRI ruby, not jruby response_json = encode_json(response) PuppetDebugServer.log_message(:debug, "--- OUTBOUND\n#{response_json}\n---") @@ -114,7 +114,7 @@ def received_parsed_object(obj) # Batch: multiple requests/notifications in an array. # NOTE: Not implemented as it doesn't make sense using JSON RPC over pure TCP / UnixSocket. else - PuppetDebugServer.log_message(:error, "Closing connection as request is not a Hash") + PuppetDebugServer.log_message(:error, 'Closing connection as request is not a Hash') close_connection_after_writing @state = :ignore end @@ -131,7 +131,7 @@ def process(obj) end # This method must be overriden in the user's inherited class. - def receive_request(request, request_json) + def receive_request(request, _request_json) PuppetDebugServer.log_message(:debug, "request received:\n#{request.inspect}") end diff --git a/lib/puppet-debugserver/message_router.rb b/lib/puppet-debugserver/message_router.rb index e02d3f7d..88ef0fa8 100644 --- a/lib/puppet-debugserver/message_router.rb +++ b/lib/puppet-debugserver/message_router.rb @@ -8,21 +8,25 @@ def send_termination_event obj = PuppetDebugServer::Protocol::TerminatedEvent.create({}) send_event obj end + def send_exited_event(exitcode) - obj = PuppetDebugServer::Protocol::ExitedEvent.create({ 'exitCode' => exitcode }) + obj = PuppetDebugServer::Protocol::ExitedEvent.create('exitCode' => exitcode) send_event obj end + def send_output_event(options) obj = PuppetDebugServer::Protocol::OutputEvent.create(options) send_event obj end + def send_stopped_event(reason, options = {}) options['reason'] = reason obj = PuppetDebugServer::Protocol::StoppedEvent.create(options) send_event obj end + def send_thread_event(reason, thread_id) - obj = PuppetDebugServer::Protocol::ThreadEvent.create({ 'reason' => reason, 'threadId' => thread_id}) + obj = PuppetDebugServer::Protocol::ThreadEvent.create('reason' => reason, 'threadId' => thread_id) send_event obj end @@ -39,34 +43,38 @@ def receive_request(request, original_json) capabilities = PuppetDebugServer::Protocol::Capabilities.create({}) # We can't accept breakpoints at any time so need them upfront capabilities['supportsConfigurationDoneRequest'] = true - capabilities['supportsFunctionBreakpoints'] = true - capabilities['supportsRestartRequest'] = false - capabilities['supportsStepBack'] = false - capabilities['supportsSetVariable'] = true - capabilities['supportsStepInTargetsRequest'] = false - capabilities['supportedChecksumAlgorithms'] = [] + capabilities['supportsFunctionBreakpoints'] = true + capabilities['supportsRestartRequest'] = false + capabilities['supportsStepBack'] = false + capabilities['supportsSetVariable'] = true + capabilities['supportsStepInTargetsRequest'] = false + capabilities['supportedChecksumAlgorithms'] = [] # Do some initialization # .... dum de dum ... - - response = PuppetDebugServer::Protocol::InitializeResponse.create_from_request({ - 'body' => capabilities, - 'success' => true, - }, request) + + response = PuppetDebugServer::Protocol::InitializeResponse.create_from_request( + { + 'body' => capabilities, + 'success' => true + }, request + ) send_response response # Send a message that we are initialized # This must happen _after_ the capabilites are sent sleep(0.5) # Sleep for a small amount of time to give the client time to process the capabilites response send_event PuppetDebugServer::Protocol::InitializedEvent.create - + when 'configurationDone' PuppetDebugServer.log_message(:debug, 'Received configurationDone request.') PuppetDebugServer::PuppetDebugSession.client_completed_configuration = true - response = PuppetDebugServer::Protocol::LaunchResponse.create_from_request({ - 'success' => true, - }, request) + response = PuppetDebugServer::Protocol::LaunchResponse.create_from_request( + { + 'success' => true + }, request + ) send_response response # Start the debug session if the session is not already running and, setup and configuration have completed @@ -78,58 +86,68 @@ def receive_request(request, original_json) bp_response = PuppetDebugServer::PuppetDebugSession.validate_and_set_source_breakpoints(bp_request['arguments']['source'], bp_request['arguments']['breakpoints']) - response = PuppetDebugServer::Protocol::SetBreakpointsResponse.create_from_request({ - 'breakpoints' => bp_response, - 'success' => 'true', - }, request) + response = PuppetDebugServer::Protocol::SetBreakpointsResponse.create_from_request( + { + 'breakpoints' => bp_response, + 'success' => 'true' + }, request + ) send_response response when 'setFunctionBreakpoints' PuppetDebugServer.log_message(:debug, 'Received setFunctionBreakpoints request.') bp_request = PuppetDebugServer::Protocol::SetFunctionBreakpointsRequest.create(original_json) - # TODO for the moment, all Function breakpoints are valid - bp_response = bp_request['arguments']['breakpoints'].each do |bp| + # TODO: for the moment, all Function breakpoints are valid + bp_response = bp_request['arguments']['breakpoints'].map do |bp| bp['verified'] = true bp end PuppetDebugServer::PuppetDebugSession.function_breakpoints = bp_request['arguments']['breakpoints'] - response = PuppetDebugServer::Protocol::SetBreakpointsResponse.create_from_request({ - 'breakpoints' => bp_response, - 'success' => 'true', - }, request) + response = PuppetDebugServer::Protocol::SetBreakpointsResponse.create_from_request( + { + 'breakpoints' => bp_response, + 'success' => 'true' + }, request + ) send_response response when 'launch' PuppetDebugServer.log_message(:debug, 'Received launch request.') - obj = PuppetDebugServer::Protocol::LaunchRequest.create(original_json) - # TODO Do we care about the noDebug? + _obj = PuppetDebugServer::Protocol::LaunchRequest.create(original_json) + # TODO: Do we care about the noDebug? - response = PuppetDebugServer::Protocol::LaunchResponse.create_from_request({ - 'success' => true, - }, request) + response = PuppetDebugServer::Protocol::LaunchResponse.create_from_request( + { + 'success' => true + }, request + ) send_response response # Start the debug session PuppetDebugServer::PuppetDebugSession.setup(self, original_json['arguments']) # Start the debug session if the session is not already running and, setup and configuration have completed PuppetDebugServer::PuppetDebugSession.start if !PuppetDebugServer::PuppetDebugSession.session_active? && PuppetDebugServer::PuppetDebugSession.client_completed_configuration? - + when 'threads' PuppetDebugServer.log_message(:debug, 'Received threads request.') if PuppetDebugServer::PuppetDebugSession.puppet_thread_id.nil? - response = PuppetDebugServer::Protocol::ThreadsResponse.create_from_request({ - 'success' => false, - 'threads' => [], - }, request) + response = PuppetDebugServer::Protocol::ThreadsResponse.create_from_request( + { + 'success' => false, + 'threads' => [] + }, request + ) else - response = PuppetDebugServer::Protocol::ThreadsResponse.create_from_request({ - 'success' => true, - 'threads' => [ { 'id' => PuppetDebugServer::PuppetDebugSession.puppet_thread_id, 'name' => 'puppet' }], - }, request) + response = PuppetDebugServer::Protocol::ThreadsResponse.create_from_request( + { + 'success' => true, + 'threads' => [{ 'id' => PuppetDebugServer::PuppetDebugSession.puppet_thread_id, 'name' => 'puppet' }] + }, request + ) end send_response response @@ -138,18 +156,22 @@ def receive_request(request, original_json) obj = PuppetDebugServer::Protocol::StackTraceRequest.create(original_json) if PuppetDebugServer::PuppetDebugSession.puppet_thread_id.nil? || PuppetDebugServer::PuppetDebugSession.puppet_thread_id != obj['arguments']['threadId'] - response = PuppetDebugServer::Protocol::Response.create_from_request({ - 'success' => false - }, request) + response = PuppetDebugServer::Protocol::Response.create_from_request( + { + 'success' => false + }, request + ) send_response response return end frames = PuppetDebugServer::PuppetDebugSession.generate_stackframe_list(obj['arguments']) - response = PuppetDebugServer::Protocol::StackTraceResponse.create_from_request({ - 'success' => true, - 'stackFrames' => frames, - }, request) + response = PuppetDebugServer::Protocol::StackTraceResponse.create_from_request( + { + 'success' => true, + 'stackFrames' => frames + }, request + ) send_response response when 'scopes' @@ -157,9 +179,11 @@ def receive_request(request, original_json) obj = PuppetDebugServer::Protocol::ScopesRequest.create(original_json) if PuppetDebugServer::PuppetDebugSession.puppet_thread_id.nil? - response = PuppetDebugServer::Protocol::Response.create_from_request({ - 'success' => false - }, request) + response = PuppetDebugServer::Protocol::Response.create_from_request( + { + 'success' => false + }, request + ) send_response response return end @@ -167,19 +191,23 @@ def receive_request(request, original_json) # We only respond to Frame 0 as we don't have the variable state in other # stack frames if obj['arguments']['frameId'] != 0 - response = PuppetDebugServer::Protocol::ScopesResponse.create_from_request({ - 'success' => true, - 'scopes' => [], - }, request) + response = PuppetDebugServer::Protocol::ScopesResponse.create_from_request( + { + 'success' => true, + 'scopes' => [] + }, request + ) send_response response return end scopes = PuppetDebugServer::PuppetDebugSession.generate_scopes_list(obj['arguments']) - response = PuppetDebugServer::Protocol::ScopesResponse.create_from_request({ - 'success' => true, - 'scopes' => scopes, - }, request) + response = PuppetDebugServer::Protocol::ScopesResponse.create_from_request( + { + 'success' => true, + 'scopes' => scopes + }, request + ) send_response response when 'variables' @@ -187,18 +215,22 @@ def receive_request(request, original_json) obj = PuppetDebugServer::Protocol::VariablesRequest.create(original_json) if PuppetDebugServer::PuppetDebugSession.puppet_thread_id.nil? - response = PuppetDebugServer::Protocol::Response.create_from_request({ - 'success' => false - }, request) + response = PuppetDebugServer::Protocol::Response.create_from_request( + { + 'success' => false + }, request + ) send_response response return end variables = PuppetDebugServer::PuppetDebugSession.generate_variable_list(obj['arguments']['variablesReference'], obj['arguments']) - response = PuppetDebugServer::Protocol::VariablesResponse.create_from_request({ - 'success' => true, - 'variables' => variables, - }, request) + response = PuppetDebugServer::Protocol::VariablesResponse.create_from_request( + { + 'success' => true, + 'variables' => variables + }, request + ) send_response response when 'evaluate' @@ -206,9 +238,11 @@ def receive_request(request, original_json) obj = PuppetDebugServer::Protocol::EvaluateRequest.create(original_json) if PuppetDebugServer::PuppetDebugSession.puppet_thread_id.nil? - response = PuppetDebugServer::Protocol::Response.create_from_request({ - 'success' => false - }, request) + response = PuppetDebugServer::Protocol::Response.create_from_request( + { + 'success' => false + }, request + ) send_response response return end @@ -216,9 +250,11 @@ def receive_request(request, original_json) # We only respond to Frame 0 as we don't have the variable state in other # stack frames if obj['arguments']['frameId'] != 0 - response = PuppetDebugServer::Protocol::Response.create_from_request({ - 'success' => true - }, request) + response = PuppetDebugServer::Protocol::Response.create_from_request( + { + 'success' => true + }, request + ) send_response response return end @@ -228,30 +264,36 @@ def receive_request(request, original_json) suppress_log = obj['arguments']['context'] == 'watch' result = PuppetDebugServer::PuppetDebugSession.evaluate_string(obj['arguments']['expression'], suppress_log) - response = PuppetDebugServer::Protocol::EvaluateResponse.create_from_request({ - 'success' => true, - 'result' => result.to_s, - 'variablesReference' => 0, - }, request) + response = PuppetDebugServer::Protocol::EvaluateResponse.create_from_request( + { + 'success' => true, + 'result' => result.to_s, + 'variablesReference' => 0 + }, request + ) send_response response - rescue => exception - response = PuppetDebugServer::Protocol::Response.create_from_request({ - 'success' => false, - 'message' => exception.to_s, - }, request) + rescue => exception # rubocop:disable Style/RescueStandardError + response = PuppetDebugServer::Protocol::Response.create_from_request( + { + 'success' => false, + 'message' => exception.to_s + }, request + ) send_response response end - + when 'continue' PuppetDebugServer.log_message(:debug, 'Received continue request.') # Continue the debug session PuppetDebugServer::PuppetDebugSession.continue_session - response = PuppetDebugServer::Protocol::ContinueResponse.create_from_request({ - 'success' => true, - 'allThreadsContinued' => true, - }, request) + response = PuppetDebugServer::Protocol::ContinueResponse.create_from_request( + { + 'success' => true, + 'allThreadsContinued' => true + }, request + ) send_response response when 'stepIn' @@ -259,9 +301,11 @@ def receive_request(request, original_json) req = PuppetDebugServer::Protocol::StepInRequest.create(original_json) if PuppetDebugServer::PuppetDebugSession.puppet_thread_id.nil? || PuppetDebugServer::PuppetDebugSession.puppet_thread_id != req['arguments']['threadId'] - response = PuppetDebugServer::Protocol::Response.create_from_request({ - 'success' => false - }, request) + response = PuppetDebugServer::Protocol::Response.create_from_request( + { + 'success' => false + }, request + ) send_response response return end @@ -269,16 +313,18 @@ def receive_request(request, original_json) # Stepin the debug session PuppetDebugServer::PuppetDebugSession.continue_stepin_session - send_response PuppetDebugServer::Protocol::StepInResponse.create_from_request({ 'success' => true }, request) + send_response PuppetDebugServer::Protocol::StepInResponse.create_from_request({ 'success' => true }, request) when 'stepOut' PuppetDebugServer.log_message(:debug, 'Received stepOut request.') req = PuppetDebugServer::Protocol::StepOutRequest.create(original_json) if PuppetDebugServer::PuppetDebugSession.puppet_thread_id.nil? || PuppetDebugServer::PuppetDebugSession.puppet_thread_id != req['arguments']['threadId'] - response = PuppetDebugServer::Protocol::Response.create_from_request({ - 'success' => false - }, request) + response = PuppetDebugServer::Protocol::Response.create_from_request( + { + 'success' => false + }, request + ) send_response response return end @@ -286,16 +332,18 @@ def receive_request(request, original_json) # Next the debug session PuppetDebugServer::PuppetDebugSession.continue_stepout_session - send_response PuppetDebugServer::Protocol::StepOutResponse.create_from_request({ 'success' => true }, request) + send_response PuppetDebugServer::Protocol::StepOutResponse.create_from_request({ 'success' => true }, request) when 'next' PuppetDebugServer.log_message(:debug, 'Received next request.') req = PuppetDebugServer::Protocol::NextRequest.create(original_json) if PuppetDebugServer::PuppetDebugSession.puppet_thread_id.nil? || PuppetDebugServer::PuppetDebugSession.puppet_thread_id != req['arguments']['threadId'] - response = PuppetDebugServer::Protocol::Response.create_from_request({ - 'success' => false - }, request) + response = PuppetDebugServer::Protocol::Response.create_from_request( + { + 'success' => false + }, request + ) send_response response return end @@ -303,7 +351,7 @@ def receive_request(request, original_json) # Next the debug session PuppetDebugServer::PuppetDebugSession.continue_next_session - send_response PuppetDebugServer::Protocol::NextResponse.create_from_request({ 'success' => true }, request) + send_response PuppetDebugServer::Protocol::NextResponse.create_from_request({ 'success' => true }, request) when 'disconnect' # Don't really care about the arguments - Kill everything @@ -313,10 +361,12 @@ def receive_request(request, original_json) else PuppetDebugServer.log_message(:error, "Unknown request command #{request['command']}") - response = PuppetDebugServer::Protocol::Response.create_from_request({ - 'success' => false, - 'message' => "This feature is not supported - Request #{request['command']}", - }, request) + response = PuppetDebugServer::Protocol::Response.create_from_request( + { + 'success' => false, + 'message' => "This feature is not supported - Request #{request['command']}" + }, request + ) send_response response end end diff --git a/lib/puppet-debugserver/puppet_debug_breakpoints.rb b/lib/puppet-debugserver/puppet_debug_breakpoints.rb index b11d7ff1..6bd0de8a 100644 --- a/lib/puppet-debugserver/puppet_debug_breakpoints.rb +++ b/lib/puppet-debugserver/puppet_debug_breakpoints.rb @@ -2,25 +2,22 @@ module PuppetDebugServer module PuppetDebugSession @session_function_breakpoints = [] @session_source_breakpoints = {} - + def self.function_breakpoints=(value) - @session_mutex.synchronize { - @session_function_breakpoints = value - } + @session_mutex.synchronize { @session_function_breakpoints = value } end + def self.function_breakpoints value = nil - @session_mutex.synchronize { - value = @session_function_breakpoints.dup - } + @session_mutex.synchronize { value = @session_function_breakpoints.dup } value end def self.source_breakpoints(filename) value = nil - @session_mutex.synchronize { + @session_mutex.synchronize do value = @session_source_breakpoints[filename].dup unless @session_source_breakpoints[filename].nil? - } + end value end @@ -32,8 +29,8 @@ def self.validate_and_set_source_breakpoints(filesource, breakpoints) file_path = File.expand_path(filesource['path']) # Rub-ify the filepath. Important on Windows platforms. file_contents = nil - if File.exists?(file_path) - # TODO Need to guard against big files + if File.exist?(file_path) + # TODO: Need to guard against big files file_contents = File.readlines(file_path) end @@ -48,7 +45,7 @@ def self.validate_and_set_source_breakpoints(filesource, breakpoints) line_text = nil line_num = bp['line'] - # TODO factor in zero based line numbers + # TODO: Factor in zero based line numbers line_text = file_contents[line_num - 1] unless line_num.nil? line_text = '' if line_text.nil? # Strip whitespace @@ -58,7 +55,7 @@ def self.validate_and_set_source_breakpoints(filesource, breakpoints) if line_text.empty? verified = false - message = "Line does not exist or is blank" + message = 'Line does not exist or is blank' else verified = true end @@ -67,22 +64,19 @@ def self.validate_and_set_source_breakpoints(filesource, breakpoints) verified = false if verified.nil? # Generate a BreakPoint response object - bpr = PuppetDebugServer::Protocol::Breakpoint.create({ + bpr = PuppetDebugServer::Protocol::Breakpoint.create( 'verified' => verified, - 'message' => message, - }) + 'message' => message + ) bp_response << bpr # Add to the list of breakpoints we should use bp_list << bp if verified end - @session_mutex.synchronize { - @session_source_breakpoints[file_path] = bp_list - } + @session_mutex.synchronize { @session_source_breakpoints[file_path] = bp_list } bp_response end - end end diff --git a/lib/puppet-debugserver/puppet_debug_session.rb b/lib/puppet-debugserver/puppet_debug_session.rb index c1741e11..6b96d8ae 100644 --- a/lib/puppet-debugserver/puppet_debug_session.rb +++ b/lib/puppet-debugserver/puppet_debug_session.rb @@ -8,11 +8,11 @@ module PuppetDebugSession @session_options = {} @session_paused = false @session_suppress_log_messages = false - @session_mutex = Mutex.new() + @session_mutex = Mutex.new @session_evaluating_parser = nil - @session_compiler = nil # TODO Not sure we need this + @session_compiler = nil # TODO: Not sure we need this @session_paused_state = {} @session_variables_cache = {} @@ -28,6 +28,7 @@ def self.setup(connection_object, options = {}) @connection = connection_object @session_options = options end + def self.setup? !@connection.nil? end @@ -35,6 +36,7 @@ def self.setup? def self.client_completed_configuration=(value) @configuration_completed = value end + def self.client_completed_configuration? @configuration_completed end @@ -50,63 +52,58 @@ def self.clear_paused_state end def self.pause_session - @session_mutex.synchronize { + @session_mutex.synchronize do @session_paused = true - } + end end def self.continue_session - @session_mutex.synchronize { + @session_mutex.synchronize do @session_paused = false @session_run_mode = { :value => :run, :options => {} } clear_paused_state - } + end end def self.continue_stepin_session - @session_mutex.synchronize { + @session_mutex.synchronize do @session_paused = false @session_run_mode = { :value => :stepin, :options => {} } clear_paused_state - } + end end def self.continue_stepout_session - @session_mutex.synchronize { + @session_mutex.synchronize do @session_paused = false @session_run_mode = { :value => :stepout, :options => { :pops_depth_level => @session_paused_state[:pops_depth_level] } } clear_paused_state - } + end end def self.continue_next_session - @session_mutex.synchronize { + @session_mutex.synchronize do @session_paused = false @session_run_mode = { :value => :next, :options => { :pops_depth_level => @session_paused_state[:pops_depth_level] } } clear_paused_state - } + end end def self.run_mode value = nil - @session_mutex.synchronize { - value = @session_run_mode[:value] - } + @session_mutex.synchronize { value = @session_run_mode[:value] } value end + def self.run_mode_options value = nil - @session_mutex.synchronize { - value = @session_run_mode[:options] - } + @session_mutex.synchronize { value = @session_run_mode[:options] } value end def self.session_paused? paused_value = nil - @session_mutex.synchronize { - paused_value = @session_paused - } + @session_mutex.synchronize { paused_value = @session_paused } paused_value end # END Session flow methods @@ -117,15 +114,12 @@ def self.session_compiler=(value) def self.suppress_log_messages value = false - @session_mutex.synchronize { - value = @session_suppress_log_messages - } + @session_mutex.synchronize { value = @session_suppress_log_messages } value end + def self.suppress_log_messages=(value) - @session_mutex.synchronize { - @session_suppress_log_messages = value - } + @session_mutex.synchronize { @session_suppress_log_messages = value } end def self.session_active? @@ -160,16 +154,15 @@ def self.raise_and_wait_stopped_event(reason, description, text, options = {}) @session_paused_state[:scope] = options[:scope] unless options[:scope].nil? @session_paused_state[:pops_depth_level] = options[:pops_depth_level] unless options[:pops_depth_level].nil? - PuppetDebugServer::PuppetDebugSession.connection.send_stopped_event(reason, { + PuppetDebugServer::PuppetDebugSession.connection.send_stopped_event( + reason, 'description' => description, 'text' => text, - 'threadId' => PuppetDebugServer::PuppetDebugSession.puppet_thread_id, - }) + 'threadId' => PuppetDebugServer::PuppetDebugSession.puppet_thread_id + ) # Spin-wait for the session to be unpaused... - begin - sleep(0.5) - end while PuppetDebugServer::PuppetDebugSession.session_paused? + sleep(0.5) while PuppetDebugServer::PuppetDebugSession.session_paused? end def self.start @@ -180,7 +173,7 @@ def self.start @puppet_thread = Thread.new do begin PuppetDebugServer::PuppetDebugSession.start_puppet - rescue => err + rescue => err # rubocop:disable Style/RescueStandardError PuppetDebugServer.log_message(:error, "Error in Puppet Thread: #{err}") raise end @@ -191,7 +184,7 @@ def self.start @watcher_thread = Thread.new do begin PuppetDebugServer::PuppetDebugSession.debug_session_watcher - rescue => err + rescue => err # rubocop:disable Style/RescueStandardError PuppetDebugServer.log_message(:error, "Error in Watcher Thread: #{err}") raise end @@ -210,8 +203,6 @@ def self.stop def self.variable_from_ruby_object(name, value) var_ref = 0 - named_variables = nil - indexed_variables = nil out_value = value.to_s if value.is_a?(Array) @@ -228,16 +219,16 @@ def self.variable_from_ruby_object(name, value) @session_variables_cache[var_ref] = value end - PuppetDebugServer::Protocol::Variable.create({ - 'name' => name, - 'value' => out_value, - 'variablesReference' => var_ref, - }) + PuppetDebugServer::Protocol::Variable.create( + 'name' => name, + 'value' => out_value, + 'variablesReference' => var_ref + ) end def self.variable_list_from_hash(obj_hash = {}) result = [] - obj_hash.sort.each do |key,value| + obj_hash.sort.each do |key, value| result << variable_from_ruby_object(key, value) end @@ -253,7 +244,7 @@ def self.variable_list_from_array(obj_array = []) result end - def self.generate_variable_list(variable_reference, options = {}) + def self.generate_variable_list(variable_reference, _options = {}) result = nil # Check if this is the topscope @@ -271,50 +262,50 @@ def self.generate_variable_list(variable_reference, options = {}) # Could be a child scope if result.nil? && !@session_paused_state[:scope].nil? this_scope = @session_paused_state[:scope] - begin + until this_scope.nil? || this_scope.is_topscope? if this_scope.object_id == variable_reference result = variable_list_from_hash(this_scope.to_hash(false)) break end this_scope = this_scope.parent - end while !(this_scope.nil? || this_scope.is_topscope?) + end end - # TODO Add paging + # TODO: Add paging result || [] end VARIABLE_REFERENCE_TOP_SCOPE = 1 - def self.generate_scopes_list(options = {}) + def self.generate_scopes_list(_options = {}) result = [] unless @session_paused_state[:scope].nil? this_scope = @session_paused_state[:scope] - begin - result << PuppetDebugServer::Protocol::Scope.create({ - 'name' => this_scope.to_s, + until this_scope.nil? || this_scope.is_topscope? + result << PuppetDebugServer::Protocol::Scope.create( + 'name' => this_scope.to_s, 'variablesReference' => this_scope.object_id, - 'namedVariables' => this_scope.to_hash(false).count, - 'expensive' => false, - }) + 'namedVariables' => this_scope.to_hash(false).count, + 'expensive' => false + ) this_scope = this_scope.parent - end while !(this_scope.nil? || this_scope.is_topscope?) + end end unless @session_compiler.nil? - result << PuppetDebugServer::Protocol::Scope.create({ - 'name' => @session_compiler.topscope.to_s, + result << PuppetDebugServer::Protocol::Scope.create( + 'name' => @session_compiler.topscope.to_s, 'variablesReference' => VARIABLE_REFERENCE_TOP_SCOPE, - 'namedVariables' => @session_compiler.topscope.to_hash(false).count, - 'expensive' => false, - }) + 'namedVariables' => @session_compiler.topscope.to_hash(false).count, + 'expensive' => false + ) end result end - def self.generate_stackframe_list(options = {}) + def self.generate_stackframe_list(_options = {}) stack_frames = [] # Generate StackFrame for a Pops::Evaluator object with location information @@ -322,25 +313,25 @@ def self.generate_stackframe_list(options = {}) target = @session_paused_state[:pops_target] frame = { - 'id' => stack_frames.count, - 'name' => get_puppet_class_name(target), - 'line' => 0, - 'column' => 0, + 'id' => stack_frames.count, + 'name' => get_puppet_class_name(target), + 'line' => 0, + 'column' => 0 } - # TODO need to check on the client capabilities of zero or one based indexes + # TODO: Need to check on the client capabilities of zero or one based indexes if target.is_a?(Puppet::Pops::Model::Positioned) - # TODO - Potential issue here with 4.10.x not implementing .file on the Positioned class - frame['source'] = PuppetDebugServer::Protocol::Source.create({ - 'path' => target.file, - }) - frame['name'] = target.file - frame['line'] = target.line + # TODO: Potential issue here with 4.10.x not implementing .file on the Positioned class + frame['source'] = PuppetDebugServer::Protocol::Source.create( + 'path' => target.file + ) + frame['name'] = target.file + frame['line'] = target.line frame['column'] = target.pos || 0 - if target.length > 0 + if target.length > 0 # rubocop:disable Style/ZeroLengthPredicate end_offset = target.offset + target.length - frame['endLine'] = target.locator.line_for_offset(end_offset) + frame['endLine'] = target.locator.line_for_offset(end_offset) frame['endColumn'] = target.locator.pos_on_line(end_offset) end end @@ -352,19 +343,19 @@ def self.generate_stackframe_list(options = {}) unless @session_paused_state[:exception].nil? err = @session_paused_state[:exception] frame = { - 'id' => stack_frames.count, - 'name' => err.class.to_s, - 'line' => 0, - 'column' => 0, + 'id' => stack_frames.count, + 'name' => err.class.to_s, + 'line' => 0, + 'column' => 0 } - # TODO need to check on the client capabilities of zero or one based indexes - # TODO - Potential issue here with 4.10.x not implementing .file on the Positioned class + # TODO: Need to check on the client capabilities of zero or one based indexes + # TODO: Potential issue here with 4.10.x not implementing .file on the Positioned class unless err.file.nil? || err.line.nil? - frame['source'] = PuppetDebugServer::Protocol::Source.create({ - 'path' => err.file, - }) - frame['line'] = err.line + frame['source'] = PuppetDebugServer::Protocol::Source.create( + 'path' => err.file + ) + frame['line'] = err.line frame['column'] = err.pos || 0 end @@ -375,17 +366,17 @@ def self.generate_stackframe_list(options = {}) unless @session_paused_state[:puppet_stacktrace].nil? @session_paused_state[:puppet_stacktrace].each do |pup_stack| source_file = pup_stack[0] - # TODO need to check on the client capabilities of zero or one based indexes + # TODO: Need to check on the client capabilities of zero or one based indexes source_line = pup_stack[1] frame = { 'id' => stack_frames.count, - 'name' => "#{source_file}", - 'source' => PuppetDebugServer::Protocol::Source.create({ - 'path' => source_file, - }), + 'name' => source_file.to_s, + 'source' => PuppetDebugServer::Protocol::Source.create( + 'path' => source_file + ), 'line' => source_line, - 'column' => 0, + 'column' => 0 } stack_frames << frame end @@ -402,7 +393,7 @@ def self.reset_pops_eval_depth # Private methods def self.get_location_from_pops_object(obj) - pos = SourcePosition.new() + pos = SourcePosition.new return pos unless obj.is_a?(Puppet::Pops::Model::Positioned) if obj.respond_to?(:file) && obj.respond_to?(:line) @@ -414,14 +405,17 @@ def self.get_location_from_pops_object(obj) else # Revert to Puppet 4.x location information. A little more expensive to call obj_loc = Puppet::Pops::Utils.find_closest_positioned(obj) - pos.file = obj_loc.locator.file - pos.line = obj_loc.line - pos.offset = obj_loc.offset - pos.length = obj_loc.length + unless obj_loc.nil? + pos.file = obj_loc.locator.file + pos.line = obj_loc.line + pos.offset = obj_loc.offset + pos.length = obj_loc.length + end end pos end + private_class_method :get_location_from_pops_object def self.get_puppet_class_name(obj) # Puppet 5 has PCore Types @@ -430,6 +424,7 @@ def self.get_puppet_class_name(obj) # e.g. Puppet::Pops::Model::CallNamedFunctionExpression becomes CallNamedFunctionExpression obj.class.to_s.split('::').last end + private_class_method :get_puppet_class_name def self.get_ast_class_name(obj) # Puppet 5 has PCore Types @@ -437,6 +432,7 @@ def self.get_ast_class_name(obj) # .. otherwise revert to Pops classname obj.class.to_s end + private_class_method :get_ast_class_name def self.line_for_offset(obj, offset) # Puppet 5 exposes the source locator on the Pops object @@ -446,6 +442,7 @@ def self.line_for_offset(obj, offset) obj_loc = Puppet::Pops::Utils.find_closest_positioned(obj) obj_loc.locator.line_for_offset(offset) end + private_class_method :line_for_offset def self.debug_session_watcher loop do @@ -455,7 +452,7 @@ def self.debug_session_watcher # Raise ThreadStop event connection.send_thread_event('exited', puppet_thread_id) PuppetDebugServer.log_message(:info, 'Puppet Debug session is no longer running. Sending termination event') - # TODO Do we need the termination? + # TODO: Do we need the termination? connection.send_termination_event break end @@ -464,23 +461,23 @@ def self.debug_session_watcher def self.start_puppet # Run puppet - cmd_args = ['apply',@session_options['manifest'],'--detailed-exitcodes','--logdest','debugserver'] + cmd_args = ['apply', @session_options['manifest'], '--detailed-exitcodes', '--logdest', 'debugserver'] cmd_args << '--noop' if @session_options['noop'] == true cmd_args.push(*@session_options['args']) unless @session_options['args'].nil? reset_pops_eval_depth # Send experimental warning - PuppetDebugServer::PuppetDebugSession.connection.send_output_event({ + PuppetDebugServer::PuppetDebugSession.connection.send_output_event( 'category' => 'console', - 'output' => "**************************************************\n* The Puppet debugger is an experimental feature *\n* Debug Server v#{PuppetVSCode.version} *\n**************************************************\n\n", - }) + 'output' => "**************************************************\n* The Puppet debugger is an experimental feature *\n* Debug Server v#{PuppetVSCode.version} *\n**************************************************\n\n" + ) - PuppetDebugServer::PuppetDebugSession.connection.send_output_event({ + PuppetDebugServer::PuppetDebugSession.connection.send_output_event( 'category' => 'console', - 'output' => 'puppet ' + cmd_args.join(' ') + "\n", - }) - Puppet::Util::CommandLine.new('puppet.rb',cmd_args).execute + 'output' => 'puppet ' + cmd_args.join(' ') + "\n" + ) + Puppet::Util::CommandLine.new('puppet.rb', cmd_args).execute end class SourcePosition diff --git a/lib/puppet-debugserver/puppet_monkey_patches.rb b/lib/puppet-debugserver/puppet_monkey_patches.rb index 3cd0ee78..a46d5a7d 100644 --- a/lib/puppet-debugserver/puppet_monkey_patches.rb +++ b/lib/puppet-debugserver/puppet_monkey_patches.rb @@ -1,11 +1,14 @@ # Monkey patch the Apply application (puppet apply) so that we route the exit # statement into the debugger first and then exit the puppet thread require 'puppet/application/apply' -class Puppet::Application::Apply < Puppet::Application - def exit(option) - - PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_before_apply_exit, [option]) - Thread.exit +module Puppet + class Application + class Apply < Puppet::Application + def exit(option) + PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_before_apply_exit, [option]) + Thread.exit + end + end end end @@ -13,102 +16,125 @@ def exit(option) # to trap any exceptions that may be of interest to us # This is a very invasive patch and should be looked at to see if we can do this # a different way +# +# These come from the original Puppet source +# rubocop:disable Style/NegatedIf, Style/TrailingCommaInLiteral, Style/StringLiterals, Style/HashSyntax require 'puppet/parser/compiler' -class Puppet::Parser::Compiler - def self.compile(node, code_id = nil) - begin - # Based on puppet/lib/puppet/parser/compiler.rb - begin - node.environment.check_for_reparse - - errors = node.environment.validation_errors - if !errors.empty? - errors.each { |e| Puppet.err(e) } if errors.size > 1 - errmsg = [ - "Compilation has been halted because: #{errors.first}", - "For more information, see https://docs.puppet.com/puppet/latest/reference/environments.html", - ] - raise(Puppet::Error, errmsg.join(' ')) +module Puppet + module Parser + class Compiler + def self.compile(node, code_id = nil) + # Based on puppet/lib/puppet/parser/compiler.rb + begin + node.environment.check_for_reparse + + errors = node.environment.validation_errors + if !errors.empty? + errors.each { |e| Puppet.err(e) } if errors.size > 1 + errmsg = [ + "Compilation has been halted because: #{errors.first}", + "For more information, see https://docs.puppet.com/puppet/latest/reference/environments.html", + ] + raise(Puppet::Error, errmsg.join(' ')) + end + # This differs from Puppet's implementation as we need the compiler object later + new_compiler = new(node, :code_id => code_id) + + # Add hook for before compilation + PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_before_compile, [new_compiler]) + + result = new_compiler.compile(&:to_resource) + + # Add hook for after compilation + PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_after_compile, [result]) + + result + rescue Puppet::ParseErrorWithIssue => detail + detail.node = node.name + Puppet.log_exception(detail) + raise + rescue => detail # rubocop:disable Style/RescueStandardError + message = "#{detail} on node #{node.name}" + Puppet.log_exception(detail, message) + raise Puppet::Error, message, detail.backtrace end - # This differs from Puppet's implementation as we need the compiler object later - new_compiler = new(node, :code_id => code_id) - - # Add hook for before compilation - PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_before_compile, [new_compiler]) - - result = new_compiler.compile {|resulting_catalog| resulting_catalog.to_resource } - - # Add hook for after compilation - PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_after_compile, [result]) - - result rescue Puppet::ParseErrorWithIssue => detail - detail.node = node.name - Puppet.log_exception(detail) + # TODO: Potential issue here with 4.10.x not implementing .file on the Positioned class + # Just re-raise if there is no Puppet manifest file associated with the error + raise if detail.file.nil? || detail.line.nil? || detail.pos.nil? + PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_exception, [detail]) raise - rescue => detail - message = "#{detail} on node #{node.name}" - Puppet.log_exception(detail, message) - raise Puppet::Error, message, detail.backtrace end - rescue Puppet::ParseErrorWithIssue => detail - # TODO - Potential issue here with 4.10.x not implementing .file on the Positioned class - # Just re-raise if there is no Puppet manifest file associated with the error - raise if detail.file.nil? || detail.line.nil? || detail.pos.nil? - PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_exception, [detail]) - raise end end end +# rubocop:enable Style/NegatedIf, Style/TrailingCommaInLiteral, Style/StringLiterals, Style/HashSyntax +# These come from the original Puppet source +# rubocop:disable Style/PerlBackrefs, Style/EachWithObject +# # Add a helper method to the PuppetStack object require 'puppet/pops/puppet_stack' -module Puppet::Pops::PuppetStack - # This is very similar to the stacktrace function, but uses the exception - # backtrace instead of caller() - def self.stacktrace_from_backtrace(exception) - exception.backtrace.reduce([]) do |memo, loc| - if loc =~ /^(.*\.pp)?:([0-9]+):in (`stack'|`block in call_function')/ - memo << [$1.nil? ? 'unknown' : $1, $2.to_i] +module Puppet + module Pops + module PuppetStack + # This is very similar to the stacktrace function, but uses the exception + # backtrace instead of caller() + def self.stacktrace_from_backtrace(exception) + exception.backtrace.reduce([]) do |memo, loc| + if loc =~ /^(.*\.pp)?:([0-9]+):in (`stack'|`block in call_function')/ + memo << [$1.nil? ? 'unknown' : $1, $2.to_i] + end + memo + end end - memo end end end +# rubocop:enable Style/PerlBackrefs, Style/EachWithObject # Add hooks to the evaluator so we can trap before and after evaluating parts of the # syntax tree require 'puppet/pops/evaluator/evaluator_impl' -class Puppet::Pops::Evaluator::EvaluatorImpl - alias_method :original_evaluate, :evaluate - - def evaluate(target, scope) +module Puppet + module Pops + module Evaluator + class EvaluatorImpl + alias_method :original_evaluate, :evaluate - PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_before_pops_evaluate, [self, target, scope]) + def evaluate(target, scope) + PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_before_pops_evaluate, [self, target, scope]) - result = original_evaluate(target, scope) + result = original_evaluate(target, scope) - PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_after_pops_evaluate, [self, target, scope]) + PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_after_pops_evaluate, [self, target, scope]) - result + result + end + end + end end end # Add hooks to the functions reset so that we can do things like # add a breakpoint function dynamically, without the need for a real puppet module require 'puppet/parser/functions' -module Puppet::Parser::Functions - class << self - alias_method :original_reset, :reset +module Puppet + module Parser + module Functions + class << self + alias_method :original_reset, :reset - def reset - PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_before_parser_function_reset, [self]) + def reset + PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_before_parser_function_reset, [self]) - result = original_reset + result = original_reset - PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_after_parser_function_reset, [self]) + PuppetDebugServer::PuppetDebugSession.hooks.exec_hook(:hook_after_parser_function_reset, [self]) - result + result + end + end end end end diff --git a/lib/puppet-languageserver.rb b/lib/puppet-languageserver.rb index 11cbbba9..62a6ae80 100644 --- a/lib/puppet-languageserver.rb +++ b/lib/puppet-languageserver.rb @@ -5,8 +5,8 @@ require 'languageserver/languageserver' require 'puppet-vscode' - %w[json_rpc_handler message_router server_capabilities document_validator puppet_parser_helper puppet_helper - facter_helper completion_provider hover_provider definition_provider puppet_monkey_patches].each do |lib| + %w[json_rpc_handler message_router server_capabilities document_validator puppet_parser_helper puppet_helper + facter_helper completion_provider hover_provider definition_provider puppet_monkey_patches].each do |lib| begin require "puppet-languageserver/#{lib}" rescue LoadError @@ -68,7 +68,7 @@ def self.parse(options) args[:fast_start_tcpserver] = false end - opts.on('--stdio', "Runs the server in stdio mode, without a TCP listener") do |_misc| + opts.on('--stdio', 'Runs the server in stdio mode, without a TCP listener') do |_misc| args[:stdio] = true end @@ -93,11 +93,11 @@ def self.parse(options) end def self.log_message(severity, message) - PuppetVSCode::log_message(severity, message) + PuppetVSCode.log_message(severity, message) end def self.init_puppet(options) - PuppetVSCode::init_logging(options) + PuppetVSCode.init_logging(options) log_message(:info, "Language Server is v#{PuppetVSCode.version}") log_message(:info, "Using Puppet v#{Puppet.version}") diff --git a/lib/puppet-languageserver/definition_provider.rb b/lib/puppet-languageserver/definition_provider.rb index 4e4f4c25..0c63e288 100644 --- a/lib/puppet-languageserver/definition_provider.rb +++ b/lib/puppet-languageserver/definition_provider.rb @@ -12,7 +12,7 @@ def self.find_definition(content, line_num, char_num) case item.class.to_s when 'Puppet::Pops::Model::CallNamedFunctionExpression' func_name = item.functor_expr.value - response << function_name(resource_name) + response << function_name(func_name) when 'Puppet::Pops::Model::LiteralString' # LiteralString could be anything. Context is the key here @@ -23,10 +23,10 @@ def self.find_definition(content, line_num, char_num) # class { 'testclass': <--- testclass would be the LiteralString inside a ResourceBody # } if !parent.nil? && - parent.class.to_s == 'Puppet::Pops::Model::ResourceBody' && - parent.title.value == item.value - resource_name = item.value - response << type_or_class(resource_name) + parent.class.to_s == 'Puppet::Pops::Model::ResourceBody' && + parent.title.value == item.value + resource_name = item.value + response << type_or_class(resource_name) end when 'Puppet::Pops::Model::QualifiedName' @@ -35,10 +35,10 @@ def self.find_definition(content, line_num, char_num) # What if it's a function name. Then the Qualified name must be the same as the function name if !parent.nil? && - parent.class.to_s == 'Puppet::Pops::Model::CallNamedFunctionExpression' && - parent.functor_expr.value == item.value - func_name = item.value - response << function_name(func_name) + parent.class.to_s == 'Puppet::Pops::Model::CallNamedFunctionExpression' && + parent.functor_expr.value == item.value + func_name = item.value + response << function_name(func_name) end # What if it's an "include " call if !parent.nil? && parent.class.to_s == 'Puppet::Pops::Model::CallNamedFunctionExpression' && parent.functor_expr.value == 'include' @@ -62,37 +62,37 @@ def self.find_definition(content, line_num, char_num) response.compact end - private def self.type_or_class(resource_name) # Strip the leading double-colons for root resource names resource_name = resource_name.slice(2, resource_name.length - 2) if resource_name.start_with?('::') location = PuppetLanguageServer::PuppetHelper.type_load_info(resource_name) location = PuppetLanguageServer::PuppetHelper.class_load_info(resource_name) if location.nil? unless location.nil? - return LanguageServer::Location.create({ + return LanguageServer::Location.create( 'uri' => 'file:///' + location['source'], 'fromline' => location['line'], 'fromchar' => 0, 'toline' => location['line'], - 'tochar' => 1024, - }) + 'tochar' => 1024 + ) end nil end + private_class_method :type_or_class def self.function_name(func_name) location = PuppetLanguageServer::PuppetHelper.function_load_info(func_name) unless location.nil? - return LanguageServer::Location.create({ + return LanguageServer::Location.create( 'uri' => 'file:///' + location['source'], 'fromline' => location['line'], 'fromchar' => 0, 'toline' => location['line'], - 'tochar' => 1024, - }) + 'tochar' => 1024 + ) end nil end - + private_class_method :function_name end end diff --git a/lib/puppet-languageserver/document_validator.rb b/lib/puppet-languageserver/document_validator.rb index 2ed025e0..21285cd4 100644 --- a/lib/puppet-languageserver/document_validator.rb +++ b/lib/puppet-languageserver/document_validator.rb @@ -77,6 +77,7 @@ def self.validate(content, workspace, _max_problems = 100) rescue StandardError => _exception # If anything catastrophic happens we resort to puppet parsing anyway end + # rubocop:enable Lint/HandleExceptions # TODO: Should I wrap this thing in a big rescue block? Puppet[:code] = content @@ -92,7 +93,7 @@ def self.validate(content, workspace, _max_problems = 100) detail = detail.cause if !detail.respond_to?(:line) && detail.respond_to?(:cause) ex_line = detail.respond_to?(:line) && !detail.line.nil? ? detail.line - 1 : nil # Line numbers from puppet exceptions are base 1 ex_pos = detail.respond_to?(:pos) && !detail.pos.nil? ? detail.pos : nil # Pos numbers from puppet are base 1 - + message = detail.respond_to?(:message) ? detail.message : nil message = detail.basic_message if message.nil? && detail.respond_to?(:basic_message) diff --git a/lib/puppet-languageserver/message_router.rb b/lib/puppet-languageserver/message_router.rb index 81fe776f..fe2f52f7 100644 --- a/lib/puppet-languageserver/message_router.rb +++ b/lib/puppet-languageserver/message_router.rb @@ -37,7 +37,7 @@ def self.write_crash_file(err, filename = nil, additional = {}) facter_version = Facter.version rescue 'Unknown' # rubocop:disable Lint/RescueWithoutErrorClass, Style/RescueModifier languageserver_version = PuppetLanguageServer.version rescue 'Unknown' # rubocop:disable Lint/RescueWithoutErrorClass, Style/RescueModifier - # rubocop:disable Layout/IndentHeredoc + # rubocop:disable Layout/IndentHeredoc, Style/FormatStringToken crashtext = <<-TEXT Puppet Language Server Crash File -=--=--=--=--=--=--=--=--=--=--=- @@ -54,7 +54,7 @@ def self.write_crash_file(err, filename = nil, additional = {}) #{err.backtrace.join("\n")} TEXT - # rubocop:enable Layout/IndentHeredoc + # rubocop:enable Layout/IndentHeredoc, Style/FormatStringToken # Append the documents in the cache PuppetLanguageServer::DocumentStore.document_uris.each do |uri| @@ -67,7 +67,7 @@ def self.write_crash_file(err, filename = nil, additional = {}) crash_file = filename.nil? ? default_crash_file : filename File.open(crash_file, 'wb') { |file| file.write(crashtext) } - rescue # rubocop:disable Lint/RescueWithoutErrorClass, Lint/HandleExceptions + rescue # rubocop:disable Style/RescueStandardError, Lint/HandleExceptions # Swallow all errors. Errors in the error handler should not # terminate the application end @@ -192,11 +192,10 @@ def receive_request(request) char_num = request.params['position']['character'] content = documents.document(file_uri) begin - #raise "Not Implemented" request.reply_result(PuppetLanguageServer::DefinitionProvider.find_definition(content, line_num, char_num)) rescue StandardError => exception PuppetLanguageServer.log_message(:error, "(textDocument/definition) #{exception}") - request.reply_result($null) + request.reply_result(nil) end else diff --git a/lib/puppet-languageserver/puppet_helper.rb b/lib/puppet-languageserver/puppet_helper.rb index c1d76fdd..a6c0c5e8 100644 --- a/lib/puppet-languageserver/puppet_helper.rb +++ b/lib/puppet-languageserver/puppet_helper.rb @@ -200,10 +200,9 @@ def self._load_classes module_path_list << File.join(Puppet.settings[:environmentpath], Puppet.settings[:environment], 'modules') unless Puppet.settings[:environment].nil? module_path_list.concat(Pathname.new(Puppet.settings[:environmentpath]) - .children - .select { |c| c.directory? } - .collect { |c| File.join(c, 'modules') } - ) + .children + .select { |c| c.directory? } + .collect { |c| File.join(c, 'modules') }) end module_path_list.uniq! PuppetLanguageServer.log_message(:debug, "[PuppetHelper::_load_classes] Loading classes from #{module_path_list}") @@ -211,14 +210,14 @@ def self._load_classes # Find all of the manifest paths for all of the modules... manifest_path_list = [] module_path_list.each do |module_path| - next unless File.exists?(module_path) + next unless File.exist?(module_path) Pathname.new(module_path) - .children - .select { |c| c.directory? } - .each do |module_filepath| - manifest_path = File.join(module_filepath,'manifests') - manifest_path_list << manifest_path if File.exists?(manifest_path) - end + .children + .select { |c| c.directory? } + .each do |module_filepath| + manifest_path = File.join(module_filepath, 'manifests') + manifest_path_list << manifest_path if File.exist?(manifest_path) + end end # Find and parse all manifests in the manifest paths @@ -228,7 +227,7 @@ def self._load_classes classes = load_classes_from_manifest(manifest_file) next if classes.nil? classes.each do |key, data| - @class_load_info[key] = data unless @class_load_info.has_key?(name) + @class_load_info[key] = data unless @class_load_info.key?(name) end end end @@ -240,7 +239,7 @@ def self._load_classes private_class_method :_load_classes def self.load_classes_from_manifest(manifest_file) - file_content = File.open(manifest_file, "r:UTF-8") { |f| f.read } + file_content = File.open(manifest_file, 'r:UTF-8') { |f| f.read } parser = Puppet::Pops::Parser::Parser.new result = nil @@ -253,9 +252,9 @@ def self.load_classes_from_manifest(manifest_file) class_info = {} # Enumerate the entire AST looking for classes and defined types - # TODO - Need to learn how to read the help/docs for hover support + # TODO: Need to learn how to read the help/docs for hover support if result.model.respond_to? :eAllContents - # TODO Puppet 4 language stuff + # TODO: Puppet 4 language stuff result.model.eAllContents.select do |item| case item.class.to_s when 'Puppet::Pops::Model::HostClassDefinition' diff --git a/lib/puppet-languageserver/puppet_monkey_patches.rb b/lib/puppet-languageserver/puppet_monkey_patches.rb index 55d4c2d9..dd1875a2 100644 --- a/lib/puppet-languageserver/puppet_monkey_patches.rb +++ b/lib/puppet-languageserver/puppet_monkey_patches.rb @@ -2,37 +2,49 @@ # Monkey Patch 3.x functions so where know where they were loaded from require 'puppet/parser/functions' -module Puppet::Parser::Functions - class << self - alias_method :original_newfunction, :newfunction - def newfunction(name, options = {}, &block) - # See if we've hooked elsewhere. This can happen while in debuggers (pry). If we're not in the previous caller - # stack then just use the last caller - monkey_index = Kernel.caller_locations.find_index{ |loc| loc.path.match(/puppet_monkey_patches\.rb/) } - monkey_index = -1 if monkey_index.nil? - caller = Kernel.caller_locations[monkey_index + 1] - PuppetLanguageServer::PuppetHelper.add_function_load_info(name, { - 'source' => caller.absolute_path, - 'line' => caller.lineno - 1, # Convert to a zero based line number system - }) +module Puppet + module Parser + module Functions + class << self + alias_method :original_newfunction, :newfunction + def newfunction(name, options = {}, &block) + # See if we've hooked elsewhere. This can happen while in debuggers (pry). If we're not in the previous caller + # stack then just use the last caller + monkey_index = Kernel.caller_locations.find_index { |loc| loc.path.match(/puppet_monkey_patches\.rb/) } + monkey_index = -1 if monkey_index.nil? + caller = Kernel.caller_locations[monkey_index + 1] + # rubocop:disable Layout/IndentHash, Style/BracesAroundHashParameters + PuppetLanguageServer::PuppetHelper.add_function_load_info(name, { + 'source' => caller.absolute_path, + 'line' => caller.lineno - 1 # Convert to a zero based line number system + }) + # rubocop:enable Layout/IndentHash, Style/BracesAroundHashParameters - original_newfunction(name, options, &block) + original_newfunction(name, options, &block) + end + end end end end - +# Monkey Patch type loading so we can inject the source location information require 'puppet/metatype/manager' -module Puppet::MetaType::Manager - alias_method :original_newtype, :newtype - def newtype(name, options = {}, &block) - if block_given? && !block.source_location.nil? - PuppetLanguageServer::PuppetHelper.add_type_load_info(name, { - 'source' => block.source_location[0], - 'line' => block.source_location[1] - 1, # Convert to a zero based line number system - }) - end +module Puppet + module MetaType + module Manager + alias_method :original_newtype, :newtype + def newtype(name, options = {}, &block) + if block_given? && !block.source_location.nil? + # rubocop:disable Layout/IndentHash, Style/BracesAroundHashParameters + PuppetLanguageServer::PuppetHelper.add_type_load_info(name, { + 'source' => block.source_location[0], + 'line' => block.source_location[1] - 1 # Convert to a zero based line number system + }) + # rubocop:enable Layout/IndentHash, Style/BracesAroundHashParameters + end - original_newtype(name, options, &block) + original_newtype(name, options, &block) + end + end end end diff --git a/lib/puppet-languageserver/server_capabilities.rb b/lib/puppet-languageserver/server_capabilities.rb index a2c429bf..3258c3b3 100644 --- a/lib/puppet-languageserver/server_capabilities.rb +++ b/lib/puppet-languageserver/server_capabilities.rb @@ -4,13 +4,13 @@ def self.capabilities # https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#initialize-request { - 'textDocumentSync' => LanguageServer::TEXTDOCUMENTSYNCKIND_FULL, - 'hoverProvider' => true, + 'textDocumentSync' => LanguageServer::TEXTDOCUMENTSYNCKIND_FULL, + 'hoverProvider' => true, 'completionProvider' => { - 'resolveProvider' => true, + 'resolveProvider' => true, 'triggerCharacters' => ['>', '$', '[', '='] }, - 'definitionProvider' => true, + 'definitionProvider' => true } end end diff --git a/lib/puppet-vscode/logging.rb b/lib/puppet-vscode/logging.rb index 5e061d93..1e23669d 100644 --- a/lib/puppet-vscode/logging.rb +++ b/lib/puppet-vscode/logging.rb @@ -28,4 +28,4 @@ def self.init_logging(options) @logger = Logger.new(options[:debug]) end end -end \ No newline at end of file +end diff --git a/lib/puppet-vscode/simple_tcp_server.rb b/lib/puppet-vscode/simple_tcp_server.rb index 41a7da51..ee55126f 100644 --- a/lib/puppet-vscode/simple_tcp_server.rb +++ b/lib/puppet-vscode/simple_tcp_server.rb @@ -103,7 +103,7 @@ def start(handler = PuppetVSCode::SimpleTCPServerConnection, connection_options thread_cycle = proc do begin io_review - rescue # rubocop:disable Lint/RescueWithoutErrorClass + rescue # rubocop:disable Style/RescueStandardError # Swallow all errors false end @@ -146,7 +146,7 @@ def start(handler = PuppetVSCode::SimpleTCPServerConnection, connection_options end end end - rescue # rubocop:disable Lint/RescueWithoutErrorClass + rescue # rubocop:disable Style/RescueStandardError # Swallow all errors true end @@ -253,7 +253,7 @@ def io_review io_r[2].each do |io| begin (remove_connection(io) || self.class.services.delete(io)).close - rescue # rubocop:disable Lint/RescueWithoutErrorClass + rescue # rubocop:disable Style/RescueStandardError # Swallow all errors true end @@ -296,7 +296,7 @@ def stop_all_services self.class.services.each do |s, p| begin s.close - rescue # rubocop:disable Lint/RescueWithoutErrorClass + rescue # rubocop:disable Style/RescueStandardError # Swallow all errors true end @@ -319,7 +319,7 @@ def stop_connections self.class.io_connection_dic.each_key do |io| begin io.close - rescue # rubocop:disable Lint/RescueWithoutErrorClass + rescue # rubocop:disable Style/RescueStandardError # Swallow all errors true end @@ -351,7 +351,7 @@ def remove_connection(io) connection_count = self.class.io_connection_dic.count begin io.close - rescue # rubocop:disable Lint/RescueWithoutErrorClass + rescue # rubocop:disable Style/RescueStandardError # Swallow all errors true end