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 +4 -4
- data/README.md +9 -0
- data/Rakefile +3 -1
- data/lib/rubygems/commands/compare_command.rb +7 -1
- data/lib/rubygems/comparator.rb +76 -13
- data/lib/rubygems/comparator/base.rb +17 -62
- data/lib/rubygems/comparator/dependency_comparator.rb +9 -12
- data/lib/rubygems/comparator/dir_utils.rb +51 -0
- data/lib/rubygems/comparator/file_list_comparator.rb +83 -154
- data/lib/rubygems/comparator/gemfile_comparator.rb +28 -31
- data/lib/rubygems/comparator/monitor.rb +106 -0
- data/lib/rubygems/comparator/report.rb +48 -39
- data/lib/rubygems/comparator/report/entry.rb +38 -0
- data/lib/rubygems/comparator/spec_comparator.rb +10 -23
- data/lib/rubygems/comparator/utils.rb +133 -0
- data/test/rubygems/comparator/test_dependency_comparator.rb +2 -1
- data/test/rubygems/comparator/test_dir_utils.rb +52 -0
- data/test/rubygems/comparator/test_file_list_comparator.rb +5 -2
- data/test/rubygems/comparator/test_monitor.rb +53 -0
- data/test/rubygems/comparator/test_report.rb +23 -0
- data/test/rubygems/comparator/test_utils.rb +33 -0
- data/test/test_helper.rb +12 -1
- metadata +38 -2
@@ -1,12 +1,43 @@
|
|
1
|
+
require 'rubygems/comparator/report/entry'
|
2
|
+
|
1
3
|
class Gem::Comparator
|
4
|
+
|
5
|
+
##
|
6
|
+
# Gem::Comparator::Report can nest sections and print only those that
|
7
|
+
# contain some messages.
|
8
|
+
#
|
9
|
+
# Usage:
|
10
|
+
# report = Gem::Comparator::Report.new
|
11
|
+
# report['section1'] << "Message 1"
|
12
|
+
# report['section1']['subsection1'].set_header 'Message 2 Header'
|
13
|
+
# report['section1']['subsection1'] << "Message 2" if false
|
14
|
+
# report['section1'].section
|
15
|
+
# nest('subsection2').section
|
16
|
+
# puts "Message 3"
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
# report.print
|
20
|
+
#
|
21
|
+
# This won't print Message 2 nor its header saving a lot of if/else.
|
22
|
+
|
2
23
|
class Report
|
3
24
|
|
25
|
+
module Signs
|
26
|
+
def same
|
27
|
+
Rainbow('SAME').green.bright
|
28
|
+
end
|
29
|
+
|
30
|
+
def different
|
31
|
+
Rainbow('DIFFERENT').red.bright
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
4
35
|
def self.new(name = 'main')
|
5
36
|
Gem::Comparator::Report::NestedSection.new(name)
|
6
37
|
end
|
7
38
|
|
8
39
|
class NestedSection
|
9
|
-
include
|
40
|
+
include Report::Signs
|
10
41
|
include Gem::UserInteraction
|
11
42
|
|
12
43
|
DEFAULT_INDENT = ' '
|
@@ -33,12 +64,19 @@ class Gem::Comparator
|
|
33
64
|
end
|
34
65
|
|
35
66
|
def puts(message)
|
36
|
-
|
67
|
+
case message
|
68
|
+
when String, Array
|
69
|
+
@messages << Entry.new(message) unless message.empty?
|
70
|
+
else
|
71
|
+
@messages << Entry.new(message) unless message
|
72
|
+
end
|
37
73
|
end
|
38
74
|
alias_method :<<, :puts
|
39
75
|
|
40
76
|
def nest(name)
|
41
|
-
@sections.each
|
77
|
+
@sections.each do |s|
|
78
|
+
return s if s.name == name
|
79
|
+
end
|
42
80
|
NestedSection.new(name, self)
|
43
81
|
end
|
44
82
|
alias_method :[], :nest
|
@@ -51,16 +89,20 @@ class Gem::Comparator
|
|
51
89
|
indent = DEFAULT_INDENT*@level
|
52
90
|
|
53
91
|
if @header.empty?
|
54
|
-
@messages.map
|
92
|
+
@messages.map do |m|
|
93
|
+
m.set_indent!(indent)
|
94
|
+
end + nested_messages
|
55
95
|
else
|
56
|
-
nested = @messages.map
|
96
|
+
nested = @messages.map do |m|
|
97
|
+
m.set_indent!(indent * 2)
|
98
|
+
end + nested_messages
|
57
99
|
return [] if nested.empty?
|
58
100
|
|
59
101
|
@header.set_indent!(indent)
|
60
102
|
nested.unshift(@header)
|
61
103
|
end
|
62
104
|
end
|
63
|
-
|
105
|
+
|
64
106
|
def lines(line_num)
|
65
107
|
all_messages[line_num].data
|
66
108
|
end
|
@@ -84,38 +126,5 @@ class Gem::Comparator
|
|
84
126
|
end
|
85
127
|
|
86
128
|
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
129
|
end
|
121
130
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Gem::Comparator
|
2
|
+
class Report
|
3
|
+
class Entry
|
4
|
+
include Gem::UserInteraction
|
5
|
+
|
6
|
+
attr_accessor :data, :indent
|
7
|
+
|
8
|
+
def initialize(data = '', indent = '')
|
9
|
+
@data = data
|
10
|
+
@indent = indent
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_indent!(indent)
|
14
|
+
@indent = indent
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def empty?
|
19
|
+
case @data
|
20
|
+
when String, Array
|
21
|
+
@data.empty?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def print
|
26
|
+
printed = case @data
|
27
|
+
when String
|
28
|
+
"#{@indent}#{@data}"
|
29
|
+
when Array
|
30
|
+
@indent + @data.join("\n#{@indent}")
|
31
|
+
else
|
32
|
+
"#{@indent}#{@data}"
|
33
|
+
end
|
34
|
+
say printed
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -5,27 +5,25 @@ class Gem::Comparator
|
|
5
5
|
##
|
6
6
|
# Gem::Comparator::SpecComparator can
|
7
7
|
# compare values from the gem verions specs
|
8
|
-
|
9
|
-
class SpecComparator
|
10
|
-
include Gem::Comparator::Base
|
11
8
|
|
12
|
-
|
9
|
+
class SpecComparator < Gem::Comparator::Base
|
13
10
|
|
14
11
|
##
|
15
12
|
# Compare common fields in spec
|
16
13
|
|
17
14
|
def compare(specs, report, options = {})
|
18
15
|
info 'Checking spec parameters...'
|
16
|
+
p = options[:param]
|
17
|
+
b = options[:brief]
|
19
18
|
|
20
|
-
filter_params(SPEC_PARAMS,
|
19
|
+
filter_params(SPEC_PARAMS, p, b).each do |param|
|
21
20
|
values = values_from_specs(param, specs)
|
22
21
|
|
23
|
-
# Are values the same?
|
24
22
|
if same_values?(values) && options[:log_all]
|
25
|
-
v = value(values[0])
|
23
|
+
v = value(values[0])
|
26
24
|
report[param].section do
|
27
|
-
set_header "#{same} #{param}:"
|
28
|
-
|
25
|
+
set_header "#{self.same} #{param}:"
|
26
|
+
puts v
|
29
27
|
end
|
30
28
|
elsif !same_values?(values)
|
31
29
|
report[param].set_header "#{different} #{param}:"
|
@@ -40,28 +38,17 @@ class Gem::Comparator
|
|
40
38
|
|
41
39
|
private
|
42
40
|
|
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
41
|
def value(value)
|
57
42
|
case value
|
58
43
|
when Gem::Requirement
|
59
44
|
unless value.requirements.empty?
|
60
45
|
r = value.requirements[0]
|
61
|
-
"#{r[0]} #{r[1].version} "
|
46
|
+
"#{r[0]} #{r[1].version} "
|
62
47
|
else
|
63
48
|
'[]'
|
64
49
|
end
|
50
|
+
when Gem::Platform
|
51
|
+
value.to_s
|
65
52
|
when String
|
66
53
|
return value unless value.empty?
|
67
54
|
''
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'rainbow'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rubygems/user_interaction'
|
4
|
+
|
5
|
+
class Gem::Comparator
|
6
|
+
module Utils
|
7
|
+
include Gem::UserInteraction
|
8
|
+
|
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
|
+
SPEC_PARAMS = %w[ author
|
14
|
+
authors
|
15
|
+
bindir
|
16
|
+
cert_chain
|
17
|
+
date
|
18
|
+
description
|
19
|
+
email
|
20
|
+
executables
|
21
|
+
extensions
|
22
|
+
has_rdoc
|
23
|
+
homepage
|
24
|
+
license
|
25
|
+
licenses
|
26
|
+
metadata
|
27
|
+
name
|
28
|
+
platform
|
29
|
+
post_install_message
|
30
|
+
rdoc_options
|
31
|
+
require_paths
|
32
|
+
required_ruby_version
|
33
|
+
required_rubygems_version
|
34
|
+
requirements
|
35
|
+
rubygems_version
|
36
|
+
signing_key
|
37
|
+
summary
|
38
|
+
version ]
|
39
|
+
SPEC_FILES_PARAMS = %w[ files
|
40
|
+
test_files
|
41
|
+
extra_rdoc_files ]
|
42
|
+
DEPENDENCY_PARAMS = %w[ runtime_dependency
|
43
|
+
development_dependency ]
|
44
|
+
GEMFILE_PARAMS = %w[ gemfiles ]
|
45
|
+
|
46
|
+
# Duplicates or obvious changes
|
47
|
+
FILTER_WHEN_BRIEF = %w[ author
|
48
|
+
date
|
49
|
+
license
|
50
|
+
platform
|
51
|
+
rubygems_version
|
52
|
+
version ]
|
53
|
+
|
54
|
+
# Not present in marshal file containing the specs
|
55
|
+
NOT_IN_MARSHAL = %w[ cert_chain
|
56
|
+
executables
|
57
|
+
extensions
|
58
|
+
extra_rdoc_files
|
59
|
+
files
|
60
|
+
license
|
61
|
+
licenses
|
62
|
+
metadata
|
63
|
+
post_install_message
|
64
|
+
rdoc_options
|
65
|
+
requirements
|
66
|
+
signing_key
|
67
|
+
test_files ]
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def param_exists?(param)
|
72
|
+
(SPEC_PARAMS.include? param) ||
|
73
|
+
(SPEC_FILES_PARAMS.include? param) ||
|
74
|
+
(DEPENDENCY_PARAMS.include? param) ||
|
75
|
+
(GEMFILE_PARAMS.include? param)
|
76
|
+
end
|
77
|
+
|
78
|
+
def param_available_in_marshal?(param)
|
79
|
+
param_exists?(param) && !NOT_IN_MARSHAL.include?(param)
|
80
|
+
end
|
81
|
+
|
82
|
+
def filter_params(params, param, brief_mode = false)
|
83
|
+
if param
|
84
|
+
if params.include? param
|
85
|
+
return [param]
|
86
|
+
else
|
87
|
+
return []
|
88
|
+
end
|
89
|
+
end
|
90
|
+
if brief_mode
|
91
|
+
filter_for_brief_mode(params)
|
92
|
+
else
|
93
|
+
params
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def filter_for_brief_mode(params)
|
98
|
+
params.delete_if{ |p| FILTER_WHEN_BRIEF.include?(p) }
|
99
|
+
end
|
100
|
+
|
101
|
+
def values_from_specs(param, specs)
|
102
|
+
values = []
|
103
|
+
specs.each do |s|
|
104
|
+
val = value_from_spec(param, s)
|
105
|
+
values << val if val
|
106
|
+
end
|
107
|
+
values
|
108
|
+
end
|
109
|
+
|
110
|
+
def value_from_spec(param, spec)
|
111
|
+
if spec.respond_to? :"#{param}"
|
112
|
+
spec.send(:"#{param}")
|
113
|
+
else
|
114
|
+
warn "#{spec.full_name} does not respond to " +
|
115
|
+
"#{param}, skipping check"
|
116
|
+
nil
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def info(msg)
|
121
|
+
say msg if Gem.configuration.really_verbose
|
122
|
+
end
|
123
|
+
|
124
|
+
def warn(msg)
|
125
|
+
say Rainbow("WARNING: #{msg}").red
|
126
|
+
end
|
127
|
+
|
128
|
+
def error(msg)
|
129
|
+
say Rainbow("ERROR: #{msg}").red
|
130
|
+
exit 1
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -24,6 +24,7 @@ class TestDependencyComparator < TestGemComparator
|
|
24
24
|
assert_equal [], @report['development_dependency']['0.0.1->0.0.2']['updated'].messages
|
25
25
|
assert_equal [], @report['development_dependency']['0.0.2->0.0.3']['added'].messages
|
26
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'].
|
27
|
+
assert_equal 'bundler from: ["~> 1.6"] to: ["~> 1.0"]', @report['development_dependency']['0.0.2->0.0.3']['updated'].lines(1)[0]
|
28
|
+
assert_equal 'rake from: [">= 0"] to: [">= 10.0.0"]', @report['development_dependency']['0.0.2->0.0.3']['updated'].lines(1)[1]
|
28
29
|
end
|
29
30
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestDirUtils < TestGemModule
|
4
|
+
|
5
|
+
def test_file_first_line
|
6
|
+
file1 = File.join(@v001, 'lib/lorem.rb')
|
7
|
+
file2 = File.join(@v002, 'bin/lorem')
|
8
|
+
file3 = File.join(@v003, 'bin/lorem')
|
9
|
+
assert_equal 'require "lorem/version"', Gem::Comparator::DirUtils.file_first_line(file1)
|
10
|
+
assert_equal nil, Gem::Comparator::DirUtils.file_first_line(file2)
|
11
|
+
assert_equal '#!/usr/bin/ruby', Gem::Comparator::DirUtils.file_first_line(file3)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_file_has_shebang?
|
15
|
+
file1 = File.join(@v003, 'lib/lorem.rb')
|
16
|
+
file2 = File.join(@v004, 'bin/lorem')
|
17
|
+
assert_equal nil, Gem::Comparator::DirUtils.file_has_shebang?(file1)
|
18
|
+
assert_equal 0, Gem::Comparator::DirUtils.file_has_shebang?(file2)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_files_same_first_line?
|
22
|
+
file1 = File.join(@v001, 'lib/lorem.rb')
|
23
|
+
file2 = File.join(@v002, 'lib/lorem.rb')
|
24
|
+
file3 = File.join(@v003, 'bin/lorem')
|
25
|
+
assert_equal true, Gem::Comparator::DirUtils.files_same_first_line?(file1, file2)
|
26
|
+
assert_equal false, Gem::Comparator::DirUtils.files_same_first_line?(file1, file3)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_file_permissions
|
30
|
+
file1 = File.join(@v001, 'lib/lorem.rb')
|
31
|
+
file2 = File.join(@v004, 'bin/lorem')
|
32
|
+
assert_equal '100664', Gem::Comparator::DirUtils.file_permissions(file1)
|
33
|
+
assert_equal '100775', Gem::Comparator::DirUtils.file_permissions(file2)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_gem_bin_file
|
37
|
+
file1 = File.join(@v001, 'lib/lorem.rb')
|
38
|
+
file2 = File.join(@v004, 'bin/lorem')
|
39
|
+
assert_equal nil, Gem::Comparator::DirUtils.gem_bin_file?(file1)
|
40
|
+
assert_equal 0, Gem::Comparator::DirUtils.gem_bin_file?(file2)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_dirs_of_files
|
44
|
+
files = ['Rakefile', '/dir1/file1', '/dir2/file2']
|
45
|
+
assert_equal ["Rakefile", "/dir1/", "/dir2/"], Gem::Comparator::DirUtils.dirs_of_files(files)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_remove_subdirs
|
49
|
+
dirs = ['/dir1/dir2/dir3', '/dir1/dir2', '/dir', 'Gemfile']
|
50
|
+
assert_equal ["/dir1/dir2", "/dir", "Gemfile"], Gem::Comparator::DirUtils.remove_subdirs(dirs)
|
51
|
+
end
|
52
|
+
end
|
@@ -5,10 +5,13 @@ class TestFileListComparator < TestGemComparator
|
|
5
5
|
def test_files_comparison
|
6
6
|
assert_equal 'DIFFERENT files:', @report['files'].header.data
|
7
7
|
assert_equal '0.0.1->0.0.2:', @report['files'].lines(1)
|
8
|
-
assert_equal
|
8
|
+
assert_equal "CHANGELOG.md", @report['files']['0.0.1->0.0.2']['added'].lines(1)
|
9
9
|
assert_equal [], @report['files']['0.0.1->0.0.2']['deleted'].messages
|
10
10
|
assert_equal [], @report['files']['0.0.1->0.0.2']['updated'].messages
|
11
|
-
assert_equal
|
11
|
+
assert_equal "bin/lorem", @report['files']['0.0.2->0.0.3']['added'].lines(1)
|
12
|
+
assert_equal "(!) Unexpected permissions: 100664", @report['files']['0.0.2->0.0.3']['added'].lines(2).strip
|
13
|
+
assert_equal "(!) File is not executable", @report['files']['0.0.2->0.0.3']['added'].lines(3).strip
|
14
|
+
assert_equal "(!) Shebang found: #!/usr/bin/ruby", @report['files']['0.0.2->0.0.3']['added'].lines(4).strip
|
12
15
|
assert_equal [], @report['files']['0.0.2->0.0.3']['deleted'].messages
|
13
16
|
assert_equal [], @report['files']['0.0.2->0.0.3']['updated'].messages
|
14
17
|
assert_equal [], @report['files']['0.0.3->0.0.4']['added'].messages
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestMonitor < TestGemModule
|
4
|
+
|
5
|
+
def test_lines_changed
|
6
|
+
file1 = File.join(@v001, 'lib/lorem.rb')
|
7
|
+
file2 = File.join(@v002, 'lib/lorem.rb')
|
8
|
+
assert_equal '+4/-0', Gem::Comparator::Monitor.lines_changed(file1, file2)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_compact_files_diff
|
12
|
+
file1 = File.join(@v001, 'lib/lorem.rb')
|
13
|
+
file2 = File.join(@v002, 'lib/lorem.rb')
|
14
|
+
assert_equal '++++', Gem::Comparator::Monitor.compact_files_diff(file1, file2)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_files_permissions_changes
|
18
|
+
file1 = File.join(@v003, 'bin/lorem')
|
19
|
+
file2 = File.join(@v004, 'bin/lorem')
|
20
|
+
assert_equal '(!) New permissions: 100664 -> 100775', Gem::Comparator::Monitor.files_permissions_changes(file1, file2).strip
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_new_file_permissions
|
24
|
+
file1 = File.join(@v004, 'bin/lorem')
|
25
|
+
file2 = File.join(@v004, 'lib/lorem.rb')
|
26
|
+
assert_equal '(!) Unexpected permissions: 100775', Gem::Comparator::Monitor.new_file_permissions(file1).strip
|
27
|
+
assert_equal '(!) Unexpected permissions: 100664', Gem::Comparator::Monitor.new_file_permissions(file2).strip
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_files_executability_changes
|
31
|
+
file1 = File.join(@v003, 'bin/lorem')
|
32
|
+
file2 = File.join(@v004, 'bin/lorem')
|
33
|
+
assert_equal '(!) File is now executable!', Gem::Comparator::Monitor.files_executability_changes(file1, file2).strip
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_new_file_executability
|
37
|
+
file1 = File.join(@v003, 'bin/lorem')
|
38
|
+
file2 = File.join(@v004, 'bin/lorem')
|
39
|
+
assert_equal '(!) File is not executable', Gem::Comparator::Monitor.new_file_executability(file1).strip
|
40
|
+
assert_equal '', Gem::Comparator::Monitor.new_file_executability(file2).strip
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_files_shebang_changes
|
44
|
+
file1 = File.join(@v003, 'bin/lorem')
|
45
|
+
file2 = File.join(@v004, 'bin/lorem')
|
46
|
+
assert_equal '', Gem::Comparator::Monitor.files_shebang_changes(file1, file2).strip
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_new_file_shebang
|
50
|
+
file1 = File.join(@v003, 'bin/lorem')
|
51
|
+
assert_equal '(!) Shebang found: #!/usr/bin/ruby', Gem::Comparator::Monitor.new_file_shebang(file1).strip
|
52
|
+
end
|
53
|
+
end
|