Skip to content

Commit

Permalink
Merge pull request #47 from bundler/various-fixes-2
Browse files Browse the repository at this point in the history
Various fixes 2
  • Loading branch information
smellsblue committed Nov 6, 2015
2 parents 366ec18 + 07c28b2 commit 1daacf4
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 41 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Expand Up @@ -2,12 +2,14 @@ language: ruby
matrix:
allow_failures:
- rvm: ruby-head
include:
- rvm: jruby-9.0.3.0
env: JRUBY_OPTS="$JRUBY_OPTS -J-Xmx1536m -J-XX:MaxPermSize=192m"
rvm:
- 2.0
- 2.1
- 2.2
- ruby-head
- jruby-9.0.3.0
bundler_args: "--binstubs --jobs=3 --retry=3"
before_install: gem install bundler -v 1.10.6
cache: bundler
Expand Down
5 changes: 3 additions & 2 deletions lib/gemstash/env.rb
Expand Up @@ -2,6 +2,7 @@
require "dalli"
require "fileutils"
require "sequel"
require "uri"

module Gemstash
# Storage for application-wide variables and configuration.
Expand Down Expand Up @@ -108,9 +109,9 @@ def db
db_path = base_file("gemstash.db")

if RUBY_PLATFORM == "java"
db = Sequel.connect("jdbc:sqlite:#{db_path}")
db = Sequel.connect("jdbc:sqlite:#{db_path}", max_connections: 1)
else
db = Sequel.connect("sqlite://#{db_path}")
db = Sequel.connect("sqlite://#{URI.escape(db_path)}", max_connections: 1)
end
when "postgres"
db = Sequel.connect(config[:db_url])
Expand Down
5 changes: 2 additions & 3 deletions spec/gemstash/storage_spec.rb
@@ -1,5 +1,4 @@
require "spec_helper"
require "securerandom"

describe Gemstash::Storage do
before do
Expand Down Expand Up @@ -67,8 +66,8 @@
end

context "with a previously stored resource" do
let(:resource_id) { SecureRandom.uuid }
let(:content) { SecureRandom.base64 }
let(:resource_id) { "42" }
let(:content) { "zapatito" }
before do
storage.resource(resource_id).save(content)
end
Expand Down
23 changes: 12 additions & 11 deletions spec/integration_spec.rb
Expand Up @@ -102,7 +102,7 @@

it "pushes valid gems to the server", :db_transaction => false do
env = { "HOME" => env_dir }
expect(execute("gem push --key test --host '#{host}' '#{gem}'", env: env)).to exit_success
expect(execute("gem", ["push", "--key", "test", "--host", host, gem], env: env)).to exit_success
expect(deps.fetch(%w(speaker))).to match_dependencies([speaker_deps])
expect(storage.resource("speaker-0.1.0").load.content).to eq(gem_contents)
expect(http_client.get("gems/speaker-0.1.0")).to eq(gem_contents)
Expand All @@ -118,7 +118,7 @@

it "removes valid gems from the server", :db_transaction => false do
env = { "HOME" => env_dir, "RUBYGEMS_HOST" => host }
expect(execute("gem yank --key test '#{gem_name}' --version #{gem_version}", env: env)).to exit_success
expect(execute("gem", ["yank", "--key", "test", gem_name, "--version", gem_version], env: env)).to exit_success
expect(deps.fetch(%w(speaker))).to match_dependencies([])
# It shouldn't actually delete the gem, to support unyank
expect(storage.resource("speaker-0.1.0").load.content).to eq(gem_contents)
Expand All @@ -137,7 +137,8 @@

it "adds valid gems back to the server", :db_transaction => false do
env = { "HOME" => env_dir, "RUBYGEMS_HOST" => host }
expect(execute("gem yank --key test '#{gem_name}' --version #{gem_version} --undo", env: env)).to exit_success
expect(execute("gem", ["yank", "--key", "test", gem_name, "--version", gem_version, "--undo"], env: env)).
to exit_success
expect(deps.fetch(%w(speaker))).to match_dependencies([speaker_deps])
expect(storage.resource("speaker-0.1.0").load.content).to eq(gem_contents)
expect(http_client.get("gems/speaker-0.1.0")).to eq(gem_contents)
Expand All @@ -163,27 +164,27 @@
shared_examples "a bundleable project" do
it "successfully bundles" do
expect(execute("bundle", dir: dir)).to exit_success
expect(execute("bundle exec speaker hi", dir: dir)).
expect(execute("bundle", %w(exec speaker hi), dir: dir)).
to exit_success.and_output("Hello world, #{platform_message}\n")
end

