rfix 2.0.4 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/exe/rfix +11 -90
  3. data/lib/rfix.rb +10 -9
  4. data/lib/rfix/branch/reference.rb +2 -2
  5. data/lib/rfix/branch/upstream.rb +2 -4
  6. data/lib/rfix/cli/command.rb +14 -1
  7. data/lib/rfix/cli/command/all.rb +21 -0
  8. data/lib/rfix/cli/command/base.rb +30 -19
  9. data/lib/rfix/cli/command/branch.rb +2 -0
  10. data/lib/rfix/cli/command/help.rb +2 -0
  11. data/lib/rfix/cli/command/info.rb +6 -1
  12. data/lib/rfix/cli/command/local.rb +2 -0
  13. data/lib/rfix/cli/command/origin.rb +2 -0
  14. data/lib/rfix/cli/command/setup.rb +2 -0
  15. data/lib/rfix/cli/command/status.rb +39 -0
  16. data/lib/rfix/collector.rb +69 -0
  17. data/lib/rfix/diff.rb +69 -0
  18. data/lib/rfix/extension/comment_config.rb +15 -0
  19. data/lib/rfix/extension/offense.rb +17 -14
  20. data/lib/rfix/extension/pastel.rb +7 -4
  21. data/lib/rfix/extension/progresbar.rb +15 -0
  22. data/lib/rfix/extension/strings.rb +10 -2
  23. data/lib/rfix/file.rb +5 -3
  24. data/lib/rfix/file/base.rb +21 -14
  25. data/lib/rfix/file/deleted.rb +2 -0
  26. data/lib/rfix/file/ignored.rb +2 -0
  27. data/lib/rfix/file/null.rb +17 -0
  28. data/lib/rfix/file/tracked.rb +39 -23
  29. data/lib/rfix/file/undefined.rb +17 -0
  30. data/lib/rfix/file/untracked.rb +3 -1
  31. data/lib/rfix/formatter.rb +67 -71
  32. data/lib/rfix/highlighter.rb +1 -3
  33. data/lib/rfix/rake/gemfile.rb +26 -23
  34. data/lib/rfix/repository.rb +59 -96
  35. data/lib/rfix/types.rb +24 -14
  36. data/lib/rfix/version.rb +1 -1
  37. data/rfix.gemspec +11 -3
  38. data/vendor/cli-ui/Gemfile +17 -0
  39. data/vendor/cli-ui/Gemfile.lock +60 -0
  40. data/vendor/cli-ui/LICENSE.txt +21 -0
  41. data/vendor/cli-ui/README.md +224 -0
  42. data/vendor/cli-ui/Rakefile +20 -0
  43. data/vendor/cli-ui/bin/console +14 -0
  44. data/vendor/cli-ui/cli-ui.gemspec +25 -0
  45. data/vendor/cli-ui/dev.yml +14 -0
  46. data/vendor/cli-ui/lib/cli/ui.rb +233 -0
  47. data/vendor/cli-ui/lib/cli/ui/ansi.rb +157 -0
  48. data/vendor/cli-ui/lib/cli/ui/color.rb +84 -0
  49. data/vendor/cli-ui/lib/cli/ui/formatter.rb +192 -0
  50. data/vendor/cli-ui/lib/cli/ui/frame.rb +269 -0
  51. data/vendor/cli-ui/lib/cli/ui/frame/frame_stack.rb +98 -0
  52. data/vendor/cli-ui/lib/cli/ui/frame/frame_style.rb +120 -0
  53. data/vendor/cli-ui/lib/cli/ui/frame/frame_style/box.rb +166 -0
  54. data/vendor/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +139 -0
  55. data/vendor/cli-ui/lib/cli/ui/glyph.rb +84 -0
  56. data/vendor/cli-ui/lib/cli/ui/os.rb +67 -0
  57. data/vendor/cli-ui/lib/cli/ui/printer.rb +59 -0
  58. data/vendor/cli-ui/lib/cli/ui/progress.rb +90 -0
  59. data/vendor/cli-ui/lib/cli/ui/prompt.rb +297 -0
  60. data/vendor/cli-ui/lib/cli/ui/prompt/interactive_options.rb +484 -0
  61. data/vendor/cli-ui/lib/cli/ui/prompt/options_handler.rb +29 -0
  62. data/vendor/cli-ui/lib/cli/ui/spinner.rb +66 -0
  63. data/vendor/cli-ui/lib/cli/ui/spinner/async.rb +40 -0
  64. data/vendor/cli-ui/lib/cli/ui/spinner/spin_group.rb +263 -0
  65. data/vendor/cli-ui/lib/cli/ui/stdout_router.rb +232 -0
  66. data/vendor/cli-ui/lib/cli/ui/terminal.rb +46 -0
  67. data/vendor/cli-ui/lib/cli/ui/truncater.rb +102 -0
  68. data/vendor/cli-ui/lib/cli/ui/version.rb +5 -0
  69. data/vendor/cli-ui/lib/cli/ui/widgets.rb +77 -0
  70. data/vendor/cli-ui/lib/cli/ui/widgets/base.rb +27 -0
  71. data/vendor/cli-ui/lib/cli/ui/widgets/status.rb +61 -0
  72. data/vendor/cli-ui/lib/cli/ui/wrap.rb +56 -0
  73. data/vendor/cli-ui/test/cli/ui/ansi_test.rb +32 -0
  74. data/vendor/cli-ui/test/cli/ui/cli_ui_test.rb +23 -0
  75. data/vendor/cli-ui/test/cli/ui/color_test.rb +40 -0
  76. data/vendor/cli-ui/test/cli/ui/formatter_test.rb +79 -0
  77. data/vendor/cli-ui/test/cli/ui/glyph_test.rb +68 -0
  78. data/vendor/cli-ui/test/cli/ui/printer_test.rb +103 -0
  79. data/vendor/cli-ui/test/cli/ui/progress_test.rb +46 -0
  80. data/vendor/cli-ui/test/cli/ui/prompt/options_handler_test.rb +39 -0
  81. data/vendor/cli-ui/test/cli/ui/prompt_test.rb +348 -0
  82. data/vendor/cli-ui/test/cli/ui/spinner/spin_group_test.rb +39 -0
  83. data/vendor/cli-ui/test/cli/ui/spinner_test.rb +141 -0
  84. data/vendor/cli-ui/test/cli/ui/stdout_router_test.rb +32 -0
  85. data/vendor/cli-ui/test/cli/ui/terminal_test.rb +26 -0
  86. data/vendor/cli-ui/test/cli/ui/truncater_test.rb +31 -0
  87. data/vendor/cli-ui/test/cli/ui/widgets/status_test.rb +49 -0
  88. data/vendor/cli-ui/test/cli/ui/widgets_test.rb +15 -0
  89. data/vendor/cli-ui/test/test_helper.rb +53 -0
  90. data/vendor/cli-ui/tmp/cache/bootsnap/compile-cache/d9/c036af0f3dc494 +0 -0
  91. data/vendor/cli-ui/tmp/cache/bootsnap/load-path-cache +0 -0
  92. data/vendor/dry-cli/lib/dry/cli/command.rb +2 -1
  93. data/vendor/dry-cli/tmp/cache/bootsnap/compile-cache/ff/a22a5daafbd74c +0 -0
  94. data/vendor/dry-cli/tmp/cache/bootsnap/load-path-cache +0 -0
  95. data/vendor/strings-ansi/tmp/cache/bootsnap/compile-cache/79/49cf49407b370e +0 -0
  96. data/vendor/strings-ansi/tmp/cache/bootsnap/load-path-cache +0 -0
  97. metadata +170 -9
  98. data/lib/rfix/extension/string.rb +0 -12
  99. data/lib/rfix/indicator.rb +0 -19
