gem_bench 1.0.5 → 2.0.1
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +111 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/CONTRIBUTING.md +62 -0
- data/README.md +190 -42
- data/SECURITY.md +14 -0
- data/lib/gem_bench/gemfile_line_tokenizer.rb +59 -55
- data/lib/gem_bench/jersey.rb +150 -0
- data/lib/gem_bench/player.rb +43 -36
- data/lib/gem_bench/scout.rb +19 -20
- data/lib/gem_bench/strict_version_gem.rb +16 -21
- data/lib/gem_bench/strict_version_requirement.rb +26 -30
- data/lib/gem_bench/team.rb +120 -81
- data/lib/gem_bench/version.rb +3 -1
- data/lib/gem_bench.rb +21 -8
- data.tar.gz.sig +0 -0
- metadata +226 -32
- metadata.gz.sig +1 -0
- data/.byebug_history +0 -44
- data/.gitignore +0 -16
- data/.rspec +0 -2
- data/.travis.yml +0 -9
- data/CHANGELOG +0 -64
- data/Gemfile +0 -12
- data/Rakefile +0 -6
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/gem_bench.gemspec +0 -36
@@ -3,46 +3,41 @@ module GemBench
|
|
3
3
|
GEM_REGEX = /\A\s*gem\s+([^#]*).*\Z/.freeze # run against gem lines like: "gem 'aftership', # Ruby SDK of AfterShip API."
|
4
4
|
GEM_NAME_REGEX = /\A\s*gem\s+['"]{1}(?<name>[^'"]*)['"].*\Z/.freeze # run against gem lines like: "gem 'aftership', # Ruby SDK of AfterShip API."
|
5
5
|
VERSION_CONSTRAINT = /['"]{1}([^'"]*)['"]/.freeze
|
6
|
-
GEMFILE_HASH_CONFIG_KEY_REGEX_PROC =
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
GEMFILE_HASH_CONFIG_KEY_REGEX_PROC = lambda { |key|
|
7
|
+
/\A\s*[^#]*(?<key1>#{key}: *)['"]{1}(?<value1>[^'"]*)['"]|(?<key2>['"]#{key}['"] *=> *)['"]{1}(?<value2>[^'"]*)['"]|(?<key3>:#{key} *=> *)['"]{1}(?<value3>[^'"]*)['"]/
|
8
|
+
}
|
9
|
+
VERSION_PATH = GEMFILE_HASH_CONFIG_KEY_REGEX_PROC.call("path").freeze
|
10
|
+
VERSION_GIT = GEMFILE_HASH_CONFIG_KEY_REGEX_PROC.call("git").freeze
|
11
|
+
VERSION_GITHUB = GEMFILE_HASH_CONFIG_KEY_REGEX_PROC.call("github").freeze
|
12
|
+
VERSION_GIT_REF = GEMFILE_HASH_CONFIG_KEY_REGEX_PROC.call("ref").freeze
|
13
|
+
VERSION_GIT_TAG = GEMFILE_HASH_CONFIG_KEY_REGEX_PROC.call("tag").freeze
|
14
|
+
VERSION_GIT_BRANCH = GEMFILE_HASH_CONFIG_KEY_REGEX_PROC.call("branch").freeze
|
15
|
+
VALID_VERSION_TYPES = %i[
|
14
16
|
constraint
|
15
17
|
git_ref
|
16
18
|
git_tag
|
17
|
-
|
19
|
+
]
|
18
20
|
# branch is only valid if the branch is not master
|
19
21
|
attr_reader :line
|
20
|
-
attr_reader :relevant_lines
|
21
|
-
attr_reader :is_gem
|
22
|
-
attr_reader :all_lines
|
23
|
-
attr_reader :index
|
24
|
-
attr_reader :tokens
|
22
|
+
attr_reader :relevant_lines, :is_gem, :all_lines, :index, :tokens, :version_type, :name, :parse_success, :valid
|
25
23
|
# version will be a string if it is a normal constraint like '~> 1.2.3'
|
26
24
|
# version will be a hash if it is an alternative constraint like:
|
27
25
|
# git: "blah/blah", ref: "shasha"
|
28
26
|
attr_reader :version
|
29
|
-
|
30
|
-
attr_reader :name
|
31
|
-
attr_reader :parse_success
|
32
|
-
attr_reader :valid
|
27
|
+
|
33
28
|
def initialize(all_lines, line, index)
|
34
29
|
@line = line.strip
|
35
30
|
@is_gem = self.line.match(GEM_REGEX)
|
36
|
-
if
|
31
|
+
if is_gem
|
37
32
|
@all_lines = all_lines
|
38
33
|
@index = index
|
39
|
-
@tokens = self.line.split(
|
34
|
+
@tokens = self.line.split(",")
|
40
35
|
determine_name
|
41
|
-
if
|
36
|
+
if name
|
42
37
|
determine_relevant_lines
|
43
38
|
determine_version
|
44
39
|
@parse_success = true
|
45
|
-
@valid = VALID_VERSION_TYPES.include?(
|
40
|
+
@valid = VALID_VERSION_TYPES.include?(version_type)
|
46
41
|
else
|
47
42
|
noop
|
48
43
|
end
|
@@ -87,6 +82,7 @@ module GemBench
|
|
87
82
|
# index 1 of the comma-split tokens will usually be the version constraint, if there is one
|
88
83
|
possible_constraint = @tokens[1]
|
89
84
|
return false unless possible_constraint
|
85
|
+
|
90
86
|
match_data = possible_constraint.strip.match(VERSION_CONSTRAINT)
|
91
87
|
# the version constraint is in a regex capture group
|
92
88
|
if match_data && (@version = match_data[1].strip)
|
@@ -99,92 +95,100 @@ module GemBench
|
|
99
95
|
|
100
96
|
def version_path
|
101
97
|
@version = {}
|
102
|
-
line = relevant_lines.detect { |next_line|
|
98
|
+
line = relevant_lines.detect { |next_line| next_line.match(VERSION_PATH) }
|
103
99
|
return false unless line
|
100
|
+
|
104
101
|
enhance_version(
|
105
|
-
|
106
|
-
|
107
|
-
|
102
|
+
line.match(VERSION_PATH),
|
103
|
+
:path,
|
104
|
+
:path,
|
108
105
|
)
|
109
106
|
end
|
110
107
|
|
111
108
|
def version_git
|
112
109
|
@version = {}
|
113
|
-
line = relevant_lines.detect { |next_line|
|
110
|
+
line = relevant_lines.detect { |next_line| next_line.match(VERSION_GIT) }
|
114
111
|
return false unless line
|
112
|
+
|
115
113
|
enhance_version(
|
116
|
-
|
117
|
-
|
118
|
-
|
114
|
+
line.match(VERSION_GIT),
|
115
|
+
:git,
|
116
|
+
:git,
|
119
117
|
)
|
120
118
|
end
|
121
119
|
|
122
120
|
def version_github
|
123
121
|
@version = {}
|
124
|
-
line = relevant_lines.detect { |next_line|
|
122
|
+
line = relevant_lines.detect { |next_line| next_line.match(VERSION_GITHUB) }
|
125
123
|
return false unless line
|
124
|
+
|
126
125
|
enhance_version(
|
127
|
-
|
128
|
-
|
129
|
-
|
126
|
+
line.match(VERSION_GITHUB),
|
127
|
+
:github,
|
128
|
+
:github,
|
130
129
|
)
|
131
130
|
end
|
132
131
|
|
133
132
|
def check_for_version_of_type_git_ref
|
134
|
-
line = relevant_lines.detect { |next_line|
|
133
|
+
line = relevant_lines.detect { |next_line| next_line.match(VERSION_GIT_REF) }
|
135
134
|
return false unless line
|
135
|
+
|
136
136
|
enhance_version(
|
137
|
-
|
138
|
-
|
139
|
-
|
137
|
+
line.match(VERSION_GIT_REF),
|
138
|
+
:ref,
|
139
|
+
:git_ref,
|
140
140
|
)
|
141
141
|
end
|
142
142
|
|
143
143
|
def check_for_version_of_type_git_tag
|
144
|
-
line = relevant_lines.detect { |next_line|
|
144
|
+
line = relevant_lines.detect { |next_line| next_line.match(VERSION_GIT_TAG) }
|
145
145
|
return false unless line
|
146
|
+
|
146
147
|
enhance_version(
|
147
|
-
|
148
|
-
|
149
|
-
|
148
|
+
line.match(VERSION_GIT_TAG),
|
149
|
+
:tag,
|
150
|
+
:git_tag,
|
150
151
|
)
|
151
152
|
end
|
152
153
|
|
153
154
|
def check_for_version_of_type_git_branch
|
154
|
-
line = relevant_lines.detect { |next_line|
|
155
|
+
line = relevant_lines.detect { |next_line| next_line.match(VERSION_GIT_BRANCH) }
|
155
156
|
return false unless line
|
157
|
+
|
156
158
|
enhance_version(
|
157
|
-
|
158
|
-
|
159
|
-
|
159
|
+
line.match(VERSION_GIT_BRANCH),
|
160
|
+
:branch,
|
161
|
+
:git_branch,
|
160
162
|
)
|
161
163
|
end
|
162
164
|
|
163
165
|
# returns an array with each line following the current line, which is not a gem line
|
164
166
|
def following_non_gem_lines
|
165
|
-
all_lines[(index+1)
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
167
|
+
all_lines[(index + 1)..-1]
|
168
|
+
.reject { |x| x.strip.empty? || x.match(GemBench::TRASH_REGEX) }
|
169
|
+
.map(&:strip)
|
170
|
+
.inject([]) do |following_lines, next_line|
|
171
|
+
break following_lines if next_line.match(GEM_REGEX)
|
172
|
+
|
173
|
+
following_lines << next_line
|
171
174
|
end
|
172
175
|
end
|
173
176
|
|
174
177
|
# returns a hash like:
|
175
178
|
# {"key" => ":git => ", "value" => "https://github.com/cte/aftership-sdk-ruby.git"}
|
176
179
|
def normalize_match_data_captures(match_data)
|
177
|
-
match_data.names.
|
178
|
-
mem[capture.gsub(/\d/,
|
180
|
+
match_data.names.each_with_object({}) do |capture, mem|
|
181
|
+
mem[capture.gsub(/\d/, "")] = match_data[capture]
|
179
182
|
break mem if mem.keys.length >= 2
|
180
|
-
mem
|
181
183
|
end
|
182
184
|
end
|
183
185
|
|
184
186
|
def enhance_version(match_data, version_key, type)
|
185
187
|
return false unless match_data
|
188
|
+
|
186
189
|
normalized_capture = normalize_match_data_captures(match_data) if match_data
|
187
190
|
return false unless normalized_capture
|
191
|
+
|
188
192
|
@version.merge!({version_key => normalized_capture["value"]})
|
189
193
|
@version_type = type
|
190
194
|
true
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# Std Libs Dependencies
|
2
|
+
require "tmpdir"
|
3
|
+
|
4
|
+
# Re-write a gem to a temp directory, re-namespace the primary namespace of that gem module, and load it.
|
5
|
+
# If the original gem defines multiple top-level namespaces, they can all be renamed by providing more key value pairs.
|
6
|
+
# If the original gem monkey patches other libraries, that behavior can't be isolated, so YMMV.
|
7
|
+
#
|
8
|
+
# NOTE: Non-top-level namespaces do not need to be renamed, as they are isolated within their parent namespace.
|
9
|
+
#
|
10
|
+
# Usage
|
11
|
+
#
|
12
|
+
# jersey = GemBench::Jersey.new(
|
13
|
+
# gem_name: "alt_memery"
|
14
|
+
# trades: {
|
15
|
+
# "Memery" => "AltMemery"
|
16
|
+
# },
|
17
|
+
# metadata: {
|
18
|
+
# something: "a value here",
|
19
|
+
# something_else: :obviously,
|
20
|
+
# },
|
21
|
+
# )
|
22
|
+
# jersey.doff_and_don
|
23
|
+
# # The re-namespaced constant is now available!
|
24
|
+
# AltMemery # => AltMemery
|
25
|
+
#
|
26
|
+
module GemBench
|
27
|
+
class Jersey
|
28
|
+
attr_reader :gem_name
|
29
|
+
attr_reader :gem_path
|
30
|
+
attr_reader :trades
|
31
|
+
attr_reader :metadata
|
32
|
+
attr_reader :files
|
33
|
+
attr_reader :verbose
|
34
|
+
|
35
|
+
def initialize(gem_name:, trades:, metadata: {}, verbose: false)
|
36
|
+
@gem_name = gem_name
|
37
|
+
@gem_path = Gem.loaded_specs[gem_name]&.full_gem_path
|
38
|
+
@gem_lib_dir = Gem
|
39
|
+
@trades = trades
|
40
|
+
@metadata = metadata
|
41
|
+
@verbose = verbose
|
42
|
+
end
|
43
|
+
|
44
|
+
def required?
|
45
|
+
gem_path && trades.values.all? { |new_namespace| Object.const_defined?(new_namespace) }
|
46
|
+
end
|
47
|
+
|
48
|
+
# Generates tempfiles and requires them, resulting
|
49
|
+
# in a loaded gem that will not have namespace
|
50
|
+
# collisions when alongside the original-namespaced gem.
|
51
|
+
# If a block is provided the contents of each file will be yielded to the block,
|
52
|
+
# after all namespace substitutions are complete, but before the contents
|
53
|
+
# are written to the re-namespaced gem. The return value of the block will be
|
54
|
+
# written to the file in this scenario.
|
55
|
+
#
|
56
|
+
# @return void
|
57
|
+
def doff_and_don(&block)
|
58
|
+
return puts "Skipping #{gem_name} (not loaded on #{RUBY_VERSION})" unless gem_path
|
59
|
+
|
60
|
+
puts "Doffing #{gem_path}" if verbose
|
61
|
+
Dir.mktmpdir do |directory|
|
62
|
+
files = []
|
63
|
+
Dir[File.join(gem_path, "lib", "**", "*.rb")].map do |file|
|
64
|
+
if verbose
|
65
|
+
puts file
|
66
|
+
puts File.basename(file)
|
67
|
+
puts "--------------------------------"
|
68
|
+
end
|
69
|
+
dirname = File.dirname(file)
|
70
|
+
puts "dirname: #{dirname}" if verbose
|
71
|
+
is_at_gem_root = dirname[(-4)..(-1)] == "/lib"
|
72
|
+
puts "is_at_gem_root: #{is_at_gem_root}" if verbose
|
73
|
+
lib_split = dirname.split("/lib/")[-1]
|
74
|
+
puts "lib_split: #{lib_split}" if verbose
|
75
|
+
# lib_split could be like:
|
76
|
+
# - "ruby/gems/3.2.0/gems/method_source-1.1.0/lib"
|
77
|
+
# - "method_source"
|
78
|
+
# Se we check to make sure it is actually a subdir of the gem's lib directory
|
79
|
+
full_path = File.join(gem_path, "lib", lib_split)
|
80
|
+
relative_path = !is_at_gem_root && Dir.exist?(full_path) && lib_split
|
81
|
+
puts "relative_path: #{relative_path}" if verbose
|
82
|
+
filename = File.basename(file)[0..-4]
|
83
|
+
puts "filename: #{filename}" if verbose
|
84
|
+
|
85
|
+
if relative_path
|
86
|
+
dir_path = File.join(directory, relative_path)
|
87
|
+
Dir.mkdir(dir_path) unless Dir.exist?(dir_path)
|
88
|
+
puts "creating #{filename} in #{dir_path}" if verbose
|
89
|
+
files << create_tempfile_copy(file, filename, dir_path, :dd1, &block)
|
90
|
+
else
|
91
|
+
puts "directory not relative (#{directory}) for file #{filename}" if verbose
|
92
|
+
files << create_tempfile_copy(file, filename, directory, :dd2, &block)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
load_gem_copy(files)
|
96
|
+
end
|
97
|
+
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
|
101
|
+
def primary_namespace
|
102
|
+
trades.values.first
|
103
|
+
end
|
104
|
+
|
105
|
+
# Will raise NameError if called before #doff_and_don
|
106
|
+
def as_klass
|
107
|
+
Object.const_get(primary_namespace) if gem_path
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def load_gem_copy(files)
|
113
|
+
files.each do |filepath|
|
114
|
+
# begin
|
115
|
+
require filepath
|
116
|
+
# rescue LoadError => e
|
117
|
+
# puts file.to_s
|
118
|
+
# puts tempfile.path
|
119
|
+
# puts e.class
|
120
|
+
# puts e.message
|
121
|
+
# end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# @return [String] the file path of the new copy of the original file
|
126
|
+
def create_tempfile_copy(file, filename, directory, from, &block)
|
127
|
+
# Value of block is returned from File.open
|
128
|
+
File.open(File.join(directory, "#{filename}.rb"), "w") do |file_copy|
|
129
|
+
new_jersey(file, file_copy, from, &block)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# @return [String] the file path of the new copy of the original file
|
134
|
+
def new_jersey(file, file_copy, from)
|
135
|
+
nj = File.read(file)
|
136
|
+
trades.each do |old_namespace, new_namespace|
|
137
|
+
nj.gsub!(old_namespace, new_namespace)
|
138
|
+
end
|
139
|
+
if verbose
|
140
|
+
puts "new_jersey has from: #{from}"
|
141
|
+
puts "new_jersey has file: #{file}"
|
142
|
+
puts "new_jersey file_copy path: #{file_copy.path}"
|
143
|
+
end
|
144
|
+
nj = yield nj if block_given?
|
145
|
+
file_copy.write(nj)
|
146
|
+
file_copy.close
|
147
|
+
file_copy.path
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
data/lib/gem_bench/player.rb
CHANGED
@@ -21,49 +21,58 @@ module GemBench
|
|
21
21
|
|
22
22
|
def set_starter(file_path, line_match: nil)
|
23
23
|
return false if file_path =~ exclude_file_pattern
|
24
|
+
|
24
25
|
# Some gems may have zero files to check, as they may be using gem as a
|
25
26
|
# delivery system for shell scripts! As such we need to check which
|
26
27
|
# gems got checked, and which had nothing to check
|
27
28
|
@checked = true
|
28
29
|
line_match ||= GemBench::RAILTIE_REGEX
|
29
|
-
scan =
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
File.read(file_path).encode('utf-8', :invalid => :replace, :undef => :replace, :replace => '_') =~ line_match
|
35
|
-
rescue ArgumentError => e
|
36
|
-
if e.message =~ /invalid byte sequence/
|
37
|
-
puts "[GemBench] checking #{file_path} failed due to unparseable file content"
|
38
|
-
false # Assume the likelihood of files with encoding issues that also contain railtie to be low, so: false.
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
self.stats << [file_path,scan] if scan
|
44
|
-
self.state = !!scan ?
|
45
|
-
GemBench::PLAYER_STATES[:starter] :
|
30
|
+
scan = !GemBench::DO_NOT_SCAN.include?(name) && check_line(file_path, line_match)
|
31
|
+
stats << [file_path, scan] if scan
|
32
|
+
self.state = if !!scan
|
33
|
+
GemBench::PLAYER_STATES[:starter]
|
34
|
+
else
|
46
35
|
GemBench::PLAYER_STATES[:bench]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def check_line(file_path, line_match)
|
40
|
+
File.read(file_path).encode(
|
41
|
+
"utf-8",
|
42
|
+
invalid: :replace,
|
43
|
+
undef: :replace,
|
44
|
+
replace: "_",
|
45
|
+
) =~ line_match
|
46
|
+
rescue ArgumentError => e
|
47
|
+
if e.message =~ /invalid byte sequence/
|
48
|
+
puts "[GemBench] checking #{file_path} failed due to unparseable file content"
|
49
|
+
false # Assume the likelihood of files with encoding issues that also contain railtie to be low, so: false.
|
50
|
+
else
|
51
|
+
puts "[GemBench] checking #{file_path} failed. Please report a bug to https://github.com/pboling/gembench/issues"
|
52
|
+
raise e
|
53
|
+
end
|
47
54
|
end
|
48
55
|
|
49
56
|
def starter?
|
50
|
-
|
57
|
+
state == GemBench::PLAYER_STATES[:starter]
|
51
58
|
end
|
52
59
|
|
53
60
|
def to_s(format = :name)
|
54
61
|
case format
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
when :name
|
63
|
+
name
|
64
|
+
when :v
|
65
|
+
"#{name} v#{version}"
|
66
|
+
when :semver
|
67
|
+
"gem '#{name}', '~> #{semver}'"
|
68
|
+
when :locked
|
69
|
+
"gem '#{name}', '#{version}'"
|
70
|
+
when :legacy # when depending on legacy gems, you specifically want to not upgrade, except patches.
|
71
|
+
"gem '#{name}', '~> #{version}'"
|
72
|
+
when :upgrade # when upgrading, and testing gem compatibility you want to try anything newer
|
73
|
+
"gem '#{name}', '>= #{version}'"
|
74
|
+
else
|
75
|
+
raise ArgumentError, "Unknown format for #{self.class.name}#to_s"
|
67
76
|
end
|
68
77
|
end
|
69
78
|
|
@@ -73,17 +82,15 @@ module GemBench
|
|
73
82
|
|
74
83
|
def semver
|
75
84
|
ver = version
|
76
|
-
until ver.split(".").length <= SEMVER_SPLIT_ON_POINT_LENGTH
|
77
|
-
ver = ver[0..(ver.rindex(".")-1)]
|
78
|
-
end
|
85
|
+
ver = ver[0..(ver.rindex(".") - 1)] until ver.split(".").length <= SEMVER_SPLIT_ON_POINT_LENGTH
|
79
86
|
ver
|
80
87
|
end
|
81
88
|
|
82
89
|
def how
|
83
|
-
case
|
84
|
-
when GemBench::PLAYER_STATES[:starter]
|
90
|
+
case state
|
91
|
+
when GemBench::PLAYER_STATES[:starter]
|
85
92
|
to_s(:semver)
|
86
|
-
when GemBench::PLAYER_STATES[:bench]
|
93
|
+
when GemBench::PLAYER_STATES[:bench]
|
87
94
|
"#{to_s(:semver)}, require: false"
|
88
95
|
else
|
89
96
|
if checked
|
data/lib/gem_bench/scout.rb
CHANGED
@@ -3,13 +3,14 @@
|
|
3
3
|
module GemBench
|
4
4
|
class Scout
|
5
5
|
attr_reader :gem_paths, :gemfile_path, :gemfile_lines, :gemfile_trash, :loaded_gems
|
6
|
+
|
6
7
|
def initialize(check_gemfile: nil)
|
7
8
|
@check_gemfile = check_gemfile.nil? ? true : check_gemfile
|
8
9
|
@gemfile_path = "#{Dir.pwd}/Gemfile"
|
9
10
|
gem_lookup_paths_from_bundler
|
10
11
|
gem_lines_from_gemfile
|
11
12
|
# Gem.loaded_specs are the gems that have been loaded / required.
|
12
|
-
@loaded_gems = Gem.loaded_specs.values.map {|x| [x.name, x.version.to_s] }
|
13
|
+
@loaded_gems = Gem.loaded_specs.values.map { |x| [x.name, x.version.to_s] }
|
13
14
|
end
|
14
15
|
|
15
16
|
def check_gemfile?
|
@@ -19,23 +20,21 @@ module GemBench
|
|
19
20
|
private
|
20
21
|
|
21
22
|
def gem_lookup_paths_from_bundler
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
@gem_paths = [] unless @gem_paths.is_a?(Array)
|
38
|
-
end
|
23
|
+
@gem_paths = [Bundler.rubygems.gem_dir, Bundler.rubygems.gem_path]
|
24
|
+
.flatten
|
25
|
+
.compact
|
26
|
+
.uniq
|
27
|
+
.map { |x| x.to_s }
|
28
|
+
.reject { |p| p.empty? }
|
29
|
+
.map { |x| "#{x}/gems" }
|
30
|
+
@gem_paths << "#{Bundler.install_path}"
|
31
|
+
@gem_paths << "#{Bundler.bundle_path}/gems"
|
32
|
+
@gem_paths.uniq!
|
33
|
+
rescue Bundler::GemfileNotFound => e
|
34
|
+
# Don't fail here, but also don't check the Gemfile.
|
35
|
+
@check_gemfile = false
|
36
|
+
ensure
|
37
|
+
@gem_paths = [] unless @gem_paths.is_a?(Array)
|
39
38
|
end
|
40
39
|
|
41
40
|
def gem_lines_from_gemfile
|
@@ -44,8 +43,8 @@ module GemBench
|
|
44
43
|
# Get all lines as an array
|
45
44
|
all_lines = file.readlines
|
46
45
|
# Remove all the commented || blank lines
|
47
|
-
@gemfile_trash, @gemfile_lines = all_lines.partition {|x| x =~ GemBench::TRASH_REGEX}
|
48
|
-
@gemfile_trash.reject! {|x| x == "\n" } # remove blank lines
|
46
|
+
@gemfile_trash, @gemfile_lines = all_lines.partition { |x| x =~ GemBench::TRASH_REGEX }
|
47
|
+
@gemfile_trash.reject! { |x| x == "\n" } # remove blank lines
|
49
48
|
else
|
50
49
|
@gemfile_trash = []
|
51
50
|
@gemfile_lines = []
|
@@ -1,25 +1,20 @@
|
|
1
1
|
module GemBench
|
2
2
|
class StrictVersionGem
|
3
|
-
attr_reader :name
|
4
|
-
attr_reader :version
|
5
|
-
attr_reader :version_type
|
6
|
-
attr_reader :valid
|
7
|
-
attr_reader :relevant_lines
|
8
|
-
attr_reader :index
|
9
|
-
attr_reader :tokenized_line
|
3
|
+
attr_reader :name, :version, :version_type, :valid, :relevant_lines, :index, :tokenized_line
|
10
4
|
|
11
5
|
class << self
|
12
6
|
def from_line(all_lines, line, index, opts = {})
|
13
7
|
tokenized_line = GemfileLineTokenizer.new(all_lines, line, index)
|
14
|
-
return
|
8
|
+
return unless tokenized_line.is_gem
|
9
|
+
|
15
10
|
new(
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
11
|
+
tokenized_line.name,
|
12
|
+
tokenized_line.version,
|
13
|
+
tokenized_line.version_type,
|
14
|
+
tokenized_line.valid,
|
15
|
+
tokenized_line.relevant_lines,
|
16
|
+
tokenized_line.index,
|
17
|
+
(opts[:debug] == true) ? tokenized_line : nil,
|
23
18
|
)
|
24
19
|
end
|
25
20
|
end
|
@@ -43,12 +38,12 @@ module GemBench
|
|
43
38
|
end
|
44
39
|
|
45
40
|
def to_s
|
46
|
-
|
47
|
-
Gem: #{name}
|
48
|
-
Line Number: #{index}
|
49
|
-
Version: #{version.inspect}
|
50
|
-
Relevant Gemfile Lines:
|
51
|
-
#{relevant_lines.join("\n")}
|
41
|
+
<<~EOS
|
42
|
+
Gem: #{name}
|
43
|
+
Line Number: #{index}
|
44
|
+
Version: #{version.inspect}
|
45
|
+
Relevant Gemfile Lines:
|
46
|
+
#{relevant_lines.join("\n")}
|
52
47
|
EOS
|
53
48
|
end
|
54
49
|
end
|
@@ -1,10 +1,6 @@
|
|
1
1
|
module GemBench
|
2
2
|
class StrictVersionRequirement
|
3
|
-
attr_reader :gemfile_path
|
4
|
-
attr_reader :gems
|
5
|
-
attr_reader :starters
|
6
|
-
attr_reader :benchers
|
7
|
-
attr_reader :verbose
|
3
|
+
attr_reader :gemfile_path, :gems, :starters, :benchers, :verbose
|
8
4
|
|
9
5
|
def initialize(options = {})
|
10
6
|
@gemfile_path = "#{Dir.pwd}/Gemfile"
|
@@ -18,14 +14,14 @@ module GemBench
|
|
18
14
|
@gems << gem if gem
|
19
15
|
end
|
20
16
|
|
21
|
-
@starters, @benchers = @gems.partition {|x| x.valid? }
|
17
|
+
@starters, @benchers = @gems.partition { |x| x.valid? }
|
22
18
|
# Remove all the commented || blank lines
|
23
19
|
@verbose = options[:verbose]
|
24
|
-
self.print if
|
20
|
+
self.print if verbose
|
25
21
|
end
|
26
22
|
|
27
23
|
def versions_present?
|
28
|
-
gems.detect {|x| !x.valid? }.nil?
|
24
|
+
gems.detect { |x| !x.valid? }.nil?
|
29
25
|
end
|
30
26
|
|
31
27
|
def list_missing_version_constraints
|
@@ -33,34 +29,34 @@ module GemBench
|
|
33
29
|
end
|
34
30
|
|
35
31
|
def find(name)
|
36
|
-
gems.detect {|x| x.name == name }
|
32
|
+
gems.detect { |x| x.name == name }
|
37
33
|
end
|
38
34
|
|
39
35
|
def gem_at(index)
|
40
|
-
gems.detect {|x| x.index == index }
|
36
|
+
gems.detect { |x| x.index == index }
|
41
37
|
end
|
42
38
|
|
43
39
|
def print
|
44
|
-
using_path = benchers.count {|x| x.is_type?(:path) }
|
45
|
-
puts
|
46
|
-
|
47
|
-
The gems that need to be improved are:
|
48
|
-
|
49
|
-
#{benchers.map(&:to_s).join("\n")}
|
50
|
-
|
51
|
-
There are #{starters.length} gems that have valid strict version constraints.
|
52
|
-
Of those:
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
There are #{benchers.length} gems that do not have strict version constraints.
|
58
|
-
Of those:
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
EOS
|
40
|
+
using_path = benchers.count { |x| x.is_type?(:path) }
|
41
|
+
puts <<~EOS
|
42
|
+
#{" "}
|
43
|
+
The gems that need to be improved are:
|
44
|
+
|
45
|
+
#{benchers.map(&:to_s).join("\n")}
|
46
|
+
|
47
|
+
There are #{starters.length} gems that have valid strict version constraints.
|
48
|
+
Of those:
|
49
|
+
#{starters.count { |x| x.is_type?(:constraint) }} use primary constraints (e.g. '~> 1.2.3').
|
50
|
+
#{starters.count { |x| x.is_type?(:git_ref) }} use git ref constraints.
|
51
|
+
#{starters.count { |x| x.is_type?(:git_tag) }} use git tag constraints.
|
52
|
+
|
53
|
+
There are #{benchers.length} gems that do not have strict version constraints.
|
54
|
+
Of those:
|
55
|
+
#{benchers.count { |x| x.is_type?(:git_branch) }} use git branch constraints.
|
56
|
+
#{benchers.count { |x| x.is_type?(:git) }} use some other form of git constraint considered not strict enough.
|
57
|
+
#{benchers.count { |x| x.is_type?(:unknown) }} gems seem to not have any constraint at all.
|
58
|
+
#{using_path} gems are using a local path. #{"WARNING!!!" if using_path > 0}
|
59
|
+
EOS
|
64
60
|
end
|
65
61
|
end
|
66
62
|
end
|