gem-compare 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,150 @@
1
+ require 'gemnasium/parser'
2
+ require 'rubygems/comparator/base'
3
+
4
+ class Gem::Comparator
5
+
6
+ ##
7
+ # Gem::Comparator::GemfileComparator can
8
+ # compare dependencies between gem's Gemfiles
9
+ # based on the given Gem::Package objects
10
+ #
11
+ # To compare Gemfiles it needs to extract
12
+ # gem packages to +options[:output]+
13
+
14
+ class GemfileComparator
15
+ include Gem::Comparator::Base
16
+
17
+ COMPARES = :packages
18
+
19
+ ##
20
+ # Compare Gemfiles using gem's +packages+
21
+ # and write the changes to the +report+
22
+
23
+ def compare(packages, report, options = {})
24
+ info 'Checking Gemfiles for dependencies...'
25
+ return report if options[:param] && options[:param] != 'gemfiles'
26
+
27
+ @packages = packages
28
+ all_same = true
29
+
30
+ # Check Gemfiles from older versions to newer
31
+ packages.each_with_index do |pkg, index|
32
+ unpacked_gem_dirs[@packages[index].spec.version] = extract_gem(pkg, options[:output])
33
+ next if index == 0
34
+
35
+ prev_gemfile = File.join(unpacked_gem_dirs[@packages[index-1].spec.version], 'Gemfile')
36
+ curr_gemfile = File.join(unpacked_gem_dirs[@packages[index].spec.version], 'Gemfile')
37
+
38
+ vers = "#{@packages[index-1].spec.version}->#{@packages[index].spec.version}"
39
+ report['gemfiles'][vers].set_header "#{Rainbow(packages[index-1].spec.version).blue}->" +
40
+ "#{Rainbow(packages[index].spec.version).blue}:"
41
+
42
+ if File.exist?(prev_gemfile) && File.exist?(curr_gemfile)
43
+ added, deleted, updated = compare_gemfiles(prev_gemfile, curr_gemfile)
44
+
45
+ report['gemfiles'][vers]['added'].section do
46
+ set_header '* Added:'
47
+ puts added.map { |x| "#{x.name} #{x.requirements_list}" } unless added.empty?
48
+ end
49
+ report['gemfiles'][vers]['deleted'].section do
50
+ set_header '* Deleted'
51
+ puts deleted.map { |x| "#{x.name} #{x.requirements_list}" } unless deleted.empty?
52
+ end
53
+ report['gemfiles'][vers]['updated'].section do
54
+ set_header '* Updated'
55
+ puts updated unless updated.empty?
56
+ end
57
+ all_same = false if !added.empty? || !deleted.empty?
58
+ elsif File.exist?(prev_gemfile)
59
+ report['gemfiles'][vers] << "Gemfile removed"
60
+ all_same = false
61
+ elsif File.exist?(curr_gemfile)
62
+ report['gemfiles'][vers] << "Gemfile added"
63
+ all_same = false
64
+ end
65
+ end
66
+ if all_same && options[:log_all]
67
+ report['gemfiles'].set_header "#{same} Gemfiles:"
68
+ gemfile = File.join(unpacked_gem_dirs[@packages[1].spec.version], 'Gemfile')
69
+ if File.exist? gemfile
70
+ deps = gemfile_deps(gemfile)
71
+ deps = '[]' if deps.empty?
72
+ report['gemfiles'] << deps
73
+ else
74
+ report['gemfiles'] << 'No Gemfiles'
75
+ end
76
+ elsif !all_same
77
+ report['gemfiles'].set_header "#{different} Gemfile dependencies"
78
+ end
79
+
80
+ report
81
+ end
82
+
83
+ private
84
+
85
+ ##
86
+ # Access @unpacked_gem_dirs hash that stores
87
+ # paths to the unpacked gem dirs
88
+ #
89
+ # Keys of the hash are gem's versions
90
+
91
+ def unpacked_gem_dirs
92
+ @unpacked_gem_dirs ||= {}
93
+ end
94
+
95
+ ##
96
+ # Compare two Gemfiles for dependencies
97
+ #
98
+ # Return [added, deleted, updated] deps
99
+
100
+ def compare_gemfiles(prev_gemfile, curr_gemfile)
101
+ prev_deps = gemfile_deps(prev_gemfile)
102
+ curr_deps = gemfile_deps(curr_gemfile)
103
+ added = curr_deps - prev_deps
104
+ deleted = prev_deps - curr_deps
105
+
106
+ split_dependencies(added, deleted)
107
+ end
108
+
109
+ ##
110
+ # Get the Gemfile dependencies from +gemfile+
111
+
112
+ def gemfile_deps(gemfile)
113
+ parse_gemfile(gemfile).dependencies
114
+ end
115
+
116
+ ##
117
+ # Parse +gemfile+ using Gemnasium::Parser
118
+ #
119
+ # Return Gemnasium::Parser::Gemfile
120
+
121
+ def parse_gemfile(gemfile)
122
+ Gemnasium::Parser.gemfile File.open(gemfile).read
123
+ end
124
+
125
+ ##
126
+ # Find updated dependencies between +added+ and
127
+ # +deleted+ deps and move them out to +updated+.
128
+ #
129
+ # Return [added, deleted, updated] deps
130
+
131
+ def split_dependencies(added, deleted)
132
+ updated = []
133
+ added.dup.each do |ad|
134
+ deleted.dup.each do |dd|
135
+ if ad.name == dd.name && ad.type == dd.type
136
+ unless ad.requirements_list == dd.requirements_list
137
+ updated << "#{ad.name} " +
138
+ "from: #{dd.requirements_list} " +
139
+ "to: #{ad.requirements_list}"
140
+ end
141
+ added.delete ad
142
+ deleted.delete dd
143
+ end
144
+ end
145
+ end
146
+ [added, deleted, updated]
147
+ end
148
+
149
+ end
150
+ end
@@ -0,0 +1,121 @@
1
+ class Gem::Comparator
2
+ class Report
3
+
4
+ def self.new(name = 'main')
5
+ Gem::Comparator::Report::NestedSection.new(name)
6
+ end
7
+
8
+ class NestedSection
9
+ include Gem::Comparator::Base
10
+ include Gem::UserInteraction
11
+
12
+ DEFAULT_INDENT = ' '
13
+
14
+ attr_reader :header, :messages, :parent_section, :level
15
+ attr_accessor :name, :sections
16
+
17
+ def initialize(name, parent_section = nil)
18
+ @name = name
19
+ @header = Entry.new
20
+ @messages = []
21
+ @sections = []
22
+ @level = 0
23
+
24
+ set_parent parent_section if parent_section
25
+ end
26
+
27
+ def section(&block)
28
+ instance_eval &block
29
+ end
30
+
31
+ def set_header(message)
32
+ @header = Entry.new(message)
33
+ end
34
+
35
+ def puts(message)
36
+ @messages << Entry.new(message)
37
+ end
38
+ alias_method :<<, :puts
39
+
40
+ def nest(name)
41
+ @sections.each { |s| if s.name == name; return s; end }
42
+ NestedSection.new(name, self)
43
+ end
44
+ alias_method :[], :nest
45
+
46
+ def print
47
+ all_messages.each { |m| m.print }
48
+ end
49
+
50
+ def all_messages
51
+ indent = DEFAULT_INDENT*@level
52
+
53
+ if @header.empty?
54
+ @messages.map { |m| m.set_indent!(indent) } + nested_messages
55
+ else
56
+ nested = @messages.map { |m| m.set_indent!(indent * 2) } + nested_messages
57
+ return [] if nested.empty?
58
+
59
+ @header.set_indent!(indent)
60
+ nested.unshift(@header)
61
+ end
62
+ end
63
+
64
+ def lines(line_num)
65
+ all_messages[line_num].data
66
+ end
67
+
68
+ def nested_messages
69
+ nested_messages = []
70
+ @sections.each do |section|
71
+ section.all_messages.each do |m|
72
+ nested_messages << m
73
+ end
74
+ end
75
+ nested_messages
76
+ end
77
+
78
+ private
79
+
80
+ def set_parent(parent)
81
+ parent.sections << self
82
+ @level = parent.level + 1
83
+ parent_section = parent
84
+ end
85
+
86
+ end
87
+
88
+ class Entry
89
+ include Gem::UserInteraction
90
+
91
+ attr_accessor :data, :indent
92
+
93
+ def initialize(data = '', indent = '')
94
+ @data = data
95
+ @indent = indent
96
+ end
97
+
98
+ def set_indent!(indent)
99
+ @indent = indent
100
+ self
101
+ end
102
+
103
+ def empty?
104
+ case @data
105
+ when String, Array
106
+ @data.empty?
107
+ end
108
+ end
109
+
110
+ def print
111
+ printed = case @data
112
+ when String
113
+ "#{@indent}#{@data}"
114
+ when Array
115
+ @indent + @data.join("\n#{@indent}")
116
+ end
117
+ say printed
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,77 @@
1
+ require 'rubygems/comparator/base'
2
+
3
+ class Gem::Comparator
4
+
5
+ ##
6
+ # Gem::Comparator::SpecComparator can
7
+ # compare values from the gem verions specs
8
+
9
+ class SpecComparator
10
+ include Gem::Comparator::Base
11
+
12
+ COMPARES = :specs
13
+
14
+ ##
15
+ # Compare common fields in spec
16
+
17
+ def compare(specs, report, options = {})
18
+ info 'Checking spec parameters...'
19
+
20
+ filter_params(SPEC_PARAMS, options[:param]).each do |param|
21
+ values = values_from_specs(param, specs)
22
+
23
+ # Are values the same?
24
+ if same_values?(values) && options[:log_all]
25
+ v = value(values[0])
26
+ report[param].section do
27
+ set_header "#{same} #{param}:"
28
+ puts v
29
+ end
30
+ elsif !same_values?(values)
31
+ report[param].set_header "#{different} #{param}:"
32
+ values.each_with_index do |value, index|
33
+ report[param] << \
34
+ "#{Rainbow(specs[index].version).blue}: #{value}"
35
+ end
36
+ end
37
+ end
38
+ report
39
+ end
40
+
41
+ private
42
+
43
+ def values_from_specs(param, specs)
44
+ values = []
45
+ specs.each do |s|
46
+ if s.respond_to? :"#{param}"
47
+ values << s.send(:"#{param}")
48
+ else
49
+ warn "#{s.full_name} does not respond to " +
50
+ "#{param}, skipping check"
51
+ end
52
+ end
53
+ values
54
+ end
55
+
56
+ def value(value)
57
+ case value
58
+ when Gem::Requirement
59
+ unless value.requirements.empty?
60
+ r = value.requirements[0]
61
+ "#{r[0]} #{r[1].version} "
62
+ else
63
+ '[]'
64
+ end
65
+ when String
66
+ return value unless value.empty?
67
+ ''
68
+ else
69
+ value.inspect
70
+ end
71
+ end
72
+
73
+ def same_values?(values)
74
+ values.count(values[0]) == values.size
75
+ end
76
+ end
77
+ end
@@ -1,9 +1,2 @@
1
1
  require 'rubygems/command_manager'