it "can bundle with full index" do
expect(execute("bundle --full-index", dir: dir)).to exit_success
expect(execute("bundle exec speaker hi", dir: dir)).
expect(execute("bundle", %w(--full-index), dir: dir)).to exit_success
expect(execute("bundle", %w(exec speaker hi), dir: dir)).
to exit_success.and_output("Hello world, #{platform_message}\n")
end

it "can bundle with prerelease versions" do
env = { "SPEAKER_VERSION" => "= 0.2.0.pre" }
expect(execute("bundle", dir: dir, env: env)).to exit_success
expect(execute("bundle exec speaker hi", dir: dir, env: env)).
expect(execute("bundle", %w(exec speaker hi), dir: dir, env: env)).
to exit_success.and_output("Hello world, pre, #{platform_message}\n")
end

it "can bundle with prerelease versions with full index" do
env = { "SPEAKER_VERSION" => "= 0.2.0.pre" }
expect(execute("bundle --full-index", dir: dir, env: env)).to exit_success
expect(execute("bundle exec speaker hi", dir: dir, env: env)).
expect(execute("bundle", %w(--full-index), dir: dir, env: env)).to exit_success
expect(execute("bundle", %w(exec speaker hi), dir: dir, env: env)).
to exit_success.and_output("Hello world, pre, #{platform_message}\n")
end
end
Expand All @@ -205,13 +206,13 @@

it "can successfully bundle twice" do
expect(execute("bundle", dir: dir)).to exit_success
expect(execute("bundle exec speaker hi", dir: dir)).
expect(execute("bundle", %w(exec speaker hi), dir: dir)).
to exit_success.and_output("Hello world, #{platform_message}\n")

clean_bundle bundle

expect(execute("bundle", dir: dir)).to exit_success
expect(execute("bundle exec speaker hi", dir: dir)).
expect(execute("bundle", %w(exec speaker hi), dir: dir)).
to exit_success.and_output("Hello world, #{platform_message}\n")
end
end
Expand Down
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Expand Up @@ -8,6 +8,7 @@
require "support/env_helpers"
require "support/exec_helpers"
require "support/file_helpers"
require "support/in_process_exec"
require "support/log_helpers"
require "support/matchers"
require "support/simple_server"
Expand Down
96 changes: 72 additions & 24 deletions spec/support/exec_helpers.rb
@@ -1,40 +1,51 @@
require "bundler/version"
require "open3"
require "pathname"

# Helpers for executing commands and asserting the results.
module ExecHelpers
def execute(command, dir: nil, env: {})
bundle_gemfile = nil

if dir
gemfile_path = File.join(dir, "Gemfile")
bundle_gemfile = gemfile_path if File.exist?(gemfile_path)
def execute(command, args = [], dir: nil, env: {})
if RUBY_PLATFORM == "java"
JRubyResult.new(env, command, args, dir)
else
Result.new(env, command, args, dir)
end

env = {
"BUNDLE_GEMFILE" => bundle_gemfile,
"RUBYLIB" => nil,
"RUBYOPT" => nil,
"GEM_PATH" => ENV["_ORIGINAL_GEM_PATH"]
}.merge(env)
dir ||= File.expand_path(".")
Result.new(env, command, dir)
end

# Executes and stores the results for an external command.
class Result
attr_reader :command, :dir, :output
attr_reader :command, :args, :dir, :output

def initialize(env, command, dir)
def initialize(env, command, args, dir)
@command = command
@dir = dir
@output, @status = Open3.capture2e(env, command, chdir: dir)
@args = args
@env = env
@original_dir = dir
@dir = dir || File.expand_path("../../..", __FILE__)
exec
fix_jruby_output
end

def exec
@output, @status = Open3.capture2e(patched_env, command, *args, chdir: dir)
end

def successful?
@status.success?
end

def display_command
display_args = args.map do |x|
if x =~ /\s/
"'#{x}'"
else
x
end
end

([command] + display_args).join(" ")
end

def matches_output?(expected)
return true unless expected
@output == expected
Expand All @@ -46,12 +57,49 @@ def fix_jruby_output
return unless RUBY_PLATFORM == "java"
# Travis builds or runs JRuby in a way that outputs the following warning for some reason
@output.gsub!(/^.*warning: unknown property jruby.cext.enabled\n/, "")
end