@@ -1,93 +1,109 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/module/concerning"
3
4
  require "active_support/core_ext/module/delegation"
4
- require "rubocop/formatter/simple_text_formatter"
5
- require "rubocop/cop/offense"
6
5
  require "dry/core/constants"
7
6
  require "dry/initializer"
7
+ require "tty/progressbar"
8
8
  require "tty/screen"
9
9
  require "tty/prompt"
10
+ require "tty/table"
10
11
  require "tty/box"
11
-
12
- RuboCop::Cop::Offense.prepend(Rfix::Extension::Offense)
12
+ require "rubocop"
13
13
 
14
14
  module Rfix
15
15
  class Formatter < RuboCop::Formatter::SimpleTextFormatter
16
- attr_reader :indicator
17
-
18
16
  include Dry::Core::Constants
19
17
  extend Dry::Initializer
20
18
  include Log
21
19
 
22
- option :indicator, default: -> { Indicator.new }
23
- option :reported_offenses
24
- option :options
25
- option :output
20
+ NoSuchFileError = Class.new(Error)
26
21
 
27
- PROMPT = TTY::Prompt.new(symbols: { marker: ">" })
28
- SPACE = " "
22
+ using(Module.new do
23
+ refine String do
24
+ def surround(value)
25
+ value + self + value
26
+ end
27
+ end
29
28
 
30
- delegate :say, to: :PROMPT
29
+ refine RuboCop::Cop::Offense.const_get(:PseudoSourceRange) do
30
+ def source_buffer
31
+ raise NoSuchFileError
32
+ end
33
+ end
34
+ end)
31
35
 
