jruby-lint 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.
- data/.gitignore +5 -0
- data/Gemfile +12 -0
- data/Guardfile +12 -0
- data/History.txt +4 -0
- data/README.md +62 -0
- data/Rakefile +24 -0
- data/bin/jrlint +5 -0
- data/jruby-lint.gemspec +38 -0
- data/lib/jruby/lint.rb +19 -0
- data/lib/jruby/lint/ast.rb +56 -0
- data/lib/jruby/lint/checkers.rb +24 -0
- data/lib/jruby/lint/checkers/fork_exec.rb +47 -0
- data/lib/jruby/lint/checkers/gem.rb +45 -0
- data/lib/jruby/lint/checkers/gemspec.rb +41 -0
- data/lib/jruby/lint/checkers/object_space.rb +25 -0
- data/lib/jruby/lint/checkers/thread_critical.rb +26 -0
- data/lib/jruby/lint/cli.rb +61 -0
- data/lib/jruby/lint/collectors.rb +75 -0
- data/lib/jruby/lint/collectors/bundler.rb +9 -0
- data/lib/jruby/lint/collectors/gemspec.rb +9 -0
- data/lib/jruby/lint/collectors/rake.rb +9 -0
- data/lib/jruby/lint/collectors/ruby.rb +14 -0
- data/lib/jruby/lint/finding.rb +15 -0
- data/lib/jruby/lint/github.crt +76 -0
- data/lib/jruby/lint/libraries.rb +107 -0
- data/lib/jruby/lint/project.rb +56 -0
- data/lib/jruby/lint/reporters.rb +35 -0
- data/lib/jruby/lint/version.rb +5 -0
- data/spec/fixtures/C-Extension-Alternatives.html +557 -0
- data/spec/jruby/lint/ast_spec.rb +23 -0
- data/spec/jruby/lint/checkers_spec.rb +135 -0
- data/spec/jruby/lint/cli_spec.rb +66 -0
- data/spec/jruby/lint/collectors_spec.rb +34 -0
- data/spec/jruby/lint/finding_spec.rb +31 -0
- data/spec/jruby/lint/libraries_spec.rb +56 -0
- data/spec/jruby/lint/project_spec.rb +77 -0
- data/spec/jruby/lint/reporters_spec.rb +42 -0
- data/spec/jruby/lint/version_spec.rb +6 -0
- data/spec/spec_helper.rb +30 -0
- metadata +194 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
module JRuby::Lint
|
2
|
+
module Checkers
|
3
|
+
class ThreadCritical
|
4
|
+
include Checker
|
5
|
+
|
6
|
+
METHODS = %w(critical critical=)
|
7
|
+
|
8
|
+
def visitCallNode(node)
|
9
|
+
if METHODS.include?(node.name)
|
10
|
+
begin
|
11
|
+
if node.receiver_node.node_type.to_s == "CONSTNODE" && node.receiver_node.name == "Thread"
|
12
|
+
add_finding(collector, node)
|
13
|
+
end
|
14
|
+
rescue
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
alias visitAttrAssignNode visitCallNode
|
19
|
+
|
20
|
+
def add_finding(collector, node)
|
21
|
+
collector.findings << Finding.new("Use of Thread.critical is discouraged. Use a Mutex instead.",
|
22
|
+
[:threads, :warning], node.position)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module JRuby
|
2
|
+
module Lint
|
3
|
+
class CLI
|
4
|
+
def initialize(args)
|
5
|
+
process_options(args)
|
6
|
+
end
|
7
|
+
|
8
|
+
def process_options(args)
|
9
|
+
require 'optparse'
|
10
|
+
require 'ostruct'
|
11
|
+
@options = OpenStruct.new
|
12
|
+
OptionParser.new do |opts|
|
13
|
+
opts.banner = "Usage: jrlint [options] [files]"
|
14
|
+
opts.separator ""
|
15
|
+
opts.separator "Options:"
|
16
|
+
|
17
|
+
opts.on('-C', '--chdir DIRECTORY', "Change working directory") do |v|
|
18
|
+
Dir.chdir(v)
|
19
|
+
end
|
20
|
+
|
21
|
+
opts.on("-e", '--eval SCRIPT', "Lint an inline script") do |v|
|
22
|
+
@options.eval ||= []
|
23
|
+
@options.eval << v
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on_tail("-v", "--version", "Print version and exit") do
|
27
|
+
require 'jruby/lint/version'
|
28
|
+
puts "JRuby-Lint version #{VERSION}"
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on_tail("-h", "--help", "This message") do
|
33
|
+
puts opts
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
end.parse!(args)
|
37
|
+
|
38
|
+
@options.files = args.empty? ? nil : args
|
39
|
+
end
|
40
|
+
|
41
|
+
def run
|
42
|
+
require 'jruby/lint'
|
43
|
+
require 'benchmark'
|
44
|
+
project = JRuby::Lint::Project.new(@options)
|
45
|
+
|
46
|
+
puts "JRuby-Lint version #{JRuby::Lint::VERSION}"
|
47
|
+
time = Benchmark.realtime { project.run }
|
48
|
+
term = @options.eval ? 'expression' : 'file'
|
49
|
+
puts "Processed #{project.files.size} #{term}#{project.files.size == 1 ? '' : 's'} in #{'%0.02f' % time} seconds"
|
50
|
+
|
51
|
+
if project.findings.empty?
|
52
|
+
puts "OK"
|
53
|
+
exit
|
54
|
+
else
|
55
|
+
puts "Found #{project.findings.size} items"
|
56
|
+
exit 1
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module JRuby::Lint
|
2
|
+
class Collector
|
3
|
+
attr_accessor :checkers, :findings, :project, :contents, :file
|
4
|
+
|
5
|
+
def initialize(project = nil, file = nil)
|
6
|
+
@checkers = Checker.loaded_checkers.map(&:new)
|
7
|
+
@checkers.each {|c| c.collector = self }
|
8
|
+
@findings = []
|
9
|
+
@project, @file = project, file || '<inline-script>'
|
10
|
+
end
|
11
|
+
|
12
|
+
class CheckersVisitor < AST::Visitor
|
13
|
+
attr_reader :checkers
|
14
|
+
|
15
|
+
def initialize(ast, checkers)
|
16
|
+
super(ast)
|
17
|
+
@checkers = checkers
|
18
|
+
end
|
19
|
+
|
20
|
+
def visit(method, node)
|
21
|
+
after_hooks = []
|
22
|
+
checkers.each do |ch|
|
23
|
+
begin
|
24
|
+
if ch.respond_to?(method)
|
25
|
+
res = ch.send(method, node)
|
26
|
+
after_hooks << res if res.respond_to?(:call)
|
27
|
+
end
|
28
|
+
rescue => e
|
29
|
+
ch.collector.findings << Finding.new("Exception while traversing: #{e.message}",
|
30
|
+
[:internal, :debug], node.position)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
super
|
34
|
+
ensure
|
35
|
+
begin
|
36
|
+
after_hooks.each {|h| h.call }
|
37
|
+
rescue
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def run
|
43
|
+
begin
|
44
|
+
CheckersVisitor.new(ast, checkers).traverse
|
45
|
+
rescue SyntaxError => e
|
46
|
+
file, line, message = e.message.split(/:\s*/, 3)
|
47
|
+
findings << Finding.new(message, [:syntax, :error], file, line)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def ast
|
52
|
+
@ast ||= JRuby.parse(contents, file, true)
|
53
|
+
end
|
54
|
+
|
55
|
+
def contents
|
56
|
+
@contents || File.read(@file)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.inherited(base)
|
60
|
+
self.all << base
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.all
|
64
|
+
@collectors ||= []
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
module Collectors
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
require 'jruby/lint/collectors/ruby'
|
73
|
+
require 'jruby/lint/collectors/bundler'
|
74
|
+
require 'jruby/lint/collectors/rake'
|
75
|
+
require 'jruby/lint/collectors/gemspec'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module JRuby::Lint
|
2
|
+
class Finding < Struct.new(:message, :tags, :file, :line)
|
3
|
+
def initialize(*args)
|
4
|
+
args[1].map! {|x| x.to_s } if args.size > 1
|
5
|
+
if args.size > 2 && args[2].respond_to?(:file) && args[2].respond_to?(:line)
|
6
|
+
args = [args[0], args[1], args[2].file, (args[2].line + 1)]
|
7
|
+
end
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
"#{file}:#{line}: [#{tags.join(', ')}] #{message}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx
|
3
|
+
ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
|
4
|
+
RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw
|
5
|
+
MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH
|
6
|
+
QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j
|
7
|
+
b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j
|
8
|
+
b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj
|
9
|
+
YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN
|
10
|
+
AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H
|
11
|
+
KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm
|
12
|
+
VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR
|
13
|
+
SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT
|
14
|
+
cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ
|
15
|
+
6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu
|
16
|
+
MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS
|
17
|
+
kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB
|
18
|
+
BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f
|
19
|
+
BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv
|
20
|
+
c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH
|
21
|
+
AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO
|
22
|
+
BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG
|
23
|
+
OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU
|
24
|
+
A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o
|
25
|
+
0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX
|
26
|
+
RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH
|
27
|
+
qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV
|
28
|
+
U+4=
|
29
|
+
-----END CERTIFICATE-----
|
30
|
+
-----BEGIN CERTIFICATE-----
|
31
|
+
MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh
|
32
|
+
bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu
|
33
|
+
Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g
|
34
|
+
QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe
|
35
|
+
BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoX
|
36
|
+
DTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBE
|
37
|
+
YWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0
|
38
|
+
aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC
|
39
|
+
ggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
|
40
|
+
2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+q
|
41
|
+
N1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiO
|
42
|
+
r18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN
|
43
|
+
f4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEH
|
44
|
+
U1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHU
|
45
|
+
TBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMb
|
46
|
+
VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwg
|
47
|
+
SW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlv
|
48
|
+
biBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEg
|
49
|
+
MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUw
|
50
|
+
AwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdv
|
51
|
+
ZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu
|
52
|
+
Z29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUd
|
53
|
+
IAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv
|
54
|
+
bS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1
|
55
|
+
QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4O
|
56
|
+
WBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0Vmsf
|
57
|
+
SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw==
|
58
|
+
-----END CERTIFICATE-----
|
59
|
+
-----BEGIN CERTIFICATE-----
|
60
|
+
MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
|
61
|
+
IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
|
62
|
+
BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
|
63
|
+
aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
|
64
|
+
9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
|
65
|
+
NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
|
66
|
+
azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
|
67
|
+
YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
|
68
|
+
Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
|
69
|
+
cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
|
70
|
+
dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
|
71
|
+
WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
|
72
|
+
v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
|
73
|
+
UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
|
74
|
+
IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
|
75
|
+
W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
|
76
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
module JRuby::Lint
|
7
|
+
class Libraries
|
8
|
+
class Cache
|
9
|
+
def initialize(cache_dir = nil)
|
10
|
+
@cache_dir = cache_dir || ENV['JRUBY_LINT_CACHE'] ||
|
11
|
+
(defined?(Gem.user_dir) && File.join(Gem.user_dir, 'lint')) || Dir::tmpdir
|
12
|
+
FileUtils.mkdir_p(@cache_dir) unless File.directory?(@cache_dir)
|
13
|
+
end
|
14
|
+
|
15
|
+
def fetch(name)
|
16
|
+
filename = filename_for(name)
|
17
|
+
if File.file?(filename) && !stale?(filename)
|
18
|
+
File.read(filename)
|
19
|
+
else
|
20
|
+
read_from_wiki(name, filename)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def store(name, content)
|
25
|
+
File.open(filename_for(name), "w") {|f| f << content }
|
26
|
+
end
|
27
|
+
|
28
|
+
def filename_for(name)
|
29
|
+
name = File.basename(name)
|
30
|
+
File.join(@cache_dir, File.extname(name).empty? ? "#{name}.html" : name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def stale?(filename)
|
34
|
+
File.mtime(filename) < Time.now - 24 * 60 * 60
|
35
|
+
end
|
36
|
+
|
37
|
+
def read_from_wiki(name, filename)
|
38
|
+
content = nil
|
39
|
+
uri = Net::HTTP.start('wiki.jruby.org', 80) do |http|
|
40
|
+
URI.parse http.head(name =~ %r{^/} ? name : "/#{name}")['Location']
|
41
|
+
end
|
42
|
+
if uri.host == "github.com"
|
43
|
+
Net::HTTP.new(uri.host, uri.port).tap do |http|
|
44
|
+
if uri.scheme == "https"
|
45
|
+
http.use_ssl = true
|
46
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
47
|
+
# gd_bundle.crt from https://certs.godaddy.com/anonymous/repository.seam
|
48
|
+
http.ca_file = File.expand_path('../github.crt', __FILE__)
|
49
|
+
end
|
50
|
+
http.start do
|
51
|
+
response = http.get(uri.path)
|
52
|
+
content = response.body
|
53
|
+
File.open(filename, "w") do |f|
|
54
|
+
f << content
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
raise "Unknown location '#{uri}' for page '#{name}'" unless content
|
60
|
+
content
|
61
|
+
rescue => e
|
62
|
+
raise "Error while reading from wiki: #{e.message}\nPlease try again later."
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class CExtensions
|
67
|
+
attr_reader :gems
|
68
|
+
|
69
|
+
def initialize(cache)
|
70
|
+
@cache = cache
|
71
|
+
end
|
72
|
+
|
73
|
+
def load
|
74
|
+
@gems = {}
|
75
|
+
content = @cache.fetch('C-Extension-Alternatives')
|
76
|
+
doc = Nokogiri::HTML(content)
|
77
|
+
doc.css('#wiki-body ul li').each do |li|
|
78
|
+
key, message = li.text.split(/[ -]+/, 2)
|
79
|
+
@gems[key.downcase] = message
|
80
|
+
end
|
81
|
+
rescue => e
|
82
|
+
@error = "Unable to load C Extension alternatives list: #{e.message}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
SOURCES = [CExtensions]
|
87
|
+
|
88
|
+
attr_reader :gems
|
89
|
+
|
90
|
+
def initialize(cache)
|
91
|
+
@sources = SOURCES.map {|s| s.new(cache) }
|
92
|
+
end
|
93
|
+
|
94
|
+
def load
|
95
|
+
@gems = {}.tap do |gems|
|
96
|
+
@sources.each do |s|
|
97
|
+
s.load
|
98
|
+
gems.update(s.gems)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def gems
|
104
|
+
@gems ||= load
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module JRuby::Lint
|
5
|
+
class Project
|
6
|
+
DEFAULT_TAGS = %w(error warning info)
|
7
|
+
|
8
|
+
attr_reader :collectors, :reporters, :findings, :files, :tags, :libraries
|
9
|
+
|
10
|
+
def initialize(options = OpenStruct.new)
|
11
|
+
@tags = DEFAULT_TAGS
|
12
|
+
@collectors = []
|
13
|
+
@files = Set.new
|
14
|
+
|
15
|
+
if options.eval
|
16
|
+
options.eval.each {|e| @collectors << JRuby::Lint::Collectors::Ruby.new(self, '-e', e) }
|
17
|
+
@files += @collectors
|
18
|
+
end
|
19
|
+
|
20
|
+
@sources = options.files || (options.eval ? [] : Dir['./**/*'])
|
21
|
+
load_collectors
|
22
|
+
load_reporters
|
23
|
+
load_libraries
|
24
|
+
end
|
25
|
+
|
26
|
+
def run
|
27
|
+
@findings = []
|
28
|
+
collectors.each do |c|
|
29
|
+
c.run
|
30
|
+
reporters.each {|r| r.report(c.findings)}
|
31
|
+
@findings += c.findings
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def load_collectors
|
37
|
+
@sources.each do |f|
|
38
|
+
next unless File.file?(f)
|
39
|
+
Collector.all.each do |c|
|
40
|
+
if c.detect?(f)
|
41
|
+
@collectors << c.new(self, f)
|
42
|
+
@files << f
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_reporters
|
49
|
+
@reporters = [(STDOUT.tty? ? Reporters::ANSIColor : Reporters::Text).new(self, STDOUT)]
|
50
|
+
end
|
51
|
+
|
52
|
+
def load_libraries
|
53
|
+
@libraries = Libraries.new(Libraries::Cache.new)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|