Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 99fd7b6dfac5^
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 8538a436dfcf
Choose a head ref
  • 2 commits
  • 4 files changed
  • 2 contributors

Commits on Aug 31, 2015

  1. [Truffle] add app/gem runner

    pitr-ch committed Aug 31, 2015
    Copy the full SHA
    99fd7b6 View commit details
  2. Copy the full SHA
    8538a43 View commit details
4 changes: 4 additions & 0 deletions tool/truffle/jruby_truffle_runner/bin/truffle
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env ruby

require_relative '../lib/jruby_truffle_runner.rb'
JRubyTruffleRunner.new
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
:global:
:jruby_truffle_path: '../../jruby/bin/ruby'
:setup:
:after:
- 'echo "$:.unshift \"\#{path}/..\"" >> "#{options[:global][:truffle_bundle_path]}/bundler/setup.rb"'
:file:
shims.rb: |
module Minitest
module Assertions
def self.diff
nil
end
end
end
bundler.rb: "module Bundler; def self.setup; end; end"
method_source.rb: nil
:without:
- db
:run:
:require:
- shims
:load_path:
- test
17 changes: 17 additions & 0 deletions tool/truffle/jruby_truffle_runner/jruby_truffle_runner.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Gem::Specification.new do |s|
s.name = 'jruby_truffle_runner'
s.version = '0.0.1'
s.platform = Gem::Platform::RUBY
s.authors = ['Petr Chalupa']
s.email = ['git@pitr.ch']
s.homepage = 'http://github.com/jruby/jruby'
s.summary = 'Temporary JRuby+Truffle runner'
s.description = 'Until JRuby+Truffle is more complete, allows to run apps/gems simply on JRuby+Truffle.'

s.required_rubygems_version = '>= 1.3.6'

s.files = Dir['{lib}/**/*.rb', 'bin/*', 'gem_configurations/*.yaml', 'LICENSE', '*.md']
s.require_path = 'lib'

s.executables = ['truffle']
end
270 changes: 270 additions & 0 deletions tool/truffle/jruby_truffle_runner/lib/jruby_truffle_runner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
require 'optparse'
require 'pp'
require 'yaml'
require 'fileutils'

# TODO stored after run combinations like -S irb, -I test

class JRubyTruffleRunner
attr_reader :options

begin
assign_new_value = -> (new, old) { new }
add_to_array = -> (new, old) { old << new }
merge_hash = -> ((k, v), old) { old.merge k => v }

# Format:
# subcommand_name: {
# :'option_name (also used as a key in yaml)' => [option_parser_on_method_args,
# -> (new_value, old_value) { result_of_this_block_is_stored },
# default_value]
# }
OPTION_DEFINITIONS = {
global: {
verbose: ['-v', '--verbose', 'Run verbosely (prints options)', assign_new_value, false],
help: ['-h', '--help', 'Show this message', -> (_, _) { help }, false],
debug_port: ['--debug-port PORT', 'Debug port', assign_new_value, '51819'],
debug_option: ['--debug-option OPTION', 'Debug JVM option', assign_new_value,
'-J-agentlib:jdwp=transport=dt_socket,server=y,address=%d,suspend=y'],
truffle_bundle_path: ['--truffle-bundle-path NAME', 'Bundle path', assign_new_value, 'truffle_bundle'],
jruby_truffle_path: ['--jruby-truffle-path PATH', 'Path to JRuby+Truffle bin/ruby', assign_new_value,
'../jruby/bin/ruby']
},
setup: {
help: ['-h', '--help', 'Show this message', -> (_, _) { help :setup }, false],
after: ['--after SH_CMD', 'Commands to execute after setup', add_to_array, []],
file: ['--file NAME,CONTENT', 'Create file in truffle_bundle_path', merge_hash, {}],
without: ['--without GROUP', 'Do not install listed gem group by bundler', add_to_array, []]
},
run: {
help: ['-h', '--help', 'Show this message', -> (_, _) { help :run }, false],
test: ['-t', '--test', 'Do not use Truffle use plain JRuby', assign_new_value, false],
debug: ['-d', '--debug', 'JVM remote debugging', assign_new_value, false],
require: ['-r', '--require FILE', 'Files to require, same as Ruby\'s -r', add_to_array, []],
load_path: ['-l', '--load-path LOAD_PATH', 'Paths to add to load path, same as Ruby\'s -I', add_to_array, []],
jexception: ['--jexception', 'print Java exceptions', assign_new_value, false]
},
clean: {
help: ['-h', '--help', 'Show this message', -> (_, _) { help :run }, false]
}
}
end

begin
global_help = <<-TXT.gsub(/^ {6}/, '')
Usage: truffle [options] [subcommand [subcommand-options]]
Subcommands are: #{(OPTION_DEFINITIONS.keys - [:global]).map(&:to_s).join(', ')}
Allows to execute gem/app on JRuby+Truffle until it's more complete. Environment
has to be set up first with setup subcommand then run subcommand can be used.
Options can be set on commandline or in local directory in .truffle.yaml file.
Tha data in yaml file follow same structure as OPTION_DEFINITIONS what, its values
are deep-merged with default values, then command-line options are applied.
Gem contains default configurations for gems gem_configurations directory.
They are copied when there is no configuration present.
TXT

setup_help = <<-TXT.gsub(/^ {6}/, '')
Usage: truffle [options] setup [subcommand-options]
Creates environment for running gem/app on JRuby+Truflle.
TXT