32
- class NullRepository
33
- include Singleton
36
+ option :reported_offenses, default: -> { EMPTY_ARRAY.dup }
37
+ option :progress
38
+ option :options
39
+ option :output
34
40
 
35
- def include_file?(*)
36
- true
37
- end
41
+ option :params do
42
+ option :repository
38
43
  end
39
44
 
45
+ SURROUNDING_LINES = 2
46
+ NEWLINE = "\n"
47
+ SPACE = " "
48
+ PADDING = 1
49
+
50
+ delegate :repository, to: :params
51
+
40
52
  def initialize(output, options = EMPTY_HASH)
41
- super(output: output, options: options, reported_offenses: EMPTY_ARRAY.dup)
53
+ TTY::ProgressBar.new(":current/:total (:eta) [:bar]", output: output).then do |bar|
54
+ super(output, output: output, options: options, params: options, progress: bar)
55
+ end
42
56
  end
43
57
 
44
58
  def started(files)
45
- # indicator.start("{{italic:rfix}} is linting {{bold:#{files.count}}} files, hold on ...")
46
- end
47
-
48
- # @files [Array<File>]
49
- def finished(files)
50
- # @indicator.stop
51
- mark_command_line
52
- report_summary(files)
59
+ progress.configure do |config|
60
+ config.bar_format = :block
61
+ config.total = files.count
62
+ config.clear_head = true
63
+ config.clear = true
64
+ config.width = width
65
+ end
53
66
  end
54
67
 
55
68
  # @file [File]
56
69
  # @offenses [Array<Offence>]
57
- def file_finished(*, offenses)
70
+ def file_finished(_file, offenses)
58
71
  @reported_offenses += offenses
59
72
 
60
- # @indicator.stop if offenses?
73
+ progress.advance
74
+ end
75
+
76
+ # @files [Array<File>]
77
+ def finished(files)
78
+ progress.finish
79
+ mark_command_line
80
+ reported_offenses.each do |offense|
81
+ progress.log(NEWLINE)
61
82
 
62
- length = offenses.length - 1
63
- offenses.each_with_index do |offense, _index|
64
83
  framed(offense) do
65
84
  report_line_with_highlight(offense)
66
85
  end
67
-
68
- puts
86
+ rescue NoSuchFileError
87
+ # NOP
69
88
  end
89
+ report_summary(files)
70
90
  end
71
91
 
72
92
  private
73
93
 
74
- using(Module.new do
75
- refine String do
76
- def surround(value)
77
- value + self + value
78
- end
79
- end
80
- end)
94
+ def width
95
+ TTY::Screen.width
96
+ end
81
97
 
82
98
  def framed(offense, &block)
