rubocop 1.30.0 → 1.31.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -2
  3. data/config/default.yml +41 -8
  4. data/config/obsoletion.yml +2 -0
  5. data/exe/rubocop +15 -7
  6. data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
  7. data/lib/rubocop/cli/command/suggest_extensions.rb +3 -3
  8. data/lib/rubocop/config.rb +4 -0
  9. data/lib/rubocop/config_loader.rb +1 -0
  10. data/lib/rubocop/config_validator.rb +9 -5
  11. data/lib/rubocop/cop/base.rb +4 -0
  12. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  13. data/lib/rubocop/cop/bundler/gem_filename.rb +4 -4
  14. data/lib/rubocop/cop/bundler/ordered_gems.rb +2 -2
  15. data/lib/rubocop/cop/corrector.rb +2 -2
  16. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +3 -3
  17. data/lib/rubocop/cop/correctors/unused_arg_corrector.rb +1 -1
  18. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +31 -16
  19. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +1 -1
  20. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  21. data/lib/rubocop/cop/gemspec/require_mfa.rb +20 -20
  22. data/lib/rubocop/cop/generator.rb +1 -1
  23. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -5
  24. data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +1 -1
  25. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +1 -1
  26. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  27. data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
  28. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +25 -4
  29. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +4 -4
  30. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +9 -9
  31. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +9 -9
  32. data/lib/rubocop/cop/layout/first_argument_indentation.rb +27 -27
  33. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +17 -11
  34. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +49 -10
  35. data/lib/rubocop/cop/layout/initial_indentation.rb +1 -1
  36. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +68 -0
  37. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +120 -0
  38. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  39. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
  40. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -2
  41. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
  42. data/lib/rubocop/cop/layout/space_around_operators.rb +1 -1
  43. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -1
  44. data/lib/rubocop/cop/layout/space_before_first_arg.rb +1 -1
  45. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +10 -10
  46. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +5 -3
  47. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +7 -7
  48. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  49. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +51 -0
  50. data/lib/rubocop/cop/lint/interpolation_check.rb +1 -1
  51. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +121 -0
  52. data/lib/rubocop/cop/lint/number_conversion.rb +3 -3
  53. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  54. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +5 -5
  55. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  56. data/lib/rubocop/cop/lint/redundant_require_statement.rb +1 -1
  57. data/lib/rubocop/cop/lint/regexp_as_condition.rb +2 -2
  58. data/lib/rubocop/cop/lint/struct_new_override.rb +2 -2
  59. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  60. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +44 -0
  61. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  62. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +36 -12
  63. data/lib/rubocop/cop/mixin/range_help.rb +7 -3
  64. data/lib/rubocop/cop/naming/accessor_method_name.rb +3 -1
  65. data/lib/rubocop/cop/naming/variable_number.rb +17 -17
  66. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  67. data/lib/rubocop/cop/style/and_or.rb +8 -8
  68. data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -1
  69. data/lib/rubocop/cop/style/block_delimiters.rb +4 -2
  70. data/lib/rubocop/cop/style/commented_keyword.rb +1 -1
  71. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -0
  72. data/lib/rubocop/cop/style/empty_else.rb +10 -10
  73. data/lib/rubocop/cop/style/empty_method.rb +16 -1
  74. data/lib/rubocop/cop/style/encoding.rb +1 -1
  75. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  76. data/lib/rubocop/cop/style/fetch_env_var.rb +9 -2
  77. data/lib/rubocop/cop/style/format_string_token.rb +48 -17
  78. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  79. data/lib/rubocop/cop/style/guard_clause.rb +8 -6
  80. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +1 -1
  81. data/lib/rubocop/cop/style/hash_except.rb +88 -8
  82. data/lib/rubocop/cop/style/hash_syntax.rb +2 -2
  83. data/lib/rubocop/cop/style/implicit_runtime_error.rb +2 -2
  84. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
  85. data/lib/rubocop/cop/style/line_end_concatenation.rb +1 -1
  86. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  87. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -2
  88. data/lib/rubocop/cop/style/missing_else.rb +24 -24
  89. data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -2
  90. data/lib/rubocop/cop/style/multiline_if_then.rb +1 -1
  91. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -3
  92. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -1
  93. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -1
  94. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -3
  95. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  96. data/lib/rubocop/cop/style/nested_ternary_operator.rb +19 -7
  97. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  98. data/lib/rubocop/cop/style/not.rb +1 -1
  99. data/lib/rubocop/cop/style/redundant_argument.rb +1 -1
  100. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  101. data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -1
  102. data/lib/rubocop/cop/style/rescue_standard_error.rb +10 -10
  103. data/lib/rubocop/cop/style/safe_navigation.rb +3 -0
  104. data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -2
  105. data/lib/rubocop/cop/style/string_concatenation.rb +5 -6
  106. data/lib/rubocop/cop/style/struct_inheritance.rb +2 -2
  107. data/lib/rubocop/cop/style/swap_values.rb +1 -1
  108. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  109. data/lib/rubocop/cop/style/unpack_first.rb +1 -1
  110. data/lib/rubocop/cop/util.rb +1 -1
  111. data/lib/rubocop/cops_documentation_generator.rb +18 -1
  112. data/lib/rubocop/formatter/disabled_config_formatter.rb +8 -5
  113. data/lib/rubocop/formatter/formatter_set.rb +20 -19
  114. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +15 -2
  115. data/lib/rubocop/formatter/html_formatter.rb +0 -1
  116. data/lib/rubocop/formatter/offense_count_formatter.rb +2 -0
  117. data/lib/rubocop/formatter/simple_text_formatter.rb +6 -9
  118. data/lib/rubocop/formatter.rb +31 -0
  119. data/lib/rubocop/options.rb +25 -2
  120. data/lib/rubocop/rake_task.rb +30 -9
  121. data/lib/rubocop/runner.rb +2 -2
  122. data/lib/rubocop/server/cache.rb +109 -0
  123. data/lib/rubocop/server/cli.rb +104 -0
  124. data/lib/rubocop/server/client_command/base.rb +44 -0
  125. data/lib/rubocop/server/client_command/exec.rb +59 -0
  126. data/lib/rubocop/server/client_command/restart.rb +25 -0
  127. data/lib/rubocop/server/client_command/start.rb +43 -0
  128. data/lib/rubocop/server/client_command/status.rb +28 -0
  129. data/lib/rubocop/server/client_command/stop.rb +31 -0
  130. data/lib/rubocop/server/client_command.rb +26 -0
  131. data/lib/rubocop/server/core.rb +79 -0
  132. data/lib/rubocop/server/errors.rb +23 -0
  133. data/lib/rubocop/server/helper.rb +34 -0
  134. data/lib/rubocop/server/server_command/base.rb +50 -0
  135. data/lib/rubocop/server/server_command/exec.rb +34 -0
  136. data/lib/rubocop/server/server_command/stop.rb +24 -0
  137. data/lib/rubocop/server/server_command.rb +21 -0
  138. data/lib/rubocop/server/socket_reader.rb +65 -0
  139. data/lib/rubocop/server.rb +53 -0
  140. data/lib/rubocop/version.rb +15 -8
  141. data/lib/rubocop.rb +7 -26
  142. metadata +27 -4
  143. data/lib/rubocop/cop/gemspec/date_assignment.rb +0 -49
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'colorizable'
4
- require_relative 'text_util'
5
-
6
3
  module RuboCop