run_help = <<-TXT.gsub(/^ {6}/, '')
Usage: truffle [options] run [subcommand-options] -- [ruby-options]
Runs file, -e expr, etc in setup environment on JRuby+Truffle
Examples: truffle run -- a_file.rb
truffle run -- -S irb
truffle run -- -e 'puts :v'
truffle --verbose run -- -Itest test/a_test_file_test.rb
TXT

clean_help = <<-TXT.gsub(/^ {6}/, '')
Usage: truffle [options] clean [subcommand-options]
Deletes all files created by setup subcommand.
TXT

HELP = { global: global_help, setup: setup_help, run: run_help, clean: clean_help }
end


def initialize(argv = ARGV)
construct_default_options
load_local_yaml_configuration
build_option_parsers

subcommand, *argv_after_global = @option_parsers[:global].order argv

if subcommand.nil?
print_options
help
end

subcommand_option_parser = @option_parsers[subcommand.to_sym] || raise("unknown subcommand: #{subcommand.inspect}")
argv_after_subcommand = subcommand_option_parser.order argv_after_global

print_options

send "subcommand_#{subcommand}", argv_after_subcommand
end

def print_options
if @options[:global][:verbose]
puts 'Options:'
pp @options
end
end

private

def build_option_parsers
@option_parsers = OPTION_DEFINITIONS.each_with_object({}) do |(group, group_options), parsers|
parsers[group] = OptionParser.new do |option_parser|
group_options.each do |option, data|
*args, description, block, default = data

option_parser.on(*args, description + " (default: #{default.inspect})") do |new_value|
old_value = @options[group][option]
@options[group][option] = block.call new_value, old_value
end
end
end
end

@option_parsers.each { |key, option_parser| option_parser.banner = HELP[key] }
end

def load_local_yaml_configuration
yaml_path = File.join Dir.pwd, '.truffle.yaml'

unless File.exist? yaml_path
candidates = Dir['*.gemspec']
if candidates.size == 1
gem_name, _ = candidates.first.split('.')

default_configuration_file_path = File.dirname(__FILE__) + "/../gem_configurations/#{gem_name}.yaml"
if File.exist?(default_configuration_file_path)
puts "Copying default .truffle.yaml for #{gem_name}."
FileUtils.cp default_configuration_file_path, '.truffle.yaml'
end
end
end

yaml_data = YAML.load_file(yaml_path) if File.exist?(yaml_path)
@options = deep_merge @options, yaml_data
end

def construct_default_options
@options = OPTION_DEFINITIONS.each_with_object({}) do |(group, group_options), options|
group_options.each_with_object(options[group] = {}) do |(option, data), group_option_defaults|
*args, block, default = data
group_option_defaults[option] = default
end
end
end

def help(key = nil)
parsers = if key
[@option_parsers[key]]
else
@option_parsers.values
end
puts *parsers
exit
end

def deep_merge(a, b)
if Hash === a
if Hash === b
return a.merge(b) { |k, ov, nv| deep_merge ov, nv }
else
return a
end
end

if Array === a
if Array === b
return a + b.map { |v| eval_yaml_strings v }
else
return a
end
end

eval_yaml_strings b
end

def eval_yaml_strings(value)
if String === value
begin
eval('"' + value.gsub(/\\#|"|\\/, '\#' => '\#', '"' => '\"', '\\' => '\\\\') + '"')
rescue => e
p value
raise e
end
else
value
end
end

def subcommand_setup(rest)
bundle_path = File.expand_path @options[:global][:truffle_bundle_path]
bundle_installed = execute_cmd 'command -v bundle 2>/dev/null', fail: false

execute_cmd 'gem install bundler' unless bundle_installed

execute_cmd "bundle install --standalone --path #{bundle_path} " +
"--without #{@options[:setup][:without].join(' ')}"

execute_cmd "ln -s #{bundle_path}/#{RUBY_ENGINE} #{bundle_path}/jruby+truffle", fail: false

@options[:setup][:file].each do |name, content|
puts "creating file: #{name}" if @options[:global][:verbose]
File.write "#{bundle_path}/#{name}", content
end

@options[:setup][:after].each do |cmd|
execute_cmd cmd
end
end

def subcommand_run(rest)
cmd_options = [
('-X+T' unless @options[:run][:test]),
(format(@options[:global][:debug_option], @options[:global][:debug_port]) if @options[:run][:debug]),
('-Xtruffle.exceptions.print_java=true' if @options[:run][:jexception]),
"-r ./#{@options[:global][:truffle_bundle_path]}/bundler/setup.rb",
*@options[:run][:require].map { |v| '-r ' + v },
*@options[:run][:load_path].map { |v| '-I ' + v }
].compact.join(' ')

cmd = [@options[:global][:jruby_truffle_path], cmd_options, *rest].join(' ')

exit execute_cmd(cmd, fail: false, print_always: true)
end

def subcommand_clean(rest)
FileUtils.rm_rf @options[:global][:truffle_bundle_path]
end

def print_cmd(cmd, print_always)
puts '$ ' + cmd if @options[:global][:verbose] || print_always
cmd
end

def execute_cmd(cmd, fail: true, print_always: false)
result = system(print_cmd(cmd, print_always))
ensure
raise 'command failed' if fail && !result
end
end