83
- puts TTY::Box.frame({
84
- width: TTY::Screen.width,
85
- padding: [1, 1, 0, 1],
99
+ progress.log TTY::Box.frame({
100
+ width: width,
101
+ padding: [PADDING, PADDING, 0, PADDING],
86
102
  title: {
87
103
  top_left: "#{offense.icon} #{offense.msg}".surround(SPACE),
88
- bottom_left: offense.clickable_severity&.surround(SPACE),
89
- bottom_right: offense.clickable_path&.surround(SPACE)
90
- }.compact
104
+ bottom_left: offense.clickable_path(repository.path)&.surround(SPACE),
105
+ top_right: offense.cop_name.surround(SPACE)
106
+ }
91
107
  }, &block)
92
108
  end
93
109
 
@@ -100,34 +116,20 @@ module Rfix
100
116
  end
101
117
 
102
118
  def mark_command_line
103
- # "#{ESC}]1337;SetMark\a"
104
- "" # TODO: Activate
105
- end
106
-
107
- def report(msg, format: true)
108
- msg
109
- end
110
-
111
- def newline(amount = 1)
112
- report("\n" * amount)
119
+ # progress.log "\e]1337;SetMark\a"
113
120
  end
114
121
 
115
122
  def report_line_with_highlight(offense)
116
123
  location = offense.location
117
124
 
118
- unless location.respond_to?(:source_buffer)
119
- return "Source not found"
120
- end
121
-
122
125
  buffer = location.source_buffer
123
126
 
124
127
  source = buffer.source
125
128
  line = location.line
126
129
  last_line = buffer.last_line
127
- surrounding_lines = 2
128
130
 
129
- min_line = [line - surrounding_lines * 2, 1].max
130
- max_line = [line + surrounding_lines * 2, last_line].min
131
+ min_line = [line - SURROUNDING_LINES * 2, 1].max
132
+ max_line = [line + SURROUNDING_LINES * 2, last_line].min
131
133
 
132
134
  begin_index = buffer.line_range(min_line).begin_pos
133
135
  end_index = buffer.line_range(max_line).end_pos
@@ -135,13 +137,11 @@ module Rfix
135
137
  visible = begin_index...end_index
136
138
  highlight = location.to_range
137
139
 
138
- highlighter = Highlighter.new(
140
+ Highlighter.new(
139
141
  visible_lines: (min_line..max_line),
140
142
  highlight: highlight,
141
143
  visible: visible
142
- )
143
-
144
- (method(:report) << highlighter).call(source)
144
+ ).call(source)
145
145
  end
146
146
 
147
147
  def corrected
@@ -159,9 +159,5 @@ module Rfix
159
159
  def offenses?
160
160
  reported_offenses.any?
161
161
  end
162
-
163
- def repository
164
- NullRepository.instance
165
- end
166
162
  end
167
163
  end
@@ -71,10 +71,8 @@ module Rfix
71
71
 
72
72
  lines.reduce([0, 1]) do |(position, lineno), tokens|
73
73
  print_line_number = lambda do
74
- block.call(SPACE * 2)
75
-
76
74
  style = is_h[lineno] ? pastel.yellow.detach : pastel.dim.detach
77
- (block << style).call(lineno.to_s.ljust(4, SPACE) + SPACE)
75
+ block.call((SPACE * 2) + style.call(lineno.to_s.ljust(4, SPACE)) + SPACE)
78
76
  end
79
77
 
80
78
  tokens.reduce(position) do |index, (token, value)|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "dry/types"
2
4
  require "dry/struct"
3
5
  require "dry/logic"
@@ -9,7 +11,8 @@ module Rfix
9
11
  end
10
12
 
11
13
  class Gemfile < Dry::Struct
12
- include Dry::Core::Constants, FileUtils
14
+ include FileUtils
15
+ include Dry::Core::Constants
13
16
 
14
17
  module Types
15
18
  include Dry::Types()
@@ -32,26 +35,26 @@ module Rfix
32
35
 
33
36
  FORMAT = "Gemfile.rubocop-%s%s"
34
37
  VERSIONS = [
35
- '0.82',
36
- '0.83',
37
- '0.84',
38
- '0.92',
39
- '0.93',
40
- '1.0.0',
41
- '1.7.0',
42
- '1.5.0',
43
- '1.5.1',
44
- '1.5.2',
45
- '1.6.1',
46
- '1.8.1',
47
- '1.8.0',
48
- '1.9.0',
49
- '1.10.0',
50
- '1.11.0',
51
- '1.12.0',
52
- '1.12.1',
53
- '1.13.0'
54
- ]
38
+ "0.82",
39
+ "0.83",
40
+ "0.84",
41
+ "0.92",
42
+ "0.93",
43
+ "1.0.0",
44
+ "1.7.0",
45
+ "1.5.0",
46
+ "1.5.1",
47
+ "1.5.2",
48
+ "1.6.1",
49
+ "1.8.1",
50
+ "1.8.0",
51
+ "1.9.0",
52
+ "1.10.0",
53
+ "1.11.0",
54
+ "1.12.0",
55
+ "1.12.1",
56
+ "1.13.0"
57
+ ].freeze
55
58
 