7
4
  module Formatter
8
5
  # A basic formatter that displays only files with offenses.
@@ -63,7 +60,7 @@ module RuboCop
63
60
  rainbow,
64
61
  # :safe_autocorrect is a derived option based on several command-line
65
62
  # arguments - see Rubocop::Options#add_autocorrection_options
66
- safe_auto_correct: @options[:safe_autocorrect])
63
+ safe_autocorrect: @options[:safe_autocorrect])
67
64
 
68
65
  output.puts
69
66
  output.puts report.summary
@@ -110,22 +107,22 @@ module RuboCop
110
107
  # rubocop:disable Metrics/ParameterLists
111
108
  def initialize(
112
109
  file_count, offense_count, correction_count, correctable_count, rainbow,
113
- safe_auto_correct: false
110
+ safe_autocorrect: false
114
111
  )
115
112
  @file_count = file_count
116
113
  @offense_count = offense_count
117
114
  @correction_count = correction_count
118
115
  @correctable_count = correctable_count
119
116
  @rainbow = rainbow
120
- @safe_auto_correct = safe_auto_correct
117
+ @safe_autocorrect = safe_autocorrect
121
118
  end
122
119
  # rubocop:enable Metrics/ParameterLists
123
120
 
124
121
  def summary
125
122
  if @correction_count.positive?
