Skip to content
This repository was archived by the owner on Jul 19, 2025. It is now read-only.

Commit 4d34157

Browse files
committed
Switch from MRI to JRuby
To take full advantage of concurrent-ruby for faster analyses this replaces MRI Ruby with JRuby since JRuby can take advantage of threads without being blocked by the GIL. * Replace posix-spawn with `IO.popen` * Replace alpine with `jruby:9.0-jdk` Docker image Here's a comparison of JRuby vs MRI on a medium sized JavaScript project using the same concurrency value and same config. JRuby: ``` codeclimate analyze --dev 0.29s user 0.22s system 0% cpu 2:26.03 total ``` MRI: ``` codeclimate analyze --dev 0.35s user 0.29s system 0% cpu 3:54.92 total ```
1 parent 2ba85a5 commit 4d34157

File tree

6 files changed

+46
-38
lines changed

6 files changed

+46
-38
lines changed

Dockerfile

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
2-
FROM alpine:edge
1+
FROM jruby:9.0.3-jdk
32

43
WORKDIR /usr/src/app/
54

@@ -9,19 +8,19 @@ COPY Gemfile.lock /usr/src/app/
98
COPY vendor/php-parser/composer.json /usr/src/app/vendor/php-parser/
109
COPY vendor/php-parser/composer.lock /usr/src/app/vendor/php-parser/
1110

12-
RUN apk --update add openssh git python nodejs php-cli php-json php-phar php-openssl php-xml curl\
13-
ruby ruby-io-console ruby-dev build-base && \
14-
gem install bundler --no-ri --no-rdoc && \
11+
RUN curl --silent --location https://deb.nodesource.com/setup_5.x | bash -
12+
RUN apt-get install -y nodejs python openssh-client php5-cli php5-json
13+
RUN gem install bundler --no-ri --no-rdoc && \
1514
bundle install -j 4 && \
16-
apk del build-base && rm -fr /usr/share/ri && \
1715
curl -sS https://getcomposer.org/installer | php
1816

1917
RUN mv composer.phar /usr/local/bin/composer
2018
RUN cd /usr/src/app/vendor/php-parser/ && composer install --prefer-source --no-interaction
2119

22-
RUN adduser -u 9000 -D app
20+
RUN adduser app -u 9000
2321

2422
COPY . /usr/src/app
23+
run chown -R app .
2524
RUN npm install
2625

2726
USER app

Gemfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ gem 'flay', git: 'https://github.com/codeclimate/flay.git'
44
gem 'concurrent-ruby', "~> 1.0.0.pre4"
55
gem 'ruby_parser'
66
gem 'pry'
7-
gem 'posix-spawn'
87
gem 'sexp_processor'
98
gem 'json'
109

Gemfile.lock

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
GIT
22
remote: https://github.com/codeclimate/flay.git
3-
revision: e6e472e064dc459277f8bd57167789f8fed77f56
3+
revision: ac8fd46ba30e9636e8bdc625cf5f849615d505b6
44
specs:
55
flay (2.6.1)
66

77
GEM
88
remote: https://rubygems.org/
99
specs:
1010
coderay (1.1.0)
11-
concurrent-ruby (1.0.0.pre4)
11+
concurrent-ruby (1.0.0.pre5)
1212
diff-lcs (1.2.5)
1313
json (1.8.3)
1414
method_source (0.8.2)
15-
posix-spawn (0.3.11)
1615
pry (0.10.3)
1716
coderay (~> 1.1.0)
1817
method_source (~> 0.8.1)
@@ -43,7 +42,6 @@ DEPENDENCIES
4342
concurrent-ruby (~> 1.0.0.pre4)
4443
flay!
4544
json
46-
posix-spawn
4745
pry
4846
rake
4947
rspec

lib/cc/engine/analyzers/javascript/parser.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
require 'posix/spawn'
21
require 'timeout'
32

43
module CC
@@ -46,7 +45,6 @@ class CommandLineRunner
4645
EXCEPTIONS = [
4746
StandardError,
4847
Timeout::Error,
49-
POSIX::Spawn::TimeoutExceeded,
5048
SystemStackError
5149
]
5250

@@ -57,11 +55,15 @@ def initialize(command, delegate)
5755

5856
def run(input, timeout = DEFAULT_TIMEOUT)
5957
Timeout.timeout(timeout) do
60-
child = ::POSIX::Spawn::Child.new(command, input: input, timeout: timeout)
61-
if child.status.success?
62-
yield child.out if block_given?
63-
end
58+
IO.popen command, 'r+' do |io|
59+
io.puts input
60+
io.close_write
61+
62+
output = io.gets
63+
io.close
6464

65+
yield output if $?.to_i == 0
66+
end
6567
end
6668
end
6769
end

lib/cc/engine/analyzers/php/parser.rb

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
require 'posix/spawn'
21
require 'cc/engine/analyzers/php/ast'
32
require 'cc/engine/analyzers/php/nodes'
43

@@ -15,16 +14,17 @@ def initialize(code, filename)
1514
end
1615

1716
def parse
18-
runner = CommandLineRunner.new("php #{parser_path}", self)
19-
runner.run(code) { |output| JSON.parse(output, max_nesting: false) }
20-
self
21-
end
17+
runner = CommandLineRunner.new("php #{parser_path}")
18+
runner.run(code) do |output|
19+
json = JSON.parse(output)
2220

23-
def on_success(output)
24-
@syntax_tree = CC::Engine::Analyzers::Php::Nodes::Node.new.tap do |node|
25-
node.stmts = CC::Engine::Analyzers::Php::AST.json_to_ast(output, filename)
26-
node.node_type = "AST"
21+
@syntax_tree = CC::Engine::Analyzers::Php::Nodes::Node.new.tap do |node|
22+
node.stmts = CC::Engine::Analyzers::Php::AST.json_to_ast(json, filename)
23+
node.node_type = "AST"
24+
end
2725
end
26+
27+
self
2828
end
2929

3030
private
@@ -40,16 +40,23 @@ def parser_path
4040
class CommandLineRunner
4141
attr_reader :command, :delegate
4242

43-
def initialize(command, delegate)
43+
DEFAULT_TIMEOUT = 20
44+
45+
def initialize(command)
4446
@command = command
45-
@delegate = delegate
4647
end
4748

48-
def run(input)
49-
child = ::POSIX::Spawn::Child.new(command, input: input)
50-
if child.status.success?
51-
output = block_given? ? yield(child.out) : child.out
52-
delegate.on_success(output)
49+
def run(input, timeout = DEFAULT_TIMEOUT)
50+
Timeout.timeout(timeout) do
51+
IO.popen command, 'r+' do |io|
52+
io.puts input
53+
io.close_write
54+
55+
output = io.gets
56+
io.close
57+
58+
yield output if $?.to_i == 0
59+
end
5360
end
5461
end
5562
end

lib/cc/engine/analyzers/python/parser.rb

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
require 'posix/spawn'
21
require 'timeout'
32
require 'json'
43

@@ -42,10 +41,14 @@ def initialize(command, delegate)
4241

4342
def run(input, timeout = DEFAULT_TIMEOUT)
4443
Timeout.timeout(timeout) do
45-
child = ::POSIX::Spawn::Child.new(command, input: input, timeout: timeout)
44+
IO.popen command, "r+" do |io|
45+
io.puts input
46+
io.close_write
4647

47-
if child.status.success?
48-
yield child.out if block_given?
48+
output = io.gets
49+
io.close
50+
51+
yield output if $?.to_i == 0
4952
end
5053
end
5154
end

0 commit comments

Comments
 (0)