gem-compare 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|