56
59
  def self.call(*args, **kwargs, &block)
57
60
  (self | AST).call(*args, **kwargs, &block)
@@ -77,9 +80,9 @@ module Rfix
77
80
  end
78
81
 
79
82
  def bundle_lock
80
- sh *lock_args
83
+ sh(*lock_args)
81
84
  rescue RuntimeError
82
- sh *lock_args[0..-2]
85
+ sh(*lock_args[0..-2])
83
86
  end
84
87
 
85
88
  def lock_args
@@ -1,89 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/string/inflections"
3
4
  require "active_support/core_ext/module/delegation"
4
- require "dry/core/constants"
5
+ require "active_support/core_ext/object/inclusion"
5
6
  require "dry/core/memoizable"
7
+ require "dry/core/constants"
8
+ require "concurrent/map"
6
9
  require "dry/struct"
7
10
  require "rugged"
8
11
 
9
12
  module Rfix
10
13
  class Repository < Dry::Struct
11
14
  include Dry::Core::Constants
12
- include Log
15
+ include Dry::Core::Memoizable
13
16
 
14
17
  attribute :repository, Types.Instance(Rugged::Repository)
15
-
16
18
  attribute :reference, Types.Instance(Branch::Base)
19
+ attribute :current_path, Types::Path::Relative.default { Pathname(".").freeze }
17
20
 
18
- delegate :head, :branches, :workdir, :rev_parse, :diff_workdir, to: :repository
19
-
20
- OPTIONS = {
21
- include_untracked_content: true,
22
- ignore_whitespace_change: false,
23
- recurse_untracked_dirs: true,
24
- ignore_whitespace_eol: false,
25
- include_unmodified: true,
26
- include_untracked: true,
27
- ignore_submodules: true,
28
- include_ignored: false,
29
- context_lines: 0
30
- }.freeze
31
-
32
- def initialize(*)
33
- super
34
- call
35
- end
36
-
37
- def origin
38
- reference.resolve
39
- end
40
-
41
- def status(found = EMPTY_HASH.dup)
42
- @status ||= begin
43
- repository.status do |path, statuses|
44
- statuses.each do |status|
45
- (found[path] ||= []) << status
46
- end
47
- end
48
-
49
- if repository.head_unborn?
50
- return found
51
- end
52
-
53
- origin.diff_workdir(**OPTIONS.dup).tap do |diff|
54
- diff.find_similar!(
55
- renames_from_rewrites: true,
56
- renames: true,
57
- copies: true
58
- )
59
- end.each_delta.each_with_object(found) do |delta, acc|
60
- (acc[delta.new_file[:path]] ||= []) << delta.status
61
- end
62
- end
63
- end
64
-
65
- def call
66
- status.each do |path, statuses|
67
- build(path, statuses)
68
- end
69
- end
21
+ INCLUDED = [File::Untracked, File::Tracked].to_set.freeze
22
+ INIT = Hash.new { |h, k| h[k] = EMPTY_ARRAY.dup }.freeze
70
23
 
71
- def path
72
- Pathname(workdir)
73
- end
24
+ delegate_missing_to :repository
74
25
 
75
- # @path [String]
76
- def refresh!(*)
77
- # NOP
26
+ def self.method_added(name)
27
+ super.tap { memoize(name) }
78
28
  end
