gem-compare 0.0.2 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 41f631f7e0326a83d40c522f6003ee17c58d3862
4
- data.tar.gz: 93bbd6f62d8c2a98bd93458f6dbb1c9f74647825
3
+ metadata.gz: c0bf945c951c897beae61add41492c92c95248fa
4
+ data.tar.gz: 1113168bb3eeb4cc7af658f2b8a7bd2665c771a4
5
5
  SHA512:
6
- metadata.gz: d384515bab09282848e2900d9737f13222e331d2853cc4fc2bc49411b08118368aec9a4d3fcd023055fba4c3dc127654b35ff09679956485824196b01f35fea5
7
- data.tar.gz: 3859779673f455b99b0a0230386b25f1b9aab3e02a8db1a533c1fb5fc2f2b97ee16a06707168d041cb7e0dfd89848a98eaeaf14c769944c18c283dc1c8359a48
6
+ metadata.gz: c4da75c477e6784574cc96651df72e4aaa3621fac232170ace9634dce53192b88997cf42115285bad9a047fb69a0f217823f20e5a4da095ab85213f707ff0232
7
+ data.tar.gz: 0c0b71c3002837de7e87b096cd6c98189708baa56e9a478135974a35d7853c88620bdb145bf12321b11950bf9e92c3d3a962c032e1068cb4f904e7ea52dec24d
data/README.md CHANGED
@@ -134,6 +134,15 @@ Compared versions: ["0.1.0", "0.1.1", "0.1.2", "0.2.0", "0.2.1", "0.2.2", "0.2.3
134
134
  rspec from: [">= 0"] to: ["= 2.14.1"]
135
135
  ```
136
136
 
137
+ #### Platforms
138
+
139
+ *gem-compare* supports querying different gem platforms via standard `--platform` option. To compare
140
+ nokogiri gem on different platform run:
141
+ ```
142
+ $ gem compare nokogiri 1.5.6 1.6.1 -ak --platform java # for JRuby
143
+ $ gem compare nokogiri 1.5.6 1.6.1 -ak --platform x86-mingw32 # on Windows
144
+ ```
145
+
137
146
  ### Supported options
138
147
 
139
148
  To see all possible options run:
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require 'rdoc/task'
4
4
 
5
5
  gemspec = Gem::Specification.new do |s|
6
6
  s.name = 'gem-compare'
7
- s.version = '0.0.2'
7
+ s.version = '0.0.3'
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.summary = 'RubyGems plugin for comparing gem versions'
10
10
  s.description = <<-EOF
@@ -19,6 +19,8 @@ gemspec = Gem::Specification.new do |s|
19
19
  'lib/**/*.rb', 'lib/**/**/*.rb', 'test/**/test*.rb']
20
20
  s.required_ruby_version = '>= 2.0.0'
21
21
  s.required_rubygems_version = '>= 2.0.0'
22
+ s.add_runtime_dependency 'json'
23
+ s.add_runtime_dependency 'curl'
22
24
  s.add_runtime_dependency 'diffy'
23
25
  s.add_runtime_dependency 'rainbow'
24
26
  s.add_runtime_dependency 'gemnasium-parser'
@@ -1,7 +1,10 @@
1
1
  require 'rubygems/command'
2
+ require 'rubygems/version_option'
2
3
  require 'rubygems/comparator'
3
4
 
4
5
  class Gem::Commands::CompareCommand < Gem::Command
6
+ include Gem::VersionOption
7
+
5
8
  def initialize
6
9
  super 'compare', 'Compare gem\'s versions and generate a report of changes',
7
10
  :output => Dir.pwd
@@ -18,7 +21,10 @@ class Gem::Commands::CompareCommand < Gem::Command
18
21
  options[:no_color] = true
19
22
  end
20
23
 
21
- add_option('-pPARAM', '--param=PARAM', 'Compare only a given paramater') do |param, options|
24
+ # Speficy the platform using --platform=PLATFORM
25
+ add_platform_option
26
+
27
+ add_option('-pPARAM', '--param PARAM', 'Compare only a given paramater') do |param, options|
22
28
  options[:param] = param
23
29
  end
24
30
 
@@ -1,10 +1,12 @@
1
1
  require 'tmpdir'
2
2
  require 'rbconfig'
3
3
  require 'rainbow'
4
+ require 'curb'
5
+ require 'json'
4
6
  require 'rubygems/package'
5
7
  require 'rubygems/dependency'
6
8
  require 'rubygems/spec_fetcher'
7
- require 'rubygems/comparator/base'
9
+ require 'rubygems/comparator/utils'
8
10
  require 'rubygems/comparator/report'
9
11
  require 'rubygems/comparator/spec_comparator'
10
12
  require 'rubygems/comparator/file_list_comparator'
@@ -17,7 +19,7 @@ require 'rubygems/comparator/gemfile_comparator'
17
19
  # Gemfiles
18
20
 
19
21
  class Gem::Comparator
20
- include Gem::Comparator::Base
22
+ include Gem::Comparator::Utils
21
23
  attr_accessor :options, :report
22
24
 
23
25
  VERSION = '0.0.2'
@@ -28,6 +30,8 @@ class Gem::Comparator
28
30
  # Creates temporal directory if the gem files shouldn't be kept
29
31
 
30
32
  def initialize(options)
33
+ info "gem-compare in #{VERSION}"
34
+
31
35
  unless options[:keep_all]
32
36
  options[:output] = Dir.mktmpdir
33
37
  end
@@ -40,6 +44,14 @@ class Gem::Comparator
40
44
  Rainbow.enabled = false
41
45
  end
42
46
 
47
+ # Let's override platforms with the latest one if
48
+ # a platform has been specified via --platform
49
+ if options[:added_platform]
50
+ Gem.platforms = [Gem.platforms.last]
51
+ options[:platform] = Gem.platforms.last.to_s
52
+ info "Overriding platform to: #{options[:platform]}"
53
+ end
54
+
43
55
  @options = options
44
56
 
45
57
  # Results from the comparison
@@ -52,18 +64,22 @@ class Gem::Comparator
52
64
  # Compares file lists, requirements, other meta data
53
65
 
54
66
  def compare_versions(gem_name, versions)
55
- info "gem-compare in #{VERSION}"
56
67
  # Expand versions (<=, >=, ~>) and sort them
57
68
  versions = expand_versions(gem_name, versions)
58
69
 
59
70
  error 'Only one version specified. Specify at lease two versions.' \
60
71
  if versions.size == 1
61
72
 
73
+ # This should match the final versions that has been compared
74
+ @compared_versions = versions
75
+
62
76
  versions.each do |version|
63
- download_gems? ? download_package(gem_name, version) : download_specification(gem_name, version)
77
+ download_gems? ?
78
+ get_package(gem_name, version) :
79
+ get_specification(gem_name, version)
64
80
  end
65
81
 
66
- @report.set_header "Compared versions: #{versions}"
82
+ @report.set_header "Compared versions: #{@compared_versions}"
67
83
 
68
84
  comparators = [SpecComparator,
69
85
  FileListComparator,
@@ -72,7 +88,7 @@ class Gem::Comparator
72
88
 
73
89
  comparators.each do |c|
74
90
  comparator = c.new
75
- cmp = (c::COMPARES == :packages) ? gem_packages.values : gem_specs.values
91
+ cmp = (comparator.compares == :packages) ? gem_packages.values : gem_specs.values
76
92
  @report = comparator.compare(cmp, @report, @options)
77
93
  end
78
94
 
@@ -95,9 +111,10 @@ class Gem::Comparator
95
111
  # Return list of expanded versions
96
112
 
97
113
  def expand_versions(gem_name, versions)
98
- info 'Expanding versions...'
114
+ info "Expanding versions #{versions}..."
99
115
  expanded = []
100
116
  versions.each do |version|
117
+ version = latest_gem_version(gem_name) if version == '_'
101
118
  if version =~ VERSION_REGEX
102
119
  expanded << version
103
120
  next
@@ -121,22 +138,46 @@ class Gem::Comparator
121
138
 
122
139
  error 'No versions found.' if versions.size == 0
123
140
 
124
- info "Versions: #{versions}"
141
+ info "Expanded versions: #{versions}"
125
142
  versions
126
143
  end
127
144
 
145
+ def remote_gem_versions(gem_name)
146
+ client = Curl::Easy.new
147
+ client.url = "https://rubygems.org/api/v1/versions/#{gem_name}.json"
148
+ client.follow_location = true
149
+ client.http_get
150
+ json = JSON.parse(client.body_str)
151
+ gems = json.collect { |version| version['number'] }
152
+ info "Upstream versions: #{gems}"
153
+ gems
154
+ end
155
+
156
+ def latest_gem_version(gem_name)
157
+ remote_gem_versions(gem_name).map{ |v| Gem::Version.new v }.max.to_s
158
+ end
159
+
128
160
  def gem_file_name(gem_name, version)
129
- "#{gem_name}-#{version}.gem"
161
+ if @options[:platform]
162
+ "#{gem_name}-#{version}-#{@options[:platform]}.gem"
163
+ else
164
+ "#{gem_name}-#{version}.gem"
165
+ end
130
166
  end
131
167
 
132
- def download_package(gem_name, version)
168
+ def get_package(gem_name, version)
133
169
  gem_file = gem_file_name(gem_name, version)
134
170
  return gem_packages["#{gem_file}"] if gem_packages["#{gem_file}"]
135
171
 
136
172
  find_downloaded_gem(gem_file)
137
173
  return gem_packages["#{gem_file}"] if gem_packages["#{gem_file}"]
138
174
 
139
- spec, source = download_specification(gem_name, version)
175
+ download_package(gem_name, version)
176
+ end
177
+
178
+ def download_package(gem_name, version)
179
+ spec, source = get_specification(gem_name, version)
180
+ gem_file = gem_file_name(gem_name, spec.version.to_s)
140
181
 
141
182
  Dir.chdir @options[:output] do
142
183
  source.download spec
@@ -149,22 +190,44 @@ class Gem::Comparator
149
190
  package
150
191
  end
151
192
 
152
- def download_specification(gem_name, version)
193
+ def get_specification(gem_name, version)
153
194
  gem_file = gem_file_name(gem_name, version)
154
195
  return gem_specs["#{gem_file}"] if gem_specs["#{gem_file}"]
155
196
 
156
197
  find_downloaded_gem(gem_file)
157
198
  return gem_specs["#{gem_file}"] if gem_specs["#{gem_file}"]
158
199
 
200
+ download_specification(gem_name, version)
201
+ end
202
+
203
+ def download_specification(gem_name, version)
159
204
  dep = Gem::Dependency.new gem_name, version
160
205
  specs_and_sources, _errors = Gem::SpecFetcher.fetcher.spec_for_dependency dep
161
206
  spec, source = specs_and_sources.max_by { |s,| s.version }
162
207
  error "Gem #{gem_name} in #{version} doesn't exist." if spec.nil?
208
+
209
+ fix_comparing_version(version, spec.version.to_s)
210
+ gem_file = gem_file_name(gem_name, spec.version.to_s)
211
+
163
212
  gem_specs["#{gem_file}"] = spec
164
213
 
165
214
  [spec, source]
166
215
  end
167
216
 
217
+ ##
218
+ # Ensure the right version is referenced
219
+
220
+ def fix_comparing_version(version, spec_version)
221
+ if spec_version != version
222
+ @compared_versions.each do |v|
223
+ if v == version
224
+ @compared_versions[@compared_versions.index(version)] = spec_version
225
+ return
226
+ end
227
+ end
228
+ end
229
+ end
230
+
168
231
  def find_downloaded_gem(gem_file)
169
232
  if File.exist? File.join(@options[:output], gem_file)
170
233
  info "#{gem_file} exists, using already downloaded file."
@@ -184,7 +247,7 @@ class Gem::Comparator
184
247
 
185
248
  def download_gems?
186
249
  return true if @options[:keep_all]
187
- @options[:param] ? SPEC_FILES_PARAMS.include?(@options[:param]) : true
250
+ @options[:param] ? !param_available_in_marshal?(@options[:param]) : true
188
251
  end
189
252
 
190
253
  def gem_packages
@@ -1,65 +1,28 @@
1
1
  require 'rainbow'
2
+ require 'rubygems/comparator/utils'
3
+ require 'rubygems/comparator/report'
2
4
 
3
5
  class Gem::Comparator
4
- module Base
5
- include Gem::UserInteraction
6
+ class Base
7
+ include Gem::Comparator::Utils
8
+ include Gem::Comparator::Report::Signs
6
9
 
7
- class DiffCommandMissing < StandardError; end
10
+ attr_accessor :compares
8
11
 
9
- SPACE = ' '
10
- DEFAULT_INDENT = SPACE*7
11
- OPERATORS = ['=', '!=', '>', '<', '>=', '<=', '~>']
12
- VERSION_REGEX = /\A(\d+\.){0,}\d+(\.[a-zA-Z]+\d{0,1}){0,1}\z/
13
- SHEBANG_REGEX = /\A#!.*/
14
- SPEC_PARAMS = %w[ author authors name platform require_paths rubygems_version summary
15
- license licenses bindir cert_chain description email executables
16
- extensions homepage metadata post_install_message rdoc_options
17
- required_ruby_version required_rubygems_version requirements
18
- signing_key has_rdoc date version ].sort
19
- SPEC_FILES_PARAMS = %w[ files test_files extra_rdoc_files ]
20
- DEPENDENCY_PARAMS = %w[ runtime_dependency development_dependency ]
21
- GEMFILE_PARAMS = %w[ gemfiles ]
12
+ ##
13
+ # Compare Gem::Specification objects by default
14
+ #
15
+ # To override create your own initialize method and
16
+ # set expect(:packages) to expect Gem::Package objects.
22
17
 
23
- private
24
-
25
- def param_exists?(param)
26
- (SPEC_PARAMS.include? param) ||
27
- (SPEC_FILES_PARAMS.include? param) ||
28
- (DEPENDENCY_PARAMS.include? param) ||
29
- (GEMFILE_PARAMS.include? param)
30
- end
31
-
32
- def filter_params(params, param)
33
- if param
34
- if params.include? param
35
- return [param]
36
- else
37
- return []
38
- end
39
- end
40
-
41
- params
42
- end
43
-
44
- def same
45
- Rainbow('SAME').green.bright
46
- end
18
+ def initialize
19
+ expect(:specs)
20
+ end
47
21
 
48
- def different
49
- Rainbow('DIFFERENT').red.bright
50
- end
51
-
52
- def info(msg)
53
- say msg if Gem.configuration.really_verbose
54
- end
55
-
56
- def warn(msg)
57
- say Rainbow("WARNING: #{msg}").red
58
- end
22
+ private
59
23
 
60
- def error(msg)
61
- say Rainbow("ERROR: #{msg}").red
62
- exit 1
24
+ def expect(what)
25
+ @compares = what
63
26
  end
64
27
 
65
28
  def extract_gem(package, target_dir)
@@ -76,13 +39,5 @@ class Gem::Comparator
76
39
  gem_dir
77
40
  end
78
41
 
79
- def check_diff_command_is_installed
80
- begin
81
- IO.popen('diff --version')
82
- rescue Exception
83
- raise DiffCommandMissing, \
84
- 'Calling `diff` command failed. Do you have it installed?'
85
- end
86
- end
87
42
  end
88
43
  end
@@ -7,15 +7,12 @@ class Gem::Comparator
7
7
  # compare dependencies between gem's versions
8
8
  # based on the given Gem::Specification objects
9
9
 
10
- class DependencyComparator
11
- include Gem::Comparator::Base
12
-
13
- COMPARES = :specs
10
+ class DependencyComparator < Gem::Comparator::Base
14
11
 
15
12
  ##
16
13
  # Compare dependencies in given +specs+ and
17
14
  # write the changes to the +report+
18
- #
15
+ #
19
16
  # If +options[:param]+ is set, it compares only
20
17
  # those dependencies
21
18
 
@@ -25,12 +22,11 @@ class Gem::Comparator
25
22
  filter_params(DEPENDENCY_PARAMS, options[:param]).each do |param|
26
23
  all_same = true
27
24
  type = param.gsub('_dependency', '').to_sym
28
-
29
25
  specs.each_with_index do |s, index|
30
26
  next if index == 0
31
27
 
32
- prev_deps = specs[index-1].dependencies.keep_if { |d| d.type == type }
33
- curr_deps = specs[index].dependencies.keep_if { |d| d.type == type }
28
+ prev_deps = specs[index-1].dependencies.select { |d| d.type == type }
29
+ curr_deps = specs[index].dependencies.select { |d| d.type == type }
34
30
  added, deleted, updated = resolve_dependencies(prev_deps, curr_deps)
35
31
 
36
32
  if (!deleted.empty? || !added.empty? || !updated.empty?)
@@ -60,20 +56,21 @@ class Gem::Comparator
60
56
  end
61
57
  if all_same && options[:log_all]
62
58
  report[param].set_header "#{same} #{type} dependencies:" if options[:log_all]
63
- deps = specs[0].dependencies.keep_if{ |d| d.type == type }.map{ |d| "#{d.name}: #{d.requirements_list}" }
59
+ deps = specs[0].dependencies.select{ |d| d.type == type }.map{ |d| "#{d.name}: #{d.requirements_list}" }
64
60
  deps = '[]' if deps.empty?
65
61
  report[param] << deps
66
62
  elsif !all_same
67
63
  report[param].set_header "#{different} #{type} dependencies:"
68
64
  end
69
65
  end
66
+
70
67
  report
71
68
  end
72
69
 
73
70
  private
74
-
71
+
75
72
  ##
76
- # Find dependencies between +prev_deps+ and +curr_deps+
73
+ # Find dependencies between +prev_deps+ and +curr_deps+
77
74
  #
78
75
  # Return [added, deleted, updated] deps
79
76
 
@@ -82,7 +79,7 @@ class Gem::Comparator
82
79
  deleted = prev_deps - curr_deps
83
80
  split_dependencies(added, deleted)
84
81
  end
85
-
82
+
86
83
  ##
87
84
  # Find updated dependencies between +added+ and
88
85
  # +deleted+ deps and move them out to +updated+.
@@ -0,0 +1,51 @@
1
+ require 'pathname'
2
+
3
+ module DirUtils
4
+ SHEBANG_REGEX = /\A#!.*/
5
+
6
+ attr_accessor :files_first_line
7
+
8
+ def self.file_first_line(file)
9
+ File.open(file){ |f| f.readline }.gsub(/(.*)\n/, '\1')
10
+ rescue
11
+ end
12
+
13
+ def self.file_has_shebang?(file)
14
+ file_first_line(file) =~ SHEBANG_REGEX
15
+ end
16
+
17
+ def self.files_same_first_line?(file1, file2)
18
+ file_first_line(file1) == file_first_line(file2)
19
+ end
20
+
21
+ def self.file_permissions(file)
22
+ sprintf("%o", File.stat(file).mode)
23
+ end
24
+
25
+ def self.gem_bin_file?(file)
26
+ file =~ /(\A|.*\/)bin\/.*/
27
+ end
28
+
29
+ ##
30
+ # Returns a unique list of directories and top level files
31
+ # out of an array of files
32
+
33
+ def self.dirs_of_files(file_list)
34
+ dirs_of_files = []
35
+ file_list.each do |file|
36
+ unless Pathname.new(file).dirname.to_s == '.'
37
+ dirs_of_files << "#{Pathname.new(file).dirname.to_s}/"
38
+ else
39
+ dirs_of_files << file
40
+ end
41
+ end
42
+ dirs_of_files.uniq
43
+ end
44
+
45
+ def self.remove_subdirs(dirs)
46
+ dirs.dup.sort_by(&:length).reverse.each do |dir|
47
+ dirs.delete_if{ |d| d =~ /#{dir}\/.+/ }
48
+ end
49
+ dirs
50
+ end
51
+ end