2
- require 'rubygems/commands/compare_command'
3
-
4
2
  Gem::CommandManager.instance.register_command :compare
5
-
6
- Gem.post_install do |installer|
7
- #installer.spec
8
- Gem::Commands::CompareCommand.execute
9
- end
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+
3
+ class TestDependencyComparator < TestGemComparator
4
+
5
+ def test_runtime_dependencies_comparison
6
+ assert_equal 'DIFFERENT runtime dependencies:', @report['runtime_dependency'].header.data
7
+ assert_equal 'DIFFERENT runtime dependencies:', @report['runtime_dependency'].lines(0)
8
+ assert_equal '0.0.2->0.0.3:', @report['runtime_dependency']['0.0.2->0.0.3'].header.data
9
+ assert_equal '0.0.2->0.0.3:', @report['runtime_dependency'].lines(1)
10
+ assert_equal '* Added:', @report['runtime_dependency']['0.0.2->0.0.3']['added'].lines(0)
11
+ assert_equal [], @report['runtime_dependency']['0.0.2->0.0.3']['deleted'].messages
12
+ assert_equal [], @report['runtime_dependency']['0.0.2->0.0.3']['updated'].messages
13
+ assert_equal ['rails [">= 4.0.0"] (runtime)'], @report['runtime_dependency']['0.0.2->0.0.3']['added'].lines(1)
14
+ assert_equal '0.0.3->0.0.4:', @report['runtime_dependency']['0.0.3->0.0.4'].header.data
15
+ assert_equal '0.0.3->0.0.4:', @report['runtime_dependency'].lines(4)
16
+ assert_equal [], @report['runtime_dependency']['0.0.3->0.0.4']['added'].messages
17
+ assert_equal [], @report['runtime_dependency']['0.0.3->0.0.4']['deleted'].messages
18
+ assert_equal ['rails from: [">= 4.0.0"] to: [">= 4.1.0"]'], @report['runtime_dependency']['0.0.3->0.0.4']['updated'].lines(1)
19
+ end
20
+
21
+ def test_development_dependencies_comparison
22
+ assert_equal [], @report['development_dependency']['0.0.1->0.0.2']['added'].messages
23
+ assert_equal [], @report['development_dependency']['0.0.1->0.0.2']['deleted'].messages
24
+ assert_equal [], @report['development_dependency']['0.0.1->0.0.2']['updated'].messages
25
+ assert_equal [], @report['development_dependency']['0.0.2->0.0.3']['added'].messages
26
+ assert_equal [], @report['development_dependency']['0.0.2->0.0.3']['deleted'].messages
27
+ assert_equal [], @report['development_dependency']['0.0.2->0.0.3']['updated'].messages
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ require 'test_helper'
2
+
3
+ class TestFileListComparator < TestGemComparator
4
+
5
+ def test_files_comparison
6
+ assert_equal 'DIFFERENT files:', @report['files'].header.data
7
+ assert_equal '0.0.1->0.0.2:', @report['files'].lines(1)
8
+ assert_equal ["CHANGELOG.md"], @report['files']['0.0.1->0.0.2']['added'].lines(1)
9
+ assert_equal [], @report['files']['0.0.1->0.0.2']['deleted'].messages
10
+ assert_equal [], @report['files']['0.0.1->0.0.2']['updated'].messages
11
+ assert_equal ["bin/lorem", "lib/lorem/utils.rb"], @report['files']['0.0.2->0.0.3']['added'].lines(1)
12
+ assert_equal [], @report['files']['0.0.2->0.0.3']['deleted'].messages
13
+ assert_equal [], @report['files']['0.0.2->0.0.3']['updated'].messages
14
+ assert_equal [], @report['files']['0.0.3->0.0.4']['added'].messages
15
+ assert_equal [], @report['files']['0.0.3->0.0.4']['deleted'].messages
16
+ assert_equal [], @report['files']['0.0.3->0.0.4']['updated'].messages
17
+ end
18
+
19
+ def test_test_files_comparison
20
+ assert_equal 'SAME test_files:', @report['test_files'].header.data
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ require 'test_helper'
2
+
3
+ class TestGemfileComparator < TestGemComparator
4
+
5
+ def test_gemfile_comparison
6
+ assert_equal '0.0.1->0.0.2:', @report['gemfiles']['0.0.1->0.0.2'].header.data
7
+ assert_equal [], @report['gemfiles']['0.0.1->0.0.2'].messages
8
+ assert_equal [], @report['gemfiles']['0.0.2->0.0.3'].messages
9
+ assert_equal [], @report['gemfiles']['0.0.3->0.0.4']['added'].messages
10
+ assert_equal '* Deleted', @report['gemfiles']['0.0.3->0.0.4'].lines(1)
11
+ assert_equal ['appraisal [">= 0"]'], @report['gemfiles']['0.0.3->0.0.4']['deleted'].lines(1)
12
+ assert_equal ['minitest from: [">= 0"] to: ["= 5.0.0"]'], @report['gemfiles']['0.0.3->0.0.4']['updated'].lines(1)
13
+ end
14
+ end
@@ -0,0 +1,153 @@
1
+ require 'test_helper'
2
+
3
+ class TestSpecComparator < TestGemComparator
4
+
5
+ def test_name_comparison
6
+ assert_equal 'SAME name:', @report['name'].header.data
7
+ assert_equal 'SAME name:', @report['name'].lines(0)
8
+ end
9
+
10
+ def test_version_comparison
11
+ assert_equal 'DIFFERENT version:', @report['version'].header.data
12
+ assert_equal 'DIFFERENT version:', @report['version'].lines(0)
13
+ assert_equal '0.0.1: 0.0.1', @report['version'].lines(1)
14
+ assert_equal '0.0.2: 0.0.2', @report['version'].lines(2)
15
+ assert_equal '0.0.3: 0.0.3', @report['version'].lines(3)
16
+ assert_equal '0.0.4: 0.0.4', @report['version'].lines(4)
17
+ end
18
+
19
+ def test_licenses_comparison
20
+ assert_equal 'DIFFERENT license:', @report['license'].header.data
21
+ assert_equal 'DIFFERENT licenses:', @report['licenses'].header.data
22
+ assert_equal 'DIFFERENT license:', @report['license'].lines(0)
23
+ assert_equal 'DIFFERENT licenses:', @report['licenses'].lines(0)
24
+ assert_equal '0.0.1: MIT', @report['license'].lines(1)
25
+ assert_equal '0.0.2: GPLv2', @report['license'].lines(2)
26
+ assert_equal '0.0.3: GPLv2', @report['license'].lines(3)
27
+ assert_equal '0.0.4: GPLv2', @report['license'].lines(4)
28
+ assert_equal '0.0.1: ["MIT"]', @report['licenses'].lines(1)
29
+ assert_equal '0.0.2: ["GPLv2"]', @report['licenses'].lines(2)
30
+ assert_equal '0.0.3: ["GPLv2"]', @report['licenses'].lines(3)
31
+ assert_equal '0.0.4: ["GPLv2"]', @report['licenses'].lines(4)
32
+ end
33
+
34
+ def test_authors_comparison
35
+ assert_equal 'SAME author:', @report['author'].header.data
36
+ assert_equal 'SAME authors:', @report['authors'].header.data
37
+ assert_equal 'SAME author:', @report['author'].lines(0)
38
+ assert_equal 'SAME authors:', @report['authors'].lines(0)
39
+ end
40
+
41
+ def test_email_comparison
42
+ assert_equal 'SAME email:', @report['email'].header.data
43
+ assert_equal 'SAME email:', @report['email'].lines(0)
44
+ end
45
+
46
+ def test_summary_comparison
47
+ assert_equal 'DIFFERENT summary:', @report['summary'].header.data
48
+ assert_equal 'DIFFERENT summary:', @report['summary'].lines(0)
49
+ assert_equal '0.0.1: lorem is a gem for testing gem-compare', @report['summary'].lines(1)
50
+ assert_equal '0.0.2: lorem is a gem for testing gem-compare', @report['summary'].lines(2)
51
+ assert_equal '0.0.3: lorem is a gem for testing gem-compare', @report['summary'].lines(3)
52
+ assert_equal '0.0.4: lorem is a gem for testing gem-compare plugin', @report['summary'].lines(4)
53
+ end
54
+
55
+ def test_description_comparison
56
+ assert_equal 'DIFFERENT description:', @report['description'].header.data
57
+ assert_equal 'DIFFERENT description:', @report['description'].lines(0)
58
+ assert_equal '0.0.1: lorem changes a lot so we can test gem-compare a lot', @report['description'].lines(1)
59
+ assert_equal '0.0.2: lorem changes a lot so we can test gem-compare a lot', @report['description'].lines(2)
60
+ assert_equal '0.0.3: lorem changes a lot so we can test gem-compare a lot', @report['description'].lines(3)
61
+ assert_equal '0.0.4: lorem changes a lot so we can test gem-compare plugin a lot', @report['description'].lines(4)
62
+ end
63
+
64
+ def test_homepage_comparison
65
+ assert_equal 'DIFFERENT homepage:', @report['homepage'].header.data
66
+ assert_equal 'DIFFERENT homepage:', @report['homepage'].lines(0)
67
+ assert_equal '0.0.1: ', @report['homepage'].lines(1)
68
+ assert_equal '0.0.2: ', @report['homepage'].lines(2)
69
+ assert_equal '0.0.3: http://lorem.lorem', @report['homepage'].lines(3)
70
+ assert_equal '0.0.4: http://lorem.lorem', @report['homepage'].lines(4)
71
+ end
72
+
73
+ def test_platform_comparison
74
+ assert_equal 'SAME platform:', @report['platform'].header.data
75
+ assert_equal 'SAME platform:', @report['platform'].lines(0)
76
+ end
77
+
78
+ def test_require_paths_comparison
79
+ assert_equal 'SAME require_paths:', @report['require_paths'].header.data
80
+ assert_equal 'SAME require_paths:', @report['require_paths'].lines(0)
81
+ end
82
+
83
+ def test_bindir_comparison
84
+ assert_equal 'SAME bindir:', @report['bindir'].header.data
85
+ assert_equal 'SAME bindir:', @report['bindir'].lines(0)
86
+ end
87
+
88
+ def test_rubygems_version_comparison
89
+ assert_equal 'SAME rubygems_version:', @report['rubygems_version'].header.data
90
+ assert_equal 'SAME rubygems_version:', @report['rubygems_version'].lines(0)
91
+ end
92
+
93
+ def test_cert_chain_comparison
94
+ assert_equal 'SAME cert_chain:', @report['cert_chain'].header.data
95
+ assert_equal 'SAME cert_chain:', @report['cert_chain'].lines(0)
96
+ end
97
+
98
+ def test_executables_comparison
99
+ assert_equal 'DIFFERENT executables:', @report['executables'].header.data
100
+ assert_equal 'DIFFERENT executables:', @report['executables'].lines(0)
101
+ end
102
+
103
+ def test_extensions_comparison
104
+ assert_equal 'SAME extensions:', @report['extensions'].header.data
105
+ assert_equal 'SAME extensions:', @report['extensions'].lines(0)
106
+ end
107
+
108
+ def test_metadata_comparison
109
+ assert_equal 'SAME metadata:', @report['metadata'].header.data
110
+ assert_equal 'SAME metadata:', @report['metadata'].lines(0)
111
+ end
112
+
113
+ def test_post_install_message_comparison
114
+ assert_equal 'SAME post_install_message:', @report['post_install_message'].header.data
115
+ assert_equal 'SAME post_install_message:', @report['post_install_message'].lines(0)
116
+ end
117
+
118
+ def test_rdoc_options_comparison
119
+ assert_equal 'SAME rdoc_options:', @report['rdoc_options'].header.data
120
+ assert_equal 'SAME rdoc_options:', @report['rdoc_options'].lines(0)
121
+ end
122
+
123
+ def test_required_ruby_version_comparison
124
+ assert_equal 'SAME required_ruby_version:', @report['required_ruby_version'].header.data
125
+ assert_equal 'SAME required_ruby_version:', @report['required_ruby_version'].lines(0)
126
+ end
127
+
128
+ def test_required_rubygems_version_comparison
129
+ assert_equal 'SAME required_rubygems_version:', @report['required_rubygems_version'].header.data
130
+ assert_equal 'SAME required_rubygems_version:', @report['required_rubygems_version'].lines(0)
131
+ end
132
+
133
+ def test_requirements_comparison
134
+ assert_equal 'SAME requirements:', @report['requirements'].header.data
135
+ assert_equal 'SAME requirements:', @report['requirements'].lines(0)
136
+ end
137
+
138
+ def test_signing_key_comparison
139
+ assert_equal 'SAME signing_key:', @report['signing_key'].header.data
140
+ assert_equal 'SAME signing_key:', @report['signing_key'].lines(0)
141
+ end
142
+
143
+ def test_has_rdoc_comparison
144
+ assert_equal 'SAME has_rdoc:', @report['has_rdoc'].header.data
145
+ assert_equal 'SAME has_rdoc:', @report['has_rdoc'].lines(0)
146
+ end
147
+
148
+ def test_date_comparison
149
+ assert_equal 'SAME date:', @report['date'].header.data
150
+ assert_equal 'SAME date:', @report['date'].lines(0)
151
+ end
152
+
153
+ end