126
123
  if @correctable_count.positive?
127
- "#{files} inspected, #{offenses} detected, #{corrections} corrected,"\
128
- " #{correctable}"
124
+ "#{files} inspected, #{offenses} detected, #{corrections} corrected, " \
125
+ "#{correctable}"
129
126
  else
130
127
  "#{files} inspected, #{offenses} detected, #{corrections} corrected"
131
128
  end
@@ -159,7 +156,7 @@ module RuboCop
159
156
  end
160
157
 
161
158
  def correctable
162
- if @safe_auto_correct
159
+ if @safe_autocorrect
163
160
  text = pluralize(@correctable_count, 'more offense')
164
161
  "#{colorize(text, :yellow)} can be corrected with `rubocop -A`"
165
162
  else
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Formatter
5
+ autoload :BaseFormatter, 'rubocop/formatter/base_formatter'
6
+ autoload :SimpleTextFormatter, 'rubocop/formatter/simple_text_formatter'
7
+ # relies on simple text
8
+ autoload :ClangStyleFormatter, 'rubocop/formatter/clang_style_formatter'
9
+ autoload :DisabledConfigFormatter, 'rubocop/formatter/disabled_config_formatter'
10
+ autoload :EmacsStyleFormatter, 'rubocop/formatter/emacs_style_formatter'
11
+ autoload :FileListFormatter, 'rubocop/formatter/file_list_formatter'
12
+ autoload :FuubarStyleFormatter, 'rubocop/formatter/fuubar_style_formatter'
13
+ autoload :GitHubActionsFormatter, 'rubocop/formatter/git_hub_actions_formatter'
14
+ autoload :HTMLFormatter, 'rubocop/formatter/html_formatter'
15
+ autoload :JSONFormatter, 'rubocop/formatter/json_formatter'
16
+ autoload :JUnitFormatter, 'rubocop/formatter/junit_formatter'
17
+ autoload :MarkdownFormatter, 'rubocop/formatter/markdown_formatter'
18
+ autoload :OffenseCountFormatter, 'rubocop/formatter/offense_count_formatter'
19
+ autoload :ProgressFormatter, 'rubocop/formatter/progress_formatter'
20
+ autoload :QuietFormatter, 'rubocop/formatter/quiet_formatter'
21
+ autoload :TapFormatter, 'rubocop/formatter/tap_formatter'
22
+ autoload :WorstOffendersFormatter, 'rubocop/formatter/worst_offenders_formatter'
23
+ autoload :PacmanFormatter, 'rubocop/formatter/pacman_formatter'
24
+ # relies on progress formatter
25
+ autoload :AutoGenConfigFormatter, 'rubocop/formatter/auto_gen_config_formatter'
26
+ autoload :Colorizable, 'rubocop/formatter/colorizable'
27
+
28
+ require_relative 'formatter/formatter_set'
29
+ require_relative 'formatter/text_util'
30
+ end
31
+ end
@@ -63,6 +63,7 @@ module RuboCop
63
63
 
64
64
  add_check_options(opts)
65
65
  add_cache_options(opts)
66
+ add_server_options(opts)
66
67
  add_output_options(opts)
67
68
  add_autocorrection_options(opts)
68
69
  add_config_generation_options(opts)
@@ -129,6 +130,7 @@ module RuboCop
129
130
  end
130
131
  end
131
132
 
133
+ # rubocop:todo Naming/InclusiveLanguage
132
134
  # the autocorrect command-line arguments map to the autocorrect @options values like so:
133
135
  # :fix_layout :autocorrect :safe_autocorrect :autocorrect_all
134
136
  # -x, --fix-layout true true - -
@@ -156,6 +158,7 @@ module RuboCop
156
158
  option(opts, '--disable-uncorrectable')
157
159
  end
158
160
  end
161
+ # rubocop:enable Naming/InclusiveLanguage
159
162
 
160
163
  def add_config_generation_options(opts)
161
164
  section(opts, 'Config Generation') do
@@ -201,6 +204,16 @@ module RuboCop
201
204
  end
202
205
  end
203
206
 