79
29
 
80
- # @path [String]
81
- # @line [Integer]
82
- # @return Bool
83
30
  def include?(path, line)
84
- get(path).include?(line)
85
- rescue KeyError
86
- false
31
+ cache[path].include?(line)
87
32
  end
88
33
 
89
34
  def skipped
@@ -91,62 +36,80 @@ module Rfix
91
36
  end
92
37
 
93
38
  def tracked
94
- files.values.select(&:tracked?)
39
+ files.select(&:tracked?)
95
40
  end
96
41
 
97
42
  def ignored
98
- files.values.select(&:ignored?)
43
+ files.select(&:ignored?)
99
44
  end
100
45
 
101
46
  def untracked
102
- files.values.select(&:untracked?)
47
+ files.select(&:untracked?)
103
48
  end
104
49
 
105
50
  def deleted
106
- files.values.select(&:deleted?)
51
+ files.select(&:deleted?)
107
52
  end
108
53
 
109
- def permitted
110
- untracked + tracked
54
+ def path
55
+ Pathname(workdir)
111
56
  end
112
57
 
113
- def to_s
114
- options = {
115
- untracked: untracked.map(&:basename).join(", "),
116
- tracked: tracked.map(&:basename).join(", "),
117
- ignored: ignored.map(&:basename).join(", "),
118
- deleted: deleted.map(&:basename).join(", ")
119
- }
120
-
121
- "Repository<Untracked: %<untracked>s, Tracked: %<tracked>s, Ignored: %<ignored>s, Deleted: %<deleted>s>" % options
58
+ def cache
59
+ Concurrent::Map.new do |storage, path|
60
+ storage.fetch(Types::Path::Absolute.call(path).to_s, File::Null)
61
+ end.tap do |storage|
62
+ files.each { |file| storage.compute_if_absent(file.key) { file } }
63
+ end
122
64
  end
123
65
 
124
66
  def files
125
- @files ||= EMPTY_HASH.dup
67
+ Diff.new(repository: self, current_path: current_path).deltas.map do |delta|
68
+ File::Tracked.call(**delta.new_file, repository: self, status: delta.status)
69
+ end
126
70
  end
127
71
 
128
- def paths
129
- permitted.map(&:basename)
72
+ def permitted
73
+ files
74
+ end
75
+
76
+ def to_s
77
+ files.each_with_object(INIT.dup) do |file, object|
78
+ object[file.class] << file
79
+ end.map do |type, files|
80
+ "%<type>s[%<count>i]:%<files>s" % {
81
+ files: files.map(&:to_s).join(", "),
82
+ type: type.name.demodulize,
83
+ count: files.count
84
+ }
85
+ end.then do |types|
86
+ "Repository<%<types>s>" % { types: types.join(", ") }
87
+ end
130
88
  end
89
+ alias inspect to_s
131
90
 
132
- def include_file?(path)
133
- permitted.include?(files.fetch(path, Undefined))
91
+ def paths
92
+ permitted.map(&:key).to_a
134
93
  end
135
94
 
136
- private
95
+ def include_file?(path, line = Undefined)
96
+ return cache[path].exists? if line == Undefined
137
97
 
138
- def store(file)
139
- files.store(file.key, file)
98
+ cache[path].include?(line)
140
99
  end
141
100
 
142
- def get(path)
143
- files.fetch(path)
101
+ alias contains? include_file?
102
+ alias include? include_file?
103
+
104
+ # TODO: Refactor
105
+ def origin
106
+ repository.lookup(repository.rev_parse(reference.name).oid)
107
+ rescue Rugged::Error, Rugged::InvalidError, Rugged::ReferenceError
108
+ raise Error, "Reference #{reference.name.inspect} not found"
144
109
  end
145
110
 
146
- def build(path, status)
147
- store(Rfix::File.call(basename: path, status: status, repository: self))
148
- rescue Dry::Struct::Error => e
149
- raise Error, { path: path, status: status, message: e.message }.inspect
111
+ def collector
112
+ Collector.call(repository: self, reference: reference.name)
150
113
  end
151
114
  end
152
115
  end