def patched_env
@patched_env ||= clear_bundler_env.merge(clear_ruby_env).merge(@env)
end

if Gem::Requirement.new(">= 1.11.0").satisfied_by?(Gem::Version.new(Bundler::VERSION))
raise "Please remove ExecHelpers#fix_jruby_output if the warning doesn't occur anymore"
def clear_ruby_env
{
"RUBYLIB" => nil,
"RUBYOPT" => nil,
"GEM_PATH" => ENV["_ORIGINAL_GEM_PATH"]
}
end

def clear_bundler_env
if @original_dir
gemfile_path = File.join(@original_dir, "Gemfile")
bundle_gemfile = gemfile_path if File.exist?(gemfile_path)
end

@output.gsub!(/^.*warning: unsupported exec option: close_others\n/, "")
{ "BUNDLE_GEMFILE" => bundle_gemfile }
end
end

# Executes and stores the results for an external command, but does it in
# process with a separate JRuby instance rather than a process.
class JRubyResult < Result
def exec
binstub_dir = File.expand_path("../jruby_binstubs", __FILE__)
binstub = File.join(binstub_dir, command)
raise "Missing binstub for #{command}" unless File.exist?(binstub)
exec_in_process(binstub)
end

def successful?
@process.status == 0
end

private

def exec_in_process(binstub)
@process = InProcessExec.new(patched_env, dir, [binstub] + args)
@output = @process.output
end
end
end
Expand All @@ -67,13 +115,13 @@ def fix_jruby_output

failure_message do |actual|
if actual.successful?
"expected '#{actual.command}' in '#{actual.dir}' to output:
"expected '#{actual.display_command}' in '#{actual.dir}' to output:
#{@expected_output}
but instead it output:
#{actual.output}"
else
"expected '#{actual.command}' in '#{actual.dir}' to exit with a success code, but it didn't.
"expected '#{actual.display_command}' in '#{actual.dir}' to exit with a success code, but it didn't.
the command output was:
#{actual.output}"
end
Expand Down
36 changes: 36 additions & 0 deletions spec/support/in_process_exec.rb
@@ -0,0 +1,36 @@
# Run a JRuby program in process.
class InProcessExec
attr_reader :status, :output

def initialize(env, dir, args)
raise "InProcessExec is only valid on JRuby!" unless RUBY_PLATFORM == "java"
@env = env
@dir = dir
@args = args
exec
end

private

def exec
prepare_streams
prepare_config
@status = org.jruby.Main.new(@config).run(@args.to_java(:String)).status
@output = @output_stream.to_string
end

def prepare_streams
@input_stream = java.io.ByteArrayInputStream.new([].to_java(:byte))
@output_stream = java.io.ByteArrayOutputStream.new
@output_print_stream = java.io.PrintStream.new(@output_stream)
end

def prepare_config
@config = org.jruby.RubyInstanceConfig.new(JRuby.runtime.instance_config)
@config.environment = @env
@config.current_directory = @dir
@config.input = @input_stream
@config.output = @output_print_stream
@config.error = @output_print_stream
end
end
25 changes: 25 additions & 0 deletions spec/support/jruby_binstubs/bundle
@@ -0,0 +1,25 @@
require "rubygems"
gem "bundler"
require "bundler"
require "bundler/fetcher"
require_relative "../in_process_exec.rb"

module Bundler
#:nodoc:
class Fetcher
# The Bundler user_agent uses SecureRandom, which causes the specs
# to run out of entropy and run a lot longer than they need to.
def user_agent
"gemstash spec"
end
end
end

def Kernel.exec(*args)
args.pop if args.last.kind_of?(Hash)
process = InProcessExec.new(ENV, File.expand_path("."), args)
puts process.output
exit process.status
end

load Gem.bin_path("bundler", "bundle")
10 changes: 10 additions & 0 deletions spec/support/jruby_binstubs/gem
@@ -0,0 +1,10 @@
# Based on jgem
require "rubygems"
require "rubygems/gem_runner"
require "rubygems/exceptions"

begin
Gem::GemRunner.new.run ARGV.clone
rescue Gem::SystemExitException => e
exit e.exit_code
end

0 comments on commit 1daacf4

Please sign in to comment.