207
+ def add_server_options(opts)
208
+ section(opts, 'Server Options') do
209
+ option(opts, '--[no-]server')
210
+ option(opts, '--restart-server')
211
+ option(opts, '--start-server')
212
+ option(opts, '--stop-server')
213
+ option(opts, '--server-status')
214
+ end
215
+ end
216
+
204
217
  def add_additional_modes(opts)
205
218
  section(opts, 'Additional Modes') do
206
219
  option(opts, '-L', '--list-target-files')
@@ -226,7 +239,7 @@ module RuboCop
226
239
  end
227
240
 
228
241
  def handle_deprecated_option(old_option, new_option)
229
- warn "#{old_option} is deprecated; use #{new_option}"
242
+ warn rainbow.wrap("#{old_option} is deprecated; use #{new_option} instead.").yellow
230
243
  @options[long_opt_symbol([new_option])] = @options.delete(long_opt_symbol([old_option]))
231
244
  end
232
245
 
@@ -569,7 +582,17 @@ module RuboCop
569
582
  'parallel. Default is true.'],
570
583
  stdin: ['Pipe source from STDIN, using FILE in offense',
571
584
  'reports. This is useful for editor integration.'],
572
- init: 'Generate a .rubocop.yml file in the current directory.'
585
+ init: 'Generate a .rubocop.yml file in the current directory.',
586
+ server: ['If a server process has not been started yet, start',
587
+ 'the server process and execute inspection with server.',
588
+ 'Default is false.',
589
+ 'You can specify the server host and port with the',
590
+ '$RUBOCOP_SERVER_HOST and the $RUBOCOP_SERVER_PORT',
591
+ 'environment variables.'],
592
+ restart_server: 'Restart server process.',
593
+ start_server: 'Start server process.',
594
+ stop_server: 'Stop server process.',
595
+ server_status: 'Show server status.'
573
596
  }.freeze
574
597
  end
575
598
  end
@@ -32,6 +32,15 @@ module RuboCop
32
32
 
33
33
  private
34
34
 
35
+ def perform(option)
36
+ options = full_options.unshift(option)
37
+ # `parallel` will automatically be removed from the options internally.
38
+ # This is a nice to have to suppress the warning message
39
+ # about --parallel and --autocorrect not being compatible.
40
+ options.delete('--parallel')
41
+ run_cli(verbose, options)
42
+ end
43
+
35
44
  def run_cli(verbose, options)
36
45
  # We lazy-load RuboCop so that the task doesn't dramatically impact the
37
46
  # load time of your Rakefile.
@@ -60,19 +69,31 @@ module RuboCop
60
69
  @formatters = []
61
70
  end
62
71
 
63
- def setup_subtasks(name, *args, &task_block)
72
+ def setup_subtasks(name, *args, &task_block) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
64
73
  namespace(name) do
65
- desc 'Autocorrect RuboCop offenses'
74
+ # rubocop:todo Naming/InclusiveLanguage
75
+ task(:auto_correct, *args) do
76
+ warn Rainbow(
77
+ 'rubocop:auto_correct task is deprecated; ' \
78
+ 'use rubocop:autocorrect task or rubocop:autocorrect_all task instead.'
79
+ ).yellow
80
+ ::Rake::Task['rubocop:autocorrect'].invoke
81
+ end
82
+ # rubocop:enable Naming/InclusiveLanguage
83
+
84
+ desc "Autocorrect RuboCop offenses (only when it's safe)."
85
+ task(:autocorrect, *args) do |_, task_args|
86
+ RakeFileUtils.verbose(verbose) do
87
+ yield(*[self, task_args].slice(0, task_block.arity)) if task_block
88
+ perform('--autocorrect')
89
+ end
90
+ end
66
91
 
67
- task(:auto_correct, *args) do |_, task_args|
92
+ desc 'Autocorrect RuboCop offenses (safe and unsafe).'
93
+ task(:autocorrect_all, *args) do |_, task_args|
68
94
  RakeFileUtils.verbose(verbose) do
69
95
  yield(*[self, task_args].slice(0, task_block.arity)) if task_block
70
- options = full_options.unshift('--autocorrect-all')
71
- # `parallel` will automatically be removed from the options internally.
72
- # This is a nice to have to suppress the warning message
73
- # about --parallel and --autocorrect not being compatible.
74
- options.delete('--parallel')
75
- run_cli(verbose, options)
96
+ perform('--autocorrect-all')
76
97
  end
77
98
  end
78
99
  end
@@ -382,7 +382,7 @@ module RuboCop
382
382
  if @options[:display_only_fail_level_offenses]
383
383
  offenses.select { |o| considered_failure?(o) }
384
384
  elsif @options[:display_only_safe_correctable]
385
- offenses.select { |o| supports_safe_auto_correct?(o) }
385
+ offenses.select { |o| supports_safe_autocorrect?(o) }
386
386
  elsif @options[:display_only_correctable]
387
387
  offenses.select(&:correctable?)
388
388
  else
@@ -390,7 +390,7 @@ module RuboCop
390
390
  end
391
391
  end
392
392
 
393
- def supports_safe_auto_correct?(offense)
393
+ def supports_safe_autocorrect?(offense)
394
394
  cop_class = Cop::Registry.global.find_by_cop_name(offense.cop_name)
395
395
  default_cfg = default_config(offense.cop_name)
396
396
 
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+
5
+ #
6
+ # This code is based on https://github.com/fohte/rubocop-daemon.
7
+ #
8
+ # Copyright (c) 2018 Hayato Kawai
9
+ #
10
+ # The MIT License (MIT)
11
+ #
12
+ # https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt
13
+ #
14
+ module RuboCop
15
+ module Server
16
+ # Caches the states of server process.
17
+ # @api private
18
+ class Cache
19
+ GEMFILE_NAMES = %w[Gemfile gems.rb].freeze
20
+
21
+ class << self
22
+ # Searches for Gemfile or gems.rb in the current dir or any parent dirs
23
+ def project_dir
24
+ current_dir = Dir.pwd
25
+ while current_dir != '/'
26
+ return current_dir if GEMFILE_NAMES.any? do |gemfile|
27
+ File.exist?(File.join(current_dir, gemfile))
28
+ end
29
+
30
+ current_dir = File.expand_path('..', current_dir)
31
+ end
32
+ # If we can't find a Gemfile, just use the current directory
33
+ Dir.pwd
34
+ end
35
+
36
+ def project_dir_cache_key
37
+ @project_dir_cache_key ||= project_dir[1..].tr('/', '+')
38
+ end
39
+
40
+ def dir
41
+ cache_path = File.expand_path('~/.cache/rubocop_cache/server')
42
+ Pathname.new(File.join(cache_path, project_dir_cache_key)).tap do |d|
43
+ d.mkpath unless d.exist?
44
+ end
45
+ end
46
+
47
+ def port_path
48
+ dir.join('port')
49
+ end
50
+
51
+ def token_path
52
+ dir.join('token')
53
+ end
54
+
55
+ def pid_path
56
+ dir.join('pid')
57
+ end
58
+
59
+ def lock_path
60
+ dir.join('lock')
61
+ end
62
+
63
+ def status_path
64
+ dir.join('status')
65
+ end
66
+
67
+ def version_path
68
+ dir.join('version')
69
+ end
70
+
71
+ def pid_running?
72
+ Process.kill(0, pid_path.read.to_i) == 1
73
+ rescue Errno::ESRCH
74
+ false
75
+ end
76
+
77
+ def acquire_lock
78
+ lock_file = File.open(lock_path, File::CREAT)
79
+ # flock returns 0 if successful, and false if not.
80
+ flock_result = lock_file.flock(File::LOCK_EX | File::LOCK_NB)
81
+ yield flock_result != false
82
+ ensure
83
+ lock_file.flock(File::LOCK_UN)
84
+ lock_file.close
85
+ end
86
+
87
+ def write_port_and_token_files(port:, token:)
88
+ port_path.write(port)
89
+ token_path.write(token)
90
+ end
91
+
92
+ def write_pid_file
93
+ pid_path.write(Process.pid)
94
+ yield
95
+ ensure
96
+ dir.rmtree
97
+ end
98
+
99
+ def write_status_file(status)
100
+ status_path.write(status)
101
+ end
102
+
103
+ def write_version_file(version)
104
+ version_path.write(version)
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+ require 'rainbow'
5
+
6
+ #
7
+ # This code is based on https://github.com/fohte/rubocop-daemon.
8
+ #
9
+ # Copyright (c) 2018 Hayato Kawai
10
+ #
11
+ # The MIT License (MIT)
12
+ #
13
+ # https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt
14
+ #
15
+ module RuboCop
16
+ module Server
17
+ # The CLI is a class responsible of handling server command line interface logic.
18
+ # @api private
19
+ class CLI
20
+ # Same exit status value as `RuboCop::CLI`.
21
+ STATUS_SUCCESS = 0
22
+ STATUS_ERROR = 2
23
+
24
+ SERVER_OPTIONS = %w[
25
+ --server --no-server --server-status --restart-server --start-server --stop-server
26
+ ].freeze
27
+ EXCLUSIVE_OPTIONS = (SERVER_OPTIONS - %w[--server --no-server]).freeze
28
+
29
+ def initialize
30
+ @exit = false
31
+ end
32
+
33
+ def run(argv = ARGV)
34
+ unless Server.support_server?
35
+ return error('RuboCop server is not supported by this Ruby.') if use_server_option?(argv)
36
+
37
+ return STATUS_SUCCESS
38
+ end
39
+
40
+ deleted_server_arguments = delete_server_argument_from(argv)
41
+
42
+ if deleted_server_arguments.size >= 2
43
+ return error("#{deleted_server_arguments.join(', ')} cannot be specified together.")
44
+ end
45
+
46
+ server_command = deleted_server_arguments.first
47
+
48
+ if EXCLUSIVE_OPTIONS.include?(server_command) && argv.count >= 2
49
+ return error("#{server_command} cannot be combined with other options.")
50
+ end
51
+
52
+ run_command(server_command)
53
+
54
+ STATUS_SUCCESS
55
+ end
56
+
57
+ def exit?
58
+ @exit
59
+ end
60
+
61
+ private
62
+
63
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength:
64
+ def run_command(server_command)
65
+ case server_command
66
+ when '--server'
67
+ Server::ClientCommand::Start.new.run unless Server.running?
68
+ when '--no-server'
69
+ Server::ClientCommand::Stop.new.run if Server.running?
70
+ when '--restart-server'
71
+ @exit = true
72
+ Server::ClientCommand::Restart.new.run
73
+ when '--start-server'
74
+ @exit = true
75
+ Server::ClientCommand::Start.new.run
76
+ when '--stop-server'
77
+ @exit = true
78
+ Server::ClientCommand::Stop.new.run
79
+ when '--server-status'
80
+ @exit = true
81
+ Server::ClientCommand::Status.new.run
82
+ end
83
+ end
84
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength:
85
+
86
+ def delete_server_argument_from(all_arguments)
87
+ SERVER_OPTIONS.each_with_object([]) do |server_option, server_arguments|
88
+ server_arguments << all_arguments.delete(server_option)
89
+ end.compact
90
+ end
91
+
92
+ def use_server_option?(argv)
93
+ (argv & SERVER_OPTIONS).any?
94
+ end
95
+
96
+ def error(message)
97
+ @exit = true
98
+ warn Rainbow(message).red
99
+
100
+ STATUS_ERROR
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'shellwords'
4
+ require 'socket'
5
+
6
+ #
7
+ # This code is based on https://github.com/fohte/rubocop-daemon.
8
+ #
9
+ # Copyright (c) 2018 Hayato Kawai
10
+ #
11
+ # The MIT License (MIT)
12
+ #
13
+ # https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt
14
+ #
15
+ module RuboCop
16
+ module Server
17
+ module ClientCommand
18
+ # Abstract base class for server client command.
19
+ # @api private
20
+ class Base
21
+ def run
22
+ raise NotImplementedError
23
+ end
24
+
25
+ private
26
+
27
+ def send_request(command:, args: [], body: '')
28
+ TCPSocket.open('127.0.0.1', Cache.port_path.read) do |socket|
29
+ socket.puts [Cache.token_path.read, Dir.pwd, command, *args].shelljoin
30
+ socket.write body
31
+ socket.close_write
32
+ $stdout.write socket.read(4096) until socket.eof?
33
+ end
34
+ end
35
+
36
+ def check_running_server
37
+ Server.running?.tap do |running|
38
+ warn 'RuboCop server is not running.' unless running
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # This code is based on https://github.com/fohte/rubocop-daemon.
5
+ #
6
+ # Copyright (c) 2018 Hayato Kawai
7
+ #
8
+ # The MIT License (MIT)
9
+ #
10
+ # https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt
11
+ #
12
+ module RuboCop
13
+ module Server
14
+ module ClientCommand
15
+ # This class is a client command to execute server process.
16
+ # @api private
17
+ class Exec < Base
18
+ def run
19
+ ensure_server!
20
+ Cache.status_path.delete if Cache.status_path.file?
21
+ send_request(
22
+ command: 'exec',
23
+ args: ARGV.dup,
24
+ body: $stdin.tty? ? '' : $stdin.read
25
+ )
26
+ status
27
+ end
28
+
29
+ private
30
+
31
+ def ensure_server!
32
+ if incompatible_version?
33
+ puts 'RuboCop version incompatibility found, RuboCop server restarting...'
34
+ ClientCommand::Stop.new.run
35
+ elsif check_running_server
36
+ return
37
+ end
38
+
39
+ ClientCommand::Start.new.run
40
+ end
41
+
42
+ def incompatible_version?
43
+ RuboCop::Version::STRING != Cache.version_path.read
44
+ end
45
+
46
+ def status
47
+ unless Cache.status_path.file?
48
+ raise "RuboCop server: Could not find status file at: #{Cache.status_path}"
49
+ end
50
+
51
+ status = Cache.status_path.read
52
+ raise "RuboCop server: '#{status}' is not a valid status!" if (status =~ /^\d+$/).nil?
53
+
54
+ status.to_i
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # This code is based on https://github.com/fohte/rubocop-daemon.
5
+ #
6
+ # Copyright (c) 2018 Hayato Kawai
7
+ #
8
+ # The MIT License (MIT)
9
+ #
10
+ # https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt
11
+ #
12
+ module RuboCop
13
+ module Server
14
+ module ClientCommand
15
+ # This class is a client command to restart server process.
16
+ # @api private
17
+ class Restart < Base
18
+ def run
19
+ ClientCommand::Stop.new.run
20
+ ClientCommand::Start.new.run
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # This code is based on https://github.com/fohte/rubocop-daemon.
5
+ #
6
+ # Copyright (c) 2018 Hayato Kawai
7
+ #
8
+ # The MIT License (MIT)
9
+ #
10
+ # https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt
11
+ #
12
+ module RuboCop
13
+ module Server
14
+ module ClientCommand
15
+ # This class is a client command to start server process.
16
+ # @api private
17
+ class Start < Base
18
+ def run
19
+ if Server.running?
20
+ warn "RuboCop server (#{Cache.pid_path.read}) is already running."
21
+ return
22
+ end
23
+
24
+ Cache.acquire_lock do |locked|
25
+ unless locked
26
+ # Another process is already starting server,
27
+ # so wait for it to be ready.
28
+ Server.wait_for_running_status!(true)
29
+ exit 0
30
+ end
31
+
32
+ Cache.write_version_file(RuboCop::Version::STRING)
33
+
34
+ host = ENV.fetch('RUBOCOP_SERVER_HOST', '127.0.0.1')
35
+ port = ENV.fetch('RUBOCOP_SERVER_PORT', 0)
36
+
37
+ Server::Core.new.start(host, port)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # This code is based on https://github.com/fohte/rubocop-daemon.
5
+ #
6
+ # Copyright (c) 2018 Hayato Kawai
7
+ #
8
+ # The MIT License (MIT)
9
+ #
10
+ # https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt
11
+ #
12
+ module RuboCop
13
+ module Server
14
+ module ClientCommand
15
+ # This class is a client command to show server process status.
16
+ # @api private
17
+ class Status < Base
18
+ def run
19
+ if Server.running?
20
+ puts "RuboCop server (#{Cache.pid_path.read}) is running."
21
+ else
22
+ puts 'RuboCop server is not running.'
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # This code is based on https://github.com/fohte/rubocop-daemon.
5
+ #
6
+ # Copyright (c) 2018 Hayato Kawai
7
+ #
8
+ # The MIT License (MIT)
9
+ #
10
+ # https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt
11
+ #
12
+ module RuboCop
13
+ module Server
14
+ module ClientCommand
15
+ # This class is a client command to stop server process.
16
+ # @api private
17
+ class Stop < Base
18
+ def run
19
+ return unless check_running_server
20
+
21
+ pid = fork do
22
+ send_request(command: 'stop')
23
+ Server.wait_for_running_status!(false)
24
+ end
25
+
26
+ Process.waitpid(pid)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end